1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
2
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License as published by
5   the Free Software Foundation; version 2 dated June, 1991, or
6   (at your option) version 3 dated 29 June, 2007.
7
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   GNU General Public License for more details.
12
13   You should have received a copy of the GNU General Public License
14   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_SCRIPT
20
21/* This file has code to fork a helper process which recieves data via a pipe
22   shared with the main process and which is responsible for calling a script when
23   DHCP leases change.
24
25   The helper process is forked before the main process drops root, so it retains root
26   privs to pass on to the script. For this reason it tries to be paranoid about
27   data received from the main process, in case that has been compromised. We don't
28   want the helper to give an attacker root. In particular, the script to be run is
29   not settable via the pipe, once the fork has taken place it is not alterable by the
30   main process.
31*/
32
33static void my_setenv(const char *name, const char *value, int *error);
34static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err);
35
36#ifdef HAVE_LUASCRIPT
37#define LUA_COMPAT_ALL
38#include <lua.h>
39#include <lualib.h>
40#include <lauxlib.h>
41
42#ifndef lua_open
43#define lua_open()     luaL_newstate()
44#endif
45
46lua_State *lua;
47
48static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
49#endif
50
51
52struct script_data
53{
54  int flags;
55  int action, hwaddr_len, hwaddr_type;
56  int clid_len, hostname_len, ed_len;
57  struct in_addr addr, giaddr;
58  unsigned int remaining_time;
59#ifdef HAVE_BROKEN_RTC
60  unsigned int length;
61#else
62  time_t expires;
63#endif
64#ifdef HAVE_TFTP
65  off_t file_len;
66#endif
67#ifdef HAVE_IPV6
68  struct in6_addr addr6;
69#endif
70#ifdef HAVE_DHCP6
71  int iaid, vendorclass_count;
72#endif
73  unsigned char hwaddr[DHCP_CHADDR_MAX];
74  char interface[IF_NAMESIZE];
75};
76
77static struct script_data *buf = NULL;
78static size_t bytes_in_buf = 0, buf_size = 0;
79
80int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
81{
82  pid_t pid;
83  int i, pipefd[2];
84  struct sigaction sigact;
85
86  /* create the pipe through which the main program sends us commands,
87     then fork our process. */
88  if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
89    {
90      send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
91      _exit(0);
92    }
93
94  if (pid != 0)
95    {
96      close(pipefd[0]); /* close reader side */
97      return pipefd[1];
98    }
99
100  /* ignore SIGTERM, so that we can clean up when the main process gets hit
101     and SIGALRM so that we can use sleep() */
102  sigact.sa_handler = SIG_IGN;
103  sigact.sa_flags = 0;
104  sigemptyset(&sigact.sa_mask);
105  sigaction(SIGTERM, &sigact, NULL);
106  sigaction(SIGALRM, &sigact, NULL);
107
108  if (!option_bool(OPT_DEBUG) && uid != 0)
109    {
110      gid_t dummy;
111      if (setgroups(0, &dummy) == -1 ||
112	  setgid(gid) == -1 ||
113	  setuid(uid) == -1)
114	{
115	  if (option_bool(OPT_NO_FORK))
116	    /* send error to daemon process if no-fork */
117	    send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
118	  else
119	    {
120	      /* kill daemon */
121	      send_event(event_fd, EVENT_DIE, 0, NULL);
122	      /* return error */
123	      send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
124	    }
125	  _exit(0);
126	}
127    }
128
129  /* close all the sockets etc, we don't need them here.
130     Don't close err_fd, in case the lua-init fails.
131     Note that we have to do this before lua init
132     so we don't close any lua fds. */
133  for (max_fd--; max_fd >= 0; max_fd--)
134    if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
135	max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
136	max_fd != event_fd && max_fd != err_fd)
137      close(max_fd);
138
139#ifdef HAVE_LUASCRIPT
140  if (daemon->luascript)
141    {
142      const char *lua_err = NULL;
143      lua = lua_open();
144      luaL_openlibs(lua);
145
146      /* get Lua to load our script file */
147      if (luaL_dofile(lua, daemon->luascript) != 0)
148	lua_err = lua_tostring(lua, -1);
149      else
150	{
151	  lua_getglobal(lua, "lease");
152	  if (lua_type(lua, -1) != LUA_TFUNCTION)
153	    lua_err = _("lease() function missing in Lua script");
154	}
155
156      if (lua_err)
157	{
158	  if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
159	    /* send error to daemon process if no-fork */
160	    send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
161	  else
162	    {
163	      /* kill daemon */
164	      send_event(event_fd, EVENT_DIE, 0, NULL);
165	      /* return error */
166	      send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
167	    }
168	  _exit(0);
169	}
170
171      lua_pop(lua, 1);  /* remove nil from stack */
172      lua_getglobal(lua, "init");
173      if (lua_type(lua, -1) == LUA_TFUNCTION)
174	lua_call(lua, 0, 0);
175      else
176	lua_pop(lua, 1);  /* remove nil from stack */
177    }
178#endif
179
180  /* All init done, close our copy of the error pipe, so that main process can return */
181  if (err_fd != -1)
182    close(err_fd);
183
184  /* loop here */
185  while(1)
186    {
187      struct script_data data;
188      char *p, *action_str, *hostname = NULL, *domain = NULL;
189      unsigned char *buf = (unsigned char *)daemon->namebuff;
190      unsigned char *end, *extradata, *alloc_buff = NULL;
191      int is6, err = 0;
192
193      free(alloc_buff);
194
195      /* we read zero bytes when pipe closed: this is our signal to exit */
196      if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
197	{
198#ifdef HAVE_LUASCRIPT
199	  if (daemon->luascript)
200	    {
201	      lua_getglobal(lua, "shutdown");
202	      if (lua_type(lua, -1) == LUA_TFUNCTION)
203		lua_call(lua, 0, 0);
204	    }
205#endif
206	  _exit(0);
207	}
208
209      is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
210
211      if (data.action == ACTION_DEL)
212	action_str = "del";
213      else if (data.action == ACTION_ADD)
214	action_str = "add";
215      else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
216	action_str = "old";
217      else if (data.action == ACTION_TFTP)
218	{
219	  action_str = "tftp";
220	  is6 = (data.flags != AF_INET);
221	}
222      else
223	continue;
224
225
226      /* stringify MAC into dhcp_buff */
227      p = daemon->dhcp_buff;
228      if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
229	p += sprintf(p, "%.2x-", data.hwaddr_type);
230      for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
231	{
232	  p += sprintf(p, "%.2x", data.hwaddr[i]);
233	  if (i != data.hwaddr_len - 1)
234	    p += sprintf(p, ":");
235	}
236
237      /* supplied data may just exceed normal buffer (unlikely) */
238      if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
239	  !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
240	continue;
241
242      if (!read_write(pipefd[0], buf,
243		      data.hostname_len + data.ed_len + data.clid_len, 1))
244	continue;
245
246      /* CLID into packet */
247      for (p = daemon->packet, i = 0; i < data.clid_len; i++)
248	{
249	  p += sprintf(p, "%.2x", buf[i]);
250	  if (i != data.clid_len - 1)
251	      p += sprintf(p, ":");
252	}
253
254#ifdef HAVE_DHCP6
255      if (is6)
256	{
257	  /* or IAID and server DUID for IPv6 */
258	  sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
259	  for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
260	    {
261	      p += sprintf(p, "%.2x", daemon->duid[i]);
262	      if (i != daemon->duid_len - 1)
263		p += sprintf(p, ":");
264	    }
265
266	}
267#endif
268
269      buf += data.clid_len;
270
271      if (data.hostname_len != 0)
272	{
273	  char *dot;
274	  hostname = (char *)buf;
275	  hostname[data.hostname_len - 1] = 0;
276	  if (data.action != ACTION_TFTP)
277	    {
278	      if (!legal_hostname(hostname))
279		hostname = NULL;
280	      else if ((dot = strchr(hostname, '.')))
281		{
282		  domain = dot+1;
283		  *dot = 0;
284		}
285	    }
286	}
287
288      extradata = buf + data.hostname_len;
289
290      if (!is6)
291	inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
292#ifdef HAVE_DHCP6
293      else
294	inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
295#endif
296
297#ifdef HAVE_TFTP
298      /* file length */
299      if (data.action == ACTION_TFTP)
300	sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
301#endif
302
303#ifdef HAVE_LUASCRIPT
304      if (daemon->luascript)
305	{
306	  if (data.action == ACTION_TFTP)
307	    {
308	      lua_getglobal(lua, "tftp");
309	      if (lua_type(lua, -1) != LUA_TFUNCTION)
310		lua_pop(lua, 1); /* tftp function optional */
311	      else
312		{
313		  lua_pushstring(lua, action_str); /* arg1 - action */
314		  lua_newtable(lua);               /* arg2 - data table */
315		  lua_pushstring(lua, daemon->addrbuff);
316		  lua_setfield(lua, -2, "destination_address");
317		  lua_pushstring(lua, hostname);
318		  lua_setfield(lua, -2, "file_name");
319		  lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
320		  lua_setfield(lua, -2, "file_size");
321		  lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
322		}
323	    }
324	  else
325	    {
326	      lua_getglobal(lua, "lease");     /* function to call */
327	      lua_pushstring(lua, action_str); /* arg1 - action */
328	      lua_newtable(lua);               /* arg2 - data table */
329
330	      if (is6)
331		{
332		  lua_pushstring(lua, daemon->packet);
333		  lua_setfield(lua, -2, "client_duid");
334		  lua_pushstring(lua, daemon->dhcp_packet.iov_base);
335		  lua_setfield(lua, -2, "server_duid");
336		  lua_pushstring(lua, daemon->dhcp_buff3);
337		  lua_setfield(lua, -2, "iaid");
338		}
339
340	      if (!is6 && data.clid_len != 0)
341		{
342		  lua_pushstring(lua, daemon->packet);
343		  lua_setfield(lua, -2, "client_id");
344		}
345
346	      if (strlen(data.interface) != 0)
347		{
348		  lua_pushstring(lua, data.interface);
349		  lua_setfield(lua, -2, "interface");
350		}
351
352#ifdef HAVE_BROKEN_RTC
353	      lua_pushnumber(lua, data.length);
354	      lua_setfield(lua, -2, "lease_length");
355#else
356	      lua_pushnumber(lua, data.expires);
357	      lua_setfield(lua, -2, "lease_expires");
358#endif
359
360	      if (hostname)
361		{
362		  lua_pushstring(lua, hostname);
363		  lua_setfield(lua, -2, "hostname");
364		}
365
366	      if (domain)
367		{
368		  lua_pushstring(lua, domain);
369		  lua_setfield(lua, -2, "domain");
370		}
371
372	      end = extradata + data.ed_len;
373	      buf = extradata;
374
375	      if (!is6)
376		buf = grab_extradata_lua(buf, end, "vendor_class");
377#ifdef HAVE_DHCP6
378	      else  if (data.vendorclass_count != 0)
379		{
380		  sprintf(daemon->dhcp_buff2, "vendor_class_id");
381		  buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
382		  for (i = 0; i < data.vendorclass_count - 1; i++)
383		    {
384		      sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
385		      buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
386		    }
387		}
388#endif
389
390	      buf = grab_extradata_lua(buf, end, "supplied_hostname");
391
392	      if (!is6)
393		{
394		  buf = grab_extradata_lua(buf, end, "cpewan_oui");
395		  buf = grab_extradata_lua(buf, end, "cpewan_serial");
396		  buf = grab_extradata_lua(buf, end, "cpewan_class");
397		  buf = grab_extradata_lua(buf, end, "circuit_id");
398		  buf = grab_extradata_lua(buf, end, "subscriber_id");
399		  buf = grab_extradata_lua(buf, end, "remote_id");
400		}
401
402	      buf = grab_extradata_lua(buf, end, "tags");
403
404	      if (is6)
405		buf = grab_extradata_lua(buf, end, "relay_address");
406	      else if (data.giaddr.s_addr != 0)
407		{
408		  lua_pushstring(lua, inet_ntoa(data.giaddr));
409		  lua_setfield(lua, -2, "relay_address");
410		}
411
412	      for (i = 0; buf; i++)
413		{
414		  sprintf(daemon->dhcp_buff2, "user_class%i", i);
415		  buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
416		}
417
418	      if (data.action != ACTION_DEL && data.remaining_time != 0)
419		{
420		  lua_pushnumber(lua, data.remaining_time);
421		  lua_setfield(lua, -2, "time_remaining");
422		}
423
424	      if (data.action == ACTION_OLD_HOSTNAME && hostname)
425		{
426		  lua_pushstring(lua, hostname);
427		  lua_setfield(lua, -2, "old_hostname");
428		}
429
430	      if (!is6 || data.hwaddr_len != 0)
431		{
432		  lua_pushstring(lua, daemon->dhcp_buff);
433		  lua_setfield(lua, -2, "mac_address");
434		}
435
436	      lua_pushstring(lua, daemon->addrbuff);
437	      lua_setfield(lua, -2, "ip_address");
438
439	      lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
440	    }
441	}
442#endif
443
444      /* no script, just lua */
445      if (!daemon->lease_change_command)
446	continue;
447
448      /* possible fork errors are all temporary resource problems */
449      while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
450	sleep(2);
451
452      if (pid == -1)
453	continue;
454
455      /* wait for child to complete */
456      if (pid != 0)
457	{
458	  /* reap our children's children, if necessary */
459	  while (1)
460	    {
461	      int status;
462	      pid_t rc = wait(&status);
463
464	      if (rc == pid)
465		{
466		  /* On error send event back to main process for logging */
467		  if (WIFSIGNALED(status))
468		    send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
469		  else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
470		    send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
471		  break;
472		}
473
474	      if (rc == -1 && errno != EINTR)
475		break;
476	    }
477
478	  continue;
479	}
480
481      if (data.action != ACTION_TFTP)
482	{
483#ifdef HAVE_DHCP6
484	  my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
485	  my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
486	  my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
487#endif
488
489	  my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
490	  my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
491
492#ifdef HAVE_BROKEN_RTC
493	  sprintf(daemon->dhcp_buff2, "%u", data.length);
494	  my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
495#else
496	  sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
497	  my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
498#endif
499
500	  my_setenv("DNSMASQ_DOMAIN", domain, &err);
501
502	  end = extradata + data.ed_len;
503	  buf = extradata;
504
505	  if (!is6)
506	    buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
507#ifdef HAVE_DHCP6
508	  else
509	    {
510	      if (data.vendorclass_count != 0)
511		{
512		  buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
513		  for (i = 0; i < data.vendorclass_count - 1; i++)
514		    {
515		      sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
516		      buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
517		    }
518		}
519	    }
520#endif
521
522	  buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
523
524	  if (!is6)
525	    {
526	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
527	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
528	      buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
529	      buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
530	      buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
531	      buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
532	    }
533
534	  buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
535
536	  if (is6)
537	    buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
538	  else
539	    my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
540
541	  for (i = 0; buf; i++)
542	    {
543	      sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
544	      buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
545	    }
546
547	  sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
548	  my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
549
550	  my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
551	  if (data.action == ACTION_OLD_HOSTNAME)
552	    hostname = NULL;
553	}
554
555      my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
556
557      /* we need to have the event_fd around if exec fails */
558      if ((i = fcntl(event_fd, F_GETFD)) != -1)
559	fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
560      close(pipefd[0]);
561
562      p =  strrchr(daemon->lease_change_command, '/');
563      if (err == 0)
564	{
565	  execl(daemon->lease_change_command,
566		p ? p+1 : daemon->lease_change_command,
567		action_str, is6 ? daemon->packet : daemon->dhcp_buff,
568		daemon->addrbuff, hostname, (char*)NULL);
569	  err = errno;
570	}
571      /* failed, send event so the main process logs the problem */
572      send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
573      _exit(0);
574    }
575}
576
577static void my_setenv(const char *name, const char *value, int *error)
578{
579  if (*error == 0)
580    {
581      if (!value)
582	unsetenv(name);
583      else if (setenv(name, value, 1) != 0)
584	*error = errno;
585    }
586}
587
588static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err)
589{
590  unsigned char *next = NULL;
591  char *val = NULL;
592
593  if (buf && (buf != end))
594    {
595      for (next = buf; ; next++)
596	if (next == end)
597	  {
598	    next = NULL;
599	    break;
600	  }
601	else if (*next == 0)
602	  break;
603
604      if (next && (next != buf))
605	{
606	  char *p;
607	  /* No "=" in value */
608	  if ((p = strchr((char *)buf, '=')))
609	    *p = 0;
610	  val = (char *)buf;
611	}
612    }
613
614  my_setenv(env, val, err);
615
616  return next ? next + 1 : NULL;
617}
618
619#ifdef HAVE_LUASCRIPT
620static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
621{
622  unsigned char *next;
623
624  if (!buf || (buf == end))
625    return NULL;
626
627  for (next = buf; *next != 0; next++)
628    if (next == end)
629      return NULL;
630
631  if (next != buf)
632    {
633      lua_pushstring(lua,  (char *)buf);
634      lua_setfield(lua, -2, field);
635    }
636
637  return next + 1;
638}
639#endif
640
641static void buff_alloc(size_t size)
642{
643  if (size > buf_size)
644    {
645      struct script_data *new;
646
647      /* start with reasonable size, will almost never need extending. */
648      if (size < sizeof(struct script_data) + 200)
649	size = sizeof(struct script_data) + 200;
650
651      if (!(new = whine_malloc(size)))
652	return;
653      if (buf)
654	free(buf);
655      buf = new;
656      buf_size = size;
657    }
658}
659
660/* pack up lease data into a buffer */
661void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
662{
663  unsigned char *p;
664  unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
665  int fd = daemon->dhcpfd;
666#ifdef HAVE_DHCP6
667  if (!daemon->dhcp)
668    fd = daemon->dhcp6fd;
669#endif
670
671  /* no script */
672  if (daemon->helperfd == -1)
673    return;
674
675  if (lease->extradata)
676    ed_len = lease->extradata_len;
677  if (lease->clid)
678    clid_len = lease->clid_len;
679  if (hostname)
680    hostname_len = strlen(hostname) + 1;
681
682  buff_alloc(sizeof(struct script_data) +  clid_len + ed_len + hostname_len);
683
684  buf->action = action;
685  buf->flags = lease->flags;
686#ifdef HAVE_DHCP6
687  buf->vendorclass_count = lease->vendorclass_count;
688  buf->addr6 = lease->addr6;
689  buf->iaid = lease->iaid;
690#endif
691  buf->hwaddr_len = lease->hwaddr_len;
692  buf->hwaddr_type = lease->hwaddr_type;
693  buf->clid_len = clid_len;
694  buf->ed_len = ed_len;
695  buf->hostname_len = hostname_len;
696  buf->addr = lease->addr;
697  buf->giaddr = lease->giaddr;
698  memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
699  if (!indextoname(fd, lease->last_interface, buf->interface))
700    buf->interface[0] = 0;
701
702#ifdef HAVE_BROKEN_RTC
703  buf->length = lease->length;
704#else
705  buf->expires = lease->expires;
706#endif
707
708  if (lease->expires != 0)
709    buf->remaining_time = (unsigned int)difftime(lease->expires, now);
710  else
711    buf->remaining_time = 0;
712
713  p = (unsigned char *)(buf+1);
714  if (clid_len != 0)
715    {
716      memcpy(p, lease->clid, clid_len);
717      p += clid_len;
718    }
719  if (hostname_len != 0)
720    {
721      memcpy(p, hostname, hostname_len);
722      p += hostname_len;
723    }
724  if (ed_len != 0)
725    {
726      memcpy(p, lease->extradata, ed_len);
727      p += ed_len;
728    }
729  bytes_in_buf = p - (unsigned char *)buf;
730}
731
732#ifdef HAVE_TFTP
733/* This nastily re-uses DHCP-fields for TFTP stuff */
734void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
735{
736  unsigned int filename_len;
737
738  /* no script */
739  if (daemon->helperfd == -1)
740    return;
741
742  filename_len = strlen(filename) + 1;
743  buff_alloc(sizeof(struct script_data) +  filename_len);
744  memset(buf, 0, sizeof(struct script_data));
745
746  buf->action = ACTION_TFTP;
747  buf->hostname_len = filename_len;
748  buf->file_len = file_len;
749
750  if ((buf->flags = peer->sa.sa_family) == AF_INET)
751    buf->addr = peer->in.sin_addr;
752#ifdef HAVE_IPV6
753  else
754    buf->addr6 = peer->in6.sin6_addr;
755#endif
756
757  memcpy((unsigned char *)(buf+1), filename, filename_len);
758
759  bytes_in_buf = sizeof(struct script_data) +  filename_len;
760}
761#endif
762
763int helper_buf_empty(void)
764{
765  return bytes_in_buf == 0;
766}
767
768void helper_write(void)
769{
770  ssize_t rc;
771
772  if (bytes_in_buf == 0)
773    return;
774
775  if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
776    {
777      if (bytes_in_buf != (size_t)rc)
778	memmove(buf, buf + rc, bytes_in_buf - rc);
779      bytes_in_buf -= rc;
780    }
781  else
782    {
783      if (errno == EAGAIN || errno == EINTR)
784	return;
785      bytes_in_buf = 0;
786    }
787}
788
789#endif
790
791
792
793