summaryrefslogtreecommitdiffstats
path: root/freebsd/sbin/dhclient
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sbin/dhclient
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sbin/dhclient')
-rw-r--r--freebsd/sbin/dhclient/bpf.c220
-rw-r--r--freebsd/sbin/dhclient/clparse.c4
-rw-r--r--freebsd/sbin/dhclient/conflex.c4
-rw-r--r--freebsd/sbin/dhclient/dhclient.c179
-rw-r--r--freebsd/sbin/dhclient/dhcpd.h20
-rw-r--r--freebsd/sbin/dhclient/options.c4
-rw-r--r--freebsd/sbin/dhclient/packet.c23
-rw-r--r--freebsd/sbin/dhclient/privsep.c5
-rw-r--r--freebsd/sbin/dhclient/privsep.h5
9 files changed, 288 insertions, 176 deletions
diff --git a/freebsd/sbin/dhclient/bpf.c b/freebsd/sbin/dhclient/bpf.c
index 8ff451b2..4d3d2276 100644
--- a/freebsd/sbin/dhclient/bpf.c
+++ b/freebsd/sbin/dhclient/bpf.c
@@ -46,6 +46,8 @@
__FBSDID("$FreeBSD$");
#include "dhcpd.h"
+#include "privsep.h"
+#include <sys/capsicum.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
@@ -63,15 +65,15 @@ __FBSDID("$FreeBSD$");
* mask.
*/
int
-if_register_bpf(struct interface_info *info)
+if_register_bpf(struct interface_info *info, int flags)
{
char filename[50];
int sock, b;
/* Open a BPF device */
- for (b = 0; 1; b++) {
+ for (b = 0;; b++) {
snprintf(filename, sizeof(filename), BPF_FORMAT, b);
- sock = open(filename, O_RDWR, 0);
+ sock = open(filename, flags);
if (sock < 0) {
if (errno == EBUSY)
continue;
@@ -89,16 +91,81 @@ if_register_bpf(struct interface_info *info)
return (sock);
}
+/*
+ * Packet write filter program:
+ * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
+ */
+struct bpf_insn dhcp_bpf_wfilter[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
+
+ /* Make sure this is an IP packet... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
+
+ /* Get the IP header length... */
+ BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's from the right port... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
+
+ /* Make sure it is to the right ports ... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+ /* Otherwise, drop it. */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
+
void
if_register_send(struct interface_info *info)
{
+ cap_rights_t rights;
+ struct bpf_version v;
+ struct bpf_program p;
int sock, on = 1;
- /*
- * If we're using the bpf API for sending and receiving, we
- * don't need to register this interface twice.
- */
- info->wfdesc = info->rfdesc;
+ /* Open a BPF device and hang it on this interface... */
+ info->wfdesc = if_register_bpf(info, O_WRONLY);
+
+ /* Make sure the BPF version is in range... */
+ if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0)
+ error("Can't get BPF version: %m");
+
+ if (v.bv_major != BPF_MAJOR_VERSION ||
+ v.bv_minor < BPF_MINOR_VERSION)
+ error("Kernel BPF version out of range - recompile dhcpd!");
+
+ /* Set up the bpf write filter program structure. */
+ p.bf_len = dhcp_bpf_wfilter_len;
+ p.bf_insns = dhcp_bpf_wfilter;
+
+ if (dhcp_bpf_wfilter[7].k == 0x1fff)
+ dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
+
+ if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0)
+ error("Can't install write filter program: %m");
+
+ if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0)
+ error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
/*
* Use raw socket for unicast send.
@@ -146,55 +213,17 @@ struct bpf_insn dhcp_bpf_filter[] = {
int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
-/*
- * Packet write filter program:
- * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
- */
-struct bpf_insn dhcp_bpf_wfilter[] = {
- BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
-
- /* Make sure this is an IP packet... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
-
- /* Make sure it's a UDP packet... */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
-
- /* Make sure this isn't a fragment... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
-
- /* Get the IP header length... */
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
-
- /* Make sure it's from the right port... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
-
- /* Make sure it is to the right ports ... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
-
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
-
- /* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
-};
-
-int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
-
void
if_register_receive(struct interface_info *info)
{
+ static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA };
+ cap_rights_t rights;
struct bpf_version v;
struct bpf_program p;
int flag = 1, sz;
/* Open a BPF device and hang it on this interface... */
- info->rfdesc = if_register_bpf(info);
+ info->rfdesc = if_register_bpf(info, O_RDONLY);
/* Make sure the BPF version is in range... */
if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0)
@@ -237,48 +266,94 @@ if_register_receive(struct interface_info *info)
if (ioctl(info->rfdesc, BIOCSETF, &p) < 0)
error("Can't install packet filter program: %m");
- /* Set up the bpf write filter program structure. */
- p.bf_len = dhcp_bpf_wfilter_len;
- p.bf_insns = dhcp_bpf_wfilter;
-
- if (dhcp_bpf_wfilter[7].k == 0x1fff)
- dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
-
- if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0)
- error("Can't install write filter program: %m");
-
if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0)
error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_IOCTL, CAP_EVENT, CAP_READ);
+ if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
+ if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS)
+ error("Can't limit ioctls for bpf descriptor: %m");
}
-ssize_t
-send_packet(struct interface_info *interface, struct dhcp_packet *raw,
- size_t len, struct in_addr from, struct sockaddr_in *to,
- struct hardware *hto)
+void
+send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len,
+ struct in_addr from, struct in_addr to)
+{
+ struct imsg_hdr hdr;
+ struct buf *buf;
+ int errs;
+
+ hdr.code = IMSG_SEND_PACKET;
+ hdr.len = sizeof(hdr) +
+ sizeof(size_t) + len +
+ sizeof(from) + sizeof(to);
+
+ if ((buf = buf_open(hdr.len)) == NULL)
+ error("buf_open: %m");
+
+ errs = 0;
+ errs += buf_add(buf, &hdr, sizeof(hdr));
+ errs += buf_add(buf, &len, sizeof(len));
+ errs += buf_add(buf, raw, len);
+ errs += buf_add(buf, &from, sizeof(from));
+ errs += buf_add(buf, &to, sizeof(to));
+ if (errs)
+ error("buf_add: %m");
+
+ if (buf_close(privfd, buf) == -1)
+ error("buf_close: %m");
+}
+
+void
+send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd)
{
unsigned char buf[256];
struct iovec iov[2];
struct msghdr msg;
+ struct dhcp_packet raw;
+ size_t len;
+ struct in_addr from, to;
int result, bufp = 0;
+ if (hdr->len < sizeof(*hdr) + sizeof(size_t))
+ error("corrupted message received");
+ buf_read(fd, &len, sizeof(len));
+ if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len +
+ sizeof(from) + sizeof(to)) {
+ error("corrupted message received");
+ }
+ if (len > sizeof(raw))
+ error("corrupted message received");
+ buf_read(fd, &raw, len);
+ buf_read(fd, &from, sizeof(from));
+ buf_read(fd, &to, sizeof(to));
+
/* Assemble the headers... */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
- assemble_hw_header(interface, buf, &bufp, hto);
- assemble_udp_ip_header(buf, &bufp, from.s_addr,
- to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
+ if (to.s_addr == INADDR_BROADCAST)
+ assemble_hw_header(interface, buf, &bufp);
+ assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr,
+ htons(REMOTE_PORT), (unsigned char *)&raw, len);
- iov[0].iov_base = (char *)buf;
+ iov[0].iov_base = buf;
iov[0].iov_len = bufp;
- iov[1].iov_base = (char *)raw;
+ iov[1].iov_base = &raw;
iov[1].iov_len = len;
/* Fire it off */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
+ if (to.s_addr == INADDR_BROADCAST)
result = writev(interface->wfdesc, iov, 2);
else {
+ struct sockaddr_in sato;
+
+ sato.sin_addr = to;
+ sato.sin_port = htons(REMOTE_PORT);
+ sato.sin_family = AF_INET;
+ sato.sin_len = sizeof(sato);
+
memset(&msg, 0, sizeof(msg));
- msg.msg_name = (struct sockaddr *)to;
- msg.msg_namelen = sizeof(*to);
+ msg.msg_name = (struct sockaddr *)&sato;
+ msg.msg_namelen = sizeof(sato);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
result = sendmsg(interface->ufdesc, &msg, 0);
@@ -286,7 +361,6 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw,
if (result < 0)
warning("send_packet: %m");
- return (result);
}
ssize_t
diff --git a/freebsd/sbin/dhclient/clparse.c b/freebsd/sbin/dhclient/clparse.c
index b52bc473..a65236fc 100644
--- a/freebsd/sbin/dhclient/clparse.c
+++ b/freebsd/sbin/dhclient/clparse.c
@@ -644,6 +644,10 @@ parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
case FILENAME:
lease->filename = parse_string(cfile);
return;
+ case NEXT_SERVER:
+ if (!parse_ip_addr(cfile, &lease->nextserver))
+ return;
+ break;
case SERVER_NAME:
lease->server_name = parse_string(cfile);
return;
diff --git a/freebsd/sbin/dhclient/conflex.c b/freebsd/sbin/dhclient/conflex.c
index 4990f45f..c4fd442c 100644
--- a/freebsd/sbin/dhclient/conflex.c
+++ b/freebsd/sbin/dhclient/conflex.c
@@ -99,8 +99,8 @@ get_char(FILE *cfile)
cur_line = line2;
prev_line = line1;
} else {
- cur_line = line2;
- prev_line = line1;
+ cur_line = line1;
+ prev_line = line2;
}
line++;
lpos = 1;
diff --git a/freebsd/sbin/dhclient/dhclient.c b/freebsd/sbin/dhclient/dhclient.c
index 97824985..c7b75c59 100644
--- a/freebsd/sbin/dhclient/dhclient.c
+++ b/freebsd/sbin/dhclient/dhclient.c
@@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$");
#include "dhcpd.h"
#include "privsep.h"
+#include <sys/capsicum.h>
+
#include <net80211/ieee80211_freebsd.h>
#ifndef _PATH_VAREMPTY
@@ -93,9 +95,10 @@ int log_perror = 1;
int privfd;
int nullfd = -1;
+char hostname[_POSIX_HOST_NAME_MAX + 1];
+
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
-struct in_addr inaddr_any;
-struct sockaddr_in sockaddr_broadcast;
+struct in_addr inaddr_any, inaddr_broadcast;
char *path_dhclient_pidfile;
struct pidfh *pidfile;
@@ -345,6 +348,7 @@ main(int argc, char *argv[])
int immediate_daemon = 0;
struct passwd *pw;
pid_t otherpid;
+ cap_rights_t rights;
/* Initially, log errors to stderr as well as to syslogd. */
openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
@@ -389,7 +393,7 @@ main(int argc, char *argv[])
if (path_dhclient_pidfile == NULL)
error("asprintf");
}
- pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
+ pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
if (pidfile == NULL) {
if (errno == EEXIST)
error("dhclient already running, pid: %d.", otherpid);
@@ -412,11 +416,7 @@ main(int argc, char *argv[])
tzset();
time(&cur_time);
- memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
- sockaddr_broadcast.sin_family = AF_INET;
- sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
- sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
- sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
+ inaddr_broadcast.s_addr = INADDR_BROADCAST;
inaddr_any.s_addr = INADDR_ANY;
read_client_conf();
@@ -453,13 +453,36 @@ main(int argc, char *argv[])
error("no such user: nobody");
}
+ /*
+ * Obtain hostname before entering capability mode - it won't be
+ * possible then, as reading kern.hostname is not permitted.
+ */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ hostname[0] = '\0';
+
+ priv_script_init("PREINIT", NULL);
+ if (ifi->client->alias)
+ priv_script_write_params("alias_", ifi->client->alias);
+ priv_script_go();
+
+ /* set up the interface */
+ discover_interfaces(ifi);
+
if (pipe(pipe_fd) == -1)
error("pipe");
fork_privchld(pipe_fd[0], pipe_fd[1]);
+ close(ifi->ufdesc);
+ ifi->ufdesc = -1;
+ close(ifi->wfdesc);
+ ifi->wfdesc = -1;
+
close(pipe_fd[0]);
privfd = pipe_fd[1];
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE);
+ if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit private descriptor: %m");
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);
@@ -467,16 +490,13 @@ main(int argc, char *argv[])
rewrite_client_leases();
close(fd);
- priv_script_init("PREINIT", NULL);
- if (ifi->client->alias)
- priv_script_write_params("alias_", ifi->client->alias);
- priv_script_go();
-
if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
add_protocol("AF_ROUTE", routefd, routehandler, ifi);
-
- /* set up the interface */
- discover_interfaces(ifi);
+ if (shutdown(routefd, SHUT_WR) < 0)
+ error("can't shutdown route socket: %m");
+ cap_rights_init(&rights, CAP_EVENT, CAP_READ);
+ if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit route socket: %m");
if (chroot(_PATH_VAREMPTY) == -1)
error("chroot");
@@ -492,6 +512,9 @@ main(int argc, char *argv[])
setproctitle("%s", ifi->name);
+ if (cap_enter() < 0 && errno != ENOSYS)
+ error("can't enter capability mode: %m");
+
if (immediate_daemon)
go_daemon();
@@ -1065,6 +1088,9 @@ packet_to_lease(struct packet *packet)
lease->address.len = sizeof(packet->raw->yiaddr);
memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
+ lease->nextserver.len = sizeof(packet->raw->siaddr);
+ memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
+
/* If the server name was filled out, copy it.
Do not attempt to validate the server name as a host name.
RFC 2131 merely states that sname is NUL-terminated (which do
@@ -1225,13 +1251,12 @@ again:
ip->client->secs = ip->client->packet.secs;
note("DHCPDISCOVER on %s to %s port %d interval %d",
- ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port),
+ ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
(int)ip->client->interval);
/* Send out a packet. */
- (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
add_timeout(cur_time + ip->client->interval, send_discover, ip);
}
@@ -1339,8 +1364,7 @@ void
send_request(void *ipp)
{
struct interface_info *ip = ipp;
- struct sockaddr_in destination;
- struct in_addr from;
+ struct in_addr from, to;
int interval;
/* Figure out how long it's been since we started transmitting. */
@@ -1428,18 +1452,13 @@ cancel:
/* If the lease T2 time has elapsed, or if we're not yet bound,
broadcast the DHCPREQUEST rather than unicasting. */
- memset(&destination, 0, sizeof(destination));
if (ip->client->state == S_REQUESTING ||
ip->client->state == S_REBOOTING ||
cur_time > ip->client->active->rebind)
- destination.sin_addr.s_addr = INADDR_BROADCAST;
+ to.s_addr = INADDR_BROADCAST;
else
- memcpy(&destination.sin_addr.s_addr,
- ip->client->destination.iabuf,
- sizeof(destination.sin_addr.s_addr));
- destination.sin_port = htons(REMOTE_PORT);
- destination.sin_family = AF_INET;
- destination.sin_len = sizeof(destination);
+ memcpy(&to.s_addr, ip->client->destination.iabuf,
+ sizeof(to.s_addr));
if (ip->client->state != S_REQUESTING)
memcpy(&from, ip->client->active->address.iabuf,
@@ -1457,12 +1476,12 @@ cancel:
ip->client->packet.secs = htons(65535);
}
- note("DHCPREQUEST on %s to %s port %d", ip->name,
- inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
+ note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
+ REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- from, &destination, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, from, to);
add_timeout(cur_time + ip->client->interval, send_request, ip);
}
@@ -1473,12 +1492,11 @@ send_decline(void *ipp)
struct interface_info *ip = ipp;
note("DHCPDECLINE on %s to %s port %d", ip->name,
- inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port));
+ inet_ntoa(inaddr_broadcast), REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
}
void
@@ -1535,11 +1553,10 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1555,12 +1572,12 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
}
/* set unique client identifier */
- char client_ident[sizeof(struct hardware)];
+ char client_ident[sizeof(ip->hw_address.haddr) + 1];
if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1659,11 +1676,10 @@ make_request(struct interface_info *ip, struct client_lease * lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1684,7 +1700,7 @@ make_request(struct interface_info *ip, struct client_lease * lease)
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1825,11 +1841,22 @@ void
rewrite_client_leases(void)
{
struct client_lease *lp;
+ cap_rights_t rights;
if (!leaseFile) {
leaseFile = fopen(path_dhclient_db, "w");
if (!leaseFile)
error("can't create %s: %m", path_dhclient_db);
+ cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC,
+ CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit lease descriptor: %m");
+ }
+ if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit lease descriptor fcntls: %m");
+ }
} else {
fflush(leaseFile);
rewind(leaseFile);
@@ -1876,6 +1903,11 @@ write_client_lease(struct interface_info *ip, struct client_lease *lease,
fprintf(leaseFile, " bootp;\n");
fprintf(leaseFile, " interface \"%s\";\n", ip->name);
fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
+ if (lease->nextserver.len == sizeof(inaddr_any) &&
+ 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
+ sizeof(inaddr_any)))
+ fprintf(leaseFile, " next-server %s;\n",
+ piaddr(lease->nextserver));
if (lease->filename)
fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
if (lease->server_name)
@@ -2245,6 +2277,17 @@ script_set_env(struct client_state *client, const char *prefix,
{
int i, j, namelen;
+ /* No `` or $() command substitution allowed in environment values! */
+ for (j=0; j < strlen(value); j++)
+ switch (value[j]) {
+ case '`':
+ case '$':
+ warning("illegal character (%c) in value '%s'",
+ value[j], value);
+ /* Ignore this option */
+ return;
+ }
+
namelen = strlen(name);
for (i = 0; client->scriptEnv[i]; i++)
@@ -2281,16 +2324,6 @@ script_set_env(struct client_state *client, const char *prefix,
strlen(value) + 1);
if (client->scriptEnv[i] == NULL)
error("script_set_env: no memory for variable assignment");
-
- /* No `` or $() command substitution allowed in environment values! */
- for (j=0; j < strlen(value); j++)
- switch (value[j]) {
- case '`':
- case '$':
- error("illegal character (%c) in value '%s'", value[j],
- value);
- /* not reached */
- }
snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
}
@@ -2329,6 +2362,7 @@ void
go_daemon(void)
{
static int state = 0;
+ cap_rights_t rights;
if (no_daemon || state)
return;
@@ -2341,8 +2375,15 @@ go_daemon(void)
if (daemon(1, 0) == -1)
error("daemon");
- if (pidfile != NULL)
+ cap_rights_init(&rights);
+
+ if (pidfile != NULL) {
pidfile_write(pidfile);
+ if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit pidfile descriptor: %m");
+ }
+ }
/* we are chrooted, daemon(3) fails to open /dev/null */
if (nullfd != -1) {
@@ -2352,6 +2393,14 @@ go_daemon(void)
close(nullfd);
nullfd = -1;
}
+
+ if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdin: %m");
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdout: %m");
+ if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stderr: %m");
}
int
@@ -2496,19 +2545,19 @@ check_classless_option(unsigned char *data, int len)
i += 4;
continue;
} else if (width < 9) {
- addr = (in_addr_t)(data[i] << 24);
+ addr = (in_addr_t)(data[i] << 24);
i += 1;
} else if (width < 17) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16);
i += 2;
} else if (width < 25) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8);
i += 3;
} else if (width < 33) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8) +
data[i + 3];
@@ -2532,7 +2581,7 @@ check_classless_option(unsigned char *data, int len)
addr &= mask;
data[i - 1] = (unsigned char)(
(addr >> (((32 - width)/8)*8)) & 0xFF);
- }
+ }
i += 4;
}
if (i > len) {
@@ -2696,6 +2745,8 @@ fork_privchld(int fd, int fd2)
dup2(nullfd, STDERR_FILENO);
close(nullfd);
close(fd2);
+ close(ifi->rfdesc);
+ ifi->rfdesc = -1;
for (;;) {
pfd[0].fd = fd;
@@ -2707,6 +2758,6 @@ fork_privchld(int fd, int fd2)
if (nfds == 0 || !(pfd[0].revents & POLLIN))
continue;
- dispatch_imsg(fd);
+ dispatch_imsg(ifi, fd);
}
}
diff --git a/freebsd/sbin/dhclient/dhcpd.h b/freebsd/sbin/dhclient/dhcpd.h
index 030a96a0..852513a8 100644
--- a/freebsd/sbin/dhclient/dhcpd.h
+++ b/freebsd/sbin/dhclient/dhcpd.h
@@ -121,6 +121,7 @@ struct client_lease {
struct client_lease *next;
time_t expiry, renewal, rebind;
struct iaddr address;
+ struct iaddr nextserver;
char *server_name;
char *filename;
struct string_list *medium;
@@ -296,11 +297,13 @@ struct hash_table *new_hash_table(int);
struct hash_bucket *new_hash_bucket(void);
/* bpf.c */
-int if_register_bpf(struct interface_info *);
+int if_register_bpf(struct interface_info *, int);
void if_register_send(struct interface_info *);
void if_register_receive(struct interface_info *);
-ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t,
- struct in_addr, struct sockaddr_in *, struct hardware *);
+void send_packet_unpriv(int, struct dhcp_packet *, size_t, struct in_addr,
+ struct in_addr);
+struct imsg_hdr;
+void send_packet_priv(struct interface_info *, struct imsg_hdr *, int);
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t,
struct sockaddr_in *, struct hardware *);
@@ -404,20 +407,13 @@ void bootp(struct packet *);
void dhcp(struct packet *);
/* packet.c */
-void assemble_hw_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
+void assemble_hw_header(struct interface_info *, unsigned char *, int *);
void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t,
unsigned int, unsigned char *, int);
ssize_t decode_hw_header(unsigned char *, int, struct hardware *);
ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *,
unsigned char *, int);
-/* ethernet.c */
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int, struct hardware *);
-
/* clparse.c */
int read_client_conf(void);
void read_client_leases(void);
@@ -441,4 +437,4 @@ struct buf *buf_open(size_t);
int buf_add(struct buf *, void *, size_t);
int buf_close(int, struct buf *);
ssize_t buf_read(int, void *, size_t);
-void dispatch_imsg(int);
+void dispatch_imsg(struct interface_info *, int);
diff --git a/freebsd/sbin/dhclient/options.c b/freebsd/sbin/dhclient/options.c
index c86b7e3b..5ea8de7c 100644
--- a/freebsd/sbin/dhclient/options.c
+++ b/freebsd/sbin/dhclient/options.c
@@ -286,8 +286,8 @@ find_search_domain_name_len(struct option_data *option, int *offset)
option->data[i + 1];
if (pointer >= *offset) {
/*
- * The pointer must indicates a prior
- * occurance.
+ * The pointer must indicate a prior
+ * occurrence.
*/
warning("Invalid forward pointer in DHCP "
"Domain Search option compression.");
diff --git a/freebsd/sbin/dhclient/packet.c b/freebsd/sbin/dhclient/packet.c
index e4fa0e86..28a9ccec 100644
--- a/freebsd/sbin/dhclient/packet.c
+++ b/freebsd/sbin/dhclient/packet.c
@@ -57,11 +57,6 @@ __FBSDID("$FreeBSD$");
u_int32_t checksum(unsigned char *, unsigned, u_int32_t);
u_int32_t wrapsum(u_int32_t);
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int bufix, struct hardware *);
-
u_int32_t
checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
{
@@ -97,14 +92,11 @@ wrapsum(u_int32_t sum)
void
assemble_hw_header(struct interface_info *interface, unsigned char *buf,
- int *bufix, struct hardware *to)
+ int *bufix)
{
struct ether_header eh;
- if (to != NULL && to->hlen == 6) /* XXX */
- memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost));
- else
- memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
+ memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
if (interface->hw_address.hlen == sizeof(eh.ether_shost))
memcpy(eh.ether_shost, interface->hw_address.haddr,
sizeof(eh.ether_shost));
@@ -137,17 +129,6 @@ assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from,
ip.ip_dst.s_addr = to;
ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
-
- /*
- * While the BPF -- used for broadcasts -- expects a "true" IP header
- * with all the bytes in network byte order, the raw socket interface
- * which is used for unicasts expects the ip_len field to be in host
- * byte order. In both cases, the checksum has to be correct, so this
- * is as good a place as any to turn the bytes around again.
- */
- if (to != INADDR_BROADCAST)
- ip.ip_len = ntohs(ip.ip_len);
-
memcpy(&buf[*bufix], &ip, sizeof(ip));
*bufix += sizeof(ip);
diff --git a/freebsd/sbin/dhclient/privsep.c b/freebsd/sbin/dhclient/privsep.c
index 7b68059a..aa1042fd 100644
--- a/freebsd/sbin/dhclient/privsep.c
+++ b/freebsd/sbin/dhclient/privsep.c
@@ -103,7 +103,7 @@ buf_read(int sock, void *buf, size_t nbytes)
}
void
-dispatch_imsg(int fd)
+dispatch_imsg(struct interface_info *ifi, int fd)
{
struct imsg_hdr hdr;
char *medium, *reason, *filename,
@@ -234,6 +234,9 @@ dispatch_imsg(int fd)
if (buf_close(fd, buf) == -1)
error("buf_close: %m");
break;
+ case IMSG_SEND_PACKET:
+ send_packet_priv(ifi, &hdr, fd);
+ break;
default:
error("received unknown message, code %d", hdr.code);
}
diff --git a/freebsd/sbin/dhclient/privsep.h b/freebsd/sbin/dhclient/privsep.h
index f30284ee..d464da43 100644
--- a/freebsd/sbin/dhclient/privsep.h
+++ b/freebsd/sbin/dhclient/privsep.h
@@ -14,6 +14,8 @@
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
*/
#include <sys/types.h>
@@ -33,7 +35,8 @@ enum imsg_code {
IMSG_SCRIPT_INIT,
IMSG_SCRIPT_WRITE_PARAMS,
IMSG_SCRIPT_GO,
- IMSG_SCRIPT_GO_RET
+ IMSG_SCRIPT_GO_RET,
+ IMSG_SEND_PACKET
};
struct imsg_hdr {