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