1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2018 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/time.h> 30 #ifdef __sun 31 #include <sys/sysmacros.h> 32 #endif 33 34 #include <assert.h> 35 #include <ctype.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #ifdef BSD 41 # include <paths.h> 42 #endif 43 #include <stdarg.h> 44 #include <stdint.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 51 #include "common.h" 52 #include "dhcpcd.h" 53 #include "if-options.h" 54 #include "logerr.h" 55 56 /* Most route(4) messages are less than 256 bytes. */ 57 #define IOVEC_BUFSIZ 256 58 59 ssize_t 60 setvar(char **e, const char *prefix, const char *var, const char *value) 61 { 62 size_t len = strlen(var) + strlen(value) + 3; 63 64 if (prefix) 65 len += strlen(prefix) + 1; 66 if ((*e = malloc(len)) == NULL) { 67 logerr(__func__); 68 return -1; 69 } 70 if (prefix) 71 snprintf(*e, len, "%s_%s=%s", prefix, var, value); 72 else 73 snprintf(*e, len, "%s=%s", var, value); 74 return (ssize_t)len; 75 } 76 77 ssize_t 78 setvard(char **e, const char *prefix, const char *var, size_t value) 79 { 80 81 char buffer[32]; 82 83 snprintf(buffer, sizeof(buffer), "%zu", value); 84 return setvar(e, prefix, var, buffer); 85 } 86 87 ssize_t 88 addvar(char ***e, const char *prefix, const char *var, const char *value) 89 { 90 ssize_t len; 91 92 len = setvar(*e, prefix, var, value); 93 if (len != -1) 94 (*e)++; 95 return (ssize_t)len; 96 } 97 98 ssize_t 99 addvard(char ***e, const char *prefix, const char *var, size_t value) 100 { 101 char buffer[32]; 102 103 snprintf(buffer, sizeof(buffer), "%zu", value); 104 return addvar(e, prefix, var, buffer); 105 } 106 107 const char * 108 hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen) 109 { 110 const unsigned char *hp, *ep; 111 char *p; 112 113 if (buf == NULL) 114 return NULL; 115 116 if (hwlen * 3 > buflen) { 117 errno = ENOBUFS; 118 return NULL; 119 } 120 121 hp = hwaddr; 122 ep = hp + hwlen; 123 p = buf; 124 125 while (hp < ep) { 126 if (hp != hwaddr) 127 *p ++= ':'; 128 p += snprintf(p, 3, "%.2x", *hp++); 129 } 130 *p ++= '\0'; 131 return buf; 132 } 133 134 size_t 135 hwaddr_aton(uint8_t *buffer, const char *addr) 136 { 137 char c[3]; 138 const char *p = addr; 139 uint8_t *bp = buffer; 140 size_t len = 0; 141 142 c[2] = '\0'; 143 while (*p != '\0') { 144 /* Skip separators */ 145 c[0] = *p++; 146 switch (c[0]) { 147 case '\n': /* long duid split on lines */ 148 case ':': /* typical mac address */ 149 case '-': /* uuid */ 150 continue; 151 } 152 c[1] = *p++; 153 /* Ensure that digits are hex */ 154 if (isxdigit((unsigned char)c[0]) == 0 || 155 isxdigit((unsigned char)c[1]) == 0) 156 { 157 errno = EINVAL; 158 return 0; 159 } 160 /* We should have at least two entries 00:01 */ 161 if (len == 0 && *p == '\0') { 162 errno = EINVAL; 163 return 0; 164 } 165 if (bp) 166 *bp++ = (uint8_t)strtol(c, NULL, 16); 167 len++; 168 } 169 return len; 170 } 171 172 size_t 173 read_hwaddr_aton(uint8_t **data, const char *path) 174 { 175 FILE *fp; 176 char *buf; 177 size_t buf_len, len; 178 179 if ((fp = fopen(path, "r")) == NULL) 180 return 0; 181 182 buf = NULL; 183 buf_len = len = 0; 184 *data = NULL; 185 while (getline(&buf, &buf_len, fp) != -1) { 186 if ((len = hwaddr_aton(NULL, buf)) != 0) { 187 if (buf_len >= len) 188 *data = (uint8_t *)buf; 189 else { 190 if ((*data = malloc(len)) == NULL) 191 len = 0; 192 } 193 if (len != 0) 194 (void)hwaddr_aton(*data, buf); 195 if (buf_len < len) 196 free(buf); 197 break; 198 } 199 } 200 fclose(fp); 201 return len; 202 } 203 204 ssize_t 205 recvmsg_realloc(int fd, struct msghdr *msg, int flags) 206 { 207 struct iovec *iov; 208 ssize_t slen; 209 size_t len; 210 void *n; 211 212 assert(msg != NULL); 213 assert(msg->msg_iov != NULL && msg->msg_iovlen > 0); 214 assert((flags & (MSG_PEEK | MSG_TRUNC)) == 0); 215 216 /* Assume we are reallocing the last iovec. */ 217 iov = &msg->msg_iov[msg->msg_iovlen - 1]; 218 219 for (;;) { 220 /* Passing MSG_TRUNC should return the actual size needed. */ 221 slen = recvmsg(fd, msg, flags | MSG_PEEK | MSG_TRUNC); 222 if (slen == -1) 223 return -1; 224 if (!(msg->msg_flags & MSG_TRUNC)) 225 break; 226 227 len = (size_t)slen; 228 229 /* Some kernels return the size of the receive buffer 230 * on truncation, not the actual size needed. 231 * So grow the buffer and try again. */ 232 if (iov->iov_len == len) 233 len++; 234 else if (iov->iov_len > len) 235 break; 236 len = roundup(len, IOVEC_BUFSIZ); 237 if ((n = realloc(iov->iov_base, len)) == NULL) 238 return -1; 239 iov->iov_base = n; 240 iov->iov_len = len; 241 } 242 243 slen = recvmsg(fd, msg, flags); 244 if (slen != -1 && msg->msg_flags & MSG_TRUNC) { 245 /* This should not be possible ... */ 246 errno = ENOBUFS; 247 return -1; 248 } 249 return slen; 250 } 251