Annotation of embedaddon/dnsmasq/src/helper.c, revision 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>