Commit message: None
CVE: CVE-2016-1503
CWE: CWE-119
Vulnerability description: dhcpcd before 6.10.0, as used in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-04-01 and other products, mismanages option lengths, which allows remote attackers to execute arbitrary code or cause a denial of service (heap-based buffer overflow) via a malformed DHCP response, aka internal bug 26461634.

Project: Android

decode_rfc3361(int dl, const uint8_t *data)
{
 uint8_t enc;
 unsigned int l;
 char *sip = NULL;
 struct in_addr addr;
 char *p;

 if (dl < 2) {
		errno = EINVAL;
 return 0;
 }

	enc = *data++;
	dl--;
 switch (enc) {
 case 0:
 if ((l = decode_rfc3397(NULL, 0, dl, data)) > 0) {
			sip = xmalloc(l);
			decode_rfc3397(sip, l, dl, data);
 }
 break;
 case 1:
 if (dl == 0 || dl % 4 != 0) {
			errno = EINVAL;
 break;
 }
		addr.s_addr = INADDR_BROADCAST;
		l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
		sip = p = xmalloc(l);
 while (dl != 0) {
			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
			data += sizeof(addr.s_addr);
			p += snprintf(p, l - (p - sip), "%s ", inet_ntoa(addr));
			dl -= sizeof(addr.s_addr);
 }
 *--p = '\0';
 break;
 default:
		errno = EINVAL;
 return 0;
 }

 return sip;
}

Project: Android

decode_rfc3397(char *out, ssize_t len, int pl, const uint8_t *p)
{
 const uint8_t *r, *q = p;
 int count = 0, l, hops;
 uint8_t ltype;

 while (q - p < pl) {
		r = NULL;
		hops = 0;
 /* We check we are inside our length again incase
		 * the data is NOT terminated correctly. */
 while ((l = *q++) && q - p < pl) {
			ltype = l & 0xc0;
 if (ltype == 0x80 || ltype == 0x40)
 return 0;
 else if (ltype == 0xc0) { /* pointer */
				l = (l & 0x3f) << 8;
				l |= *q++;
 /* save source of first jump. */
 if (!r)
					r = q;
				hops++;
 if (hops > 255)
 return 0;
				q = p + l;
 if (q - p >= pl)
 return 0;
 } else {
 /* straightforward name segment, add with '.' */
				count += l + 1;
 if (out) {
 if ((ssize_t)l + 1 > len) {
						errno = ENOBUFS;
 return -1;
 }
					memcpy(out, q, l);
					out += l;
 *out++ = '.';
					len -= l;
					len--;
 }
				q += l;
 }
 }
 /* change last dot to space */
 if (out)
 *(out - 1) = ' ';
 if (r)
			q = r;
 }

 /* change last space to zero terminator */
 if (out)
 *(out - 1) = 0;

 return count; 
}

Project: Android

decode_rfc3442_rt(int dl, const uint8_t *data)
{
 const uint8_t *p = data;
 const uint8_t *e;
 uint8_t cidr;
 size_t ocets;
 struct rt *routes = NULL;
 struct rt *rt = NULL;

 /* Minimum is 5 -first is CIDR and a router length of 4 */
 if (dl < 5)
 return NULL;

	e = p + dl;
 while (p < e) {
		cidr = *p++;
 if (cidr > 32) {
			free_routes(routes);
			errno = EINVAL;
 return NULL;
 }

 if (rt) {
			rt->next = xzalloc(sizeof(*rt));
			rt = rt->next;
 } else {
			routes = rt = xzalloc(sizeof(*routes));
 }
		rt->next = NULL;

		ocets = (cidr + 7) / 8;
 /* If we have ocets then we have a destination and netmask */
 if (ocets > 0) {
			memcpy(&rt->dest.s_addr, p, ocets);
			p += ocets;
			rt->net.s_addr = htonl(~0U << (32 - cidr));
 }

 /* Finally, snag the router */
		memcpy(&rt->gate.s_addr, p, 4);
		p += 4;
 }
 return routes;
}

Project: Android

decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p)
{
 uint8_t ipv4masklen, ipv6prefixlen;
 uint8_t ipv6prefix[16];
 uint8_t br[4];
 int i;
 ssize_t b, bytes = 0;

 if (pl < 22) {
		errno = EINVAL;
 return 0;
 }
 
	ipv4masklen = *p++;
	pl--;
	ipv6prefixlen = *p++;
	pl--;
 
 for (i = 0; i < 16; i++) {
		ipv6prefix[i] = *p++;
		pl--;
 }
 if (out) {
		b= snprintf(out, len,
 "%d %d "
 "%02x%02x:%02x%02x:"
 "%02x%02x:%02x%02x:"
 "%02x%02x:%02x%02x:"
 "%02x%02x:%02x%02x",
		    ipv4masklen, ipv6prefixlen,
		    ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3],
		    ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7],
		    ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11],
		    ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15]
 );
 
		len -= b;
		out += b;
		bytes += b;
 } else {
		bytes += 16 * 2 + 8 + 2 + 1 + 2;
 }

 while (pl >= 4) {
		br[0] = *p++;
		br[1] = *p++;
		br[2] = *p++;
		br[3] = *p++;
		pl -= 4;
 
 if (out) {
			b= snprintf(out, len, " %d.%d.%d.%d",
			    br[0], br[1], br[2], br[3]);
			len -= b;
			out += b;
			bytes += b;
 } else {
			bytes += (4 * 4);
 }
 }
 
 return bytes;
}

Project: Android

free_option_buffer(void)
{
	free(opt_buffer);
}

Project: Android

get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
{
 struct timeval now;

	lease->cookie = dhcp->cookie;
 /* BOOTP does not set yiaddr for replies when ciaddr is set. */
 if (dhcp->yiaddr)
		lease->addr.s_addr = dhcp->yiaddr;
 else
		lease->addr.s_addr = dhcp->ciaddr;
 if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
		lease->net.s_addr = get_netmask(lease->addr.s_addr);
 if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
		lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
 if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
 /* Ensure that we can use the lease */
		get_monotonic(&now);
 if (now.tv_sec + (time_t)lease->leasetime < now.tv_sec)
			lease->leasetime = ~0U; /* Infinite lease */
 } else
		lease->leasetime = ~0U; /* Default to infinite lease */
 if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
		lease->renewaltime = 0;
 if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
		lease->rebindtime = 0;
 if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
		lease->server.s_addr = INADDR_ANY;
}

Project: Android

get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
{
 const uint8_t *p = dhcp->options;
 const uint8_t *e = p + sizeof(dhcp->options);
 uint8_t l, ol = 0;
 uint8_t o = 0;
 uint8_t overl = 0;
 uint8_t *bp = NULL;
 const uint8_t *op = NULL;
 int bl = 0;

 /* DHCP Options are in TLV format with T and L each being a single
	 * byte.  In general, here we have p -> T, ol=p+1 -> L, op -> V.
	 * We must make sure there is enough room to read both T and L.
	 */
 while (p + 1 < e) {
		o = *p++;
 if (o == opt) {
 if (op) {
 if (!opt_buffer) {
					opt_buffer = xmalloc(sizeof(*dhcp));
#ifdef DEBUG_MEMORY
					atexit(free_option_buffer);
#endif
 }
 if (!bp) 
					bp = opt_buffer;
				memcpy(bp, op, ol);
				bp += ol;
 }
			ol = (p + *p < e) ? *p : e - (p + 1);
			op = p + 1;
			bl += ol;
 }
 switch (o) {
 case DHO_PAD:
 continue;
 case DHO_END:
 if (overl & 1) {
 /* bit 1 set means parse boot file */
				overl &= ~1;
				p = dhcp->bootfile;
				e = p + sizeof(dhcp->bootfile);
 } else if (overl & 2) {
 /* bit 2 set means parse server name */
				overl &= ~2;
				p = dhcp->servername;
				e = p + sizeof(dhcp->servername);
 } else
 goto exit;
 break;
 case DHO_OPTIONSOVERLOADED:
 /* Ensure we only get this option once */
 if (!overl)
				overl = 0x80 | p[1];
 break;
 }
		l = *p++;
		p += l;
 }

exit:
 if (valid_length(opt, bl, type) == -1) {
		errno = EINVAL;
 return NULL;
 }
 if (len)
 *len = bl;
 if (bp) {
		memcpy(bp, op, ol);
 return (const uint8_t *)opt_buffer;
 }
 if (op)
 return op;
	errno = ENOENT;
 return NULL;
}

Project: Android

get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
 uint8_t option)
{
 const uint8_t *p = get_option_raw(dhcp, option);

 if (!p)
 return -1;
	memcpy(&a->s_addr, p, sizeof(a->s_addr));
 return 0;
}

Project: Android

get_option_routes(const struct dhcp_message *dhcp,
 const char *ifname, unsigned long long *opts)
{
 const uint8_t *p;
 const uint8_t *e;
 struct rt *routes = NULL;
 struct rt *route = NULL;
 int len;

 /* If we have CSR's then we MUST use these only */
	p = get_option(dhcp, DHO_CSR, &len, NULL);
 /* Check for crappy MS option */
 if (!p)
		p = get_option(dhcp, DHO_MSCSR, &len, NULL);
 if (p) {
		routes = decode_rfc3442_rt(len, p);
 if (routes) {
 if (!(*opts & DHCPCD_CSR_WARNED)) {
				syslog(LOG_DEBUG,
 "%s: using Classless Static Routes",
				    ifname);
 *opts |= DHCPCD_CSR_WARNED;
 }
 return routes;
 }
 }

 /* OK, get our static routes first. */
	p = get_option(dhcp, DHO_STATICROUTE, &len, NULL);
 if (p) {
		e = p + len;
 while (p < e) {
 if (route) {
				route->next = xmalloc(sizeof(*route));
				route = route->next;
 } else
				routes = route = xmalloc(sizeof(*routes));
			route->next = NULL;
			memcpy(&route->dest.s_addr, p, 4);
			p += 4;
			memcpy(&route->gate.s_addr, p, 4);
			p += 4;
			route->net.s_addr = route_netmask(route->dest.s_addr);
 }
 }

 /* Now grab our routers */
	p = get_option(dhcp, DHO_ROUTER, &len, NULL);
 if (p) {
		e = p + len;
 while (p < e) {
 if (route) {
				route->next = xzalloc(sizeof(*route));
				route = route->next;
 } else
				routes = route = xzalloc(sizeof(*route));
			memcpy(&route->gate.s_addr, p, 4);
			p += 4;
 }
 }

 return routes;
}

Project: Android

get_option_string(const struct dhcp_message *dhcp, uint8_t option)
{
 int type = 0;
 int len;
 const uint8_t *p;
 char *s;

	p = get_option(dhcp, option, &len, &type);
 if (!p || *p == '\0')
 return NULL;

 if (type & RFC3397) {
		type = decode_rfc3397(NULL, 0, len, p);
 if (!type) {
			errno = EINVAL;
 return NULL;
 }
		s = xmalloc(sizeof(char) * type);
		decode_rfc3397(s, type, len, p);
 return s;
 }

 if (type & RFC3361)
 return decode_rfc3361(len, p);

	s = xmalloc(sizeof(char) * (len + 1));
	memcpy(s, p, len);
	s[len] = '\0';
 return s;
}

Project: Android

get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
{
 const uint8_t *p = get_option_raw(dhcp, option);
 uint32_t d;

 if (!p)
 return -1;
	memcpy(&d, p, sizeof(d));
 *i = ntohl(d);
 return 0;
}

Project: Android

make_message(struct dhcp_message **message,
 const struct interface *iface,
 uint8_t type)
{
 struct dhcp_message *dhcp;
 uint8_t *m, *lp, *p;
 uint8_t *n_params = NULL;
 time_t up = uptime() - iface->start_uptime;
 uint32_t ul;
 uint16_t sz;
 size_t len;
 const char *hp;
 const struct dhcp_opt *opt;
 const struct if_options *ifo = iface->state->options;
 const struct dhcp_lease *lease = &iface->state->lease;

	dhcp = xzalloc(sizeof (*dhcp));
	m = (uint8_t *)dhcp;
	p = dhcp->options;

 if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
 (type == DHCP_REQUEST &&
		    iface->net.s_addr == lease->net.s_addr &&
 (iface->state->new == NULL ||
			iface->state->new->cookie == htonl(MAGIC_COOKIE)))))
 {
		dhcp->ciaddr = iface->addr.s_addr;
 /* In-case we haven't actually configured the address yet */
 if (type == DHCP_INFORM && iface->addr.s_addr == 0)
			dhcp->ciaddr = lease->addr.s_addr;
 }

	dhcp->op = DHCP_BOOTREQUEST;
	dhcp->hwtype = iface->family;
 switch (iface->family) {
 case ARPHRD_ETHER:
 case ARPHRD_IEEE802:
		dhcp->hwlen = iface->hwlen;
		memcpy(&dhcp->chaddr, &iface->hwaddr, iface->hwlen);
 break;
 }

 if (ifo->options & DHCPCD_BROADCAST &&
	    dhcp->ciaddr == 0 &&
	    type != DHCP_DECLINE &&
	    type != DHCP_RELEASE)
		dhcp->flags = htons(BROADCAST_FLAG);

 if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
 if (up < 0 || up > (time_t)UINT16_MAX)
			dhcp->secs = htons((uint16_t)UINT16_MAX);
 else
			dhcp->secs = htons(up);
 }
	dhcp->xid = iface->state->xid;
	dhcp->cookie = htonl(MAGIC_COOKIE);

 *p++ = DHO_MESSAGETYPE; 
 *p++ = 1;
 *p++ = type;

 if (iface->clientid) {
 *p++ = DHO_CLIENTID;
		memcpy(p, iface->clientid, iface->clientid[0] + 1);
		p += iface->clientid[0] + 1;
 }

 if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
 if (type == DHCP_DECLINE ||
 (type == DHCP_REQUEST &&
			lease->addr.s_addr != iface->addr.s_addr))
 {
			PUTADDR(DHO_IPADDRESS, lease->addr);
 if (lease->server.s_addr)
				PUTADDR(DHO_SERVERID, lease->server);
 }

 if (type == DHCP_RELEASE) {
 if (lease->server.s_addr)
				PUTADDR(DHO_SERVERID, lease->server);
 }
 }

 if (type == DHCP_DECLINE) {
 *p++ = DHO_MESSAGE;
		len = strlen(DAD);
 *p++ = len;
		memcpy(p, DAD, len);
		p += len;
 }

 if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
		PUTADDR(DHO_IPADDRESS, ifo->req_addr);

 if (type == DHCP_DISCOVER ||
	    type == DHCP_INFORM ||
	    type == DHCP_REQUEST)
 {
 *p++ = DHO_MAXMESSAGESIZE;
 *p++ = 2;
		sz = get_mtu(iface->name);
 if (sz < MTU_MIN) {
 if (set_mtu(iface->name, MTU_MIN) == 0)
				sz = MTU_MIN;
 } else if (sz > MTU_MAX) {
 /* Even though our MTU could be greater than
			 * MTU_MAX (1500) dhcpcd does not presently
			 * handle DHCP packets any bigger. */
			sz = MTU_MAX;
 }
		sz = htons(sz);
		memcpy(p, &sz, 2);
		p += 2;

 if (ifo->userclass[0]) {
 *p++ = DHO_USERCLASS;
			memcpy(p, ifo->userclass, ifo->userclass[0] + 1);
			p += ifo->userclass[0] + 1;
 }

 if (ifo->vendorclassid[0]) {
 *p++ = DHO_VENDORCLASSID;
			memcpy(p, ifo->vendorclassid,
			    ifo->vendorclassid[0] + 1);
			p += ifo->vendorclassid[0] + 1;
 }


 if (type != DHCP_INFORM) {
 if (ifo->leasetime != 0) {
 *p++ = DHO_LEASETIME;
 *p++ = 4;
				ul = htonl(ifo->leasetime);
				memcpy(p, &ul, 4);
				p += 4;
 }
 }

 /* Regardless of RFC2132, we should always send a hostname
		 * upto the first dot (the short hostname) as otherwise
		 * confuses some DHCP servers when updating DNS.
		 * The FQDN option should be used if a FQDN is required. */
 if (ifo->options & DHCPCD_HOSTNAME && ifo->hostname[0]) {
 *p++ = DHO_HOSTNAME;
			hp = strchr(ifo->hostname, '.');
 if (hp)
				len = hp - ifo->hostname;
 else
				len = strlen(ifo->hostname);
 *p++ = len;
			memcpy(p, ifo->hostname, len);
			p += len;
 }
 if (ifo->fqdn != FQDN_DISABLE && ifo->hostname[0]) {
 /* IETF DHC-FQDN option (81), RFC4702 */
 *p++ = DHO_FQDN;
			lp = p;
 *p++ = 3;
 /*
			 * Flags: 0000NEOS
			 * S: 1 => Client requests Server to update
			 *         a RR in DNS as well as PTR
			 * O: 1 => Server indicates to client that
			 *         DNS has been updated
			 * E: 1 => Name data is DNS format
			 * N: 1 => Client requests Server to not
			 *         update DNS
			 */
 *p++ = (ifo->fqdn & 0x09) | 0x04;
 *p++ = 0; /* from server for PTR RR */
 *p++ = 0; /* from server for A RR if S=1 */
			ul = encode_rfc1035(ifo->hostname, p);
 *lp += ul;
			p += ul;
 }

 /* vendor is already encoded correctly, so just add it */
 if (ifo->vendor[0]) {
 *p++ = DHO_VENDOR;
			memcpy(p, ifo->vendor, ifo->vendor[0] + 1);
			p += ifo->vendor[0] + 1;
 }

 *p++ = DHO_PARAMETERREQUESTLIST;
		n_params = p;
 *p++ = 0;
 for (opt = dhcp_opts; opt->option; opt++) {
 if (!(opt->type & REQUEST || 
				has_option_mask(ifo->requestmask, opt->option)))
 continue;
 if (type == DHCP_INFORM &&
 (opt->option == DHO_RENEWALTIME ||
				opt->option == DHO_REBINDTIME))
 continue;
 *p++ = opt->option;
 }
 *n_params = p - n_params - 1;
 }
 *p++ = DHO_END;

#ifdef BOOTP_MESSAGE_LENTH_MIN
 /* Some crappy DHCP servers think they have to obey the BOOTP minimum
	 * message length.
	 * They are wrong, but we should still cater for them. */
 while (p - m < BOOTP_MESSAGE_LENTH_MIN)
 *p++ = DHO_PAD;
#endif

 *message = dhcp;
 return p - m;
}

Project: Android

int make_option_mask(uint8_t *mask, const char *opts, int add)
{
 char *token, *o, *p, *t;
 const struct dhcp_opt *opt;
 int match, n;

	o = p = xstrdup(opts);
 while ((token = strsep(&p, ", "))) {
 if (*token == '\0')
 continue;
 for (opt = dhcp_opts; opt->option; opt++) {
 if (!opt->var)
 continue;
			match = 0;
 if (strcmp(opt->var, token) == 0)
				match = 1;
 else {
				errno = 0;
				n = strtol(token, &t, 0);
 if (errno == 0 && !*t)
 if (opt->option == n)
						match = 1;
 }
 if (match) {
 if (add == 2 && !(opt->type & IPV4)) {
					free(o);
					errno = EINVAL;
 return -1;
 }
 if (add == 1 || add == 2)
					add_option_mask(mask,
					    opt->option);
 else
					del_option_mask(mask,
					    opt->option);
 break;
 }
 }
 if (!opt->option) {
			free(o);
			errno = ENOENT;
 return -1;
 }
 }
	free(o);
 return 0;
}

Project: Android

print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
{
 const uint8_t *e, *t;
 uint16_t u16;
 int16_t s16;
 uint32_t u32;
 int32_t s32;
 struct in_addr addr;
 ssize_t bytes = 0;
 ssize_t l;
 char *tmp;

 if (type & RFC3397) {
		l = decode_rfc3397(NULL, 0, dl, data);
 if (l < 1)
 return l;
		tmp = xmalloc(l);
		decode_rfc3397(tmp, l, dl, data);
		l = print_string(s, len, l - 1, (uint8_t *)tmp);
		free(tmp);
 return l;
 }

 if (type & RFC3361) {
 if ((tmp = decode_rfc3361(dl, data)) == NULL)
 return -1;
		l = strlen(tmp);
		l = print_string(s, len, l - 1, (uint8_t *)tmp);
		free(tmp);
 return l;
 }

 if (type & RFC3442)
 return decode_rfc3442(s, len, dl, data);

 if (type & RFC5969)
 return decode_rfc5969(s, len, dl, data);

 if (type & STRING) {
 /* Some DHCP servers return NULL strings */
 if (*data == '\0')
 return 0;
 return print_string(s, len, dl, data);
 }

 if (!s) {
 if (type & UINT8)
			l = 3;
 else if (type & UINT16) {
			l = 5;
			dl /= 2;
 } else if (type & SINT16) {
			l = 6;
			dl /= 2;
 } else if (type & UINT32) {
			l = 10;
			dl /= 4;
 } else if (type & SINT32) {
			l = 11;
			dl /= 4;
 } else if (type & IPV4) {
			l = 16;
			dl /= 4;
 } else {
			errno = EINVAL;
 return -1;
 }
 return (l + 1) * dl;
 }

	t = data;
	e = data + dl;
 while (data < e) {
 if (data != t) {
 *s++ = ' ';
			bytes++;
			len--;
 }
 if (type & UINT8) {
			l = snprintf(s, len, "%d", *data);
			data++;
 } else if (type & UINT16) {
			memcpy(&u16, data, sizeof(u16));
			u16 = ntohs(u16);
			l = snprintf(s, len, "%d", u16);
			data += sizeof(u16);
 } else if (type & SINT16) {
			memcpy(&s16, data, sizeof(s16));
			s16 = ntohs(s16);
			l = snprintf(s, len, "%d", s16);
			data += sizeof(s16);
 } else if (type & UINT32) {
			memcpy(&u32, data, sizeof(u32));
			u32 = ntohl(u32);
			l = snprintf(s, len, "%d", u32);
			data += sizeof(u32);
 } else if (type & SINT32) {
			memcpy(&s32, data, sizeof(s32));
			s32 = ntohl(s32);
			l = snprintf(s, len, "%d", s32);
			data += sizeof(s32);
 } else if (type & IPV4) {
			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
			l = snprintf(s, len, "%s", inet_ntoa(addr));
			data += sizeof(addr.s_addr);
 } else
			l = 0;
 if (len <= l) {
			bytes += len;
 break;
 }
		len -= l;
		bytes += l;
		s += l;
 }

 return bytes;
}

Project: Android

print_options(void)
{
 const struct dhcp_opt *opt;
 const char **p;

 for (p = if_params; *p; p++)
		printf(" -  %s\n", *p);

 for (p = dhcp_params; *p; p++)
		printf("    %s\n", *p);

 for (opt = dhcp_opts; opt->option; opt++)
 if (opt->var)
			printf("%03d %s\n", opt->option, opt->var);
}

Project: Android

print_string(char *s, ssize_t len, int dl, const uint8_t *data)
{
 uint8_t c;
 const uint8_t *e, *p;
 ssize_t bytes = 0;
 ssize_t r;

	e = data + dl;
 while (data < e) {
		c = *data++;
 if (c == '\0') {
 /* If rest is all NULL, skip it. */
 for (p = data; p < e; p++)
 if (*p != '\0')
 break;
 if (p == e)
 break;
 }
 if (!isascii(c) || !isprint(c)) {
 if (s) {
 if (len < 5) {
					errno = ENOBUFS;
 return -1;
 }
				r = snprintf(s, len, "\\%03o", c);
				len -= r;
				bytes += r;
				s += r;
 } else
				bytes += 4;
 continue;
 }
 switch (c) {
 case '"': /* FALLTHROUGH */
 case '\'': /* FALLTHROUGH */
 case '$': /* FALLTHROUGH */
 case '`': /* FALLTHROUGH */
 case '\\': /* FALLTHROUGH */
 case '|': /* FALLTHROUGH */
 case '&':
 if (s) {
 if (len < 3) {
					errno = ENOBUFS;
 return -1;
 }
 *s++ = '\\';
				len--;
 }
			bytes++;
 break;
 }
 if (s) {
 *s++ = c;
			len--;
 }
		bytes++;
 }

 /* NULL */
 if (s)
 *s = '\0';
	bytes++;
 return bytes;
}

Project: Android

read_lease(const struct interface *iface)
{
 int fd;
 struct dhcp_message *dhcp;
 ssize_t bytes;

	fd = open(iface->leasefile, O_RDONLY);
 if (fd == -1) {
 if (errno != ENOENT)
			syslog(LOG_ERR, "%s: open `%s': %m",
			    iface->name, iface->leasefile);
 return NULL;
 }
	syslog(LOG_DEBUG, "%s: reading lease `%s'",
	    iface->name, iface->leasefile);
	dhcp = xmalloc(sizeof(*dhcp));
	memset(dhcp, 0, sizeof(*dhcp));
	bytes = read(fd, dhcp, sizeof(*dhcp));
	close(fd);
 if (bytes < 0) {
		free(dhcp);
		dhcp = NULL;
 }
 return dhcp;
}

Project: Android

route_netmask(uint32_t ip_in)
{
 /* used to be unsigned long - check if error */
 uint32_t p = ntohl(ip_in);
 uint32_t t;

 if (IN_CLASSA(p))
		t = ~IN_CLASSA_NET;
 else {
 if (IN_CLASSB(p))
			t = ~IN_CLASSB_NET;
 else {
 if (IN_CLASSC(p))
				t = ~IN_CLASSC_NET;
 else
				t = 0;
 }
 }

 while (t & p)
		t >>= 1;

 return (htonl(~t));
}

Project: Android

write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
{
 int fd;
 ssize_t bytes = sizeof(*dhcp);
 const uint8_t *p = dhcp->options;
 const uint8_t *e = p + sizeof(dhcp->options);
 uint8_t l;
 uint8_t o = 0;

 /* We don't write BOOTP leases */
 if (is_bootp(dhcp)) {
		unlink(iface->leasefile);
 return 0;
 }

	syslog(LOG_DEBUG, "%s: writing lease `%s'",
	    iface->name, iface->leasefile);

	fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
#ifdef ANDROID
 if (fd == -1 && errno == EACCES) {
 /* the lease file might have been created when dhcpcd was running as root */
		unlink(iface->leasefile);
		fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
 }
#endif
 if (fd == -1) {
		syslog(LOG_ERR, "%s: open: %m", iface->name);
 return -1;
 }

 /* Only write as much as we need */
 while (p < e) {
		o = *p;
 if (o == DHO_END) {
			bytes = p - (const uint8_t *)dhcp;
 break;
 }
		p++;
 if (o != DHO_PAD) {
			l = *p++;
			p += l;
 }
 }
	bytes = write(fd, dhcp, bytes);
	close(fd);
 return bytes;
}