File: | src/usr.sbin/npppd/npppd/privsep.c |
Warning: | line 717, column 10 Although the value stored to 'retval' is used in the enclosing expression, the value is never actually read from 'retval' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: privsep.c,v 1.24 2020/01/23 00:17:27 dlg Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2010 Yasuoka Masahiko <yasuoka@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | #include <sys/queue.h> |
19 | #include <sys/uio.h> |
20 | #include <sys/socket.h> |
21 | #include <sys/ioctl.h> |
22 | #include <arpa/inet.h> |
23 | #include <net/if.h> |
24 | #include <net/pfkeyv2.h> |
25 | #include <netinet/in.h> |
26 | |
27 | #include <errno(*__errno()).h> |
28 | #include <fcntl.h> |
29 | #include <imsg.h> |
30 | #include <stddef.h> |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | #include <unistd.h> |
34 | |
35 | #include "pathnames.h" |
36 | #include "privsep.h" |
37 | |
38 | #include "npppd.h" |
39 | #include "ppp.h" |
40 | |
41 | #ifndef nitems |
42 | #define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0])) |
43 | #endif |
44 | |
45 | enum imsg_code { |
46 | PRIVSEP_OK, |
47 | PRIVSEP_OPEN, |
48 | PRIVSEP_SOCKET, |
49 | PRIVSEP_BIND, |
50 | PRIVSEP_SENDTO, |
51 | PRIVSEP_UNLINK, |
52 | PRIVSEP_GET_USER_INFO, |
53 | PRIVSEP_GET_IF_ADDR, |
54 | PRIVSEP_SET_IF_ADDR, |
55 | PRIVSEP_DEL_IF_ADDR, |
56 | PRIVSEP_GET_IF_FLAGS, |
57 | PRIVSEP_SET_IF_FLAGS |
58 | }; |
59 | |
60 | struct PRIVSEP_OPEN_ARG { |
61 | char path[PATH_MAX1024]; |
62 | int flags; |
63 | }; |
64 | |
65 | struct PRIVSEP_SOCKET_ARG { |
66 | int domain; |
67 | int type; |
68 | int protocol; |
69 | }; |
70 | |
71 | struct PRIVSEP_BIND_ARG { |
72 | struct sockaddr_storage name; |
73 | socklen_t namelen; |
74 | }; |
75 | |
76 | struct PRIVSEP_SENDTO_ARG { |
77 | size_t len; |
78 | int flags; |
79 | struct sockaddr_storage to; |
80 | socklen_t tolen; |
81 | u_char msg[0]; |
82 | }; |
83 | |
84 | struct PRIVSEP_UNLINK_ARG { |
85 | char path[PATH_MAX1024]; |
86 | }; |
87 | |
88 | struct PRIVSEP_GET_USER_INFO_ARG { |
89 | char path[PATH_MAX1024]; |
90 | char username[MAX_USERNAME_LENGTH256]; |
91 | }; |
92 | |
93 | struct PRIVSEP_GET_IF_ADDR_ARG { |
94 | char ifname[IFNAMSIZ16]; |
95 | }; |
96 | |
97 | struct PRIVSEP_GET_IF_ADDR_RESP { |
98 | int retval; |
99 | int rerrno; |
100 | struct in_addr addr; |
101 | }; |
102 | |
103 | struct PRIVSEP_SET_IF_ADDR_ARG { |
104 | char ifname[IFNAMSIZ16]; |
105 | struct in_addr addr; |
106 | }; |
107 | |
108 | struct PRIVSEP_DEL_IF_ADDR_ARG { |
109 | char ifname[IFNAMSIZ16]; |
110 | }; |
111 | |
112 | struct PRIVSEP_GET_IF_FLAGS_ARG { |
113 | char ifname[IFNAMSIZ16]; |
114 | int flags; |
115 | }; |
116 | |
117 | struct PRIVSEP_GET_IF_FLAGS_RESP { |
118 | int retval; |
119 | int rerrno; |
120 | int flags; |
121 | }; |
122 | |
123 | struct PRIVSEP_SET_IF_FLAGS_ARG { |
124 | char ifname[IFNAMSIZ16]; |
125 | int flags; |
126 | }; |
127 | |
128 | struct PRIVSEP_COMMON_RESP { |
129 | int retval; |
130 | int rerrno; |
131 | }; |
132 | |
133 | struct PRIVSEP_GET_USER_INFO_RESP { |
134 | int retval; |
135 | int rerrno; |
136 | char password[MAX_PASSWORD_LENGTH256]; |
137 | struct in_addr framed_ip_address; |
138 | struct in_addr framed_ip_netmask; |
139 | char calling_number[NPPPD_PHONE_NUMBER_LEN32 + 1]; |
140 | }; |
141 | |
142 | static void privsep_priv_main (int); |
143 | static void privsep_priv_dispatch_imsg (struct imsgbuf *); |
144 | int imsg_read_and_get(struct imsgbuf *, struct imsg *); |
145 | static int startswith(const char *, const char *); |
146 | static int privsep_recvfd (void); |
147 | static int privsep_common_resp (void); |
148 | |
149 | static int privsep_npppd_check_open (struct PRIVSEP_OPEN_ARG *); |
150 | static int privsep_npppd_check_socket (struct PRIVSEP_SOCKET_ARG *); |
151 | static int privsep_npppd_check_bind (struct PRIVSEP_BIND_ARG *); |
152 | static int privsep_npppd_check_sendto (struct PRIVSEP_SENDTO_ARG *); |
153 | static int privsep_npppd_check_unlink (struct PRIVSEP_UNLINK_ARG *); |
154 | static int privsep_npppd_check_get_user_info ( |
155 | struct PRIVSEP_GET_USER_INFO_ARG *); |
156 | static int privsep_npppd_check_get_if_addr ( |
157 | struct PRIVSEP_GET_IF_ADDR_ARG *); |
158 | static int privsep_npppd_check_set_if_addr ( |
159 | struct PRIVSEP_SET_IF_ADDR_ARG *); |
160 | static int privsep_npppd_check_del_if_addr ( |
161 | struct PRIVSEP_DEL_IF_ADDR_ARG *); |
162 | static int privsep_npppd_check_get_if_flags ( |
163 | struct PRIVSEP_GET_IF_FLAGS_ARG *); |
164 | static int privsep_npppd_check_set_if_flags ( |
165 | struct PRIVSEP_SET_IF_FLAGS_ARG *); |
166 | |
167 | static int privsep_sock = -1; |
168 | static struct imsgbuf privsep_ibuf; |
169 | static pid_t privsep_pid; |
170 | |
171 | int |
172 | privsep_init(void) |
173 | { |
174 | pid_t pid; |
175 | int pairsock[2]; |
176 | |
177 | if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, pairsock) == -1) |
178 | return (-1); |
179 | |
180 | if ((pid = fork()) < 0) |
181 | goto fail; |
182 | else if (pid == 0) { |
183 | setsid(); |
184 | /* privileged process */ |
185 | setproctitle("[priv]"); |
186 | close(pairsock[1]); |
187 | privsep_priv_main(pairsock[0]); |
188 | _exit(0); |
189 | /* NOTREACHED */ |
190 | } |
191 | close(pairsock[0]); |
192 | privsep_sock = pairsock[1]; |
193 | privsep_pid = pid; |
194 | imsg_init(&privsep_ibuf, privsep_sock); |
195 | |
196 | return (0); |
197 | /* NOTREACHED */ |
198 | fail: |
199 | if (pairsock[0] >= 0) { |
200 | close(pairsock[0]); |
201 | close(pairsock[1]); |
202 | } |
203 | |
204 | return (-1); |
205 | } |
206 | |
207 | void |
208 | privsep_fini(void) |
209 | { |
210 | imsg_clear(&privsep_ibuf); |
211 | if (privsep_sock >= 0) { |
212 | close(privsep_sock); |
213 | privsep_sock = -1; |
214 | } |
215 | } |
216 | |
217 | pid_t |
218 | privsep_priv_pid(void) |
219 | { |
220 | return (privsep_pid); |
221 | } |
222 | |
223 | /*********************************************************************** |
224 | * Functions for from jail |
225 | ***********************************************************************/ |
226 | int |
227 | priv_bind(int sock, const struct sockaddr *name, socklen_t namelen) |
228 | { |
229 | struct PRIVSEP_BIND_ARG a; |
230 | |
231 | if (namelen > sizeof(a.name)) { |
232 | errno(*__errno()) = EINVAL22; |
233 | return (-1); |
234 | } |
235 | if ((sock = dup(sock)) == -1) |
236 | return (-1); |
237 | |
238 | memcpy(&a.name, name, namelen); |
239 | a.namelen = namelen; |
240 | |
241 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_BIND, 0, 0, sock, |
242 | &a, sizeof(a)); |
243 | imsg_flush(&privsep_ibuf); |
244 | |
245 | return (privsep_common_resp()); |
246 | } |
247 | |
248 | int |
249 | priv_socket(int domain, int type, int protocol) |
250 | { |
251 | struct PRIVSEP_SOCKET_ARG a; |
252 | |
253 | a.domain = domain; |
254 | a.type = type; |
255 | a.protocol = protocol; |
256 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_SOCKET, 0, 0, -1, |
257 | &a, sizeof(a)); |
258 | imsg_flush(&privsep_ibuf); |
259 | |
260 | return (privsep_recvfd()); |
261 | } |
262 | |
263 | int |
264 | priv_open(const char *path, int flags) |
265 | { |
266 | struct PRIVSEP_OPEN_ARG a; |
267 | |
268 | strlcpy(a.path, path, sizeof(a.path)); |
269 | a.flags = flags; |
270 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_OPEN, 0, 0, -1, |
271 | &a, sizeof(a)); |
272 | imsg_flush(&privsep_ibuf); |
273 | |
274 | return (privsep_recvfd()); |
275 | } |
276 | |
277 | FILE * |
278 | priv_fopen(const char *path) |
279 | { |
280 | int f; |
281 | FILE *fp; |
282 | |
283 | if ((f = priv_open(path, O_RDONLY0x0000)) < 0) |
284 | return (NULL((void *)0)); |
285 | |
286 | if ((fp = fdopen(f, "r")) == NULL((void *)0)) { |
287 | close(f); |
288 | return (NULL((void *)0)); |
289 | } else |
290 | return (fp); |
291 | } |
292 | |
293 | int |
294 | priv_sendto(int s, const void *msg, int len, int flags, |
295 | const struct sockaddr *to, socklen_t tolen) |
296 | { |
297 | struct PRIVSEP_SENDTO_ARG a; |
298 | struct iovec iov[2]; |
299 | |
300 | if (tolen > sizeof(a.to)) { |
301 | errno(*__errno()) = EINVAL22; |
302 | return (-1); |
303 | } |
304 | if ((s = dup(s)) == -1) |
305 | return (-1); |
306 | |
307 | a.len = len; |
308 | a.flags = flags; |
309 | a.tolen = tolen; |
310 | if (tolen > 0) |
311 | memcpy(&a.to, to, tolen); |
312 | iov[0].iov_base = &a; |
313 | iov[0].iov_len = offsetof(struct PRIVSEP_SENDTO_ARG, msg)__builtin_offsetof(struct PRIVSEP_SENDTO_ARG, msg); |
314 | iov[1].iov_base = (void *)msg; |
315 | iov[1].iov_len = len; |
316 | |
317 | (void)imsg_composev(&privsep_ibuf, PRIVSEP_SENDTO, 0, 0, s, |
318 | iov, nitems(iov)(sizeof((iov)) / sizeof((iov)[0]))); |
319 | imsg_flush(&privsep_ibuf); |
320 | |
321 | return (privsep_common_resp()); |
322 | } |
323 | |
324 | int |
325 | priv_send(int s, const void *msg, int len, int flags) |
326 | { |
327 | return (priv_sendto(s, msg, len, flags, NULL((void *)0), 0)); |
328 | } |
329 | |
330 | int |
331 | priv_unlink(const char *path) |
332 | { |
333 | struct PRIVSEP_UNLINK_ARG a; |
334 | |
335 | strlcpy(a.path, path, sizeof(a.path)); |
336 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_UNLINK, 0, 0, -1, |
337 | &a, sizeof(a)); |
338 | imsg_flush(&privsep_ibuf); |
339 | |
340 | return (privsep_common_resp()); |
341 | } |
342 | |
343 | int |
344 | priv_get_user_info(const char *path, const char *username, |
345 | npppd_auth_user **puser) |
346 | { |
347 | struct imsg imsg; |
348 | ssize_t n; |
349 | struct PRIVSEP_GET_USER_INFO_RESP *r; |
350 | struct PRIVSEP_GET_USER_INFO_ARG a; |
351 | npppd_auth_user *u; |
352 | char *cp; |
353 | int sz; |
354 | |
355 | strlcpy(a.path, path, sizeof(a.path)); |
356 | strlcpy(a.username, username, sizeof(a.username)); |
357 | |
358 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_USER_INFO, 0, 0, -1, |
359 | &a, sizeof(a)); |
360 | imsg_flush(&privsep_ibuf); |
361 | |
362 | if ((n = imsg_read_and_get(&privsep_ibuf, &imsg)) == -1) |
363 | return (-1); |
364 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*r)) { |
365 | errno(*__errno()) = EACCES13; |
366 | goto on_error; |
367 | } |
368 | r = imsg.data; |
369 | if (r->retval != 0) { |
370 | errno(*__errno()) = r->rerrno; |
371 | goto on_error; |
372 | } |
373 | |
374 | sz = strlen(username) + strlen(r->password) + |
375 | strlen(r->calling_number) + 3; |
376 | |
377 | if ((u = malloc(offsetof(npppd_auth_user, space[sz])__builtin_offsetof(npppd_auth_user, space[sz]))) == NULL((void *)0)) |
378 | goto on_error; |
379 | |
380 | cp = u->space; |
381 | |
382 | u->username = cp; |
383 | n = strlcpy(cp, username, sz); |
384 | cp += ++n; sz -= n; |
385 | |
386 | u->password = cp; |
387 | n = strlcpy(cp, r->password, sz); |
388 | cp += ++n; sz -= n; |
389 | |
390 | u->calling_number = cp; |
391 | n = strlcpy(cp, r->calling_number, sz); |
392 | cp += ++n; sz -= n; |
393 | |
394 | u->framed_ip_address = r->framed_ip_address; |
395 | u->framed_ip_netmask = r->framed_ip_netmask; |
396 | |
397 | *puser = u; |
398 | imsg_free(&imsg); |
399 | |
400 | return (0); |
401 | |
402 | on_error: |
403 | imsg_free(&imsg); |
404 | return (-1); |
405 | } |
406 | |
407 | int |
408 | priv_get_if_addr(const char *ifname, struct in_addr *addr) |
409 | { |
410 | struct PRIVSEP_GET_IF_ADDR_ARG a; |
411 | struct PRIVSEP_GET_IF_ADDR_RESP *r; |
412 | struct imsg imsg; |
413 | int retval = -1; |
414 | |
415 | strlcpy(a.ifname, ifname, sizeof(a.ifname)); |
416 | |
417 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_IF_ADDR, 0, 0, -1, |
418 | &a, sizeof(a)); |
419 | imsg_flush(&privsep_ibuf); |
420 | |
421 | if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) |
422 | return (-1); |
423 | |
424 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*r)) |
425 | errno(*__errno()) = EACCES13; |
426 | else { |
427 | r = imsg.data; |
428 | if (r->retval != -1) |
429 | *addr = r->addr; |
430 | else |
431 | errno(*__errno()) = r->rerrno; |
432 | retval = r->retval; |
433 | } |
434 | imsg_free(&imsg); |
435 | |
436 | return (retval); |
437 | } |
438 | |
439 | int |
440 | priv_delete_if_addr(const char *ifname) |
441 | { |
442 | struct PRIVSEP_DEL_IF_ADDR_ARG a; |
443 | |
444 | strlcpy(a.ifname, ifname, sizeof(a.ifname)); |
445 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_DEL_IF_ADDR, 0, 0, -1, |
446 | &a, sizeof(a)); |
447 | imsg_flush(&privsep_ibuf); |
448 | |
449 | return (privsep_common_resp()); |
450 | } |
451 | |
452 | int |
453 | priv_set_if_addr(const char *ifname, struct in_addr *addr) |
454 | { |
455 | struct PRIVSEP_SET_IF_ADDR_ARG a; |
456 | |
457 | strlcpy(a.ifname, ifname, sizeof(a.ifname)); |
458 | a.addr = *addr; |
459 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_SET_IF_ADDR, 0, 0, -1, |
460 | &a, sizeof(a)); |
461 | imsg_flush(&privsep_ibuf); |
462 | |
463 | return (privsep_common_resp()); |
464 | } |
465 | |
466 | int |
467 | priv_get_if_flags(const char *ifname, int *pflags) |
468 | { |
469 | struct PRIVSEP_GET_IF_FLAGS_ARG a; |
470 | struct PRIVSEP_GET_IF_FLAGS_RESP *r; |
471 | struct imsg imsg; |
472 | int retval = -1; |
473 | |
474 | strlcpy(a.ifname, ifname, sizeof(a.ifname)); |
475 | a.flags = 0; |
476 | |
477 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_IF_FLAGS, 0, 0, -1, |
478 | &a, sizeof(a)); |
479 | imsg_flush(&privsep_ibuf); |
480 | |
481 | if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) |
482 | return (-1); |
483 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*r)) |
484 | errno(*__errno()) = EACCES13; |
485 | else { |
486 | r = imsg.data; |
487 | *pflags = r->flags; |
488 | if (r->retval != 0) |
489 | errno(*__errno()) = r->rerrno; |
490 | retval = r->retval; |
491 | } |
492 | imsg_free(&imsg); |
493 | |
494 | return (retval); |
495 | } |
496 | |
497 | int |
498 | priv_set_if_flags(const char *ifname, int flags) |
499 | { |
500 | struct PRIVSEP_SET_IF_FLAGS_ARG a; |
501 | |
502 | strlcpy(a.ifname, ifname, sizeof(a.ifname)); |
503 | a.flags = flags; |
504 | |
505 | (void)imsg_compose(&privsep_ibuf, PRIVSEP_SET_IF_FLAGS, 0, 0, -1, |
506 | &a, sizeof(a)); |
507 | imsg_flush(&privsep_ibuf); |
508 | |
509 | return (privsep_common_resp()); |
510 | } |
511 | |
512 | static int |
513 | privsep_recvfd(void) |
514 | { |
515 | struct PRIVSEP_COMMON_RESP *r; |
516 | struct imsg imsg; |
517 | int retval = -1; |
518 | |
519 | if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) |
520 | return (-1); |
521 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*r)) |
522 | errno(*__errno()) = EACCES13; |
523 | else { |
524 | r = imsg.data; |
525 | retval = r->retval; |
526 | if (r->retval != 0) |
527 | errno(*__errno()) = r->rerrno; |
528 | else |
529 | retval = imsg.fd; |
530 | } |
531 | imsg_free(&imsg); |
532 | |
533 | return (retval); |
534 | } |
535 | |
536 | static int |
537 | privsep_common_resp(void) |
538 | { |
539 | struct PRIVSEP_COMMON_RESP *r; |
540 | struct imsg imsg; |
541 | int retval = -1; |
542 | |
543 | if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) { |
544 | errno(*__errno()) = EACCES13; |
545 | return (-1); |
546 | } |
547 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*r)) |
548 | errno(*__errno()) = EACCES13; |
549 | else { |
550 | r = imsg.data; |
551 | if (r->retval != 0) |
552 | errno(*__errno()) = r->rerrno; |
553 | retval = r->retval; |
554 | } |
555 | imsg_free(&imsg); |
556 | |
557 | return (retval); |
558 | } |
559 | |
560 | /*********************************************************************** |
561 | * privileged process |
562 | ***********************************************************************/ |
563 | static void |
564 | privsep_priv_main(int sock) |
565 | { |
566 | struct imsgbuf ibuf; |
567 | |
568 | imsg_init(&ibuf, sock); |
569 | privsep_priv_dispatch_imsg(&ibuf); |
570 | imsg_clear(&ibuf); |
571 | close(sock); |
572 | |
573 | exit(EXIT_SUCCESS0); |
574 | } |
575 | |
576 | static void |
577 | privsep_priv_dispatch_imsg(struct imsgbuf *ibuf) |
578 | { |
579 | struct imsg imsg; |
580 | |
581 | for (;;) { |
582 | if (imsg_read_and_get(ibuf, &imsg) == -1) |
583 | return; |
584 | |
585 | switch (imsg.hdr.type) { |
586 | case PRIVSEP_OPEN: { |
587 | int f = -1; |
588 | struct PRIVSEP_OPEN_ARG *a = imsg.data; |
589 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
590 | |
591 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
592 | r.rerrno = EINVAL22; |
593 | else if (privsep_npppd_check_open(a)) |
594 | r.rerrno = EACCES13; |
595 | else { |
596 | if ((f = open(a->path, a->flags & ~O_CREAT0x0200)) |
597 | == -1) |
598 | r.rerrno = errno(*__errno()); |
599 | else |
600 | r.retval = 0; |
601 | } |
602 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, f, |
603 | &r, sizeof(r)); |
604 | imsg_flush(ibuf); |
605 | } |
606 | break; |
607 | case PRIVSEP_SOCKET: { |
608 | int s = -1; |
609 | struct PRIVSEP_SOCKET_ARG *a = imsg.data; |
610 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
611 | |
612 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
613 | r.rerrno = EINVAL22; |
614 | else if (privsep_npppd_check_socket(a)) |
615 | r.rerrno = EACCES13; |
616 | else { |
617 | if ((s = socket(a->domain, a->type, |
618 | a->protocol)) == -1) |
619 | r.rerrno = errno(*__errno()); |
620 | else |
621 | r.retval = 0; |
622 | } |
623 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, s, |
624 | &r, sizeof(r)); |
625 | imsg_flush(ibuf); |
626 | } |
627 | break; |
628 | case PRIVSEP_UNLINK: { |
629 | struct PRIVSEP_UNLINK_ARG *a = imsg.data; |
630 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
631 | |
632 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
633 | r.rerrno = EINVAL22; |
634 | else if (privsep_npppd_check_unlink(a)) |
635 | r.rerrno = EACCES13; |
636 | else { |
637 | if ((r.retval = unlink(a->path)) != 0) |
638 | r.rerrno = errno(*__errno()); |
639 | } |
640 | |
641 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
642 | &r, sizeof(r)); |
643 | imsg_flush(ibuf); |
644 | } |
645 | break; |
646 | case PRIVSEP_BIND: { |
647 | struct PRIVSEP_BIND_ARG *a = imsg.data; |
648 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
649 | |
650 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a) || |
651 | imsg.fd < 0) |
652 | r.rerrno = EINVAL22; |
653 | else if (privsep_npppd_check_bind(a)) |
654 | r.rerrno = EACCES13; |
655 | else { |
656 | if ((r.retval = bind(imsg.fd, |
657 | (struct sockaddr *)&a->name, a->namelen)) |
658 | != 0) |
659 | r.rerrno = errno(*__errno()); |
660 | close(imsg.fd); |
661 | } |
662 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
663 | &r, sizeof(r)); |
664 | imsg_flush(ibuf); |
665 | } |
666 | break; |
667 | case PRIVSEP_GET_USER_INFO: { |
668 | struct PRIVSEP_GET_USER_INFO_ARG *a = imsg.data; |
669 | struct PRIVSEP_GET_USER_INFO_RESP r; |
670 | int retval; |
671 | char *str, *buf, *db[2] = { NULL((void *)0), NULL((void *)0) }; |
672 | |
673 | memset(&r, 0, sizeof(r)); |
674 | r.retval = -1; |
675 | r.framed_ip_address.s_addr = INADDR_NAS_SELECT((__uint32_t)(__builtin_constant_p(0xFFFFFFFEL) ? (__uint32_t )(((__uint32_t)(0xFFFFFFFEL) & 0xff) << 24 | ((__uint32_t )(0xFFFFFFFEL) & 0xff00) << 8 | ((__uint32_t)(0xFFFFFFFEL ) & 0xff0000) >> 8 | ((__uint32_t)(0xFFFFFFFEL) & 0xff000000) >> 24) : __swap32md(0xFFFFFFFEL))); |
676 | r.framed_ip_netmask.s_addr = INADDR_NONE((u_int32_t)(0xffffffff)); |
677 | str = buf = NULL((void *)0); |
678 | |
679 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) { |
680 | r.rerrno = EINVAL22; |
681 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
682 | &r, sizeof(r)); |
683 | return; |
684 | } |
685 | db[0] = a->path; |
686 | if (privsep_npppd_check_get_user_info(a)) |
687 | r.rerrno = EACCES13; |
688 | else if ((retval = cgetent(&buf, db, a->username)) |
689 | == 0) { |
690 | if ((retval = cgetstr(buf, "password", &str)) |
691 | >= 0) { |
692 | if (strlcpy(r.password, str, |
693 | sizeof(r.password)) >= |
694 | sizeof(r.password)) |
695 | goto on_broken_entry; |
696 | free(str); |
697 | str = NULL((void *)0); |
698 | } |
699 | if ((retval = cgetstr(buf, "calling-number", |
700 | &str)) >= 0) { |
701 | if (strlcpy(r.calling_number, str, |
702 | sizeof(r.calling_number)) >= |
703 | sizeof(r.calling_number)) |
704 | goto on_broken_entry; |
705 | free(str); |
706 | str = NULL((void *)0); |
707 | } |
708 | if ((retval = cgetstr(buf, "framed-ip-address", |
709 | &str)) >= 0) { |
710 | if (inet_aton(str, |
711 | &r.framed_ip_address) != 1) |
712 | goto on_broken_entry; |
713 | free(str); |
714 | str = NULL((void *)0); |
715 | } |
716 | |
717 | if ((retval = cgetstr(buf, "framed-ip-netmask", |
Although the value stored to 'retval' is used in the enclosing expression, the value is never actually read from 'retval' | |
718 | &str)) >= 0) { |
719 | if (inet_aton(str, |
720 | &r.framed_ip_netmask) != 1) |
721 | goto on_broken_entry; |
722 | free(str); |
723 | str = NULL((void *)0); |
724 | } |
725 | cgetclose(); |
726 | free(buf); |
727 | r.retval = 0; |
728 | } else if (retval == -1) { |
729 | buf = NULL((void *)0); |
730 | on_broken_entry: |
731 | free(buf); |
732 | free(str); |
733 | r.retval = -1; |
734 | r.rerrno = ENOENT2; |
735 | } else { |
736 | r.retval = retval; |
737 | r.rerrno = errno(*__errno()); |
738 | } |
739 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
740 | &r, sizeof(r)); |
741 | imsg_flush(ibuf); |
742 | } |
743 | break; |
744 | case PRIVSEP_SENDTO: { |
745 | struct PRIVSEP_SENDTO_ARG *a = imsg.data; |
746 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
747 | |
748 | if (imsg.hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a) || |
749 | imsg.hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
750 | offsetof(struct PRIVSEP_SENDTO_ARG,__builtin_offsetof(struct PRIVSEP_SENDTO_ARG, msg[a->len]) |
751 | msg[a->len])__builtin_offsetof(struct PRIVSEP_SENDTO_ARG, msg[a->len])) |
752 | r.rerrno = EMSGSIZE40; |
753 | else if (imsg.fd < 0) |
754 | r.rerrno = EINVAL22; |
755 | else if (privsep_npppd_check_sendto(a)) |
756 | r.rerrno = EACCES13; |
757 | else { |
758 | if (a->tolen > 0) |
759 | r.retval = sendto(imsg.fd, a->msg, |
760 | a->len, a->flags, |
761 | (struct sockaddr *)&a->to, |
762 | a->tolen); |
763 | else |
764 | r.retval = send(imsg.fd, a->msg, a->len, |
765 | a->flags); |
766 | if (r.retval < 0) |
767 | r.rerrno = errno(*__errno()); |
768 | close(imsg.fd); |
769 | } |
770 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
771 | &r, sizeof(r)); |
772 | imsg_flush(ibuf); |
773 | } |
774 | break; |
775 | case PRIVSEP_GET_IF_ADDR: { |
776 | int s; |
777 | struct ifreq ifr; |
778 | struct PRIVSEP_GET_IF_ADDR_ARG *a = imsg.data; |
779 | struct PRIVSEP_GET_IF_ADDR_RESP r; |
780 | |
781 | memset(&r, 0, sizeof(r)); |
782 | r.retval = -1; |
783 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
784 | r.rerrno = EINVAL22; |
785 | else if (privsep_npppd_check_get_if_addr(a)) |
786 | r.rerrno = EACCES13; |
787 | else { |
788 | memset(&ifr, 0, sizeof(ifr)); |
789 | strlcpy(ifr.ifr_name, a->ifname, |
790 | sizeof(ifr.ifr_name)); |
791 | if ((s = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0 || |
792 | ioctl(s, SIOCGIFADDR(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((33))), &ifr) != 0) { |
793 | r.retval = -1; |
794 | r.rerrno = errno(*__errno()); |
795 | } else { |
796 | r.retval = 0; |
797 | r.addr = ((struct sockaddr_in *) |
798 | &ifr.ifr_addrifr_ifru.ifru_addr)->sin_addr; |
799 | } |
800 | if (s >= 0) |
801 | close(s); |
802 | } |
803 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
804 | &r, sizeof(r)); |
805 | imsg_flush(ibuf); |
806 | } |
807 | break; |
808 | case PRIVSEP_SET_IF_ADDR: { |
809 | int s; |
810 | struct ifaliasreq ifra; |
811 | struct PRIVSEP_SET_IF_ADDR_ARG *a = imsg.data; |
812 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
813 | struct sockaddr_in *sin4; |
814 | |
815 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
816 | r.rerrno = EINVAL22; |
817 | else if (privsep_npppd_check_set_if_addr(a)) |
818 | r.rerrno = EACCES13; |
819 | else { |
820 | memset(&ifra, 0, sizeof(ifra)); |
821 | strlcpy(ifra.ifra_name, a->ifname, |
822 | sizeof(ifra.ifra_name)); |
823 | |
824 | sin4 = (struct sockaddr_in *)&ifra.ifra_addrifra_ifrau.ifrau_addr; |
825 | sin4->sin_family = AF_INET2; |
826 | sin4->sin_len = sizeof(struct sockaddr_in); |
827 | sin4->sin_addr = a->addr; |
828 | |
829 | sin4 = (struct sockaddr_in *)&ifra.ifra_mask; |
830 | sin4->sin_family = AF_INET2; |
831 | sin4->sin_len = sizeof(struct sockaddr_in); |
832 | sin4->sin_addr.s_addr = 0xffffffffUL; |
833 | |
834 | sin4 = |
835 | (struct sockaddr_in *)&ifra.ifra_broadaddrifra_dstaddr; |
836 | sin4->sin_family = AF_INET2; |
837 | sin4->sin_len = sizeof(struct sockaddr_in); |
838 | sin4->sin_addr.s_addr = 0; |
839 | |
840 | if ((s = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0 || |
841 | ioctl(s, SIOCAIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifaliasreq) & 0x1fff) << 16) | ((('i')) << 8) | ((26))), &ifra) != 0) { |
842 | r.retval = -1; |
843 | r.rerrno = errno(*__errno()); |
844 | } else |
845 | r.retval = 0; |
846 | if (s >= 0) |
847 | close(s); |
848 | } |
849 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
850 | &r, sizeof(r)); |
851 | imsg_flush(ibuf); |
852 | } |
853 | break; |
854 | case PRIVSEP_DEL_IF_ADDR: { |
855 | int s; |
856 | struct ifreq ifr; |
857 | struct PRIVSEP_DEL_IF_ADDR_ARG *a = imsg.data; |
858 | struct PRIVSEP_COMMON_RESP r = { 0, -1 }; |
859 | |
860 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
861 | r.rerrno = EINVAL22; |
862 | else if (privsep_npppd_check_del_if_addr(a)) |
863 | r.rerrno = EACCES13; |
864 | else { |
865 | memset(&ifr, 0, sizeof(ifr)); |
866 | strlcpy(ifr.ifr_name, a->ifname, |
867 | sizeof(ifr.ifr_name)); |
868 | if ((s = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0 || |
869 | ioctl(s, SIOCDIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((25))), &ifr) != 0) { |
870 | r.retval = -1; |
871 | r.rerrno = errno(*__errno()); |
872 | } else |
873 | r.retval = 0; |
874 | if (s >= 0) |
875 | close(s); |
876 | } |
877 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
878 | &r, sizeof(r)); |
879 | imsg_flush(ibuf); |
880 | } |
881 | break; |
882 | case PRIVSEP_GET_IF_FLAGS: { |
883 | int s; |
884 | struct ifreq ifr; |
885 | struct PRIVSEP_GET_IF_FLAGS_ARG *a = imsg.data; |
886 | struct PRIVSEP_GET_IF_FLAGS_RESP r; |
887 | |
888 | memset(&r, 0, sizeof(r)); |
889 | r.retval = -1; |
890 | |
891 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
892 | r.rerrno = EINVAL22; |
893 | else if (privsep_npppd_check_get_if_flags(a)) { |
894 | r.rerrno = EACCES13; |
895 | } else { |
896 | memset(&ifr, 0, sizeof(ifr)); |
897 | strlcpy(ifr.ifr_name, a->ifname, |
898 | sizeof(ifr.ifr_name)); |
899 | if ((s = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0 || |
900 | ioctl(s, SIOCGIFFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((17))), &ifr) != 0) { |
901 | r.retval = -1; |
902 | r.rerrno = errno(*__errno()); |
903 | } else { |
904 | r.retval = 0; |
905 | r.flags = ifr.ifr_flagsifr_ifru.ifru_flags; |
906 | } |
907 | if (s >= 0) |
908 | close(s); |
909 | } |
910 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
911 | &r, sizeof(r)); |
912 | imsg_flush(ibuf); |
913 | } |
914 | break; |
915 | case PRIVSEP_SET_IF_FLAGS: { |
916 | int s; |
917 | struct ifreq ifr; |
918 | struct PRIVSEP_SET_IF_FLAGS_ARG *a = imsg.data; |
919 | struct PRIVSEP_COMMON_RESP r = { -1, 0 }; |
920 | |
921 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*a)) |
922 | r.rerrno = EINVAL22; |
923 | else if (privsep_npppd_check_set_if_flags(a)) |
924 | r.rerrno = EACCES13; |
925 | else { |
926 | memset(&ifr, 0, sizeof(ifr)); |
927 | strlcpy(ifr.ifr_name, a->ifname, |
928 | sizeof(ifr.ifr_name)); |
929 | ifr.ifr_flagsifr_ifru.ifru_flags = a->flags; |
930 | if ((s = socket(AF_INET2, SOCK_DGRAM2, 0)) < 0 || |
931 | ioctl(s, SIOCGIFFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((17))), &ifr) != 0) { |
932 | r.retval = -1; |
933 | r.rerrno = errno(*__errno()); |
934 | } else |
935 | r.retval = 0; |
936 | if (s >= 0) |
937 | close(s); |
938 | } |
939 | (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, |
940 | &r, sizeof(r)); |
941 | imsg_flush(ibuf); |
942 | } |
943 | break; |
944 | } |
945 | imsg_free(&imsg); |
946 | } |
947 | } |
948 | |
949 | int |
950 | imsg_read_and_get(struct imsgbuf *ibuf, struct imsg *imsg) |
951 | { |
952 | ssize_t n; |
953 | |
954 | for (;;) { |
955 | if ((n = imsg_read(ibuf)) <= 0) { |
956 | if (n == -1 && (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)) |
957 | continue; |
958 | return (-1); |
959 | } |
960 | if ((n = imsg_get(ibuf, imsg)) < 0) |
961 | return (-1); |
962 | if (n == 0) |
963 | continue; |
964 | break; |
965 | } |
966 | |
967 | return (0); |
968 | } |
969 | |
970 | static int |
971 | startswith(const char *str, const char *prefix) |
972 | { |
973 | return (strncmp(str, prefix, strlen(prefix)) == 0)? 1 : 0; |
974 | } |
975 | |
976 | static int |
977 | privsep_npppd_check_open(struct PRIVSEP_OPEN_ARG *arg) |
978 | { |
979 | int i; |
980 | struct _allow_paths { |
981 | const char *path; |
982 | int path_is_prefix; |
983 | int readonly; |
984 | } const allow_paths[] = { |
985 | { NPPPD_DIR"/etc/npppd" "/", 1, 1 }, |
986 | { "/dev/bpf", 0, 0 }, |
987 | { "/etc/resolv.conf", 0, 1 }, |
988 | { "/dev/tun", 1, 0 }, |
989 | { "/dev/pppac", 1, 0 }, |
990 | { "/dev/pppx", 1, 0 } |
991 | }; |
992 | |
993 | /* O_NONBLOCK is the only 'extra' flag permitted */ |
994 | if (arg->flags & ~(O_ACCMODE0x0003 | O_NONBLOCK0x0004)) |
995 | return (1); |
996 | for (i = 0; i < (int)nitems(allow_paths)(sizeof((allow_paths)) / sizeof((allow_paths)[0])); i++) { |
997 | if (allow_paths[i].path_is_prefix) { |
998 | if (!startswith(arg->path, allow_paths[i].path)) |
999 | continue; |
1000 | } else if (strcmp(arg->path, allow_paths[i].path) != 0) |
1001 | continue; |
1002 | if (allow_paths[i].readonly) { |
1003 | if ((arg->flags & O_ACCMODE0x0003) != O_RDONLY0x0000) |
1004 | continue; |
1005 | } |
1006 | return (0); |
1007 | } |
1008 | return (1); |
1009 | } |
1010 | |
1011 | static int |
1012 | privsep_npppd_check_socket(struct PRIVSEP_SOCKET_ARG *arg) |
1013 | { |
1014 | /* npppd uses routing socket */ |
1015 | if (arg->domain == PF_ROUTE17 && arg->type == SOCK_RAW3 && |
1016 | arg->protocol == AF_UNSPEC0) |
1017 | return (0); |
1018 | |
1019 | /* npppd uses raw ip socket for GRE */ |
1020 | if (arg->domain == AF_INET2 && arg->type == SOCK_RAW3 && |
1021 | arg->protocol == IPPROTO_GRE47) |
1022 | return (0); |
1023 | |
1024 | /* L2TP uses PF_KEY socket to delete IPsec-SA */ |
1025 | if (arg->domain == PF_KEY30 && arg->type == SOCK_RAW3 && |
1026 | arg->protocol == PF_KEY_V22) |
1027 | return (0); |
1028 | |
1029 | return (1); |
1030 | } |
1031 | |
1032 | static int |
1033 | privsep_npppd_check_bind(struct PRIVSEP_BIND_ARG *arg) |
1034 | { |
1035 | return (1); |
1036 | } |
1037 | |
1038 | static int |
1039 | privsep_npppd_check_sendto(struct PRIVSEP_SENDTO_ARG *arg) |
1040 | { |
1041 | /* for reply npppdctl's request */ |
1042 | if (arg->flags == 0 && arg->tolen > 0 && |
1043 | arg->to.ss_family == AF_UNIX1) |
1044 | return (0); |
1045 | |
1046 | /* for sending a routing socket message. */ |
1047 | if (arg->flags == 0 && arg->tolen == 0) |
1048 | return (0); |
1049 | |
1050 | return (1); |
1051 | } |
1052 | |
1053 | static int |
1054 | privsep_npppd_check_unlink(struct PRIVSEP_UNLINK_ARG *arg) |
1055 | { |
1056 | |
1057 | return (1); |
1058 | } |
1059 | |
1060 | static int |
1061 | privsep_npppd_check_get_user_info(struct PRIVSEP_GET_USER_INFO_ARG *arg) |
1062 | { |
1063 | int l; |
1064 | |
1065 | l = strlen(NPPPD_DIR"/etc/npppd" "/"); |
1066 | if (strncmp(arg->path, NPPPD_DIR"/etc/npppd" "/", l) == 0) |
1067 | return (0); |
1068 | |
1069 | return (1); |
1070 | } |
1071 | |
1072 | static int |
1073 | privsep_npppd_check_ifname(const char *ifname) |
1074 | { |
1075 | if (startswith(ifname, "tun") || |
1076 | startswith(ifname, "pppac") || |
1077 | startswith(ifname, "pppx")) |
1078 | return (0); |
1079 | |
1080 | return (0); |
1081 | } |
1082 | |
1083 | static int |
1084 | privsep_npppd_check_get_if_addr(struct PRIVSEP_GET_IF_ADDR_ARG *arg) |
1085 | { |
1086 | return (privsep_npppd_check_ifname(arg->ifname)); |
1087 | } |
1088 | |
1089 | static int |
1090 | privsep_npppd_check_set_if_addr(struct PRIVSEP_SET_IF_ADDR_ARG *arg) |
1091 | { |
1092 | return (privsep_npppd_check_ifname(arg->ifname)); |
1093 | } |
1094 | |
1095 | static int |
1096 | privsep_npppd_check_del_if_addr(struct PRIVSEP_DEL_IF_ADDR_ARG *arg) |
1097 | { |
1098 | return (privsep_npppd_check_ifname(arg->ifname)); |
1099 | } |
1100 | |
1101 | static int |
1102 | privsep_npppd_check_get_if_flags(struct PRIVSEP_GET_IF_FLAGS_ARG *arg) |
1103 | { |
1104 | return (privsep_npppd_check_ifname(arg->ifname)); |
1105 | } |
1106 | |
1107 | static int |
1108 | privsep_npppd_check_set_if_flags(struct PRIVSEP_SET_IF_FLAGS_ARG *arg) |
1109 | { |
1110 | return (privsep_npppd_check_ifname(arg->ifname)); |
1111 | } |