xref: /freebsd/usr.sbin/ppp/server.c (revision 74457d3d4327f7169df5e5596a955d1862b76270)
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