* SUCH DAMAGE.
*/
+#include <sys/stat.h>
#include <sys/statvfs.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "dhcpcd.h"
#include "if-options.h"
-#include "logerr.h"
const char *
hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
return len;
}
-size_t
-read_hwaddr_aton(uint8_t **data, const char *path)
+ssize_t
+readfile(const char *file, void *data, size_t len)
{
- FILE *fp;
- char *buf;
- size_t buf_len, len;
-
- if ((fp = fopen(path, "r")) == NULL)
- return 0;
-
- buf = NULL;
- buf_len = len = 0;
- *data = NULL;
- while (getline(&buf, &buf_len, fp) != -1) {
- if ((len = hwaddr_aton(NULL, buf)) != 0) {
- if (buf_len >= len)
- *data = (uint8_t *)buf;
- else {
- if ((*data = malloc(len)) == NULL)
- len = 0;
- }
- if (len != 0)
- (void)hwaddr_aton(*data, buf);
- if (buf_len < len)
- free(buf);
- break;
- }
+ int fd;
+ struct stat st;
+ ssize_t bytes = -1;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ if (fstat(fd, &st) != 0)
+ goto out;
+ if (!S_ISREG(st.st_mode)) {
+ errno = EINVAL;
+ goto out;
}
- fclose(fp);
- return len;
+ if ((size_t)st.st_size > len) {
+ errno = E2BIG;
+ goto out;
+ }
+ bytes = read(fd, data, len);
+
+out:
+ if (fd != -1)
+ close(fd);
+ return bytes;
+}
+
+ssize_t
+writefile(const char *file, mode_t mode, const void *data, size_t len)
+{
+ int fd;
+ ssize_t bytes;
+
+ fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (fd == -1)
+ return -1;
+ bytes = write(fd, data, len);
+ close(fd);
+ return bytes;
+}
+
+int
+filemtime(const char *file, time_t *time)
+{
+ struct stat st;
+
+ if (stat(file, &st) == -1)
+ return -1;
+ *time = st.st_mtime;
+ return 0;
}
int
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *);
-size_t read_hwaddr_aton(uint8_t **, const char *);
+ssize_t readfile(const char *, void *, size_t);
+ssize_t writefile(const char *, mode_t, const void *, size_t);
+int filemtime(const char *, time_t *);
int is_root_local(void);
#endif
* SUCH DAMAGE.
*/
-#include <sys/stat.h>
#include <sys/utsname.h>
#include <ctype.h>
return -1;
p += l;
len -= (size_t)l;
- l = if_machinearch(p, len);
+ l = if_machinearch(p + 1, len - 1);
if (l == -1 || (size_t)(l + 1) > len)
return -1;
+ *p = ':';
p += l;
return p - str;
}
dhcp_zero_index(o);
}
-size_t
-dhcp_read_lease_fd(int fd, void **lease)
+ssize_t
+dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len)
{
- struct stat st;
- size_t sz;
- void *buf;
- ssize_t len;
- if (fstat(fd, &st) != 0)
- goto out;
- if (!S_ISREG(st.st_mode)) {
- errno = EINVAL;
- goto out;
- }
- if (st.st_size > UINT32_MAX) {
- errno = E2BIG;
- goto out;
- }
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP &&
+ !(ctx->options & DHCPCD_PRIVSEPROOT))
+ return ps_root_readfile(ctx, file, data, len);
+#else
+ UNUSED(ctx);
+#endif
- sz = (size_t)st.st_size;
- if (sz == 0)
- goto out;
- if ((buf = malloc(sz)) == NULL)
- goto out;
- if ((len = read(fd, buf, sz)) == -1) {
- free(buf);
- goto out;
- }
- *lease = buf;
- return (size_t)len;
+ return readfile(file, data, len);
+}
-out:
- *lease = NULL;
- return 0;
+ssize_t
+dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
+ const void *data, size_t len)
+{
+
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP &&
+ !(ctx->options & DHCPCD_PRIVSEPROOT))
+ return ps_root_writefile(ctx, file, mode, data, len);
+#else
+ UNUSED(ctx);
+#endif
+
+ return writefile(file, mode, data, len);
+}
+
+int
+dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
+{
+
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP &&
+ !(ctx->options & DHCPCD_PRIVSEPROOT))
+ return ps_root_filemtime(ctx, file, time);
+#else
+ UNUSED(ctx);
+#endif
+
+ return filemtime(file, time);
+}
+
+int
+dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file)
+{
+
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP &&
+ !(ctx->options & DHCPCD_PRIVSEPROOT))
+ return ps_root_unlink(ctx, file);
+#else
+ UNUSED(ctx);
+#endif
+
+ return unlink(file);
+}
+
+size_t
+dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file)
+{
+ char buf[BUFSIZ];
+ ssize_t bytes;
+ size_t len;
+
+ bytes = dhcp_readfile(ctx, file, buf, sizeof(buf));
+ if (bytes == -1 || bytes == sizeof(buf))
+ return 0;
+
+ bytes[buf] = '\0';
+ len = hwaddr_aton(NULL, buf);
+ if (len == 0)
+ return 0;
+ *data = malloc(len);
+ if (*data == NULL)
+ return 0;
+ hwaddr_aton(*data, buf);
+ return len;
}
const uint8_t *, size_t, struct dhcp_opt **),
const uint8_t *od, size_t ol);
void dhcp_zero_index(struct dhcp_opt *);
-size_t dhcp_read_lease_fd(int, void **);
+ssize_t dhcp_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
+ssize_t dhcp_writefile(struct dhcpcd_ctx *, const char *, mode_t,
+ const void *, size_t);
+int dhcp_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
+int dhcp_unlink(struct dhcpcd_ctx *, const char *);
+size_t dhcp_read_hwaddr_aton(struct dhcpcd_ctx *, uint8_t **, const char *);
#endif
#include <sys/param.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <arpa/inet.h>
#include <net/if.h>
return -1;
}
-static ssize_t
-write_lease(const struct interface *ifp, const struct bootp *bootp, size_t len)
-{
- int fd;
- ssize_t bytes;
- const struct dhcp_state *state = D_CSTATE(ifp);
-
- logdebugx("%s: writing lease `%s'", ifp->name, state->leasefile);
-
- fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- bytes = write(fd, bootp, len);
- close(fd);
- return bytes;
-}
-
static size_t
read_lease(struct interface *ifp, struct bootp **bootp)
{
- int fd;
- bool fd_opened;
+ union {
+ struct bootp bootp;
+ uint8_t buf[FRAMELEN_MAX];
+ } buf;
struct dhcp_state *state = D_STATE(ifp);
struct bootp *lease;
- size_t bytes;
+ ssize_t bytes;
uint8_t type;
#ifdef AUTH
const uint8_t *auth;
*bootp = NULL;
if (state->leasefile[0] == '\0') {
- fd = fileno(stdin);
- fd_opened = false;
+ logdebugx("reading standard input");
+ bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
} else {
- fd = open(state->leasefile, O_RDONLY);
- fd_opened = true;
+ logdebugx("%s: reading lease `%s'",
+ ifp->name, state->leasefile);
+ bytes = dhcp_readfile(ifp->ctx, state->leasefile,
+ buf.buf, sizeof(buf.buf));
}
- if (fd == -1) {
+ if (bytes == -1) {
if (errno != ENOENT)
- logerr("%s: open `%s'",
- ifp->name, state->leasefile);
+ logerr("%s: %s", ifp->name, state->leasefile);
return 0;
}
- if (state->leasefile[0] == '\0')
- logdebugx("reading standard input");
- else
- logdebugx("%s: reading lease `%s'",
- ifp->name, state->leasefile);
-
- bytes = dhcp_read_lease_fd(fd, (void **)&lease);
- if (fd_opened)
- close(fd);
- if (bytes == 0)
- return 0;
/* Ensure the packet is at lease BOOTP sized
* with a vendor area of 4 octets
* (it should be more, and our read packet enforces this so this
* code should not be needed, but of course people could
* scribble whatever in the stored lease file. */
- if (bytes < DHCP_MIN_LEN) {
- free(lease);
+ if ((size_t)bytes < DHCP_MIN_LEN) {
logerrx("%s: %s: truncated lease", ifp->name, __func__);
return 0;
}
goto out;
/* We may have found a BOOTP server */
- if (get_option_uint8(ifp->ctx, &type, (struct bootp *)lease, bytes,
+ if (get_option_uint8(ifp->ctx, &type, &buf.bootp, bytes,
DHO_MESSAGETYPE) == -1)
type = 0;
#ifdef AUTH
/* Authenticate the message */
- auth = get_option(ifp->ctx, (struct bootp *)lease, bytes,
+ auth = get_option(ifp->ctx, &buf.bootp, bytes,
DHO_AUTHENTICATION, &auth_len);
if (auth) {
if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
lease, bytes, 4, type, auth, auth_len) == NULL)
{
logerr("%s: authentication failed", ifp->name);
- free(lease);
return 0;
}
if (state->auth.token)
DHCPCD_AUTH_SENDREQUIRE)
{
logerrx("%s: authentication now required", ifp->name);
- free(lease);
return 0;
}
#endif
out:
- *bootp = (struct bootp *)lease;
- return bytes;
+ *bootp = malloc(bytes);
+ if (*bootp == NULL) {
+ logerr(__func__);
+ return 0;
+ }
+ memcpy(*bootp, buf.buf, bytes);
+ return (size_t)bytes;
}
static const struct dhcp_opt *
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcp_drop(ifp, "EXPIRE");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
state->interval = 0;
if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier > LINK_DOWN)
dhcp_discover(ifp);
/* RFC 2131 3.1.5, Client-server interaction */
logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia));
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo)
dhcp_decline(ifp);
#ifdef IN_IFF_DUPLICATED
}
state->state = DHS_BOUND;
if (!state->lease.frominfo &&
- !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
- if (write_lease(ifp, state->new, state->new_len) == -1)
- logerr("write_lease: %s", state->leasefile);
+ !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) {
+ logdebugx("%s: writing lease `%s'",
+ ifp->name, state->leasefile);
+ if (dhcp_writefile(ifp->ctx, state->leasefile, 0640,
+ state->new, state->new_len) == -1)
+ logerr("dhcp_writefile: %s", state->leasefile);
+ }
/* Close the BPF filter as we can now receive DHCP messages
* on a UDP socket. */
return;
state->state = DHS_RELEASE;
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
if (ifp->carrier > LINK_DOWN &&
state->new != NULL &&
state->lease.server.s_addr != INADDR_ANY)
return;
if (!(ifp->ctx->options & DHCPCD_TEST)) {
dhcp_drop(ifp, "NAK");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
/* If we constantly get NAKS then we should slowly back off */
/* We need to drop the leasefile so that dhcp_start
* doesn't load it. */
if (ifo->options & DHCPCD_REQUEST)
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
free(state->clientid);
state->clientid = NULL;
struct dhcpcd_ctx *ctx = ifp->ctx;
struct if_options *ifo = ifp->options;
struct dhcp_state *state;
- struct stat st;
uint32_t l;
int nolease;
}
if (state->offer) {
struct ipv4_addr *ia;
+ time_t mtime;
get_lease(ifp, &state->lease, state->offer, state->offer_len);
state->lease.frominfo = 1;
state->offer_len = 0;
} else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) &&
state->lease.leasetime != DHCP_INFINITE_LIFETIME &&
- stat(state->leasefile, &st) == 0)
+ dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == 0)
{
time_t now;
/* Offset lease times and check expiry */
now = time(NULL);
if (now == -1 ||
- (time_t)state->lease.leasetime < now - st.st_mtime)
+ (time_t)state->lease.leasetime < now - mtime)
{
logdebugx("%s: discarding expired lease",
ifp->name);
dhcp_drop(ifp, "EXPIRE");
#endif
} else {
- l = (uint32_t)(now - st.st_mtime);
+ l = (uint32_t)(now - mtime);
state->lease.leasetime -= l;
state->lease.renewaltime -= l;
state->lease.rebindtime -= l;
* SUCH DAMAGE.
*/
-#include <sys/stat.h>
#include <sys/utsname.h>
#include <netinet/in.h>
dhcp6_makevendor(void *data, const struct interface *ifp)
{
const struct if_options *ifo;
- size_t len, i;
+ size_t len, vlen, i;
uint8_t *p;
- ssize_t vlen;
const struct vivco *vivco;
char vendor[VENDORCLASSID_MAX_LEN];
struct dhcp6_option o;
len += sizeof(uint16_t) + vivco->len;
vlen = 0; /* silence bogus gcc warning */
} else {
- vlen = dhcp_vendor(vendor, sizeof(vendor));
- if (vlen == -1)
- vlen = 0;
- else
- len += sizeof(uint16_t) + (size_t)vlen;
+ vlen = strlcpy(vendor, ifp->ctx->vendor, sizeof(vendor));
+ len += sizeof(uint16_t) + vlen;
}
if (len > UINT16_MAX) {
state->new_len = 0;
if (state->old != NULL)
script_runreason(ifp, "EXPIRE6");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
if (!dhcp6_startdiscoinform(ifp)) {
}
static ssize_t
-dhcp6_writelease(const struct interface *ifp)
-{
- const struct dhcp6_state *state;
- int fd;
- ssize_t bytes;
-
- state = D6_CSTATE(ifp);
- logdebugx("%s: writing lease `%s'", ifp->name, state->leasefile);
-
- fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- bytes = write(fd, state->new, state->new_len);
- close(fd);
- return bytes;
-}
-
-static int
dhcp6_readlease(struct interface *ifp, int validate)
{
+ union {
+ struct dhcp6_message dhcp6;
+ uint8_t buf[UDPLEN_MAX];
+ } buf;
struct dhcp6_state *state;
- struct stat st;
+ ssize_t bytes;
int fd;
- time_t now;
- int retval;
- bool read_stdin, fd_opened;
+ time_t mtime, now;
#ifdef AUTH
uint8_t *o;
uint16_t ol;
#endif
state = D6_STATE(ifp);
- read_stdin = state->leasefile[0] == '\0';
- if (read_stdin) {
+ if (state->leasefile[0] == '\0') {
logdebugx("reading standard input");
- fd = fileno(stdin);
- fd_opened = false;
+ bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
} else {
- logdebugx("%s: reading lease `%s'", ifp->name,state->leasefile);
- fd = open(state->leasefile, O_RDONLY);
- if (fd != -1 && fstat(fd, &st) == -1) {
- close(fd);
- fd = -1;
- }
- fd_opened = true;
+ logdebugx("%s: reading lease `%s'",
+ ifp->name, state->leasefile);
+ bytes = dhcp_readfile(ifp->ctx, state->leasefile,
+ buf.buf, sizeof(buf.buf));
}
- if (fd == -1)
- return -1;
- retval = -1;
- free(state->new);
- state->new_len = dhcp_read_lease_fd(fd, (void **)&state->new);
- if (fd_opened)
- close(fd);
+ if (bytes == -1)
+ goto ex;
- if (ifp->ctx->options & DHCPCD_DUMPLEASE || read_stdin)
- return 0;
+ if (ifp->ctx->options & DHCPCD_DUMPLEASE || state->leasefile[0] == '\0')
+ goto out;
- if (state->new_len == 0) {
- retval = 0;
+ if (bytes == 0)
goto ex;
- }
/* If not validating IA's and if they have expired,
* skip to the auth check. */
- if (!validate) {
- fd = 0;
+ if (!validate)
goto auth;
- }
+ if (dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == -1)
+ goto ex;
clock_gettime(CLOCK_MONOTONIC, &state->acquired);
if ((now = time(NULL)) == -1)
goto ex;
- state->acquired.tv_sec -= now - st.st_mtime;
+ state->acquired.tv_sec -= now - mtime;
/* Check to see if the lease is still valid */
- fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
+ fd = dhcp6_validatelease(ifp, &buf.dhcp6, bytes, NULL,
&state->acquired);
if (fd == -1)
goto ex;
if (state->expire != ND6_INFINITE_LIFETIME &&
- (time_t)state->expire < now - st.st_mtime &&
+ (time_t)state->expire < now - mtime &&
!(ifp->options->options & DHCPCD_LASTLEASE_EXTEND))
{
logdebugx("%s: discarding expired lease", ifp->name);
- retval = 0;
+ bytes = 0;
goto ex;
}
auth:
- retval = 0;
#ifdef AUTH
/* Authenticate the message */
- o = dhcp6_findmoption(state->new, state->new_len, D6_OPTION_AUTH, &ol);
+ o = dhcp6_findmoption(&buf.dhcp6, bytes, D6_OPTION_AUTH, &ol);
if (o) {
if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
- (uint8_t *)state->new, state->new_len, 6, state->new->type,
- o, ol) == NULL)
+ buf.buf, bytes, 6, buf.dhcp6.type, o, ol) == NULL)
{
logerr("%s: authentication failed", ifp->name);
+ bytes = 0;
goto ex;
}
if (state->auth.token)
}
#endif
- return fd;
+out:
+ free(state->new);
+ state->new = malloc(bytes);
+ if (state->new == NULL) {
+ logerr(__func__);
+ goto ex;
+ }
+
+ memcpy(state->new, buf.buf, bytes);
+ state->new_len = bytes;
+ return bytes;
ex:
dhcp6_freedrop_addrs(ifp, 0, NULL);
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
free(state->new);
state->new = NULL;
state->new_len = 0;
- return retval;
+ return bytes == 0 ? 0 : -1;
}
static void
dhcp6_startinit(struct interface *ifp)
{
struct dhcp6_state *state;
- int r;
+ ssize_t r;
uint8_t has_ta, has_non_ta;
size_t i;
logmessage(loglevel, "%s: expire in %"PRIu32" seconds",
ifp->name, state->expire);
rt_build(ifp->ctx, AF_INET6);
- if (!confirmed && !timedout)
- if (dhcp6_writelease(ifp) == -1)
- logerr("dhcp6_writelease: %s",state->leasefile);
+ if (!confirmed && !timedout) {
+ logdebugx("%s: writing lease `%s'",
+ ifp->name, state->leasefile);
+ if (dhcp_writefile(ifp->ctx, state->leasefile, 0640,
+ state->new, state->new_len) == -1)
+ logerr("dhcp_writefile: %s",state->leasefile);
+ }
#ifndef SMALL
dhcp6_delegate_prefix(ifp);
#endif
* replay it in my code.
*/
static int replyn = 0;
- char fname[PATH_MAX], tbuf[64 * 1024];
+ char fname[PATH_MAX], tbuf[UDPLEN_MAX];
int fd;
ssize_t tlen;
uint8_t *si1, *si2;
struct sockaddr_in6 from;
union {
struct dhcp6_message dhcp6;
- uint8_t buf[64 * 1024]; /* Maximum UDP message size */
+ uint8_t buf[UDPLEN_MAX]; /* Maximum UDP message size */
} iovbuf;
struct iovec iov = {
.iov_base = iovbuf.buf, .iov_len = sizeof(iovbuf.buf),
dhcp6_startrelease(ifp);
return;
}
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
dhcp6_freedrop_addrs(ifp, drop, NULL);
free(state->old);
#include <unistd.h>
-const char * const dhcpcd_embedded_conf[] = {
+const char dhcpcd_embedded_conf[] =
#define INITDEFINE6S @INITDEFINE6S@
#endif
-extern const char * const dhcpcd_embedded_conf[];
+extern const char dhcpcd_embedded_conf[];
eloop_event_delete(ctx->eloop, ctx->fork_fd);
close(ctx->fork_fd);
ctx->fork_fd = -1;
- (void)freopen(_PATH_DEVNULL, "w", stdout);
- (void)freopen(_PATH_DEVNULL, "w", stderr);
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP) {
+ /* Aside from Linux, we don't have access to /dev/null */
+ fclose(stdout);
+ fclose(stderr);
+ } else
+#endif
+ {
+ (void)freopen(_PATH_DEVNULL, "w", stdout);
+ (void)freopen(_PATH_DEVNULL, "w", stderr);
+ }
#endif
}
ifp->name, ifn->name);
}
+static void
+dhcpcd_initduid(struct dhcpcd_ctx *ctx, struct interface *ifp)
+{
+ char buf[DUID_LEN * 3];
+
+ if (ctx->duid != NULL)
+ return;
+
+ duid_init(ctx, ifp);
+ if (ctx->duid == NULL)
+ return;
+
+ loginfox("DUID %s",
+ hwaddr_ntoa(ctx->duid, ctx->duid_len, buf, sizeof(buf)));
+}
+
void
dhcpcd_startinterface(void *arg)
{
struct interface *ifp = arg;
struct if_options *ifo = ifp->options;
- char buf[DUID_LEN * 3];
int carrier;
if (ifo->options & DHCPCD_LINK) {
if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) &&
!(ifo->options & DHCPCD_ANONYMOUS))
{
+ char buf[sizeof(ifo->iaid) * 3];
#ifdef INET6
size_t i;
struct if_ia *ia;
#endif
- /* Report client DUID */
- if (ifp->ctx->duid == NULL) {
- if (duid_init(ifp) == 0)
- return;
- loginfox("DUID %s",
- hwaddr_ntoa(ifp->ctx->duid,
- ifp->ctx->duid_len,
- buf, sizeof(buf)));
- }
+ /* Try and init DUID from the interface hardware address */
+ dhcpcd_initduid(ifp->ctx, ifp);
/* Report IAIDs */
loginfox("%s: IAID %s", ifp->name,
hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
buf, sizeof(buf)));
warn_iaid_conflict(ifp, 0, ifo->iaid);
+
#ifdef INET6
for (i = 0; i < ifo->ia_len; i++) {
ia = &ifo->ia[i];
dhcpcd_setlinkrcvbuf(&ctx);
#endif
+ /* Try and create DUID from the machine UUID. */
+ dhcpcd_initduid(&ctx, NULL);
+
+ /* Cache the default vendor option. */
+ if (dhcp_vendor(ctx.vendor, sizeof(ctx.vendor)) == -1)
+ logerrx("dhcp_vendor");
+
#ifdef PRIVSEP
if (ctx.options & DHCPCD_PRIVSEP) {
+
/*
* PSF_CAP_ENTER is not set because the following functions
* won't work in it:
struct dhcpcd_ctx {
char pidfile[sizeof(PIDFILE) + IF_NAMESIZE + 1];
+ char vendor[256];
int fork_fd; /* FD for the fork init signal pipe */
const char *cffile;
unsigned long long options;
#define DUID_STRLEN DUID_LEN * 3
static size_t
-duid_get(uint8_t **d, const struct interface *ifp)
+duid_get(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
- FILE *fp;
uint8_t *data;
- size_t len;
- int x = 0;
+ size_t len, slen;
char line[DUID_STRLEN];
const struct interface *ifp2;
/* If we already have a DUID then use it as it's never supposed
* to change once we have one even if the interfaces do */
- if ((len = read_hwaddr_aton(&data, DUID)) != 0) {
+ if ((len = dhcp_read_hwaddr_aton(ctx, &data, DUID)) != 0) {
if (len <= DUID_LEN) {
- *d = data;
+ ctx->duid = data;
return len;
}
logerrx("DUID too big (max %u): %s", DUID_LEN, DUID);
}
}
- /* Regardless of what happens we will create a DUID to use. */
- *d = data;
-
/* No file? OK, lets make one based the machines UUID */
- len = duid_make_uuid(data);
- if (len > 0)
+ if (ifp == NULL) {
+ len = duid_make_uuid(data);
+ if (len == 0)
+ free(data);
+ else
+ ctx->duid = data;
return len;
+ }
+
+ /* Regardless of what happens we will create a DUID to use. */
+ ctx->duid = data;
/* No UUID? OK, lets make one based on our interface */
if (ifp->hwlen == 0) {
}
}
- if (!(fp = fopen(DUID, "w"))) {
- logerr("%s", DUID);
- return duid_make(data, ifp, DUID_LL);
- }
len = duid_make(data, ifp, DUID_LLT);
- x = fprintf(fp, "%s\n", hwaddr_ntoa(data, len, line, sizeof(line)));
- if (fclose(fp) == EOF)
- x = -1;
- /* Failed to write the duid? scrub it, we cannot use it */
- if (x < 1) {
- logerr("%s", DUID);
- unlink(DUID);
+ hwaddr_ntoa(data, len, line, sizeof(line));
+ slen = strlen(line);
+ if (slen < sizeof(line) - 2) {
+ line[slen++] = '\n';
+ line[slen] = '\0';
+ }
+ if (dhcp_writefile(ctx, DUID, 0640, line, slen) == -1) {
+ logerr("%s: cannot write duid", __func__);
return duid_make(data, ifp, DUID_LL);
}
return len;
}
-size_t duid_init(const struct interface *ifp)
+size_t
+duid_init(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
- if (ifp->ctx->duid == NULL)
- ifp->ctx->duid_len = duid_get(&ifp->ctx->duid, ifp);
- return ifp->ctx->duid_len;
+ if (ctx->duid == NULL)
+ ctx->duid_len = duid_get(ctx, ifp);
+ return ctx->duid_len;
}
#define DUID_UUID 4
size_t duid_make(void *, const struct interface *, uint16_t);
-size_t duid_init(const struct interface *);
+size_t duid_init(struct dhcpcd_ctx *, const struct interface *);
#endif
-e 's/#.*$//' \
-e '/^$/d' \
-e 's/^/"/g' \
- -e 's/$/\",/g' \
+ -e 's/$/\\n\"/g' \
-e 's/ [ ]*/ /g' \
-e 's/ [ ]*/ /g' \
$CONF_SMALL
-e 's/#.*$//' \
-e '/^$/d' \
-e 's/^/"/g' \
- -e 's/$/\",/g' \
+ -e 's/$/\\n"/g' \
-e 's/ [ ]*/ /g' \
-e 's/ [ ]*/ /g' \
$CONF
echo "#endif"
-printf "%s\n%s\n" "NULL" "};"
+printf "%s\n%s\n" '"\0";'
}
#ifndef SYS_NMLN /* OSX */
-# define SYS_NMLN 256
+# define SYS_NMLN __SYS_NAMELEN
#endif
#ifndef HW_MACHINE_ARCH
# ifdef HW_MODEL /* OpenBSD */
if_machinearch(char *str, size_t len)
{
int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
- char march[SYS_NMLN];
- size_t marchlen = sizeof(march);
-return -1;
- if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
- march, &marchlen, NULL, 0) != 0)
- return -1;
- return snprintf(str, len, ":%s", march);
+ return sysctl(mib, sizeof(mib) / sizeof(mib[0]), str, &len, NULL, 0);
}
#ifdef INET6
fscanf(fp, "%255s", buf) == 1)
{
fclose(fp);
- return snprintf(str, len, ":%s", buf);
+ return snprintf(str, len, "%s", buf);
}
}
fclose(fp);
*/
#include <sys/param.h>
-#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
* We strip leading space and avoid comment lines, making the code that calls
* us smaller. */
static char *
-get_line(char ** __restrict buf, size_t * __restrict buflen,
- FILE * __restrict fp)
+get_line(char ** __restrict buf, ssize_t * __restrict buflen)
{
char *p, *c;
- ssize_t bytes;
- int quoted;
+ bool quoted;
do {
- bytes = getline(buf, buflen, fp);
- if (bytes == -1)
- return NULL;
- for (p = *buf; *p == ' ' || *p == '\t'; p++)
+ p = *buf;
+ c = memchr(*buf, '\n', *buflen);
+ if (c == NULL) {
+ c = memchr(*buf, '\0', *buflen);
+ if (c == NULL)
+ return NULL;
+ *buflen = c - *buf;
+ *buf = NULL;
+ } else {
+ *c++ = '\0';
+ *buflen -= c - *buf;
+ *buf = c;
+ }
+ for (; *p == ' ' || *p == '\t'; p++)
;
} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
- if ((*buf)[--bytes] == '\n')
- (*buf)[bytes] = '\0';
/* Strip embedded comments unless in a quoted string or escaped */
- quoted = 0;
+ quoted = false;
for (c = p; *c != '\0'; c++) {
if (*c == '\\') {
c++; /* escaped */
const char *ifname, const char *ssid, const char *profile)
{
struct if_options *ifo;
- FILE *fp;
- struct stat sb;
- char *line, *buf, *option, *p;
- size_t buflen;
+ char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
+ char *line, *option, *p;
+ ssize_t buflen;
ssize_t vlen;
int skip, have_profile, new_block, had_block;
-#ifndef EMBEDDED_CONFIG
- const char * const *e;
- size_t ol;
-#endif
#if !defined(INET) || !defined(INET6)
size_t i;
struct dhcp_opt *opt;
ifo->options |= DHCPCD_DHCP6;
#endif
- vlen = dhcp_vendor((char *)ifo->vendorclassid + 1,
- sizeof(ifo->vendorclassid) - 1);
- ifo->vendorclassid[0] = (uint8_t)(vlen == -1 ? 0 : vlen);
-
- buf = NULL;
- buflen = 0;
+ vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor,
+ sizeof(ifo->vendorclassid) - 1);
+ ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen);
/* Reset route order */
ctx->rt_order = 0;
/* Now load our embedded config */
#ifdef EMBEDDED_CONFIG
- fp = fopen(EMBEDDED_CONFIG, "r");
- if (fp == NULL)
- logerr("%s: fopen `%s'", __func__, EMBEDDED_CONFIG);
-
- while (fp && (line = get_line(&buf, &buflen, fp))) {
+ buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
+ if (buflen == -1) {
+ logerr("%s: %s", __func__, EMBEDDED_CONFIG);
+ return ifo;
+ }
+ if (buf[buflen] != '\0') {
+ if (buflen < sizeof(buf) - 1)
+ bulen++;
+ buf[buflen] = '\0';
+ }
#else
- buflen = 80;
- buf = malloc(buflen);
- if (buf == NULL) {
- logerr(__func__);
- free_options(ctx, ifo);
- return NULL;
+ buflen = strlcpy(buf, dhcpcd_embedded_conf, sizeof(buf));
+ if ((size_t)buflen >= sizeof(buf)) {
+ logerrx("%s: embedded config too big", __func__);
+ return ifo;
}
- ldop = edop = NULL;
- for (e = dhcpcd_embedded_conf; *e; e++) {
- ol = strlen(*e) + 1;
- if (ol > buflen) {
- char *nbuf;
-
- buflen = ol;
- nbuf = realloc(buf, buflen);
- if (nbuf == NULL) {
- logerr(__func__);
- free(buf);
- free_options(ctx, ifo);
- return NULL;
- }
- buf = nbuf;
- }
- memcpy(buf, *e, ol);
- line = buf;
+ /* Our embedded config is NULL terminated */
#endif
+ bp = buf;
+ while ((line = get_line(&bp, &buflen)) != NULL) {
option = strsep(&line, " \t");
if (line)
line = strskipwhite(line);
}
parse_config_line(ctx, NULL, ifo, option, line,
&ldop, &edop);
-
}
-#ifdef EMBEDDED_CONFIG
- if (fp)
- fclose(fp);
-#endif
#ifdef INET
ctx->dhcp_opts = ifo->dhcp_override;
ctx->dhcp_opts_len = ifo->dhcp_override_len;
}
/* Parse our options file */
-#ifdef PRIVSEP
- if (ctx->options & DHCPCD_PRIVSEP &&
- ps_root_copychroot(ctx, ctx->cffile) == -1)
- logwarn("%s: ps_root_copychroot `%s'", __func__, ctx->cffile);
-#endif
- fp = fopen(ctx->cffile, "r");
- if (fp == NULL) {
+ buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
+ if (buflen == -1) {
/* dhcpcd can continue without it, but no DNS options
* would be requested ... */
- logwarn("%s: fopen `%s'", __func__, ctx->cffile);
- free(buf);
+ logerr("%s: %s", __func__, ctx->cffile);
return ifo;
}
- if (stat(ctx->cffile, &sb) == 0)
- ifo->mtime = sb.st_mtime;
+ if (buf[buflen] != '\0') {
+ if ((size_t)buflen < sizeof(buf) - 1)
+ buflen++;
+ buf[buflen] = '\0';
+ }
+ dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
ldop = edop = NULL;
skip = have_profile = new_block = 0;
had_block = ifname == NULL ? 1 : 0;
- while ((line = get_line(&buf, &buflen, fp))) {
+ bp = buf;
+ while ((line = get_line(&bp, &buflen)) != NULL) {
option = strsep(&line, " \t");
if (line)
line = strskipwhite(line);
continue;
if (skip)
continue;
+
parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
}
- fclose(fp);
- free(buf);
if (profile && !have_profile) {
free_options(ctx, ifo);
#define DHCPCD_ONESHOT (1ULL << 60)
#define DHCPCD_INACTIVE (1ULL << 61)
#define DHCPCD_SLAACTEMP (1ULL << 62)
+#define DHCPCD_PRIVSEPROOT (1ULL << 63)
#define DHCPCD_NODROP (DHCPCD_EXITING | DHCPCD_PERSISTENT)
#define FRAMEHDRLEN_MAX 14 /* only ethernet support */
#define FRAMELEN_MAX (FRAMEHDRLEN_MAX + 9216)
+#define UDPLEN_MAX 64 * 1024
+
/* Work out if we have a private address or not
* 10/8
* 172.16/12
static ssize_t
ipv6_readsecret(struct dhcpcd_ctx *ctx)
{
- FILE *fp;
char line[1024];
unsigned char *p;
size_t len;
uint32_t r;
- int x;
- if ((ctx->secret_len = read_hwaddr_aton(&ctx->secret, SECRET)) != 0)
+ ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET);
+ if (ctx->secret_len != 0)
return (ssize_t)ctx->secret_len;
if (errno != ENOENT)
- logerr("%s: %s", __func__, SECRET);
+ logerr("%s: cannot read secret", __func__);
/* Chaining arc4random should be good enough.
* RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
p += sizeof(r);
}
- /* Ensure that only the dhcpcd user can read the secret.
- * Write permission is also denied as changing it would remove
- * it's stability. */
- if ((fp = fopen(SECRET, "w")) == NULL ||
- chmod(SECRET, S_IRUSR) == -1)
- goto eexit;
- x = fprintf(fp, "%s\n",
- hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)));
- if (fclose(fp) == EOF)
- x = -1;
- fp = NULL;
- if (x > 0)
- return (ssize_t)ctx->secret_len;
-
-eexit:
- logerr("%s: %s", __func__, SECRET);
- if (fp != NULL)
- fclose(fp);
- unlink(SECRET);
- ctx->secret_len = 0;
- return -1;
+ hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line));
+ len = strlen(line);
+ if (len < sizeof(line) - 2) {
+ line[len++] = '\n';
+ line[len] = '\0';
+ }
+ if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) {
+ logerr("%s: cannot write secret", __func__);
+ ctx->secret_len = 0;
+ return -1;
+ }
+ return (ssize_t)ctx->secret_len;
}
/* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
return -1;
now = tv.tv_sec;
- tzset();
if (localtime_r(&now, &tmnow) == NULL)
return -1;
if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0)
{
struct logctx *ctx = &_logctx;
+ /* Cache timezone */
+ tzset();
+
if (path == NULL) {
int opts = 0;
#ifdef ARP
static ssize_t
-ps_bpf_arp_addr(uint8_t cmd, struct ps_process *psp, struct msghdr *msg)
+ps_bpf_arp_addr(uint16_t cmd, struct ps_process *psp, struct msghdr *msg)
{
struct interface *ifp = &psp->psp_ifp;
struct iovec *iov = msg->msg_iov;
ssize_t
ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
- uint8_t cmd;
+ uint16_t cmd;
struct ps_process *psp;
pid_t start;
struct iovec *iov = msg->msg_iov;
struct ipv4_state *istate;
unsigned int flags = PSF_DROPPRIVS | PSF_CAP_ENTER;
- cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
+ cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
* Pledge is currently useless for BPF ARP because we cannot
* change the filter:
* http://openbsd-archive.7691.n7.nabble.com/ \
- * pledge-bpf-32bit-arch-unbreak-td299901.html
+ * pledge-bpf-32bit-arch-unbreak-td299901.html
*/
break;
#endif
}
static ssize_t
-ps_bpf_send(const struct interface *ifp, uint8_t cmd,
+ps_bpf_send(const struct interface *ifp, uint16_t cmd,
const void *data, size_t len)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
}
static ssize_t
-ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint8_t domain, unsigned long request,
+ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request,
void *data, size_t len)
{
ssize_t
ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request,
- void *data,size_t len)
+ void *data, size_t len)
{
return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len);
ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
__unused struct msghdr *msg)
{
- uint8_t cmd;
+ uint16_t cmd;
struct ps_process *psp;
int (*start_func)(void *);
pid_t start;
- cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
+ cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
#ifdef INET
static ssize_t
-ps_inet_in_docmd(struct ipv4_addr *ia, uint8_t cmd, const struct msghdr *msg)
+ps_inet_in_docmd(struct ipv4_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
assert(ia != NULL);
struct dhcpcd_ctx *ctx = ia->iface->ctx;
#ifdef INET6
#ifdef __sun
static ssize_t
-ps_inet_ifp_docmd(struct interface *ifp, uint8_t cmd, const struct msghdr *msg)
+ps_inet_ifp_docmd(struct interface *ifp, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct ps_msghdr psm = {
#ifdef DHCP6
static ssize_t
-ps_inet_in6_docmd(struct ipv6_addr *ia, uint8_t cmd, const struct msghdr *msg)
+ps_inet_in6_docmd(struct ipv6_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
struct ps_msghdr psm = {
return status;
}
-#if defined(__linux__) && !defined(st_mtimespec)
-#define st_atimespec st_atim
-#define st_mtimespec st_mtim
-#endif
-ssize_t
-ps_root_docopychroot(struct dhcpcd_ctx *ctx, const char *file)
-{
-
- char path[PATH_MAX], buf[BUFSIZ], *slash;
- struct stat from_sb, to_sb;
- int from_fd, to_fd;
- ssize_t rcount, wcount, total;
-#if defined(BSD) || defined(__linux__)
- struct timespec ts[2];
-#else
- struct timeval tv[2];
-#endif
-
- if (snprintf(path, sizeof(path), "%s/%s", ctx->ps_chroot, file) == -1)
- return -1;
- if (stat(file, &from_sb) == -1)
- return -1;
- if (stat(path, &to_sb) == 0) {
-#if defined(BSD) || defined(__linux__)
- if (from_sb.st_mtimespec.tv_sec == to_sb.st_mtimespec.tv_sec &&
- from_sb.st_mtimespec.tv_nsec == to_sb.st_mtimespec.tv_nsec)
- return 0;
-#else
- if (from_sb.st_mtime == to_sb.st_mtime)
- return 0;
-#endif
- } else {
- /* Ensure directory exists */
- slash = strrchr(path, '/');
- if (slash != NULL) {
- *slash = '\0';
- ps_mkdir(path);
- *slash = '/';
- }
- }
-
- if (unlink(path) == -1 && errno != ENOENT)
- return -1;
- if ((from_fd = open(file, O_RDONLY, 0)) == -1)
- return -1;
- if ((to_fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0555)) == -1)
- return -1;
-
- total = 0;
- while ((rcount = read(from_fd, buf, sizeof(buf))) > 0) {
- wcount = write(to_fd, buf, (size_t)rcount);
- if (wcount != rcount) {
- total = -1;
- break;
- }
- total += wcount;
- }
-
-#if defined(BSD) || defined(__linux__)
- ts[0] = from_sb.st_atimespec;
- ts[1] = from_sb.st_mtimespec;
- if (futimens(to_fd, ts) == -1)
- total = -1;
-#else
- tv[0].tv_sec = from_sb.st_atime;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = from_sb.st_mtime;
- tv[1].tv_usec = 0;
- if (futimes(to_fd, tv) == -1)
- total = -1;
-#endif
- close(from_fd);
- close(to_fd);
-
- return total;
-}
-
static ssize_t
-ps_root_dofileop(struct dhcpcd_ctx *ctx, void *data, size_t len, uint8_t op)
+ps_root_dowritefile(mode_t mode, void *data, size_t len)
{
- char *path = data;
- size_t plen;
-
- if (len < sizeof(plen)) {
- errno = EINVAL;
- return -1;
- }
+ char *file = data, *nc;
- memcpy(&plen, path, sizeof(plen));
- path += sizeof(plen);
- if (sizeof(plen) + plen > len) {
+ nc = memchr(file, '\0', len);
+ if (nc == NULL) {
errno = EINVAL;
return -1;
}
-
- switch(op) {
- case PS_COPY:
- return ps_root_docopychroot(ctx, path);
- case PS_UNLINK:
- return (ssize_t)unlink(path);
- default:
- errno = ENOTSUP;
- return -1;
- }
+ nc++;
+ return writefile(file, mode, nc, len - (nc - file));
}
static ssize_t
ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
- uint8_t cmd;
+ uint16_t cmd;
struct ps_process *psp;
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
size_t len = iov->iov_len;
+ uint8_t buf[PS_BUFLEN];
+ time_t mtime;
ssize_t err;
+ bool retdata = false;
- cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP | PS_DELETE));
+ cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP | PS_DELETE));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
switch (psm->ps_cmd) {
case PS_IOCTL:
err = ps_root_doioctl(psm->ps_flags, data, len);
+ retdata = true;
break;
case PS_SCRIPT:
err = ps_root_run_script(ctx, data, len);
break;
- case PS_COPY: /* FALLTHROUGH */
case PS_UNLINK:
- err = ps_root_dofileop(ctx, data, len, psm->ps_cmd);
+ err = unlink(data);
+ break;
+ case PS_READFILE:
+ errno = 0;
+ err = readfile(data, buf, sizeof(buf));
+ if (err != -1) {
+ data = buf;
+ len = (size_t)err;
+ retdata = true;
+ }
+ break;
+ case PS_WRITEFILE:
+ err = ps_root_dowritefile(psm->ps_flags, data, len);
+ break;
+ case PS_FILEMTIME:
+ err = filemtime(data, &mtime);
+ if (err != -1) {
+ data = &mtime;
+ len = sizeof(mtime);
+ retdata = true;
+ }
break;
default:
err = ps_root_os(psm, msg);
break;
}
- return ps_root_writeerror(ctx, err, data, len);
+ return ps_root_writeerror(ctx, err, data, retdata ? len : 0);
}
/* Receive from state engine, do an action. */
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
ctx->ps_root_pid = getpid();
+ ctx->options |= DHCPCD_PRIVSEPROOT;
return 0;
}
return ps_root_readerror(ctx, data, len);
}
-static ssize_t
-ps_root_fileop(struct dhcpcd_ctx *ctx, const char *path, uint8_t op)
+ssize_t
+ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
{
- char buf[PATH_MAX], *p = buf;
- size_t plen = strlen(path) + 1;
- size_t len = sizeof(plen) + plen;
-
- if (len > sizeof(buf)) {
- errno = ENOBUFS;
- return -1;
- }
-
- memcpy(p, &plen, sizeof(plen));
- p += sizeof(plen);
- memcpy(p, path, plen);
- if (ps_sendcmd(ctx, ctx->ps_root_fd, op, 0, buf, len) == -1)
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0,
+ file, strlen(file) + 1) == -1)
return -1;
return ps_root_readerror(ctx, NULL, 0);
}
+ssize_t
+ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
+ void *data, size_t len)
+{
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0,
+ file, strlen(file) + 1) == -1)
+ return -1;
+ return ps_root_readerror(ctx, data, len);
+}
ssize_t
-ps_root_copychroot(struct dhcpcd_ctx *ctx, const char *path)
+ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
+ const void *data, size_t len)
{
+ char buf[PS_BUFLEN];
+ size_t flen;
- return ps_root_fileop(ctx, path, PS_COPY);
+ flen = strlcpy(buf, file, sizeof(buf));
+ flen += 1;
+ if (flen > sizeof(buf) || flen + len > sizeof(buf)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ memcpy(buf + flen, data, len);
+
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode,
+ buf, flen + len) == -1)
+ return -1;
+ return ps_root_readerror(ctx, NULL, 0);
}
-ssize_t
-ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path)
+int
+ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
{
- return ps_root_fileop(ctx, path, PS_UNLINK);
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0,
+ file, strlen(file) + 1) == -1)
+ return -1;
+ return ps_root_readerror(ctx, time, sizeof(*time));
}
int ps_root_stop(struct dhcpcd_ctx *ctx);
ssize_t ps_root_readerror(struct dhcpcd_ctx *, void *, size_t);
-ssize_t ps_root_docopychroot(struct dhcpcd_ctx *, const char *);
-ssize_t ps_root_copychroot(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *);
+int ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
+ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
+ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
+ const void *, size_t);
ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
#if defined(BSD) || defined(__sun)
ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
#include <util.h>
#endif
-int
-ps_mkdir(char *path)
-{
- char *slash;
- bool done;
-
- slash = path;
- for (;;) {
- slash += strspn(slash, "/");
- slash += strcspn(slash, "/");
- done = (*slash == '\0');
- *slash = '\0';
- if (mkdir(path, 0755) == -1 && errno != EEXIST)
- return -1;
- if (done)
- break;
- *slash = '/';
- }
- return 0;
-}
-
int
ps_init(struct dhcpcd_ctx *ctx)
{
- char path[PATH_MAX];
struct passwd *pw;
errno = 0;
ctx->ps_chroot = pw->pw_dir;
/* If we pickup the _dhcp user refuse the default directory */
- if (*ctx->ps_chroot != '/' ||
- strcmp(ctx->ps_chroot, "/var/empty") == 0)
- {
+ if (*ctx->ps_chroot != '/') {
ctx->options &= ~DHCPCD_PRIVSEP;
logerrx("refusing chroot: %s: %s",
PRIVSEP_USER, ctx->ps_chroot);
return -1;
}
- /* Create the database directory. */
- if (snprintf(path, sizeof(path), "%s%s", ctx->ps_chroot, DBDIR) == -1 ||
- ps_mkdir(path) == -1 ||
- chown(path, pw->pw_uid, pw->pw_gid) == -1 ||
- chmod(path, 0755) == -1)
- logerr("%s: %s", __func__, path);
-
- /* Ensure we have a localtime to correctly format dates. */
- if (ps_root_docopychroot(ctx, "/etc/localtime") == -1 && errno!=ENOENT)
- logerr("%s: %s", __func__, "/etc/localtime");
-
ctx->options |= DHCPCD_PRIVSEP;
return 0;
}
if (!(ctx->options & DHCPCD_FORKED))
logdebugx("chrooting to `%s'", ctx->ps_chroot);
-
if (chroot(ctx->ps_chroot) == -1)
logerr("%s: chroot `%s'", __func__, ctx->ps_chroot);
if (chdir("/") == -1)
if (ctx->options & DHCPCD_UNPRIV)
promises = "stdio dns bpf";
else
- /* SIOCGIFGROUP requries inet
- * lease files and foo require rpath, wpath and cpath */
- promises = "stdio dns inet route rpath wpath cpath";
+ /* SIOCGIFGROUP requires inet */
+ promises = "stdio dns inet route";
if (pledge(promises, NULL) == -1) {
logerr("%s: pledge", __func__);
return -1;
ssize_t
-ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
+ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags,
const struct msghdr *msg)
{
assert(msg->msg_iovlen == 1);
}
ssize_t
-ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
+ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags,
const void *data, size_t len)
{
struct ps_msghdr psm = {
}
static ssize_t
-ps_sendcmdmsg(int fd, uint8_t cmd, const struct msghdr *msg)
+ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg)
{
struct ps_msghdr psm = { .ps_cmd = cmd };
uint8_t data[PS_BUFLEN], *p = data;
}
ssize_t
-ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint8_t cmd, int wfd)
+ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
{
struct sockaddr_storage ss = { .ss_family = AF_UNSPEC };
uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 };
#define PSF_CAP_ENTER 0x02
#define PSF_PLEDGE 0x04
-/* Commands */
-#define PS_BOOTP 0x01
-#define PS_ND 0x02
-#define PS_DHCP6 0x03
-#define PS_BPF_BOOTP 0x04
-#define PS_BPF_ARP 0x05
-#define PS_BPF_ARP_ADDR 0x06
-
-#define PS_IOCTL 0x10
-#define PS_ROUTE 0x11 /* Also used for NETLINK */
-#define PS_SCRIPT 0x12
-#define PS_UNLINK 0x13
-#define PS_COPY 0x14
+/* Protocols */
+#define PS_BOOTP 0x0001
+#define PS_ND 0x0002
+#define PS_DHCP6 0x0003
+#define PS_BPF_BOOTP 0x0004
+#define PS_BPF_ARP 0x0005
+#define PS_BPF_ARP_ADDR 0x0006
+
+/* Generic commands */
+#define PS_IOCTL 0x0010
+#define PS_ROUTE 0x0011 /* Also used for NETLINK */
+#define PS_SCRIPT 0x0012
+#define PS_UNLINK 0x0013
+#define PS_READFILE 0x0014
+#define PS_WRITEFILE 0x0015
+#define PS_FILEMTIME 0x0016
/* BSD Commands */
-#define PS_IOCTLLINK 0x15
-#define PS_IOCTL6 0x16
-#define PS_IOCTLINDIRECT 0x17
-#define PS_IP6FORWARDING 0x18
+#define PS_IOCTLLINK 0x0101
+#define PS_IOCTL6 0x0102
+#define PS_IOCTLINDIRECT 0x0103
+#define PS_IP6FORWARDING 0x0104
/* Linux commands */
-#define PS_WRITEPATHUINT 0x19
+#define PS_WRITEPATHUINT 0x0201
-#define PS_DELETE 0x20
-#define PS_START 0x40
-#define PS_STOP 0x80
+/* Process commands */
+#define PS_DELETE 0x2000
+#define PS_START 0x4000
+#define PS_STOP 0x8000
/* Max INET message size + meta data for IPC */
#define PS_BUFLEN ((64 * 1024) + \
struct ps_id {
struct ps_addr psi_addr;
unsigned int psi_ifindex;
- uint8_t psi_cmd;
- uint8_t psi_pad[3];
+ uint16_t psi_cmd;
+ uint8_t psi_pad[2];
};
struct ps_msghdr {
- uint8_t ps_cmd;
- uint8_t ps_pad[sizeof(unsigned long) - 1];
+ uint16_t ps_cmd;
+ uint8_t ps_pad[sizeof(unsigned long) - sizeof(uint16_t)];
unsigned long ps_flags;
struct ps_id ps_id;
socklen_t ps_namelen;
#include "privsep-bpf.h"
#endif
-int ps_mkdir(char *);
int ps_init(struct dhcpcd_ctx *);
int ps_dropprivs(struct dhcpcd_ctx *, unsigned int);
int ps_start(struct dhcpcd_ctx *);
struct ps_msghdr *, const struct msghdr *);
ssize_t ps_sendpsmdata(struct dhcpcd_ctx *, int,
struct ps_msghdr *, const void *, size_t);
-ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint8_t, unsigned long,
+ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const struct msghdr *);
-ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint8_t, unsigned long,
+ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const void *data, size_t len);
-ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, uint8_t, int);
+ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, uint16_t, int);
ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int,
ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *);