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.44.14.1 2010/12/21 17:10:29 kensmith Exp $ 27 */ 28 29#include <sys/param.h> 30 31#include <sys/socket.h> 32#include <netinet/in.h> 33#include <sys/un.h> 34 35#include <errno.h> 36#include <stdarg.h> 37#include <stdio.h> 38#include <string.h> 39#include <sys/stat.h> 40#include <termios.h> 41#include <unistd.h> 42 43#include "log.h" 44#include "descriptor.h" 45#include "server.h" 46#include "prompt.h" 47#include "ncpaddr.h" 48#include "probe.h" 49 50static int 51server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 52{ 53 struct server *s = descriptor2server(d); 54 struct prompt *p; 55 int sets; 56 57 sets = 0; 58 if (r && s->fd >= 0) { 59 if (*n < s->fd + 1) 60 *n = s->fd + 1; 61 FD_SET(s->fd, r); 62 log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 63 sets++; 64 } 65 66 for (p = log_PromptList(); p; p = p->next) 67 sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 68 69 return sets; 70} 71 72static int 73server_IsSet(struct fdescriptor *d, const fd_set *fdset) 74{ 75 struct server *s = descriptor2server(d); 76 struct prompt *p; 77 78 if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 79 return 1; 80 81 for (p = log_PromptList(); p; p = p->next) 82 if (descriptor_IsSet(&p->desc, fdset)) 83 return 1; 84 85 return 0; 86} 87 88static void 89server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 90{ 91 struct server *s = descriptor2server(d); 92 struct sockaddr_storage ss; 93 struct sockaddr *sa = (struct sockaddr *)&ss; 94 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 95#ifndef NOINET6 96 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 97#endif 98 int ssize = sizeof ss, wfd; 99 struct prompt *p; 100 struct ncpaddr addr; 101 102 if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 103 wfd = accept(s->fd, sa, &ssize); 104 if (wfd < 0) 105 log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 106 else if (sa->sa_len == 0) { 107 close(wfd); 108 wfd = -1; 109 } 110 } else 111 wfd = -1; 112 113 if (wfd >= 0) 114 switch (sa->sa_family) { 115 case AF_LOCAL: 116 log_Printf(LogPHASE, "Connected to local client.\n"); 117 break; 118 119 case AF_INET: 120 ncpaddr_setsa(&addr, sa); 121 if (ntohs(sin->sin_port) < 1024) { 122 log_Printf(LogALERT, "Rejected client connection from %s:%u" 123 "(invalid port number) !\n", 124 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 125 close(wfd); 126 wfd = -1; 127 break; 128 } 129 log_Printf(LogPHASE, "Connected to client from %s:%u\n", 130 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 131 break; 132 133#ifndef NOINET6 134 case AF_INET6: 135 ncpaddr_setsa(&addr, sa); 136 if (ntohs(sin6->sin6_port) < 1024) { 137 log_Printf(LogALERT, "Rejected client connection from %s:%u" 138 "(invalid port number) !\n", 139 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 140 close(wfd); 141 wfd = -1; 142 break; 143 } 144 log_Printf(LogPHASE, "Connected to client from %s:%u\n", 145 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 146 break; 147#endif 148 149 default: 150 write(wfd, "Unrecognised access !\n", 22); 151 close(wfd); 152 wfd = -1; 153 break; 154 } 155 156 if (wfd >= 0) { 157 if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 158 write(wfd, "Connection refused.\n", 20); 159 close(wfd); 160 } else { 161 switch (sa->sa_family) { 162 case AF_LOCAL: 163 p->src.type = "local"; 164 strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1); 165 p->src.from[sizeof p->src.from - 1] = '\0'; 166 break; 167 case AF_INET: 168 p->src.type = "ip"; 169 snprintf(p->src.from, sizeof p->src.from, "%s:%u", 170 ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 171 break; 172#ifndef NOINET6 173 case AF_INET6: 174 p->src.type = "ip6"; 175 snprintf(p->src.from, sizeof p->src.from, "%s:%u", 176 ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 177 break; 178#endif 179 } 180 prompt_TtyCommandMode(p); 181 prompt_Required(p); 182 } 183 } 184 185 log_PromptListChanged = 0; 186 for (p = log_PromptList(); p; p = p->next) 187 if (descriptor_IsSet(&p->desc, fdset)) { 188 descriptor_Read(&p->desc, bundle, fdset); 189 if (log_PromptListChanged) 190 break; 191 } 192} 193 194static int 195server_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 196 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 203struct 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 215enum server_stat 216server_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 242enum server_stat 243server_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 297failed: 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 309enum server_stat 310server_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#ifndef NOINET6 350 if (probe.ipv6_available) { 351 int off = 0; 352 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); 353 } 354#endif 355 356 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 357 if (bind(s, (struct sockaddr *)&ss, sz) < 0) { 358 log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 359 close(s); 360 goto failed; 361 } 362 if (listen(s, 5) != 0) { 363 log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 364 strerror(errno)); 365 close(s); 366 goto failed; 367 } 368 server_Close(bundle); 369 server.fd = s; 370 server.cfg.port = port; 371 *server.cfg.sockname = '\0'; 372 server.cfg.mask = 0; 373 log_Printf(LogPHASE, "Listening at port %d.\n", port); 374 return SERVER_OK; 375 376failed: 377 if (server.fd == -1) { 378 server.fd = -1; 379 server.cfg.port = port; 380 *server.cfg.sockname = '\0'; 381 server.cfg.mask = 0; 382 } 383 return SERVER_FAILED; 384} 385 386int 387server_Close(struct bundle *bundle __unused) 388{ 389 if (server.fd >= 0) { 390 if (*server.cfg.sockname != '\0') { 391 struct sockaddr_un un; 392 int sz = sizeof un; 393 394 if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 395 un.sun_family == AF_LOCAL && sz == sizeof un) 396 unlink(un.sun_path); 397 } 398 close(server.fd); 399 server.fd = -1; 400 /* Drop associated prompts */ 401 log_DestroyPrompts(&server); 402 403 return 1; 404 } 405 406 return 0; 407} 408 409int 410server_Clear(struct bundle *bundle) 411{ 412 int ret; 413 414 ret = server_Close(bundle); 415 416 server.fd = -1; 417 server.cfg.port = 0; 418 *server.cfg.sockname = '\0'; 419 server.cfg.mask = 0; 420 421 return ret; 422} 423