1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
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.
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.
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/>.
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
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
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
);
37 #define LUA_COMPAT_ALL
43 #define lua_open() luaL_newstate()
48 static unsigned char *grab_extradata_lua(unsigned char *buf
, unsigned char *end
, char *field
);
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
65 struct in6_addr addr6
;
66 int iaid
, vendorclass_count
;
68 unsigned char hwaddr
[DHCP_CHADDR_MAX
];
69 char interface
[IF_NAMESIZE
];
72 static struct script_data
*buf
= NULL
;
73 static size_t bytes_in_buf
= 0, buf_size
= 0;
75 int create_helper(int event_fd
, int err_fd
, uid_t uid
, gid_t gid
, long max_fd
)
79 struct sigaction sigact
;
81 /* create the pipe through which the main program sends us commands,
82 then fork our process. */
83 if (pipe(pipefd
) == -1 || !fix_fd(pipefd
[1]) || (pid
= fork()) == -1)
85 send_event(err_fd
, EVENT_PIPE_ERR
, errno
, NULL
);
91 close(pipefd
[0]); /* close reader side */
95 /* ignore SIGTERM, so that we can clean up when the main process gets hit
96 and SIGALRM so that we can use sleep() */
97 sigact
.sa_handler
= SIG_IGN
;
99 sigemptyset(&sigact
.sa_mask
);
100 sigaction(SIGTERM
, &sigact
, NULL
);
101 sigaction(SIGALRM
, &sigact
, NULL
);
103 if (!option_bool(OPT_DEBUG
) && uid
!= 0)
106 if (setgroups(0, &dummy
) == -1 ||
110 if (option_bool(OPT_NO_FORK
))
111 /* send error to daemon process if no-fork */
112 send_event(event_fd
, EVENT_USER_ERR
, errno
, daemon
->scriptuser
);
116 send_event(event_fd
, EVENT_DIE
, 0, NULL
);
118 send_event(err_fd
, EVENT_USER_ERR
, errno
, daemon
->scriptuser
);
124 /* close all the sockets etc, we don't need them here.
125 Don't close err_fd, in case the lua-init fails.
126 Note that we have to do this before lua init
127 so we don't close any lua fds. */
128 for (max_fd
--; max_fd
>= 0; max_fd
--)
129 if (max_fd
!= STDOUT_FILENO
&& max_fd
!= STDERR_FILENO
&&
130 max_fd
!= STDIN_FILENO
&& max_fd
!= pipefd
[0] &&
131 max_fd
!= event_fd
&& max_fd
!= err_fd
)
134 #ifdef HAVE_LUASCRIPT
135 if (daemon
->luascript
)
137 const char *lua_err
= NULL
;
141 /* get Lua to load our script file */
142 if (luaL_dofile(lua
, daemon
->luascript
) != 0)
143 lua_err
= lua_tostring(lua
, -1);
146 lua_getglobal(lua
, "lease");
147 if (lua_type(lua
, -1) != LUA_TFUNCTION
)
148 lua_err
= _("lease() function missing in Lua script");
153 if (option_bool(OPT_NO_FORK
) || option_bool(OPT_DEBUG
))
154 /* send error to daemon process if no-fork */
155 send_event(event_fd
, EVENT_LUA_ERR
, 0, (char *)lua_err
);
159 send_event(event_fd
, EVENT_DIE
, 0, NULL
);
161 send_event(err_fd
, EVENT_LUA_ERR
, 0, (char *)lua_err
);
166 lua_pop(lua
, 1); /* remove nil from stack */
167 lua_getglobal(lua
, "init");
168 if (lua_type(lua
, -1) == LUA_TFUNCTION
)
171 lua_pop(lua
, 1); /* remove nil from stack */
175 /* All init done, close our copy of the error pipe, so that main process can return */
182 struct script_data data
;
183 char *p
, *action_str
, *hostname
= NULL
, *domain
= NULL
;
184 unsigned char *buf
= (unsigned char *)daemon
->namebuff
;
185 unsigned char *end
, *extradata
, *alloc_buff
= NULL
;
190 /* we read zero bytes when pipe closed: this is our signal to exit */
191 if (!read_write(pipefd
[0], (unsigned char *)&data
, sizeof(data
), 1))
193 #ifdef HAVE_LUASCRIPT
194 if (daemon
->luascript
)
196 lua_getglobal(lua
, "shutdown");
197 if (lua_type(lua
, -1) == LUA_TFUNCTION
)
204 is6
= !!(data
.flags
& (LEASE_TA
| LEASE_NA
));
206 if (data
.action
== ACTION_DEL
)
208 else if (data
.action
== ACTION_ADD
)
210 else if (data
.action
== ACTION_OLD
|| data
.action
== ACTION_OLD_HOSTNAME
)
212 else if (data
.action
== ACTION_TFTP
)
215 is6
= (data
.flags
!= AF_INET
);
221 /* stringify MAC into dhcp_buff */
222 p
= daemon
->dhcp_buff
;
223 if (data
.hwaddr_type
!= ARPHRD_ETHER
|| data
.hwaddr_len
== 0)
224 p
+= sprintf(p
, "%.2x-", data
.hwaddr_type
);
225 for (i
= 0; (i
< data
.hwaddr_len
) && (i
< DHCP_CHADDR_MAX
); i
++)
227 p
+= sprintf(p
, "%.2x", data
.hwaddr
[i
]);
228 if (i
!= data
.hwaddr_len
- 1)
229 p
+= sprintf(p
, ":");
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
)))
237 if (!read_write(pipefd
[0], buf
,
238 data
.hostname_len
+ data
.ed_len
+ data
.clid_len
, 1))
241 /* CLID into packet */
242 for (p
= daemon
->packet
, i
= 0; i
< data
.clid_len
; i
++)
244 p
+= sprintf(p
, "%.2x", buf
[i
]);
245 if (i
!= data
.clid_len
- 1)
246 p
+= sprintf(p
, ":");
252 /* or IAID and server DUID for IPv6 */
253 sprintf(daemon
->dhcp_buff3
, "%s%u", data
.flags
& LEASE_TA
? "T" : "", data
.iaid
);
254 for (p
= daemon
->dhcp_packet
.iov_base
, i
= 0; i
< daemon
->duid_len
; i
++)
256 p
+= sprintf(p
, "%.2x", daemon
->duid
[i
]);
257 if (i
!= daemon
->duid_len
- 1)
258 p
+= sprintf(p
, ":");
264 buf
+= data
.clid_len
;
266 if (data
.hostname_len
!= 0)
269 hostname
= (char *)buf
;
270 hostname
[data
.hostname_len
- 1] = 0;
271 if (data
.action
!= ACTION_TFTP
)
273 if (!legal_hostname(hostname
))
275 else if ((dot
= strchr(hostname
, '.')))
283 extradata
= buf
+ data
.hostname_len
;
286 inet_ntop(AF_INET
, &data
.addr
, daemon
->addrbuff
, ADDRSTRLEN
);
289 inet_ntop(AF_INET6
, &data
.addr6
, daemon
->addrbuff
, ADDRSTRLEN
);
293 if (data
.action
== ACTION_TFTP
)
294 sprintf(is6
? daemon
->packet
: daemon
->dhcp_buff
, "%u", data
.iaid
);
296 #ifdef HAVE_LUASCRIPT
297 if (daemon
->luascript
)
299 if (data
.action
== ACTION_TFTP
)
301 lua_getglobal(lua
, "tftp");
302 if (lua_type(lua
, -1) != LUA_TFUNCTION
)
303 lua_pop(lua
, 1); /* tftp function optional */
306 lua_pushstring(lua
, action_str
); /* arg1 - action */
307 lua_newtable(lua
); /* arg2 - data table */
308 lua_pushstring(lua
, daemon
->addrbuff
);
309 lua_setfield(lua
, -2, "destination_address");
310 lua_pushstring(lua
, hostname
);
311 lua_setfield(lua
, -2, "file_name");
312 lua_pushstring(lua
, is6
? daemon
->packet
: daemon
->dhcp_buff
);
313 lua_setfield(lua
, -2, "file_size");
314 lua_call(lua
, 2, 0); /* pass 2 values, expect 0 */
319 lua_getglobal(lua
, "lease"); /* function to call */
320 lua_pushstring(lua
, action_str
); /* arg1 - action */
321 lua_newtable(lua
); /* arg2 - data table */
325 lua_pushstring(lua
, daemon
->packet
);
326 lua_setfield(lua
, -2, "client_duid");
327 lua_pushstring(lua
, daemon
->dhcp_packet
.iov_base
);
328 lua_setfield(lua
, -2, "server_duid");
329 lua_pushstring(lua
, daemon
->dhcp_buff3
);
330 lua_setfield(lua
, -2, "iaid");
333 if (!is6
&& data
.clid_len
!= 0)
335 lua_pushstring(lua
, daemon
->packet
);
336 lua_setfield(lua
, -2, "client_id");
339 if (strlen(data
.interface
) != 0)
341 lua_pushstring(lua
, data
.interface
);
342 lua_setfield(lua
, -2, "interface");
345 #ifdef HAVE_BROKEN_RTC
346 lua_pushnumber(lua
, data
.length
);
347 lua_setfield(lua
, -2, "lease_length");
349 lua_pushnumber(lua
, data
.expires
);
350 lua_setfield(lua
, -2, "lease_expires");
355 lua_pushstring(lua
, hostname
);
356 lua_setfield(lua
, -2, "hostname");
361 lua_pushstring(lua
, domain
);
362 lua_setfield(lua
, -2, "domain");
365 end
= extradata
+ data
.ed_len
;
369 buf
= grab_extradata_lua(buf
, end
, "vendor_class");
371 else if (data
.vendorclass_count
!= 0)
373 sprintf(daemon
->dhcp_buff2
, "vendor_class_id");
374 buf
= grab_extradata_lua(buf
, end
, daemon
->dhcp_buff2
);
375 for (i
= 0; i
< data
.vendorclass_count
- 1; i
++)
377 sprintf(daemon
->dhcp_buff2
, "vendor_class%i", i
);
378 buf
= grab_extradata_lua(buf
, end
, daemon
->dhcp_buff2
);
383 buf
= grab_extradata_lua(buf
, end
, "supplied_hostname");
387 buf
= grab_extradata_lua(buf
, end
, "cpewan_oui");
388 buf
= grab_extradata_lua(buf
, end
, "cpewan_serial");
389 buf
= grab_extradata_lua(buf
, end
, "cpewan_class");
390 buf
= grab_extradata_lua(buf
, end
, "circuit_id");
391 buf
= grab_extradata_lua(buf
, end
, "subscriber_id");
392 buf
= grab_extradata_lua(buf
, end
, "remote_id");
395 buf
= grab_extradata_lua(buf
, end
, "tags");
398 buf
= grab_extradata_lua(buf
, end
, "relay_address");
399 else if (data
.giaddr
.s_addr
!= 0)
401 lua_pushstring(lua
, inet_ntoa(data
.giaddr
));
402 lua_setfield(lua
, -2, "relay_address");
405 for (i
= 0; buf
; i
++)
407 sprintf(daemon
->dhcp_buff2
, "user_class%i", i
);
408 buf
= grab_extradata_lua(buf
, end
, daemon
->dhcp_buff2
);
411 if (data
.action
!= ACTION_DEL
&& data
.remaining_time
!= 0)
413 lua_pushnumber(lua
, data
.remaining_time
);
414 lua_setfield(lua
, -2, "time_remaining");
417 if (data
.action
== ACTION_OLD_HOSTNAME
&& hostname
)
419 lua_pushstring(lua
, hostname
);
420 lua_setfield(lua
, -2, "old_hostname");
423 if (!is6
|| data
.hwaddr_len
!= 0)
425 lua_pushstring(lua
, daemon
->dhcp_buff
);
426 lua_setfield(lua
, -2, "mac_address");
429 lua_pushstring(lua
, daemon
->addrbuff
);
430 lua_setfield(lua
, -2, "ip_address");
432 lua_call(lua
, 2, 0); /* pass 2 values, expect 0 */
437 /* no script, just lua */
438 if (!daemon
->lease_change_command
)
441 /* possible fork errors are all temporary resource problems */
442 while ((pid
= fork()) == -1 && (errno
== EAGAIN
|| errno
== ENOMEM
))
448 /* wait for child to complete */
451 /* reap our children's children, if necessary */
455 pid_t rc
= wait(&status
);
459 /* On error send event back to main process for logging */
460 if (WIFSIGNALED(status
))
461 send_event(event_fd
, EVENT_KILLED
, WTERMSIG(status
), NULL
);
462 else if (WIFEXITED(status
) && WEXITSTATUS(status
) != 0)
463 send_event(event_fd
, EVENT_EXITED
, WEXITSTATUS(status
), NULL
);
467 if (rc
== -1 && errno
!= EINTR
)
474 if (data
.action
!= ACTION_TFTP
)
479 my_setenv("DNSMASQ_IAID", daemon
->dhcp_buff3
, &err
);
480 my_setenv("DNSMASQ_SERVER_DUID", daemon
->dhcp_packet
.iov_base
, &err
);
481 if (data
.hwaddr_len
!= 0)
482 my_setenv("DNSMASQ_MAC", daemon
->dhcp_buff
, &err
);
486 if (!is6
&& data
.clid_len
!= 0)
487 my_setenv("DNSMASQ_CLIENT_ID", daemon
->packet
, &err
);
489 if (strlen(data
.interface
) != 0)
490 my_setenv("DNSMASQ_INTERFACE", data
.interface
, &err
);
492 #ifdef HAVE_BROKEN_RTC
493 sprintf(daemon
->dhcp_buff2
, "%u", data
.length
);
494 my_setenv("DNSMASQ_LEASE_LENGTH", daemon
->dhcp_buff2
, &err
);
496 sprintf(daemon
->dhcp_buff2
, "%lu", (unsigned long)data
.expires
);
497 my_setenv("DNSMASQ_LEASE_EXPIRES", daemon
->dhcp_buff2
, &err
);
501 my_setenv("DNSMASQ_DOMAIN", domain
, &err
);
503 end
= extradata
+ data
.ed_len
;
507 buf
= grab_extradata(buf
, end
, "DNSMASQ_VENDOR_CLASS", &err
);
511 if (data
.vendorclass_count
!= 0)
513 buf
= grab_extradata(buf
, end
, "DNSMASQ_VENDOR_CLASS_ID", &err
);
514 for (i
= 0; i
< data
.vendorclass_count
- 1; i
++)
516 sprintf(daemon
->dhcp_buff2
, "DNSMASQ_VENDOR_CLASS%i", i
);
517 buf
= grab_extradata(buf
, end
, daemon
->dhcp_buff2
, &err
);
523 buf
= grab_extradata(buf
, end
, "DNSMASQ_SUPPLIED_HOSTNAME", &err
);
527 buf
= grab_extradata(buf
, end
, "DNSMASQ_CPEWAN_OUI", &err
);
528 buf
= grab_extradata(buf
, end
, "DNSMASQ_CPEWAN_SERIAL", &err
);
529 buf
= grab_extradata(buf
, end
, "DNSMASQ_CPEWAN_CLASS", &err
);
530 buf
= grab_extradata(buf
, end
, "DNSMASQ_CIRCUIT_ID", &err
);
531 buf
= grab_extradata(buf
, end
, "DNSMASQ_SUBSCRIBER_ID", &err
);
532 buf
= grab_extradata(buf
, end
, "DNSMASQ_REMOTE_ID", &err
);
535 buf
= grab_extradata(buf
, end
, "DNSMASQ_TAGS", &err
);
538 buf
= grab_extradata(buf
, end
, "DNSMASQ_RELAY_ADDRESS", &err
);
539 else if (data
.giaddr
.s_addr
!= 0)
540 my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data
.giaddr
), &err
);
542 for (i
= 0; buf
; i
++)
544 sprintf(daemon
->dhcp_buff2
, "DNSMASQ_USER_CLASS%i", i
);
545 buf
= grab_extradata(buf
, end
, daemon
->dhcp_buff2
, &err
);
548 if (data
.action
!= ACTION_DEL
&& data
.remaining_time
!= 0)
550 sprintf(daemon
->dhcp_buff2
, "%u", data
.remaining_time
);
551 my_setenv("DNSMASQ_TIME_REMAINING", daemon
->dhcp_buff2
, &err
);
554 if (data
.action
== ACTION_OLD_HOSTNAME
&& hostname
)
556 my_setenv("DNSMASQ_OLD_HOSTNAME", hostname
, &err
);
561 if (option_bool(OPT_LOG_OPTS
))
562 my_setenv("DNSMASQ_LOG_DHCP", "1", &err
);
564 /* we need to have the event_fd around if exec fails */
565 if ((i
= fcntl(event_fd
, F_GETFD
)) != -1)
566 fcntl(event_fd
, F_SETFD
, i
| FD_CLOEXEC
);
569 p
= strrchr(daemon
->lease_change_command
, '/');
572 execl(daemon
->lease_change_command
,
573 p
? p
+1 : daemon
->lease_change_command
,
574 action_str
, is6
? daemon
->packet
: daemon
->dhcp_buff
,
575 daemon
->addrbuff
, hostname
, (char*)NULL
);
578 /* failed, send event so the main process logs the problem */
579 send_event(event_fd
, EVENT_EXEC_ERR
, err
, NULL
);
584 static void my_setenv(const char *name
, const char *value
, int *error
)
586 if (*error
== 0 && setenv(name
, value
, 1) != 0)
590 static unsigned char *grab_extradata(unsigned char *buf
, unsigned char *end
, char *env
, int *err
)
594 if (!buf
|| (buf
== end
))
597 for (next
= buf
; *next
!= 0; next
++)
604 /* No "=" in value */
605 if ((p
= strchr((char *)buf
, '=')))
607 my_setenv(env
, (char *)buf
, err
);
613 #ifdef HAVE_LUASCRIPT
614 static unsigned char *grab_extradata_lua(unsigned char *buf
, unsigned char *end
, char *field
)
618 if (!buf
|| (buf
== end
))
621 for (next
= buf
; *next
!= 0; next
++)
627 lua_pushstring(lua
, (char *)buf
);
628 lua_setfield(lua
, -2, field
);
635 static void buff_alloc(size_t size
)
639 struct script_data
*new;
641 /* start with reasonable size, will almost never need extending. */
642 if (size
< sizeof(struct script_data
) + 200)
643 size
= sizeof(struct script_data
) + 200;
645 if (!(new = whine_malloc(size
)))
654 /* pack up lease data into a buffer */
655 void queue_script(int action
, struct dhcp_lease
*lease
, char *hostname
, time_t now
)
658 unsigned int hostname_len
= 0, clid_len
= 0, ed_len
= 0;
659 int fd
= daemon
->dhcpfd
;
662 fd
= daemon
->dhcp6fd
;
666 if (daemon
->helperfd
== -1)
669 if (lease
->extradata
)
670 ed_len
= lease
->extradata_len
;
672 clid_len
= lease
->clid_len
;
674 hostname_len
= strlen(hostname
) + 1;
676 buff_alloc(sizeof(struct script_data
) + clid_len
+ ed_len
+ hostname_len
);
678 buf
->action
= action
;
679 buf
->flags
= lease
->flags
;
681 buf
->vendorclass_count
= lease
->vendorclass_count
;
682 buf
->addr6
= lease
->addr6
;
683 buf
->iaid
= lease
->iaid
;
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;
696 #ifdef HAVE_BROKEN_RTC
697 buf
->length
= lease
->length
;
699 buf
->expires
= lease
->expires
;
702 if (lease
->expires
!= 0)
703 buf
->remaining_time
= (unsigned int)difftime(lease
->expires
, now
);
705 buf
->remaining_time
= 0;
707 p
= (unsigned char *)(buf
+1);
710 memcpy(p
, lease
->clid
, clid_len
);
713 if (hostname_len
!= 0)
715 memcpy(p
, hostname
, hostname_len
);
720 memcpy(p
, lease
->extradata
, ed_len
);
723 bytes_in_buf
= p
- (unsigned char *)buf
;
727 /* This nastily re-uses DHCP-fields for TFTP stuff */
728 void queue_tftp(off_t file_len
, char *filename
, union mysockaddr
*peer
)
730 unsigned int filename_len
;
733 if (daemon
->helperfd
== -1)
736 filename_len
= strlen(filename
) + 1;
737 buff_alloc(sizeof(struct script_data
) + filename_len
);
738 memset(buf
, 0, sizeof(struct script_data
));
740 buf
->action
= ACTION_TFTP
;
741 buf
->hostname_len
= filename_len
;
742 buf
->iaid
= file_len
;
744 if ((buf
->flags
= peer
->sa
.sa_family
) == AF_INET
)
745 buf
->addr
= peer
->in
.sin_addr
;
748 buf
->addr6
= peer
->in6
.sin6_addr
;
751 memcpy((unsigned char *)(buf
+1), filename
, filename_len
);
753 bytes_in_buf
= sizeof(struct script_data
) + filename_len
;
757 int helper_buf_empty(void)
759 return bytes_in_buf
== 0;
762 void helper_write(void)
766 if (bytes_in_buf
== 0)
769 if ((rc
= write(daemon
->helperfd
, buf
, bytes_in_buf
)) != -1)
771 if (bytes_in_buf
!= (size_t)rc
)
772 memmove(buf
, buf
+ rc
, bytes_in_buf
- rc
);
777 if (errno
== EAGAIN
|| errno
== EINTR
)