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 <arpa/inet.h> 34 #include <sys/un.h> 35 36 #include <errno.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 "id.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, struct bundle *bundle, const fd_set *fdset) 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 }; 213 214 enum server_stat 215 server_Reopen(struct bundle *bundle) 216 { 217 char name[sizeof server.cfg.sockname]; 218 struct stat st; 219 u_short port; 220 mode_t mask; 221 enum server_stat ret; 222 223 if (server.cfg.sockname[0] != '\0') { 224 strcpy(name, server.cfg.sockname); 225 mask = server.cfg.mask; 226 server_Close(bundle); 227 if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0) 228 if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0) 229 return SERVER_FAILED; 230 ret = server_LocalOpen(bundle, name, mask); 231 } else if (server.cfg.port != 0) { 232 port = server.cfg.port; 233 server_Close(bundle); 234 ret = server_TcpOpen(bundle, port); 235 } else 236 ret = SERVER_UNSET; 237 238 return ret; 239 } 240 241 enum server_stat 242 server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 243 { 244 struct sockaddr_un ifsun; 245 mode_t oldmask; 246 int s; 247 248 oldmask = (mode_t)-1; /* Silence compiler */ 249 250 if (server.cfg.sockname && !strcmp(server.cfg.sockname, name)) 251 server_Close(bundle); 252 253 memset(&ifsun, '\0', sizeof ifsun); 254 ifsun.sun_len = strlen(name); 255 if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { 256 log_Printf(LogERROR, "Local: %s: Path too long\n", name); 257 return SERVER_INVALID; 258 } 259 ifsun.sun_family = AF_LOCAL; 260 strcpy(ifsun.sun_path, name); 261 262 s = socket(PF_LOCAL, SOCK_STREAM, 0); 263 if (s < 0) { 264 log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 265 goto failed; 266 } 267 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 268 if (mask != (mode_t)-1) 269 oldmask = umask(mask); 270 if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { 271 if (mask != (mode_t)-1) 272 umask(oldmask); 273 log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 274 close(s); 275 goto failed; 276 } 277 if (mask != (mode_t)-1) 278 umask(oldmask); 279 if (listen(s, 5) != 0) { 280 log_Printf(LogERROR, "Local: Unable to listen to socket -" 281 " BUNDLE overload?\n"); 282 close(s); 283 unlink(name); 284 goto failed; 285 } 286 server_Close(bundle); 287 server.fd = s; 288 server.cfg.port = 0; 289 strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1); 290 server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 291 server.cfg.mask = mask; 292 log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 293 294 return SERVER_OK; 295 296 failed: 297 if (server.fd == -1) { 298 server.fd = -1; 299 server.cfg.port = 0; 300 strncpy(server.cfg.sockname, ifsun.sun_path, 301 sizeof server.cfg.sockname - 1); 302 server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 303 server.cfg.mask = mask; 304 } 305 return SERVER_FAILED; 306 } 307 308 enum server_stat 309 server_TcpOpen(struct bundle *bundle, u_short port) 310 { 311 struct sockaddr_storage ss; 312 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 313 #ifndef NOINET6 314 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 315 #endif 316 int s, sz; 317 318 if (server.cfg.port == port) 319 server_Close(bundle); 320 321 if (port == 0) 322 return SERVER_INVALID; 323 324 memset(&ss, '\0', sizeof ss); 325 #ifndef NOINET6 326 if (probe.ipv6_available) { 327 sin6->sin6_family = AF_INET6; 328 sin6->sin6_port = htons(port); 329 sin6->sin6_len = (u_int8_t)sizeof ss; 330 sz = sizeof *sin6; 331 s = socket(PF_INET6, SOCK_STREAM, 0); 332 } else 333 #endif 334 { 335 sin->sin_family = AF_INET; 336 sin->sin_port = htons(port); 337 sin->sin_len = (u_int8_t)sizeof ss; 338 sin->sin_addr.s_addr = INADDR_ANY; 339 sz = sizeof *sin; 340 s = socket(PF_INET, SOCK_STREAM, 0); 341 } 342 343 if (s < 0) { 344 log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 345 goto failed; 346 } 347 348 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 349 if (bind(s, (struct sockaddr *)&ss, sz) < 0) { 350 log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 351 close(s); 352 goto failed; 353 } 354 if (listen(s, 5) != 0) { 355 log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 356 strerror(errno)); 357 close(s); 358 goto failed; 359 } 360 server_Close(bundle); 361 server.fd = s; 362 server.cfg.port = port; 363 *server.cfg.sockname = '\0'; 364 server.cfg.mask = 0; 365 log_Printf(LogPHASE, "Listening at port %d.\n", port); 366 return SERVER_OK; 367 368 failed: 369 if (server.fd == -1) { 370 server.fd = -1; 371 server.cfg.port = port; 372 *server.cfg.sockname = '\0'; 373 server.cfg.mask = 0; 374 } 375 return SERVER_FAILED; 376 } 377 378 int 379 server_Close(struct bundle *bundle) 380 { 381 if (server.fd >= 0) { 382 if (*server.cfg.sockname != '\0') { 383 struct sockaddr_un un; 384 int sz = sizeof un; 385 386 if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 387 un.sun_family == AF_LOCAL && sz == sizeof un) 388 unlink(un.sun_path); 389 } 390 close(server.fd); 391 server.fd = -1; 392 /* Drop associated prompts */ 393 log_DestroyPrompts(&server); 394 395 return 1; 396 } 397 398 return 0; 399 } 400 401 int 402 server_Clear(struct bundle *bundle) 403 { 404 int ret; 405 406 ret = server_Close(bundle); 407 408 server.fd = -1; 409 server.cfg.port = 0; 410 *server.cfg.sockname = '\0'; 411 server.cfg.mask = 0; 412 413 return ret; 414 } 415