Annotation of embedaddon/dnsmasq/src/helper.c, revision 1.1.1.1
1.1 misho 1: /* dnsmasq is Copyright (c) 2000-2013 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:
33: static void my_setenv(const char *name, const char *value, int *error);
34: static 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:
46: lua_State *lua;
47:
48: static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
49: #endif
50:
51:
52: struct 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: unsigned char hwaddr[DHCP_CHADDR_MAX];
65: char interface[IF_NAMESIZE];
66:
67: };
68:
69: static struct script_data *buf = NULL;
70: static size_t bytes_in_buf = 0, buf_size = 0;
71:
72: int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
73: {
74: pid_t pid;
75: int i, pipefd[2];
76: struct sigaction sigact;
77:
78: /* create the pipe through which the main program sends us commands,
79: then fork our process. */
80: if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
81: {
82: send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
83: _exit(0);
84: }
85:
86: if (pid != 0)
87: {
88: close(pipefd[0]); /* close reader side */
89: return pipefd[1];
90: }
91:
92: /* ignore SIGTERM, so that we can clean up when the main process gets hit
93: and SIGALRM so that we can use sleep() */
94: sigact.sa_handler = SIG_IGN;
95: sigact.sa_flags = 0;
96: sigemptyset(&sigact.sa_mask);
97: sigaction(SIGTERM, &sigact, NULL);
98: sigaction(SIGALRM, &sigact, NULL);
99:
100: if (!option_bool(OPT_DEBUG) && uid != 0)
101: {
102: gid_t dummy;
103: if (setgroups(0, &dummy) == -1 ||
104: setgid(gid) == -1 ||
105: setuid(uid) == -1)
106: {
107: if (option_bool(OPT_NO_FORK))
108: /* send error to daemon process if no-fork */
109: send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
110: else
111: {
112: /* kill daemon */
113: send_event(event_fd, EVENT_DIE, 0, NULL);
114: /* return error */
115: send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
116: }
117: _exit(0);
118: }
119: }
120:
121: /* close all the sockets etc, we don't need them here.
122: Don't close err_fd, in case the lua-init fails.
123: Note that we have to do this before lua init
124: so we don't close any lua fds. */
125: for (max_fd--; max_fd >= 0; max_fd--)
126: if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
127: max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
128: max_fd != event_fd && max_fd != err_fd)
129: close(max_fd);
130:
131: #ifdef HAVE_LUASCRIPT
132: if (daemon->luascript)
133: {
134: const char *lua_err = NULL;
135: lua = lua_open();
136: luaL_openlibs(lua);
137:
138: /* get Lua to load our script file */
139: if (luaL_dofile(lua, daemon->luascript) != 0)
140: lua_err = lua_tostring(lua, -1);
141: else
142: {
143: lua_getglobal(lua, "lease");
144: if (lua_type(lua, -1) != LUA_TFUNCTION)
145: lua_err = _("lease() function missing in Lua script");
146: }
147:
148: if (lua_err)
149: {
150: if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
151: /* send error to daemon process if no-fork */
152: send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
153: else
154: {
155: /* kill daemon */
156: send_event(event_fd, EVENT_DIE, 0, NULL);
157: /* return error */
158: send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
159: }
160: _exit(0);
161: }
162:
163: lua_pop(lua, 1); /* remove nil from stack */
164: lua_getglobal(lua, "init");
165: if (lua_type(lua, -1) == LUA_TFUNCTION)
166: lua_call(lua, 0, 0);
167: else
168: lua_pop(lua, 1); /* remove nil from stack */
169: }
170: #endif
171:
172: /* All init done, close our copy of the error pipe, so that main process can return */
173: if (err_fd != -1)
174: close(err_fd);
175:
176: /* loop here */
177: while(1)
178: {
179: struct script_data data;
180: char *p, *action_str, *hostname = NULL, *domain = NULL;
181: unsigned char *buf = (unsigned char *)daemon->namebuff;
182: unsigned char *end, *extradata, *alloc_buff = NULL;
183: int is6, err = 0;
184:
185: free(alloc_buff);
186:
187: /* we read zero bytes when pipe closed: this is our signal to exit */
188: if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
189: {
190: #ifdef HAVE_LUASCRIPT
191: if (daemon->luascript)
192: {
193: lua_getglobal(lua, "shutdown");
194: if (lua_type(lua, -1) == LUA_TFUNCTION)
195: lua_call(lua, 0, 0);
196: }
197: #endif
198: _exit(0);
199: }
200:
201: is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
202:
203: if (data.action == ACTION_DEL)
204: action_str = "del";
205: else if (data.action == ACTION_ADD)
206: action_str = "add";
207: else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
208: action_str = "old";
209: else if (data.action == ACTION_TFTP)
210: {
211: action_str = "tftp";
212: is6 = (data.flags != AF_INET);
213: }
214: else
215: continue;
216:
217:
218: if (!is6)
219: {
220: /* stringify MAC into dhcp_buff */
221: p = daemon->dhcp_buff;
222: if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
223: p += sprintf(p, "%.2x-", data.hwaddr_type);
224: for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
225: {
226: p += sprintf(p, "%.2x", data.hwaddr[i]);
227: if (i != data.hwaddr_len - 1)
228: p += sprintf(p, ":");
229: }
230: }
231:
232: /* supplied data may just exceed normal buffer (unlikely) */
233: if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
234: !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
235: continue;
236:
237: if (!read_write(pipefd[0], buf,
238: data.hostname_len + data.ed_len + data.clid_len, 1))
239: continue;
240:
241: /* CLID into packet */
242: if (!is6)
243: for (p = daemon->packet, i = 0; i < data.clid_len; i++)
244: {
245: p += sprintf(p, "%.2x", buf[i]);
246: if (i != data.clid_len - 1)
247: p += sprintf(p, ":");
248: }
249: #ifdef HAVE_DHCP6
250: else
251: {
252: /* or IAID and server DUID for IPv6 */
253: sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
254: for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
255: {
256: p += sprintf(p, "%.2x", daemon->duid[i]);
257: if (i != daemon->duid_len - 1)
258: p += sprintf(p, ":");
259: }
260:
261: /* duid not MAC for IPv6 */
262: for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
263: {
264: p += sprintf(p, "%.2x", buf[i]);
265: if (i != data.clid_len - 1)
266: p += sprintf(p, ":");
267: }
268: }
269: #endif
270:
271: buf += data.clid_len;
272:
273: if (data.hostname_len != 0)
274: {
275: char *dot;
276: hostname = (char *)buf;
277: hostname[data.hostname_len - 1] = 0;
278: if (data.action != ACTION_TFTP)
279: {
280: if (!legal_hostname(hostname))
281: hostname = NULL;
282: else if ((dot = strchr(hostname, '.')))
283: {
284: domain = dot+1;
285: *dot = 0;
286: }
287: }
288: }
289:
290: extradata = buf + data.hostname_len;
291:
292: if (!is6)
293: inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
294: #ifdef HAVE_DHCP6
295: else
296: inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
297: #endif
298:
299: /* file length */
300: if (data.action == ACTION_TFTP)
301: sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
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, 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->dhcp_buff);
333: lua_setfield(lua, -2, "client_duid");
334: lua_pushstring(lua, daemon->packet);
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
379: for (i = 0; i < data.hwaddr_len; i++)
380: {
381: sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
382: buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
383: }
384: #endif
385:
386: buf = grab_extradata_lua(buf, end, "supplied_hostname");
387:
388: if (!is6)
389: {
390: buf = grab_extradata_lua(buf, end, "cpewan_oui");
391: buf = grab_extradata_lua(buf, end, "cpewan_serial");
392: buf = grab_extradata_lua(buf, end, "cpewan_class");
393: buf = grab_extradata_lua(buf, end, "circuit_id");
394: buf = grab_extradata_lua(buf, end, "subscriber_id");
395: buf = grab_extradata_lua(buf, end, "remote_id");
396: }
397:
398: buf = grab_extradata_lua(buf, end, "tags");
399:
400: if (is6)
401: buf = grab_extradata_lua(buf, end, "relay_address");
402: else if (data.giaddr.s_addr != 0)
403: {
404: lua_pushstring(lua, inet_ntoa(data.giaddr));
405: lua_setfield(lua, -2, "relay_address");
406: }
407:
408: for (i = 0; buf; i++)
409: {
410: sprintf(daemon->dhcp_buff2, "user_class%i", i);
411: buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
412: }
413:
414: if (data.action != ACTION_DEL && data.remaining_time != 0)
415: {
416: lua_pushnumber(lua, data.remaining_time);
417: lua_setfield(lua, -2, "time_remaining");
418: }
419:
420: if (data.action == ACTION_OLD_HOSTNAME && hostname)
421: {
422: lua_pushstring(lua, hostname);
423: lua_setfield(lua, -2, "old_hostname");
424: }
425:
426: if (!is6)
427: {
428: lua_pushstring(lua, daemon->dhcp_buff);
429: lua_setfield(lua, -2, "mac_address");
430: }
431:
432: lua_pushstring(lua, daemon->addrbuff);
433: lua_setfield(lua, -2, "ip_address");
434:
435: lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
436: }
437: }
438: #endif
439:
440: /* no script, just lua */
441: if (!daemon->lease_change_command)
442: continue;
443:
444: /* possible fork errors are all temporary resource problems */
445: while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
446: sleep(2);
447:
448: if (pid == -1)
449: continue;
450:
451: /* wait for child to complete */
452: if (pid != 0)
453: {
454: /* reap our children's children, if necessary */
455: while (1)
456: {
457: int status;
458: pid_t rc = wait(&status);
459:
460: if (rc == pid)
461: {
462: /* On error send event back to main process for logging */
463: if (WIFSIGNALED(status))
464: send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
465: else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
466: send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
467: break;
468: }
469:
470: if (rc == -1 && errno != EINTR)
471: break;
472: }
473:
474: continue;
475: }
476:
477: if (data.action != ACTION_TFTP)
478: {
479: if (is6)
480: {
481: my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
482: my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
483: }
484:
485: if (!is6 && data.clid_len != 0)
486: my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
487:
488: if (strlen(data.interface) != 0)
489: my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
490:
491: #ifdef HAVE_BROKEN_RTC
492: sprintf(daemon->dhcp_buff2, "%u", data.length);
493: my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
494: #else
495: sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
496: my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
497: #endif
498:
499: if (domain)
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.hwaddr_len != 0)
511: {
512: buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
513: for (i = 0; i < data.hwaddr_len - 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 if (data.giaddr.s_addr != 0)
539: my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &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: if (data.action != ACTION_DEL && data.remaining_time != 0)
548: {
549: sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
550: my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
551: }
552:
553: if (data.action == ACTION_OLD_HOSTNAME && hostname)
554: {
555: my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
556: hostname = NULL;
557: }
558: }
559:
560: if (option_bool(OPT_LOG_OPTS))
561: my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
562:
563: /* we need to have the event_fd around if exec fails */
564: if ((i = fcntl(event_fd, F_GETFD)) != -1)
565: fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
566: close(pipefd[0]);
567:
568: p = strrchr(daemon->lease_change_command, '/');
569: if (err == 0)
570: {
571: execl(daemon->lease_change_command,
572: p ? p+1 : daemon->lease_change_command,
573: action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
574: err = errno;
575: }
576: /* failed, send event so the main process logs the problem */
577: send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
578: _exit(0);
579: }
580: }
581:
582: static void my_setenv(const char *name, const char *value, int *error)
583: {
584: if (*error == 0 && setenv(name, value, 1) != 0)
585: *error = errno;
586: }
587:
588: static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
589: {
590: unsigned char *next;
591:
592: if (!buf || (buf == end))
593: return NULL;
594:
595: for (next = buf; *next != 0; next++)
596: if (next == end)
597: return NULL;
598:
599: if (next != buf)
600: {
601: char *p;
602: /* No "=" in value */
603: if ((p = strchr((char *)buf, '=')))
604: *p = 0;
605: my_setenv(env, (char *)buf, err);
606: }
607:
608: return next + 1;
609: }
610:
611: #ifdef HAVE_LUASCRIPT
612: static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
613: {
614: unsigned char *next;
615:
616: if (!buf || (buf == end))
617: return NULL;
618:
619: for (next = buf; *next != 0; next++)
620: if (next == end)
621: return NULL;
622:
623: if (next != buf)
624: {
625: lua_pushstring(lua, (char *)buf);
626: lua_setfield(lua, -2, field);
627: }
628:
629: return next + 1;
630: }
631: #endif
632:
633: static void buff_alloc(size_t size)
634: {
635: if (size > buf_size)
636: {
637: struct script_data *new;
638:
639: /* start with reasonable size, will almost never need extending. */
640: if (size < sizeof(struct script_data) + 200)
641: size = sizeof(struct script_data) + 200;
642:
643: if (!(new = whine_malloc(size)))
644: return;
645: if (buf)
646: free(buf);
647: buf = new;
648: buf_size = size;
649: }
650: }
651:
652: /* pack up lease data into a buffer */
653: void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
654: {
655: unsigned char *p;
656: unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
657: int fd = daemon->dhcpfd;
658: #ifdef HAVE_DHCP6
659: int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
660:
661: if (!daemon->dhcp)
662: fd = daemon->dhcp6fd;
663: #endif
664:
665: /* no script */
666: if (daemon->helperfd == -1)
667: return;
668:
669: if (lease->extradata)
670: ed_len = lease->extradata_len;
671: if (lease->clid)
672: clid_len = lease->clid_len;
673: if (hostname)
674: hostname_len = strlen(hostname) + 1;
675:
676: buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
677:
678: buf->action = action;
679: buf->flags = lease->flags;
680: #ifdef HAVE_DHCP6
681: if (is6)
682: buf->hwaddr_len = lease->vendorclass_count;
683: else
684: #endif
685: buf->hwaddr_len = lease->hwaddr_len;
686: buf->hwaddr_type = lease->hwaddr_type;
687: buf->clid_len = clid_len;
688: buf->ed_len = ed_len;
689: buf->hostname_len = hostname_len;
690: buf->addr = lease->addr;
691: buf->giaddr = lease->giaddr;
692: memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
693: if (!indextoname(fd, lease->last_interface, buf->interface))
694: buf->interface[0] = 0;
695:
696: #ifdef HAVE_BROKEN_RTC
697: buf->length = lease->length;
698: #else
699: buf->expires = lease->expires;
700: #endif
701:
702: if (lease->expires != 0)
703: buf->remaining_time = (unsigned int)difftime(lease->expires, now);
704: else
705: buf->remaining_time = 0;
706:
707: p = (unsigned char *)(buf+1);
708: if (clid_len != 0)
709: {
710: memcpy(p, lease->clid, clid_len);
711: p += clid_len;
712: }
713: if (hostname_len != 0)
714: {
715: memcpy(p, hostname, hostname_len);
716: p += hostname_len;
717: }
718: if (ed_len != 0)
719: {
720: memcpy(p, lease->extradata, ed_len);
721: p += ed_len;
722: }
723: bytes_in_buf = p - (unsigned char *)buf;
724: }
725:
726: #ifdef HAVE_TFTP
727: /* This nastily re-uses DHCP-fields for TFTP stuff */
728: void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
729: {
730: unsigned int filename_len;
731:
732: /* no script */
733: if (daemon->helperfd == -1)
734: return;
735:
736: filename_len = strlen(filename) + 1;
737: buff_alloc(sizeof(struct script_data) + filename_len);
738: memset(buf, 0, sizeof(struct script_data));
739:
740: buf->action = ACTION_TFTP;
741: buf->hostname_len = filename_len;
742: buf->hwaddr_len = file_len;
743:
744: if ((buf->flags = peer->sa.sa_family) == AF_INET)
745: buf->addr = peer->in.sin_addr;
746: #ifdef HAVE_IPV6
747: else
748: memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
749: #endif
750:
751: memcpy((unsigned char *)(buf+1), filename, filename_len);
752:
753: bytes_in_buf = sizeof(struct script_data) + filename_len;
754: }
755: #endif
756:
757: int helper_buf_empty(void)
758: {
759: return bytes_in_buf == 0;
760: }
761:
762: void helper_write(void)
763: {
764: ssize_t rc;
765:
766: if (bytes_in_buf == 0)
767: return;
768:
769: if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
770: {
771: if (bytes_in_buf != (size_t)rc)
772: memmove(buf, buf + rc, bytes_in_buf - rc);
773: bytes_in_buf -= rc;
774: }
775: else
776: {
777: if (errno == EAGAIN || errno == EINTR)
778: return;
779: bytes_in_buf = 0;
780: }
781: }
782:
783: #endif
784:
785:
786:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>