]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/server.c
This commit was generated by cvs2svn to compensate for changes in r98681,
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / server.c
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$
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 <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 "prompt.h"
46 #include "ncpaddr.h"
47 #include "probe.h"
48
49 static int
50 server_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
71 static int
72 server_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 static void
88 server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
89 {
90   struct server *s = descriptor2server(d);
91   struct sockaddr_storage ss;
92   struct sockaddr *sa = (struct sockaddr *)&ss;
93   struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
94 #ifndef NOINET6
95   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
96 #endif
97   int ssize = sizeof ss, wfd;
98   struct prompt *p;
99   struct ncpaddr addr;
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 if (sa->sa_len == 0) {
106       close(wfd);
107       wfd = -1;
108     }
109   } else
110     wfd = -1;
111
112   if (wfd >= 0)
113     switch (sa->sa_family) {
114       case AF_LOCAL:
115         log_Printf(LogPHASE, "Connected to local client.\n");
116         break;
117
118       case AF_INET:
119         ncpaddr_setsa(&addr, sa);
120         if (ntohs(sin->sin_port) < 1024) {
121           log_Printf(LogALERT, "Rejected client connection from %s:%u"
122                     "(invalid port number) !\n",
123                     ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
124           close(wfd);
125           wfd = -1;
126           break;
127         }
128         log_Printf(LogPHASE, "Connected to client from %s:%u\n",
129                   ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
130         break;
131
132 #ifndef NOINET6
133       case AF_INET6:
134         ncpaddr_setsa(&addr, sa);
135         if (ntohs(sin6->sin6_port) < 1024) {
136           log_Printf(LogALERT, "Rejected client connection from %s:%u"
137                     "(invalid port number) !\n",
138                     ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
139           close(wfd);
140           wfd = -1;
141           break;
142         }
143         log_Printf(LogPHASE, "Connected to client from %s:%u\n",
144                   ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
145         break;
146 #endif
147
148       default:
149         write(wfd, "Unrecognised access !\n", 22);
150         close(wfd);
151         wfd = -1;
152         break;
153     }
154
155   if (wfd >= 0) {
156     if ((p = prompt_Create(s, bundle, wfd)) == NULL) {
157       write(wfd, "Connection refused.\n", 20);
158       close(wfd);
159     } else {
160       switch (sa->sa_family) {
161         case AF_LOCAL:
162           p->src.type = "local";
163           strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1);
164           p->src.from[sizeof p->src.from - 1] = '\0';
165           break;
166         case AF_INET:
167           p->src.type = "ip";
168           snprintf(p->src.from, sizeof p->src.from, "%s:%u",
169                    ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
170           break;
171 #ifndef NOINET6
172         case AF_INET6:
173           p->src.type = "ip6";
174           snprintf(p->src.from, sizeof p->src.from, "%s:%u",
175                    ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
176           break;
177 #endif
178       }
179       prompt_TtyCommandMode(p);
180       prompt_Required(p);
181     }
182   }
183
184   log_PromptListChanged = 0;
185   for (p = log_PromptList(); p; p = p->next)
186     if (descriptor_IsSet(&p->desc, fdset)) {
187       descriptor_Read(&p->desc, bundle, fdset);
188       if (log_PromptListChanged)
189         break;
190     }
191 }
192
193 static int
194 server_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
195 {
196   /* We never want to write here ! */
197   log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n");
198   return 0;
199 }
200
201 struct server server = {
202   {
203     SERVER_DESCRIPTOR,
204     server_UpdateSet,
205     server_IsSet,
206     server_Read,
207     server_Write
208   },
209   -1
210 };
211
212 enum server_stat
213 server_Reopen(struct bundle *bundle)
214 {
215   char name[sizeof server.cfg.sockname];
216   struct stat st;
217   u_short port;
218   mode_t mask;
219   enum server_stat ret;
220
221   if (server.cfg.sockname[0] != '\0') {
222     strcpy(name, server.cfg.sockname);
223     mask = server.cfg.mask;
224     server_Close(bundle);
225     if (server.cfg.sockname[0] != '\0' && stat(server.cfg.sockname, &st) == 0)
226       if (!(st.st_mode & S_IFSOCK) || unlink(server.cfg.sockname) != 0)
227         return SERVER_FAILED;
228     ret = server_LocalOpen(bundle, name, mask);
229   } else if (server.cfg.port != 0) {
230     port = server.cfg.port;
231     server_Close(bundle);
232     ret = server_TcpOpen(bundle, port);
233   } else
234     ret = SERVER_UNSET;
235
236   return ret;
237 }
238
239 enum server_stat
240 server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask)
241 {
242   struct sockaddr_un ifsun;
243   mode_t oldmask;
244   int s;
245
246   oldmask = (mode_t)-1;         /* Silence compiler */
247
248   if (server.cfg.sockname && !strcmp(server.cfg.sockname, name))
249     server_Close(bundle);
250
251   memset(&ifsun, '\0', sizeof ifsun);
252   ifsun.sun_len = strlen(name);
253   if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
254     log_Printf(LogERROR, "Local: %s: Path too long\n", name);
255     return SERVER_INVALID;
256   }
257   ifsun.sun_family = AF_LOCAL;
258   strcpy(ifsun.sun_path, name);
259
260   s = socket(PF_LOCAL, SOCK_STREAM, 0);
261   if (s < 0) {
262     log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno));
263     goto failed;
264   }
265   setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
266   if (mask != (mode_t)-1)
267     oldmask = umask(mask);
268   if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) {
269     if (mask != (mode_t)-1)
270       umask(oldmask);
271     log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno));
272     close(s);
273     goto failed;
274   }
275   if (mask != (mode_t)-1)
276     umask(oldmask);
277   if (listen(s, 5) != 0) {
278     log_Printf(LogERROR, "Local: Unable to listen to socket -"
279                " BUNDLE overload?\n");
280     close(s);
281     unlink(name);
282     goto failed;
283   }
284   server_Close(bundle);
285   server.fd = s;
286   server.cfg.port = 0;
287   strncpy(server.cfg.sockname, ifsun.sun_path, sizeof server.cfg.sockname - 1);
288   server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
289   server.cfg.mask = mask;
290   log_Printf(LogPHASE, "Listening at local socket %s.\n", name);
291
292   return SERVER_OK;
293
294 failed:
295   if (server.fd == -1) {
296     server.fd = -1;
297     server.cfg.port = 0;
298     strncpy(server.cfg.sockname, ifsun.sun_path,
299             sizeof server.cfg.sockname - 1);
300     server.cfg.sockname[sizeof server.cfg.sockname - 1] = '\0';
301     server.cfg.mask = mask;
302   }
303   return SERVER_FAILED;
304 }
305
306 enum server_stat
307 server_TcpOpen(struct bundle *bundle, u_short port)
308 {
309   struct sockaddr_storage ss;
310   struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
311 #ifndef NOINET6
312   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
313 #endif
314   int s, sz;
315
316   if (server.cfg.port == port)
317     server_Close(bundle);
318
319   if (port == 0)
320     return SERVER_INVALID;
321
322   memset(&ss, '\0', sizeof ss);
323 #ifndef NOINET6
324   if (probe.ipv6_available) {
325     sin6->sin6_family = AF_INET6;
326     sin6->sin6_port = htons(port);
327     sin6->sin6_len = (u_int8_t)sizeof ss;
328     sz = sizeof *sin6;
329     s = socket(PF_INET6, SOCK_STREAM, 0);
330   } else
331 #endif
332   {
333     sin->sin_family = AF_INET;
334     sin->sin_port = htons(port);
335     sin->sin_len = (u_int8_t)sizeof ss;
336     sin->sin_addr.s_addr = INADDR_ANY;
337     sz = sizeof *sin;
338     s = socket(PF_INET, SOCK_STREAM, 0);
339   }
340
341   if (s < 0) {
342     log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
343     goto failed;
344   }
345
346   setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
347   if (bind(s, (struct sockaddr *)&ss, sz) < 0) {
348     log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno));
349     close(s);
350     goto failed;
351   }
352   if (listen(s, 5) != 0) {
353     log_Printf(LogERROR, "Tcp: Unable to listen to socket: %s\n",
354                strerror(errno));
355     close(s);
356     goto failed;
357   }
358   server_Close(bundle);
359   server.fd = s;
360   server.cfg.port = port;
361   *server.cfg.sockname = '\0';
362   server.cfg.mask = 0;
363   log_Printf(LogPHASE, "Listening at port %d.\n", port);
364   return SERVER_OK;
365
366 failed:
367   if (server.fd == -1) {
368     server.fd = -1;
369     server.cfg.port = port;
370     *server.cfg.sockname = '\0';
371     server.cfg.mask = 0;
372   }
373   return SERVER_FAILED;
374 }
375
376 int
377 server_Close(struct bundle *bundle)
378 {
379   if (server.fd >= 0) {
380     if (*server.cfg.sockname != '\0') {
381       struct sockaddr_un un;
382       int sz = sizeof un;
383
384       if (getsockname(server.fd, (struct sockaddr *)&un, &sz) == 0 &&
385           un.sun_family == AF_LOCAL && sz == sizeof un)
386         unlink(un.sun_path);
387     }
388     close(server.fd);
389     server.fd = -1;
390     /* Drop associated prompts */
391     log_DestroyPrompts(&server);
392
393     return 1;
394   }
395
396   return 0;
397 }
398
399 int
400 server_Clear(struct bundle *bundle)
401 {
402   int ret;
403
404   ret = server_Close(bundle);
405
406   server.fd = -1;
407   server.cfg.port = 0;
408   *server.cfg.sockname = '\0';
409   server.cfg.mask = 0;
410
411   return ret;
412 }