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

1.1     ! misho       1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
        !             2: 
        !             3:    This program is free software; you can redistribute it and/or modify
        !             4:    it under the terms of the GNU General Public License as published by
        !             5:    the Free Software Foundation; version 2 dated June, 1991, or
        !             6:    (at your option) version 3 dated 29 June, 2007.
        !             7:  
        !             8:    This program is distributed in the hope that it will be useful,
        !             9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            11:    GNU General Public License for more details.
        !            12:      
        !            13:    You should have received a copy of the GNU General Public License
        !            14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
        !            15: */
        !            16: 
        !            17: #include "dnsmasq.h"
        !            18: 
        !            19: #ifdef HAVE_SCRIPT
        !            20: 
        !            21: /* This file has code to fork a helper process which recieves data via a pipe 
        !            22:    shared with the main process and which is responsible for calling a script when
        !            23:    DHCP leases change.
        !            24: 
        !            25:    The helper process is forked before the main process drops root, so it retains root 
        !            26:    privs to pass on to the script. For this reason it tries to be paranoid about 
        !            27:    data received from the main process, in case that has been compromised. We don't
        !            28:    want the helper to give an attacker root. In particular, the script to be run is
        !            29:    not settable via the pipe, once the fork has taken place it is not alterable by the 
        !            30:    main process.
        !            31: */
        !            32: 
        !            33: static void my_setenv(const char *name, const char *value, int *error);
        !            34: static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err);
        !            35: 
        !            36: #ifdef HAVE_LUASCRIPT
        !            37: #define LUA_COMPAT_ALL
        !            38: #include <lua.h>  
        !            39: #include <lualib.h>  
        !            40: #include <lauxlib.h>  
        !            41: 
        !            42: #ifndef lua_open
        !            43: #define lua_open()     luaL_newstate()
        !            44: #endif
        !            45: 
        !            46: lua_State *lua;
        !            47: 
        !            48: static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
        !            49: #endif
        !            50: 
        !            51: 
        !            52: struct script_data
        !            53: {
        !            54:   int flags;
        !            55:   int action, hwaddr_len, hwaddr_type;
        !            56:   int clid_len, hostname_len, ed_len;
        !            57:   struct in_addr addr, giaddr;
        !            58:   unsigned int remaining_time;
        !            59: #ifdef HAVE_BROKEN_RTC
        !            60:   unsigned int length;
        !            61: #else
        !            62:   time_t expires;
        !            63: #endif
        !            64:   unsigned char hwaddr[DHCP_CHADDR_MAX];
        !            65:   char interface[IF_NAMESIZE];
        !            66: 
        !            67: };
        !            68: 
        !            69: static struct script_data *buf = NULL;
        !            70: static size_t bytes_in_buf = 0, buf_size = 0;
        !            71: 
        !            72: int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
        !            73: {
        !            74:   pid_t pid;
        !            75:   int i, pipefd[2];
        !            76:   struct sigaction sigact;
        !            77: 
        !            78:   /* create the pipe through which the main program sends us commands,
        !            79:      then fork our process. */
        !            80:   if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
        !            81:     {
        !            82:       send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
        !            83:       _exit(0);
        !            84:     }
        !            85: 
        !            86:   if (pid != 0)
        !            87:     {
        !            88:       close(pipefd[0]); /* close reader side */
        !            89:       return pipefd[1];
        !            90:     }
        !            91: 
        !            92:   /* ignore SIGTERM, so that we can clean up when the main process gets hit
        !            93:      and SIGALRM so that we can use sleep() */
        !            94:   sigact.sa_handler = SIG_IGN;
        !            95:   sigact.sa_flags = 0;
        !            96:   sigemptyset(&sigact.sa_mask);
        !            97:   sigaction(SIGTERM, &sigact, NULL);
        !            98:   sigaction(SIGALRM, &sigact, NULL);
        !            99: 
        !           100:   if (!option_bool(OPT_DEBUG) && uid != 0)
        !           101:     {
        !           102:       gid_t dummy;
        !           103:       if (setgroups(0, &dummy) == -1 || 
        !           104:          setgid(gid) == -1 || 
        !           105:          setuid(uid) == -1)
        !           106:        {
        !           107:          if (option_bool(OPT_NO_FORK))
        !           108:            /* send error to daemon process if no-fork */
        !           109:            send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
        !           110:          else
        !           111:            {
        !           112:              /* kill daemon */
        !           113:              send_event(event_fd, EVENT_DIE, 0, NULL);
        !           114:              /* return error */
        !           115:              send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
        !           116:            }
        !           117:          _exit(0);
        !           118:        }
        !           119:     }
        !           120: 
        !           121:   /* close all the sockets etc, we don't need them here. 
        !           122:      Don't close err_fd, in case the lua-init fails.
        !           123:      Note that we have to do this before lua init
        !           124:      so we don't close any lua fds. */
        !           125:   for (max_fd--; max_fd >= 0; max_fd--)
        !           126:     if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && 
        !           127:        max_fd != STDIN_FILENO && max_fd != pipefd[0] && 
        !           128:        max_fd != event_fd && max_fd != err_fd)
        !           129:       close(max_fd);
        !           130:   
        !           131: #ifdef HAVE_LUASCRIPT
        !           132:   if (daemon->luascript)
        !           133:     {
        !           134:       const char *lua_err = NULL;
        !           135:       lua = lua_open();
        !           136:       luaL_openlibs(lua);
        !           137:       
        !           138:       /* get Lua to load our script file */
        !           139:       if (luaL_dofile(lua, daemon->luascript) != 0)
        !           140:        lua_err = lua_tostring(lua, -1);
        !           141:       else
        !           142:        {
        !           143:          lua_getglobal(lua, "lease");
        !           144:          if (lua_type(lua, -1) != LUA_TFUNCTION) 
        !           145:            lua_err = _("lease() function missing in Lua script");
        !           146:        }
        !           147:       
        !           148:       if (lua_err)
        !           149:        {
        !           150:          if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
        !           151:            /* send error to daemon process if no-fork */
        !           152:            send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
        !           153:          else
        !           154:            {
        !           155:              /* kill daemon */
        !           156:              send_event(event_fd, EVENT_DIE, 0, NULL);
        !           157:              /* return error */
        !           158:              send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
        !           159:            }
        !           160:          _exit(0);
        !           161:        }
        !           162:       
        !           163:       lua_pop(lua, 1);  /* remove nil from stack */
        !           164:       lua_getglobal(lua, "init");
        !           165:       if (lua_type(lua, -1) == LUA_TFUNCTION)
        !           166:        lua_call(lua, 0, 0);
        !           167:       else
        !           168:        lua_pop(lua, 1);  /* remove nil from stack */   
        !           169:     }
        !           170: #endif
        !           171: 
        !           172:   /* All init done, close our copy of the error pipe, so that main process can return */
        !           173:   if (err_fd != -1)
        !           174:     close(err_fd);
        !           175:     
        !           176:   /* loop here */
        !           177:   while(1)
        !           178:     {
        !           179:       struct script_data data;
        !           180:       char *p, *action_str, *hostname = NULL, *domain = NULL;
        !           181:       unsigned char *buf = (unsigned char *)daemon->namebuff;
        !           182:       unsigned char *end, *extradata, *alloc_buff = NULL;
        !           183:       int is6, err = 0;
        !           184: 
        !           185:       free(alloc_buff);
        !           186:       
        !           187:       /* we read zero bytes when pipe closed: this is our signal to exit */ 
        !           188:       if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
        !           189:        {
        !           190: #ifdef HAVE_LUASCRIPT
        !           191:          if (daemon->luascript)
        !           192:            {
        !           193:              lua_getglobal(lua, "shutdown");
        !           194:              if (lua_type(lua, -1) == LUA_TFUNCTION)
        !           195:                lua_call(lua, 0, 0);
        !           196:            }
        !           197: #endif
        !           198:          _exit(0);
        !           199:        }
        !           200:  
        !           201:       is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
        !           202:       
        !           203:       if (data.action == ACTION_DEL)
        !           204:        action_str = "del";
        !           205:       else if (data.action == ACTION_ADD)
        !           206:        action_str = "add";
        !           207:       else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
        !           208:        action_str = "old";
        !           209:       else if (data.action == ACTION_TFTP)
        !           210:        {
        !           211:          action_str = "tftp";
        !           212:          is6 = (data.flags != AF_INET);
        !           213:        }
        !           214:       else
        !           215:        continue;
        !           216: 
        !           217:        
        !           218:       if (!is6)
        !           219:        {
        !           220:          /* stringify MAC into dhcp_buff */
        !           221:          p = daemon->dhcp_buff;
        !           222:          if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) 
        !           223:            p += sprintf(p, "%.2x-", data.hwaddr_type);
        !           224:          for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
        !           225:            {
        !           226:              p += sprintf(p, "%.2x", data.hwaddr[i]);
        !           227:              if (i != data.hwaddr_len - 1)
        !           228:                p += sprintf(p, ":");
        !           229:            }
        !           230:        }
        !           231:        
        !           232:       /* supplied data may just exceed normal buffer (unlikely) */
        !           233:       if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME && 
        !           234:          !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
        !           235:        continue;
        !           236:       
        !           237:       if (!read_write(pipefd[0], buf, 
        !           238:                      data.hostname_len + data.ed_len + data.clid_len, 1))
        !           239:        continue;
        !           240: 
        !           241:       /* CLID into packet */
        !           242:       if (!is6)
        !           243:        for (p = daemon->packet, i = 0; i < data.clid_len; i++)
        !           244:          {
        !           245:            p += sprintf(p, "%.2x", buf[i]);
        !           246:            if (i != data.clid_len - 1) 
        !           247:              p += sprintf(p, ":");
        !           248:          }
        !           249: #ifdef HAVE_DHCP6
        !           250:       else
        !           251:        {
        !           252:          /* or IAID and server DUID for IPv6 */
        !           253:          sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);      
        !           254:          for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
        !           255:            {
        !           256:              p += sprintf(p, "%.2x", daemon->duid[i]);
        !           257:              if (i != daemon->duid_len - 1) 
        !           258:                p += sprintf(p, ":");
        !           259:            }
        !           260: 
        !           261:          /* duid not MAC for IPv6 */
        !           262:          for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
        !           263:            {
        !           264:              p += sprintf(p, "%.2x", buf[i]);
        !           265:              if (i != data.clid_len - 1) 
        !           266:                p += sprintf(p, ":");
        !           267:            } 
        !           268:        }
        !           269: #endif
        !           270: 
        !           271:       buf += data.clid_len;
        !           272: 
        !           273:       if (data.hostname_len != 0)
        !           274:        {
        !           275:          char *dot;
        !           276:          hostname = (char *)buf;
        !           277:          hostname[data.hostname_len - 1] = 0;
        !           278:          if (data.action != ACTION_TFTP)
        !           279:            {
        !           280:              if (!legal_hostname(hostname))
        !           281:                hostname = NULL;
        !           282:              else if ((dot = strchr(hostname, '.')))
        !           283:                {
        !           284:                  domain = dot+1;
        !           285:                  *dot = 0;
        !           286:                } 
        !           287:            }
        !           288:        }
        !           289:     
        !           290:       extradata = buf + data.hostname_len;
        !           291:     
        !           292:       if (!is6)
        !           293:        inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
        !           294: #ifdef HAVE_DHCP6
        !           295:       else
        !           296:        inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
        !           297: #endif
        !           298: 
        !           299:       /* file length */
        !           300:       if (data.action == ACTION_TFTP)
        !           301:        sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
        !           302:       
        !           303: #ifdef HAVE_LUASCRIPT
        !           304:       if (daemon->luascript)
        !           305:        {
        !           306:          if (data.action == ACTION_TFTP)
        !           307:            {
        !           308:              lua_getglobal(lua, "tftp"); 
        !           309:              if (lua_type(lua, -1) != LUA_TFUNCTION)
        !           310:                lua_pop(lua, 1); /* tftp function optional */
        !           311:              else
        !           312:                {
        !           313:                  lua_pushstring(lua, action_str); /* arg1 - action */
        !           314:                  lua_newtable(lua);               /* arg2 - data table */
        !           315:                  lua_pushstring(lua, daemon->addrbuff);
        !           316:                  lua_setfield(lua, -2, "destination_address");
        !           317:                  lua_pushstring(lua, hostname);
        !           318:                  lua_setfield(lua, -2, "file_name"); 
        !           319:                  lua_pushstring(lua, daemon->dhcp_buff);
        !           320:                  lua_setfield(lua, -2, "file_size");
        !           321:                  lua_call(lua, 2, 0);  /* pass 2 values, expect 0 */
        !           322:                }
        !           323:            }
        !           324:          else
        !           325:            {
        !           326:              lua_getglobal(lua, "lease");     /* function to call */
        !           327:              lua_pushstring(lua, action_str); /* arg1 - action */
        !           328:              lua_newtable(lua);               /* arg2 - data table */
        !           329:              
        !           330:              if (is6)
        !           331:                {
        !           332:                  lua_pushstring(lua, daemon->dhcp_buff);
        !           333:                  lua_setfield(lua, -2, "client_duid");
        !           334:                  lua_pushstring(lua, daemon->packet);
        !           335:                  lua_setfield(lua, -2, "server_duid");
        !           336:                  lua_pushstring(lua, daemon->dhcp_buff3);
        !           337:                  lua_setfield(lua, -2, "iaid");
        !           338:                }
        !           339:              
        !           340:              if (!is6 && data.clid_len != 0)
        !           341:                {
        !           342:                  lua_pushstring(lua, daemon->packet);
        !           343:                  lua_setfield(lua, -2, "client_id");
        !           344:                }
        !           345:              
        !           346:              if (strlen(data.interface) != 0)
        !           347:                {
        !           348:                  lua_pushstring(lua, data.interface);
        !           349:                  lua_setfield(lua, -2, "interface");
        !           350:                }
        !           351:              
        !           352: #ifdef HAVE_BROKEN_RTC 
        !           353:              lua_pushnumber(lua, data.length);
        !           354:              lua_setfield(lua, -2, "lease_length");
        !           355: #else
        !           356:              lua_pushnumber(lua, data.expires);
        !           357:              lua_setfield(lua, -2, "lease_expires");
        !           358: #endif
        !           359:              
        !           360:              if (hostname)
        !           361:                {
        !           362:                  lua_pushstring(lua, hostname);
        !           363:                  lua_setfield(lua, -2, "hostname");
        !           364:                }
        !           365:              
        !           366:              if (domain)
        !           367:                {
        !           368:                  lua_pushstring(lua, domain);
        !           369:                  lua_setfield(lua, -2, "domain");
        !           370:                }
        !           371:              
        !           372:              end = extradata + data.ed_len;
        !           373:              buf = extradata;
        !           374:              
        !           375:              if (!is6)
        !           376:                buf = grab_extradata_lua(buf, end, "vendor_class");
        !           377: #ifdef HAVE_DHCP6
        !           378:              else
        !           379:                for (i = 0; i < data.hwaddr_len; i++)
        !           380:                  {
        !           381:                    sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
        !           382:                    buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
        !           383:                  }
        !           384: #endif
        !           385:              
        !           386:              buf = grab_extradata_lua(buf, end, "supplied_hostname");
        !           387:              
        !           388:              if (!is6)
        !           389:                {
        !           390:                  buf = grab_extradata_lua(buf, end, "cpewan_oui");
        !           391:                  buf = grab_extradata_lua(buf, end, "cpewan_serial");   
        !           392:                  buf = grab_extradata_lua(buf, end, "cpewan_class");
        !           393:                  buf = grab_extradata_lua(buf, end, "circuit_id");
        !           394:                  buf = grab_extradata_lua(buf, end, "subscriber_id");
        !           395:                  buf = grab_extradata_lua(buf, end, "remote_id");
        !           396:                }
        !           397:              
        !           398:              buf = grab_extradata_lua(buf, end, "tags");
        !           399:              
        !           400:              if (is6)
        !           401:                buf = grab_extradata_lua(buf, end, "relay_address");
        !           402:              else if (data.giaddr.s_addr != 0)
        !           403:                {
        !           404:                  lua_pushstring(lua, inet_ntoa(data.giaddr));
        !           405:                  lua_setfield(lua, -2, "relay_address");
        !           406:                }
        !           407:              
        !           408:              for (i = 0; buf; i++)
        !           409:                {
        !           410:                  sprintf(daemon->dhcp_buff2, "user_class%i", i);
        !           411:                  buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
        !           412:                }
        !           413:              
        !           414:              if (data.action != ACTION_DEL && data.remaining_time != 0)
        !           415:                {
        !           416:                  lua_pushnumber(lua, data.remaining_time);
        !           417:                  lua_setfield(lua, -2, "time_remaining");
        !           418:                }
        !           419:              
        !           420:              if (data.action == ACTION_OLD_HOSTNAME && hostname)
        !           421:                {
        !           422:                  lua_pushstring(lua, hostname);
        !           423:                  lua_setfield(lua, -2, "old_hostname");
        !           424:                }
        !           425:              
        !           426:              if (!is6)
        !           427:                {
        !           428:                  lua_pushstring(lua, daemon->dhcp_buff);
        !           429:                  lua_setfield(lua, -2, "mac_address");
        !           430:                }
        !           431:              
        !           432:              lua_pushstring(lua, daemon->addrbuff);
        !           433:              lua_setfield(lua, -2, "ip_address");
        !           434:            
        !           435:              lua_call(lua, 2, 0);      /* pass 2 values, expect 0 */
        !           436:            }
        !           437:        }
        !           438: #endif
        !           439: 
        !           440:       /* no script, just lua */
        !           441:       if (!daemon->lease_change_command)
        !           442:        continue;
        !           443: 
        !           444:       /* possible fork errors are all temporary resource problems */
        !           445:       while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
        !           446:        sleep(2);
        !           447: 
        !           448:       if (pid == -1)
        !           449:        continue;
        !           450:       
        !           451:       /* wait for child to complete */
        !           452:       if (pid != 0)
        !           453:        {
        !           454:          /* reap our children's children, if necessary */
        !           455:          while (1)
        !           456:            {
        !           457:              int status;
        !           458:              pid_t rc = wait(&status);
        !           459:              
        !           460:              if (rc == pid)
        !           461:                {
        !           462:                  /* On error send event back to main process for logging */
        !           463:                  if (WIFSIGNALED(status))
        !           464:                    send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
        !           465:                  else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
        !           466:                    send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
        !           467:                  break;
        !           468:                }
        !           469:              
        !           470:              if (rc == -1 && errno != EINTR)
        !           471:                break;
        !           472:            }
        !           473:          
        !           474:          continue;
        !           475:        }
        !           476:       
        !           477:       if (data.action != ACTION_TFTP)
        !           478:        {
        !           479:          if (is6)
        !           480:            {
        !           481:              my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
        !           482:              my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
        !           483:            }
        !           484:          
        !           485:          if (!is6 && data.clid_len != 0)
        !           486:            my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
        !           487:          
        !           488:          if (strlen(data.interface) != 0)
        !           489:            my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
        !           490:          
        !           491: #ifdef HAVE_BROKEN_RTC
        !           492:          sprintf(daemon->dhcp_buff2, "%u", data.length);
        !           493:          my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
        !           494: #else
        !           495:          sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
        !           496:          my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); 
        !           497: #endif
        !           498:          
        !           499:          if (domain)
        !           500:            my_setenv("DNSMASQ_DOMAIN", domain, &err);
        !           501:          
        !           502:          end = extradata + data.ed_len;
        !           503:          buf = extradata;
        !           504:          
        !           505:          if (!is6)
        !           506:            buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
        !           507: #ifdef HAVE_DHCP6
        !           508:          else
        !           509:            {
        !           510:              if (data.hwaddr_len != 0)
        !           511:                {
        !           512:                  buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
        !           513:                  for (i = 0; i < data.hwaddr_len - 1; i++)
        !           514:                    {
        !           515:                      sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
        !           516:                      buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
        !           517:                    }
        !           518:                }
        !           519:            }
        !           520: #endif
        !           521:          
        !           522:          buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
        !           523:          
        !           524:          if (!is6)
        !           525:            {
        !           526:              buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
        !           527:              buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);   
        !           528:              buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
        !           529:              buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
        !           530:              buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
        !           531:              buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
        !           532:            }
        !           533:          
        !           534:          buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
        !           535: 
        !           536:          if (is6)
        !           537:            buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
        !           538:          else if (data.giaddr.s_addr != 0)
        !           539:            my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err); 
        !           540:          
        !           541:          for (i = 0; buf; i++)
        !           542:            {
        !           543:              sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
        !           544:              buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
        !           545:            }
        !           546:          
        !           547:          if (data.action != ACTION_DEL && data.remaining_time != 0)
        !           548:            {
        !           549:              sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
        !           550:              my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
        !           551:            }
        !           552:          
        !           553:          if (data.action == ACTION_OLD_HOSTNAME && hostname)
        !           554:            {
        !           555:              my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
        !           556:              hostname = NULL;
        !           557:            }
        !           558:        }
        !           559: 
        !           560:       if (option_bool(OPT_LOG_OPTS))
        !           561:        my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
        !           562:         
        !           563:       /* we need to have the event_fd around if exec fails */
        !           564:       if ((i = fcntl(event_fd, F_GETFD)) != -1)
        !           565:        fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
        !           566:       close(pipefd[0]);
        !           567: 
        !           568:       p =  strrchr(daemon->lease_change_command, '/');
        !           569:       if (err == 0)
        !           570:        {
        !           571:          execl(daemon->lease_change_command, 
        !           572:                p ? p+1 : daemon->lease_change_command,
        !           573:                action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
        !           574:          err = errno;
        !           575:        }
        !           576:       /* failed, send event so the main process logs the problem */
        !           577:       send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
        !           578:       _exit(0)        !           579:     }
        !           580: }
        !           581: 
        !           582: static void my_setenv(const char *name, const char *value, int *error)
        !           583: {
        !           584:   if (*error == 0 && setenv(name, value, 1) != 0)
        !           585:     *error = errno;
        !           586: }
        !           587:  
        !           588: static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end,  char *env, int *err)
        !           589: {
        !           590:   unsigned char *next;
        !           591: 
        !           592:   if (!buf || (buf == end))
        !           593:     return NULL;
        !           594: 
        !           595:   for (next = buf; *next != 0; next++)
        !           596:     if (next == end)
        !           597:       return NULL;
        !           598:   
        !           599:   if (next != buf)
        !           600:     {
        !           601:       char *p;
        !           602:       /* No "=" in value */
        !           603:       if ((p = strchr((char *)buf, '=')))
        !           604:        *p = 0;
        !           605:       my_setenv(env, (char *)buf, err);
        !           606:     }
        !           607: 
        !           608:   return next + 1;
        !           609: }
        !           610: 
        !           611: #ifdef HAVE_LUASCRIPT
        !           612: static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
        !           613: {
        !           614:   unsigned char *next;
        !           615: 
        !           616:   if (!buf || (buf == end))
        !           617:     return NULL;
        !           618: 
        !           619:   for (next = buf; *next != 0; next++)
        !           620:     if (next == end)
        !           621:       return NULL;
        !           622:   
        !           623:   if (next != buf)
        !           624:     {
        !           625:       lua_pushstring(lua,  (char *)buf);
        !           626:       lua_setfield(lua, -2, field);
        !           627:     }
        !           628: 
        !           629:   return next + 1;
        !           630: }
        !           631: #endif
        !           632: 
        !           633: static void buff_alloc(size_t size)
        !           634: {
        !           635:   if (size > buf_size)
        !           636:     {
        !           637:       struct script_data *new;
        !           638:       
        !           639:       /* start with reasonable size, will almost never need extending. */
        !           640:       if (size < sizeof(struct script_data) + 200)
        !           641:        size = sizeof(struct script_data) + 200;
        !           642: 
        !           643:       if (!(new = whine_malloc(size)))
        !           644:        return;
        !           645:       if (buf)
        !           646:        free(buf);
        !           647:       buf = new;
        !           648:       buf_size = size;
        !           649:     }
        !           650: }
        !           651: 
        !           652: /* pack up lease data into a buffer */    
        !           653: void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
        !           654: {
        !           655:   unsigned char *p;
        !           656:   unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
        !           657:   int fd = daemon->dhcpfd;
        !           658: #ifdef HAVE_DHCP6 
        !           659:   int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
        !           660: 
        !           661:   if (!daemon->dhcp)
        !           662:     fd = daemon->dhcp6fd;
        !           663: #endif
        !           664: 
        !           665:   /* no script */
        !           666:   if (daemon->helperfd == -1)
        !           667:     return;
        !           668: 
        !           669:   if (lease->extradata)
        !           670:     ed_len = lease->extradata_len;
        !           671:   if (lease->clid)
        !           672:     clid_len = lease->clid_len;
        !           673:   if (hostname)
        !           674:     hostname_len = strlen(hostname) + 1;
        !           675: 
        !           676:   buff_alloc(sizeof(struct script_data) +  clid_len + ed_len + hostname_len);
        !           677: 
        !           678:   buf->action = action;
        !           679:   buf->flags = lease->flags;
        !           680: #ifdef HAVE_DHCP6 
        !           681:   if (is6)
        !           682:     buf->hwaddr_len = lease->vendorclass_count;
        !           683:   else
        !           684: #endif
        !           685:     buf->hwaddr_len = lease->hwaddr_len;
        !           686:   buf->hwaddr_type = lease->hwaddr_type;
        !           687:   buf->clid_len = clid_len;
        !           688:   buf->ed_len = ed_len;
        !           689:   buf->hostname_len = hostname_len;
        !           690:   buf->addr = lease->addr;
        !           691:   buf->giaddr = lease->giaddr;
        !           692:   memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
        !           693:   if (!indextoname(fd, lease->last_interface, buf->interface))
        !           694:     buf->interface[0] = 0;
        !           695:   
        !           696: #ifdef HAVE_BROKEN_RTC 
        !           697:   buf->length = lease->length;
        !           698: #else
        !           699:   buf->expires = lease->expires;
        !           700: #endif
        !           701: 
        !           702:   if (lease->expires != 0)
        !           703:     buf->remaining_time = (unsigned int)difftime(lease->expires, now);
        !           704:   else
        !           705:     buf->remaining_time = 0;
        !           706: 
        !           707:   p = (unsigned char *)(buf+1);
        !           708:   if (clid_len != 0)
        !           709:     {
        !           710:       memcpy(p, lease->clid, clid_len);
        !           711:       p += clid_len;
        !           712:     }
        !           713:   if (hostname_len != 0)
        !           714:     {
        !           715:       memcpy(p, hostname, hostname_len);
        !           716:       p += hostname_len;
        !           717:     }
        !           718:   if (ed_len != 0)
        !           719:     {
        !           720:       memcpy(p, lease->extradata, ed_len);
        !           721:       p += ed_len;
        !           722:     }
        !           723:   bytes_in_buf = p - (unsigned char *)buf;
        !           724: }
        !           725: 
        !           726: #ifdef HAVE_TFTP
        !           727: /* This nastily re-uses DHCP-fields for TFTP stuff */
        !           728: void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
        !           729: {
        !           730:   unsigned int filename_len;
        !           731: 
        !           732:   /* no script */
        !           733:   if (daemon->helperfd == -1)
        !           734:     return;
        !           735:   
        !           736:   filename_len = strlen(filename) + 1;
        !           737:   buff_alloc(sizeof(struct script_data) +  filename_len);
        !           738:   memset(buf, 0, sizeof(struct script_data));
        !           739: 
        !           740:   buf->action = ACTION_TFTP;
        !           741:   buf->hostname_len = filename_len;
        !           742:   buf->hwaddr_len = file_len;
        !           743: 
        !           744:   if ((buf->flags = peer->sa.sa_family) == AF_INET)
        !           745:     buf->addr = peer->in.sin_addr;
        !           746: #ifdef HAVE_IPV6
        !           747:   else
        !           748:     memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
        !           749: #endif
        !           750: 
        !           751:   memcpy((unsigned char *)(buf+1), filename, filename_len);
        !           752:   
        !           753:   bytes_in_buf = sizeof(struct script_data) +  filename_len;
        !           754: }
        !           755: #endif
        !           756: 
        !           757: int helper_buf_empty(void)
        !           758: {
        !           759:   return bytes_in_buf == 0;
        !           760: }
        !           761: 
        !           762: void helper_write(void)
        !           763: {
        !           764:   ssize_t rc;
        !           765: 
        !           766:   if (bytes_in_buf == 0)
        !           767:     return;
        !           768:   
        !           769:   if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
        !           770:     {
        !           771:       if (bytes_in_buf != (size_t)rc)
        !           772:        memmove(buf, buf + rc, bytes_in_buf - rc); 
        !           773:       bytes_in_buf -= rc;
        !           774:     }
        !           775:   else
        !           776:     {
        !           777:       if (errno == EAGAIN || errno == EINTR)
        !           778:        return;
        !           779:       bytes_in_buf = 0;
        !           780:     }
        !           781: }
        !           782: 
        !           783: #endif
        !           784: 
        !           785: 
        !           786: 

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