diff options
-rw-r--r-- | distrib/special/dhclient/Makefile | 4 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.c | 111 | ||||
-rw-r--r-- | sbin/dhclient/dhcpd.h | 10 | ||||
-rw-r--r-- | sbin/dhclient/dispatch.c | 14 | ||||
-rw-r--r-- | sbin/dhclient/kroute.c | 184 | ||||
-rw-r--r-- | sbin/dhclient/privsep.c | 361 | ||||
-rw-r--r-- | sbin/dhclient/privsep.h | 54 |
7 files changed, 251 insertions, 487 deletions
diff --git a/distrib/special/dhclient/Makefile b/distrib/special/dhclient/Makefile index fc5a3014d75..e8cc7af8524 100644 --- a/distrib/special/dhclient/Makefile +++ b/distrib/special/dhclient/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.12 2012/11/09 18:51:56 krw Exp $ +# $OpenBSD: Makefile,v 1.13 2012/11/23 15:25:47 krw Exp $ .include <bsd.own.mk> @@ -10,6 +10,8 @@ SRCS= dhclient.c clparse.c dispatch.c bpf.c options.c \ conflex.c errwarn.c kroute.c packet.c convert.c \ tables.c parse.c privsep.c PROG= dhclient +LDADD+= -lutil +DPADD+= ${LIBUTIL} .include <bsd.prog.mk> .include <bsd.subdir.mk> diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index fc2bfcc1d83..038b74dfed6 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dhclient.c,v 1.178 2012/11/16 16:46:18 krw Exp $ */ +/* $OpenBSD: dhclient.c,v 1.179 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright 2004 Henning Brauer <henning@openbsd.org> @@ -69,7 +69,6 @@ char *path_dhclient_conf = _PATH_DHCLIENT_CONF; char *path_dhclient_db = NULL; int log_perror = 1; -int privfd; int nullfd = -1; int no_daemon; int unknown_ok = 1; @@ -84,6 +83,7 @@ struct sockaddr_in sockaddr_broadcast; struct interface_info *ifi; struct client_state *client; struct client_config *config; +struct imsgbuf *unpriv_ibuf; int findproto(char *, int); struct sockaddr *get_ifa(char *, int); @@ -97,6 +97,7 @@ void get_ifname(char *, char *); void new_resolv_conf(char *, char *, char *); struct client_lease *apply_defaults(struct client_lease *); struct client_lease *clone_lease(struct client_lease *); +void socket_nonblockmode(int); #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) @@ -259,7 +260,7 @@ die: int main(int argc, char *argv[]) { - int ch, fd, quiet = 0, i = 0, pipe_fd[2]; + int ch, fd, quiet = 0, i = 0, socket_fd[2]; extern char *__progname; struct passwd *pw; int rtfilter; @@ -356,16 +357,20 @@ main(int argc, char *argv[]) if ((pw = getpwnam("_dhcp")) == NULL) error("no such user: _dhcp"); - if (pipe(pipe_fd) == -1) - error("pipe"); - /* set up the interface */ discover_interface(); - fork_privchld(pipe_fd[0], pipe_fd[1]); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socket_fd) == -1) + error("socketpair: %m"); + socket_nonblockmode(socket_fd[0]); + socket_nonblockmode(socket_fd[1]); + + fork_privchld(socket_fd[0], socket_fd[1]); - close(pipe_fd[0]); - privfd = pipe_fd[1]; + close(socket_fd[0]); + if ((unpriv_ibuf = malloc(sizeof(struct imsgbuf))) == NULL) + error("no memory for unpriv_ibuf"); + imsg_init(unpriv_ibuf, socket_fd[1]); if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); @@ -1688,6 +1693,8 @@ int fork_privchld(int fd, int fd2) { struct pollfd pfd[1]; + struct imsgbuf *priv_ibuf; + ssize_t n; int nfds; switch (fork()) { @@ -1714,17 +1721,29 @@ fork_privchld(int fd, int fd2) close(nullfd); close(fd2); + if ((priv_ibuf = malloc(sizeof(struct imsgbuf))) == NULL) + error("no memory for priv_ibuf"); + + imsg_init(priv_ibuf, fd); + for (;;) { - pfd[0].fd = fd; + pfd[0].fd = priv_ibuf->fd; pfd[0].events = POLLIN; - if ((nfds = poll(pfd, 1, INFTIM)) == -1) + if ((nfds = poll(pfd, 1, INFTIM)) == -1) { if (errno != EINTR) - error("poll error"); + error("poll error: %m"); + } if (nfds == 0 || !(pfd[0].revents & POLLIN)) continue; - dispatch_imsg(fd); + if ((n = imsg_read(priv_ibuf)) == -1) + error("imsg_read(priv_ibuf): %m"); + + if (n == 0) /* connection closed */ + error("dispatch_imsg in main: pipe closed"); + + dispatch_imsg(priv_ibuf); } } @@ -1774,52 +1793,40 @@ get_ifname(char *ifname, char *arg) * Update resolv.conf. */ -#define MAXRESOLVCONFSIZE 2048 - void new_resolv_conf(char *ifname, char *domainname, char *nameservers) { - size_t len; - struct imsg_hdr hdr; - struct buf *buf; - char *contents, *p; + struct imsg_resolv_conf imsg; + char *p; + int rslt; - contents = calloc(1, MAXRESOLVCONFSIZE); + memset(&imsg, 0, sizeof(imsg)); /* Build string of contents of new resolv.conf. */ if (domainname && strlen(domainname)) { - strlcat(contents, "search ", MAXRESOLVCONFSIZE); - strlcat(contents, domainname, MAXRESOLVCONFSIZE); - strlcat(contents, "\n", MAXRESOLVCONFSIZE); + strlcat(imsg.contents, "search ", MAXRESOLVCONFSIZE); + strlcat(imsg.contents, domainname, MAXRESOLVCONFSIZE); + strlcat(imsg.contents, "\n", MAXRESOLVCONFSIZE); } for (p = strsep(&nameservers, " "); p != NULL; p = strsep(&nameservers, " ")) { if (*p == '\0') continue; - strlcat(contents, "nameserver ", MAXRESOLVCONFSIZE); - strlcat(contents, p, MAXRESOLVCONFSIZE); - strlcat(contents, "\n", MAXRESOLVCONFSIZE); + strlcat(imsg.contents, "nameserver ", MAXRESOLVCONFSIZE); + strlcat(imsg.contents, p, MAXRESOLVCONFSIZE); + strlcat(imsg.contents, "\n", MAXRESOLVCONFSIZE); } - hdr.code = IMSG_NEW_RESOLV_CONF; - hdr.len = sizeof(hdr) + - sizeof(len) + strlen(contents); - - buf = buf_open(hdr.len); - buf_add(buf, &hdr, sizeof(hdr)); + rslt = imsg_compose(unpriv_ibuf, IMSG_NEW_RESOLV_CONF, 0, 0, -1, &imsg, + sizeof(imsg)); - len = strlen(contents); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, contents, len); - - buf_close(privfd, buf); - - free(contents); + if (rslt == -1) + warning("new_resolv_conf: imsg_compose: %m"); } void -priv_resolv_conf(char *contents) +priv_resolv_conf(struct imsg_resolv_conf *imsg) { ssize_t n; int conffd, tailfd, tailn; @@ -1833,15 +1840,15 @@ priv_resolv_conf(char *contents) return; } - if (contents) { - n = write(conffd, contents, strlen(contents)); + if (strlen(imsg->contents)) { + n = write(conffd, imsg->contents, strlen(imsg->contents)); if (n == -1) note("Couldn't write contents to resolv.conf: %m"); else if (n == 0) note("Couldn't write contents to resolv.conf"); - else if (n < strlen(contents)) + else if (n < strlen(imsg->contents)) note("Short contents write to resolv.conf (%zd vs %zd)", - n, strlen(contents)); + n, strlen(imsg->contents)); } tailfd = open("/etc/resolv.conf.tail", O_RDONLY); @@ -1871,7 +1878,7 @@ priv_resolv_conf(char *contents) free(buf); } - if ((!contents || strlen(contents) == 0) && (tailn < 1 || n < 1)) { + if ((strlen(imsg->contents) == 0) && (tailn < 1 || n < 1)) { note("No contents for resolv.conf"); unlink("/etc/resolv.conf"); close(conffd); @@ -1988,3 +1995,17 @@ clone_lease(struct client_lease *oldlease) return (newlease); } + +void +socket_nonblockmode(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + error("fcntl F_GETF: %m"); + + flags |= O_NONBLOCK; + + if ((flags = fcntl(fd, F_SETFL, flags)) == -1) + error("fcntl F_SETFL: %m"); +} diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h index 4a34af62311..a3b2bcdb1b2 100644 --- a/sbin/dhclient/dhcpd.h +++ b/sbin/dhclient/dhcpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dhcpd.h,v 1.92 2012/11/14 15:47:41 krw Exp $ */ +/* $OpenBSD: dhcpd.h,v 1.93 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> @@ -191,7 +191,7 @@ struct dhcp_timeout { extern struct interface_info *ifi; extern struct client_state *client; extern struct client_config *config; -extern int privfd; +extern struct imsgbuf *unpriv_ibuf; extern struct in_addr deleting; extern struct in_addr adding; @@ -295,8 +295,6 @@ void go_daemon(void); void routehandler(void); -void priv_resolv_conf(char *); - /* packet.c */ void assemble_hw_header(unsigned char *, int *, struct hardware *); void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, @@ -320,13 +318,9 @@ void parse_reject_statement(FILE *); /* kroute.c */ void delete_addresses(char *, int); void delete_address(char *, int, struct in_addr); -void priv_delete_address(char *, int, struct in_addr); void add_address(char *, int, struct in_addr, struct in_addr); -void priv_add_address(char *, int, struct in_addr, struct in_addr); void flush_routes_and_arp_cache(int); -void priv_flush_routes_and_arp_cache(int); void add_default_route(int, struct in_addr, struct in_addr); -void priv_add_default_route(int, struct in_addr, struct in_addr); diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c index 3b0d17128f9..cd73f79d7d1 100644 --- a/sbin/dhclient/dispatch.c +++ b/sbin/dhclient/dispatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dispatch.c,v 1.65 2012/11/08 21:32:55 krw Exp $ */ +/* $OpenBSD: dispatch.c,v 1.66 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright 2004 Henning Brauer <henning@openbsd.org> @@ -40,6 +40,7 @@ */ #include "dhcpd.h" +#include "privsep.h" #include <sys/ioctl.h> @@ -154,10 +155,13 @@ another: fds[0].fd = ifi->rfdesc; fds[1].fd = routefd; /* Could be -1, which will be ignored. */ - fds[2].fd = privfd; + fds[2].fd = unpriv_ibuf->fd; fds[0].events = fds[1].events = fds[2].events = POLLIN; - /* Wait for a packet or a timeout or privfd ... XXX */ + if (unpriv_ibuf->w.queued) + fds[2].events |= POLLOUT; + + /* Wait for a packet or a timeout or unpriv_ibuf->fd ... XXX */ count = poll(fds, 3, to_msec); /* Not likely to be transitory... */ @@ -176,6 +180,10 @@ another: if (ifi) routehandler(); } + if (fds[2].revents & POLLOUT) { + if (msgbuf_write(&unpriv_ibuf->w) == -1) + error("pipe write error to [priv]"); + } if ((fds[2].revents & (POLLIN | POLLHUP))) { error("lost connection to [priv]"); } diff --git a/sbin/dhclient/kroute.c b/sbin/dhclient/kroute.c index a991f7574c2..03b201cebda 100644 --- a/sbin/dhclient/kroute.c +++ b/sbin/dhclient/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.18 2012/11/17 10:39:24 krw Exp $ */ +/* $OpenBSD: kroute.c,v 1.19 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright 2012 Kenneth R Westerback <krw@openbsd.org> @@ -36,26 +36,26 @@ void flush_routes_and_arp_cache(int rdomain) { - size_t len; - struct imsg_hdr hdr; - struct buf *buf; + struct imsg_flush_routes imsg; + int rslt; - hdr.code = IMSG_FLUSH_ROUTES; - hdr.len = sizeof(hdr) + - sizeof(len) + sizeof(rdomain); + memset(&imsg, 0, sizeof(imsg)); - buf = buf_open(hdr.len); - buf_add(buf, &hdr, sizeof(hdr)); + imsg.rdomain = rdomain; - len = sizeof(rdomain); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &rdomain, len); + rslt = imsg_compose(unpriv_ibuf, IMSG_FLUSH_ROUTES, 0, 0, -1, + &imsg, sizeof(imsg)); + if (rslt == -1) + warning("flush_routes_and_arp_cache: imsg_compose: %m"); - buf_close(privfd, buf); + /* Do flush to maximize chances of cleaning up routes on exit. */ + rslt = imsg_flush(unpriv_ibuf); + if (rslt == -1) + warning("flush_routes_and_arp_cache: imsg_flush: %m"); } void -priv_flush_routes_and_arp_cache(int rdomain) +priv_flush_routes_and_arp_cache(struct imsg_flush_routes *imsg) { struct sockaddr *rti_info[RTAX_MAX]; int mib[7]; @@ -74,10 +74,10 @@ priv_flush_routes_and_arp_cache(int rdomain) mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; - mib[6] = rdomain; + mib[6] = imsg->rdomain; if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) { - if (rdomain != 0 && errno == EINVAL) + if (imsg->rdomain != 0 && errno == EINVAL) return; error("could not get routes"); } @@ -155,7 +155,7 @@ priv_flush_routes_and_arp_cache(int rdomain) rtm->rtm_type = RTM_DELETE; rtm->rtm_seq = seqno; - rtm->rtm_tableid = rdomain; + rtm->rtm_tableid = imsg->rdomain; rlen = write(s, next, rtm->rtm_msglen); if (rlen == -1) { @@ -185,40 +185,26 @@ priv_flush_routes_and_arp_cache(int rdomain) * depending on the contents of the gateway parameter. */ void -add_default_route(int rdomain, struct in_addr addr, - struct in_addr gateway) +add_default_route(int rdomain, struct in_addr addr, struct in_addr gateway) { - size_t len; - struct imsg_hdr hdr; - struct buf *buf; + struct imsg_add_default_route imsg; + int rslt; - hdr.code = IMSG_ADD_DEFAULT_ROUTE; - hdr.len = sizeof(hdr) + - sizeof(len) + sizeof(rdomain) + - sizeof(len) + sizeof(addr) + - sizeof(len) + sizeof(gateway); + memset(&imsg, 0, sizeof(imsg)); - buf = buf_open(hdr.len); - buf_add(buf, &hdr, sizeof(hdr)); + imsg.rdomain = rdomain; + imsg.addr = addr; + imsg.gateway = gateway; - len = sizeof(rdomain); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &rdomain, len); + rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_DEFAULT_ROUTE, 0, 0, -1, + &imsg, sizeof(imsg)); - len = sizeof(addr); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &addr, len); - - len = sizeof(gateway); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &gateway, len); - - buf_close(privfd, buf); + if (rslt == -1) + warning("add_default_route: imsg_compose: %m"); } void -priv_add_default_route(int rdomain, struct in_addr addr, - struct in_addr router) +priv_add_default_route(struct imsg_add_default_route *imsg) { struct rt_msghdr rtm; struct sockaddr_in dest, gateway, mask; @@ -239,7 +225,7 @@ priv_add_default_route(int rdomain, struct in_addr addr, rtm.rtm_version = RTM_VERSION; rtm.rtm_type = RTM_ADD; - rtm.rtm_tableid = rdomain; + rtm.rtm_tableid = imsg->rdomain; rtm.rtm_priority = 0; rtm.rtm_msglen = sizeof(rtm); @@ -265,10 +251,10 @@ priv_add_default_route(int rdomain, struct in_addr addr, */ memset(&gateway, 0, sizeof(gateway)); - if (bcmp(&router, &addr, sizeof(addr)) != 0) { + if (bcmp(&imsg->gateway, &imsg->addr, sizeof(imsg->addr)) != 0) { gateway.sin_len = sizeof(gateway); gateway.sin_family = AF_INET; - gateway.sin_addr.s_addr = router.s_addr; + gateway.sin_addr.s_addr = imsg->gateway.s_addr; rtm.rtm_flags |= RTF_GATEWAY | RTF_STATIC; rtm.rtm_addrs |= RTA_GATEWAY; @@ -360,39 +346,27 @@ delete_addresses(char *ifname, int rdomain) void delete_address(char *ifname, int rdomain, struct in_addr addr) { - size_t len; - struct imsg_hdr hdr; - struct buf *buf; + struct imsg_delete_address imsg; + int rslt; + + memset(&imsg, 0, sizeof(imsg)); /* Note the address we are deleting for RTM_DELADDR filtering! */ deleting.s_addr = addr.s_addr; - hdr.code = IMSG_DELETE_ADDRESS; - hdr.len = sizeof(hdr) + - sizeof(len) + strlen(ifname) + - sizeof(len) + sizeof(rdomain) + - sizeof(len) + sizeof(addr); - - buf = buf_open(hdr.len); - buf_add(buf, &hdr, sizeof(hdr)); - - len = strlen(ifname); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, ifname, len); - - len = sizeof(rdomain); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &rdomain, len); + strlcpy(imsg.ifname, ifname, sizeof(imsg.ifname)); + imsg.rdomain = rdomain; + imsg.addr = addr; - len = sizeof(addr); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &addr, len); + rslt = imsg_compose(unpriv_ibuf, IMSG_DELETE_ADDRESS, 0, 0 , -1, &imsg, + sizeof(imsg)); - buf_close(privfd, buf); + if (rslt == -1) + warning("delete_address: imsg_compose: %m"); } void -priv_delete_address(char *ifname, int rdomain, struct in_addr addr) +priv_delete_address(struct imsg_delete_address *imsg) { struct ifaliasreq ifaliasreq; struct rt_msghdr rtm; @@ -409,16 +383,17 @@ priv_delete_address(char *ifname, int rdomain, struct in_addr addr) error("socket open failed: %m"); memset(&ifaliasreq, 0, sizeof(ifaliasreq)); - strncpy(ifaliasreq.ifra_name, ifname, sizeof(ifaliasreq.ifra_name)); + strncpy(ifaliasreq.ifra_name, imsg->ifname, + sizeof(ifaliasreq.ifra_name)); in = (struct sockaddr_in *)&ifaliasreq.ifra_addr; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_addr); - in->sin_addr.s_addr = addr.s_addr; + in->sin_addr.s_addr = imsg->addr.s_addr; /* SIOCDIFADDR will result in a RTM_DELADDR message we must catch! */ if (ioctl(s, SIOCDIFADDR, &ifaliasreq) == -1) { - warning("SIOCDIFADDR failed (%s): %m", inet_ntoa(addr)); + warning("SIOCDIFADDR failed (%s): %m", inet_ntoa(imsg->addr)); close(s); return; } @@ -438,7 +413,7 @@ priv_delete_address(char *ifname, int rdomain, struct in_addr addr) rtm.rtm_version = RTM_VERSION; rtm.rtm_type = RTM_DELETE; - rtm.rtm_tableid = rdomain; + rtm.rtm_tableid = imsg->rdomain; rtm.rtm_priority = 0; rtm.rtm_msglen = sizeof(rtm); @@ -451,7 +426,7 @@ priv_delete_address(char *ifname, int rdomain, struct in_addr addr) dest.sin_len = sizeof(dest); dest.sin_family = AF_INET; - dest.sin_addr.s_addr = addr.s_addr; + dest.sin_addr.s_addr = imsg->addr.s_addr; rtm.rtm_addrs |= RTA_DST; rtm.rtm_msglen += sizeof(dest); @@ -491,44 +466,28 @@ void add_address(char *ifname, int rdomain, struct in_addr addr, struct in_addr mask) { - struct buf *buf; - size_t len; - struct imsg_hdr hdr; + struct imsg_add_address imsg; + int rslt; + + memset(&imsg, 0, sizeof(imsg)); + /* Note the address we are adding for RTM_NEWADDR filtering! */ adding = addr; - hdr.code = IMSG_ADD_ADDRESS; - hdr.len = sizeof(hdr) + - sizeof(len) + strlen(ifname) + - sizeof(len) + sizeof(rdomain) + - sizeof(len) + sizeof(addr) + - sizeof(len) + sizeof(mask); + strlcpy(imsg.ifname, ifname, sizeof(imsg.ifname)); + imsg.rdomain = rdomain; + imsg.addr = addr; + imsg.mask = mask; + + rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_ADDRESS, 0, 0, -1, &imsg, + sizeof(imsg)); - buf = buf_open(hdr.len); - buf_add(buf, &hdr, sizeof(hdr)); - - len = strlen(ifname); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, ifname, len); - - len = sizeof(rdomain); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &rdomain, len); - - len = sizeof(addr); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &addr, len); - - len = sizeof(mask); - buf_add(buf, &len, sizeof(len)); - buf_add(buf, &mask, len); - - buf_close(privfd, buf); + if (rslt == -1) + warning("add_address: imsg_compose: %m"); } void -priv_add_address(char *ifname, int rdomain, struct in_addr addr, - struct in_addr mask) +priv_add_address(struct imsg_add_address *imsg) { struct ifaliasreq ifaliasreq; struct rt_msghdr rtm; @@ -546,24 +505,25 @@ priv_add_address(char *ifname, int rdomain, struct in_addr addr, error("socket open failed: %m"); memset(&ifaliasreq, 0, sizeof(ifaliasreq)); - strncpy(ifaliasreq.ifra_name, ifname, sizeof(ifaliasreq.ifra_name)); + strncpy(ifaliasreq.ifra_name, imsg->ifname, + sizeof(ifaliasreq.ifra_name)); /* The actual address in ifra_addr. */ in = (struct sockaddr_in *)&ifaliasreq.ifra_addr; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_addr); - in->sin_addr.s_addr = addr.s_addr; + in->sin_addr.s_addr = imsg->addr.s_addr; /* And the netmask in ifra_mask. */ in = (struct sockaddr_in *)&ifaliasreq.ifra_mask; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_mask); - memcpy(&in->sin_addr.s_addr, &mask, sizeof(mask)); + memcpy(&in->sin_addr.s_addr, &imsg->mask, sizeof(imsg->mask)); /* No need to set broadcast address. Kernel can figure it out. */ if (ioctl(s, SIOCAIFADDR, &ifaliasreq) == -1) - warning("SIOCAIFADDR failed (%s): %m", inet_ntoa(addr)); + warning("SIOCAIFADDR failed (%s): %m", inet_ntoa(imsg->addr)); close(s); @@ -580,7 +540,7 @@ priv_add_address(char *ifname, int rdomain, struct in_addr addr, rtm.rtm_version = RTM_VERSION; rtm.rtm_type = RTM_ADD; - rtm.rtm_tableid = rdomain; + rtm.rtm_tableid = imsg->rdomain; rtm.rtm_priority = 0; rtm.rtm_msglen = sizeof(rtm); @@ -593,7 +553,7 @@ priv_add_address(char *ifname, int rdomain, struct in_addr addr, dest.sin_len = sizeof(dest); dest.sin_family = AF_INET; - dest.sin_addr.s_addr = addr.s_addr; + dest.sin_addr.s_addr = imsg->addr.s_addr; rtm.rtm_addrs |= RTA_DST; rtm.rtm_msglen += sizeof(dest); diff --git a/sbin/dhclient/privsep.c b/sbin/dhclient/privsep.c index 5ab2c2a6759..e6f6dd0fb86 100644 --- a/sbin/dhclient/privsep.c +++ b/sbin/dhclient/privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.c,v 1.23 2012/11/14 15:47:41 krw Exp $ */ +/* $OpenBSD: privsep.c,v 1.24 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> @@ -19,311 +19,68 @@ #include "dhcpd.h" #include "privsep.h" -struct buf * -buf_open(size_t len) -{ - struct buf *buf; - - if ((buf = calloc(1, sizeof(struct buf))) == NULL) - error("buf_open: %m"); - if ((buf->buf = malloc(len)) == NULL) { - free(buf); - error("buf_open: %m"); - } - buf->size = len; - - return (buf); -} - -void -buf_add(struct buf *buf, void *data, size_t len) -{ - if (len == 0) - return; - - if (buf->wpos + len > buf->size) - error("buf_add: %m"); - - memcpy(buf->buf + buf->wpos, data, len); - buf->wpos += len; -} - -void -buf_close(int sock, struct buf *buf) -{ - ssize_t n; - - do { - n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); - if (n == 0) /* connection closed */ - error("buf_close (connection closed)"); - if (n != -1 && n < buf->size - buf->rpos) - error("buf_close (short write): %m"); - - } while (n == -1 && (errno == EAGAIN || errno == EINTR)); - - if (n == -1) - error("buf_close: %m"); - - free(buf->buf); - free(buf); -} - -void -buf_read(int sock, void *buf, size_t nbytes) -{ - ssize_t n; - - do { - n = read(sock, buf, nbytes); - if (n == 0) { /* connection closed */ -#ifdef DEBUG - debug("buf_read (connection closed)"); -#endif - exit(1); - } - if (n != -1 && n < nbytes) - error("buf_read (short read): %m"); - } while (n == -1 && (errno == EINTR || errno == EAGAIN)); - - if (n == -1) - error("buf_read: %m"); -} +#include <sys/queue.h> +#include <sys/uio.h> void -dispatch_imsg(int fd) +dispatch_imsg(struct imsgbuf *ibuf) { - struct imsg_hdr hdr; - struct in_addr *addr, *mask, *gateway; - char *ifname, *contents; - size_t totlen, len; - int rdomain; - - buf_read(fd, &hdr, sizeof(hdr)); - - switch (hdr.code) { - case IMSG_DELETE_ADDRESS: - totlen = sizeof(hdr); - ifname = NULL; - addr = NULL; - if (hdr.len < totlen + sizeof(len)) - error("IMSG_DELETE_ADDRESS missing ifname length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_DELETE_ADDRESS invalid ifname length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_DELETE_ADDRESS short ifname"); - if ((ifname = calloc(1, len + 1)) == NULL) - error("%m"); - buf_read(fd, ifname, len); - totlen += len; - } else - error("IMSG_DELETE_ADDRESS ifname missing"); - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_DELETE_ADDRESS missing rdomain length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_DELETE_ADDRESS invalid rdomain length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_DELETE_ADDRESS short rdomain"); - buf_read(fd, &rdomain, len); - totlen += len; - } else - error("IMSG_DELETE_ADDRESS rdomain missing"); - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_DELETE_ADDRESS missing addr length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_DELETE_ADDRESS invalid addr"); - } else if (len == sizeof(*addr)) { - if ((addr = calloc(1, len)) == NULL) - error("%m"); - buf_read(fd, addr, len); - totlen += len; - } else { - error("IMSG_DELETE_ADDRESS addr missing %zu", len); - } - - priv_delete_address(ifname, rdomain, *addr); - free(ifname); - free(addr); - break; - - case IMSG_ADD_ADDRESS: - totlen = sizeof(hdr); - ifname = NULL; - addr = NULL; - mask = NULL; - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_ADDRESS missing ifname length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_ADDRESS invalid ifname length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_ADD_ADDRESS short ifname"); - if ((ifname = calloc(1, len + 1)) == NULL) - error("%m"); - buf_read(fd, ifname, len); - totlen += len; - } else - error("IMSG_ADD_ADDRESS ifname missing"); - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_ADDRESS missing rdomain length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_ADDRESS invalid rdomain length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_ADD_ADDRESS short rdomain"); - buf_read(fd, &rdomain, len); - totlen += len; - } else - error("IMSG_ADD_ADDRESS rdomain missing"); - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_ADDRESS missing addr length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_ADDRESS invalid addr"); - } else if (len == sizeof(*addr)) { - if ((addr = calloc(1, len)) == NULL) - error("%m"); - buf_read(fd, addr, len); - totlen += len; - } else { - error("IMSG_ADD_ADDRESS addr missing %zu", len); - } - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_ADDRESS missing mask length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - mask = NULL; - if (len == SIZE_T_MAX) { - error("IMSG_ADD_ADDRESS invalid mask"); - } else if (len == sizeof(*mask)) { - if ((mask = calloc(1, len)) == NULL) - error("%m"); - buf_read(fd, mask, len); - totlen += len; - } else { - error("IMSG_ADD_ADDRESS mask missing %zu", len); - } - - priv_add_address(ifname, rdomain, *addr, *mask); - free(ifname); - free(addr); - free(mask); - break; - - case IMSG_FLUSH_ROUTES: - totlen = sizeof(hdr); - if (hdr.len < totlen + sizeof(len)) - error("IMSG_FLUSH_ROUTES missing rdomain length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_FLUSH_ROUTES invalid rdomain length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_FLUSH_ROUTES short rdomain"); - buf_read(fd, &rdomain, len); - totlen += len; - } else - error("IMSG_FLUSH_ROUTES rdomain missing"); - - priv_flush_routes_and_arp_cache(rdomain); - break; - - case IMSG_ADD_DEFAULT_ROUTE: - totlen = sizeof(hdr); - addr = NULL; - gateway = NULL; - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_DEFAULT_ROUTE missing rdomain length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_DEFAULT_ROUTE invalid rdomain length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_FLUSH_ROUTES short rdomain"); - buf_read(fd, &rdomain, len); - totlen += len; - } else - error("IMSG_ADD_DEFAULT_ROUTE rdomain missing"); - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_DEFAULT_ROUTE missing addr length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_DEFAULT_ROUTE invalid addr"); - } else if (len == sizeof(*addr)) { - if ((addr = calloc(1, len)) == NULL) - error("%m"); - buf_read(fd, addr, len); - totlen += len; - } else { - error("IMSG_ADD_DEFAULT_ROUTE addr missing %zu", - len); - } - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_ADD_DEFAULT_ROUTE missing gateway length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_ADD_DEFAULT_ROUTE invalid gateway"); - } else if (len == sizeof(*gateway)) { - if ((gateway = calloc(1, len)) == NULL) - error("%m"); - buf_read(fd, gateway, len); - totlen += len; - } else { - error("IMSG_ADD_DEFAULT_ROUTE gateway missing %zu", - len); - } - - priv_add_default_route(rdomain, *addr, *gateway); - free(addr); - free(gateway); - break; - case IMSG_NEW_RESOLV_CONF: - totlen = sizeof(hdr); - contents = NULL; - - if (hdr.len < totlen + sizeof(len)) - error("IMSG_NEW_RESOLV_CONF missing contents length"); - buf_read(fd, &len, sizeof(len)); - totlen += sizeof(len); - if (len == SIZE_T_MAX) { - error("IMSG_NEW_RESOLV_CONF invalid contents length"); - } else if (len > 0) { - if (hdr.len < totlen + len) - error("IMSG_NEW_RESOLV_CONF short contents"); - if ((contents = calloc(1, len + 1)) == NULL) - error("%m"); - buf_read(fd, contents, len); - totlen += len; + struct imsg imsg; + ssize_t n; + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + error("dispatch_imsg: imsg_get failure: %m"); + + if (n == 0) + break; + + switch (imsg.hdr.type) { + case IMSG_DELETE_ADDRESS: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct imsg_delete_address)) + warning("bad IMSG_DELETE_ADDRESS"); + else + priv_delete_address(imsg.data); + break; + + case IMSG_ADD_ADDRESS: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct imsg_add_address)) + warning("bad IMSG_ADD_ADDRESS"); + else + priv_add_address(imsg.data); + break; + + case IMSG_FLUSH_ROUTES: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct imsg_flush_routes)) + warning("bad IMSG_FLUSH_ROUTES"); + else + priv_flush_routes_and_arp_cache(imsg.data); + break; + + case IMSG_ADD_DEFAULT_ROUTE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct imsg_add_default_route)) + warning("bad IMSG_ADD_DEFAULT_ROUTE"); + else + priv_add_default_route(imsg.data); + break; + + case IMSG_NEW_RESOLV_CONF: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct imsg_resolv_conf)) + warning("bad IMSG_NEW_RESOLV_CONF"); + else + priv_resolv_conf(imsg.data); + break; + + default: + warning("received unknown message, code %d", + imsg.hdr.type); } - priv_resolv_conf(contents); - free(contents); - break; - default: - error("received unknown message, code %d", hdr.code); + imsg_free(&imsg); } } diff --git a/sbin/dhclient/privsep.h b/sbin/dhclient/privsep.h index 59300e00f53..a72294bb910 100644 --- a/sbin/dhclient/privsep.h +++ b/sbin/dhclient/privsep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.h,v 1.6 2012/10/30 18:39:44 krw Exp $ */ +/* $OpenBSD: privsep.h,v 1.7 2012/11/23 15:25:47 krw Exp $ */ /* * Copyright (c) 2004 Henning Brauer <henning@openbsd.org> @@ -16,14 +16,13 @@ * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> +#include <arpa/inet.h> -struct buf { - u_char *buf; - size_t size; - size_t wpos; - size_t rpos; -}; +#include <imsg.h> + +#define MAXRESOLVCONFSIZE 2048 + +extern struct imsgbuf *ibuf; enum imsg_code { IMSG_NONE, @@ -34,13 +33,36 @@ enum imsg_code { IMSG_NEW_RESOLV_CONF }; -struct imsg_hdr { - enum imsg_code code; - size_t len; +struct imsg_delete_address { + char ifname[IFNAMSIZ]; + int rdomain; + struct in_addr addr; +}; + +struct imsg_add_address { + char ifname[IFNAMSIZ]; + int rdomain; + struct in_addr addr; + struct in_addr mask; +}; + +struct imsg_flush_routes { + int rdomain; +}; + +struct imsg_add_default_route { + int rdomain; + struct in_addr addr; + struct in_addr gateway; +}; + +struct imsg_resolv_conf { + char contents[MAXRESOLVCONFSIZE]; }; -struct buf *buf_open(size_t); -void buf_add(struct buf *, void *, size_t); -void buf_close(int, struct buf *); -void buf_read(int, void *, size_t); -void dispatch_imsg(int); +void dispatch_imsg(struct imsgbuf *); +void priv_resolv_conf(struct imsg_resolv_conf *); +void priv_delete_address(struct imsg_delete_address *); +void priv_add_address(struct imsg_add_address *); +void priv_flush_routes_and_arp_cache(struct imsg_flush_routes *); +void priv_add_default_route(struct imsg_add_default_route *); |