server.c revision 81924
131921Sbrian/*- 231921Sbrian * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 331921Sbrian * All rights reserved. 431921Sbrian * 531921Sbrian * Redistribution and use in source and binary forms, with or without 631921Sbrian * modification, are permitted provided that the following conditions 731921Sbrian * are met: 831921Sbrian * 1. Redistributions of source code must retain the above copyright 931921Sbrian * notice, this list of conditions and the following disclaimer. 1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1131921Sbrian * notice, this list of conditions and the following disclaimer in the 1231921Sbrian * documentation and/or other materials provided with the distribution. 1331921Sbrian * 1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1731921Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2431921Sbrian * SUCH DAMAGE. 2531921Sbrian * 2650479Speter * $FreeBSD: head/usr.sbin/ppp/server.c 81924 2001-08-19 22:23:28Z brian $ 2730715Sbrian */ 2830715Sbrian 2971657Sbrian#include <sys/param.h> 3071657Sbrian 3126940Sbrian#include <sys/socket.h> 3226940Sbrian#include <netinet/in.h> 3326940Sbrian#include <arpa/inet.h> 3436285Sbrian#include <sys/un.h> 3530715Sbrian 3630715Sbrian#include <errno.h> 3730715Sbrian#include <stdio.h> 3826940Sbrian#include <string.h> 3930715Sbrian#include <sys/stat.h> 4036285Sbrian#include <termios.h> 4126940Sbrian#include <unistd.h> 4230715Sbrian 4326940Sbrian#include "log.h" 4436285Sbrian#include "descriptor.h" 4526940Sbrian#include "server.h" 4631061Sbrian#include "id.h" 4736285Sbrian#include "prompt.h" 4881634Sbrian#include "ncpaddr.h" 4981900Sbrian#include "probe.h" 5026940Sbrian 5136285Sbrianstatic int 5258028Sbrianserver_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 5336285Sbrian{ 5436285Sbrian struct server *s = descriptor2server(d); 5536314Sbrian struct prompt *p; 5636314Sbrian int sets; 5730715Sbrian 5836314Sbrian sets = 0; 5936285Sbrian if (r && s->fd >= 0) { 6036285Sbrian if (*n < s->fd + 1) 6136285Sbrian *n = s->fd + 1; 6236285Sbrian FD_SET(s->fd, r); 6336285Sbrian log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 6436314Sbrian sets++; 6536285Sbrian } 6636314Sbrian 6736314Sbrian for (p = log_PromptList(); p; p = p->next) 6836314Sbrian sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 6936314Sbrian 7036314Sbrian return sets; 7136285Sbrian} 7226940Sbrian 7336285Sbrianstatic int 7458028Sbrianserver_IsSet(struct fdescriptor *d, const fd_set *fdset) 7536285Sbrian{ 7636285Sbrian struct server *s = descriptor2server(d); 7736314Sbrian struct prompt *p; 7836314Sbrian 7936314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 8036314Sbrian return 1; 8136314Sbrian 8236314Sbrian for (p = log_PromptList(); p; p = p->next) 8336314Sbrian if (descriptor_IsSet(&p->desc, fdset)) 8436314Sbrian return 1; 8536314Sbrian 8636314Sbrian return 0; 8736285Sbrian} 8836285Sbrian 8936285Sbrianstatic void 9058028Sbrianserver_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 9136285Sbrian{ 9236285Sbrian struct server *s = descriptor2server(d); 9381634Sbrian struct sockaddr_storage ss; 9481634Sbrian struct sockaddr *sa = (struct sockaddr *)&ss; 9581634Sbrian struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 9681634Sbrian#ifndef NOINET6 9781634Sbrian struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 9881634Sbrian#endif 9981634Sbrian int ssize = sizeof ss, wfd; 10036285Sbrian struct prompt *p; 10181634Sbrian struct ncpaddr addr; 10236285Sbrian 10336314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 10436314Sbrian wfd = accept(s->fd, sa, &ssize); 10536314Sbrian if (wfd < 0) 10636314Sbrian log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 10772436Sbrian else if (sa->sa_len == 0) { 10872436Sbrian close(wfd); 10972436Sbrian wfd = -1; 11072436Sbrian } 11136314Sbrian } else 11236314Sbrian wfd = -1; 11336285Sbrian 11436314Sbrian if (wfd >= 0) 11536285Sbrian switch (sa->sa_family) { 11636285Sbrian case AF_LOCAL: 11736314Sbrian log_Printf(LogPHASE, "Connected to local client.\n"); 11836285Sbrian break; 11936314Sbrian 12036285Sbrian case AF_INET: 12181634Sbrian ncpaddr_setsa(&addr, sa); 12281634Sbrian if (ntohs(sin->sin_port) < 1024) { 12336314Sbrian log_Printf(LogALERT, "Rejected client connection from %s:%u" 12436314Sbrian "(invalid port number) !\n", 12581634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 12636314Sbrian close(wfd); 12736314Sbrian wfd = -1; 12836314Sbrian break; 12936314Sbrian } 13036314Sbrian log_Printf(LogPHASE, "Connected to client from %s:%u\n", 13181634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 13236285Sbrian break; 13336314Sbrian 13481634Sbrian#ifndef NOINET6 13581634Sbrian case AF_INET6: 13681634Sbrian ncpaddr_setsa(&addr, sa); 13781634Sbrian if (ntohs(sin6->sin6_port) < 1024) { 13881634Sbrian log_Printf(LogALERT, "Rejected client connection from %s:%u" 13981634Sbrian "(invalid port number) !\n", 14081634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 14181634Sbrian close(wfd); 14281634Sbrian wfd = -1; 14381634Sbrian break; 14481634Sbrian } 14581634Sbrian log_Printf(LogPHASE, "Connected to client from %s:%u\n", 14681634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 14781634Sbrian break; 14881634Sbrian#endif 14981634Sbrian 15036314Sbrian default: 15136314Sbrian write(wfd, "Unrecognised access !\n", 22); 15236314Sbrian close(wfd); 15336314Sbrian wfd = -1; 15436314Sbrian break; 15536285Sbrian } 15636314Sbrian 15736314Sbrian if (wfd >= 0) { 15836314Sbrian if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 15936314Sbrian write(wfd, "Connection refused.\n", 20); 16036314Sbrian close(wfd); 16136314Sbrian } else { 16236314Sbrian switch (sa->sa_family) { 16336314Sbrian case AF_LOCAL: 16436314Sbrian p->src.type = "local"; 16571657Sbrian strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1); 16636314Sbrian p->src.from[sizeof p->src.from - 1] = '\0'; 16736314Sbrian break; 16836314Sbrian case AF_INET: 16981634Sbrian p->src.type = "ip"; 17036314Sbrian snprintf(p->src.from, sizeof p->src.from, "%s:%u", 17181634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 17236314Sbrian break; 17381634Sbrian#ifndef NOINET6 17481634Sbrian case AF_INET6: 17581634Sbrian p->src.type = "ip6"; 17681634Sbrian snprintf(p->src.from, sizeof p->src.from, "%s:%u", 17781634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 17881634Sbrian break; 17981634Sbrian#endif 18036314Sbrian } 18136314Sbrian prompt_TtyCommandMode(p); 18236314Sbrian prompt_Required(p); 18336314Sbrian } 18436285Sbrian } 18536314Sbrian 18638013Sbrian log_PromptListChanged = 0; 18736314Sbrian for (p = log_PromptList(); p; p = p->next) 18838013Sbrian if (descriptor_IsSet(&p->desc, fdset)) { 18936314Sbrian descriptor_Read(&p->desc, bundle, fdset); 19038013Sbrian if (log_PromptListChanged) 19138013Sbrian break; 19238013Sbrian } 19336285Sbrian} 19436285Sbrian 19537141Sbrianstatic int 19658028Sbrianserver_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 19736285Sbrian{ 19836285Sbrian /* We never want to write here ! */ 19937019Sbrian log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n"); 20037141Sbrian return 0; 20136285Sbrian} 20236285Sbrian 20336285Sbrianstruct server server = { 20436285Sbrian { 20536285Sbrian SERVER_DESCRIPTOR, 20636285Sbrian server_UpdateSet, 20736285Sbrian server_IsSet, 20836285Sbrian server_Read, 20936285Sbrian server_Write 21036285Sbrian }, 21136285Sbrian -1 21236285Sbrian}; 21336285Sbrian 21471657Sbrianenum server_stat 21571657Sbrianserver_Reopen(struct bundle *bundle) 21671657Sbrian{ 21771657Sbrian char name[sizeof server.cfg.sockname]; 21871764Sbrian struct stat st; 21971657Sbrian u_short port; 22071657Sbrian mode_t mask; 22171657Sbrian enum server_stat ret; 22271657Sbrian 22371657Sbrian if (server.cfg.sockname[0] != '\0') { 22471657Sbrian strcpy(name, server.cfg.sockname); 22571657Sbrian mask = server.cfg.mask; 22671657Sbrian server_Close(bundle); 22771764Sbrian if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0) 22871764Sbrian if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0) 22971764Sbrian return SERVER_FAILED; 23071657Sbrian ret = server_LocalOpen(bundle, name, mask); 23171657Sbrian } else if (server.cfg.port != 0) { 23271657Sbrian port = server.cfg.port; 23371657Sbrian server_Close(bundle); 23471657Sbrian ret = server_TcpOpen(bundle, port); 23571657Sbrian } else 23671657Sbrian ret = SERVER_UNSET; 23771657Sbrian 23871657Sbrian return ret; 23971657Sbrian} 24071657Sbrian 24171657Sbrianenum server_stat 24236285Sbrianserver_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 24326940Sbrian{ 24471657Sbrian struct sockaddr_un ifsun; 24571657Sbrian mode_t oldmask; 24628679Sbrian int s; 24726940Sbrian 24871657Sbrian oldmask = (mode_t)-1; /* Silence compiler */ 24929083Sbrian 25071657Sbrian if (server.cfg.sockname && !strcmp(server.cfg.sockname, name)) 25171657Sbrian server_Close(bundle); 25271657Sbrian 25371657Sbrian memset(&ifsun, '\0', sizeof ifsun); 25471657Sbrian ifsun.sun_len = strlen(name); 25571657Sbrian if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { 25636285Sbrian log_Printf(LogERROR, "Local: %s: Path too long\n", name); 25771657Sbrian return SERVER_INVALID; 25828679Sbrian } 25971657Sbrian ifsun.sun_family = AF_LOCAL; 26071657Sbrian strcpy(ifsun.sun_path, name); 26126940Sbrian 26271657Sbrian s = socket(PF_LOCAL, SOCK_STREAM, 0); 26328679Sbrian if (s < 0) { 26436285Sbrian log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 26571657Sbrian goto failed; 26628679Sbrian } 26728679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 26831081Sbrian if (mask != (mode_t)-1) 26971657Sbrian oldmask = umask(mask); 27071657Sbrian if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { 27131081Sbrian if (mask != (mode_t)-1) 27271657Sbrian umask(oldmask); 27336285Sbrian log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 27428679Sbrian close(s); 27571657Sbrian goto failed; 27628679Sbrian } 27731081Sbrian if (mask != (mode_t)-1) 27871657Sbrian umask(oldmask); 27928679Sbrian if (listen(s, 5) != 0) { 28067912Sbrian log_Printf(LogERROR, "Local: Unable to listen to socket -" 28167912Sbrian " BUNDLE overload?\n"); 28228679Sbrian close(s); 28371657Sbrian unlink(name); 28471657Sbrian goto failed; 28528679Sbrian } 28644588Sbrian server_Close(bundle); 28736285Sbrian server.fd = s; 28871657Sbrian server.cfg.port = 0; 28971657Sbrian strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1); 29071657Sbrian server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 29171657Sbrian server.cfg.mask = mask; 29236285Sbrian log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 29371657Sbrian 29471657Sbrian return SERVER_OK; 29571657Sbrian 29671657Sbrianfailed: 29771657Sbrian if (server.fd == -1) { 29871657Sbrian server.fd = -1; 29971657Sbrian server.cfg.port = 0; 30071657Sbrian strncpy(server.cfg.sockname, ifsun.sun_path, 30171657Sbrian sizeof server.cfg.sockname - 1); 30271657Sbrian server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 30371657Sbrian server.cfg.mask = mask; 30471657Sbrian } 30571657Sbrian return SERVER_FAILED; 30626940Sbrian} 30726940Sbrian 30871657Sbrianenum server_stat 30971657Sbrianserver_TcpOpen(struct bundle *bundle, u_short port) 31026940Sbrian{ 31181634Sbrian struct sockaddr_storage ss; 31281634Sbrian struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 31381900Sbrian#ifndef NOINET6 31481634Sbrian struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 31581634Sbrian#endif 31681634Sbrian int s, sz; 31726940Sbrian 31871657Sbrian if (server.cfg.port == port) 31971657Sbrian server_Close(bundle); 32029252Sbrian 32171657Sbrian if (port == 0) 32271657Sbrian return SERVER_INVALID; 32371657Sbrian 32481634Sbrian memset(&ss, '\0', sizeof ss); 32581900Sbrian#ifndef NOINET6 32681900Sbrian if (probe.ipv6_available) { 32781900Sbrian sin6->sin6_family = AF_INET6; 32881900Sbrian sin6->sin6_port = htons(port); 32981924Sbrian sin6->sin6_len = (u_int8_t)sizeof ss; 33081900Sbrian sz = sizeof *sin6; 33181900Sbrian s = socket(PF_INET6, SOCK_STREAM, 0); 33281900Sbrian } else 33381634Sbrian#endif 33481900Sbrian { 33581900Sbrian sin->sin_family = AF_INET; 33681900Sbrian sin->sin_port = htons(port); 33781924Sbrian sin->sin_len = (u_int8_t)sizeof ss; 33881900Sbrian sin->sin_addr.s_addr = INADDR_ANY; 33981900Sbrian sz = sizeof *sin; 34081900Sbrian s = socket(PF_INET, SOCK_STREAM, 0); 34181900Sbrian } 34281900Sbrian 34328679Sbrian if (s < 0) { 34436285Sbrian log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 34571657Sbrian goto failed; 34628679Sbrian } 34781634Sbrian 34828679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 34981634Sbrian if (bind(s, (struct sockaddr *)&ss, sz) < 0) { 35036285Sbrian log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 35128679Sbrian close(s); 35271657Sbrian goto failed; 35328679Sbrian } 35428679Sbrian if (listen(s, 5) != 0) { 35544588Sbrian log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 35644588Sbrian strerror(errno)); 35728679Sbrian close(s); 35871657Sbrian goto failed; 35928679Sbrian } 36036285Sbrian server_Close(bundle); 36136285Sbrian server.fd = s; 36271657Sbrian server.cfg.port = port; 36371657Sbrian *server.cfg.sockname = '\0'; 36471657Sbrian server.cfg.mask = 0; 36536285Sbrian log_Printf(LogPHASE, "Listening at port %d.\n", port); 36671657Sbrian return SERVER_OK; 36771657Sbrian 36871657Sbrianfailed: 36971657Sbrian if (server.fd == -1) { 37071657Sbrian server.fd = -1; 37171657Sbrian server.cfg.port = port; 37271657Sbrian *server.cfg.sockname = '\0'; 37371657Sbrian server.cfg.mask = 0; 37471657Sbrian } 37571657Sbrian return SERVER_FAILED; 37626940Sbrian} 37726940Sbrian 37836285Sbrianint 37936285Sbrianserver_Close(struct bundle *bundle) 38026940Sbrian{ 38136285Sbrian if (server.fd >= 0) { 38271657Sbrian if (*server.cfg.sockname != '\0') { 38344588Sbrian struct sockaddr_un un; 38444588Sbrian int sz = sizeof un; 38544588Sbrian 38644588Sbrian if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 38744588Sbrian un.sun_family == AF_LOCAL && sz == sizeof un) 38871657Sbrian unlink(un.sun_path); 38926940Sbrian } 39044588Sbrian close(server.fd); 39136285Sbrian server.fd = -1; 39236285Sbrian /* Drop associated prompts */ 39336314Sbrian log_DestroyPrompts(&server); 39471657Sbrian 39536285Sbrian return 1; 39626940Sbrian } 39771657Sbrian 39836285Sbrian return 0; 39926940Sbrian} 40071657Sbrian 40171657Sbrianint 40271657Sbrianserver_Clear(struct bundle *bundle) 40371657Sbrian{ 40471657Sbrian int ret; 40571657Sbrian 40671657Sbrian ret = server_Close(bundle); 40771657Sbrian 40871657Sbrian server.fd = -1; 40971657Sbrian server.cfg.port = 0; 41071657Sbrian *server.cfg.sockname = '\0'; 41171657Sbrian server.cfg.mask = 0; 41271657Sbrian 41371657Sbrian return ret; 41471657Sbrian} 415