diff --git a/ifchd/ifchd-defines.h b/ifchd/ifchd-defines.h index f8ceeff..a62045c 100644 --- a/ifchd/ifchd-defines.h +++ b/ifchd/ifchd-defines.h @@ -11,28 +11,19 @@ #define MAX_IFACES 10 #include -#include "strlist.h" struct ifchd_client { /* Socket fd, current state, and idle time for connection. */ int fd; int state; int idle_time; - /* - * Per-connection pointers into the command lists. Respectively, the - * topmost item on the list, the current item, and the last item on the - * list. - */ - strlist_t *head, *curl, *last; - /* Lists of nameservers and search domains. Unfortunately they must be - * per-connection, since otherwise seperate clients could race against - * one another to write out unpredictable data. - */ - strlist_t *namesvrs, *domains; /* Symbolic name of the interface associated with a connection. */ char ifnam[IFNAMSIZ]; /* Per-connection buffer. */ char ibuf[MAX_BUF]; + /* ' '-delimited buffers of nameservers and domains */ + char namesvrs[MAX_BUF]; + char domains[MAX_BUF]; }; #endif /* IFCHD_DEFINES_H_ */ diff --git a/ifchd/ifchd.c b/ifchd/ifchd.c index 9be2953..b4fe466 100644 --- a/ifchd/ifchd.c +++ b/ifchd/ifchd.c @@ -49,12 +49,10 @@ #include #include "ifchd-defines.h" -#include "malloc.h" #include "log.h" #include "chroot.h" #include "pidfile.h" #include "signals.h" -#include "strlist.h" #include "ifch_proto.h" #include "strl.h" #include "cap.h" @@ -98,14 +96,6 @@ static pid_t peer_pid; static int gflags_verbose = 0; -static void die_nulstr(strlist_t *p) -{ - if (!p) - suicide("FATAL - NULL passed to die_nulstr"); - if (!p->str) - suicide("FATAL - NULL string in strlist"); -} - static void writeordie(int fd, const char *buf, int len) { if (safe_write(fd, buf, len) == -1) @@ -177,43 +167,71 @@ static int enforce_seccomp(void) return 0; } -/* Abstracts away the details of accept()ing a socket connection. */ -/* Writes out each element in a strlist as an argument to a keyword in - * a file. */ -static void write_resolve_list(const char *keyword, strlist_t *list) -{ - char *buf; - strlist_t *p = list; - unsigned int len; - - if (!keyword || resolv_conf_fd == -1) - return; - - while (p) { - buf = p->str; - len = strlen(buf); - if (len) { - writeordie(resolv_conf_fd, keyword, strlen(keyword)); - writeordie(resolv_conf_fd, buf, strlen(buf)); - writeordie(resolv_conf_fd, "\n", 1); - } - p = p->next; - } -} - /* Writes a new resolv.conf based on the information we have received. */ -static void write_resolve_conf(int idx) +static void write_resolve_conf(struct ifchd_client *cl) { + const static char ns_str[] = "nameserver "; + const static char dom_str[] = "domain "; + const static char srch_str[] = "search "; int r; off_t off; + char buf[MAX_BUF]; if (resolv_conf_fd == -1) return; + if (strlen(cl->namesvrs) == 0) + return; + if (lseek(resolv_conf_fd, 0, SEEK_SET) == -1) return; - write_resolve_list("nameserver ", clients[idx].namesvrs); - write_resolve_list("search ", clients[idx].domains); + char *p = cl->namesvrs; + while (p && (*p != '\0')) { + char *q = strchr(p, ' '); + if (!q) + q = strchr(p, '\0'); + else + *q++ = '\0'; + strlcpy(buf, p, sizeof buf); + + writeordie(resolv_conf_fd, ns_str, strlen(ns_str)); + writeordie(resolv_conf_fd, buf, strlen(buf)); + writeordie(resolv_conf_fd, "\n", 1); + + p = q; + } + + p = cl->domains; + int numdoms = 0; + while (p && (*p != '\0')) { + char *q = strchr(p, ' '); + if (!q) + q = strchr(p, '\0'); + else + *q++ = '\0'; + strlcpy(buf, p, sizeof buf); + + if (numdoms == 0) { + writeordie(resolv_conf_fd, dom_str, strlen(dom_str)); + writeordie(resolv_conf_fd, buf, strlen(buf)); + } else { + if (numdoms == 1) { + writeordie(resolv_conf_fd, "\n", 1); + writeordie(resolv_conf_fd, srch_str, strlen(srch_str)); + writeordie(resolv_conf_fd, buf, strlen(buf)); + } else { + writeordie(resolv_conf_fd, " ", 1); + writeordie(resolv_conf_fd, buf, strlen(buf)); + } + } + + ++numdoms; + p = q; + if (numdoms > 6) + break; + } + writeordie(resolv_conf_fd, "\n", 1); + off = lseek(resolv_conf_fd, 0, SEEK_CUR); if (off == -1) { log_line("write_resolve_conf: lseek returned error: %s\n", @@ -237,55 +255,25 @@ static void write_resolve_conf(int idx) } } -/* Decomposes a ' '-delimited flat character array onto a strlist, then - * calls the given function to perform work on the generated strlist. */ -static void parse_list(int idx, char *str, strlist_t **toplist, - void (*fn)(int)) -{ - char *p, n[256]; - unsigned int i; - strlist_t *newn = 0; - - if (!str || !toplist || !fn) - return; - p = str; - - while (p != '\0') { - memset(n, '\0', sizeof n); - for (i = 0; i < sizeof n - 1 && *p != '\0' && *p != ' '; ++p, ++i) - n[i] = *p; - if (*p == ' ') - ++p; - add_to_strlist(&newn, n); - } - - if (newn) { - free_strlist(*toplist); - *toplist = newn; - } else - return; - - (*fn)(idx); -} - /* XXX: addme */ -static void perform_timezone(int idx, char *str) +static void perform_timezone(struct ifchd_client *cl, char *str) {} /* Add a dns server to the /etc/resolv.conf -- we already have a fd. */ -static void perform_dns(int idx, char *str) +static void perform_dns(struct ifchd_client *cl, char *str) { if (!str || resolv_conf_fd == -1) return; - parse_list(idx, str, &clients[idx].namesvrs, &write_resolve_conf); + strlcpy(cl->namesvrs, str, MAX_BUF); + write_resolve_conf(cl); } /* Updates for print daemons are too non-standard to be useful. */ -static void perform_lprsvr(int idx, char *str) +static void perform_lprsvr(struct ifchd_client *cl, char *str) {} /* Sets machine hostname. */ -static void perform_hostname(int idx, char *str) +static void perform_hostname(struct ifchd_client *cl, char *str) { if (!allow_hostname || !str) return; @@ -293,25 +281,26 @@ static void perform_hostname(int idx, char *str) log_line("sethostname returned %s\n", strerror(errno)); } -/* update "search" in /etc/resolv.conf */ -static void perform_domain(int idx, char *str) +/* update "domain" and "search" in /etc/resolv.conf */ +static void perform_domain(struct ifchd_client *cl, char *str) { if (!str || resolv_conf_fd == -1) return; - parse_list(idx, str, &clients[idx].domains, &write_resolve_conf); + strlcpy(cl->domains, str, MAX_BUF); + write_resolve_conf(cl); } /* I don't think this can be done without a netfilter extension * that isn't in the mainline kernels. */ -static void perform_ipttl(int idx, char *str) +static void perform_ipttl(struct ifchd_client *cl, char *str) {} /* XXX: addme */ -static void perform_ntpsrv(int idx, char *str) +static void perform_ntpsrv(struct ifchd_client *cl, char *str) {} /* Maybe Samba cares about this feature? I don't know. */ -static void perform_wins(int idx, char *str) +static void perform_wins(struct ifchd_client *cl, char *str) {} static void ifchd_client_init(struct ifchd_client *p) @@ -322,11 +311,8 @@ static void ifchd_client_init(struct ifchd_client *p) memset(p->ibuf, 0, sizeof p->ibuf); memset(p->ifnam, 0, sizeof p->ifnam); - p->head = NULL; - p->curl = NULL; - p->last = NULL; - p->namesvrs = NULL; - p->domains = NULL; + memset(p->namesvrs, 0, sizeof p->namesvrs); + memset(p->domains, 0, sizeof p->domains); } static void ifchd_client_wipe(struct ifchd_client *p) @@ -335,9 +321,6 @@ static void ifchd_client_wipe(struct ifchd_client *p) epoll_del(p->fd); close(p->fd); } - free_strlist(p->head); - free_strlist(p->namesvrs); - free_strlist(p->domains); ifchd_client_init(p); } @@ -379,56 +362,43 @@ static void close_idle_sk(void) } } -/* Decomposes a ':'-delimited flat character array onto a strlist. */ -static int stream_onto_list(int i) +/* + * Returns -1 on fatal error. + */ +static int execute_buffer(struct ifchd_client *cl, char *newbuf) { - int e, s; - struct ifchd_client *cl = &clients[i]; + char buf[MAX_BUF * 2]; + char *p = buf, *endp; - for (e = 0, s = 0; cl->ibuf[e] != '\0'; e++) { - if (cl->ibuf[e] == ':') { - /* Zero-length command: skip. */ - if (s == e) { - s = e + 1; - continue; - } - cl->curl = xmalloc(sizeof(strlist_t)); - - if (cl->head == NULL) { - cl->head = cl->curl; - cl->last = NULL; - } - - cl->curl->next = NULL; - if (cl->last != NULL) - cl->last->next = cl->curl; - - cl->curl->str = xmalloc(e - s + 1); - - strlcpy(cl->curl->str, cl->ibuf + s, e - s + 1); - cl->last = cl->curl; - s = e + 1; - } - } - return s; -} - -/* State machine that runs over the command and argument list, - * executing commands. */ -static void execute_list(int i) -{ - char *p; - struct ifchd_client *cl = &clients[i]; + memset(buf, 0, sizeof buf); + strlcat(buf, cl->ibuf, sizeof buf); + strlcat(buf, newbuf, sizeof buf); for (;;) { - if (!cl->curl) - break; - die_nulstr(cl->curl); - - p = cl->curl->str; - - if (gflags_verbose) - log_line("execute_list - p = '%s'", p); + endp = p; + if (cl->state == STATE_NOTHING) { + char *colon = strchr(p, ':'); + if (!colon) + break; + char *semi = strchr(p, ';'); + if (semi && semi < colon) { + log_line("bad syntax: STATE_NOTHING and a ';' came before ':'"); + return -1; + } + *colon = '\0'; + endp = colon + 1; + } else { + char *semi = strchr(p, ';'); + if (!semi) + break; + char *colon = strchr(p, ':'); + if (colon && colon < semi) { + log_line("bad syntax: !STATE_NOTHING and a ':' came before ';'"); + return -1; + } + *semi = '\0'; + endp = semi + 1; + } switch (cl->state) { case STATE_NOTHING: @@ -460,90 +430,75 @@ static void execute_list(int i) cl->state = STATE_NTPSVR; if (strncmp(p, CMD_WINS, sizeof(CMD_WINS)) == 0) cl->state = STATE_WINS; - free_stritem(&cl->curl); break; case STATE_INTERFACE: - perform_interface(i, p); - free_stritem(&cl->curl); + perform_interface(cl, p); cl->state = STATE_NOTHING; break; case STATE_IP: - perform_ip(i, p); - free_stritem(&cl->curl); + perform_ip(cl, p); cl->state = STATE_NOTHING; break; case STATE_SUBNET: - perform_subnet(i, p); - free_stritem(&cl->curl); + perform_subnet(cl, p); cl->state = STATE_NOTHING; break; case STATE_TIMEZONE: - perform_timezone(i, p); - free_stritem(&cl->curl); + perform_timezone(cl, p); cl->state = STATE_NOTHING; break; case STATE_ROUTER: - perform_router(i, p); - free_stritem(&cl->curl); + perform_router(cl, p); cl->state = STATE_NOTHING; break; case STATE_DNS: - perform_dns(i, p); - free_stritem(&cl->curl); + perform_dns(cl, p); cl->state = STATE_NOTHING; break; case STATE_LPRSVR: - perform_lprsvr(i, p); - free_stritem(&cl->curl); + perform_lprsvr(cl, p); cl->state = STATE_NOTHING; break; case STATE_HOSTNAME: - perform_hostname(i, p); - free_stritem(&cl->curl); + perform_hostname(cl, p); cl->state = STATE_NOTHING; break; case STATE_DOMAIN: - perform_domain(i, p); - free_stritem(&cl->curl); + perform_domain(cl, p); cl->state = STATE_NOTHING; break; case STATE_IPTTL: - perform_ipttl(i, p); - free_stritem(&cl->curl); + perform_ipttl(cl, p); cl->state = STATE_NOTHING; break; case STATE_MTU: - perform_mtu(i, p); - free_stritem(&cl->curl); + perform_mtu(cl, p); cl->state = STATE_NOTHING; break; case STATE_BROADCAST: - perform_broadcast(i, p); - free_stritem(&cl->curl); + perform_broadcast(cl, p); cl->state = STATE_NOTHING; break; case STATE_NTPSVR: - perform_ntpsrv(i, p); - free_stritem(&cl->curl); + perform_ntpsrv(cl, p); cl->state = STATE_NOTHING; break; case STATE_WINS: - perform_wins(i, p); - free_stritem(&cl->curl); + perform_wins(cl, p); cl->state = STATE_NOTHING; break; @@ -551,8 +506,13 @@ static void execute_list(int i) log_line("warning: invalid state in dispatch_work\n"); break; } + p = endp; } - cl->head = cl->curl; + size_t remsize = strlen(endp); + if (remsize > MAX_BUF - 1) + return -1; + strlcpy(cl->ibuf, endp, MAX_BUF); + return 0; } /* Opens a non-blocking listening socket with the appropriate properties. */ @@ -687,53 +647,32 @@ static void signal_dispatch() static void process_client_fd(int fd) { + struct ifchd_client *cl = NULL; + int r; char buf[MAX_BUF]; - int r, index, sqidx = -1; + for (int j = 0; j < SOCK_QUEUE; ++j) { if (clients[j].fd == fd) { - sqidx = j; + cl = &clients[j]; break; } } - if (sqidx == -1) + if (!cl) suicide("epoll returned pending read for untracked fd"); - struct ifchd_client *cl = &clients[sqidx]; cl->idle_time = time(NULL); memset(buf, '\0', sizeof buf); - r = safe_read(cl->fd, buf, sizeof buf / 2 - 1); + r = safe_read(cl->fd, buf, sizeof buf - 1); if (r == 0) - goto fail; + return; else if (r < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return; log_line("error reading from client fd: %s", strerror(errno)); + goto fail; } - /* Discard everything and close connection if we risk overflow. - * This approach is maximally conservative... worst case is that - * some client requests will get dropped. */ - index = strlen(cl->ibuf); - if (index + strlen(buf) > sizeof buf - 2) + if (execute_buffer(cl, buf) == -1) goto fail; - - /* Append new stream input avoiding overflow. */ - strlcpy(cl->ibuf + index, buf, sizeof cl->ibuf - index); - - /* Decompose ibuf contents onto strlist. */ - index = stream_onto_list(sqidx); - - /* Remove everything that we've parsed into the list. */ - strlcpy(buf, cl->ibuf + index, sizeof buf); - strlcpy(cl->ibuf, buf, sizeof cl->ibuf); - - /* Now we have a strlist of commands and arguments. - * Decompose and execute it. */ - if (!cl->head) - return; - cl->curl = cl->head; - execute_list(sqidx); return; fail: ifchd_client_wipe(cl); diff --git a/ifchd/linux.c b/ifchd/linux.c index 9541c0e..0cace36 100644 --- a/ifchd/linux.c +++ b/ifchd/linux.c @@ -103,42 +103,42 @@ int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid) return ret; } -void perform_interface(int idx, char *str) +void perform_interface(struct ifchd_client *cl, char *str) { if (!str) return; /* Update interface name. */ - memset(clients[idx].ifnam, '\0', IFNAMSIZ); - strlcpy(clients[idx].ifnam, str, IFNAMSIZ); + memset(cl->ifnam, '\0', IFNAMSIZ); + strlcpy(cl->ifnam, str, IFNAMSIZ); } -static int set_if_flag(int idx, short flag) +static int set_if_flag(struct ifchd_client *cl, short flag) { int fd, ret = -1; struct ifreq ifrt; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) goto out0; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { log_line("%s: (set_if_flag) failed to open interface socket: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); goto out0; } - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) { - log_line("%s: unknown interface: %s\n", clients[idx].ifnam, strerror(errno)); + log_line("%s: unknown interface: %s\n", cl->ifnam, strerror(errno)); goto out1; } if (((ifrt.ifr_flags & flag ) ^ flag) & flag) { - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); ifrt.ifr_flags |= flag; if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) { log_line("%s: failed to set interface flags: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); goto out1; } } else @@ -151,7 +151,7 @@ static int set_if_flag(int idx, short flag) } /* Sets IP address on an interface and brings it up. */ -void perform_ip(int idx, char *str) +void perform_ip(struct ifchd_client *cl, char *str) { int fd; struct in_addr ipaddr; @@ -160,14 +160,14 @@ void perform_ip(int idx, char *str) if (!str) return; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) return; if (!inet_pton(AF_INET, str, &ipaddr)) return; - if (set_if_flag(idx, (IFF_UP | IFF_RUNNING))) + if (set_if_flag(cl, (IFF_UP | IFF_RUNNING))) return; - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); sin.sin_family = AF_INET; sin.sin_addr = ipaddr; @@ -176,17 +176,17 @@ void perform_ip(int idx, char *str) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { log_line("%s: (perform_ip) failed to open interface socket: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); return; } if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0) log_line("%s: failed to configure IP: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); close(fd); } /* Sets the subnet mask on an interface. */ -void perform_subnet(int idx, char *str) +void perform_subnet(struct ifchd_client *cl, char *str) { int fd; struct in_addr subnet; @@ -195,12 +195,12 @@ void perform_subnet(int idx, char *str) if (!str) return; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) return; if (!inet_pton(AF_INET, str, &subnet)) return; - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); sin.sin_family = AF_INET; sin.sin_addr = subnet; @@ -209,19 +209,19 @@ void perform_subnet(int idx, char *str) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { log_line("%s: (perform_ip) failed to open interface socket: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); return; } if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) { sin.sin_addr.s_addr = 0xffffffff; if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) log_line("%s: failed to configure subnet: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); } close(fd); } -void perform_router(int idx, char *str) +void perform_router(struct ifchd_client *cl, char *str) { struct rtentry rt; struct sockaddr_in *dest; @@ -232,7 +232,7 @@ void perform_router(int idx, char *str) if (!str) return; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) return; if (!inet_pton(AF_INET, str, &router)) return; @@ -250,24 +250,24 @@ void perform_router(int idx, char *str) rt.rt_flags = RTF_UP | RTF_GATEWAY; if (mask->sin_addr.s_addr == 0xffffffff) rt.rt_flags |= RTF_HOST; - rt.rt_dev = clients[idx].ifnam; + rt.rt_dev = cl->ifnam; rt.rt_metric = 1; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { log_line("%s: (perform_router) failed to open interface socket: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); return; } if (ioctl(fd, SIOCADDRT, &rt)) { if (errno != EEXIST) log_line("%s: failed to set route: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); } close(fd); } -void perform_mtu(int idx, char *str) +void perform_mtu(struct ifchd_client *cl, char *str) { int fd; unsigned int mtu; @@ -275,26 +275,26 @@ void perform_mtu(int idx, char *str) if (!str) return; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) return; mtu = strtol(str, NULL, 10); ifrt.ifr_mtu = mtu; - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { log_line("%s: (perform_mtu) failed to open interface socket: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); return; } if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0) - log_line("%s: failed to set MTU (%d): %s\n", clients[idx].ifnam, mtu, + log_line("%s: failed to set MTU (%d): %s\n", cl->ifnam, mtu, strerror(errno)); close(fd); } -void perform_broadcast(int idx, char *str) +void perform_broadcast(struct ifchd_client *cl, char *str) { int fd; struct in_addr broadcast; @@ -303,12 +303,12 @@ void perform_broadcast(int idx, char *str) if (!str) return; - if (!is_permitted(clients[idx].ifnam)) + if (!is_permitted(cl->ifnam)) return; if (!inet_pton(AF_INET, str, &broadcast)) return; - strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ); + strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); sin.sin_family = AF_INET; sin.sin_addr = broadcast; @@ -316,11 +316,11 @@ void perform_broadcast(int idx, char *str) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", clients[idx].ifnam, strerror(errno)); + log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", cl->ifnam, strerror(errno)); return; } if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0) log_line("%s: failed to set broadcast: %s\n", - clients[idx].ifnam, strerror(errno)); + cl->ifnam, strerror(errno)); close(fd); } diff --git a/ifchd/linux.h b/ifchd/linux.h index a89b3f3..2faaaa1 100644 --- a/ifchd/linux.h +++ b/ifchd/linux.h @@ -1,6 +1,6 @@ /* linux.h - ifchd Linux-specific functions include * - * Copyright (c) 2004-2010 Nicholas J. Kain + * Copyright (c) 2004-2012 Nicholas J. Kain * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,15 +28,15 @@ #ifndef NJK_IFCHD_LINUX_H_ #define NJK_IFCHD_LINUX_H_ -void clear_if_data(int idx); +void clear_if_data(struct ifchd_client *cl); void initialize_if_data(void); void add_permitted_if(char *s); int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid); -void perform_interface(int idx, char *str); -void perform_ip(int idx, char *str); -void perform_subnet(int idx, char *str); -void perform_router(int idx, char *str); -void perform_mtu(int idx, char *str); -void perform_broadcast(int idx, char *str); +void perform_interface(struct ifchd_client *cl, char *str); +void perform_ip(struct ifchd_client *cl, char *str); +void perform_subnet(struct ifchd_client *cl, char *str); +void perform_router(struct ifchd_client *cl, char *str); +void perform_mtu(struct ifchd_client *cl, char *str); +void perform_broadcast(struct ifchd_client *cl, char *str); #endif diff --git a/ndhc/ifchange.c b/ndhc/ifchange.c index b718225..8650a85 100644 --- a/ndhc/ifchange.c +++ b/ndhc/ifchange.c @@ -57,7 +57,7 @@ static int ifchd_cmd_u8(char *buf, size_t buflen, char *optname, { if (!optdata || optlen < 1) return -1; - return snprintf(buf, buflen, "%s:%c:", optname, *optdata); + return snprintf(buf, buflen, "%s:%c;", optname, *optdata); } static int ifchd_cmd_u16(char *buf, size_t buflen, char *optname, @@ -68,7 +68,7 @@ static int ifchd_cmd_u16(char *buf, size_t buflen, char *optname, uint16_t v; memcpy(&v, optdata, 2); v = ntohs(v); - return snprintf(buf, buflen, "%s:%hu:", optname, v); + return snprintf(buf, buflen, "%s:%hu;", optname, v); } static int ifchd_cmd_s32(char *buf, size_t buflen, char *optname, @@ -79,7 +79,7 @@ static int ifchd_cmd_s32(char *buf, size_t buflen, char *optname, int32_t v; memcpy(&v, optdata, 4); v = ntohl(v); - return snprintf(buf, buflen, "%s:%d:", optname, v); + return snprintf(buf, buflen, "%s:%d;", optname, v); } static int ifchd_cmd_ip(char *buf, size_t buflen, char *optname, @@ -89,7 +89,7 @@ static int ifchd_cmd_ip(char *buf, size_t buflen, char *optname, if (!optdata || optlen < 4) return -1; inet_ntop(AF_INET, optdata, ipbuf, sizeof ipbuf); - return snprintf(buf, buflen, "%s:%s:", optname, ipbuf); + return snprintf(buf, buflen, "%s:%s;", optname, ipbuf); } static int ifchd_cmd_iplist(char *buf, size_t buflen, char *optname, @@ -109,7 +109,10 @@ static int ifchd_cmd_iplist(char *buf, size_t buflen, char *optname, inet_ntop(AF_INET, optdata, ipbuf, sizeof ipbuf); if (buflen < strlen(ipbuf) + (buf - obuf) + 2) break; - buf += snprintf(buf, buflen - (buf - obuf), "%s:", ipbuf); + if (optlen >= 8) + buf += snprintf(buf, buflen - (buf - obuf), "%s:", ipbuf); + else + buf += snprintf(buf, buflen - (buf - obuf), "%s;", ipbuf); optlen -= 4; optdata += 4; } @@ -124,7 +127,7 @@ static int ifchd_cmd_str(char *buf, size_t buflen, char *optname, return -1; buf += snprintf(buf, buflen, "%s:", optname); memcpy(buf, optdata, optlen); - buf[optlen] = ':'; + buf[optlen] = ';'; buf[optlen+1] = '\0'; return (buf - obuf) + optlen + 1; } @@ -193,7 +196,7 @@ void ifchange_deconfig(void) sockfd = open_ifch(); - snprintf(buf, sizeof buf, CMD_INTERFACE ":%s:" CMD_IP ":0.0.0.0:", + snprintf(buf, sizeof buf, CMD_INTERFACE ":%s;" CMD_IP ":0.0.0.0;", client_config.interface); log_line("Resetting %s IP configuration.", client_config.interface); sockwrite(sockfd, buf, strlen(buf)); @@ -210,9 +213,9 @@ static size_t send_client_ip(char *out, size_t olen, struct dhcpmsg *packet) if (!memcmp(&packet->yiaddr, &cfg_packet.yiaddr, sizeof packet->yiaddr)) return 0; inet_ntop(AF_INET, &packet->yiaddr, ip, sizeof ip); - snprintf(ipb, sizeof ipb, "ip:%s:", ip); + snprintf(ipb, sizeof ipb, "ip:%s;", ip); strlcat(out, ipb, olen); - log_line("Sent to ifchd: %s", ipb); + log_line("Sent to ifchd: %s", out); return strlen(ipb); } @@ -249,7 +252,7 @@ void ifchange_bind(struct dhcpmsg *packet) if (!packet) return; - snprintf(buf, sizeof buf, CMD_INTERFACE ":%s:", client_config.interface); + snprintf(buf, sizeof buf, CMD_INTERFACE ":%s;", client_config.interface); tbs |= send_client_ip(buf, sizeof buf, packet); tbs |= send_cmd(buf, sizeof buf, packet, DCODE_SUBNET); tbs |= send_cmd(buf, sizeof buf, packet, DCODE_ROUTER);