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$ 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 50 static int 51 server_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 72 static int 73 server_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 88 static void 89 server_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 194 static int 195 server_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 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 #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 376 failed: 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 386 int 387 server_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 409 int 410 server_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