18bcf1996Sroy /* SPDX-License-Identifier: BSD-2-Clause */
28fd57d42Sroy /*
38fd57d42Sroy * dhcpcd - DHCP client daemon
4794dfa77Sroy * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
58fd57d42Sroy * All rights reserved
68fd57d42Sroy
78fd57d42Sroy * Redistribution and use in source and binary forms, with or without
88fd57d42Sroy * modification, are permitted provided that the following conditions
98fd57d42Sroy * are met:
108fd57d42Sroy * 1. Redistributions of source code must retain the above copyright
118fd57d42Sroy * notice, this list of conditions and the following disclaimer.
128fd57d42Sroy * 2. Redistributions in binary form must reproduce the above copyright
138fd57d42Sroy * notice, this list of conditions and the following disclaimer in the
148fd57d42Sroy * documentation and/or other materials provided with the distribution.
158fd57d42Sroy *
168fd57d42Sroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178fd57d42Sroy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188fd57d42Sroy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198fd57d42Sroy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208fd57d42Sroy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218fd57d42Sroy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228fd57d42Sroy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238fd57d42Sroy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248fd57d42Sroy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258fd57d42Sroy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268fd57d42Sroy * SUCH DAMAGE.
278fd57d42Sroy */
288fd57d42Sroy
297c187152Sroy #include <sys/stat.h>
308fc24ed9Sroy #include <sys/statvfs.h>
318fd57d42Sroy
328fd57d42Sroy #include <ctype.h>
338fd57d42Sroy #include <errno.h>
347c187152Sroy #include <fcntl.h>
358fd57d42Sroy #include <stdio.h>
368fd57d42Sroy #include <stdlib.h>
377c187152Sroy #include <string.h>
388fd57d42Sroy
398fd57d42Sroy #include "common.h"
408fd57d42Sroy #include "dhcpcd.h"
418fd57d42Sroy #include "if-options.h"
428fd57d42Sroy
438fd57d42Sroy const char *
hwaddr_ntoa(const void * hwaddr,size_t hwlen,char * buf,size_t buflen)448fd57d42Sroy hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
458fd57d42Sroy {
468fd57d42Sroy const unsigned char *hp, *ep;
478fd57d42Sroy char *p;
488fd57d42Sroy
49*f3ce8585Sroy /* Allow a hwlen of 0 to be an empty string. */
50*f3ce8585Sroy if (buf == NULL || buflen == 0) {
51*f3ce8585Sroy errno = ENOBUFS;
528fd57d42Sroy return NULL;
53*f3ce8585Sroy }
548fd57d42Sroy
558fd57d42Sroy if (hwlen * 3 > buflen) {
56*f3ce8585Sroy /* We should still terminate the string just in case. */
57*f3ce8585Sroy buf[0] = '\0';
588fd57d42Sroy errno = ENOBUFS;
598fd57d42Sroy return NULL;
608fd57d42Sroy }
618fd57d42Sroy
628fd57d42Sroy hp = hwaddr;
638fd57d42Sroy ep = hp + hwlen;
648fd57d42Sroy p = buf;
658fd57d42Sroy while (hp < ep) {
668fd57d42Sroy if (hp != hwaddr)
678fd57d42Sroy *p ++= ':';
688fd57d42Sroy p += snprintf(p, 3, "%.2x", *hp++);
698fd57d42Sroy }
708fd57d42Sroy *p ++= '\0';
718fd57d42Sroy return buf;
728fd57d42Sroy }
738fd57d42Sroy
748fd57d42Sroy size_t
hwaddr_aton(uint8_t * buffer,const char * addr)758fd57d42Sroy hwaddr_aton(uint8_t *buffer, const char *addr)
768fd57d42Sroy {
778fd57d42Sroy char c[3];
788fd57d42Sroy const char *p = addr;
798fd57d42Sroy uint8_t *bp = buffer;
808fd57d42Sroy size_t len = 0;
818fd57d42Sroy
828fd57d42Sroy c[2] = '\0';
838798a270Sroy while (*p != '\0') {
848798a270Sroy /* Skip separators */
858fd57d42Sroy c[0] = *p++;
868798a270Sroy switch (c[0]) {
878798a270Sroy case '\n': /* long duid split on lines */
888798a270Sroy case ':': /* typical mac address */
898798a270Sroy case '-': /* uuid */
908fd57d42Sroy continue;
918798a270Sroy }
928fd57d42Sroy c[1] = *p++;
938fd57d42Sroy /* Ensure that digits are hex */
948fd57d42Sroy if (isxdigit((unsigned char)c[0]) == 0 ||
958fd57d42Sroy isxdigit((unsigned char)c[1]) == 0)
968fd57d42Sroy {
978fd57d42Sroy errno = EINVAL;
988fd57d42Sroy return 0;
998fd57d42Sroy }
1008fd57d42Sroy /* We should have at least two entries 00:01 */
1018fd57d42Sroy if (len == 0 && *p == '\0') {
1028fd57d42Sroy errno = EINVAL;
1038fd57d42Sroy return 0;
1048fd57d42Sroy }
1058fd57d42Sroy if (bp)
1068fd57d42Sroy *bp++ = (uint8_t)strtol(c, NULL, 16);
1078fd57d42Sroy len++;
1088fd57d42Sroy }
1098fd57d42Sroy return len;
1108fd57d42Sroy }
1118fd57d42Sroy
1127c187152Sroy ssize_t
readfile(const char * file,void * data,size_t len)1137c187152Sroy readfile(const char *file, void *data, size_t len)
1148fd57d42Sroy {
1157c187152Sroy int fd;
1167c187152Sroy ssize_t bytes;
1178fd57d42Sroy
1187c187152Sroy fd = open(file, O_RDONLY);
1197c187152Sroy if (fd == -1)
1207c187152Sroy return -1;
1217c187152Sroy bytes = read(fd, data, len);
1227c187152Sroy close(fd);
1237c187152Sroy if ((size_t)bytes == len) {
1247c187152Sroy errno = ENOBUFS;
1257c187152Sroy return -1;
1268fd57d42Sroy }
1277c187152Sroy return bytes;
1287c187152Sroy }
1297c187152Sroy
1307c187152Sroy ssize_t
writefile(const char * file,mode_t mode,const void * data,size_t len)1317c187152Sroy writefile(const char *file, mode_t mode, const void *data, size_t len)
1327c187152Sroy {
1337c187152Sroy int fd;
1347c187152Sroy ssize_t bytes;
1357c187152Sroy
1367c187152Sroy fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
1377c187152Sroy if (fd == -1)
1387c187152Sroy return -1;
1397c187152Sroy bytes = write(fd, data, len);
1407c187152Sroy close(fd);
1417c187152Sroy return bytes;
1427c187152Sroy }
1437c187152Sroy
1447c187152Sroy int
filemtime(const char * file,time_t * time)1457c187152Sroy filemtime(const char *file, time_t *time)
1467c187152Sroy {
1477c187152Sroy struct stat st;
1487c187152Sroy
1497c187152Sroy if (stat(file, &st) == -1)
1507c187152Sroy return -1;
1517c187152Sroy *time = st.st_mtime;
1527c187152Sroy return 0;
1537c187152Sroy }
1547c187152Sroy
1557c187152Sroy /* Handy routine to read very long lines in text files.
1567c187152Sroy * This means we read the whole line and avoid any nasty buffer overflows.
1577c187152Sroy * We strip leading space and avoid comment lines, making the code that calls
1587c187152Sroy * us smaller. */
1597c187152Sroy char *
get_line(char ** __restrict buf,ssize_t * __restrict buflen)1607c187152Sroy get_line(char ** __restrict buf, ssize_t * __restrict buflen)
1617c187152Sroy {
1627c187152Sroy char *p, *c;
1637c187152Sroy bool quoted;
1647c187152Sroy
1657c187152Sroy do {
1667c187152Sroy p = *buf;
1677c187152Sroy if (*buf == NULL)
1687c187152Sroy return NULL;
1697c187152Sroy c = memchr(*buf, '\n', (size_t)*buflen);
1707c187152Sroy if (c == NULL) {
1717c187152Sroy c = memchr(*buf, '\0', (size_t)*buflen);
1727c187152Sroy if (c == NULL)
1737c187152Sroy return NULL;
1747c187152Sroy *buflen = c - *buf;
1757c187152Sroy *buf = NULL;
1767c187152Sroy } else {
1777c187152Sroy *c++ = '\0';
1787c187152Sroy *buflen -= c - *buf;
1797c187152Sroy *buf = c;
1807c187152Sroy }
1817c187152Sroy for (; *p == ' ' || *p == '\t'; p++)
1827c187152Sroy ;
1837c187152Sroy } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
1847c187152Sroy
1857c187152Sroy /* Strip embedded comments unless in a quoted string or escaped */
1867c187152Sroy quoted = false;
1877c187152Sroy for (c = p; *c != '\0'; c++) {
1887c187152Sroy if (*c == '\\') {
1897c187152Sroy c++; /* escaped */
1907c187152Sroy continue;
1917c187152Sroy }
1927c187152Sroy if (*c == '"')
1937c187152Sroy quoted = !quoted;
1947c187152Sroy else if (*c == '#' && !quoted) {
1957c187152Sroy *c = '\0';
1968fd57d42Sroy break;
1978fd57d42Sroy }
1988fd57d42Sroy }
1997c187152Sroy return p;
2008fd57d42Sroy }
2018fc24ed9Sroy
2027c187152Sroy
2038fc24ed9Sroy int
is_root_local(void)2048fc24ed9Sroy is_root_local(void)
2058fc24ed9Sroy {
2068fc24ed9Sroy #ifdef ST_LOCAL
2078fc24ed9Sroy struct statvfs vfs;
2088fc24ed9Sroy
2098fc24ed9Sroy if (statvfs("/", &vfs) == -1)
2108fc24ed9Sroy return -1;
2118fc24ed9Sroy return vfs.f_flag & ST_LOCAL ? 1 : 0;
2128fc24ed9Sroy #else
2138fc24ed9Sroy errno = ENOTSUP;
2148fc24ed9Sroy return -1;
2158fc24ed9Sroy #endif
2168fc24ed9Sroy }
217