return 0;
}
+static int
+if_sysctl(struct dhcpcd_ctx *ctx,
+ const int *name, u_int namelen,
+ void *oldp, size_t *oldlenp, const void *newp, size_t newlen)
+{
+#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
+ if (IN_PRIVSEP(ctx))
+ return (int)ps_root_sysctl(ctx, name, namelen,
+ oldp, oldlenp, newp, newlen);
+#endif
+
+ return sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+}
+
int
if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
{
struct rt_msghdr *rtm;
int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 };
- size_t needed;
+ size_t bufl;
char *buf, *p, *end;
struct rt rt, *rtn;
- if (sysctl(mib, __arraycount(mib), NULL, &needed, NULL, 0) == -1)
+ if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1)
return -1;
- if (needed == 0)
+ if (bufl == 0)
return 0;
- if ((buf = malloc(needed)) == NULL)
+ if ((buf = malloc(bufl)) == NULL)
return -1;
- if (sysctl(mib, __arraycount(mib), buf, &needed, NULL, 0) == -1) {
+ if (if_sysctl(ctx, mib, __arraycount(mib), buf, &bufl, NULL, 0) == -1)
+ {
free(buf);
return -1;
}
- end = buf + needed;
+ end = buf + bufl;
for (p = buf; p < end; p += rtm->rtm_msglen) {
rtm = (void *)p;
if (p + sizeof(*rtm) > end || p + rtm->rtm_msglen > end) {
*/
#include <sys/ioctl.h>
+#include <sys/sysctl.h>
/* Need these for filtering the ioctls */
#include <arpa/inet.h>
#endif
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
}
#endif
+#ifdef HAVE_CAPSICUM
+static ssize_t
+ps_root_dosysctl(unsigned long flags,
+ void *data, size_t len, void **rdata, size_t *rlen)
+{
+ char *p = data, *e = p + len;
+ int name[10];
+ unsigned int namelen;
+ void *oldp;
+ size_t *oldlenp, oldlen, nlen;
+ void *newp;
+ size_t newlen;
+ int err;
+
+ if (sizeof(namelen) >= len) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(&namelen, p, sizeof(namelen));
+ p += sizeof(namelen);
+ nlen = sizeof(*name) * namelen;
+ if (namelen > __arraycount(name)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ if (p + nlen > e) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(name, p, nlen);
+ p += nlen;
+ if (p + sizeof(oldlen) > e) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(&oldlen, p, sizeof(oldlen));
+ p += sizeof(oldlen);
+ if (p + sizeof(newlen) > e) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(&newlen, p, sizeof(newlen));
+ p += sizeof(newlen);
+ if (p + newlen > e) {
+ errno = EINVAL;
+ return -1;
+ }
+ newp = newlen ? p : NULL;
+
+ if (flags & PS_SYSCTL_OLEN) {
+ *rlen = sizeof(oldlen) + oldlen;
+ *rdata = malloc(*rlen);
+ if (*rdata == NULL)
+ return -1;
+ oldlenp = (size_t *)*rdata;
+ *oldlenp = oldlen;
+ if (flags & PS_SYSCTL_ODATA)
+ oldp = (char *)*rdata + sizeof(oldlen);
+ else
+ oldp = NULL;
+ } else {
+ oldlenp = NULL;
+ oldp = NULL;
+ }
+
+ err = sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+ return err;
+}
+#endif
+
ssize_t
ps_root_os(struct ps_msghdr *psm, struct msghdr *msg,
- void **rdata, size_t *rlen)
+ void **rdata, size_t *rlen, bool *free_rdata)
{
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
#ifdef HAVE_PLEDGE
case PS_IFIGNOREGRP:
return ps_root_doifignoregroup(data, len);
+#endif
+#ifdef HAVE_CAPSICUM
+ case PS_SYSCTL:
+ *free_rdata = true;
+ return ps_root_dosysctl(psm->ps_flags, data, len, rdata, rlen);
#endif
default:
errno = ENOTSUP;
return -1;
return ps_root_readerror(ctx, data, len);
}
+#endif
+#ifdef HAVE_PLEDGE
ssize_t
ps_root_ifignoregroup(struct dhcpcd_ctx *ctx, const char *ifname)
{
return ps_root_readerror(ctx, NULL, 0);
}
#endif
+
+#ifdef HAVE_CAPSICUM
+ssize_t
+ps_root_sysctl(struct dhcpcd_ctx *ctx,
+ const int *name, unsigned int namelen,
+ void *oldp, size_t *oldlenp, const void *newp, size_t newlen)
+{
+ char buf[PS_BUFLEN], *p = buf;
+ unsigned long flags = 0;
+ size_t olen = (oldp && oldlenp) ? *oldlenp : 0, nolen;
+
+ if (sizeof(namelen) + (sizeof(*name) * namelen) +
+ sizeof(oldlenp) +
+ sizeof(newlen) + newlen > sizeof(buf))
+ {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ if (oldlenp)
+ flags |= PS_SYSCTL_OLEN;
+ if (oldp)
+ flags |= PS_SYSCTL_ODATA;
+ memcpy(p, &namelen, sizeof(namelen));
+ p += sizeof(namelen);
+ memcpy(p, name, sizeof(*name) * namelen);
+ p += sizeof(*name) * namelen;
+ memcpy(p, &olen, sizeof(olen));
+ p += sizeof(olen);
+ memcpy(p, &newlen, sizeof(newlen));
+ p += sizeof(newlen);
+ if (newlen) {
+ memcpy(p, newp, newlen);
+ p += newlen;
+ }
+
+ if (ps_sendcmd(ctx, ctx->ps_root->psp_fd, PS_SYSCTL,
+ flags, buf, (size_t)(p - buf)) == -1)
+ return -1;
+
+ if (ps_root_readerror(ctx, buf, sizeof(buf)) == -1)
+ return -1;
+
+ p = buf;
+ memcpy(&nolen, p, sizeof(nolen));
+ p += sizeof(nolen);
+ if (oldlenp) {
+ *oldlenp = nolen;
+ if (oldp && nolen <= olen)
+ memcpy(oldp, p, nolen);
+ }
+
+ return 0;
+}
+#endif
ssize_t
ps_root_os(struct ps_msghdr *psm, struct msghdr *msg,
- __unused void **rdata, __unused size_t *rlen)
+ __unused void **rdata, __unused size_t *rlen, __unused bool *free_data)
{
switch (psm->ps_cmd) {
break;
#endif
default:
- err = ps_root_os(psm, msg, &rdata, &rlen);
+ err = ps_root_os(psm, msg, &rdata, &rlen, &free_rdata);
break;
}
int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
#endif
-ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *, void **, size_t *);
+ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *,
+ void **, size_t *, bool *);
#if defined(BSD) || defined(__sun)
ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t);
ssize_t ps_root_indirectioctl(struct dhcpcd_ctx *, unsigned long, const char *,
void *, size_t);
ssize_t ps_root_ifignoregroup(struct dhcpcd_ctx *, const char *);
+ssize_t ps_root_sysctl(struct dhcpcd_ctx *, const int *, unsigned int,
+ void *, size_t *, const void *, size_t);
#endif
#ifdef __linux__
ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
ssize_t
ps_root_os(struct ps_msghdr *psm, struct msghdr *msg,
- void **rdata, size_t *rlen)
+ void **rdata, size_t *rlen, __unused bool *free_rdata)
{
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
#define PS_IP6FORWARDING 0x0204
#define PS_GETIFADDRS 0x0205
#define PS_IFIGNOREGRP 0x0206
+#define PS_SYSCTL 0x0207
/* Dev Commands */
#define PS_DEV_LISTENING 0x1001
#define PS_CTL_PRIV 0x0004
#define PS_CTL_UNPRIV 0x0005
+/* Sysctl Needs (via flags) */
+#define PS_SYSCTL_OLEN 0x0001
+#define PS_SYSCTL_ODATA 0x0002
+
/* Process commands */
#define PS_START 0x4000
#define PS_STOP 0x8000