mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-23 10:06:42 +08:00
privsep: Handle all file IO in the Priviledged Actioneer
This allows us to move the database directory back into the root of the filesystem. While here, harden the files by denying any user read access to them. As part of this change, init the DUID from any machine data and cache the default DHCP vendor field before dropping priviledges as we may lose access to this later.
This commit is contained in:
parent
123d782925
commit
cf85354d04
77
src/common.c
77
src/common.c
@ -26,17 +26,18 @@
|
||||
* 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)
|
||||
@ -103,36 +104,58 @@ hwaddr_aton(uint8_t *buffer, const char *addr)
|
||||
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;
|
||||
int fd;
|
||||
struct stat st;
|
||||
ssize_t bytes = -1;
|
||||
|
||||
if ((fp = fopen(path, "r")) == NULL)
|
||||
return 0;
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
@ -147,6 +147,8 @@
|
||||
|
||||
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
|
||||
|
@ -26,7 +26,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <ctype.h>
|
||||
@ -176,9 +175,10 @@ dhcp_vendor(char *str, size_t len)
|
||||
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;
|
||||
}
|
||||
@ -945,38 +945,85 @@ dhcp_zero_index(struct dhcp_opt *opt)
|
||||
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;
|
||||
|
||||
out:
|
||||
*lease = NULL;
|
||||
return 0;
|
||||
return readfile(file, data, len);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -136,6 +136,11 @@ void dhcp_envoption(struct dhcpcd_ctx *,
|
||||
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
|
||||
|
100
src/dhcp.c
100
src/dhcp.c
@ -28,7 +28,6 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
@ -1142,31 +1141,16 @@ toobig:
|
||||
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;
|
||||
@ -1177,37 +1161,26 @@ read_lease(struct interface *ifp, struct bootp **bootp)
|
||||
*bootp = NULL;
|
||||
|
||||
if (state->leasefile[0] == '\0') {
|
||||
fd = fileno(stdin);
|
||||
fd_opened = false;
|
||||
} else {
|
||||
fd = open(state->leasefile, O_RDONLY);
|
||||
fd_opened = true;
|
||||
}
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT)
|
||||
logerr("%s: open `%s'",
|
||||
ifp->name, state->leasefile);
|
||||
return 0;
|
||||
}
|
||||
if (state->leasefile[0] == '\0')
|
||||
logdebugx("reading standard input");
|
||||
else
|
||||
bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
|
||||
} 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)
|
||||
bytes = dhcp_readfile(ifp->ctx, state->leasefile,
|
||||
buf.buf, sizeof(buf.buf));
|
||||
}
|
||||
if (bytes == -1) {
|
||||
if (errno != ENOENT)
|
||||
logerr("%s: %s", ifp->name, state->leasefile);
|
||||
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;
|
||||
}
|
||||
@ -1216,20 +1189,19 @@ read_lease(struct interface *ifp, struct bootp **bootp)
|
||||
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)
|
||||
@ -1241,14 +1213,18 @@ read_lease(struct interface *ifp, struct bootp **bootp)
|
||||
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 *
|
||||
@ -1929,7 +1905,7 @@ dhcp_expire1(struct interface *ifp)
|
||||
|
||||
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);
|
||||
@ -2072,7 +2048,7 @@ dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia)
|
||||
|
||||
/* 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
|
||||
@ -2299,9 +2275,13 @@ dhcp_bind(struct interface *ifp)
|
||||
}
|
||||
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. */
|
||||
@ -2749,7 +2729,7 @@ dhcp_drop(struct interface *ifp, const char *reason)
|
||||
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)
|
||||
@ -3114,7 +3094,7 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
|
||||
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 */
|
||||
@ -3788,7 +3768,7 @@ dhcp_init(struct interface *ifp)
|
||||
/* 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;
|
||||
@ -3862,7 +3842,6 @@ dhcp_start1(void *arg)
|
||||
struct dhcpcd_ctx *ctx = ifp->ctx;
|
||||
struct if_options *ifo = ifp->options;
|
||||
struct dhcp_state *state;
|
||||
struct stat st;
|
||||
uint32_t l;
|
||||
int nolease;
|
||||
|
||||
@ -3947,6 +3926,7 @@ dhcp_start1(void *arg)
|
||||
}
|
||||
if (state->offer) {
|
||||
struct ipv4_addr *ia;
|
||||
time_t mtime;
|
||||
|
||||
get_lease(ifp, &state->lease, state->offer, state->offer_len);
|
||||
state->lease.frominfo = 1;
|
||||
@ -3974,14 +3954,14 @@ dhcp_start1(void *arg)
|
||||
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);
|
||||
@ -4006,7 +3986,7 @@ dhcp_start1(void *arg)
|
||||
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;
|
||||
|
134
src/dhcp6.c
134
src/dhcp6.c
@ -26,7 +26,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
@ -258,9 +257,8 @@ static size_t
|
||||
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;
|
||||
@ -274,11 +272,8 @@ dhcp6_makevendor(void *data, const struct interface *ifp)
|
||||
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) {
|
||||
@ -1748,7 +1743,7 @@ dhcp6_fail(struct interface *ifp)
|
||||
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)) {
|
||||
@ -2590,106 +2585,77 @@ dhcp6_validatelease(struct interface *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 (ifp->ctx->options & DHCPCD_DUMPLEASE || read_stdin)
|
||||
return 0;
|
||||
|
||||
if (state->new_len == 0) {
|
||||
retval = 0;
|
||||
if (bytes == -1)
|
||||
goto ex;
|
||||
|
||||
if (ifp->ctx->options & DHCPCD_DUMPLEASE || state->leasefile[0] == '\0')
|
||||
goto out;
|
||||
|
||||
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)
|
||||
@ -2705,22 +2671,32 @@ auth:
|
||||
}
|
||||
#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;
|
||||
|
||||
@ -3259,9 +3235,13 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
|
||||
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
|
||||
@ -3688,7 +3668,7 @@ dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, struct ipv6_addr *ia)
|
||||
* 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;
|
||||
@ -3725,7 +3705,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
|
||||
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),
|
||||
@ -4044,7 +4024,7 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
|
||||
dhcp6_startrelease(ifp);
|
||||
return;
|
||||
}
|
||||
unlink(state->leasefile);
|
||||
dhcp_unlink(ifp->ctx, state->leasefile);
|
||||
}
|
||||
dhcp6_freedrop_addrs(ifp, drop, NULL);
|
||||
free(state->old);
|
||||
|
@ -33,4 +33,4 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
const char * const dhcpcd_embedded_conf[] = {
|
||||
const char dhcpcd_embedded_conf[] =
|
||||
|
@ -35,4 +35,4 @@
|
||||
#define INITDEFINE6S @INITDEFINE6S@
|
||||
#endif
|
||||
|
||||
extern const char * const dhcpcd_embedded_conf[];
|
||||
extern const char dhcpcd_embedded_conf[];
|
||||
|
51
src/dhcpcd.c
51
src/dhcpcd.c
@ -357,8 +357,17 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
|
||||
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
|
||||
}
|
||||
|
||||
@ -825,12 +834,27 @@ warn_iaid_conflict(struct interface *ifp, uint16_t ia_type, uint8_t *iaid)
|
||||
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) {
|
||||
@ -863,26 +887,21 @@ dhcpcd_startinterface(void *arg)
|
||||
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];
|
||||
@ -2251,8 +2270,16 @@ printpidfile:
|
||||
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:
|
||||
|
@ -125,6 +125,7 @@ struct passwd;
|
||||
|
||||
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;
|
||||
|
53
src/duid.c
53
src/duid.c
@ -149,20 +149,18 @@ duid_make(void *d, const struct interface *ifp, uint16_t type)
|
||||
|
||||
#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);
|
||||
@ -176,13 +174,18 @@ duid_get(uint8_t **d, const struct interface *ifp)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
@ -202,27 +205,25 @@ duid_get(uint8_t **d, const struct interface *ifp)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -35,6 +35,6 @@
|
||||
#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
|
||||
|
@ -13,7 +13,7 @@ $TOOL_SED \
|
||||
-e 's/#.*$//' \
|
||||
-e '/^$/d' \
|
||||
-e 's/^/"/g' \
|
||||
-e 's/$/\",/g' \
|
||||
-e 's/$/\\n\"/g' \
|
||||
-e 's/ [ ]*/ /g' \
|
||||
-e 's/ [ ]*/ /g' \
|
||||
$CONF_SMALL
|
||||
@ -22,9 +22,9 @@ $TOOL_SED \
|
||||
-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";'
|
||||
|
10
src/if-bsd.c
10
src/if-bsd.c
@ -1555,7 +1555,7 @@ if_handlelink(struct dhcpcd_ctx *ctx)
|
||||
}
|
||||
|
||||
#ifndef SYS_NMLN /* OSX */
|
||||
# define SYS_NMLN 256
|
||||
# define SYS_NMLN __SYS_NAMELEN
|
||||
#endif
|
||||
#ifndef HW_MACHINE_ARCH
|
||||
# ifdef HW_MODEL /* OpenBSD */
|
||||
@ -1566,14 +1566,8 @@ int
|
||||
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
|
||||
|
@ -211,7 +211,7 @@ if_machinearch(char *str, size_t len)
|
||||
fscanf(fp, "%255s", buf) == 1)
|
||||
{
|
||||
fclose(fp);
|
||||
return snprintf(str, len, ":%s", buf);
|
||||
return snprintf(str, len, "%s", buf);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
128
src/if-options.c
128
src/if-options.c
@ -27,7 +27,6 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
@ -2265,25 +2264,31 @@ finish_config(struct if_options *ifo)
|
||||
* 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 */
|
||||
@ -2334,16 +2339,11 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
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;
|
||||
@ -2366,12 +2366,9 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
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;
|
||||
@ -2407,38 +2404,26 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
|
||||
/* 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))) {
|
||||
#else
|
||||
buflen = 80;
|
||||
buf = malloc(buflen);
|
||||
if (buf == NULL) {
|
||||
logerr(__func__);
|
||||
free_options(ctx, ifo);
|
||||
return NULL;
|
||||
buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
|
||||
if (buflen == -1) {
|
||||
logerr("%s: %s", __func__, EMBEDDED_CONFIG);
|
||||
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;
|
||||
if (buf[buflen] != '\0') {
|
||||
if (buflen < sizeof(buf) - 1)
|
||||
bulen++;
|
||||
buf[buflen] = '\0';
|
||||
}
|
||||
#else
|
||||
buflen = strlcpy(buf, dhcpcd_embedded_conf, sizeof(buf));
|
||||
if ((size_t)buflen >= sizeof(buf)) {
|
||||
logerrx("%s: embedded config too big", __func__);
|
||||
return ifo;
|
||||
}
|
||||
/* 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);
|
||||
@ -2452,13 +2437,8 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
}
|
||||
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;
|
||||
@ -2503,26 +2483,25 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@ -2596,10 +2575,9 @@ read_config(struct dhcpcd_ctx *ctx,
|
||||
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);
|
||||
|
@ -120,6 +120,7 @@
|
||||
#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)
|
||||
|
||||
|
2
src/if.h
2
src/if.h
@ -95,6 +95,8 @@ typedef unsigned long ioctl_request_t;
|
||||
#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
|
||||
|
40
src/ipv6.c
40
src/ipv6.c
@ -147,18 +147,17 @@ ipv6_init(struct dhcpcd_ctx *ctx)
|
||||
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.
|
||||
@ -178,27 +177,18 @@ ipv6_readsecret(struct dhcpcd_ctx *ctx)
|
||||
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
|
||||
|
@ -104,7 +104,6 @@ logprintdate(FILE *stream)
|
||||
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)
|
||||
@ -366,6 +365,9 @@ logopen(const char *path)
|
||||
{
|
||||
struct logctx *ctx = &_logctx;
|
||||
|
||||
/* Cache timezone */
|
||||
tzset();
|
||||
|
||||
if (path == NULL) {
|
||||
int opts = 0;
|
||||
|
||||
|
@ -91,7 +91,7 @@ ps_bpf_recvbpf(void *arg)
|
||||
|
||||
#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;
|
||||
@ -197,7 +197,7 @@ ps_bpf_signal_bpfcb(int sig, void *arg)
|
||||
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;
|
||||
@ -205,7 +205,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
|
||||
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
|
||||
@ -261,7 +261,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
|
||||
* 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
|
||||
@ -321,7 +321,7 @@ ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -114,7 +114,7 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@ -126,7 +126,7 @@ ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint8_t domain, unsigned long request,
|
||||
|
||||
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);
|
||||
|
@ -498,12 +498,12 @@ ssize_t
|
||||
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
|
||||
@ -570,7 +570,7 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
|
||||
|
||||
#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;
|
||||
@ -614,7 +614,7 @@ ps_inet_sendbootp(struct ipv4_addr *ia, const struct msghdr *msg)
|
||||
#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 = {
|
||||
@ -659,7 +659,7 @@ ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
|
||||
|
||||
#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 = {
|
||||
|
@ -217,124 +217,35 @@ ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
|
||||
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;
|
||||
char *file = data, *nc;
|
||||
|
||||
if (len < sizeof(plen)) {
|
||||
nc = memchr(file, '\0', len);
|
||||
if (nc == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&plen, path, sizeof(plen));
|
||||
path += sizeof(plen);
|
||||
if (sizeof(plen) + plen > len) {
|
||||
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
|
||||
@ -388,20 +299,40 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
|
||||
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. */
|
||||
@ -428,6 +359,7 @@ ps_root_startcb(void *arg)
|
||||
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
|
||||
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
|
||||
ctx->ps_root_pid = getpid();
|
||||
ctx->options |= DHCPCD_PRIVSEPROOT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -574,38 +506,53 @@ ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
|
||||
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_copychroot(struct dhcpcd_ctx *ctx, const char *path)
|
||||
ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
|
||||
void *data, size_t len)
|
||||
{
|
||||
|
||||
return ps_root_fileop(ctx, path, PS_COPY);
|
||||
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_unlink(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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
@ -35,10 +35,12 @@ pid_t ps_root_start(struct dhcpcd_ctx *ctx);
|
||||
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);
|
||||
|
@ -77,31 +77,9 @@
|
||||
#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;
|
||||
@ -120,9 +98,7 @@ ps_init(struct dhcpcd_ctx *ctx)
|
||||
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);
|
||||
@ -130,17 +106,6 @@ ps_init(struct dhcpcd_ctx *ctx)
|
||||
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;
|
||||
}
|
||||
@ -152,7 +117,6 @@ ps_dropprivs(struct dhcpcd_ctx *ctx, unsigned int flags)
|
||||
|
||||
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)
|
||||
@ -184,9 +148,8 @@ ps_dropprivs(struct dhcpcd_ctx *ctx, unsigned int flags)
|
||||
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;
|
||||
@ -568,7 +531,7 @@ ps_sendpsmdata(struct dhcpcd_ctx *ctx, int fd,
|
||||
|
||||
|
||||
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);
|
||||
@ -610,7 +573,7 @@ ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
|
||||
}
|
||||
|
||||
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 = {
|
||||
@ -628,7 +591,7 @@ ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
|
||||
}
|
||||
|
||||
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;
|
||||
@ -671,7 +634,7 @@ nobufs:
|
||||
}
|
||||
|
||||
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 };
|
||||
|
@ -36,32 +36,36 @@
|
||||
#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
|
||||
/* 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
|
||||
|
||||
#define PS_IOCTL 0x10
|
||||
#define PS_ROUTE 0x11 /* Also used for NETLINK */
|
||||
#define PS_SCRIPT 0x12
|
||||
#define PS_UNLINK 0x13
|
||||
#define PS_COPY 0x14
|
||||
/* 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) + \
|
||||
@ -96,13 +100,13 @@ struct ps_addr {
|
||||
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;
|
||||
@ -141,7 +145,6 @@ TAILQ_HEAD(ps_process_head, ps_process);
|
||||
#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 *);
|
||||
@ -152,11 +155,11 @@ ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,
|
||||
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 *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user