Annotation of embedaddon/dnsmasq/src/helper.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* dnsmasq is Copyright (c) 2000-2014 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:        }
                    222:       else
                    223:        continue;
                    224: 
                    225:        
1.1.1.2 ! misho     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, ":");
1.1       misho     235:        }
1.1.1.2 ! misho     236:       
1.1       misho     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 */
1.1.1.2 ! misho     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) 
1.1       misho     251:              p += sprintf(p, ":");
1.1.1.2 ! misho     252:        }
        !           253: 
1.1       misho     254: #ifdef HAVE_DHCP6
1.1.1.2 ! misho     255:       if (is6)
1.1       misho     256:        {
                    257:          /* or IAID and server DUID for IPv6 */
1.1.1.2 ! misho     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++)
1.1       misho     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
1.1.1.2 ! misho     294:        inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
1.1       misho     295: #endif
                    296: 
1.1.1.2 ! misho     297: #ifdef HAVE_TFTP
1.1       misho     298:       /* file length */
                    299:       if (data.action == ACTION_TFTP)
1.1.1.2 ! misho     300:        sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
        !           301: #endif
        !           302: 
1.1       misho     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"); 
1.1.1.2 ! misho     319:                  lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
1.1       misho     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);
1.1.1.2 ! misho     333:                  lua_setfield(lua, -2, "client_duid");
        !           334:                  lua_pushstring(lua, daemon->dhcp_packet.iov_base);
1.1       misho     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
1.1.1.2 ! misho     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:                }
1.1       misho     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:              
1.1.1.2 ! misho     430:              if (!is6 || data.hwaddr_len != 0)
1.1       misho     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:        {
1.1.1.2 ! misho     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
1.1       misho     488:          
1.1.1.2 ! misho     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);
1.1       misho     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:          
1.1.1.2 ! misho     500:          my_setenv("DNSMASQ_DOMAIN", domain, &err);
1.1       misho     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:            {
1.1.1.2 ! misho     510:              if (data.vendorclass_count != 0)
1.1       misho     511:                {
                    512:                  buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
1.1.1.2 ! misho     513:                  for (i = 0; i < data.vendorclass_count - 1; i++)
1.1       misho     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);
1.1.1.2 ! misho     538:          else 
        !           539:            my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err); 
1.1       misho     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:          
1.1.1.2 ! misho     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);
1.1       misho     549:          
1.1.1.2 ! misho     550:          my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
        !           551:          if (data.action == ACTION_OLD_HOSTNAME)
        !           552:            hostname = NULL;
1.1       misho     553:        }
                    554: 
1.1.1.2 ! misho     555:       my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
        !           556:       
1.1       misho     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,
1.1.1.2 ! misho     567:                action_str, is6 ? daemon->packet : daemon->dhcp_buff, 
        !           568:                daemon->addrbuff, hostname, (char*)NULL);
1.1       misho     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: {
1.1.1.2 ! misho     579:   if (*error == 0)
        !           580:     {
        !           581:       if (!value)
        !           582:        unsetenv(name);
        !           583:       else if (setenv(name, value, 1) != 0)
        !           584:        *error = errno;
        !           585:     }
1.1       misho     586: }
                    587:  
                    588: static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err)
                    589: {
1.1.1.2 ! misho     590:   unsigned char *next = NULL;
        !           591:   char *val = NULL;
1.1       misho     592: 
1.1.1.2 ! misho     593:   if (buf && (buf != end))
1.1       misho     594:     {
1.1.1.2 ! misho     595:       for (next = buf; ; next++)
        !           596:        if (next == end)
        !           597:          {
        !           598:            next = NULL;
        !           599:            break;
        !           600:          }
        !           601:        else if (*next == 0)
        !           602:          break;
1.1       misho     603: 
1.1.1.2 ! misho     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;
1.1       misho     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 
1.1.1.2 ! misho     687:   buf->vendorclass_count = lease->vendorclass_count;
        !           688:   buf->addr6 = lease->addr6;
        !           689:   buf->iaid = lease->iaid;
1.1       misho     690: #endif
1.1.1.2 ! misho     691:   buf->hwaddr_len = lease->hwaddr_len;
1.1       misho     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;
1.1.1.2 ! misho     748:   buf->file_len = file_len;
1.1       misho     749: 
                    750:   if ((buf->flags = peer->sa.sa_family) == AF_INET)
                    751:     buf->addr = peer->in.sin_addr;
                    752: #ifdef HAVE_IPV6
                    753:   else
1.1.1.2 ! misho     754:     buf->addr6 = peer->in6.sin6_addr;
1.1       misho     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>