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