diff --git a/src/auth.c b/src/auth.c index 85663072..d56326b3 100644 --- a/src/auth.c +++ b/src/auth.c @@ -41,6 +41,7 @@ #include "config.h" #include "auth.h" +#include "common.h" #include "dhcp.h" #include "dhcp6.h" #include "dhcpcd.h" @@ -437,16 +438,17 @@ auth_get_rdm_monotonic(uint64_t *rdm) int flocked; #endif - fp = fopen(RDM_MONOFILE, "r+"); + ensure_dir(dhcpcd_rdm_monofile, 0750); + fp = fopen(dhcpcd_rdm_monofile, "r+"); if (fp == NULL) { if (errno != ENOENT) return -1; - fp = fopen(RDM_MONOFILE, "w"); + fp = fopen(dhcpcd_rdm_monofile, "w"); if (fp == NULL) return -1; - if (chmod(RDM_MONOFILE, 0400) == -1) { + if (chmod(dhcpcd_rdm_monofile, 0400) == -1) { (void)fclose(fp); - unlink(RDM_MONOFILE); + unlink(dhcpcd_rdm_monofile); return -1; } #ifdef LOCK_EX diff --git a/src/common.c b/src/common.c index d938ef00..0c363f28 100644 --- a/src/common.c +++ b/src/common.c @@ -146,12 +146,96 @@ readfile(const char *file, void **data, size_t *len) return bytes; } +/* Return a copy of s with every '%' doubled so it is safe to use as a + * literal within a printf-style format string. Returns NULL on failure. */ +char * +escape_percent(const char *s) +{ + const char *p; + char *r, *d; + size_t extra = 0; + + if (s == NULL) + s = ""; + for (p = s; *p != '\0'; p++) + if (*p == '%') + extra++; + r = malloc(strlen(s) + extra + 1); + if (r == NULL) + return NULL; + for (p = s, d = r; *p != '\0'; p++) { + if (*p == '%') + *d++ = '%'; + *d++ = *p; + } + *d = '\0'; + return r; +} + +/* Create a directory and any missing parents, like mkdir -p. */ +int +mkdirs(const char *dir, mode_t mode) +{ + char *d, *p; + int r = 0; + + if (dir == NULL || dir[0] == '\0') { + errno = EINVAL; + return -1; + } + d = strdup(dir); + if (d == NULL) + return -1; + for (p = d + 1; *p != '\0'; p++) { + if (*p != '/') + continue; + *p = '\0'; + if (mkdir(d, mode) == -1 && errno != EEXIST) + r = -1; + *p = '/'; + } + if (mkdir(d, mode) == -1 && errno != EEXIST) + r = -1; + free(d); + return r; +} + +/* Ensure the directory part of a file path exists. */ +int +ensure_dir(const char *file, mode_t mode) +{ + char *d, *p; + int r; + + if (file == NULL) { + errno = EINVAL; + return -1; + } + d = strdup(file); + if (d == NULL) + return -1; + p = strrchr(d, '/'); + if (p == NULL) { + free(d); + return 0; + } + if (p == d) + *(p + 1) = '\0'; + else + *p = '\0'; + r = mkdirs(d, mode); + free(d); + return r; +} + ssize_t writefile(const char *file, mode_t mode, const void *data, size_t len) { int fd; ssize_t bytes; + if (ensure_dir(file, 0750) == -1) + return -1; fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd == -1) return -1; diff --git a/src/common.h b/src/common.h index 577afc4d..29df45e2 100644 --- a/src/common.h +++ b/src/common.h @@ -169,6 +169,9 @@ const char *hwaddr_ntoa(const void *, size_t, char *, size_t); size_t 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); +char *escape_percent(const char *); +int mkdirs(const char *, mode_t); +int ensure_dir(const char *, mode_t); int filemtime(const char *, time_t *); char *get_line(char **__restrict, size_t *__restrict); int is_root_local(void); diff --git a/src/control.c b/src/control.c index 9164b7ab..6f883538 100644 --- a/src/control.c +++ b/src/control.c @@ -491,7 +491,7 @@ make_path(char *path, size_t len, const char *ifname, sa_family_t family) per = ""; break; } - return snprintf(path, len, CONTROLSOCKET, ifname ? ifname : "", + return snprintf(path, len, dhcpcd_controlsock, ifname ? ifname : "", ifname ? per : "", "", ifname ? "." : ""); } @@ -521,6 +521,8 @@ control_start1(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family) if (fd == -1) return -1; + ensure_dir(sa.sun_path, 0755); + len = (socklen_t)SUN_LEN(&sa); if (GID_SET(ctx->control_group) && GID_SET(ctx->read_group)) { if (ctx->control_group == ctx->read_group) { diff --git a/src/defs.h b/src/defs.h index fe8c51c4..4c4a7ad8 100644 --- a/src/defs.h +++ b/src/defs.h @@ -66,6 +66,32 @@ #define RDM_MONOFILE DBDIR "/rdm_monotonic" #endif +/* + * Runtime configurable paths. + * These default to the compiled in values but can be overridden at runtime + * with the corresponding command line options (--instance, --dbdir, --rundir, + * --devdir). The individual file paths are derived from these and rebuilt + * whenever a base directory is changed (see dhcpcd_paths_update()). + */ +extern const char *dhcpcd_dbdir; +extern const char *dhcpcd_rundir; +extern const char *dhcpcd_devdir; +extern const char *dhcpcd_instance; +extern const char *dhcpcd_duidfile; +extern const char *dhcpcd_secretfile; +extern const char *dhcpcd_rdm_monofile; +extern const char *dhcpcd_leasefile; +extern const char *dhcpcd_leasefile6; +extern const char *dhcpcd_pidfile; +extern const char *dhcpcd_controlsock; + +void dhcpcd_paths_init(void); +void dhcpcd_paths_update(void); +void dhcpcd_paths_set_dbdir(const char *); +void dhcpcd_paths_set_rundir(const char *); +void dhcpcd_paths_set_devdir(const char *); +void dhcpcd_paths_set_instance(const char *); + #ifndef NO_SIGNALS #define USE_SIGNALS #endif diff --git a/src/dev.c b/src/dev.c index bada148c..45d9ce16 100644 --- a/src/dev.c +++ b/src/dev.c @@ -99,7 +99,7 @@ dev_start2(struct dhcpcd_ctx *ctx, const struct dev_dhcpcd *dev_dhcpcd, void (*fptr)(struct dev *, const struct dev_dhcpcd *); int r; - snprintf(file, sizeof(file), DEVDIR "/%s", name); + snprintf(file, sizeof(file), "%s/%s", dhcpcd_devdir, name); h = dlopen(file, RTLD_LAZY); if (h == NULL) { logerrx("dlopen: %s", dlerror()); @@ -143,9 +143,9 @@ dev_start1(struct dhcpcd_ctx *ctx, const struct dev_dhcpcd *dev_dhcpcd) if (ctx->dev_load) return dev_start2(ctx, dev_dhcpcd, ctx->dev_load); - dp = opendir(DEVDIR); + dp = opendir(dhcpcd_devdir); if (dp == NULL) { - logdebug("dev: %s", DEVDIR); + logdebug("dev: %s", dhcpcd_devdir); return -1; } diff --git a/src/dhcp-common.c b/src/dhcp-common.c index e87094de..5b10a67c 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -1041,7 +1041,8 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family, } else ssid[0] = '\0'; return snprintf(leasefile, len, - family == AF_INET ? LEASEFILE : LEASEFILE6, ifname, ssid); + family == AF_INET ? dhcpcd_leasefile : dhcpcd_leasefile6, ifname, + ssid); } void diff --git a/src/dhcpcd.8.in b/src/dhcpcd.8.in index 26d37772..9707ef28 100644 --- a/src/dhcpcd.8.in +++ b/src/dhcpcd.8.in @@ -61,6 +61,10 @@ .Op Fl Z , Fl Fl denyinterfaces Ar pattern .Op Fl z , Fl Fl allowinterfaces Ar pattern .Op Fl Fl inactive +.Op Fl Fl instance Ar instance +.Op Fl Fl dbdir Ar dir +.Op Fl Fl rundir Ar dir +.Op Fl Fl devdir Ar dir .Op Fl Fl configure .Op Fl Fl noconfigure .Op interface @@ -271,9 +275,9 @@ Use a DHCP Unique Identifier. If persistent storage is available then a DUID-LLT (link local address + time) is generated, otherwise DUID-LL is generated (link local address). -The DUID type can be hinted as an optional parameter if the file -.Pa @DBDIR@/duid -does not exist. + The DUID type can be hinted as an optional parameter if the default DUID file + .Pa @DBDIR@/duid + does not exist. If not .Va ll , .Va lt @@ -284,9 +288,9 @@ then will be converted from 00:11:22:33 format. This, plus the IAID will be used as the .Fl I , Fl Fl clientid . -The DUID generated will be held in -.Pa @DBDIR@/duid -and should not be copied to other hosts. + The DUID generated will be held in the default DUID file + .Pa @DBDIR@/duid + and should not be copied to other hosts. This file also takes precedence over the above rules except for setting a value. .It Fl d , Fl Fl debug Echo debug messages to the stderr and syslog. @@ -778,6 +782,51 @@ addition of Don't load any .Pa /dev management modules. +.It Fl Fl instance Ar instance +Prefix the state and runtime files that +.Nm +writes, namely the DUID, secret, lease, RDM, PID and control socket files, +with the +.Ar instance +name inside the state and runtime directories. +.Ar instance +must be a single path component and must not contain a +.Sq / . +For example, +.Fl Fl instance=foo +will cause the DUID file to be written to +.Pa @DBDIR@/ Ns Pa foo Ns .duid +and the PID file to +.Pa @RUNDIR@/ Ns Pa foo Ns .pid . +The base directories remain unchanged. +.It Fl Fl dbdir Ar dir +Specify the base directory where +.Nm +stores its lease and state database. +This overrides the compiled in default +.Pa @DBDIR@ . +Without +.Fl Fl instance +the DUID, secret, lease and RDM files are created directly here, otherwise +they are created here under the file name prefixed with the instance name. +.It Fl Fl rundir Ar dir +Specify the base directory where +.Nm +stores its runtime files, such as the PID file and control socket. +This overrides the compiled in default +.Pa @RUNDIR@ . +Without +.Fl Fl instance +the PID file and control socket are created directly here, otherwise they +are created here under the file name prefixed with the instance name. +.It Fl Fl devdir Ar dir +Specify the directory from which +.Nm +loads +.Pa /dev +management modules. +This overrides the compiled in default +.Pa @LIBDIR@/dhcpcd/dev . .El .Sh 3RDPARTY LINK MANAGEMENT Some interfaces require configuration by 3rd parties, such as PPP or VPN. @@ -818,6 +867,18 @@ sends to match. If using a DUID in place of the ClientID, edit .Pa @DBDIR@/duid accordingly. +.Pp +The file paths shown in this manual, such as +.Pa @DBDIR@/duid , +are the compiled in defaults. +The effective path used by +.Nm +can be changed with the +.Fl Fl dbdir , +.Fl Fl rundir +and +.Fl Fl instance +options described above. .Sh FILES .Bl -ohang .It Pa @SYSCONFDIR@/dhcpcd.conf diff --git a/src/dhcpcd.c b/src/dhcpcd.c index bf277bbc..500df63b 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -101,6 +101,179 @@ const size_t dhcpcd_signals_ignore_len = __arraycount(dhcpcd_signals_ignore); const char *dhcpcd_default_script = SCRIPT; +/* + * Runtime configurable paths. + * The base directories (dbdir, rundir, devdir) default to the compiled in + * values but may be overridden on the command line. When dhcpcd_instance is + * set, all files dhcpcd writes (lease, DUID, secret, RDM, PID and control + * socket files) are placed under the instance directory and named after the + * state or runtime directory. The file paths are derived from the base + * directories by dhcpcd_paths_update(). + */ +const char *dhcpcd_dbdir; +const char *dhcpcd_rundir; +const char *dhcpcd_devdir; +const char *dhcpcd_instance; +const char *dhcpcd_duidfile; +const char *dhcpcd_secretfile; +const char *dhcpcd_rdm_monofile; +const char *dhcpcd_leasefile; +const char *dhcpcd_leasefile6; +const char *dhcpcd_pidfile; +const char *dhcpcd_controlsock; + +/* Initialise the runtime paths to the compiled in defaults and derive the + * file paths. Must be called before any other dhcpcd_paths_* function. */ +void +dhcpcd_paths_init(void) +{ + dhcpcd_dbdir = strdup(DBDIR); + dhcpcd_rundir = strdup(RUNDIR); + dhcpcd_devdir = strdup(DEVDIR); + if (dhcpcd_dbdir == NULL || dhcpcd_rundir == NULL || + dhcpcd_devdir == NULL) { + logerrx("out of memory"); + exit(EXIT_FAILURE); + } + dhcpcd_paths_update(); +} + +/* Replace *var with a copy of value, freeing the previous string. */ +static void +path_set_str(const char **var, const char *value) +{ + free(UNCONST(*var)); + *var = strdup(value); + if (*var == NULL) { + logerrx("out of memory"); + exit(EXIT_FAILURE); + } +} + +/* Set the state/lease database directory and rebuild the derived paths. */ +void +dhcpcd_paths_set_dbdir(const char *dir) +{ + path_set_str(&dhcpcd_dbdir, dir); + dhcpcd_paths_update(); +} + +/* Set the runtime directory and rebuild the derived paths. */ +void +dhcpcd_paths_set_rundir(const char *dir) +{ + path_set_str(&dhcpcd_rundir, dir); + dhcpcd_paths_update(); +} + +/* Set the directory from which /dev management modules are loaded. */ +void +dhcpcd_paths_set_devdir(const char *dir) +{ + path_set_str(&dhcpcd_devdir, dir); +} + +/* Set the instance directory and rebuild the derived paths. The instance + * must be a single path component without '/'. */ +void +dhcpcd_paths_set_instance(const char *instance) +{ + if (strchr(instance, '/') != NULL) { + logerrx("--instance must not contain a '/': %s", instance); + exit(EXIT_FAILURE); + } + path_set_str(&dhcpcd_instance, instance); + dhcpcd_paths_update(); +} + +/* Rebuild all derived file paths from the current base directories and + * instance. The lease, lease6, PID and control socket paths are returned + * as printf-style format strings. */ +void +dhcpcd_paths_update(void) +{ + char *duidfile = NULL, *secretfile = NULL, *rdm_monofile = NULL; + char *leasefile = NULL, *leasefile6 = NULL, *pidfile = NULL; + char *controlsock = NULL; + char *einstance, *edbdir, *erundir; + + free(UNCONST(dhcpcd_duidfile)); + free(UNCONST(dhcpcd_secretfile)); + free(UNCONST(dhcpcd_rdm_monofile)); + free(UNCONST(dhcpcd_leasefile)); + free(UNCONST(dhcpcd_leasefile6)); + free(UNCONST(dhcpcd_pidfile)); + free(UNCONST(dhcpcd_controlsock)); + + /* lease, lease6, pid and controlsock are later used as printf-style + * format strings, so escape '%' in the configured directories. */ + einstance = escape_percent(dhcpcd_instance); + edbdir = escape_percent(dhcpcd_dbdir); + erundir = escape_percent(dhcpcd_rundir); + if (einstance == NULL || edbdir == NULL || erundir == NULL) + goto oom; + + if (dhcpcd_instance != NULL && dhcpcd_instance[0] != '\0') { + /* + * The instance name is used as a file name base inside the + * state and runtime directories, e.g. /.duid. + */ + if (asprintf(&duidfile, "%s/%s.duid", dhcpcd_dbdir, + dhcpcd_instance) == -1 || + asprintf(&secretfile, "%s/%s.secret", dhcpcd_dbdir, + dhcpcd_instance) == -1 || + asprintf(&rdm_monofile, "%s/%s.rdm_monotonic", dhcpcd_dbdir, + dhcpcd_instance) == -1 || + asprintf(&leasefile, "%s/%s.%%s%%s.lease", edbdir, + einstance) == -1 || + asprintf(&leasefile6, "%s/%s.%%s%%s.lease6", edbdir, + einstance) == -1 || + asprintf(&pidfile, "%s/%s.%%s%%s%%spid", erundir, + einstance) == -1 || + asprintf(&controlsock, "%s/%s.%%s%%s%%s%%ssock", erundir, + einstance) == -1) + goto oom; + } else { + if (asprintf(&duidfile, "%s/duid", dhcpcd_dbdir) == -1 || + asprintf(&secretfile, "%s/secret", dhcpcd_dbdir) == -1 || + asprintf(&rdm_monofile, "%s/rdm_monotonic", dhcpcd_dbdir) == + -1 || + asprintf(&leasefile, "%s/%%s%%s.lease", edbdir) == -1 || + asprintf(&leasefile6, "%s/%%s%%s.lease6", edbdir) == -1 || + asprintf(&pidfile, "%s/%%s%%s%%spid", erundir) == -1 || + asprintf(&controlsock, "%s/%%s%%s%%s%%ssock", erundir) == + -1) + goto oom; + } + + free(einstance); + free(edbdir); + free(erundir); + + dhcpcd_duidfile = duidfile; + dhcpcd_secretfile = secretfile; + dhcpcd_rdm_monofile = rdm_monofile; + dhcpcd_leasefile = leasefile; + dhcpcd_leasefile6 = leasefile6; + dhcpcd_pidfile = pidfile; + dhcpcd_controlsock = controlsock; + return; + +oom: + free(duidfile); + free(secretfile); + free(rdm_monofile); + free(leasefile); + free(leasefile6); + free(pidfile); + free(controlsock); + free(einstance); + free(edbdir); + free(erundir); + logerrx("out of memory"); + exit(EXIT_FAILURE); +} + static void usage(void) { @@ -119,7 +292,8 @@ usage(void) "\t\t[-v, --vendor code, value] [-W, --whitelist address[/cidr]] [-w]\n" "\t\t[--waitip [4 | 6]] [-y, --reboot seconds]\n" "\t\t[-X, --blacklist address[/cidr]] [-Z, --denyinterfaces pattern]\n" - "\t\t[-z, --allowinterfaces pattern] [--inactive] [interface] [...]\n" + "\t\t[-z, --allowinterfaces pattern] [--inactive] [--instance instance]\n" + "\t\t[--dbdir dir] [--rundir dir] [--devdir dir] [interface] [...]\n" " " PACKAGE "\t-n, --rebind [interface]\n" " " PACKAGE "\t-k, --release [interface]\n" " " PACKAGE "\t-U, --dumplease interface\n" @@ -2138,6 +2312,7 @@ main(int argc, char **argv, char **envp) memset(&ctx, 0, sizeof(ctx)); closefrom(STDERR_FILENO + 1); + dhcpcd_paths_init(); ifo = NULL; ctx.cffile = CONFIG; @@ -2247,6 +2422,18 @@ main(int argc, char **argv, char **envp) case 'V': i = 2; break; + case O_DBDIR: + dhcpcd_paths_set_dbdir(optarg); + break; + case O_RUNDIR: + dhcpcd_paths_set_rundir(optarg); + break; + case O_DEVDIR: + dhcpcd_paths_set_devdir(optarg); + break; + case O_INSTANCE: + dhcpcd_paths_set_instance(optarg); + break; case '?': if (ctx.options & DHCPCD_PRINT_PIDFILE) continue; @@ -2354,13 +2541,14 @@ main(int argc, char **argv, char **envp) default: per = ""; } - if (asprintf(&ctx.pidfile, PIDFILE, ifname, per, ".") == - -1) { + if (asprintf(&ctx.pidfile, dhcpcd_pidfile, ifname, per, + ".") == -1) { logerr("%s: asprintf", __func__); goto exit_failure; } } else { - if (asprintf(&ctx.pidfile, PIDFILE, "", "", "") == -1) { + if (asprintf(&ctx.pidfile, dhcpcd_pidfile, "", "", + "") == -1) { logerr("%s: asprintf", __func__); goto exit_failure; } @@ -2539,10 +2727,7 @@ main(int argc, char **argv, char **envp) if (!(ctx.options & DHCPCD_TEST)) { /* Ensure we have the needed directories */ - if (mkdir(DBDIR, 0750) == -1 && errno != EEXIST) - logerr("%s: mkdir: %s", __func__, DBDIR); - if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST) - logerr("%s: mkdir: %s", __func__, RUNDIR); + ensure_dir(ctx.pidfile, 0755); if ((pid = pidfile_lock(ctx.pidfile)) != 0) { if (pid == -1) logerr("%s: pidfile_lock: %s", __func__, @@ -2648,6 +2833,7 @@ main(int argc, char **argv, char **envp) start_manager: ctx.options |= DHCPCD_STARTED; + ensure_dir(ctx.pidfile, 0755); if ((pid = pidfile_lock(ctx.pidfile)) != 0) { logerr("%s: pidfile_lock %d", __func__, (int)pid); #ifdef PRIVSEP diff --git a/src/duid.c b/src/duid.c index d3cba7e6..95b437d5 100644 --- a/src/duid.c +++ b/src/duid.c @@ -163,16 +163,16 @@ duid_get(struct dhcpcd_ctx *ctx, const struct interface *ifp) /* 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 = dhcp_read_hwaddr_aton(ctx, &data, DUID)) != 0) { + if ((len = dhcp_read_hwaddr_aton(ctx, &data, dhcpcd_duidfile)) != 0) { if (len <= DUID_LEN) { ctx->duid = data; return len; } - logerrx("DUID too big (max %u): %s", DUID_LEN, DUID); + logerrx("DUID too big (max %u): %s", DUID_LEN, dhcpcd_duidfile); /* Keep the buffer, will assign below. */ } else { if (errno != ENOENT) - logerr("%s", DUID); + logerr("%s", dhcpcd_duidfile); if ((data = malloc(DUID_LEN)) == NULL) { logerr(__func__); return 0; @@ -228,7 +228,7 @@ duid_get(struct dhcpcd_ctx *ctx, const struct interface *ifp) line[slen++] = '\n'; line[slen] = '\0'; } - if (dhcp_writefile(ctx, DUID, 0640, line, slen) == -1) { + if (dhcp_writefile(ctx, dhcpcd_duidfile, 0640, line, slen) == -1) { logerr("%s: cannot write duid", __func__); if (ctx->duid_type != DUID_LL) return duid_make(data, ifp, DUID_LL); diff --git a/src/if-options.c b/src/if-options.c index 7b445f45..f50a323f 100644 --- a/src/if-options.c +++ b/src/if-options.c @@ -180,6 +180,10 @@ const struct option cf_options[] = { { "background", no_argument, NULL, 'b' }, { "backoff_cutoff", required_argument, NULL, O_BACKOFF_CUTOFF }, { "backoff_jitter", required_argument, NULL, O_BACKOFF_JITTER }, { "allow", required_argument, NULL, O_ALLOW }, + { "dbdir", required_argument, NULL, O_DBDIR }, + { "rundir", required_argument, NULL, O_RUNDIR }, + { "devdir", required_argument, NULL, O_DEVDIR }, + { "instance", required_argument, NULL, O_INSTANCE }, { NULL, 0, NULL, '\0' } }; static char * @@ -2647,6 +2651,26 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, return -1; } break; + case O_DBDIR: + ARG_REQUIRED; + if (!(ctx->options & DHCPCD_STARTED)) + dhcpcd_paths_set_dbdir(arg); + break; + case O_RUNDIR: + ARG_REQUIRED; + if (!(ctx->options & DHCPCD_STARTED)) + dhcpcd_paths_set_rundir(arg); + break; + case O_DEVDIR: + ARG_REQUIRED; + if (!(ctx->options & DHCPCD_STARTED)) + dhcpcd_paths_set_devdir(arg); + break; + case O_INSTANCE: + ARG_REQUIRED; + if (!(ctx->options & DHCPCD_STARTED)) + dhcpcd_paths_set_instance(arg); + break; default: return 0; } diff --git a/src/if-options.h b/src/if-options.h index 0158b9ae..6823941b 100644 --- a/src/if-options.h +++ b/src/if-options.h @@ -205,6 +205,10 @@ #define O_BACKOFF_JITTER O_BASE + 62 #define O_ALLOW O_BASE + 63 #define O_READGRP O_BASE + 64 +#define O_DBDIR O_BASE + 65 +#define O_RUNDIR O_BASE + 66 +#define O_DEVDIR O_BASE + 67 +#define O_INSTANCE O_BASE + 68 extern const struct option cf_options[]; diff --git a/src/ipv6.c b/src/ipv6.c index 80ee4ad3..d1dd0f5f 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -154,7 +154,8 @@ ipv6_readsecret(struct dhcpcd_ctx *ctx) size_t len; uint32_t r; - ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET); + ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, + dhcpcd_secretfile); if (ctx->secret_len != 0) return (ssize_t)ctx->secret_len; @@ -185,7 +186,7 @@ ipv6_readsecret(struct dhcpcd_ctx *ctx) line[len++] = '\n'; line[len] = '\0'; } - if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) { + if (dhcp_writefile(ctx, dhcpcd_secretfile, S_IRUSR, line, len) == -1) { logerr("%s: cannot write secret", __func__); ctx->secret_len = 0; return -1; diff --git a/src/privsep-root.c b/src/privsep-root.c index 47170c8e..c4c59d95 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -264,12 +264,17 @@ static bool ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path, size_t len) { + size_t dbdirlen, rundirlen; + /* path must be a valid string */ if (memchr(path, '\0', len) == NULL) { errno = EINVAL; return false; } + dbdirlen = strlen(dhcpcd_dbdir); + rundirlen = strlen(dhcpcd_rundir); + /* Avoid a previous directory attack to avoid /proc/../ * dhcpcd should never use a path with double dots. */ if (strstr(path, "..") != NULL) @@ -283,9 +288,11 @@ ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path, if (strcmp(ctx->cffile, path) == 0) return true; } - if (strncmp(DBDIR, path, strlen(DBDIR)) == 0) + if (strncmp(dhcpcd_dbdir, path, dbdirlen) == 0 && + (path[dbdirlen] == '\0' || path[dbdirlen] == '/')) return true; - if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0) + if (strncmp(dhcpcd_rundir, path, rundirlen) == 0 && + (path[rundirlen] == '\0' || path[rundirlen] == '/')) return true; #ifdef __linux__