server.c revision 50479
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 50479 1999-08-28 01:35:59Z peter $
27 */
28
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <sys/un.h>
34
35#include <errno.h>
36#include <stdio.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <termios.h>
40#include <unistd.h>
41
42#include "log.h"
43#include "descriptor.h"
44#include "server.h"
45#include "id.h"
46#include "prompt.h"
47
48static int
49server_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
50{
51  struct server *s = descriptor2server(d);
52  struct prompt *p;
53  int sets;
54
55  sets = 0;
56  if (r && s->fd >= 0) {
57    if (*n < s->fd + 1)
58      *n = s->fd + 1;
59    FD_SET(s->fd, r);
60    log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd);
61    sets++;
62  }
63
64  for (p = log_PromptList(); p; p = p->next)
65    sets += descriptor_UpdateSet(&p->desc, r, w, e, n);
66
67  return sets;
68}
69
70static int
71server_IsSet(struct descriptor *d, const fd_set *fdset)
72{
73  struct server *s = descriptor2server(d);
74  struct prompt *p;
75
76  if (s->fd >= 0 && FD_ISSET(s->fd, fdset))
77    return 1;
78
79  for (p = log_PromptList(); p; p = p->next)
80    if (descriptor_IsSet(&p->desc, fdset))
81      return 1;
82
83  return 0;
84}
85
86#define IN_SIZE sizeof(struct sockaddr_in)
87#define UN_SIZE sizeof(struct sockaddr_in)
88#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE)
89
90static void
91server_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
92{
93  struct server *s = descriptor2server(d);
94  char hisaddr[ADDRSZ];
95  struct sockaddr *sa = (struct sockaddr *)hisaddr;
96  struct sockaddr_in *in = (struct sockaddr_in *)hisaddr;
97  int ssize = ADDRSZ, wfd;
98  struct prompt *p;
99
100  if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) {
101    wfd = accept(s->fd, sa, &ssize);
102    if (wfd < 0)
103      log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno));
104  } else
105    wfd = -1;
106
107  if (wfd >= 0)
108    switch (sa->sa_family) {
109      case AF_LOCAL:
110        log_Printf(LogPHASE, "Connected to local client.\n");
111        break;
112
113      case AF_INET:
114        if (ntohs(in->sin_port) < 1024) {
115          log_Printf(LogALERT, "Rejected client connection from %s:%u"
116                    "(invalid port number) !\n",
117                    inet_ntoa(in->sin_addr), ntohs(in->sin_port));
118          close(wfd);
119          wfd = -1;
120          break;
121        }
122        log_Printf(LogPHASE, "Connected to client from %s:%u\n",
123                  inet_ntoa(in->sin_addr), in->sin_port);
124        break;
125
126      default:
127        write(wfd, "Unrecognised access !\n", 22);
128        close(wfd);
129        wfd = -1;
130        break;
131    }
132
133  if (wfd >= 0) {
134    if ((p = prompt_Create(s, bundle, wfd)) == NULL) {
135      write(wfd, "Connection refused.\n", 20);
136      close(wfd);
137    } else {
138      switch (sa->sa_family) {
139        case AF_LOCAL:
140          p->src.type = "local";
141          strncpy(p->src.from, s->rm, sizeof p->src.from - 1);
142          p->src.from[sizeof p->src.from - 1] = '\0';
143          break;
144        case AF_INET:
145          p->src.type = "tcp";
146          snprintf(p->src.from, sizeof p->src.from, "%s:%u",
147                   inet_ntoa(in->sin_addr), in->sin_port);
148          break;
149      }
150      prompt_TtyCommandMode(p);
151      prompt_Required(p);
152    }
153  }
154
155  log_PromptListChanged = 0;
156  for (p = log_PromptList(); p; p = p->next)
157    if (descriptor_IsSet(&p->desc, fdset)) {
158      descriptor_Read(&p->desc, bundle, fdset);
159      if (log_PromptListChanged)
160        break;
161    }
162}
163
164static int
165server_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
166{
167  /* We never want to write here ! */
168  log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n");
169  return 0;
170}
171
172struct server server = {
173  {
174    SERVER_DESCRIPTOR,
175    server_UpdateSet,
176    server_IsSet,
177    server_Read,
178    server_Write
179  },
180  -1
181};
182
183int
184server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask)
185{
186  int s;
187
188  if (server.rm && !strcmp(server.rm, name)) {
189    if (chmod(server.rm, mask))
190      log_Printf(LogERROR, "Local: chmod: %s\n", strerror(errno));
191    return 0;
192  }
193
194  memset(&server.ifsun, '\0', sizeof server.ifsun);
195  server.ifsun.sun_len = strlen(name);
196  if (server.ifsun.sun_len > sizeof server.ifsun.sun_path - 1) {
197    log_Printf(LogERROR, "Local: %s: Path too long\n", name);
198    return 2;
199  }
200  server.ifsun.sun_family = AF_LOCAL;
201  strcpy(server.ifsun.sun_path, name);
202
203  s = ID0socket(PF_LOCAL, SOCK_STREAM, 0);
204  if (s < 0) {
205    log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno));
206    return 3;
207  }
208  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
209  if (mask != (mode_t)-1)
210    mask = umask(mask);
211  if (bind(s, (struct sockaddr *)&server.ifsun, sizeof server.ifsun) < 0) {
212    if (mask != (mode_t)-1)
213      umask(mask);
214    log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno));
215    close(s);
216    return 4;
217  }
218  if (mask != (mode_t)-1)
219    umask(mask);
220  if (listen(s, 5) != 0) {
221    log_Printf(LogERROR, "Local: Unable to listen to socket - BUNDLE overload?\n");
222    close(s);
223    ID0unlink(name);
224    return 5;
225  }
226  server_Close(bundle);
227  server.fd = s;
228  server.rm = server.ifsun.sun_path;
229  log_Printf(LogPHASE, "Listening at local socket %s.\n", name);
230  return 0;
231}
232
233int
234server_TcpOpen(struct bundle *bundle, int port)
235{
236  struct sockaddr_in ifsin;
237  int s;
238
239  if (server.port == port)
240    return 0;
241
242  s = ID0socket(PF_INET, SOCK_STREAM, 0);
243  if (s < 0) {
244    log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
245    return 7;
246  }
247  memset(&ifsin, '\0', sizeof ifsin);
248  ifsin.sin_family = AF_INET;
249  ifsin.sin_addr.s_addr = INADDR_ANY;
250  ifsin.sin_port = htons(port);
251  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
252  if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) {
253    log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno));
254    close(s);
255    return 8;
256  }
257  if (listen(s, 5) != 0) {
258    log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n",
259               strerror(errno));
260    close(s);
261    return 9;
262  }
263  server_Close(bundle);
264  server.fd = s;
265  server.port = port;
266  log_Printf(LogPHASE, "Listening at port %d.\n", port);
267  return 0;
268}
269
270int
271server_Close(struct bundle *bundle)
272{
273  if (server.fd >= 0) {
274    if (server.rm) {
275      struct sockaddr_un un;
276      int sz = sizeof un;
277
278      if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 &&
279          un.sun_family == AF_LOCAL && sz == sizeof un)
280        ID0unlink(un.sun_path);
281      server.rm = NULL;
282    }
283    close(server.fd);
284    server.fd = -1;
285    server.port = 0;
286    /* Drop associated prompts */
287    log_DestroyPrompts(&server);
288    return 1;
289  }
290  return 0;
291}
292