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