From: Roy Marples Date: Tue, 21 Jan 2020 20:08:56 +0000 (+0000) Subject: privsep: copy configuration file into chroot X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a4cd387823dc5e122839af9d9463985cb99f383;p=thirdparty%2Fdhcpcd.git privsep: copy configuration file into chroot Only if it has changed. Saves having to maintian it outside of dhcpcdm in a script or something. --- diff --git a/src/if-options.c b/src/if-options.c index 2b4cd1ed..e8fb93f0 100644 --- a/src/if-options.c +++ b/src/if-options.c @@ -2520,6 +2520,11 @@ 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) { /* dhcpcd can continue without it, but no DNS options diff --git a/src/privsep-root.c b/src/privsep-root.c index b6ba8af8..076d71de 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -28,11 +28,15 @@ #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -199,7 +203,94 @@ ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) } static ssize_t -ps_root_dounlink(void *data, size_t len) +ps_root_docopy(const char *dir, 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; +#ifdef BSD + struct timespec ts[2]; +#else + struct timeval ts[2]; +#endif + + if (snprintf(path, sizeof(path), "%s/%s", dir, file) == -1) + return -1; + if (stat(file, &from_sb) == -1) + return -1; + if (stat(path, &to_sb) == 0) { +#ifdef BSD + if (timespeccmp(&from_sb.st_mtimespec, &to_sb.st_mtimespec, ==)) + 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; + } + +#ifdef BSD + 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, ts) == -1) + total = -1; +#endif + close(from_fd); + close(to_fd); + + return total; +} + +static ssize_t +ps_root_docopy1(const char *file) +{ + struct passwd *pw; + + errno = 0; + if ((pw = getpwnam(PRIVSEP_USER)) == NULL) { + if (errno == 0) + errno = ENOENT; + return -1; + } + + return ps_root_docopy(pw->pw_dir, file); +} + +static ssize_t +ps_root_dofileop(void *data, size_t len, uint8_t op) { char *path = data; size_t plen; @@ -216,7 +307,15 @@ ps_root_dounlink(void *data, size_t len) return -1; } - return (ssize_t)unlink(path); + switch(op) { + case PS_COPY: + return ps_root_docopy1(path); + case PS_UNLINK: + return (ssize_t)unlink(path); + default: + errno = ENOTSUP; + return -1; + } } static ssize_t @@ -288,8 +387,9 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) case PS_SCRIPT: err = ps_root_run_script(ctx, data, len); break; + case PS_COPY: /* FALLTHROUGH */ case PS_UNLINK: - err = ps_root_dounlink(data, len); + err = ps_root_dofileop(data, len, psm->ps_cmd); break; default: err = ps_root_os(psm, msg); @@ -461,8 +561,8 @@ ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, return ps_root_readerror(ctx); } -ssize_t -ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path) +static ssize_t +ps_root_fileop(struct dhcpcd_ctx *ctx, const char *path, uint8_t op) { char buf[PATH_MAX], *p = buf; size_t plen = strlen(path) + 1; @@ -477,7 +577,22 @@ ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path) p += sizeof(plen); memcpy(p, path, plen); - if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, buf, len) == -1) + if (ps_sendcmd(ctx, ctx->ps_root_fd, op, 0, buf, len) == -1) return -1; return ps_root_readerror(ctx); } + + +ssize_t +ps_root_copychroot(struct dhcpcd_ctx *ctx, const char *path) +{ + + return ps_root_fileop(ctx, path, PS_COPY); +} + +ssize_t +ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path) +{ + + return ps_root_fileop(ctx, path, PS_UNLINK); +} diff --git a/src/privsep-root.h b/src/privsep-root.h index b4966bc9..d7f3148a 100644 --- a/src/privsep-root.h +++ b/src/privsep-root.h @@ -35,6 +35,7 @@ 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 *); +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 *); ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *); diff --git a/src/privsep.c b/src/privsep.c index e9ec25f2..ffd32de0 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -36,6 +36,7 @@ */ #include +#include #include #include @@ -68,10 +69,32 @@ #include #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) { struct passwd *pw; + char path[PATH_MAX]; errno = 0; if ((pw = getpwnam(PRIVSEP_USER)) == NULL) { @@ -85,6 +108,13 @@ ps_init(struct dhcpcd_ctx *ctx) return -1; } + /* Create the database directory. */ + if (snprintf(path, sizeof(path), "%s%s", pw->pw_dir, DBDIR) == -1 || + ps_mkdir(path) == -1 || + chown(path, pw->pw_uid, pw->pw_gid) == -1 || + chmod(path, 0755) == -1) + logerr("%s: %s", __func__, path); + ctx->options |= DHCPCD_PRIVSEP; return 0; } diff --git a/src/privsep.h b/src/privsep.h index babcb37c..8372c0e5 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -46,13 +46,14 @@ #define PS_ROUTE 0x11 /* Also used for NETLINK */ #define PS_SCRIPT 0x12 #define PS_UNLINK 0x13 +#define PS_COPY 0x14 /* BSD Commands */ -#define PS_IOCTLLINK 0x14 -#define PS_IOCTL6 0x15 +#define PS_IOCTLLINK 0x15 +#define PS_IOCTL6 0x16 /* Linux commands */ -#define PS_WRITEPATHUINT 0x16 +#define PS_WRITEPATHUINT 0x17 #define PS_DELETE 0x20 #define PS_START 0x40 @@ -136,6 +137,7 @@ 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 *); int ps_start(struct dhcpcd_ctx *);