Annotation of embedaddon/dnsmasq/src/helper.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
1.1 misho 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
1.1.1.2 misho 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
1.1 misho 73: unsigned char hwaddr[DHCP_CHADDR_MAX];
74: char interface[IF_NAMESIZE];
75: };
76:
77: static struct script_data *buf = NULL;
78: static size_t bytes_in_buf = 0, buf_size = 0;
79:
80: int 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: }
1.1.1.3 ! misho 222: else if (data.action == ACTION_ARP)
! 223: {
! 224: action_str = "arp-add";
! 225: is6 = (data.flags != AF_INET);
! 226: }
! 227: else if (data.action == ACTION_ARP_DEL)
! 228: {
! 229: action_str = "arp-del";
! 230: is6 = (data.flags != AF_INET);
! 231: data.action = ACTION_ARP;
! 232: }
! 233: else
1.1 misho 234: continue;
235:
236:
1.1.1.2 misho 237: /* stringify MAC into dhcp_buff */
238: p = daemon->dhcp_buff;
239: if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
240: p += sprintf(p, "%.2x-", data.hwaddr_type);
241: for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
242: {
243: p += sprintf(p, "%.2x", data.hwaddr[i]);
244: if (i != data.hwaddr_len - 1)
245: p += sprintf(p, ":");
1.1 misho 246: }
1.1.1.2 misho 247:
1.1 misho 248: /* supplied data may just exceed normal buffer (unlikely) */
249: if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
250: !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
251: continue;
252:
253: if (!read_write(pipefd[0], buf,
254: data.hostname_len + data.ed_len + data.clid_len, 1))
255: continue;
256:
257: /* CLID into packet */
1.1.1.2 misho 258: for (p = daemon->packet, i = 0; i < data.clid_len; i++)
259: {
260: p += sprintf(p, "%.2x", buf[i]);
261: if (i != data.clid_len - 1)
1.1 misho 262: p += sprintf(p, ":");
1.1.1.2 misho 263: }
264:
1.1 misho 265: #ifdef HAVE_DHCP6
1.1.1.2 misho 266: if (is6)
1.1 misho 267: {
268: /* or IAID and server DUID for IPv6 */
1.1.1.2 misho 269: sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
270: for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
1.1 misho 271: {
272: p += sprintf(p, "%.2x", daemon->duid[i]);
273: if (i != daemon->duid_len - 1)
274: p += sprintf(p, ":");
275: }
276:
277: }
278: #endif
279:
280: buf += data.clid_len;
281:
282: if (data.hostname_len != 0)
283: {
284: char *dot;
285: hostname = (char *)buf;
286: hostname[data.hostname_len - 1] = 0;
287: if (data.action != ACTION_TFTP)
288: {
289: if (!legal_hostname(hostname))
290: hostname = NULL;
291: else if ((dot = strchr(hostname, '.')))
292: {
293: domain = dot+1;
294: *dot = 0;
295: }
296: }
297: }
298:
299: extradata = buf + data.hostname_len;
300:
301: if (!is6)
302: inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
1.1.1.3 ! misho 303: #ifdef HAVE_IPV6
1.1 misho 304: else
1.1.1.2 misho 305: inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 306: #endif
307:
1.1.1.2 misho 308: #ifdef HAVE_TFTP
1.1 misho 309: /* file length */
310: if (data.action == ACTION_TFTP)
1.1.1.2 misho 311: sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
312: #endif
313:
1.1 misho 314: #ifdef HAVE_LUASCRIPT
315: if (daemon->luascript)
316: {
317: if (data.action == ACTION_TFTP)
318: {
319: lua_getglobal(lua, "tftp");
320: if (lua_type(lua, -1) != LUA_TFUNCTION)
321: lua_pop(lua, 1); /* tftp function optional */
322: else
323: {
324: lua_pushstring(lua, action_str); /* arg1 - action */
325: lua_newtable(lua); /* arg2 - data table */
326: lua_pushstring(lua, daemon->addrbuff);
327: lua_setfield(lua, -2, "destination_address");
328: lua_pushstring(lua, hostname);
329: lua_setfield(lua, -2, "file_name");
1.1.1.2 misho 330: lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
1.1 misho 331: lua_setfield(lua, -2, "file_size");
332: lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
333: }
334: }
1.1.1.3 ! misho 335: else if (data.action == ACTION_ARP)
! 336: {
! 337: lua_getglobal(lua, "arp");
! 338: if (lua_type(lua, -1) != LUA_TFUNCTION)
! 339: lua_pop(lua, 1); /* arp function optional */
! 340: else
! 341: {
! 342: lua_pushstring(lua, action_str); /* arg1 - action */
! 343: lua_newtable(lua); /* arg2 - data table */
! 344: lua_pushstring(lua, daemon->addrbuff);
! 345: lua_setfield(lua, -2, "client_address");
! 346: lua_pushstring(lua, daemon->dhcp_buff);
! 347: lua_setfield(lua, -2, "mac_address");
! 348: lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
! 349: }
! 350: }
1.1 misho 351: else
352: {
353: lua_getglobal(lua, "lease"); /* function to call */
354: lua_pushstring(lua, action_str); /* arg1 - action */
355: lua_newtable(lua); /* arg2 - data table */
356:
357: if (is6)
358: {
359: lua_pushstring(lua, daemon->packet);
1.1.1.2 misho 360: lua_setfield(lua, -2, "client_duid");
361: lua_pushstring(lua, daemon->dhcp_packet.iov_base);
1.1 misho 362: lua_setfield(lua, -2, "server_duid");
363: lua_pushstring(lua, daemon->dhcp_buff3);
364: lua_setfield(lua, -2, "iaid");
365: }
366:
367: if (!is6 && data.clid_len != 0)
368: {
369: lua_pushstring(lua, daemon->packet);
370: lua_setfield(lua, -2, "client_id");
371: }
372:
373: if (strlen(data.interface) != 0)
374: {
375: lua_pushstring(lua, data.interface);
376: lua_setfield(lua, -2, "interface");
377: }
378:
379: #ifdef HAVE_BROKEN_RTC
380: lua_pushnumber(lua, data.length);
381: lua_setfield(lua, -2, "lease_length");
382: #else
383: lua_pushnumber(lua, data.expires);
384: lua_setfield(lua, -2, "lease_expires");
385: #endif
386:
387: if (hostname)
388: {
389: lua_pushstring(lua, hostname);
390: lua_setfield(lua, -2, "hostname");
391: }
392:
393: if (domain)
394: {
395: lua_pushstring(lua, domain);
396: lua_setfield(lua, -2, "domain");
397: }
398:
399: end = extradata + data.ed_len;
400: buf = extradata;
401:
402: if (!is6)
403: buf = grab_extradata_lua(buf, end, "vendor_class");
404: #ifdef HAVE_DHCP6
1.1.1.2 misho 405: else if (data.vendorclass_count != 0)
406: {
407: sprintf(daemon->dhcp_buff2, "vendor_class_id");
408: buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
409: for (i = 0; i < data.vendorclass_count - 1; i++)
410: {
411: sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
412: buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
413: }
414: }
1.1 misho 415: #endif
416:
417: buf = grab_extradata_lua(buf, end, "supplied_hostname");
418:
419: if (!is6)
420: {
421: buf = grab_extradata_lua(buf, end, "cpewan_oui");
422: buf = grab_extradata_lua(buf, end, "cpewan_serial");
423: buf = grab_extradata_lua(buf, end, "cpewan_class");
424: buf = grab_extradata_lua(buf, end, "circuit_id");
425: buf = grab_extradata_lua(buf, end, "subscriber_id");
426: buf = grab_extradata_lua(buf, end, "remote_id");
427: }
428:
429: buf = grab_extradata_lua(buf, end, "tags");
430:
431: if (is6)
432: buf = grab_extradata_lua(buf, end, "relay_address");
433: else if (data.giaddr.s_addr != 0)
434: {
435: lua_pushstring(lua, inet_ntoa(data.giaddr));
436: lua_setfield(lua, -2, "relay_address");
437: }
438:
439: for (i = 0; buf; i++)
440: {
441: sprintf(daemon->dhcp_buff2, "user_class%i", i);
442: buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
443: }
444:
445: if (data.action != ACTION_DEL && data.remaining_time != 0)
446: {
447: lua_pushnumber(lua, data.remaining_time);
448: lua_setfield(lua, -2, "time_remaining");
449: }
450:
451: if (data.action == ACTION_OLD_HOSTNAME && hostname)
452: {
453: lua_pushstring(lua, hostname);
454: lua_setfield(lua, -2, "old_hostname");
455: }
456:
1.1.1.2 misho 457: if (!is6 || data.hwaddr_len != 0)
1.1 misho 458: {
459: lua_pushstring(lua, daemon->dhcp_buff);
460: lua_setfield(lua, -2, "mac_address");
461: }
462:
463: lua_pushstring(lua, daemon->addrbuff);
464: lua_setfield(lua, -2, "ip_address");
465:
466: lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
467: }
468: }
469: #endif
470:
471: /* no script, just lua */
472: if (!daemon->lease_change_command)
473: continue;
474:
475: /* possible fork errors are all temporary resource problems */
476: while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
477: sleep(2);
478:
479: if (pid == -1)
480: continue;
481:
482: /* wait for child to complete */
483: if (pid != 0)
484: {
485: /* reap our children's children, if necessary */
486: while (1)
487: {
488: int status;
489: pid_t rc = wait(&status);
490:
491: if (rc == pid)
492: {
493: /* On error send event back to main process for logging */
494: if (WIFSIGNALED(status))
495: send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
496: else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
497: send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
498: break;
499: }
500:
501: if (rc == -1 && errno != EINTR)
502: break;
503: }
504:
505: continue;
506: }
507:
1.1.1.3 ! misho 508: if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
1.1 misho 509: {
1.1.1.2 misho 510: #ifdef HAVE_DHCP6
511: my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
512: my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
513: my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
514: #endif
1.1 misho 515:
1.1.1.2 misho 516: my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
517: my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
1.1 misho 518:
519: #ifdef HAVE_BROKEN_RTC
520: sprintf(daemon->dhcp_buff2, "%u", data.length);
521: my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
522: #else
523: sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
524: my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
525: #endif
526:
1.1.1.2 misho 527: my_setenv("DNSMASQ_DOMAIN", domain, &err);
1.1 misho 528:
529: end = extradata + data.ed_len;
530: buf = extradata;
531:
532: if (!is6)
533: buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
534: #ifdef HAVE_DHCP6
535: else
536: {
1.1.1.2 misho 537: if (data.vendorclass_count != 0)
1.1 misho 538: {
539: buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
1.1.1.2 misho 540: for (i = 0; i < data.vendorclass_count - 1; i++)
1.1 misho 541: {
542: sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
543: buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
544: }
545: }
546: }
547: #endif
548:
549: buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
550:
551: if (!is6)
552: {
553: buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
554: buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
555: buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
556: buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
557: buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
558: buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
559: }
560:
561: buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
562:
563: if (is6)
564: buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
1.1.1.2 misho 565: else
566: my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
1.1 misho 567:
568: for (i = 0; buf; i++)
569: {
570: sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
571: buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
572: }
573:
1.1.1.2 misho 574: sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
575: my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
1.1 misho 576:
1.1.1.2 misho 577: my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
578: if (data.action == ACTION_OLD_HOSTNAME)
579: hostname = NULL;
1.1.1.3 ! misho 580:
! 581: my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
! 582: }
1.1 misho 583: /* we need to have the event_fd around if exec fails */
584: if ((i = fcntl(event_fd, F_GETFD)) != -1)
585: fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
586: close(pipefd[0]);
587:
588: p = strrchr(daemon->lease_change_command, '/');
589: if (err == 0)
590: {
591: execl(daemon->lease_change_command,
1.1.1.3 ! misho 592: p ? p+1 : daemon->lease_change_command, action_str,
! 593: (is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
1.1.1.2 misho 594: daemon->addrbuff, hostname, (char*)NULL);
1.1 misho 595: err = errno;
596: }
597: /* failed, send event so the main process logs the problem */
598: send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
599: _exit(0);
600: }
601: }
602:
603: static void my_setenv(const char *name, const char *value, int *error)
604: {
1.1.1.2 misho 605: if (*error == 0)
606: {
607: if (!value)
608: unsetenv(name);
609: else if (setenv(name, value, 1) != 0)
610: *error = errno;
611: }
1.1 misho 612: }
613:
614: static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
615: {
1.1.1.2 misho 616: unsigned char *next = NULL;
617: char *val = NULL;
1.1 misho 618:
1.1.1.2 misho 619: if (buf && (buf != end))
1.1 misho 620: {
1.1.1.2 misho 621: for (next = buf; ; next++)
622: if (next == end)
623: {
624: next = NULL;
625: break;
626: }
627: else if (*next == 0)
628: break;
1.1 misho 629:
1.1.1.2 misho 630: if (next && (next != buf))
631: {
632: char *p;
633: /* No "=" in value */
634: if ((p = strchr((char *)buf, '=')))
635: *p = 0;
636: val = (char *)buf;
637: }
638: }
639:
640: my_setenv(env, val, err);
641:
642: return next ? next + 1 : NULL;
1.1 misho 643: }
644:
645: #ifdef HAVE_LUASCRIPT
646: static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
647: {
648: unsigned char *next;
649:
650: if (!buf || (buf == end))
651: return NULL;
652:
653: for (next = buf; *next != 0; next++)
654: if (next == end)
655: return NULL;
656:
657: if (next != buf)
658: {
659: lua_pushstring(lua, (char *)buf);
660: lua_setfield(lua, -2, field);
661: }
662:
663: return next + 1;
664: }
665: #endif
666:
667: static void buff_alloc(size_t size)
668: {
669: if (size > buf_size)
670: {
671: struct script_data *new;
672:
673: /* start with reasonable size, will almost never need extending. */
674: if (size < sizeof(struct script_data) + 200)
675: size = sizeof(struct script_data) + 200;
676:
677: if (!(new = whine_malloc(size)))
678: return;
679: if (buf)
680: free(buf);
681: buf = new;
682: buf_size = size;
683: }
684: }
685:
686: /* pack up lease data into a buffer */
687: void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
688: {
689: unsigned char *p;
690: unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
691: int fd = daemon->dhcpfd;
692: #ifdef HAVE_DHCP6
693: if (!daemon->dhcp)
694: fd = daemon->dhcp6fd;
695: #endif
696:
697: /* no script */
698: if (daemon->helperfd == -1)
699: return;
700:
701: if (lease->extradata)
702: ed_len = lease->extradata_len;
703: if (lease->clid)
704: clid_len = lease->clid_len;
705: if (hostname)
706: hostname_len = strlen(hostname) + 1;
707:
708: buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
709:
710: buf->action = action;
711: buf->flags = lease->flags;
712: #ifdef HAVE_DHCP6
1.1.1.2 misho 713: buf->vendorclass_count = lease->vendorclass_count;
714: buf->addr6 = lease->addr6;
715: buf->iaid = lease->iaid;
1.1 misho 716: #endif
1.1.1.2 misho 717: buf->hwaddr_len = lease->hwaddr_len;
1.1 misho 718: buf->hwaddr_type = lease->hwaddr_type;
719: buf->clid_len = clid_len;
720: buf->ed_len = ed_len;
721: buf->hostname_len = hostname_len;
722: buf->addr = lease->addr;
723: buf->giaddr = lease->giaddr;
724: memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
725: if (!indextoname(fd, lease->last_interface, buf->interface))
726: buf->interface[0] = 0;
727:
728: #ifdef HAVE_BROKEN_RTC
729: buf->length = lease->length;
730: #else
731: buf->expires = lease->expires;
732: #endif
733:
734: if (lease->expires != 0)
735: buf->remaining_time = (unsigned int)difftime(lease->expires, now);
736: else
737: buf->remaining_time = 0;
738:
739: p = (unsigned char *)(buf+1);
740: if (clid_len != 0)
741: {
742: memcpy(p, lease->clid, clid_len);
743: p += clid_len;
744: }
745: if (hostname_len != 0)
746: {
747: memcpy(p, hostname, hostname_len);
748: p += hostname_len;
749: }
750: if (ed_len != 0)
751: {
752: memcpy(p, lease->extradata, ed_len);
753: p += ed_len;
754: }
755: bytes_in_buf = p - (unsigned char *)buf;
756: }
757:
758: #ifdef HAVE_TFTP
759: /* This nastily re-uses DHCP-fields for TFTP stuff */
760: void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
761: {
762: unsigned int filename_len;
763:
764: /* no script */
765: if (daemon->helperfd == -1)
766: return;
767:
768: filename_len = strlen(filename) + 1;
769: buff_alloc(sizeof(struct script_data) + filename_len);
770: memset(buf, 0, sizeof(struct script_data));
771:
772: buf->action = ACTION_TFTP;
773: buf->hostname_len = filename_len;
1.1.1.2 misho 774: buf->file_len = file_len;
1.1 misho 775:
776: if ((buf->flags = peer->sa.sa_family) == AF_INET)
777: buf->addr = peer->in.sin_addr;
778: #ifdef HAVE_IPV6
779: else
1.1.1.2 misho 780: buf->addr6 = peer->in6.sin6_addr;
1.1 misho 781: #endif
782:
783: memcpy((unsigned char *)(buf+1), filename, filename_len);
784:
785: bytes_in_buf = sizeof(struct script_data) + filename_len;
786: }
787: #endif
1.1.1.3 ! misho 788:
! 789: void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
! 790: {
! 791: /* no script */
! 792: if (daemon->helperfd == -1)
! 793: return;
! 794:
! 795: buff_alloc(sizeof(struct script_data));
! 796: memset(buf, 0, sizeof(struct script_data));
! 797:
! 798: buf->action = action;
! 799: buf->hwaddr_len = maclen;
! 800: buf->hwaddr_type = ARPHRD_ETHER;
! 801: if ((buf->flags = family) == AF_INET)
! 802: buf->addr = addr->addr.addr4;
! 803: #ifdef HAVE_IPV6
! 804: else
! 805: buf->addr6 = addr->addr.addr6;
! 806: #endif
! 807:
! 808: memcpy(buf->hwaddr, mac, maclen);
! 809:
! 810: bytes_in_buf = sizeof(struct script_data);
! 811: }
1.1 misho 812:
813: int helper_buf_empty(void)
814: {
815: return bytes_in_buf == 0;
816: }
817:
818: void helper_write(void)
819: {
820: ssize_t rc;
821:
822: if (bytes_in_buf == 0)
823: return;
824:
825: if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
826: {
827: if (bytes_in_buf != (size_t)rc)
828: memmove(buf, buf + rc, bytes_in_buf - rc);
829: bytes_in_buf -= rc;
830: }
831: else
832: {
833: if (errno == EAGAIN || errno == EINTR)
834: return;
835: bytes_in_buf = 0;
836: }
837: }
838:
839: #endif
840:
841:
842:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>