1 /*- 2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/usr.sbin/ppp/server.c,v 1.28.2.6 2002/09/01 02:12:32 brian Exp $ 27 * $DragonFly: src/usr.sbin/ppp/server.c,v 1.2 2003/06/17 04:30:01 dillon Exp $ 28 */ 29 30 #include <sys/param.h> 31 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <sys/un.h> 35 36 #include <errno.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <sys/stat.h> 41 #include <termios.h> 42 #include <unistd.h> 43 44 #include "log.h" 45 #include "descriptor.h" 46 #include "server.h" 47 #include "prompt.h" 48 #include "ncpaddr.h" 49 #include "probe.h" 50 51 static int 52 server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 53 { 54 struct server *s = descriptor2server(d); 55 struct prompt *p; 56 int sets; 57 58 sets = 0; 59 if (r && s->fd >= 0) { 60 if (*n < s->fd + 1) 61 *n = s->fd + 1; 62 FD_SET(s->fd, r); 63 log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 64 sets++; 65 } 66 67 for (p = log_PromptList(); p; p = p->next) 68 sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 69 70 return sets; 71 } 72 73 static int 74 server_IsSet(struct fdescriptor *d, const fd_set *fdset) 75 { 76 struct server *s = descriptor2server(d); 77 struct prompt *p; 78 79 if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 80 return 1; 81 82 for (p = log_PromptList(); p; p = p->next) 83 if (descriptor_IsSet(&p->desc, fdset)) 84 return 1; 85 86 return 0; 87 } 88 89 static void 90 server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 91 { 92 struct server *s = descriptor2server(d); 93 struct sockaddr_storage ss; 94 struct sockaddr *sa = (struct sockaddr *)&ss; 95 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 96 #ifndef NOINET6 97 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 98 #endif 99 int ssize = sizeof ss, wfd; 100 struct prompt *p; 101 struct ncpaddr addr; 102 103 if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 104 wfd = accept(s->fd, sa, &ssize); 105 if (wfd < 0) 106 log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 107 else if (sa->sa_len == 0) { 108 close(wfd); 109 wfd = -1; 110 } 111 } else 112 wfd = -1; 113 114 if (wfd >= 0) 115 switch (sa->sa_family) { 116 case AF_LOCAL: 117 log_Printf(LogPHASE, "Connected to local client.\n"); 118 break; 119 120 case AF_INET: 121 ncpaddr_setsa(&addr, sa); 122 if (ntohs(sin->sin_port) < 1024) { 123 log_Printf(LogALERT, "Rejected client connection from %s:%u" 124 "(invalid port number) !\n", 125 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 126 close(wfd); 127 wfd = -1; 128 break; 129 } 130 log_Printf(LogPHASE, "Connected to client from %s:%u\n", 131 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 132 break; 133 134 #ifndef NOINET6 135 case AF_INET6: 136 ncpaddr_setsa(&addr, sa); 137 if (ntohs(sin6->sin6_port) < 1024) { 138 log_Printf(LogALERT, "Rejected client connection from %s:%u" 139 "(invalid port number) !\n", 140 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 141 close(wfd); 142 wfd = -1; 143 break; 144 } 145 log_Printf(LogPHASE, "Connected to client from %s:%u\n", 146 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 147 break; 148 #endif 149 150 default: 151 write(wfd, "Unrecognised access !\n", 22); 152 close(wfd); 153 wfd = -1; 154 break; 155 } 156 157 if (wfd >= 0) { 158 if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 159 write(wfd, "Connection refused.\n", 20); 160 close(wfd); 161 } else { 162 switch (sa->sa_family) { 163 case AF_LOCAL: 164 p->src.type = "local"; 165 strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1); 166 p->src.from[sizeof p->src.from - 1] = '\0'; 167 break; 168 case AF_INET: 169 p->src.type = "ip"; 170 snprintf(p->src.from, sizeof p->src.from, "%s:%u", 171 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 172 break; 173 #ifndef NOINET6 174 case AF_INET6: 175 p->src.type = "ip6"; 176 snprintf(p->src.from, sizeof p->src.from, "%s:%u", 177 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 178 break; 179 #endif 180 } 181 prompt_TtyCommandMode(p); 182 prompt_Required(p); 183 } 184 } 185 186 log_PromptListChanged = 0; 187 for (p = log_PromptList(); p; p = p->next) 188 if (descriptor_IsSet(&p->desc, fdset)) { 189 descriptor_Read(&p->desc, bundle, fdset); 190 if (log_PromptListChanged) 191 break; 192 } 193 } 194 195 static int 196 server_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, const fd_set *fdset __unused) 197 { 198 /* We never want to write here ! */ 199 log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n"); 200 return 0; 201 } 202 203 struct server server = { 204 { 205 SERVER_DESCRIPTOR, 206 server_UpdateSet, 207 server_IsSet, 208 server_Read, 209 server_Write 210 }, 211 -1, 212 { "", "", 0, 0 } 213 }; 214 215 enum server_stat 216 server_Reopen(struct bundle *bundle) 217 { 218 char name[sizeof server.cfg.sockname]; 219 struct stat st; 220 u_short port; 221 mode_t mask; 222 enum server_stat ret; 223 224 if (server.cfg.sockname[0] != '\0') { 225 strcpy(name, server.cfg.sockname); 226 mask = server.cfg.mask; 227 server_Close(bundle); 228 if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0) 229 if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0) 230 return SERVER_FAILED; 231 ret = server_LocalOpen(bundle, name, mask); 232 } else if (server.cfg.port != 0) { 233 port = server.cfg.port; 234 server_Close(bundle); 235 ret = server_TcpOpen(bundle, port); 236 } else 237 ret = SERVER_UNSET; 238 239 return ret; 240 } 241 242 enum server_stat 243 server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 244 { 245 struct sockaddr_un ifsun; 246 mode_t oldmask; 247 int s; 248 249 oldmask = (mode_t)-1; /* Silence compiler */ 250 251 if (server.cfg.sockname && !strcmp(server.cfg.sockname, name)) 252 server_Close(bundle); 253 254 memset(&ifsun, '\0', sizeof ifsun); 255 ifsun.sun_len = strlen(name); 256 if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { 257 log_Printf(LogERROR, "Local: %s: Path too long\n", name); 258 return SERVER_INVALID; 259 } 260 ifsun.sun_family = AF_LOCAL; 261 strcpy(ifsun.sun_path, name); 262 263 s = socket(PF_LOCAL, SOCK_STREAM, 0); 264 if (s < 0) { 265 log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 266 goto failed; 267 } 268 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 269 if (mask != (mode_t)-1) 270 oldmask = umask(mask); 271 if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { 272 if (mask != (mode_t)-1) 273 umask(oldmask); 274 log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 275 close(s); 276 goto failed; 277 } 278 if (mask != (mode_t)-1) 279 umask(oldmask); 280 if (listen(s, 5) != 0) { 281 log_Printf(LogERROR, "Local: Unable to listen to socket -" 282 " BUNDLE overload?\n"); 283 close(s); 284 unlink(name); 285 goto failed; 286 } 287 server_Close(bundle); 288 server.fd = s; 289 server.cfg.port = 0; 290 strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1); 291 server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 292 server.cfg.mask = mask; 293 log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 294 295 return SERVER_OK; 296 297 failed: 298 if (server.fd == -1) { 299 server.fd = -1; 300 server.cfg.port = 0; 301 strncpy(server.cfg.sockname, ifsun.sun_path, 302 sizeof server.cfg.sockname - 1); 303 server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 304 server.cfg.mask = mask; 305 } 306 return SERVER_FAILED; 307 } 308 309 enum server_stat 310 server_TcpOpen(struct bundle *bundle, u_short port) 311 { 312 struct sockaddr_storage ss; 313 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 314 #ifndef NOINET6 315 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 316 #endif 317 int s, sz; 318 319 if (server.cfg.port == port) 320 server_Close(bundle); 321 322 if (port == 0) 323 return SERVER_INVALID; 324 325 memset(&ss, '\0', sizeof ss); 326 #ifndef NOINET6 327 if (probe.ipv6_available) { 328 sin6->sin6_family = AF_INET6; 329 sin6->sin6_port = htons(port); 330 sin6->sin6_len = (u_int8_t)sizeof ss; 331 sz = sizeof *sin6; 332 s = socket(PF_INET6, SOCK_STREAM, 0); 333 } else 334 #endif 335 { 336 sin->sin_family = AF_INET; 337 sin->sin_port = htons(port); 338 sin->sin_len = (u_int8_t)sizeof ss; 339 sin->sin_addr.s_addr = INADDR_ANY; 340 sz = sizeof *sin; 341 s = socket(PF_INET, SOCK_STREAM, 0); 342 } 343 344 if (s < 0) { 345 log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 346 goto failed; 347 } 348 349 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 350 if (bind(s, (struct sockaddr *)&ss, sz) < 0) { 351 log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 352 close(s); 353 goto failed; 354 } 355 if (listen(s, 5) != 0) { 356 log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 357 strerror(errno)); 358 close(s); 359 goto failed; 360 } 361 server_Close(bundle); 362 server.fd = s; 363 server.cfg.port = port; 364 *server.cfg.sockname = '\0'; 365 server.cfg.mask = 0; 366 log_Printf(LogPHASE, "Listening at port %d.\n", port); 367 return SERVER_OK; 368 369 failed: 370 if (server.fd == -1) { 371 server.fd = -1; 372 server.cfg.port = port; 373 *server.cfg.sockname = '\0'; 374 server.cfg.mask = 0; 375 } 376 return SERVER_FAILED; 377 } 378 379 int 380 server_Close(struct bundle *bundle __unused) 381 { 382 if (server.fd >= 0) { 383 if (*server.cfg.sockname != '\0') { 384 struct sockaddr_un un; 385 int sz = sizeof un; 386 387 if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 388 un.sun_family == AF_LOCAL && sz == sizeof un) 389 unlink(un.sun_path); 390 } 391 close(server.fd); 392 server.fd = -1; 393 /* Drop associated prompts */ 394 log_DestroyPrompts(&server); 395 396 return 1; 397 } 398 399 return 0; 400 } 401 402 int 403 server_Clear(struct bundle *bundle) 404 { 405 int ret; 406 407 ret = server_Close(bundle); 408 409 server.fd = -1; 410 server.cfg.port = 0; 411 *server.cfg.sockname = '\0'; 412 server.cfg.mask = 0; 413 414 return ret; 415 } 416