1/*	$OpenBSD: privsep.c,v 1.25 2024/01/18 09:58:23 claudio 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.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]))
43#endif
44
45enum 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
60struct PRIVSEP_OPEN_ARG {
61	char			 path[PATH_MAX];
62	int			 flags;
63};
64
65struct PRIVSEP_SOCKET_ARG {
66	int			 domain;
67	int			 type;
68	int			 protocol;
69};
70
71struct PRIVSEP_BIND_ARG {
72	struct sockaddr_storage	 name;
73	socklen_t		 namelen;
74};
75
76struct 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
84struct PRIVSEP_UNLINK_ARG {
85	char			 path[PATH_MAX];
86};
87
88struct PRIVSEP_GET_USER_INFO_ARG {
89	char			 path[PATH_MAX];
90	char			 username[MAX_USERNAME_LENGTH];
91};
92
93struct PRIVSEP_GET_IF_ADDR_ARG {
94	char			 ifname[IFNAMSIZ];
95};
96
97struct PRIVSEP_GET_IF_ADDR_RESP {
98	int			 retval;
99	int			 rerrno;
100	struct in_addr		 addr;
101};
102
103struct PRIVSEP_SET_IF_ADDR_ARG {
104	char			 ifname[IFNAMSIZ];
105	struct in_addr		 addr;
106};
107
108struct PRIVSEP_DEL_IF_ADDR_ARG {
109	char			 ifname[IFNAMSIZ];
110};
111
112struct PRIVSEP_GET_IF_FLAGS_ARG {
113	char			 ifname[IFNAMSIZ];
114	int			 flags;
115};
116
117struct PRIVSEP_GET_IF_FLAGS_RESP {
118	int			 retval;
119	int			 rerrno;
120	int			 flags;
121};
122
123struct PRIVSEP_SET_IF_FLAGS_ARG {
124	char			 ifname[IFNAMSIZ];
125	int			 flags;
126};
127
128struct PRIVSEP_COMMON_RESP {
129	int			 retval;
130	int			 rerrno;
131};
132
133struct PRIVSEP_GET_USER_INFO_RESP {
134	int			 retval;
135	int			 rerrno;
136	char			 password[MAX_PASSWORD_LENGTH];
137	struct in_addr		 framed_ip_address;
138	struct in_addr		 framed_ip_netmask;
139	char			 calling_number[NPPPD_PHONE_NUMBER_LEN + 1];
140};
141
142static void	 privsep_priv_main (int);
143static void	 privsep_priv_dispatch_imsg (struct imsgbuf *);
144int		 imsg_read_and_get(struct imsgbuf *, struct imsg *);
145static int	 startswith(const char *, const char *);
146static int	 privsep_recvfd (void);
147static int	 privsep_common_resp (void);
148
149static int	 privsep_npppd_check_open (struct PRIVSEP_OPEN_ARG *);
150static int	 privsep_npppd_check_socket (struct PRIVSEP_SOCKET_ARG *);
151static int	 privsep_npppd_check_bind (struct PRIVSEP_BIND_ARG *);
152static int	 privsep_npppd_check_sendto (struct PRIVSEP_SENDTO_ARG *);
153static int	 privsep_npppd_check_unlink (struct PRIVSEP_UNLINK_ARG *);
154static int	 privsep_npppd_check_get_user_info (
155		    struct PRIVSEP_GET_USER_INFO_ARG *);
156static int	 privsep_npppd_check_get_if_addr (
157		    struct PRIVSEP_GET_IF_ADDR_ARG *);
158static int	 privsep_npppd_check_set_if_addr (
159		    struct PRIVSEP_SET_IF_ADDR_ARG *);
160static int	 privsep_npppd_check_del_if_addr (
161		    struct PRIVSEP_DEL_IF_ADDR_ARG *);
162static int	 privsep_npppd_check_get_if_flags (
163		    struct PRIVSEP_GET_IF_FLAGS_ARG *);
164static int	 privsep_npppd_check_set_if_flags (
165		    struct PRIVSEP_SET_IF_FLAGS_ARG *);
166
167static int		 privsep_sock = -1;
168static struct imsgbuf	 privsep_ibuf;
169static pid_t		 privsep_pid;
170
171int
172privsep_init(void)
173{
174	pid_t	 pid;
175	int	 pairsock[2];
176
177	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, 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 */
198fail:
199	if (pairsock[0] >= 0) {
200		close(pairsock[0]);
201		close(pairsock[1]);
202	}
203
204	return (-1);
205}
206
207void
208privsep_fini(void)
209{
210	imsg_clear(&privsep_ibuf);
211	if (privsep_sock >= 0) {
212		close(privsep_sock);
213		privsep_sock = -1;
214	}
215}
216
217pid_t
218privsep_priv_pid(void)
219{
220	return (privsep_pid);
221}
222
223/***********************************************************************
224 * Functions for from jail
225 ***********************************************************************/
226int
227priv_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 = EINVAL;
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
248int
249priv_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
263int
264priv_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
277FILE *
278priv_fopen(const char *path)
279{
280	int f;
281	FILE *fp;
282
283	if ((f = priv_open(path, O_RDONLY)) < 0)
284		return (NULL);
285
286	if ((fp = fdopen(f, "r")) == NULL) {
287		close(f);
288		return (NULL);
289	} else
290		return (fp);
291}
292
293int
294priv_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 = EINVAL;
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);
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));
319	imsg_flush(&privsep_ibuf);
320
321	return (privsep_common_resp());
322}
323
324int
325priv_send(int s, const void *msg, int len, int flags)
326{
327	return (priv_sendto(s, msg, len, flags, NULL, 0));
328}
329
330int
331priv_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
343int
344priv_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_SIZE + sizeof(*r)) {
365		errno = EACCES;
366		goto on_error;
367	}
368	r = imsg.data;
369	if (r->retval != 0) {
370		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]))) == NULL)
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
402on_error:
403	imsg_free(&imsg);
404	return (-1);
405}
406
407int
408priv_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_SIZE + sizeof(*r))
425		errno = EACCES;
426	else {
427		r = imsg.data;
428		if (r->retval != -1)
429			*addr = r->addr;
430		else
431			errno = r->rerrno;
432		retval = r->retval;
433	}
434	imsg_free(&imsg);
435
436	return (retval);
437}
438
439int
440priv_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
452int
453priv_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
466int
467priv_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_SIZE + sizeof(*r))
484		errno = EACCES;
485	else {
486		r = imsg.data;
487		*pflags = r->flags;
488		if (r->retval != 0)
489			errno = r->rerrno;
490		retval = r->retval;
491	}
492	imsg_free(&imsg);
493
494	return (retval);
495}
496
497int
498priv_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
512static int
513privsep_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_SIZE + sizeof(*r))
522		errno = EACCES;
523	else {
524		r = imsg.data;
525		retval = r->retval;
526		if (r->retval != 0)
527			errno = r->rerrno;
528		else
529			retval = imsg_get_fd(&imsg);
530	}
531	imsg_free(&imsg);
532
533	return (retval);
534}
535
536static int
537privsep_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 = EACCES;
545		return (-1);
546	}
547	if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r))
548		errno = EACCES;
549	else {
550		r = imsg.data;
551		if (r->retval != 0)
552			errno = r->rerrno;
553		retval = r->retval;
554	}
555	imsg_free(&imsg);
556
557	return (retval);
558}
559
560/***********************************************************************
561 * privileged process
562 ***********************************************************************/
563static void
564privsep_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_SUCCESS);
574}
575
576static void
577privsep_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_SIZE + sizeof(*a))
592				r.rerrno = EINVAL;
593			else if (privsep_npppd_check_open(a))
594				r.rerrno = EACCES;
595			else {
596				if ((f = open(a->path, a->flags & ~O_CREAT))
597				    == -1)
598					r.rerrno = 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_SIZE + sizeof(*a))
613				r.rerrno = EINVAL;
614			else if (privsep_npppd_check_socket(a))
615				r.rerrno = EACCES;
616			else {
617				if ((s = socket(a->domain, a->type,
618				    a->protocol)) == -1)
619					r.rerrno = 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_SIZE + sizeof(*a))
633				r.rerrno = EINVAL;
634			else if (privsep_npppd_check_unlink(a))
635				r.rerrno = EACCES;
636			else {
637				if ((r.retval = unlink(a->path)) != 0)
638					r.rerrno = 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			int fd;
650
651			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a) ||
652			    (fd = imsg_get_fd(&imsg)) < 0)
653				r.rerrno = EINVAL;
654			else if (privsep_npppd_check_bind(a))
655				r.rerrno = EACCES;
656			else {
657				if ((r.retval = bind(fd,
658				    (struct sockaddr *)&a->name, a->namelen))
659				    != 0)
660					r.rerrno = errno;
661				close(fd);
662			}
663			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
664			    &r, sizeof(r));
665			imsg_flush(ibuf);
666		    }
667			break;
668		case PRIVSEP_GET_USER_INFO: {
669			struct PRIVSEP_GET_USER_INFO_ARG *a = imsg.data;
670			struct PRIVSEP_GET_USER_INFO_RESP r;
671			int   retval;
672			char *str, *buf, *db[2] = { NULL, NULL };
673
674			memset(&r, 0, sizeof(r));
675			r.retval = -1;
676			r.framed_ip_address.s_addr = INADDR_NAS_SELECT;
677			r.framed_ip_netmask.s_addr = INADDR_NONE;
678			str = buf = NULL;
679
680			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) {
681				r.rerrno = EINVAL;
682				(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
683				    &r, sizeof(r));
684				return;
685			}
686			db[0] = a->path;
687			if (privsep_npppd_check_get_user_info(a))
688				r.rerrno = EACCES;
689			else if ((retval = cgetent(&buf, db, a->username))
690			    == 0) {
691				if ((retval = cgetstr(buf, "password", &str))
692				    >= 0) {
693					if (strlcpy(r.password, str,
694					    sizeof(r.password)) >=
695					    sizeof(r.password))
696						goto on_broken_entry;
697					free(str);
698					str = NULL;
699				}
700				if ((retval = cgetstr(buf, "calling-number",
701				    &str)) >= 0) {
702					if (strlcpy(r.calling_number, str,
703					    sizeof(r.calling_number)) >=
704					    sizeof(r.calling_number))
705						goto on_broken_entry;
706					free(str);
707					str = NULL;
708				}
709				if ((retval = cgetstr(buf, "framed-ip-address",
710				    &str)) >= 0) {
711					if (inet_aton(str,
712					    &r.framed_ip_address) != 1)
713						goto on_broken_entry;
714					free(str);
715					str = NULL;
716				}
717
718				if ((retval = cgetstr(buf, "framed-ip-netmask",
719				    &str)) >= 0) {
720					if (inet_aton(str,
721					    &r.framed_ip_netmask) != 1)
722						goto on_broken_entry;
723					free(str);
724					str = NULL;
725				}
726				cgetclose();
727				free(buf);
728				r.retval = 0;
729			} else if (retval == -1) {
730				buf = NULL;
731on_broken_entry:
732				free(buf);
733				free(str);
734				r.retval = -1;
735				r.rerrno = ENOENT;
736			} else {
737				r.retval = retval;
738				r.rerrno = errno;
739			}
740			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
741			    &r, sizeof(r));
742			imsg_flush(ibuf);
743		    }
744			break;
745		case PRIVSEP_SENDTO: {
746			struct PRIVSEP_SENDTO_ARG *a = imsg.data;
747			struct PRIVSEP_COMMON_RESP r = { -1, 0 };
748			int fd;
749
750			if (imsg.hdr.len < IMSG_HEADER_SIZE + sizeof(*a) ||
751			    imsg.hdr.len < IMSG_HEADER_SIZE +
752				offsetof(struct PRIVSEP_SENDTO_ARG,
753					msg[a->len]))
754				r.rerrno = EMSGSIZE;
755			else if ((fd = imsg_get_fd(&imsg)) < 0)
756				r.rerrno = EINVAL;
757			else if (privsep_npppd_check_sendto(a))
758				r.rerrno = EACCES;
759			else {
760				if (a->tolen > 0)
761					r.retval = sendto(fd, a->msg,
762					    a->len, a->flags,
763					    (struct sockaddr *)&a->to,
764					    a->tolen);
765				else
766					r.retval = send(fd, a->msg, a->len,
767					    a->flags);
768				if (r.retval < 0)
769					r.rerrno = errno;
770				close(fd);
771			}
772			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
773			    &r, sizeof(r));
774			imsg_flush(ibuf);
775		    }
776			break;
777		case PRIVSEP_GET_IF_ADDR: {
778			int                              s;
779			struct ifreq                     ifr;
780			struct PRIVSEP_GET_IF_ADDR_ARG  *a = imsg.data;
781			struct PRIVSEP_GET_IF_ADDR_RESP  r;
782
783			memset(&r, 0, sizeof(r));
784			r.retval = -1;
785			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a))
786				r.rerrno = EINVAL;
787			else if (privsep_npppd_check_get_if_addr(a))
788				r.rerrno = EACCES;
789			else {
790				memset(&ifr, 0, sizeof(ifr));
791				strlcpy(ifr.ifr_name, a->ifname,
792				    sizeof(ifr.ifr_name));
793				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
794				    ioctl(s, SIOCGIFADDR, &ifr) != 0) {
795					r.retval = -1;
796					r.rerrno = errno;
797				} else {
798					r.retval = 0;
799					r.addr = ((struct sockaddr_in *)
800					    &ifr.ifr_addr)->sin_addr;
801				}
802				if (s >= 0)
803					close(s);
804			}
805			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
806			    &r, sizeof(r));
807			imsg_flush(ibuf);
808		    }
809			break;
810		case PRIVSEP_SET_IF_ADDR: {
811			int                              s;
812			struct ifaliasreq                ifra;
813			struct PRIVSEP_SET_IF_ADDR_ARG  *a = imsg.data;
814			struct PRIVSEP_COMMON_RESP       r = { -1, 0 };
815			struct sockaddr_in              *sin4;
816
817			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a))
818				r.rerrno = EINVAL;
819			else if (privsep_npppd_check_set_if_addr(a))
820				r.rerrno = EACCES;
821			else {
822				memset(&ifra, 0, sizeof(ifra));
823				strlcpy(ifra.ifra_name, a->ifname,
824				    sizeof(ifra.ifra_name));
825
826				sin4 = (struct sockaddr_in *)&ifra.ifra_addr;
827				sin4->sin_family = AF_INET;
828				sin4->sin_len = sizeof(struct sockaddr_in);
829				sin4->sin_addr = a->addr;
830
831				sin4 = (struct sockaddr_in *)&ifra.ifra_mask;
832				sin4->sin_family = AF_INET;
833				sin4->sin_len = sizeof(struct sockaddr_in);
834				sin4->sin_addr.s_addr = 0xffffffffUL;
835
836				sin4 =
837				    (struct sockaddr_in *)&ifra.ifra_broadaddr;
838				sin4->sin_family = AF_INET;
839				sin4->sin_len = sizeof(struct sockaddr_in);
840				sin4->sin_addr.s_addr = 0;
841
842				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
843				    ioctl(s, SIOCAIFADDR, &ifra) != 0) {
844					r.retval = -1;
845					r.rerrno = errno;
846				} else
847					r.retval = 0;
848				if (s >= 0)
849					close(s);
850			}
851			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
852			    &r, sizeof(r));
853			imsg_flush(ibuf);
854		    }
855			break;
856		case PRIVSEP_DEL_IF_ADDR: {
857			int                              s;
858			struct ifreq                     ifr;
859			struct PRIVSEP_DEL_IF_ADDR_ARG  *a = imsg.data;
860			struct PRIVSEP_COMMON_RESP       r = { 0, -1 };
861
862			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a))
863				r.rerrno = EINVAL;
864			else if (privsep_npppd_check_del_if_addr(a))
865				r.rerrno = EACCES;
866			else {
867				memset(&ifr, 0, sizeof(ifr));
868				strlcpy(ifr.ifr_name, a->ifname,
869				    sizeof(ifr.ifr_name));
870				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
871				    ioctl(s, SIOCDIFADDR, &ifr) != 0) {
872					r.retval = -1;
873					r.rerrno = errno;
874				} else
875					r.retval = 0;
876				if (s >= 0)
877					close(s);
878			}
879			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
880			    &r, sizeof(r));
881			imsg_flush(ibuf);
882		    }
883			break;
884		case PRIVSEP_GET_IF_FLAGS: {
885			int                               s;
886			struct ifreq                      ifr;
887			struct PRIVSEP_GET_IF_FLAGS_ARG  *a = imsg.data;
888			struct PRIVSEP_GET_IF_FLAGS_RESP  r;
889
890			memset(&r, 0, sizeof(r));
891			r.retval = -1;
892
893			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a))
894				r.rerrno = EINVAL;
895			else if (privsep_npppd_check_get_if_flags(a)) {
896				r.rerrno = EACCES;
897			} else {
898				memset(&ifr, 0, sizeof(ifr));
899				strlcpy(ifr.ifr_name, a->ifname,
900				    sizeof(ifr.ifr_name));
901				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
902				    ioctl(s, SIOCGIFFLAGS, &ifr) != 0) {
903					r.retval = -1;
904					r.rerrno = errno;
905				} else {
906					r.retval = 0;
907					r.flags = ifr.ifr_flags;
908				}
909				if (s >= 0)
910					close(s);
911			}
912			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
913			    &r, sizeof(r));
914			imsg_flush(ibuf);
915		    }
916			break;
917		case PRIVSEP_SET_IF_FLAGS: {
918			int                               s;
919			struct ifreq                      ifr;
920			struct PRIVSEP_SET_IF_FLAGS_ARG  *a = imsg.data;
921			struct PRIVSEP_COMMON_RESP        r = { -1, 0 };
922
923			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a))
924				r.rerrno = EINVAL;
925			else if (privsep_npppd_check_set_if_flags(a))
926				r.rerrno = EACCES;
927			else {
928				memset(&ifr, 0, sizeof(ifr));
929				strlcpy(ifr.ifr_name, a->ifname,
930				    sizeof(ifr.ifr_name));
931				ifr.ifr_flags = a->flags;
932				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
933				    ioctl(s, SIOCGIFFLAGS, &ifr) != 0) {
934					r.retval = -1;
935					r.rerrno = errno;
936				} else
937					r.retval = 0;
938				if (s >= 0)
939					close(s);
940			}
941			(void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1,
942			    &r, sizeof(r));
943			imsg_flush(ibuf);
944		    }
945			break;
946		}
947		imsg_free(&imsg);
948	}
949}
950
951int
952imsg_read_and_get(struct imsgbuf *ibuf, struct imsg *imsg)
953{
954	ssize_t	 n;
955
956	for (;;) {
957		if ((n = imsg_read(ibuf)) <= 0) {
958			if (n == -1 && (errno == EAGAIN || errno == EINTR))
959				continue;
960			return (-1);
961		}
962		if ((n = imsg_get(ibuf, imsg)) < 0)
963			return (-1);
964		if (n == 0)
965			continue;
966		break;
967	}
968
969	return (0);
970}
971
972static int
973startswith(const char *str, const char *prefix)
974{
975	return (strncmp(str, prefix, strlen(prefix)) == 0)? 1 : 0;
976}
977
978static int
979privsep_npppd_check_open(struct PRIVSEP_OPEN_ARG *arg)
980{
981	int i;
982	struct _allow_paths {
983		const char *path;
984		int path_is_prefix;
985		int readonly;
986	} const allow_paths[] = {
987		{ NPPPD_DIR "/",	1,	1 },
988		{ "/dev/bpf",		0,	0 },
989		{ "/etc/resolv.conf",	0,	1 },
990		{ "/dev/tun",		1,	0 },
991		{ "/dev/pppac",		1,	0 },
992		{ "/dev/pppx",		1,	0 }
993	};
994
995	/* O_NONBLOCK is the only 'extra' flag permitted */
996	if (arg->flags & ~(O_ACCMODE | O_NONBLOCK))
997		return (1);
998	for (i = 0; i < (int)nitems(allow_paths); i++) {
999		if (allow_paths[i].path_is_prefix) {
1000			if (!startswith(arg->path, allow_paths[i].path))
1001				continue;
1002		} else if (strcmp(arg->path, allow_paths[i].path) != 0)
1003			continue;
1004		if (allow_paths[i].readonly) {
1005			if ((arg->flags & O_ACCMODE) != O_RDONLY)
1006				continue;
1007		}
1008		return (0);
1009	}
1010	return (1);
1011}
1012
1013static int
1014privsep_npppd_check_socket(struct PRIVSEP_SOCKET_ARG *arg)
1015{
1016	/* npppd uses routing socket */
1017	if (arg->domain == PF_ROUTE && arg->type == SOCK_RAW &&
1018	    arg->protocol  == AF_UNSPEC)
1019		return (0);
1020
1021	/* npppd uses raw ip socket for GRE */
1022	if (arg->domain == AF_INET && arg->type == SOCK_RAW &&
1023	    arg->protocol == IPPROTO_GRE)
1024		return (0);
1025
1026	/* L2TP uses PF_KEY socket to delete IPsec-SA */
1027	if (arg->domain == PF_KEY && arg->type == SOCK_RAW &&
1028	    arg->protocol == PF_KEY_V2)
1029		return (0);
1030
1031	return (1);
1032}
1033
1034static int
1035privsep_npppd_check_bind(struct PRIVSEP_BIND_ARG *arg)
1036{
1037	return (1);
1038}
1039
1040static int
1041privsep_npppd_check_sendto(struct PRIVSEP_SENDTO_ARG *arg)
1042{
1043	/* for reply npppdctl's request */
1044	if (arg->flags == 0 && arg->tolen > 0 &&
1045	    arg->to.ss_family == AF_UNIX)
1046		return (0);
1047
1048	/* for sending a routing socket message. */
1049	if (arg->flags == 0 && arg->tolen == 0)
1050		return (0);
1051
1052	return (1);
1053}
1054
1055static int
1056privsep_npppd_check_unlink(struct PRIVSEP_UNLINK_ARG *arg)
1057{
1058
1059	return (1);
1060}
1061
1062static int
1063privsep_npppd_check_get_user_info(struct PRIVSEP_GET_USER_INFO_ARG *arg)
1064{
1065	int l;
1066
1067	l = strlen(NPPPD_DIR "/");
1068	if (strncmp(arg->path, NPPPD_DIR "/", l) == 0)
1069		return (0);
1070
1071	return (1);
1072}
1073
1074static int
1075privsep_npppd_check_ifname(const char *ifname)
1076{
1077	if (startswith(ifname, "tun") ||
1078	    startswith(ifname, "pppac") ||
1079	    startswith(ifname, "pppx"))
1080		return (0);
1081
1082	return (0);
1083}
1084
1085static int
1086privsep_npppd_check_get_if_addr(struct PRIVSEP_GET_IF_ADDR_ARG *arg)
1087{
1088	return (privsep_npppd_check_ifname(arg->ifname));
1089}
1090
1091static int
1092privsep_npppd_check_set_if_addr(struct PRIVSEP_SET_IF_ADDR_ARG *arg)
1093{
1094	return (privsep_npppd_check_ifname(arg->ifname));
1095}
1096
1097static int
1098privsep_npppd_check_del_if_addr(struct PRIVSEP_DEL_IF_ADDR_ARG *arg)
1099{
1100	return (privsep_npppd_check_ifname(arg->ifname));
1101}
1102
1103static int
1104privsep_npppd_check_get_if_flags(struct PRIVSEP_GET_IF_FLAGS_ARG *arg)
1105{
1106	return (privsep_npppd_check_ifname(arg->ifname));
1107}
1108
1109static int
1110privsep_npppd_check_set_if_flags(struct PRIVSEP_SET_IF_FLAGS_ARG *arg)
1111{
1112	return (privsep_npppd_check_ifname(arg->ifname));
1113}
1114