1c39934eaSBrian Somers /*- 2c39934eaSBrian Somers * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 3c39934eaSBrian Somers * All rights reserved. 4c39934eaSBrian Somers * 5c39934eaSBrian Somers * Redistribution and use in source and binary forms, with or without 6c39934eaSBrian Somers * modification, are permitted provided that the following conditions 7c39934eaSBrian Somers * are met: 8c39934eaSBrian Somers * 1. Redistributions of source code must retain the above copyright 9c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer. 10c39934eaSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 11c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer in the 12c39934eaSBrian Somers * documentation and/or other materials provided with the distribution. 13c39934eaSBrian Somers * 14c39934eaSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c39934eaSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c39934eaSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c39934eaSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c39934eaSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c39934eaSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c39934eaSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c39934eaSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c39934eaSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c39934eaSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c39934eaSBrian Somers * SUCH DAMAGE. 25c39934eaSBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 2775240ed1SBrian Somers */ 2875240ed1SBrian Somers 2974457d3dSBrian Somers #include <sys/param.h> 3074457d3dSBrian Somers 314ef16f24SBrian Somers #include <sys/socket.h> 324ef16f24SBrian Somers #include <netinet/in.h> 334ef16f24SBrian Somers #include <arpa/inet.h> 341fa665f5SBrian Somers #include <sys/un.h> 3575240ed1SBrian Somers 364ef16f24SBrian Somers #include <errno.h> 3775240ed1SBrian Somers #include <stdio.h> 3875240ed1SBrian Somers #include <string.h> 3975240ed1SBrian Somers #include <sys/stat.h> 4085b542cfSBrian Somers #include <termios.h> 414ef16f24SBrian Somers #include <unistd.h> 4275240ed1SBrian Somers 434ef16f24SBrian Somers #include "log.h" 4477ff88adSBrian Somers #include "descriptor.h" 454ef16f24SBrian Somers #include "server.h" 465106c671SBrian Somers #include "id.h" 4785b542cfSBrian Somers #include "prompt.h" 484ef16f24SBrian Somers 4977ff88adSBrian Somers static int 50f013f33eSBrian Somers server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 5177ff88adSBrian Somers { 5277ff88adSBrian Somers struct server *s = descriptor2server(d); 530f2f3eb3SBrian Somers struct prompt *p; 540f2f3eb3SBrian Somers int sets; 5575240ed1SBrian Somers 560f2f3eb3SBrian Somers sets = 0; 57b6dec9f0SBrian Somers if (r && s->fd >= 0) { 5877ff88adSBrian Somers if (*n < s->fd + 1) 5977ff88adSBrian Somers *n = s->fd + 1; 6085b542cfSBrian Somers FD_SET(s->fd, r); 6124989c68SBrian Somers log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); 620f2f3eb3SBrian Somers sets++; 6377ff88adSBrian Somers } 640f2f3eb3SBrian Somers 650f2f3eb3SBrian Somers for (p = log_PromptList(); p; p = p->next) 660f2f3eb3SBrian Somers sets += descriptor_UpdateSet(&p->desc, r, w, e, n); 670f2f3eb3SBrian Somers 680f2f3eb3SBrian Somers return sets; 6977ff88adSBrian Somers } 7077ff88adSBrian Somers 7177ff88adSBrian Somers static int 72f013f33eSBrian Somers server_IsSet(struct fdescriptor *d, const fd_set *fdset) 7377ff88adSBrian Somers { 7477ff88adSBrian Somers struct server *s = descriptor2server(d); 750f2f3eb3SBrian Somers struct prompt *p; 760f2f3eb3SBrian Somers 770f2f3eb3SBrian Somers if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) 780f2f3eb3SBrian Somers return 1; 790f2f3eb3SBrian Somers 800f2f3eb3SBrian Somers for (p = log_PromptList(); p; p = p->next) 810f2f3eb3SBrian Somers if (descriptor_IsSet(&p->desc, fdset)) 820f2f3eb3SBrian Somers return 1; 830f2f3eb3SBrian Somers 840f2f3eb3SBrian Somers return 0; 8577ff88adSBrian Somers } 8677ff88adSBrian Somers 8777ff88adSBrian Somers #define IN_SIZE sizeof(struct sockaddr_in) 88f84f2c00SBrian Somers #define UN_SIZE sizeof(struct sockaddr_un) 8977ff88adSBrian Somers #define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE) 9077ff88adSBrian Somers 9177ff88adSBrian Somers static void 92f013f33eSBrian Somers server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 9377ff88adSBrian Somers { 9477ff88adSBrian Somers struct server *s = descriptor2server(d); 9577ff88adSBrian Somers char hisaddr[ADDRSZ]; 9677ff88adSBrian Somers struct sockaddr *sa = (struct sockaddr *)hisaddr; 97cdbbb6b5SBrian Somers struct sockaddr_in *in = (struct sockaddr_in *)hisaddr; 9877ff88adSBrian Somers int ssize = ADDRSZ, wfd; 99b6217683SBrian Somers struct prompt *p; 10077ff88adSBrian Somers 1010f2f3eb3SBrian Somers if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { 10277ff88adSBrian Somers wfd = accept(s->fd, sa, &ssize); 1030f2f3eb3SBrian Somers if (wfd < 0) 104dd7e2610SBrian Somers log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); 1050f2f3eb3SBrian Somers } else 1060f2f3eb3SBrian Somers wfd = -1; 10777ff88adSBrian Somers 1080f2f3eb3SBrian Somers if (wfd >= 0) 10977ff88adSBrian Somers switch (sa->sa_family) { 11077ff88adSBrian Somers case AF_LOCAL: 111dd7e2610SBrian Somers log_Printf(LogPHASE, "Connected to local client.\n"); 11277ff88adSBrian Somers break; 11377ff88adSBrian Somers 11477ff88adSBrian Somers case AF_INET: 115cdbbb6b5SBrian Somers if (ntohs(in->sin_port) < 1024) { 116dd7e2610SBrian Somers log_Printf(LogALERT, "Rejected client connection from %s:%u" 11777ff88adSBrian Somers "(invalid port number) !\n", 118cdbbb6b5SBrian Somers inet_ntoa(in->sin_addr), ntohs(in->sin_port)); 11977ff88adSBrian Somers close(wfd); 1200f2f3eb3SBrian Somers wfd = -1; 1210f2f3eb3SBrian Somers break; 12277ff88adSBrian Somers } 123dd7e2610SBrian Somers log_Printf(LogPHASE, "Connected to client from %s:%u\n", 124cdbbb6b5SBrian Somers inet_ntoa(in->sin_addr), in->sin_port); 12577ff88adSBrian Somers break; 12677ff88adSBrian Somers 12777ff88adSBrian Somers default: 12877ff88adSBrian Somers write(wfd, "Unrecognised access !\n", 22); 12977ff88adSBrian Somers close(wfd); 1300f2f3eb3SBrian Somers wfd = -1; 1310f2f3eb3SBrian Somers break; 13277ff88adSBrian Somers } 13377ff88adSBrian Somers 1340f2f3eb3SBrian Somers if (wfd >= 0) { 135b6217683SBrian Somers if ((p = prompt_Create(s, bundle, wfd)) == NULL) { 136b6217683SBrian Somers write(wfd, "Connection refused.\n", 20); 13777ff88adSBrian Somers close(wfd); 13877ff88adSBrian Somers } else { 139b6217683SBrian Somers switch (sa->sa_family) { 140b6217683SBrian Somers case AF_LOCAL: 141565e35e5SBrian Somers p->src.type = "local"; 14274457d3dSBrian Somers strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1); 143565e35e5SBrian Somers p->src.from[sizeof p->src.from - 1] = '\0'; 144b6217683SBrian Somers break; 145b6217683SBrian Somers case AF_INET: 146565e35e5SBrian Somers p->src.type = "tcp"; 147565e35e5SBrian Somers snprintf(p->src.from, sizeof p->src.from, "%s:%u", 148cdbbb6b5SBrian Somers inet_ntoa(in->sin_addr), in->sin_port); 149b6217683SBrian Somers break; 150b6217683SBrian Somers } 151b6217683SBrian Somers prompt_TtyCommandMode(p); 152b6217683SBrian Somers prompt_Required(p); 15377ff88adSBrian Somers } 15477ff88adSBrian Somers } 15577ff88adSBrian Somers 1560bdcbcbeSBrian Somers log_PromptListChanged = 0; 1570f2f3eb3SBrian Somers for (p = log_PromptList(); p; p = p->next) 1580bdcbcbeSBrian Somers if (descriptor_IsSet(&p->desc, fdset)) { 1590f2f3eb3SBrian Somers descriptor_Read(&p->desc, bundle, fdset); 1600bdcbcbeSBrian Somers if (log_PromptListChanged) 1610bdcbcbeSBrian Somers break; 1620bdcbcbeSBrian Somers } 1630f2f3eb3SBrian Somers } 1640f2f3eb3SBrian Somers 1651af29a6eSBrian Somers static int 166f013f33eSBrian Somers server_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 16777ff88adSBrian Somers { 16877ff88adSBrian Somers /* We never want to write here ! */ 169a33b2ef7SBrian Somers log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n"); 1701af29a6eSBrian Somers return 0; 17177ff88adSBrian Somers } 17277ff88adSBrian Somers 17377ff88adSBrian Somers struct server server = { 17477ff88adSBrian Somers { 17577ff88adSBrian Somers SERVER_DESCRIPTOR, 17677ff88adSBrian Somers server_UpdateSet, 17777ff88adSBrian Somers server_IsSet, 17877ff88adSBrian Somers server_Read, 17977ff88adSBrian Somers server_Write 18077ff88adSBrian Somers }, 18177ff88adSBrian Somers -1 18277ff88adSBrian Somers }; 1834ef16f24SBrian Somers 18474457d3dSBrian Somers enum server_stat 18574457d3dSBrian Somers server_Reopen(struct bundle *bundle) 18674457d3dSBrian Somers { 18774457d3dSBrian Somers char name[sizeof server.cfg.sockname]; 18874457d3dSBrian Somers u_short port; 18974457d3dSBrian Somers mode_t mask; 19074457d3dSBrian Somers enum server_stat ret; 19174457d3dSBrian Somers 19274457d3dSBrian Somers if (server.cfg.sockname[0] != '\0') { 19374457d3dSBrian Somers strcpy(name, server.cfg.sockname); 19474457d3dSBrian Somers mask = server.cfg.mask; 19574457d3dSBrian Somers server_Close(bundle); 19674457d3dSBrian Somers if (server.cfg.sockname[0] != '\0') 19774457d3dSBrian Somers /* blow it away - and hope nobody else is using it */ 19874457d3dSBrian Somers unlink(server.cfg.sockname); 19974457d3dSBrian Somers ret = server_LocalOpen(bundle, name, mask); 20074457d3dSBrian Somers } else if (server.cfg.port != 0) { 20174457d3dSBrian Somers port = server.cfg.port; 20274457d3dSBrian Somers server_Close(bundle); 20374457d3dSBrian Somers ret = server_TcpOpen(bundle, port); 20474457d3dSBrian Somers } else 20574457d3dSBrian Somers ret = SERVER_UNSET; 20674457d3dSBrian Somers 20774457d3dSBrian Somers return ret; 20874457d3dSBrian Somers } 20974457d3dSBrian Somers 21074457d3dSBrian Somers enum server_stat 211dd7e2610SBrian Somers server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) 2124ef16f24SBrian Somers { 21374457d3dSBrian Somers struct sockaddr_un ifsun; 21474457d3dSBrian Somers mode_t oldmask; 2154ef16f24SBrian Somers int s; 2164ef16f24SBrian Somers 21774457d3dSBrian Somers oldmask = (mode_t)-1; /* Silence compiler */ 218683cef3cSBrian Somers 21974457d3dSBrian Somers if (server.cfg.sockname && !strcmp(server.cfg.sockname, name)) 22074457d3dSBrian Somers server_Close(bundle); 22174457d3dSBrian Somers 22274457d3dSBrian Somers memset(&ifsun, '\0', sizeof ifsun); 22374457d3dSBrian Somers ifsun.sun_len = strlen(name); 22474457d3dSBrian Somers if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { 225dd7e2610SBrian Somers log_Printf(LogERROR, "Local: %s: Path too long\n", name); 22674457d3dSBrian Somers return SERVER_INVALID; 2274ef16f24SBrian Somers } 22874457d3dSBrian Somers ifsun.sun_family = AF_LOCAL; 22974457d3dSBrian Somers strcpy(ifsun.sun_path, name); 2304ef16f24SBrian Somers 23174457d3dSBrian Somers s = socket(PF_LOCAL, SOCK_STREAM, 0); 2324ef16f24SBrian Somers if (s < 0) { 233dd7e2610SBrian Somers log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); 23474457d3dSBrian Somers goto failed; 2354ef16f24SBrian Somers } 2364ef16f24SBrian Somers setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 2378ea8442cSBrian Somers if (mask != (mode_t)-1) 23874457d3dSBrian Somers oldmask = umask(mask); 23974457d3dSBrian Somers if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { 2408ea8442cSBrian Somers if (mask != (mode_t)-1) 24174457d3dSBrian Somers umask(oldmask); 242dd7e2610SBrian Somers log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); 2434ef16f24SBrian Somers close(s); 24474457d3dSBrian Somers goto failed; 2454ef16f24SBrian Somers } 2468ea8442cSBrian Somers if (mask != (mode_t)-1) 24774457d3dSBrian Somers umask(oldmask); 2484ef16f24SBrian Somers if (listen(s, 5) != 0) { 2499b996792SBrian Somers log_Printf(LogERROR, "Local: Unable to listen to socket -" 2509b996792SBrian Somers " BUNDLE overload?\n"); 2514ef16f24SBrian Somers close(s); 25274457d3dSBrian Somers unlink(name); 25374457d3dSBrian Somers goto failed; 2544ef16f24SBrian Somers } 255661a0e90SBrian Somers server_Close(bundle); 25677ff88adSBrian Somers server.fd = s; 25774457d3dSBrian Somers server.cfg.port = 0; 25874457d3dSBrian Somers strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1); 25974457d3dSBrian Somers server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 26074457d3dSBrian Somers server.cfg.mask = mask; 261dd7e2610SBrian Somers log_Printf(LogPHASE, "Listening at local socket %s.\n", name); 26274457d3dSBrian Somers 26374457d3dSBrian Somers return SERVER_OK; 26474457d3dSBrian Somers 26574457d3dSBrian Somers failed: 26674457d3dSBrian Somers if (server.fd == -1) { 26774457d3dSBrian Somers server.fd = -1; 26874457d3dSBrian Somers server.cfg.port = 0; 26974457d3dSBrian Somers strncpy(server.cfg.sockname, ifsun.sun_path, 27074457d3dSBrian Somers sizeof server.cfg.sockname - 1); 27174457d3dSBrian Somers server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0'; 27274457d3dSBrian Somers server.cfg.mask = mask; 27374457d3dSBrian Somers } 27474457d3dSBrian Somers return SERVER_FAILED; 2754ef16f24SBrian Somers } 2764ef16f24SBrian Somers 27774457d3dSBrian Somers enum server_stat 27874457d3dSBrian Somers server_TcpOpen(struct bundle *bundle, u_short port) 2794ef16f24SBrian Somers { 2804ef16f24SBrian Somers struct sockaddr_in ifsin; 2814ef16f24SBrian Somers int s; 2824ef16f24SBrian Somers 28374457d3dSBrian Somers if (server.cfg.port == port) 28474457d3dSBrian Somers server_Close(bundle); 285d40f8a5aSBrian Somers 28674457d3dSBrian Somers if (port == 0) 28774457d3dSBrian Somers return SERVER_INVALID; 28874457d3dSBrian Somers 28974457d3dSBrian Somers s = socket(PF_INET, SOCK_STREAM, 0); 2904ef16f24SBrian Somers if (s < 0) { 291dd7e2610SBrian Somers log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); 29274457d3dSBrian Somers goto failed; 2934ef16f24SBrian Somers } 2942e14bb46SBrian Somers memset(&ifsin, '\0', sizeof ifsin); 2954ef16f24SBrian Somers ifsin.sin_family = AF_INET; 2964ef16f24SBrian Somers ifsin.sin_addr.s_addr = INADDR_ANY; 2974ef16f24SBrian Somers ifsin.sin_port = htons(port); 2984ef16f24SBrian Somers setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); 29970ee81ffSBrian Somers if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) { 300dd7e2610SBrian Somers log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); 3014ef16f24SBrian Somers close(s); 30274457d3dSBrian Somers goto failed; 3034ef16f24SBrian Somers } 3044ef16f24SBrian Somers if (listen(s, 5) != 0) { 305661a0e90SBrian Somers log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n", 306661a0e90SBrian Somers strerror(errno)); 3074ef16f24SBrian Somers close(s); 30874457d3dSBrian Somers goto failed; 3094ef16f24SBrian Somers } 310dd7e2610SBrian Somers server_Close(bundle); 31177ff88adSBrian Somers server.fd = s; 31274457d3dSBrian Somers server.cfg.port = port; 31374457d3dSBrian Somers *server.cfg.sockname = '\0'; 31474457d3dSBrian Somers server.cfg.mask = 0; 315dd7e2610SBrian Somers log_Printf(LogPHASE, "Listening at port %d.\n", port); 31674457d3dSBrian Somers return SERVER_OK; 31774457d3dSBrian Somers 31874457d3dSBrian Somers failed: 31974457d3dSBrian Somers if (server.fd == -1) { 32074457d3dSBrian Somers server.fd = -1; 32174457d3dSBrian Somers server.cfg.port = port; 32274457d3dSBrian Somers *server.cfg.sockname = '\0'; 32374457d3dSBrian Somers server.cfg.mask = 0; 32474457d3dSBrian Somers } 32574457d3dSBrian Somers return SERVER_FAILED; 3264ef16f24SBrian Somers } 3274ef16f24SBrian Somers 32877ff88adSBrian Somers int 329dd7e2610SBrian Somers server_Close(struct bundle *bundle) 3304ef16f24SBrian Somers { 33177ff88adSBrian Somers if (server.fd >= 0) { 33274457d3dSBrian Somers if (*server.cfg.sockname != '\0') { 333661a0e90SBrian Somers struct sockaddr_un un; 334661a0e90SBrian Somers int sz = sizeof un; 335661a0e90SBrian Somers 336661a0e90SBrian Somers if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 && 337661a0e90SBrian Somers un.sun_family == AF_LOCAL && sz == sizeof un) 33874457d3dSBrian Somers unlink(un.sun_path); 3394ef16f24SBrian Somers } 340661a0e90SBrian Somers close(server.fd); 34177ff88adSBrian Somers server.fd = -1; 342b6217683SBrian Somers /* Drop associated prompts */ 3430f2f3eb3SBrian Somers log_DestroyPrompts(&server); 34474457d3dSBrian Somers 34577ff88adSBrian Somers return 1; 3464ef16f24SBrian Somers } 34774457d3dSBrian Somers 34877ff88adSBrian Somers return 0; 3494ef16f24SBrian Somers } 35074457d3dSBrian Somers 35174457d3dSBrian Somers int 35274457d3dSBrian Somers server_Clear(struct bundle *bundle) 35374457d3dSBrian Somers { 35474457d3dSBrian Somers int ret; 35574457d3dSBrian Somers 35674457d3dSBrian Somers ret = server_Close(bundle); 35774457d3dSBrian Somers 35874457d3dSBrian Somers server.fd = -1; 35974457d3dSBrian Somers server.cfg.port = 0; 36074457d3dSBrian Somers *server.cfg.sockname = '\0'; 36174457d3dSBrian Somers server.cfg.mask = 0; 36274457d3dSBrian Somers 36374457d3dSBrian Somers return ret; 36474457d3dSBrian Somers } 365