server.c revision 71764
1/*-
2 * Copyright (c) 1997 Brian Somers <brian@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: head/usr.sbin/ppp/server.c 71764 2001-01-29 01:35:06Z brian $
27 */
28
29#include <sys/param.h>
30
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <sys/un.h>
35
36#include <errno.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 "id.h"
47#include "prompt.h"
48
49static int
50server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
51{
52  struct server *s = descriptor2server(d);
53  struct prompt *p;
54  int sets;
55
56  sets = 0;
57  if (r && s->fd >= 0) {
58    if (*n < s->fd + 1)
59      *n = s->fd + 1;
60    FD_SET(s->fd, r);
61    log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd);
62    sets++;
63  }
64
65  for (p = log_PromptList(); p; p = p->next)
66    sets += descriptor_UpdateSet(&p->desc, r, w, e, n);
67
68  return sets;
69}
70
71static int
72server_IsSet(struct fdescriptor *d, const fd_set *fdset)
73{
74  struct server *s = descriptor2server(d);
75  struct prompt *p;
76
77  if (s->fd >= 0 && FD_ISSET(s->fd, fdset))
78    return 1;
79
80  for (p = log_PromptList(); p; p = p->next)
81    if (descriptor_IsSet(&p->desc, fdset))
82      return 1;
83
84  return 0;
85}
86
87#define IN_SIZE sizeof(struct sockaddr_in)
88#define UN_SIZE sizeof(struct sockaddr_un)
89#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE)
90
91static void
92server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
93{
94  struct server *s = descriptor2server(d);
95  char hisaddr[ADDRSZ];
96  struct sockaddr *sa = (struct sockaddr *)hisaddr;
97  struct sockaddr_in *in = (struct sockaddr_in *)hisaddr;
98  int ssize = ADDRSZ, wfd;
99  struct prompt *p;
100
101  if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) {
102    wfd = accept(s->fd, sa, &ssize);
103    if (wfd < 0)
104      log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno));
105  } else
106    wfd = -1;
107
108  if (wfd >= 0)
109    switch (sa->sa_family) {
110      case AF_LOCAL:
111        log_Printf(LogPHASE, "Connected to local client.\n");
112        break;
113
114      case AF_INET:
115        if (ntohs(in->sin_port) < 1024) {
116          log_Printf(LogALERT, "Rejected client connection from %s:%u"
117                    "(invalid port number) !\n",
118                    inet_ntoa(in->sin_addr), ntohs(in->sin_port));
119          close(wfd);
120          wfd = -1;
121          break;
122        }
123        log_Printf(LogPHASE, "Connected to client from %s:%u\n",
124                  inet_ntoa(in->sin_addr), in->sin_port);
125        break;
126
127      default:
128        write(wfd, "Unrecognised access !\n", 22);
129        close(wfd);
130        wfd = -1;
131        break;
132    }
133
134  if (wfd >= 0) {
135    if ((p = prompt_Create(s, bundle, wfd)) == NULL) {
136      write(wfd, "Connection refused.\n", 20);
137      close(wfd);
138    } else {
139      switch (sa->sa_family) {
140        case AF_LOCAL:
141          p->src.type = "local";
142          strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1);
143          p->src.from[sizeof p->src.from - 1] = '\0';
144          break;
145        case AF_INET:
146          p->src.type = "tcp";
147          snprintf(p->src.from, sizeof p->src.from, "%s:%u",
148                   inet_ntoa(in->sin_addr), in->sin_port);
149          break;
150      }
151      prompt_TtyCommandMode(p);
152      prompt_Required(p);
153    }
154  }
155
156  log_PromptListChanged = 0;
157  for (p = log_PromptList(); p; p = p->next)
158    if (descriptor_IsSet(&p->desc, fdset)) {
159      descriptor_Read(&p->desc, bundle, fdset);
160      if (log_PromptListChanged)
161        break;
162    }
163}
164
165static int
166server_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
167{
168  /* We never want to write here ! */
169  log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n");
170  return 0;
171}
172
173struct server server = {
174  {
175    SERVER_DESCRIPTOR,
176    server_UpdateSet,
177    server_IsSet,
178    server_Read,
179    server_Write
180  },
181  -1
182};
183
184enum server_stat
185server_Reopen(struct bundle *bundle)
186{
187  char name[sizeof server.cfg.sockname];
188  struct stat st;
189  u_short port;
190  mode_t mask;
191  enum server_stat ret;
192
193  if (server.cfg.sockname[0] != '\0') {
194    strcpy(name, server.cfg.sockname);
195    mask = server.cfg.mask;
196    server_Close(bundle);
197    if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0)
198      if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0)
199        return SERVER_FAILED;
200    ret = server_LocalOpen(bundle, name, mask);
201  } else if (server.cfg.port != 0) {
202    port = server.cfg.port;
203    server_Close(bundle);
204    ret = server_TcpOpen(bundle, port);
205  } else
206    ret = SERVER_UNSET;
207
208  return ret;
209}
210
211enum server_stat
212server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask)
213{
214  struct sockaddr_un ifsun;
215  mode_t oldmask;
216  int s;
217
218  oldmask = (mode_t)-1;		/* Silence compiler */
219
220  if (server.cfg.sockname && !strcmp(server.cfg.sockname, name))
221    server_Close(bundle);
222
223  memset(&ifsun, '\0', sizeof ifsun);
224  ifsun.sun_len = strlen(name);
225  if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
226    log_Printf(LogERROR, "Local: %s: Path too long\n", name);
227    return SERVER_INVALID;
228  }
229  ifsun.sun_family = AF_LOCAL;
230  strcpy(ifsun.sun_path, name);
231
232  s = socket(PF_LOCAL, SOCK_STREAM, 0);
233  if (s < 0) {
234    log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno));
235    goto failed;
236  }
237  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
238  if (mask != (mode_t)-1)
239    oldmask = umask(mask);
240  if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) {
241    if (mask != (mode_t)-1)
242      umask(oldmask);
243    log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno));
244    close(s);
245    goto failed;
246  }
247  if (mask != (mode_t)-1)
248    umask(oldmask);
249  if (listen(s, 5) != 0) {
250    log_Printf(LogERROR, "Local: Unable to listen to socket -"
251               " BUNDLE overload?\n");
252    close(s);
253    unlink(name);
254    goto failed;
255  }
256  server_Close(bundle);
257  server.fd = s;
258  server.cfg.port = 0;
259  strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1);
260  server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
261  server.cfg.mask = mask;
262  log_Printf(LogPHASE, "Listening at local socket %s.\n", name);
263
264  return SERVER_OK;
265
266failed:
267  if (server.fd == -1) {
268    server.fd = -1;
269    server.cfg.port = 0;
270    strncpy(server.cfg.sockname, ifsun.sun_path,
271            sizeof server.cfg.sockname - 1);
272    server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
273    server.cfg.mask = mask;
274  }
275  return SERVER_FAILED;
276}
277
278enum server_stat
279server_TcpOpen(struct bundle *bundle, u_short port)
280{
281  struct sockaddr_in ifsin;
282  int s;
283
284  if (server.cfg.port == port)
285    server_Close(bundle);
286
287  if (port == 0)
288    return SERVER_INVALID;
289
290  s = socket(PF_INET, SOCK_STREAM, 0);
291  if (s < 0) {
292    log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
293    goto failed;
294  }
295  memset(&ifsin, '\0', sizeof ifsin);
296  ifsin.sin_family = AF_INET;
297  ifsin.sin_addr.s_addr = INADDR_ANY;
298  ifsin.sin_port = htons(port);
299  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
300  if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) {
301    log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno));
302    close(s);
303    goto failed;
304  }
305  if (listen(s, 5) != 0) {
306    log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n",
307               strerror(errno));
308    close(s);
309    goto failed;
310  }
311  server_Close(bundle);
312  server.fd = s;
313  server.cfg.port = port;
314  *server.cfg.sockname = '\0';
315  server.cfg.mask = 0;
316  log_Printf(LogPHASE, "Listening at port %d.\n", port);
317  return SERVER_OK;
318
319failed:
320  if (server.fd == -1) {
321    server.fd = -1;
322    server.cfg.port = port;
323    *server.cfg.sockname = '\0';
324    server.cfg.mask = 0;
325  }
326  return SERVER_FAILED;
327}
328
329int
330server_Close(struct bundle *bundle)
331{
332  if (server.fd >= 0) {
333    if (*server.cfg.sockname != '\0') {
334      struct sockaddr_un un;
335      int sz = sizeof un;
336
337      if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 &&
338          un.sun_family == AF_LOCAL && sz == sizeof un)
339        unlink(un.sun_path);
340    }
341    close(server.fd);
342    server.fd = -1;
343    /* Drop associated prompts */
344    log_DestroyPrompts(&server);
345
346    return 1;
347  }
348
349  return 0;
350}
351
352int
353server_Clear(struct bundle *bundle)
354{
355  int ret;
356
357  ret = server_Close(bundle);
358
359  server.fd = -1;
360  server.cfg.port = 0;
361  *server.cfg.sockname = '\0';
362  server.cfg.mask = 0;
363
364  return ret;
365}
366