Bug Summary

File:src/usr.sbin/npppd/npppd/../pptp/pptpd.c
Warning:line 639, column 5
Value stored to 'reason' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pptpd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/npppd/npppd/../common -I /usr/src/usr.sbin/npppd/npppd -I /usr/src/usr.sbin/npppd/npppd/../pptp -I /usr/src/usr.sbin/npppd/npppd/../l2tp -I /usr/src/usr.sbin/npppd/npppd/../pppoe -D USE_NPPPD_PPTP -D USE_NPPPD_L2TP -D USE_NPPPD_PPPOE -D __COPYRIGHT(x)= -D __RCSID(x)= -D NPPPD_MAX_IFACE=8 -D NPPPD_MAX_POOL=8 -D USE_NPPPD_MPPE -D USE_NPPPD_PIPEX -D USE_NPPPD_RADIUS -D USE_SA_COOKIE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/npppd/npppd/../pptp/pptpd.c
1/* $OpenBSD: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $ */
2
3/*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/* $Id: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $ */
29
30/**@file
31 * This file provides a implementation of PPTP daemon. Currently it
32 * provides functions for PAC (PPTP Access Concentrator) only.
33 * $Id: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $
34 */
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/sysctl.h>
38#include <net/if.h>
39#include <netinet/in.h>
40#include <netinet/ip.h>
41#include <netinet/ip_gre.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <stdio.h>
45#include <stdarg.h>
46#include <signal.h>
47#include <syslog.h>
48#include <fcntl.h>
49#include <unistd.h>
50#include <stdlib.h>
51#include <errno(*__errno()).h>
52#include <string.h>
53#include <event.h>
54
55#ifdef USE_LIBSOCKUTIL
56#include <seil/sockfromto.h>
57#endif
58
59#include "net_utils.h"
60#include "bytebuf.h"
61#include "debugutil.h"
62#include "hash.h"
63#include "slist.h"
64#include "addr_range.h"
65
66#include "pptp.h"
67#include "pptp_local.h"
68#include "privsep.h"
69#include "accept.h"
70
71#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
72
73static int pptpd_seqno = 0;
74
75#ifdef PPTPD_DEBUG
76#define PPTPD_ASSERT(x) ASSERT(x)((void)0);
77#define PPTPD_DBG(x) pptpd_log x
78#else
79#define PPTPD_ASSERT(x)
80#define PPTPD_DBG(x)
81#endif
82
83static void pptpd_log (pptpd *, int, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4)));
84static void pptpd_close_gre (pptpd *);
85static void pptpd_close_1723 (pptpd *);
86static void pptpd_io_event (int, short, void *);
87static void pptpd_gre_io_event (int, short, void *);
88static void pptpd_gre_input (pptpd_listener *, struct sockaddr *, u_char *, int);
89static void pptp_ctrl_start_by_pptpd (pptpd *, int, int, struct sockaddr *);
90static int pptp_call_cmp (const void *, const void *);
91static uint32_t pptp_call_hash (const void *, int);
92static void pptp_gre_header_string (struct pptp_gre_header *, char *, int);
93
94#define PPTPD_SHUFFLE_MARK-1 -1
95
96/* initialize pptp daemon */
97int
98pptpd_init(pptpd *_this)
99{
100 int i, m;
101 uint16_t call0, call[UINT16_MAX0xffff - 1];
102
103 int mib[] = { CTL_NET4, PF_INET2, IPPROTO_GRE47, GRECTL_ALLOW1 };
104 int value;
105 size_t size;
106 size = sizeof(value);
107
108 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL((void *)0), 0) == 0) {
109 if(value == 0) {
110 pptpd_log(_this, LOG_WARNING4, "GRE protocol not allowed");
111 }
112 }
113
114 memset(_this, 0, sizeof(pptpd));
115 _this->id = pptpd_seqno++;
116
117 slist_init(&_this->ctrl_list);
118 slist_init(&_this->call_free_list);
119
120 /* randomize call id */
121 for (i = 0; i < countof(call)(sizeof(call) / sizeof((call)[0])) ; i++)
122 call[i] = i + 1;
123 for (i = countof(call)(sizeof(call) / sizeof((call)[0])); i > 1; i--) {
124 m = arc4random_uniform(i);
125 call0 = call[m];
126 call[m] = call[i - 1];
127 call[i - 1] = call0;
128 }
129
130 for (i = 0; i < MINIMUM(PPTP_MAX_CALL, countof(call))(((8192) < ((sizeof(call) / sizeof((call)[0])))) ? (8192) :
((sizeof(call) / sizeof((call)[0]))))
; i++)
131 slist_add(&_this->call_free_list, (void *)(uintptr_t)call[i]);
132 slist_add(&_this->call_free_list, (void *)PPTPD_SHUFFLE_MARK-1);
133
134 if (_this->call_id_map == NULL((void *)0))
135 _this->call_id_map = hash_create(pptp_call_cmp, pptp_call_hash,
136 0);
137
138 return 0;
139}
140
141/* add a listener to pptpd daemon context */
142int
143pptpd_add_listener(pptpd *_this, int idx, struct pptp_conf *conf,
144 struct sockaddr *addr)
145{
146 int inaddr_any;
147 pptpd_listener *plistener, *plstn;
148
149 plistener = NULL((void *)0);
150 if (idx == 0 && slist_length(&_this->listener) > 0) {
151 slist_itr_first(&_this->listener);
152 while (slist_itr_has_next(&_this->listener)) {
153 slist_itr_next(&_this->listener);
154 plstn = slist_itr_remove(&_this->listener);
155 PPTPD_ASSERT(plstn != NULL);
156 PPTPD_ASSERT(plstn->sock == -1);
157 PPTPD_ASSERT(plstn->sock_gre == -1);
158 free(plstn);
159 }
160 }
161 PPTPD_ASSERT(slist_length(&_this->listener) == idx);
162 if (slist_length(&_this->listener) != idx) {
163 pptpd_log(_this, LOG_ERR3,
164 "Invalid argument error on %s(): idx must be %d but %d",
165 __func__, slist_length(&_this->listener), idx);
166 goto fail;
167 }
168 if ((plistener = calloc(1, sizeof(pptpd_listener))) == NULL((void *)0)) {
169 pptpd_log(_this, LOG_ERR3, "calloc() failed in %s: %m",
170 __func__);
171 goto fail;
172 }
173
174 PPTPD_ASSERT(sizeof(plistener->bind_sin) >= addr->sa_len);
175 memcpy(&plistener->bind_sin, addr, addr->sa_len);
176 memcpy(&plistener->bind_sin_gre, addr, addr->sa_len);
177
178 if (plistener->bind_sin.sin_port == 0)
179 plistener->bind_sin.sin_port = htons(PPTPD_DEFAULT_TCP_PORT)(__uint16_t)(__builtin_constant_p(1723) ? (__uint16_t)(((__uint16_t
)(1723) & 0xffU) << 8 | ((__uint16_t)(1723) & 0xff00U
) >> 8) : __swap16md(1723))
;
180
181 /* When a raw socket binds both of an INADDR_ANY and specific IP
182 * address sockets, packets will be received by those sockets
183 * simultaneously. To avoid this duplicate receives, not
184 * permit such kind of configuration */
185 inaddr_any = 0;
186 slist_itr_first(&_this->listener);
187 while (slist_itr_has_next(&_this->listener)) {
188 plstn = slist_itr_next(&_this->listener);
189 if (plstn->bind_sin_gre.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))
190 inaddr_any++;
191 }
192 if (plistener->bind_sin_gre.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))
193 inaddr_any++;
194 if (inaddr_any > 0 && idx > 0) {
195 log_printf(LOG_ERR3, "configuration error at pptpd.listener_in: "
196 "combination 0.0.0.0 and other address is not allowed.");
197 goto fail;
198 }
199
200 plistener->bind_sin_gre.sin_port = 0;
201 plistener->sock = -1;
202 plistener->sock_gre = -1;
203 plistener->self = _this;
204 plistener->index = idx;
205 plistener->conf = conf;
206 strlcpy(plistener->tun_name, conf->name, sizeof(plistener->tun_name));
207
208 if (slist_add(&_this->listener, plistener) == NULL((void *)0)) {
209 pptpd_log(_this, LOG_ERR3, "slist_add() failed in %s: %m",
210 __func__);
211 goto fail;
212 }
213 return 0;
214fail:
215 free(plistener);
216 return 1;
217}
218
219void
220pptpd_uninit(pptpd *_this)
221{
222 pptpd_listener *plstn;
223
224 slist_fini(&_this->ctrl_list);
225 slist_fini(&_this->call_free_list);
226
227 slist_itr_first(&_this->listener);
228 while (slist_itr_has_next(&_this->listener)) {
229 plstn = slist_itr_next(&_this->listener);
230 PPTPD_ASSERT(plstn != NULL);
231 PPTPD_ASSERT(plstn->sock == -1);
232 PPTPD_ASSERT(plstn->sock_gre == -1);
233 free(plstn);
234 }
235 slist_fini(&_this->listener);
236 if (_this->call_id_map != NULL((void *)0))
237 hash_free(_this->call_id_map);
238 _this->call_id_map = NULL((void *)0);
239}
240
241#define CALL_ID_KEY(call_id, listener_idx)((void *)((uintptr_t)(call_id) | (listener_idx) << 16)) \
242 ((void *)((uintptr_t)(call_id) | (listener_idx) << 16))
243#define CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index
) << 16))
\
244 CALL_ID_KEY((call)->id, (call)->ctrl->listener_index)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index
) << 16))
245int
246pptpd_assign_call(pptpd *_this, pptp_call *call)
247{
248 int shuffle_cnt = 0;
249 u_int call_id;
250
251 shuffle_cnt = 0;
252 slist_itr_first(&_this->call_free_list);
253 while (slist_length(&_this->call_free_list) > 1 &&
254 slist_itr_has_next(&_this->call_free_list)) {
255 call_id = (uintptr_t)slist_itr_next(&_this->call_free_list);
256 if (call_id == 0)
257 break;
258 slist_itr_remove(&_this->call_free_list);
259 if (call_id == PPTPD_SHUFFLE_MARK-1) {
260 if (shuffle_cnt++ > 0)
261 break;
262 slist_shuffle(&_this->call_free_list);
263 slist_add(&_this->call_free_list,
264 (void *)PPTPD_SHUFFLE_MARK-1);
265 slist_itr_first(&_this->call_free_list);
266 continue;
267 }
268 call->id = call_id;
269 hash_insert(_this->call_id_map, CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index
) << 16))
, call);
270
271 return 0;
272 }
273 errno(*__errno()) = EBUSY16;
274 pptpd_log(_this, LOG_ERR3, "call request reached limit=%d",
275 PPTP_MAX_CALL8192);
276 return -1;
277}
278
279void
280pptpd_release_call(pptpd *_this, pptp_call *call)
281{
282 if (call->id != 0)
283 slist_add(&_this->call_free_list, (void *)(uintptr_t)call->id);
284 hash_delete(_this->call_id_map, CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index
) << 16))
, 0);
285 call->id = 0;
286}
287
288static int
289pptpd_listener_start(pptpd_listener *_this)
290{
291 int sock, ival, sock_gre;
292 struct sockaddr_in bind_sin, bind_sin_gre;
293 int wildcardbinding;
294
295 wildcardbinding =
296 (_this->bind_sin.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))? 1 : 0;
297 sock = -1;
298 sock_gre = -1;
299 memcpy(&bind_sin, &_this->bind_sin, sizeof(bind_sin));
300 memcpy(&bind_sin_gre, &_this->bind_sin_gre, sizeof(bind_sin_gre));
301
302 if ((sock = socket(AF_INET2, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, IPPROTO_TCP6))
303 < 0) {
304 pptpd_log(_this->self, LOG_ERR3, "socket() failed at %s(): %m",
305 __func__);
306 goto fail;
307 }
308 ival = 1;
309 if(setsockopt(sock, SOL_SOCKET0xffff, SO_REUSEPORT0x0200, &ival, sizeof(ival)) < 0){
310 pptpd_log(_this->self, LOG_WARNING4,
311 "setsockopt(SO_REUSEPORT) failed at %s(): %m", __func__);
312 }
313#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF)
314 ival = 1;
315 if (setsockopt(sock, IPPROTO_IP0, IP_STRICT_RCVIF, &ival, sizeof(ival))
316 != 0)
317 pptpd_log(_this->self, LOG_WARNING4,
318 "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__);
319#endif
320 if (bind(sock, (struct sockaddr *)&_this->bind_sin,
321 _this->bind_sin.sin_len) != 0) {
322 pptpd_log(_this->self, LOG_ERR3,
323 "bind(%s:%u) failed at %s(): %m",
324 inet_ntoa(_this->bind_sin.sin_addr),
325 ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port
) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) &
0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port
) & 0xff00U) >> 8) : __swap16md(_this->bind_sin.
sin_port))
, __func__);
326 goto fail;
327 }
328 if (listen(sock, PPTP_BACKLOG32) != 0) {
329 pptpd_log(_this->self, LOG_ERR3,
330 "listen(%s:%u) failed at %s(): %m",
331 inet_ntoa(_this->bind_sin.sin_addr),
332 ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port
) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) &
0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port
) & 0xff00U) >> 8) : __swap16md(_this->bind_sin.
sin_port))
, __func__);
333 goto fail;
334 }
335 pptpd_log(_this->self, LOG_INFO6, "Listening %s:%u/tcp (PPTP PAC) [%s]",
336 inet_ntoa(_this->bind_sin.sin_addr),
337 ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port
) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) &
0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port
) & 0xff00U) >> 8) : __swap16md(_this->bind_sin.
sin_port))
, _this->tun_name);
338
339 /* GRE */
340 bind_sin_gre.sin_port = 0;
341 if ((sock_gre = priv_socket(AF_INET2, SOCK_RAW3, IPPROTO_GRE47)) < 0) {
342 pptpd_log(_this->self, LOG_ERR3, "socket() failed at %s(): %m",
343 __func__);
344 goto fail;
345 }
346#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF)
347 ival = 1;
348 if (setsockopt(sock_gre, IPPROTO_IP0, IP_STRICT_RCVIF, &ival,
349 sizeof(ival)) != 0)
350 pptpd_log(_this->self, LOG_WARNING4,
351 "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__);
352#endif
353#ifdef IP_PIPEX34
354 ival = 1;
355 if (setsockopt(sock_gre, IPPROTO_IP0, IP_PIPEX34, &ival, sizeof(ival))
356 != 0)
357 pptpd_log(_this->self, LOG_WARNING4,
358 "%s(): setsockopt(IP_PIPEX) failed: %m", __func__);
359#endif
360 if ((ival = fcntl(sock_gre, F_GETFL3)) < 0) {
361 pptpd_log(_this->self, LOG_ERR3,
362 "fcntl(F_GET_FL) failed at %s(): %m", __func__);
363 goto fail;
364 } else if (fcntl(sock_gre, F_SETFL4, ival | O_NONBLOCK0x0004) < 0) {
365 pptpd_log(_this->self, LOG_ERR3,
366 "fcntl(F_SET_FL) failed at %s(): %m", __func__);
367 goto fail;
368 }
369 if (bind(sock_gre, (struct sockaddr *)&bind_sin_gre,
370 bind_sin_gre.sin_len) != 0) {
371 pptpd_log(_this->self, LOG_ERR3,
372 "bind(%s:%u) failed at %s(): %m",
373 inet_ntoa(bind_sin_gre.sin_addr),
374 ntohs(bind_sin_gre.sin_port)(__uint16_t)(__builtin_constant_p(bind_sin_gre.sin_port) ? (__uint16_t
)(((__uint16_t)(bind_sin_gre.sin_port) & 0xffU) << 8
| ((__uint16_t)(bind_sin_gre.sin_port) & 0xff00U) >>
8) : __swap16md(bind_sin_gre.sin_port))
, __func__);
375 goto fail;
376 }
377 if (wildcardbinding) {
378#ifdef USE_LIBSOCKUTIL
379 if (setsockoptfromto(sock) != 0) {
380 pptpd_log(_this->self, LOG_ERR3,
381 "setsockoptfromto() failed in %s(): %m", __func__);
382 goto fail;
383 }
384#else
385 /* nothing to do */
386#endif
387 }
388 pptpd_log(_this->self, LOG_INFO6, "Listening %s:gre (PPTP PAC)",
389 inet_ntoa(bind_sin_gre.sin_addr));
390
391 _this->sock = sock;
392 _this->sock_gre = sock_gre;
393
394 if (accept_add(_this->sock, pptpd_io_event, _this) != 0) {
395 pptpd_log(_this->self, LOG_ERR3,
396 "accept_add() failed in %s(): %m", __func__);
397 goto fail;
398 }
399
400 event_set(&_this->ev_sock_gre, _this->sock_gre, EV_READ0x02 | EV_PERSIST0x10,
401 pptpd_gre_io_event, _this);
402 event_add(&_this->ev_sock_gre, NULL((void *)0));
403
404 return 0;
405fail:
406 if (sock >= 0)
407 close(sock);
408 if (sock_gre >= 0)
409 close(sock_gre);
410
411 _this->sock = -1;
412 _this->sock_gre = -1;
413
414 return 1;
415}
416
417int
418pptpd_start(pptpd *_this)
419{
420 int rval = 0;
421 pptpd_listener *plistener;
422
423 slist_itr_first(&_this->listener);
424 while (slist_itr_has_next(&_this->listener)) {
425 plistener = slist_itr_next(&_this->listener);
426 PPTPD_ASSERT(plistener != NULL);
427 rval |= pptpd_listener_start(plistener);
428 }
429 if (rval == 0)
430 _this->state = PPTPD_STATE_RUNNING1;
431
432 return rval;
433}
434
435static void
436pptpd_listener_close_gre(pptpd_listener *_this)
437{
438 if (_this->sock_gre >= 0) {
439 event_del(&_this->ev_sock_gre);
440 close(_this->sock_gre);
441 pptpd_log(_this->self, LOG_INFO6, "Shutdown %s/gre",
442 inet_ntoa(_this->bind_sin_gre.sin_addr));
443 }
444 _this->sock_gre = -1;
445}
446
447static void
448pptpd_close_gre(pptpd *_this)
449{
450 pptpd_listener *plistener;
451
452 slist_itr_first(&_this->listener);
453 while (slist_itr_has_next(&_this->listener)) {
454 plistener = slist_itr_next(&_this->listener);
455 pptpd_listener_close_gre(plistener);
456 }
457}
458
459static void
460pptpd_listener_close_1723(pptpd_listener *_this)
461{
462 if (_this->sock >= 0) {
463 accept_del(_this->sock);
464 close(_this->sock);
465 pptpd_log(_this->self, LOG_INFO6, "Shutdown %s:%u/tcp",
466 inet_ntoa(_this->bind_sin.sin_addr),
467 ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port
) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) &
0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port
) & 0xff00U) >> 8) : __swap16md(_this->bind_sin.
sin_port))
);
468 }
469 _this->sock = -1;
470}
471
472static void
473pptpd_close_1723(pptpd *_this)
474{
475 pptpd_listener *plistener;
476
477 slist_itr_first(&_this->listener);
478 while (slist_itr_has_next(&_this->listener)) {
479 plistener = slist_itr_next(&_this->listener);
480 pptpd_listener_close_1723(plistener);
481 }
482}
483
484void
485pptpd_stop_immediatly(pptpd *_this)
486{
487 pptp_ctrl *ctrl;
488
489 if (event_initialized(&_this->ev_timer)((&_this->ev_timer)->ev_flags & 0x80))
490 evtimer_del(&_this->ev_timer)event_del(&_this->ev_timer);
491 if (_this->state != PPTPD_STATE_STOPPED3) {
492 /* lock, to avoid multiple call from pptp_ctrl_stop() */
493 _this->state = PPTPD_STATE_STOPPED3;
494
495 pptpd_close_1723(_this);
496 for (slist_itr_first(&_this->ctrl_list);
497 (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL((void *)0);) {
498 pptp_ctrl_stop(ctrl, 0);
499 }
500 pptpd_close_gre(_this);
501 slist_fini(&_this->ctrl_list);
502 slist_fini(&_this->call_free_list);
503 PPTPD_DBG((_this, LOG_DEBUG, "Stopped"));
504 } else {
505 PPTPD_DBG((_this, LOG_DEBUG, "(Already) Stopped"));
506 }
507}
508
509static void
510pptpd_stop_timeout(int fd, short event, void *ctx)
511{
512 pptpd *_this;
513
514 _this = ctx;
515 pptpd_stop_immediatly(_this);
516}
517
518void
519pptpd_stop(pptpd *_this)
520{
521 int nctrl;
522 pptp_ctrl *ctrl;
523 struct timeval tv;
524
525 if (event_initialized(&_this->ev_timer)((&_this->ev_timer)->ev_flags & 0x80))
526 evtimer_del(&_this->ev_timer)event_del(&_this->ev_timer);
527 pptpd_close_1723(_this);
528
529 /* XXX: use common procedure with l2tpd_stop */
530
531 if (pptpd_is_stopped(_this)(((_this)->state != 2 && (_this)->state != 1)? 1
: 0)
)
532 return;
533 if (pptpd_is_shutting_down(_this)(((_this)->state == 2)? 1 : 0)) {
534 pptpd_stop_immediatly(_this);
535 return;
536 }
537 _this->state = PPTPD_STATE_SHUTTING_DOWN2;
538 nctrl = 0;
539 for (slist_itr_first(&_this->ctrl_list);
540 (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL((void *)0);) {
541 pptp_ctrl_stop(ctrl, PPTP_CDN_RESULT_ADMIN_SHUTDOWN3);
542 nctrl++;
543 }
544 if (nctrl > 0) {
545 tv.tv_sec = PPTPD_SHUTDOWN_TIMEOUT5;
546 tv.tv_usec = 0;
547
548 evtimer_set(&_this->ev_timer, pptpd_stop_timeout, _this)event_set(&_this->ev_timer, -1, 0, pptpd_stop_timeout,
_this)
;
549 evtimer_add(&_this->ev_timer, &tv)event_add(&_this->ev_timer, &tv);
550
551 return;
552 }
553 pptpd_stop_immediatly(_this);
554}
555
556/*
557 * PPTP Configuration
558 */
559int
560pptpd_reload(pptpd *_this, struct pptp_confs *pptp_conf)
561{
562 int i;
563 struct pptp_conf *conf;
564 pptpd_listener *listener;
565 struct pptp_listen_addr *addr;
566
567 if (slist_length(&_this->listener) > 0) {
568 /*
569 * TODO: add / remove / restart listener.
570 */
571 slist_itr_first(&_this->listener);
572 while (slist_itr_has_next(&_this->listener)) {
573 listener = slist_itr_next(&_this->listener);
574 TAILQ_FOREACH(conf, pptp_conf, entry)for((conf) = ((pptp_conf)->tqh_first); (conf) != ((void *)
0); (conf) = ((conf)->entry.tqe_next))
{
575 if (strcmp(listener->tun_name,
576 conf->name) == 0) {
577 listener->conf = conf;
578 break;
579 }
580 }
581 }
582
583 return 0;
584 }
585
586 i = 0;
587 TAILQ_FOREACH(conf, pptp_conf, entry)for((conf) = ((pptp_conf)->tqh_first); (conf) != ((void *)
0); (conf) = ((conf)->entry.tqe_next))
{
588 TAILQ_FOREACH(addr, &conf->listen, entry)for((addr) = ((&conf->listen)->tqh_first); (addr) !=
((void *)0); (addr) = ((addr)->entry.tqe_next))
589 pptpd_add_listener(_this, i++, conf,
590 (struct sockaddr *)&addr->addr);
591 }
592 if (pptpd_start(_this) != 0)
593 return -1;
594
595 return 0;
596}
597
598/*
599 * I/O functions
600 */
601/* I/O event handler of 1723/tcp */
602static void
603pptpd_io_event(int fd, short evmask, void *ctx)
604{
605 int newsock;
606 const char *reason;
607 socklen_t peerlen;
608 struct sockaddr_storage peer;
609 pptpd *_this;
610 pptpd_listener *listener;
611
612 listener = ctx;
613 PPTPD_ASSERT(listener != NULL);
614 _this = listener->self;
615 PPTPD_ASSERT(_this != NULL);
616
617 if ((evmask & EV_READ0x02) != 0) {
618 for (;;) { /* accept till EAGAIN occurred */
619 peerlen = sizeof(peer);
620 if ((newsock = accept(listener->sock,
621 (struct sockaddr *)&peer, &peerlen)) < 0) {
622 if (errno(*__errno()) != EAGAIN35 && errno(*__errno()) == EINTR4 &&
623 errno(*__errno()) != ECONNABORTED53) {
624 if (errno(*__errno()) == EMFILE24 || errno(*__errno()) == ENFILE23)
625 accept_pause();
626 pptpd_log(_this, LOG_ERR3,
627 "accept() failed at %s(): %m",
628 __func__);
629 }
630 break;
631 }
632 /* check peer */
633 switch (peer.ss_family) {
634 case AF_INET2:
635 pptp_ctrl_start_by_pptpd(_this, newsock,
636 listener->index, (struct sockaddr *)&peer);
637 break;
638 default:
639 reason = "address family is not supported.";
Value stored to 'reason' is never read
640 break;
641 }
642 }
643 }
644}
645
646/* I/O event handler of GRE */
647static void
648pptpd_gre_io_event(int fd, short evmask, void *ctx)
649{
650 int sz;
651 u_char pkt[65535];
652 socklen_t peerlen;
653 struct sockaddr_storage peer;
654 pptpd *_this;
655 pptpd_listener *listener;
656
657 listener = ctx;
658 PPTPD_ASSERT(listener != NULL);
659 _this = listener->self;
660 PPTPD_ASSERT(_this != NULL);
661
662 if (evmask & EV_READ0x02) {
663 for (;;) {
664 /* read till bloked */
665 peerlen = sizeof(peer);
666 if ((sz = recvfrom(listener->sock_gre, pkt, sizeof(pkt),
667 0, (struct sockaddr *)&peer, &peerlen)) == -1) {
668 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
669 break;
670 pptpd_log(_this, LOG_INFO6,
671 "read(GRE) failed: %m");
672 pptpd_stop(_this);
673 return;
674 }
675 pptpd_gre_input(listener, (struct sockaddr *)&peer, pkt,
676 sz);
677 }
678 }
679}
680
681/* receive GRE then route to pptp_call */
682static void
683pptpd_gre_input(pptpd_listener *listener, struct sockaddr *peer, u_char *pkt,
684 int lpkt)
685{
686 int hlen, input_flags;
687 uint32_t seq, ack, call_id;
688 struct ip *iphdr;
689 struct pptp_gre_header *grehdr;
690 char hbuf0[NI_MAXHOST256], logbuf[512];
691 const char *reason;
692 pptp_call *call;
693 hash_link *hl;
694 pptpd *_this;
695
696 seq = 0;
697 ack = 0;
698 input_flags = 0;
699 reason = "No error";
700 _this = listener->self;
701
702 PPTPD_ASSERT(peer->sa_family == AF_INET);
703
704 strlcpy(hbuf0, "<unknown>", sizeof(hbuf0));
705 if (getnameinfo(peer, peer->sa_len, hbuf0, sizeof(hbuf0), NULL((void *)0), 0,
706 NI_NUMERICHOST1 | NI_NUMERICSERV2) != 0) {
707 pptpd_log(_this, LOG_ERR3,
708 "getnameinfo() failed at %s(): %m", __func__);
709 goto fail;
710 }
711 if (listener->conf->data_in_pktdump != 0) {
712 pptpd_log(_this, LOG_DEBUG7, "PPTP Data input packet dump");
713 show_hd(debug_get_debugfp(), pkt, lpkt);
714 }
715 if (peer->sa_family != AF_INET2) {
716 pptpd_log(_this, LOG_ERR3,
717 "Received malformed GRE packet: address family is not "
718 "supported: peer=%s af=%d", hbuf0, peer->sa_family);
719 goto fail;
720 }
721
722 if (lpkt < sizeof(struct ip)) {
723 pptpd_log(_this, LOG_ERR3,
724 "Received a short length packet length=%d, from %s", lpkt,
725 hbuf0);
726 goto fail;
727 }
728 iphdr = (struct ip *)pkt;
729
730 iphdr->ip_len = ntohs(iphdr->ip_len)(__uint16_t)(__builtin_constant_p(iphdr->ip_len) ? (__uint16_t
)(((__uint16_t)(iphdr->ip_len) & 0xffU) << 8 | (
(__uint16_t)(iphdr->ip_len) & 0xff00U) >> 8) : __swap16md
(iphdr->ip_len))
;
731 hlen = iphdr->ip_hl * 4;
732
733 if (iphdr->ip_len > lpkt ||
734 iphdr->ip_len < hlen + sizeof(struct pptp_gre_header)) {
735 pptpd_log(_this, LOG_ERR3,
736 "Received a broken packet: ip_hl=%d iplen=%d lpkt=%d", hlen,
737 iphdr->ip_len, lpkt);
738 show_hd(debug_get_debugfp(), pkt, lpkt);
739 goto fail;
740 }
741 pkt += hlen;
742 lpkt -= hlen;
743 grehdr = (struct pptp_gre_header *)pkt;
744 pkt += sizeof(struct pptp_gre_header);
745 lpkt -= sizeof(struct pptp_gre_header);
746
747 grehdr->protocol_type = htons(grehdr->protocol_type)(__uint16_t)(__builtin_constant_p(grehdr->protocol_type) ?
(__uint16_t)(((__uint16_t)(grehdr->protocol_type) & 0xffU
) << 8 | ((__uint16_t)(grehdr->protocol_type) & 0xff00U
) >> 8) : __swap16md(grehdr->protocol_type))
;
748 grehdr->payload_length = htons(grehdr->payload_length)(__uint16_t)(__builtin_constant_p(grehdr->payload_length) ?
(__uint16_t)(((__uint16_t)(grehdr->payload_length) & 0xffU
) << 8 | ((__uint16_t)(grehdr->payload_length) &
0xff00U) >> 8) : __swap16md(grehdr->payload_length)
)
;
749 grehdr->call_id = htons(grehdr->call_id)(__uint16_t)(__builtin_constant_p(grehdr->call_id) ? (__uint16_t
)(((__uint16_t)(grehdr->call_id) & 0xffU) << 8 |
((__uint16_t)(grehdr->call_id) & 0xff00U) >> 8)
: __swap16md(grehdr->call_id))
;
750
751 if (!(grehdr->protocol_type == PPTP_GRE_PROTOCOL_TYPE0x880b &&
752 grehdr->C == 0 && grehdr->R == 0 && grehdr->K != 0 &&
753 grehdr->recur == 0 && grehdr->s == 0 && grehdr->flags == 0 &&
754 grehdr->ver == PPTP_GRE_VERSION1)) {
755 reason = "GRE header is broken";
756 goto bad_gre;
757 }
758 if (grehdr->S != 0) {
759 if (lpkt < 2) {
760 reason = "No enough space for seq number";
761 goto bad_gre;
762 }
763 input_flags |= PPTP_GRE_PKT_SEQ_PRESENT0x0001;
764 seq = ntohl(*(uint32_t *)pkt)(__uint32_t)(__builtin_constant_p(*(uint32_t *)pkt) ? (__uint32_t
)(((__uint32_t)(*(uint32_t *)pkt) & 0xff) << 24 | (
(__uint32_t)(*(uint32_t *)pkt) & 0xff00) << 8 | ((__uint32_t
)(*(uint32_t *)pkt) & 0xff0000) >> 8 | ((__uint32_t
)(*(uint32_t *)pkt) & 0xff000000) >> 24) : __swap32md
(*(uint32_t *)pkt))
;
765 pkt += 4;
766 lpkt -= 4;
767 }
768
769 if (grehdr->A != 0) {
770 if (lpkt < 2) {
771 reason = "No enough space for ack number";
772 goto bad_gre;
773 }
774 input_flags |= PPTP_GRE_PKT_ACK_PRESENT0x0002;
775 ack = ntohl(*(uint32_t *)pkt)(__uint32_t)(__builtin_constant_p(*(uint32_t *)pkt) ? (__uint32_t
)(((__uint32_t)(*(uint32_t *)pkt) & 0xff) << 24 | (
(__uint32_t)(*(uint32_t *)pkt) & 0xff00) << 8 | ((__uint32_t
)(*(uint32_t *)pkt) & 0xff0000) >> 8 | ((__uint32_t
)(*(uint32_t *)pkt) & 0xff000000) >> 24) : __swap32md
(*(uint32_t *)pkt))
;
776 pkt += 4;
777 lpkt -= 4;
778 }
779
780 if (grehdr->payload_length > lpkt) {
781 reason = "'Payload Length' is mismatch from actual length";
782 goto bad_gre;
783 }
784
785
786 /* route to pptp_call */
787 call_id = grehdr->call_id;
788
789 hl = hash_lookup(_this->call_id_map, CALL_ID_KEY(call_id, listener->index)((void *)((uintptr_t)(call_id) | (listener->index) <<
16))
);
790 if (hl == NULL((void *)0)) {
791 reason = "Received GRE packet has unknown call_id";
792 goto bad_gre;
793 }
794 call = hl->item;
795 pptp_call_gre_input(call, seq, ack, input_flags, pkt, lpkt);
796
797 return;
798bad_gre:
799 pptp_gre_header_string(grehdr, logbuf, sizeof(logbuf));
800 pptpd_log(_this, LOG_INFO6,
801 "Received malformed GRE packet: %s: peer=%s sock=%s %s seq=%u: "
802 "ack=%u ifidx=%d", reason, hbuf0, inet_ntoa(iphdr->ip_dst), logbuf,
803 seq, ack, listener->index);
804fail:
805 return;
806}
807
808/* start PPTP control, when new connection is established */
809static void
810pptp_ctrl_start_by_pptpd(pptpd *_this, int sock, int listener_index,
811 struct sockaddr *peer)
812{
813 pptp_ctrl *ctrl;
814 socklen_t sslen;
815
816 ctrl = NULL((void *)0);
817 if ((ctrl = pptp_ctrl_create()) == NULL((void *)0))
818 goto fail;
819 if (pptp_ctrl_init(ctrl) != 0)
820 goto fail;
821
822 memset(&ctrl->peer, 0, sizeof(ctrl->peer));
823 memcpy(&ctrl->peer, peer, peer->sa_len);
824 ctrl->pptpd = _this;
825 ctrl->sock = sock;
826 ctrl->listener_index = listener_index;
827
828 sslen = sizeof(ctrl->our);
829 if (getsockname(ctrl->sock, (struct sockaddr *)&ctrl->our,
830 &sslen) != 0) {
831 pptpd_log(_this, LOG_WARNING4,
832 "getsockname() failed at %s(): %m", __func__);
833 goto fail;
834 }
835
836 if (PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener
, (ctrl)->listener_index))->conf
->echo_interval != 0)
837 ctrl->echo_interval = PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener
, (ctrl)->listener_index))->conf
->echo_interval;
838 if (PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener
, (ctrl)->listener_index))->conf
->echo_timeout != 0)
839 ctrl->echo_timeout = PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener
, (ctrl)->listener_index))->conf
->echo_timeout;
840
841 if (pptp_ctrl_start(ctrl) != 0)
842 goto fail;
843
844 slist_add(&_this->ctrl_list, ctrl);
845
846 return;
847fail:
848 close(sock);
849 pptp_ctrl_destroy(ctrl);
850 return;
851}
852
853void
854pptpd_ctrl_finished_notify(pptpd *_this, pptp_ctrl *ctrl)
855{
856 pptp_ctrl *ctrl1;
857 int i, nctrl;
858
859 PPTPD_ASSERT(_this != NULL);
860 PPTPD_ASSERT(ctrl != NULL);
861
862 accept_unpause();
863
864 nctrl = 0;
865 for (i = 0; i < slist_length(&_this->ctrl_list); i++) {
866 ctrl1 = slist_get(&_this->ctrl_list, i);
867 if (ctrl1 == ctrl) {
868 slist_remove(&_this->ctrl_list, i);
869 break;
870 }
871 }
872 pptp_ctrl_destroy(ctrl);
873
874 PPTPD_DBG((_this, LOG_DEBUG, "Remains %d ctrls", nctrl));
875 if (pptpd_is_shutting_down(_this)(((_this)->state == 2)? 1 : 0) && nctrl == 0)
876 pptpd_stop_immediatly(_this);
877}
878
879/*
880 * utility functions
881 */
882
883/* logging with the this PPTP instance */
884static void
885pptpd_log(pptpd *_this, int prio, const char *fmt, ...)
886{
887 char logbuf[BUFSIZ1024];
888 va_list ap;
889
890 PPTPD_ASSERT(_this != NULL);
891 va_start(ap, fmt)__builtin_va_start(ap, fmt);
892#ifdef PPTPD_MULTIPLE
893 snprintf(logbuf, sizeof(logbuf), "pptpd id=%u %s", _this->id, fmt);
894#else
895 snprintf(logbuf, sizeof(logbuf), "pptpd %s", fmt);
896#endif
897 vlog_printf(prio, logbuf, ap);
898 va_end(ap)__builtin_va_end(ap);
899}
900
901static int
902pptp_call_cmp(const void *a0, const void *b0)
903{
904 return ((intptr_t)a0 - (intptr_t)b0);
905}
906
907static uint32_t
908pptp_call_hash(const void *ctx, int size)
909{
910 return (uintptr_t)ctx % size;
911}
912
913/* convert GRE packet header to strings */
914static void
915pptp_gre_header_string(struct pptp_gre_header *grehdr, char *buf, int lbuf)
916{
917 snprintf(buf, lbuf,
918 "[%s%s%s%s%s%s] ver=%d "
919 "protocol_type=%04x payload_length=%d call_id=%d",
920 (grehdr->C != 0)? "C" : "", (grehdr->R != 0)? "R" : "",
921 (grehdr->K != 0)? "K" : "", (grehdr->S != 0)? "S" : "",
922 (grehdr->s != 0)? "s" : "", (grehdr->A != 0)? "A" : "", grehdr->ver,
923 grehdr->protocol_type, grehdr->payload_length, grehdr->call_id);
924}