1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley 2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is free software; you can redistribute it and/or modify 4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat it under the terms of the GNU General Public License as published by 5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat the Free Software Foundation; version 2 dated June, 1991, or 6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (at your option) version 3 dated 29 June, 2007. 7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is distributed in the hope that it will be useful, 9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat but WITHOUT ANY WARRANTY; without even the implied warranty of 10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat GNU General Public License for more details. 12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat You should have received a copy of the GNU General Public License 14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat along with this program. If not, see <http://www.gnu.org/licenses/>. 15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h" 18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* This file has code to fork a helper process which recieves data via a pipe 20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat shared with the main process and which is responsible for calling a script when 21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat DHCP leases change. 22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat The helper process is forked before the main process drops root, so it retains root 24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat privs to pass on to the script. For this reason it tries to be paranoid about 25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat data received from the main process, in case that has been compromised. We don't 26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat want the helper to give an attacker root. In particular, the script to be run is 27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat not settable via the pipe, once the fork has taken place it is not alterable by the 28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat main process. 29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT) 32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void my_setenv(const char *name, const char *value, int *error); 34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct script_data 36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char action, hwaddr_len, hwaddr_type; 38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char clid_len, hostname_len, uclass_len, vclass_len, shost_len; 39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr addr, giaddr; 40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int remaining_time; 41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC 42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int length; 43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat time_t expires; 45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char hwaddr[DHCP_CHADDR_MAX]; 47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char interface[IF_NAMESIZE]; 48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}; 49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct script_data *buf = NULL; 51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic size_t bytes_in_buf = 0, buf_size = 0; 52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) 54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pid_t pid; 56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int i, pipefd[2]; 57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sigaction sigact; 58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* create the pipe through which the main program sends us commands, 60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat then fork our process. */ 61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1) 62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(err_fd, EVENT_PIPE_ERR, errno); 64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat _exit(0); 65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (pid != 0) 68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(pipefd[0]); /* close reader side */ 70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return pipefd[1]; 71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* ignore SIGTERM, so that we can clean up when the main process gets hit 74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat and SIGALRM so that we can use sleep() */ 75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sigact.sa_handler = SIG_IGN; 76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sigact.sa_flags = 0; 77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sigemptyset(&sigact.sa_mask); 78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sigaction(SIGTERM, &sigact, NULL); 79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sigaction(SIGALRM, &sigact, NULL); 80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(daemon->options & OPT_DEBUG) && uid != 0) 82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat gid_t dummy; 84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (setgroups(0, &dummy) == -1 || 85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setgid(gid) == -1 || 86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setuid(uid) == -1) 87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_NO_FORK) 89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* send error to daemon process if no-fork */ 90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(event_fd, EVENT_HUSER_ERR, errno); 91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* kill daemon */ 94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(event_fd, EVENT_DIE, 0); 95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* return error */ 96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(err_fd, EVENT_HUSER_ERR, errno); 97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat _exit(0); 99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* close all the sockets etc, we don't need them here. This closes err_fd, so that 103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat main process can return. */ 104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (max_fd--; max_fd >= 0; max_fd--) 105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && 106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd) 107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(max_fd); 108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* loop here */ 110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while(1) 111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct script_data data; 113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *p, *action_str, *hostname = NULL; 114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *buf = (unsigned char *)daemon->namebuff; 115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int err = 0; 116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* we read zero bytes when pipe closed: this is our signal to exit */ 118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1)) 119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat _exit(0); 120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.action == ACTION_DEL) 122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat action_str = "del"; 123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (data.action == ACTION_ADD) 124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat action_str = "add"; 125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME) 126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat action_str = "old"; 127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* stringify MAC into dhcp_buff */ 131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p = daemon->dhcp_buff; 132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) 133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sprintf(p, "%.2x-", data.hwaddr_type); 134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) 135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sprintf(p, "%.2x", data.hwaddr[i]); 137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (i != data.hwaddr_len - 1) 138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sprintf(p, ":"); 139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* and CLID into packet */ 142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(pipefd[0], buf, data.clid_len, 1)) 143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (p = daemon->packet, i = 0; i < data.clid_len; i++) 145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sprintf(p, "%.2x", buf[i]); 147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (i != data.clid_len - 1) 148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sprintf(p, ":"); 149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* and expiry or length into dhcp_buff2 */ 152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC 153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sprintf(daemon->dhcp_buff2, "%u ", data.length); 154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long)data.expires); 156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(pipefd[0], buf, 159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat data.hostname_len + data.uclass_len + data.vclass_len + data.shost_len, 1)) 160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* possible fork errors are all temporary resource problems */ 163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM)) 164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sleep(2); 165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (pid == -1) 167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* wait for child to complete */ 170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (pid != 0) 171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* reap our children's children, if necessary */ 173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int status; 176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pid_t rc = wait(&status); 177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rc == pid) 179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* On error send event back to main process for logging */ 181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (WIFSIGNALED(status)) 182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(event_fd, EVENT_KILLED, WTERMSIG(status)); 183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status)); 185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rc == -1 && errno != EINTR) 189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.clid_len != 0) 196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err); 197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strlen(data.interface) != 0) 199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_INTERFACE", data.interface, &err); 200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC 202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err); 203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); 205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.vclass_len != 0) 208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf[data.vclass_len - 1] = 0; /* don't trust zero-term */ 210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* cannot have = chars in env - truncate if found . */ 211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((p = strchr((char *)buf, '='))) 212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p = 0; 213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_VENDOR_CLASS", (char *)buf, &err); 214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf += data.vclass_len; 215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.uclass_len != 0) 218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *end = buf + data.uclass_len; 220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf[data.uclass_len - 1] = 0; /* don't trust zero-term */ 221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (i = 0; buf < end;) 223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t len = strlen((char *)buf) + 1; 225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((p = strchr((char *)buf, '='))) 226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p = 0; 227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strlen((char *)buf) != 0) 228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i++); 230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv(daemon->dhcp_buff2, (char *)buf, &err); 231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf += len; 233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.shost_len != 0) 237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf[data.shost_len - 1] = 0; /* don't trust zero-term */ 239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* cannot have = chars in env - truncate if found . */ 240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((p = strchr((char *)buf, '='))) 241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p = 0; 242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_SUPPLIED_HOSTNAME", (char *)buf, &err); 243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf += data.shost_len; 244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.giaddr.s_addr != 0) 247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err); 248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time); 250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err); 251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.hostname_len != 0) 253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *dot; 255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname = (char *)buf; 256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname[data.hostname_len - 1] = 0; 257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!legal_hostname(hostname)) 258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname = NULL; 259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if ((dot = strchr(hostname, '.'))) 260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_DOMAIN", dot+1, &err); 262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *dot = 0; 263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (data.action == ACTION_OLD_HOSTNAME && hostname) 267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err); 269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname = NULL; 270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* we need to have the event_fd around if exec fails */ 273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((i = fcntl(event_fd, F_GETFD)) != -1) 274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat fcntl(event_fd, F_SETFD, i | FD_CLOEXEC); 275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(pipefd[0]); 276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p = strrchr(daemon->lease_change_command, '/'); 278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (err == 0) 279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat execl(daemon->lease_change_command, 281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p ? p+1 : daemon->lease_change_command, 282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL); 283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat err = errno; 284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* failed, send event so the main process logs the problem */ 286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_event(event_fd, EVENT_EXEC_ERR, err); 287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat _exit(0); 288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void my_setenv(const char *name, const char *value, int *error) 292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (*error == 0 && setenv(name, value, 1) != 0) 294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *error = errno; 295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* pack up lease data into a buffer */ 298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now) 299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *p; 301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t size; 302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0; 303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int uclass_len = 0, shost_len = 0; 304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* no script */ 306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->helperfd == -1) 307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->vendorclass) 310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat vclass_len = lease->vendorclass_len; 311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->userclass) 312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat uclass_len = lease->userclass_len; 313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->supplied_hostname) 314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat shost_len = lease->supplied_hostname_len; 315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->clid) 316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat clid_len = lease->clid_len; 317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (hostname) 318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname_len = strlen(hostname) + 1; 319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size = sizeof(struct script_data) + clid_len + vclass_len + uclass_len + shost_len + hostname_len; 321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size > buf_size) 323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct script_data *new; 325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* start with reasonable size, will almost never need extending. */ 327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size < sizeof(struct script_data) + 200) 328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size = sizeof(struct script_data) + 200; 329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(new = whine_malloc(size))) 331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (buf) 333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(buf); 334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf = new; 335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf_size = size; 336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->action = action; 339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->hwaddr_len = lease->hwaddr_len; 340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->hwaddr_type = lease->hwaddr_type; 341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->clid_len = clid_len; 342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->vclass_len = vclass_len; 343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->uclass_len = uclass_len; 344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->shost_len = shost_len; 345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->hostname_len = hostname_len; 346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->addr = lease->addr; 347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->giaddr = lease->giaddr; 348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len); 349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->interface[0] = 0; 350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_LINUX_NETWORK 351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->last_interface != 0) 352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifreq ifr; 354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ifr.ifr_ifindex = lease->last_interface; 355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) != -1) 356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncpy(buf->interface, ifr.ifr_name, IF_NAMESIZE); 357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lease->last_interface != 0) 360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_indextoname(lease->last_interface, buf->interface); 361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC 364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->length = lease->length; 365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->expires = lease->expires; 367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buf->remaining_time = (unsigned int)difftime(lease->expires, now); 369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p = (unsigned char *)(buf+1); 371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (clid_len != 0) 372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, lease->clid, clid_len); 374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += clid_len; 375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (vclass_len != 0) 377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, lease->vendorclass, vclass_len); 379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += vclass_len; 380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (uclass_len != 0) 382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, lease->userclass, uclass_len); 384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += uclass_len; 385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (shost_len != 0) 387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, lease->supplied_hostname, shost_len); 389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += shost_len; 390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (hostname_len != 0) 392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, hostname, hostname_len); 394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += hostname_len; 395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat bytes_in_buf = p - (unsigned char *)buf; 398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint helper_buf_empty(void) 401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return bytes_in_buf == 0; 403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid helper_write(void) 406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t rc; 408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (bytes_in_buf == 0) 410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1) 413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (bytes_in_buf != (size_t)rc) 415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memmove(buf, buf + rc, bytes_in_buf - rc); 416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat bytes_in_buf -= rc; 417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (errno == EAGAIN || errno == EINTR) 421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat bytes_in_buf = 0; 423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 429