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