Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1997 Brian Somers <brian (at) Awfulhak.org>
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     24  * SUCH DAMAGE.
     25  *
     26  * $FreeBSD: src/usr.sbin/ppp/server.c,v 1.44.14.1 2010/12/21 17:10:29 kensmith Exp $
     27  */
     28 
     29 #include <sys/param.h>
     30 
     31 #include <sys/socket.h>
     32 #include <netinet/in.h>
     33 #include <sys/un.h>
     34 
     35 #include <errno.h>
     36 #include <stdarg.h>
     37 #include <stdio.h>
     38 #include <string.h>
     39 #include <sys/stat.h>
     40 #include <termios.h>
     41 #include <unistd.h>
     42 
     43 #include "log.h"
     44 #include "descriptor.h"
     45 #include "server.h"
     46 #include "prompt.h"
     47 #include "ncpaddr.h"
     48 #include "probe.h"
     49 
     50 static int
     51 server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
     52 {
     53   struct server *s = descriptor2server(d);
     54   struct prompt *p;
     55   int sets;
     56 
     57   sets = 0;
     58   if (r && s->fd >= 0) {
     59     if (*n < s->fd + 1)
     60       *n = s->fd + 1;
     61     FD_SET(s->fd, r);
     62     log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd);
     63     sets++;
     64   }
     65 
     66   for (p = log_PromptList(); p; p = p->next)
     67     sets += descriptor_UpdateSet(&p->desc, r, w, e, n);
     68 
     69   return sets;
     70 }
     71 
     72 static int
     73 server_IsSet(struct fdescriptor *d, const fd_set *fdset)
     74 {
     75   struct server *s = descriptor2server(d);
     76   struct prompt *p;
     77 
     78   if (s->fd >= 0 && FD_ISSET(s->fd, fdset))
     79     return 1;
     80 
     81   for (p = log_PromptList(); p; p = p->next)
     82     if (descriptor_IsSet(&p->desc, fdset))
     83       return 1;
     84 
     85   return 0;
     86 }
     87 
     88 static void
     89 server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
     90 {
     91   struct server *s = descriptor2server(d);
     92   struct sockaddr_storage ss;
     93   struct sockaddr *sa = (struct sockaddr *)&ss;
     94   struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
     95 #ifndef NOINET6
     96   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
     97 #endif
     98   int ssize = sizeof ss, wfd;
     99   struct prompt *p;
    100   struct ncpaddr addr;
    101 
    102   if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) {
    103     wfd = accept(s->fd, sa, &ssize);
    104     if (wfd < 0)
    105       log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno));
    106     else if (sa->sa_len == 0) {
    107       close(wfd);
    108       wfd = -1;
    109     }
    110   } else
    111     wfd = -1;
    112 
    113   if (wfd >= 0)
    114     switch (sa->sa_family) {
    115       case AF_LOCAL:
    116         log_Printf(LogPHASE, "Connected to local client.\n");
    117         break;
    118 
    119       case AF_INET:
    120         ncpaddr_setsa(&addr, sa);
    121         if (ntohs(sin->sin_port) < 1024) {
    122           log_Printf(LogALERT, "Rejected client connection from %s:%u"
    123                     "(invalid port number) !\n",
    124                     ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
    125           close(wfd);
    126           wfd = -1;
    127           break;
    128         }
    129         log_Printf(LogPHASE, "Connected to client from %s:%u\n",
    130                   ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
    131         break;
    132 
    133 #ifndef NOINET6
    134       case AF_INET6:
    135         ncpaddr_setsa(&addr, sa);
    136         if (ntohs(sin6->sin6_port) < 1024) {
    137           log_Printf(LogALERT, "Rejected client connection from %s:%u"
    138                     "(invalid port number) !\n",
    139                     ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
    140           close(wfd);
    141           wfd = -1;
    142           break;
    143         }
    144         log_Printf(LogPHASE, "Connected to client from %s:%u\n",
    145                   ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
    146         break;
    147 #endif
    148 
    149       default:
    150         write(wfd, "Unrecognised access !\n", 22);
    151         close(wfd);
    152         wfd = -1;
    153         break;
    154     }
    155 
    156   if (wfd >= 0) {
    157     if ((p = prompt_Create(s, bundle, wfd)) == NULL) {
    158       write(wfd, "Connection refused.\n", 20);
    159       close(wfd);
    160     } else {
    161       switch (sa->sa_family) {
    162         case AF_LOCAL:
    163           p->src.type = "local";
    164           strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1);
    165           p->src.from[sizeof p->src.from - 1] = '\0';
    166           break;
    167         case AF_INET:
    168           p->src.type = "ip";
    169           snprintf(p->src.from, sizeof p->src.from, "%s:%u",
    170                    ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
    171           break;
    172 #ifndef NOINET6
    173         case AF_INET6:
    174           p->src.type = "ip6";
    175           snprintf(p->src.from, sizeof p->src.from, "%s:%u",
    176                    ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
    177           break;
    178 #endif
    179       }
    180       prompt_TtyCommandMode(p);
    181       prompt_Required(p);
    182     }
    183   }
    184 
    185   log_PromptListChanged = 0;
    186   for (p = log_PromptList(); p; p = p->next)
    187     if (descriptor_IsSet(&p->desc, fdset)) {
    188       descriptor_Read(&p->desc, bundle, fdset);
    189       if (log_PromptListChanged)
    190         break;
    191     }
    192 }
    193 
    194 static int
    195 server_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused,
    196 	     const fd_set *fdset __unused)
    197 {
    198   /* We never want to write here ! */
    199   log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n");
    200   return 0;
    201 }
    202 
    203 struct server server = {
    204   {
    205     SERVER_DESCRIPTOR,
    206     server_UpdateSet,
    207     server_IsSet,
    208     server_Read,
    209     server_Write
    210   },
    211   -1,
    212   { "", "", 0, 0 }
    213 };
    214 
    215 enum server_stat
    216 server_Reopen(struct bundle *bundle)
    217 {
    218   char name[sizeof server.cfg.sockname];
    219   struct stat st;
    220   u_short port;
    221   mode_t mask;
    222   enum server_stat ret;
    223 
    224   if (server.cfg.sockname[0] != '\0') {
    225     strcpy(name, server.cfg.sockname);
    226     mask = server.cfg.mask;
    227     server_Close(bundle);
    228     if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0)
    229       if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0)
    230         return SERVER_FAILED;
    231     ret = server_LocalOpen(bundle, name, mask);
    232   } else if (server.cfg.port != 0) {
    233     port = server.cfg.port;
    234     server_Close(bundle);
    235     ret = server_TcpOpen(bundle, port);
    236   } else
    237     ret = SERVER_UNSET;
    238 
    239   return ret;
    240 }
    241 
    242 enum server_stat
    243 server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask)
    244 {
    245   struct sockaddr_un ifsun;
    246   mode_t oldmask;
    247   int s;
    248 
    249   oldmask = (mode_t)-1;		/* Silence compiler */
    250 
    251   if (server.cfg.sockname && !strcmp(server.cfg.sockname, name))
    252     server_Close(bundle);
    253 
    254   memset(&ifsun, '\0', sizeof ifsun);
    255   ifsun.sun_len = strlen(name);
    256   if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
    257     log_Printf(LogERROR, "Local: %s: Path too long\n", name);
    258     return SERVER_INVALID;
    259   }
    260   ifsun.sun_family = AF_LOCAL;
    261   strcpy(ifsun.sun_path, name);
    262 
    263   s = socket(PF_LOCAL, SOCK_STREAM, 0);
    264   if (s < 0) {
    265     log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno));
    266     goto failed;
    267   }
    268   setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
    269   if (mask != (mode_t)-1)
    270     oldmask = umask(mask);
    271   if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) {
    272     if (mask != (mode_t)-1)
    273       umask(oldmask);
    274     log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno));
    275     close(s);
    276     goto failed;
    277   }
    278   if (mask != (mode_t)-1)
    279     umask(oldmask);
    280   if (listen(s, 5) != 0) {
    281     log_Printf(LogERROR, "Local: Unable to listen to socket -"
    282                " BUNDLE overload?\n");
    283     close(s);
    284     unlink(name);
    285     goto failed;
    286   }
    287   server_Close(bundle);
    288   server.fd = s;
    289   server.cfg.port = 0;
    290   strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1);
    291   server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
    292   server.cfg.mask = mask;
    293   log_Printf(LogPHASE, "Listening at local socket %s.\n", name);
    294 
    295   return SERVER_OK;
    296 
    297 failed:
    298   if (server.fd == -1) {
    299     server.fd = -1;
    300     server.cfg.port = 0;
    301     strncpy(server.cfg.sockname, ifsun.sun_path,
    302             sizeof server.cfg.sockname - 1);
    303     server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
    304     server.cfg.mask = mask;
    305   }
    306   return SERVER_FAILED;
    307 }
    308 
    309 enum server_stat
    310 server_TcpOpen(struct bundle *bundle, u_short port)
    311 {
    312   struct sockaddr_storage ss;
    313   struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
    314 #ifndef NOINET6
    315   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
    316 #endif
    317   int s, sz;
    318 
    319   if (server.cfg.port == port)
    320     server_Close(bundle);
    321 
    322   if (port == 0)
    323     return SERVER_INVALID;
    324 
    325   memset(&ss, '\0', sizeof ss);
    326 #ifndef NOINET6
    327   if (probe.ipv6_available) {
    328     sin6->sin6_family = AF_INET6;
    329     sin6->sin6_port = htons(port);
    330     sin6->sin6_len = (u_int8_t)sizeof ss;
    331     sz = sizeof *sin6;
    332     s = socket(PF_INET6, SOCK_STREAM, 0);
    333   } else
    334 #endif
    335   {
    336     sin->sin_family = AF_INET;
    337     sin->sin_port = htons(port);
    338     sin->sin_len = (u_int8_t)sizeof ss;
    339     sin->sin_addr.s_addr = INADDR_ANY;
    340     sz = sizeof *sin;
    341     s = socket(PF_INET, SOCK_STREAM, 0);
    342   }
    343 
    344   if (s < 0) {
    345     log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
    346     goto failed;
    347   }
    348 
    349 #ifndef NOINET6
    350   if (probe.ipv6_available) {
    351     int off = 0;
    352     setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
    353   }
    354 #endif
    355 
    356   setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
    357   if (bind(s, (struct sockaddr *)&ss, sz) < 0) {
    358     log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno));
    359     close(s);
    360     goto failed;
    361   }
    362   if (listen(s, 5) != 0) {
    363     log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n",
    364                strerror(errno));
    365     close(s);
    366     goto failed;
    367   }
    368   server_Close(bundle);
    369   server.fd = s;
    370   server.cfg.port = port;
    371   *server.cfg.sockname = '\0';
    372   server.cfg.mask = 0;
    373   log_Printf(LogPHASE, "Listening at port %d.\n", port);
    374   return SERVER_OK;
    375 
    376 failed:
    377   if (server.fd == -1) {
    378     server.fd = -1;
    379     server.cfg.port = port;
    380     *server.cfg.sockname = '\0';
    381     server.cfg.mask = 0;
    382   }
    383   return SERVER_FAILED;
    384 }
    385 
    386 int
    387 server_Close(struct bundle *bundle __unused)
    388 {
    389   if (server.fd >= 0) {
    390     if (*server.cfg.sockname != '\0') {
    391       struct sockaddr_un un;
    392       int sz = sizeof un;
    393 
    394       if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 &&
    395           un.sun_family == AF_LOCAL && sz == sizeof un)
    396         unlink(un.sun_path);
    397     }
    398     close(server.fd);
    399     server.fd = -1;
    400     /* Drop associated prompts */
    401     log_DestroyPrompts(&server);
    402 
    403     return 1;
    404   }
    405 
    406   return 0;
    407 }
    408 
    409 int
    410 server_Clear(struct bundle *bundle)
    411 {
    412   int ret;
    413 
    414   ret = server_Close(bundle);
    415 
    416   server.fd = -1;
    417   server.cfg.port = 0;
    418   *server.cfg.sockname = '\0';
    419   server.cfg.mask = 0;
    420 
    421   return ret;
    422 }
    423