122f7cecaSroy /* SPDX-License-Identifier: BSD-2-Clause */
222f7cecaSroy /*
322f7cecaSroy * Privilege Separation for dhcpcd, BSD driver
43ee74c9aSroy * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
522f7cecaSroy * All rights reserved
622f7cecaSroy
722f7cecaSroy * Redistribution and use in source and binary forms, with or without
822f7cecaSroy * modification, are permitted provided that the following conditions
922f7cecaSroy * are met:
1022f7cecaSroy * 1. Redistributions of source code must retain the above copyright
1122f7cecaSroy * notice, this list of conditions and the following disclaimer.
1222f7cecaSroy * 2. Redistributions in binary form must reproduce the above copyright
1322f7cecaSroy * notice, this list of conditions and the following disclaimer in the
1422f7cecaSroy * documentation and/or other materials provided with the distribution.
1522f7cecaSroy *
1622f7cecaSroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1722f7cecaSroy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1822f7cecaSroy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1922f7cecaSroy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2022f7cecaSroy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2122f7cecaSroy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2222f7cecaSroy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2322f7cecaSroy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2422f7cecaSroy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2522f7cecaSroy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2622f7cecaSroy * SUCH DAMAGE.
2722f7cecaSroy */
2822f7cecaSroy
2922f7cecaSroy #include <sys/ioctl.h>
303ee74c9aSroy #include <sys/types.h>
313ee74c9aSroy #include <sys/sysctl.h>
3222f7cecaSroy
3354b96bebSroy /* Need these for filtering the ioctls */
34d302d004Sroy #include <arpa/inet.h>
3554b96bebSroy #include <net/if.h>
36d302d004Sroy #include <netinet/if_ether.h>
3754b96bebSroy #include <netinet/in.h>
3854b96bebSroy #include <netinet6/in6_var.h>
3954b96bebSroy #include <netinet6/nd6.h>
40d302d004Sroy #ifdef __NetBSD__
41d302d004Sroy #include <netinet/if_ether.h>
42d302d004Sroy #include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
43d302d004Sroy #elif defined(__DragonFly__)
44d302d004Sroy #include <net/vlan/if_vlan_var.h>
45d302d004Sroy #else
46d302d004Sroy #include <net/if_vlan_var.h>
47d302d004Sroy #endif
4854b96bebSroy #ifdef __DragonFly__
4954b96bebSroy # include <netproto/802_11/ieee80211_ioctl.h>
5054b96bebSroy #else
5154b96bebSroy # include <net80211/ieee80211.h>
5254b96bebSroy # include <net80211/ieee80211_ioctl.h>
5354b96bebSroy #endif
5454b96bebSroy
5522f7cecaSroy #include <errno.h>
563ee74c9aSroy #include <stdlib.h>
5754b96bebSroy #include <string.h>
5822f7cecaSroy #include <unistd.h>
5922f7cecaSroy
6022f7cecaSroy #include "dhcpcd.h"
613ee74c9aSroy #include "if.h"
6222f7cecaSroy #include "logerr.h"
6322f7cecaSroy #include "privsep.h"
6422f7cecaSroy
6522f7cecaSroy static ssize_t
ps_root_doioctldom(struct dhcpcd_ctx * ctx,int domain,unsigned long req,void * data,size_t len)663ee74c9aSroy ps_root_doioctldom(struct dhcpcd_ctx *ctx, int domain, unsigned long req, void *data, size_t len)
6722f7cecaSroy {
683ee74c9aSroy #if defined(INET6) || (defined(SIOCALIFADDR) && defined(IFLR_ACTIVE))
693ee74c9aSroy struct priv *priv = (struct priv *)ctx->priv;
703ee74c9aSroy #endif
713ee74c9aSroy int s;
723ee74c9aSroy
733ee74c9aSroy switch(domain) {
743ee74c9aSroy #ifdef INET
753ee74c9aSroy case PF_INET:
763ee74c9aSroy s = ctx->pf_inet_fd;
773ee74c9aSroy break;
783ee74c9aSroy #endif
793ee74c9aSroy #ifdef INET6
803ee74c9aSroy case PF_INET6:
813ee74c9aSroy s = priv->pf_inet6_fd;
823ee74c9aSroy break;
833ee74c9aSroy #endif
843ee74c9aSroy #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
853ee74c9aSroy case PF_LINK:
863ee74c9aSroy s = priv->pf_link_fd;
873ee74c9aSroy break;
883ee74c9aSroy #endif
893ee74c9aSroy default:
903ee74c9aSroy errno = EPFNOSUPPORT;
913ee74c9aSroy return -1;
923ee74c9aSroy }
9322f7cecaSroy
9454b96bebSroy /* Only allow these ioctls */
9554b96bebSroy switch(req) {
96c73d34bfSroy #ifdef SIOCGIFDATA
97c73d34bfSroy case SIOCGIFDATA: /* FALLTHROUGH */
98c73d34bfSroy #endif
996006de69Sroy #ifdef SIOCG80211NWID
1006006de69Sroy case SIOCG80211NWID: /* FALLTHROUGH */
1016006de69Sroy #endif
1026006de69Sroy #ifdef SIOCGETVLAN
1036006de69Sroy case SIOCGETVLAN: /* FALLTHROUGH */
1046006de69Sroy #endif
10554b96bebSroy #ifdef SIOCIFAFATTACH
10654b96bebSroy case SIOCIFAFATTACH: /* FALLTHROUGH */
10754b96bebSroy #endif
10854b96bebSroy #ifdef SIOCSIFXFLAGS
10954b96bebSroy case SIOCSIFXFLAGS: /* FALLTHROUGH */
11054b96bebSroy #endif
11154b96bebSroy #ifdef SIOCSIFINFO_FLAGS
11254b96bebSroy case SIOCSIFINFO_FLAGS: /* FALLTHROUGH */
11354b96bebSroy #endif
11454b96bebSroy #ifdef SIOCSRTRFLUSH_IN6
11554b96bebSroy case SIOCSRTRFLUSH_IN6: /* FALLTHROUGH */
11654b96bebSroy case SIOCSPFXFLUSH_IN6: /* FALLTHROUGH */
11754b96bebSroy #endif
11854b96bebSroy #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE)
11954b96bebSroy case SIOCALIFADDR: /* FALLTHROUGH */
12054b96bebSroy case SIOCDLIFADDR: /* FALLTHROUGH */
12154b96bebSroy #else
12254b96bebSroy case SIOCSIFLLADDR: /* FALLTHROUGH */
12354b96bebSroy #endif
12454b96bebSroy #ifdef SIOCSIFINFO_IN6
12554b96bebSroy case SIOCSIFINFO_IN6: /* FALLTHROUGH */
12654b96bebSroy #endif
12754b96bebSroy case SIOCAIFADDR_IN6: /* FALLTHROUGH */
1286006de69Sroy case SIOCDIFADDR_IN6:
12954b96bebSroy break;
13054b96bebSroy default:
13154b96bebSroy errno = EPERM;
13254b96bebSroy return -1;
13354b96bebSroy }
13454b96bebSroy
1353ee74c9aSroy return ioctl(s, req, data, len);
13622f7cecaSroy }
13722f7cecaSroy
13822f7cecaSroy static ssize_t
ps_root_doroute(struct dhcpcd_ctx * ctx,void * data,size_t len)1393ee74c9aSroy ps_root_doroute(struct dhcpcd_ctx *ctx, void *data, size_t len)
14022f7cecaSroy {
14122f7cecaSroy
1423ee74c9aSroy return write(ctx->link_fd, data, len);
14322f7cecaSroy }
14422f7cecaSroy
145c73d34bfSroy #if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
14654b96bebSroy static ssize_t
ps_root_doindirectioctl(struct dhcpcd_ctx * ctx,unsigned long req,void * data,size_t len)1473ee74c9aSroy ps_root_doindirectioctl(struct dhcpcd_ctx *ctx,
1483ee74c9aSroy unsigned long req, void *data, size_t len)
14954b96bebSroy {
15054b96bebSroy char *p = data;
15154b96bebSroy struct ifreq ifr = { .ifr_flags = 0 };
15254b96bebSroy
1536006de69Sroy /* ioctl filtering is done in ps_root_doioctldom */
15454b96bebSroy
1556006de69Sroy if (len < IFNAMSIZ + 1) {
15654b96bebSroy errno = EINVAL;
15754b96bebSroy return -1;
15854b96bebSroy }
15954b96bebSroy
16054b96bebSroy strlcpy(ifr.ifr_name, p, IFNAMSIZ);
1616006de69Sroy len -= IFNAMSIZ;
1626006de69Sroy memmove(data, p + IFNAMSIZ, len);
1636006de69Sroy ifr.ifr_data = data;
1646006de69Sroy
1653ee74c9aSroy return ps_root_doioctldom(ctx, PF_INET, req, &ifr, sizeof(ifr));
16654b96bebSroy }
167c73d34bfSroy #endif
168708ac11bSroy
169c73d34bfSroy #ifdef HAVE_PLEDGE
170708ac11bSroy static ssize_t
ps_root_doifignoregroup(struct dhcpcd_ctx * ctx,void * data,size_t len)1713ee74c9aSroy ps_root_doifignoregroup(struct dhcpcd_ctx *ctx, void *data, size_t len)
172708ac11bSroy {
173708ac11bSroy
174708ac11bSroy if (len == 0 || ((const char *)data)[len - 1] != '\0') {
175708ac11bSroy errno = EINVAL;
176708ac11bSroy return -1;
177708ac11bSroy }
178708ac11bSroy
1793ee74c9aSroy return if_ignoregroup(ctx->pf_inet_fd, data);
1803ee74c9aSroy }
1813ee74c9aSroy #endif
1823ee74c9aSroy
1833ee74c9aSroy #ifdef HAVE_CAPSICUM
1843ee74c9aSroy static ssize_t
ps_root_dosysctl(unsigned long flags,void * data,size_t len,void ** rdata,size_t * rlen)1853ee74c9aSroy ps_root_dosysctl(unsigned long flags,
1863ee74c9aSroy void *data, size_t len, void **rdata, size_t *rlen)
1873ee74c9aSroy {
1883ee74c9aSroy char *p = data, *e = p + len;
1893ee74c9aSroy int name[10];
1903ee74c9aSroy unsigned int namelen;
1913ee74c9aSroy void *oldp;
1923ee74c9aSroy size_t *oldlenp, oldlen, nlen;
1933ee74c9aSroy void *newp;
1943ee74c9aSroy size_t newlen;
1953ee74c9aSroy int err;
1963ee74c9aSroy
1973ee74c9aSroy if (sizeof(namelen) >= len) {
1983ee74c9aSroy errno = EINVAL;
199708ac11bSroy return -1;
2003ee74c9aSroy }
2013ee74c9aSroy memcpy(&namelen, p, sizeof(namelen));
2023ee74c9aSroy p += sizeof(namelen);
2033ee74c9aSroy nlen = sizeof(*name) * namelen;
2043ee74c9aSroy if (namelen > __arraycount(name)) {
2053ee74c9aSroy errno = ENOBUFS;
2063ee74c9aSroy return -1;
2073ee74c9aSroy }
2083ee74c9aSroy if (p + nlen > e) {
2093ee74c9aSroy errno = EINVAL;
2103ee74c9aSroy return -1;
2113ee74c9aSroy }
2123ee74c9aSroy memcpy(name, p, nlen);
2133ee74c9aSroy p += nlen;
2143ee74c9aSroy if (p + sizeof(oldlen) > e) {
2153ee74c9aSroy errno = EINVAL;
2163ee74c9aSroy return -1;
2173ee74c9aSroy }
2183ee74c9aSroy memcpy(&oldlen, p, sizeof(oldlen));
2193ee74c9aSroy p += sizeof(oldlen);
2203ee74c9aSroy if (p + sizeof(newlen) > e) {
2213ee74c9aSroy errno = EINVAL;
2223ee74c9aSroy return -1;
2233ee74c9aSroy }
2243ee74c9aSroy memcpy(&newlen, p, sizeof(newlen));
2253ee74c9aSroy p += sizeof(newlen);
2263ee74c9aSroy if (p + newlen > e) {
2273ee74c9aSroy errno = EINVAL;
2283ee74c9aSroy return -1;
2293ee74c9aSroy }
2303ee74c9aSroy newp = newlen ? p : NULL;
2313ee74c9aSroy
2323ee74c9aSroy if (flags & PS_SYSCTL_OLEN) {
2333ee74c9aSroy *rlen = sizeof(oldlen) + oldlen;
2343ee74c9aSroy *rdata = malloc(*rlen);
2353ee74c9aSroy if (*rdata == NULL)
2363ee74c9aSroy return -1;
2373ee74c9aSroy oldlenp = (size_t *)*rdata;
2383ee74c9aSroy *oldlenp = oldlen;
2393ee74c9aSroy if (flags & PS_SYSCTL_ODATA)
2403ee74c9aSroy oldp = (char *)*rdata + sizeof(oldlen);
2413ee74c9aSroy else
2423ee74c9aSroy oldp = NULL;
2433ee74c9aSroy } else {
2443ee74c9aSroy oldlenp = NULL;
2453ee74c9aSroy oldp = NULL;
2463ee74c9aSroy }
2473ee74c9aSroy
2483ee74c9aSroy err = sysctl(name, namelen, oldp, oldlenp, newp, newlen);
249708ac11bSroy return err;
250708ac11bSroy }
25154b96bebSroy #endif
25254b96bebSroy
25322f7cecaSroy ssize_t
ps_root_os(struct dhcpcd_ctx * ctx,struct ps_msghdr * psm,struct msghdr * msg,void ** rdata,size_t * rlen,bool * free_rdata)2543ee74c9aSroy ps_root_os(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg,
2553ee74c9aSroy void **rdata, size_t *rlen, bool *free_rdata)
25622f7cecaSroy {
25722f7cecaSroy struct iovec *iov = msg->msg_iov;
25822f7cecaSroy void *data = iov->iov_base;
25922f7cecaSroy size_t len = iov->iov_len;
2606006de69Sroy ssize_t err;
26122f7cecaSroy
26222f7cecaSroy switch (psm->ps_cmd) {
26322f7cecaSroy case PS_IOCTLLINK:
2643ee74c9aSroy err = ps_root_doioctldom(ctx, PF_LINK, psm->ps_flags, data, len);
2656006de69Sroy break;
26622f7cecaSroy case PS_IOCTL6:
2673ee74c9aSroy err = ps_root_doioctldom(ctx, PF_INET6, psm->ps_flags, data, len);
2686006de69Sroy break;
26922f7cecaSroy case PS_ROUTE:
2703ee74c9aSroy return ps_root_doroute(ctx, data, len);
271c73d34bfSroy #if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
27254b96bebSroy case PS_IOCTLINDIRECT:
2733ee74c9aSroy err = ps_root_doindirectioctl(ctx, psm->ps_flags, data, len);
2746006de69Sroy break;
275c73d34bfSroy #endif
276c73d34bfSroy #ifdef HAVE_PLEDGE
277708ac11bSroy case PS_IFIGNOREGRP:
2783ee74c9aSroy return ps_root_doifignoregroup(ctx, data, len);
2793ee74c9aSroy #endif
2803ee74c9aSroy #ifdef HAVE_CAPSICUM
2813ee74c9aSroy case PS_SYSCTL:
2823ee74c9aSroy *free_rdata = true;
2833ee74c9aSroy return ps_root_dosysctl(psm->ps_flags, data, len, rdata, rlen);
2843ee74c9aSroy #else
2853ee74c9aSroy UNUSED(free_rdata);
28654b96bebSroy #endif
28722f7cecaSroy default:
28822f7cecaSroy errno = ENOTSUP;
28922f7cecaSroy return -1;
29022f7cecaSroy }
2916006de69Sroy
2926006de69Sroy if (err != -1) {
2936006de69Sroy *rdata = data;
2946006de69Sroy *rlen = len;
2956006de69Sroy }
2966006de69Sroy return err;
29722f7cecaSroy }
29822f7cecaSroy
29922f7cecaSroy static ssize_t
ps_root_ioctldom(struct dhcpcd_ctx * ctx,uint16_t domain,unsigned long request,void * data,size_t len)30054b96bebSroy ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request,
30122f7cecaSroy void *data, size_t len)
30222f7cecaSroy {
30322f7cecaSroy
304*5ccf87deSroy if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), domain,
30522f7cecaSroy request, data, len) == -1)
30622f7cecaSroy return -1;
30754b96bebSroy return ps_root_readerror(ctx, data, len);
30822f7cecaSroy }
30922f7cecaSroy
31022f7cecaSroy ssize_t
ps_root_ioctllink(struct dhcpcd_ctx * ctx,unsigned long request,void * data,size_t len)31122f7cecaSroy ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request,
31222f7cecaSroy void *data, size_t len)
31322f7cecaSroy {
31422f7cecaSroy
31522f7cecaSroy return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len);
31622f7cecaSroy }
31722f7cecaSroy
31822f7cecaSroy ssize_t
ps_root_ioctl6(struct dhcpcd_ctx * ctx,unsigned long request,void * data,size_t len)31922f7cecaSroy ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request,
32022f7cecaSroy void *data, size_t len)
32122f7cecaSroy {
32222f7cecaSroy
32322f7cecaSroy return ps_root_ioctldom(ctx, PS_IOCTL6, request, data, len);
32422f7cecaSroy }
32522f7cecaSroy
32622f7cecaSroy ssize_t
ps_root_route(struct dhcpcd_ctx * ctx,void * data,size_t len)32722f7cecaSroy ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
32822f7cecaSroy {
32922f7cecaSroy
330*5ccf87deSroy if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_ROUTE, 0, data, len) == -1)
33122f7cecaSroy return -1;
33254b96bebSroy return ps_root_readerror(ctx, data, len);
33322f7cecaSroy }
33454b96bebSroy
335c73d34bfSroy #if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
33654b96bebSroy ssize_t
ps_root_indirectioctl(struct dhcpcd_ctx * ctx,unsigned long request,const char * ifname,void * data,size_t len)33754b96bebSroy ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
33854b96bebSroy const char *ifname, void *data, size_t len)
33954b96bebSroy {
34054b96bebSroy char buf[PS_BUFLEN];
34154b96bebSroy
3426006de69Sroy if (IFNAMSIZ + len > sizeof(buf)) {
3436006de69Sroy errno = ENOBUFS;
3446006de69Sroy return -1;
3456006de69Sroy }
3466006de69Sroy
34754b96bebSroy strlcpy(buf, ifname, IFNAMSIZ);
34854b96bebSroy memcpy(buf + IFNAMSIZ, data, len);
349*5ccf87deSroy if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT,
35054b96bebSroy request, buf, IFNAMSIZ + len) == -1)
35154b96bebSroy return -1;
35254b96bebSroy return ps_root_readerror(ctx, data, len);
35354b96bebSroy }
3543ee74c9aSroy #endif
355708ac11bSroy
3563ee74c9aSroy #ifdef HAVE_PLEDGE
357708ac11bSroy ssize_t
ps_root_ifignoregroup(struct dhcpcd_ctx * ctx,const char * ifname)358708ac11bSroy ps_root_ifignoregroup(struct dhcpcd_ctx *ctx, const char *ifname)
359708ac11bSroy {
360708ac11bSroy
361*5ccf87deSroy if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IFIGNOREGRP, 0,
362708ac11bSroy ifname, strlen(ifname) + 1) == -1)
363708ac11bSroy return -1;
364708ac11bSroy return ps_root_readerror(ctx, NULL, 0);
365708ac11bSroy }
36654b96bebSroy #endif
3673ee74c9aSroy
3683ee74c9aSroy #ifdef HAVE_CAPSICUM
3693ee74c9aSroy 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)3703ee74c9aSroy ps_root_sysctl(struct dhcpcd_ctx *ctx,
3713ee74c9aSroy const int *name, unsigned int namelen,
3723ee74c9aSroy void *oldp, size_t *oldlenp, const void *newp, size_t newlen)
3733ee74c9aSroy {
3743ee74c9aSroy char buf[PS_BUFLEN], *p = buf;
3753ee74c9aSroy unsigned long flags = 0;
3763ee74c9aSroy size_t olen = (oldp && oldlenp) ? *oldlenp : 0, nolen;
3773ee74c9aSroy
3783ee74c9aSroy if (sizeof(namelen) + (sizeof(*name) * namelen) +
3793ee74c9aSroy sizeof(oldlenp) +
3803ee74c9aSroy sizeof(newlen) + newlen > sizeof(buf))
3813ee74c9aSroy {
3823ee74c9aSroy errno = ENOBUFS;
3833ee74c9aSroy return -1;
3843ee74c9aSroy }
3853ee74c9aSroy
3863ee74c9aSroy if (oldlenp)
3873ee74c9aSroy flags |= PS_SYSCTL_OLEN;
3883ee74c9aSroy if (oldp)
3893ee74c9aSroy flags |= PS_SYSCTL_ODATA;
3903ee74c9aSroy memcpy(p, &namelen, sizeof(namelen));
3913ee74c9aSroy p += sizeof(namelen);
3923ee74c9aSroy memcpy(p, name, sizeof(*name) * namelen);
3933ee74c9aSroy p += sizeof(*name) * namelen;
3943ee74c9aSroy memcpy(p, &olen, sizeof(olen));
3953ee74c9aSroy p += sizeof(olen);
3963ee74c9aSroy memcpy(p, &newlen, sizeof(newlen));
3973ee74c9aSroy p += sizeof(newlen);
3983ee74c9aSroy if (newlen) {
3993ee74c9aSroy memcpy(p, newp, newlen);
4003ee74c9aSroy p += newlen;
4013ee74c9aSroy }
4023ee74c9aSroy
403*5ccf87deSroy if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_SYSCTL,
4043ee74c9aSroy flags, buf, (size_t)(p - buf)) == -1)
4053ee74c9aSroy return -1;
4063ee74c9aSroy
4073ee74c9aSroy if (ps_root_readerror(ctx, buf, sizeof(buf)) == -1)
4083ee74c9aSroy return -1;
4093ee74c9aSroy
4103ee74c9aSroy p = buf;
4113ee74c9aSroy memcpy(&nolen, p, sizeof(nolen));
4123ee74c9aSroy p += sizeof(nolen);
4133ee74c9aSroy if (oldlenp) {
4143ee74c9aSroy *oldlenp = nolen;
4153ee74c9aSroy if (oldp && nolen <= olen)
4163ee74c9aSroy memcpy(oldp, p, nolen);
4173ee74c9aSroy }
4183ee74c9aSroy
4193ee74c9aSroy return 0;
4203ee74c9aSroy }
4213ee74c9aSroy #endif
422