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: releng/11.0/usr.sbin/ppp/server.c 277857 2015-01-28 21:33:49Z dim $ 2730715Sbrian */ 2830715Sbrian 2971657Sbrian#include <sys/param.h> 3071657Sbrian 3126940Sbrian#include <sys/socket.h> 3226940Sbrian#include <netinet/in.h> 3336285Sbrian#include <sys/un.h> 3430715Sbrian 3530715Sbrian#include <errno.h> 36102500Sbrian#include <stdarg.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" 4636285Sbrian#include "prompt.h" 4781634Sbrian#include "ncpaddr.h" 4881900Sbrian#include "probe.h" 4926940Sbrian 5036285Sbrianstatic int 5158028Sbrianserver_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 5236285Sbrian{ 5336285Sbrian struct server *s = descriptor2server(d); 5436314Sbrian struct prompt *p; 5536314Sbrian int sets; 5630715Sbrian 5736314Sbrian sets = 0; 5836285Sbrian if (r && s->fd >= 0) { 5936285Sbrian if (*n < s->fd + 1) 6036285Sbrian *n = s->fd + 1; 6136285Sbrian FD_SET(s->fd, r); 6236285Sbrian log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 6336314Sbrian sets++; 6436285Sbrian } 6536314Sbrian 6636314Sbrian for (p = log_PromptList(); p; p = p->next) 6736314Sbrian sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 6836314Sbrian 6936314Sbrian return sets; 7036285Sbrian} 7126940Sbrian 7236285Sbrianstatic int 7358028Sbrianserver_IsSet(struct fdescriptor *d, const fd_set *fdset) 7436285Sbrian{ 7536285Sbrian struct server *s = descriptor2server(d); 7636314Sbrian struct prompt *p; 7736314Sbrian 7836314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 7936314Sbrian return 1; 8036314Sbrian 8136314Sbrian for (p = log_PromptList(); p; p = p->next) 8236314Sbrian if (descriptor_IsSet(&p->desc, fdset)) 8336314Sbrian return 1; 8436314Sbrian 8536314Sbrian return 0; 8636285Sbrian} 8736285Sbrian 8836285Sbrianstatic void 8958028Sbrianserver_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 9036285Sbrian{ 9136285Sbrian struct server *s = descriptor2server(d); 9281634Sbrian struct sockaddr_storage ss; 9381634Sbrian struct sockaddr *sa = (struct sockaddr *)&ss; 9481634Sbrian struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 9581634Sbrian#ifndef NOINET6 9681634Sbrian struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 9781634Sbrian#endif 9881634Sbrian int ssize = sizeof ss, wfd; 9936285Sbrian struct prompt *p; 10081634Sbrian struct ncpaddr addr; 10136285Sbrian 10236314Sbrian if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 10336314Sbrian wfd = accept(s->fd, sa, &ssize); 10436314Sbrian if (wfd < 0) 10536314Sbrian log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 10672436Sbrian else if (sa->sa_len == 0) { 10772436Sbrian close(wfd); 10872436Sbrian wfd = -1; 10972436Sbrian } 11036314Sbrian } else 11136314Sbrian wfd = -1; 11236285Sbrian 11336314Sbrian if (wfd >= 0) 11436285Sbrian switch (sa->sa_family) { 11536285Sbrian case AF_LOCAL: 11636314Sbrian log_Printf(LogPHASE, "Connected to local client.\n"); 11736285Sbrian break; 11836314Sbrian 11936285Sbrian case AF_INET: 12081634Sbrian ncpaddr_setsa(&addr, sa); 12181634Sbrian if (ntohs(sin->sin_port) < 1024) { 12236314Sbrian log_Printf(LogALERT, "Rejected client connection from %s:%u" 12336314Sbrian "(invalid port number) !\n", 12481634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 12536314Sbrian close(wfd); 12636314Sbrian wfd = -1; 12736314Sbrian break; 12836314Sbrian } 12936314Sbrian log_Printf(LogPHASE, "Connected to client from %s:%u\n", 13081634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 13136285Sbrian break; 13236314Sbrian 13381634Sbrian#ifndef NOINET6 13481634Sbrian case AF_INET6: 13581634Sbrian ncpaddr_setsa(&addr, sa); 13681634Sbrian if (ntohs(sin6->sin6_port) < 1024) { 13781634Sbrian log_Printf(LogALERT, "Rejected client connection from %s:%u" 13881634Sbrian "(invalid port number) !\n", 13981634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 14081634Sbrian close(wfd); 14181634Sbrian wfd = -1; 14281634Sbrian break; 14381634Sbrian } 14481634Sbrian log_Printf(LogPHASE, "Connected to client from %s:%u\n", 14581634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 14681634Sbrian break; 14781634Sbrian#endif 14881634Sbrian 14936314Sbrian default: 15036314Sbrian write(wfd, "Unrecognised access !\n", 22); 15136314Sbrian close(wfd); 15236314Sbrian wfd = -1; 15336314Sbrian break; 15436285Sbrian } 15536314Sbrian 15636314Sbrian if (wfd >= 0) { 15736314Sbrian if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 15836314Sbrian write(wfd, "Connection refused.\n", 20); 15936314Sbrian close(wfd); 16036314Sbrian } else { 16136314Sbrian switch (sa->sa_family) { 16236314Sbrian case AF_LOCAL: 16336314Sbrian p->src.type = "local"; 16471657Sbrian strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1); 16536314Sbrian p->src.from[sizeof p->src.from - 1] = '\0'; 16636314Sbrian break; 16736314Sbrian case AF_INET: 16881634Sbrian p->src.type = "ip"; 16936314Sbrian snprintf(p->src.from, sizeof p->src.from, "%s:%u", 17081634Sbrian ncpaddr_ntoa(&addr), ntohs(sin->sin_port)); 17136314Sbrian break; 17281634Sbrian#ifndef NOINET6 17381634Sbrian case AF_INET6: 17481634Sbrian p->src.type = "ip6"; 17581634Sbrian snprintf(p->src.from, sizeof p->src.from, "%s:%u", 17681634Sbrian ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port)); 17781634Sbrian break; 17881634Sbrian#endif 17936314Sbrian } 18036314Sbrian prompt_TtyCommandMode(p); 18136314Sbrian prompt_Required(p); 18236314Sbrian } 18336285Sbrian } 18436314Sbrian 18538013Sbrian log_PromptListChanged = 0; 18636314Sbrian for (p = log_PromptList(); p; p = p->next) 18738013Sbrian if (descriptor_IsSet(&p->desc, fdset)) { 18836314Sbrian descriptor_Read(&p->desc, bundle, fdset); 18938013Sbrian if (log_PromptListChanged) 19038013Sbrian break; 19138013Sbrian } 19236285Sbrian} 19336285Sbrian 19437141Sbrianstatic int 195134789Sbrianserver_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 196134789Sbrian const fd_set *fdset __unused) 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 }, 211134789Sbrian -1, 212134789Sbrian { "", "", 0, 0 } 21336285Sbrian}; 21436285Sbrian 21571657Sbrianenum server_stat 21671657Sbrianserver_Reopen(struct bundle *bundle) 21771657Sbrian{ 21871657Sbrian char name[sizeof server.cfg.sockname]; 21971764Sbrian struct stat st; 22071657Sbrian u_short port; 22171657Sbrian mode_t mask; 22271657Sbrian enum server_stat ret; 22371657Sbrian 22471657Sbrian if (server.cfg.sockname[0] != '\0') { 22571657Sbrian strcpy(name, server.cfg.sockname); 22671657Sbrian mask = server.cfg.mask; 22771657Sbrian server_Close(bundle); 22871764Sbrian if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0) 22971764Sbrian if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0) 23071764Sbrian return SERVER_FAILED; 23171657Sbrian ret = server_LocalOpen(bundle, name, mask); 23271657Sbrian } else if (server.cfg.port != 0) { 23371657Sbrian port = server.cfg.port; 23471657Sbrian server_Close(bundle); 23571657Sbrian ret = server_TcpOpen(bundle, port); 23671657Sbrian } else 23771657Sbrian ret = SERVER_UNSET; 23871657Sbrian 23971657Sbrian return ret; 24071657Sbrian} 24171657Sbrian 24271657Sbrianenum server_stat 24336285Sbrianserver_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 24426940Sbrian{ 24571657Sbrian struct sockaddr_un ifsun; 24671657Sbrian mode_t oldmask; 24728679Sbrian int s; 24826940Sbrian 24971657Sbrian oldmask = (mode_t)-1; /* Silence compiler */ 25029083Sbrian 251277857Sdim if (server.cfg.sockname[0] != '\0' && !strcmp(server.cfg.sockname, name)) 25271657Sbrian server_Close(bundle); 25371657Sbrian 25471657Sbrian memset(&ifsun, '\0', sizeof ifsun); 25571657Sbrian ifsun.sun_len = strlen(name); 25671657Sbrian if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { 25736285Sbrian log_Printf(LogERROR, "Local: %s: Path too long\n", name); 25871657Sbrian return SERVER_INVALID; 25928679Sbrian } 26071657Sbrian ifsun.sun_family = AF_LOCAL; 26171657Sbrian strcpy(ifsun.sun_path, name); 26226940Sbrian 26389422Sbrian s = socket(PF_LOCAL, SOCK_STREAM, 0); 26428679Sbrian if (s < 0) { 26536285Sbrian log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 26671657Sbrian goto failed; 26728679Sbrian } 26828679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 26931081Sbrian if (mask != (mode_t)-1) 27071657Sbrian oldmask = umask(mask); 27171657Sbrian if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { 27231081Sbrian if (mask != (mode_t)-1) 27371657Sbrian umask(oldmask); 27436285Sbrian log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 27528679Sbrian close(s); 27671657Sbrian goto failed; 27728679Sbrian } 27831081Sbrian if (mask != (mode_t)-1) 27971657Sbrian umask(oldmask); 28028679Sbrian if (listen(s, 5) != 0) { 28167912Sbrian log_Printf(LogERROR, "Local: Unable to listen to socket -" 28267912Sbrian " BUNDLE overload?\n"); 28328679Sbrian close(s); 28471657Sbrian unlink(name); 28571657Sbrian goto failed; 28628679Sbrian } 28744588Sbrian server_Close(bundle); 28836285Sbrian server.fd = s; 28971657Sbrian server.cfg.port = 0; 29071657Sbrian strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1); 29171657Sbrian server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 29271657Sbrian server.cfg.mask = mask; 29336285Sbrian log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 29471657Sbrian 29571657Sbrian return SERVER_OK; 29671657Sbrian 29771657Sbrianfailed: 29871657Sbrian if (server.fd == -1) { 29971657Sbrian server.fd = -1; 30071657Sbrian server.cfg.port = 0; 30171657Sbrian strncpy(server.cfg.sockname, ifsun.sun_path, 30271657Sbrian sizeof server.cfg.sockname - 1); 30371657Sbrian server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 30471657Sbrian server.cfg.mask = mask; 30571657Sbrian } 30671657Sbrian return SERVER_FAILED; 30726940Sbrian} 30826940Sbrian 30971657Sbrianenum server_stat 31071657Sbrianserver_TcpOpen(struct bundle *bundle, u_short port) 31126940Sbrian{ 31281634Sbrian struct sockaddr_storage ss; 31381634Sbrian struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 31481900Sbrian#ifndef NOINET6 31581634Sbrian struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 31681634Sbrian#endif 31781634Sbrian int s, sz; 31826940Sbrian 31971657Sbrian if (server.cfg.port == port) 32071657Sbrian server_Close(bundle); 32129252Sbrian 32271657Sbrian if (port == 0) 32371657Sbrian return SERVER_INVALID; 32471657Sbrian 32581634Sbrian memset(&ss, '\0', sizeof ss); 32681900Sbrian#ifndef NOINET6 32781900Sbrian if (probe.ipv6_available) { 32881900Sbrian sin6->sin6_family = AF_INET6; 32981900Sbrian sin6->sin6_port = htons(port); 33081924Sbrian sin6->sin6_len = (u_int8_t)sizeof ss; 33181900Sbrian sz = sizeof *sin6; 33289422Sbrian s = socket(PF_INET6, SOCK_STREAM, 0); 33381900Sbrian } else 33481634Sbrian#endif 33581900Sbrian { 33681900Sbrian sin->sin_family = AF_INET; 33781900Sbrian sin->sin_port = htons(port); 33881924Sbrian sin->sin_len = (u_int8_t)sizeof ss; 33981900Sbrian sin->sin_addr.s_addr = INADDR_ANY; 34081900Sbrian sz = sizeof *sin; 34189422Sbrian s = socket(PF_INET, SOCK_STREAM, 0); 34281900Sbrian } 34381900Sbrian 34428679Sbrian if (s < 0) { 34536285Sbrian log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 34671657Sbrian goto failed; 34728679Sbrian } 34881634Sbrian 349162389Sume#ifndef NOINET6 350162389Sume if (probe.ipv6_available) { 351162389Sume int off = 0; 352162389Sume setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); 353162389Sume } 354162389Sume#endif 355162389Sume 35628679Sbrian setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 35781634Sbrian if (bind(s, (struct sockaddr *)&ss, sz) < 0) { 35836285Sbrian log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 35928679Sbrian close(s); 36071657Sbrian goto failed; 36128679Sbrian } 36228679Sbrian if (listen(s, 5) != 0) { 36344588Sbrian log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 36444588Sbrian strerror(errno)); 36528679Sbrian close(s); 36671657Sbrian goto failed; 36728679Sbrian } 36836285Sbrian server_Close(bundle); 36936285Sbrian server.fd = s; 37071657Sbrian server.cfg.port = port; 37171657Sbrian *server.cfg.sockname = '\0'; 37271657Sbrian server.cfg.mask = 0; 37336285Sbrian log_Printf(LogPHASE, "Listening at port %d.\n", port); 37471657Sbrian return SERVER_OK; 37571657Sbrian 37671657Sbrianfailed: 37771657Sbrian if (server.fd == -1) { 37871657Sbrian server.fd = -1; 37971657Sbrian server.cfg.port = port; 38071657Sbrian *server.cfg.sockname = '\0'; 38171657Sbrian server.cfg.mask = 0; 38271657Sbrian } 38371657Sbrian return SERVER_FAILED; 38426940Sbrian} 38526940Sbrian 38636285Sbrianint 387134789Sbrianserver_Close(struct bundle *bundle __unused) 38826940Sbrian{ 38936285Sbrian if (server.fd >= 0) { 39071657Sbrian if (*server.cfg.sockname != '\0') { 39144588Sbrian struct sockaddr_un un; 39244588Sbrian int sz = sizeof un; 39344588Sbrian 39444588Sbrian if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 39544588Sbrian un.sun_family == AF_LOCAL && sz == sizeof un) 39671657Sbrian unlink(un.sun_path); 39726940Sbrian } 39844588Sbrian close(server.fd); 39936285Sbrian server.fd = -1; 40036285Sbrian /* Drop associated prompts */ 40136314Sbrian log_DestroyPrompts(&server); 40271657Sbrian 40336285Sbrian return 1; 40426940Sbrian } 40571657Sbrian 40636285Sbrian return 0; 40726940Sbrian} 40871657Sbrian 40971657Sbrianint 41071657Sbrianserver_Clear(struct bundle *bundle) 41171657Sbrian{ 41271657Sbrian int ret; 41371657Sbrian 41471657Sbrian ret = server_Close(bundle); 41571657Sbrian 41671657Sbrian server.fd = -1; 41771657Sbrian server.cfg.port = 0; 41871657Sbrian *server.cfg.sockname = '\0'; 41971657Sbrian server.cfg.mask = 0; 42071657Sbrian 42171657Sbrian return ret; 42271657Sbrian} 423