File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / helper.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years, 1 month ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

    1: /* dnsmasq is Copyright (c) 2000-2014 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: #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: 
   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: 	}
  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: 
  577: static 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:  
  588: static 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
  620: static 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: 
  641: static 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 */    
  661: void 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 */
  734: void 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: 
  763: int helper_buf_empty(void)
  764: {
  765:   return bytes_in_buf == 0;
  766: }
  767: 
  768: void 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: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>