server.c revision 50479
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 50479 1999-08-28 01:35:59Z peter $ 2730715Sbrian */ 2830715Sbrian 2936285Sbrian#include <sys/types.h> 3026940Sbrian#include <sys/socket.h> 3126940Sbrian#include <netinet/in.h> 3226940Sbrian#include <arpa/inet.h> 3336285Sbrian#include <sys/un.h> 3430715Sbrian 3530715Sbrian#include <errno.h> 3630715Sbrian#include <stdio.h> 3726940Sbrian#include <string.h> 3830715Sbrian#include <sys/stat.h> 3936285Sbrian#include <termios.h> 4026940Sbrian#include <unistd.h> 4130715Sbrian 4226940Sbrian#include "log.h" 4336285Sbrian#include "descriptor.h" 4426940Sbrian#include "server.h" 4531061Sbrian#include "id.h" 4636285Sbrian#include "prompt.h" 4726940Sbrian 4836285Sbrianstatic int 4936285Sbrianserver_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 5036285Sbrian{ 5136285Sbrian struct server *s = descriptor2server(d); 5236314Sbrian struct prompt *p; 5336314Sbrian int sets; 5430715Sbrian 5536314Sbrian sets = 0; 5636285Sbrian if (r && s->fd >= 0) { 5736285Sbrian if (*n < s->fd + 1) 5836285Sbrian *n = s->fd + 1; 5936285Sbrian FD_SET(s->fd, r); 6036285Sbrian log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 6136314Sbrian sets++; 6236285Sbrian } 6336314Sbrian 6436314Sbrian for (p = log_PromptList(); p; p = p->next) 6536314Sbrian sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 6636314Sbrian 6736314Sbrian return sets; 6836285Sbrian} 6926940Sbrian 7036285Sbrianstatic int 7136285Sbrianserver_IsSet(struct descriptor *d, const fd_set *fdset) 7236285Sbrian{ 7336285Sbrian struct server *s = descriptor2server(d); 7436314Sbrian struct prompt *p; 7536314Sbrian 7636314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 7736314Sbrian return 1; 7836314Sbrian 7936314Sbrian for (p = log_PromptList(); p; p = p->next) 8036314Sbrian if (descriptor_IsSet(&p->desc, fdset)) 8136314Sbrian return 1; 8236314Sbrian 8336314Sbrian return 0; 8436285Sbrian} 8536285Sbrian 8636285Sbrian#define IN_SIZE sizeof(struct sockaddr_in) 8736285Sbrian#define UN_SIZE sizeof(struct sockaddr_in) 8836285Sbrian#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE) 8936285Sbrian 9036285Sbrianstatic void 9136285Sbrianserver_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 9236285Sbrian{ 9336285Sbrian struct server *s = descriptor2server(d); 9436285Sbrian char hisaddr[ADDRSZ]; 9536285Sbrian struct sockaddr *sa = (struct sockaddr *)hisaddr; 9636285Sbrian struct sockaddr_in *in = (struct sockaddr_in *)hisaddr; 9736285Sbrian int ssize = ADDRSZ, wfd; 9836285Sbrian struct prompt *p; 9936285Sbrian 10036314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 10136314Sbrian wfd = accept(s->fd, sa, &ssize); 10236314Sbrian if (wfd < 0) 10336314Sbrian log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 10436314Sbrian } else 10536314Sbrian wfd = -1; 10636285Sbrian 10736314Sbrian if (wfd >= 0) 10836285Sbrian switch (sa->sa_family) { 10936285Sbrian case AF_LOCAL: 11036314Sbrian log_Printf(LogPHASE, "Connected to local client.\n"); 11136285Sbrian break; 11236314Sbrian 11336285Sbrian case AF_INET: 11436314Sbrian if (ntohs(in->sin_port) < 1024) { 11536314Sbrian log_Printf(LogALERT, "Rejected client connection from %s:%u" 11636314Sbrian "(invalid port number) !\n", 11736314Sbrian inet_ntoa(in->sin_addr), ntohs(in->sin_port)); 11836314Sbrian close(wfd); 11936314Sbrian wfd = -1; 12036314Sbrian break; 12136314Sbrian } 12236314Sbrian log_Printf(LogPHASE, "Connected to client from %s:%u\n", 12336314Sbrian inet_ntoa(in->sin_addr), in->sin_port); 12436285Sbrian break; 12536314Sbrian 12636314Sbrian default: 12736314Sbrian write(wfd, "Unrecognised access !\n", 22); 12836314Sbrian close(wfd); 12936314Sbrian wfd = -1; 13036314Sbrian break; 13136285Sbrian } 13236314Sbrian 13336314Sbrian if (wfd >= 0) { 13436314Sbrian if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 13536314Sbrian write(wfd, "Connection refused.\n", 20); 13636314Sbrian close(wfd); 13736314Sbrian } else { 13836314Sbrian switch (sa->sa_family) { 13936314Sbrian case AF_LOCAL: 14036314Sbrian p->src.type = "local"; 14136314Sbrian strncpy(p->src.from, s->rm, sizeof p->src.from - 1); 14236314Sbrian p->src.from[sizeof p->src.from - 1] = '\0'; 14336314Sbrian break; 14436314Sbrian case AF_INET: 14536314Sbrian p->src.type = "tcp"; 14636314Sbrian snprintf(p->src.from, sizeof p->src.from, "%s:%u", 14736314Sbrian inet_ntoa(in->sin_addr), in->sin_port); 14836314Sbrian break; 14936314Sbrian } 15036314Sbrian prompt_TtyCommandMode(p); 15136314Sbrian prompt_Required(p); 15236314Sbrian } 15336285Sbrian } 15436314Sbrian 15538013Sbrian log_PromptListChanged = 0; 15636314Sbrian for (p = log_PromptList(); p; p = p->next) 15738013Sbrian if (descriptor_IsSet(&p->desc, fdset)) { 15836314Sbrian descriptor_Read(&p->desc, bundle, fdset); 15938013Sbrian if (log_PromptListChanged) 16038013Sbrian break; 16138013Sbrian } 16236285Sbrian} 16336285Sbrian 16437141Sbrianstatic int 16536285Sbrianserver_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 16636285Sbrian{ 16736285Sbrian /* We never want to write here ! */ 16837019Sbrian log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n"); 16937141Sbrian return 0; 17036285Sbrian} 17136285Sbrian 17236285Sbrianstruct server server = { 17336285Sbrian { 17436285Sbrian SERVER_DESCRIPTOR, 17536285Sbrian server_UpdateSet, 17636285Sbrian server_IsSet, 17736285Sbrian server_Read, 17836285Sbrian server_Write 17936285Sbrian }, 18036285Sbrian -1 18136285Sbrian}; 18236285Sbrian 18326940Sbrianint 18436285Sbrianserver_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 18526940Sbrian{ 18628679Sbrian int s; 18726940Sbrian 18836285Sbrian if (server.rm && !strcmp(server.rm, name)) { 18936285Sbrian if (chmod(server.rm, mask)) 19036285Sbrian log_Printf(LogERROR, "Local: chmod: %s\n", strerror(errno)); 19136285Sbrian return 0; 19229083Sbrian } 19329083Sbrian 19436285Sbrian memset(&server.ifsun, '\0', sizeof server.ifsun); 19536285Sbrian server.ifsun.sun_len = strlen(name); 19636285Sbrian if (server.ifsun.sun_len > sizeof server.ifsun.sun_path - 1) { 19736285Sbrian log_Printf(LogERROR, "Local: %s: Path too long\n", name); 19829083Sbrian return 2; 19928679Sbrian } 20036285Sbrian server.ifsun.sun_family = AF_LOCAL; 20136285Sbrian strcpy(server.ifsun.sun_path, name); 20226940Sbrian 20331061Sbrian s = ID0socket(PF_LOCAL, SOCK_STREAM, 0); 20428679Sbrian if (s < 0) { 20536285Sbrian log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 20629083Sbrian return 3; 20728679Sbrian } 20828679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 20931081Sbrian if (mask != (mode_t)-1) 21031081Sbrian mask = umask(mask); 21136285Sbrian if (bind(s, (struct sockaddr *)&server.ifsun, sizeof server.ifsun) < 0) { 21231081Sbrian if (mask != (mode_t)-1) 21331081Sbrian umask(mask); 21436285Sbrian log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 21528679Sbrian close(s); 21629083Sbrian return 4; 21728679Sbrian } 21831081Sbrian if (mask != (mode_t)-1) 21931081Sbrian umask(mask); 22028679Sbrian if (listen(s, 5) != 0) { 22136285Sbrian log_Printf(LogERROR, "Local: Unable to listen to socket - BUNDLE overload?\n"); 22228679Sbrian close(s); 22331061Sbrian ID0unlink(name); 22429083Sbrian return 5; 22528679Sbrian } 22644588Sbrian server_Close(bundle); 22736285Sbrian server.fd = s; 22836285Sbrian server.rm = server.ifsun.sun_path; 22936285Sbrian log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 23028679Sbrian return 0; 23126940Sbrian} 23226940Sbrian 23326940Sbrianint 23436285Sbrianserver_TcpOpen(struct bundle *bundle, int port) 23526940Sbrian{ 23628679Sbrian struct sockaddr_in ifsin; 23728679Sbrian int s; 23826940Sbrian 23936285Sbrian if (server.port == port) 24036285Sbrian return 0; 24129252Sbrian 24231061Sbrian s = ID0socket(PF_INET, SOCK_STREAM, 0); 24328679Sbrian if (s < 0) { 24436285Sbrian log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 24529083Sbrian return 7; 24628679Sbrian } 24731914Sbrian memset(&ifsin, '\0', sizeof ifsin); 24828679Sbrian ifsin.sin_family = AF_INET; 24928679Sbrian ifsin.sin_addr.s_addr = INADDR_ANY; 25028679Sbrian ifsin.sin_port = htons(port); 25128679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 25231962Sbrian if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) { 25336285Sbrian log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 25428679Sbrian close(s); 25529083Sbrian return 8; 25628679Sbrian } 25728679Sbrian if (listen(s, 5) != 0) { 25844588Sbrian log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 25944588Sbrian strerror(errno)); 26028679Sbrian close(s); 26129083Sbrian return 9; 26228679Sbrian } 26336285Sbrian server_Close(bundle); 26436285Sbrian server.fd = s; 26536285Sbrian server.port = port; 26636285Sbrian log_Printf(LogPHASE, "Listening at port %d.\n", port); 26728679Sbrian return 0; 26826940Sbrian} 26926940Sbrian 27036285Sbrianint 27136285Sbrianserver_Close(struct bundle *bundle) 27226940Sbrian{ 27336285Sbrian if (server.fd >= 0) { 27436285Sbrian if (server.rm) { 27544588Sbrian struct sockaddr_un un; 27644588Sbrian int sz = sizeof un; 27744588Sbrian 27844588Sbrian if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 27944588Sbrian un.sun_family == AF_LOCAL && sz == sizeof un) 28044588Sbrian ID0unlink(un.sun_path); 28136285Sbrian server.rm = NULL; 28226940Sbrian } 28344588Sbrian close(server.fd); 28436285Sbrian server.fd = -1; 28536285Sbrian server.port = 0; 28636285Sbrian /* Drop associated prompts */ 28736314Sbrian log_DestroyPrompts(&server); 28836285Sbrian return 1; 28926940Sbrian } 29036285Sbrian return 0; 29126940Sbrian} 292