1 /* dnsmasq is Copyright (c) 2000-2015 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
68 struct in6_addr addr6
;
71 int iaid
, vendorclass_count
;
73 unsigned char hwaddr
[DHCP_CHADDR_MAX
];
74 char interface
[IF_NAMESIZE
];
77 static struct script_data
*buf
= NULL
;
78 static size_t bytes_in_buf
= 0, buf_size
= 0;
80 int create_helper(int event_fd
, int err_fd
, uid_t uid
, gid_t gid
, long max_fd
)
84 struct sigaction sigact
;
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)
90 send_event(err_fd
, EVENT_PIPE_ERR
, errno
, NULL
);
96 close(pipefd
[0]); /* close reader side */
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
;
104 sigemptyset(&sigact
.sa_mask
);
105 sigaction(SIGTERM
, &sigact
, NULL
);
106 sigaction(SIGALRM
, &sigact
, NULL
);
108 if (!option_bool(OPT_DEBUG
) && uid
!= 0)
111 if (setgroups(0, &dummy
) == -1 ||
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
);
121 send_event(event_fd
, EVENT_DIE
, 0, NULL
);
123 send_event(err_fd
, EVENT_USER_ERR
, errno
, daemon
->scriptuser
);
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
)
139 #ifdef HAVE_LUASCRIPT
140 if (daemon
->luascript
)
142 const char *lua_err
= NULL
;
146 /* get Lua to load our script file */
147 if (luaL_dofile(lua
, daemon
->luascript
) != 0)
148 lua_err
= lua_tostring(lua
, -1);
151 lua_getglobal(lua
, "lease");
152 if (lua_type(lua
, -1) != LUA_TFUNCTION
)
153 lua_err
= _("lease() function missing in Lua script");
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
);
164 send_event(event_fd
, EVENT_DIE
, 0, NULL
);
166 send_event(err_fd
, EVENT_LUA_ERR
, 0, (char *)lua_err
);
171 lua_pop(lua
, 1); /* remove nil from stack */
172 lua_getglobal(lua
, "init");
173 if (lua_type(lua
, -1) == LUA_TFUNCTION
)
176 lua_pop(lua
, 1); /* remove nil from stack */
180 /* All init done, close our copy of the error pipe, so that main process can return */
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
;
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))
198 #ifdef HAVE_LUASCRIPT
199 if (daemon
->luascript
)
201 lua_getglobal(lua
, "shutdown");
202 if (lua_type(lua
, -1) == LUA_TFUNCTION
)
209 is6
= !!(data
.flags
& (LEASE_TA
| LEASE_NA
));
211 if (data
.action
== ACTION_DEL
)
213 else if (data
.action
== ACTION_ADD
)
215 else if (data
.action
== ACTION_OLD
|| data
.action
== ACTION_OLD_HOSTNAME
)
217 else if (data
.action
== ACTION_TFTP
)
220 is6
= (data
.flags
!= AF_INET
);
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
++)
232 p
+= sprintf(p
, "%.2x", data
.hwaddr
[i
]);
233 if (i
!= data
.hwaddr_len
- 1)
234 p
+= sprintf(p
, ":");
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
)))
242 if (!read_write(pipefd
[0], buf
,
243 data
.hostname_len
+ data
.ed_len
+ data
.clid_len
, 1))
246 /* CLID into packet */
247 for (p
= daemon
->packet
, i
= 0; i
< data
.clid_len
; i
++)
249 p
+= sprintf(p
, "%.2x", buf
[i
]);
250 if (i
!= data
.clid_len
- 1)
251 p
+= sprintf(p
, ":");
257 /* or IAID and server DUID for IPv6 */
258 sprintf(daemon
->dhcp_buff3
, "%s%u", data
.flags
& LEASE_TA
? "T" : "", data
.iaid
);
259 for (p
= daemon
->dhcp_packet
.iov_base
, i
= 0; i
< daemon
->duid_len
; i
++)
261 p
+= sprintf(p
, "%.2x", daemon
->duid
[i
]);
262 if (i
!= daemon
->duid_len
- 1)
263 p
+= sprintf(p
, ":");
269 buf
+= data
.clid_len
;
271 if (data
.hostname_len
!= 0)
274 hostname
= (char *)buf
;
275 hostname
[data
.hostname_len
- 1] = 0;
276 if (data
.action
!= ACTION_TFTP
)
278 if (!legal_hostname(hostname
))
280 else if ((dot
= strchr(hostname
, '.')))
288 extradata
= buf
+ data
.hostname_len
;
291 inet_ntop(AF_INET
, &data
.addr
, daemon
->addrbuff
, ADDRSTRLEN
);
294 inet_ntop(AF_INET6
, &data
.addr6
, daemon
->addrbuff
, ADDRSTRLEN
);
299 if (data
.action
== ACTION_TFTP
)
300 sprintf(is6
? daemon
->packet
: daemon
->dhcp_buff
, "%lu", (unsigned long)data
.file_len
);
303 #ifdef HAVE_LUASCRIPT
304 if (daemon
->luascript
)
306 if (data
.action
== ACTION_TFTP
)
308 lua_getglobal(lua
, "tftp");
309 if (lua_type(lua
, -1) != LUA_TFUNCTION
)
310 lua_pop(lua
, 1); /* tftp function optional */
313 lua_pushstring(lua
, action_str
); /* arg1 - action */
314 lua_newtable(lua
); /* arg2 - data table */
315 lua_pushstring(lua
, daemon
->addrbuff
);
316 lua_setfield(lua
, -2, "destination_address");
317 lua_pushstring(lua
, hostname
);
318 lua_setfield(lua
, -2, "file_name");
319 lua_pushstring(lua
, is6
? daemon
->packet
: daemon
->dhcp_buff
);
320 lua_setfield(lua
, -2, "file_size");
321 lua_call(lua
, 2, 0); /* pass 2 values, expect 0 */
326 lua_getglobal(lua
, "lease"); /* function to call */
327 lua_pushstring(lua
, action_str
); /* arg1 - action */
328 lua_newtable(lua
); /* arg2 - data table */
332 lua_pushstring(lua
, daemon
->packet
);
333 lua_setfield(lua
, -2, "client_duid");
334 lua_pushstring(lua
, daemon
->dhcp_packet
.iov_base
);
335 lua_setfield(lua
, -2, "server_duid");
336 lua_pushstring(lua
, daemon
->dhcp_buff3
);
337 lua_setfield(lua
, -2, "iaid");
340 if (!is6
&& data
.clid_len
!= 0)
342 lua_pushstring(lua
, daemon
->packet
);
343 lua_setfield(lua
, -2, "client_id");
346 if (strlen(data
.interface
) != 0)
348 lua_pushstring(lua
, data
.interface
);
349 lua_setfield(lua
, -2, "interface");
352 #ifdef HAVE_BROKEN_RTC
353 lua_pushnumber(lua
, data
.length
);
354 lua_setfield(lua
, -2, "lease_length");
356 lua_pushnumber(lua
, data
.expires
);
357 lua_setfield(lua
, -2, "lease_expires");
362 lua_pushstring(lua
, hostname
);
363 lua_setfield(lua
, -2, "hostname");
368 lua_pushstring(lua
, domain
);
369 lua_setfield(lua
, -2, "domain");
372 end
= extradata
+ data
.ed_len
;
376 buf
= grab_extradata_lua(buf
, end
, "vendor_class");
378 else if (data
.vendorclass_count
!= 0)
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
++)
384 sprintf(daemon
->dhcp_buff2
, "vendor_class%i", i
);
385 buf
= grab_extradata_lua(buf
, end
, daemon
->dhcp_buff2
);
390 buf
= grab_extradata_lua(buf
, end
, "supplied_hostname");
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");
402 buf
= grab_extradata_lua(buf
, end
, "tags");
405 buf
= grab_extradata_lua(buf
, end
, "relay_address");
406 else if (data
.giaddr
.s_addr
!= 0)
408 lua_pushstring(lua
, inet_ntoa(data
.giaddr
));
409 lua_setfield(lua
, -2, "relay_address");
412 for (i
= 0; buf
; i
++)
414 sprintf(daemon
->dhcp_buff2
, "user_class%i", i
);
415 buf
= grab_extradata_lua(buf
, end
, daemon
->dhcp_buff2
);
418 if (data
.action
!= ACTION_DEL
&& data
.remaining_time
!= 0)
420 lua_pushnumber(lua
, data
.remaining_time
);
421 lua_setfield(lua
, -2, "time_remaining");
424 if (data
.action
== ACTION_OLD_HOSTNAME
&& hostname
)
426 lua_pushstring(lua
, hostname
);
427 lua_setfield(lua
, -2, "old_hostname");
430 if (!is6
|| data
.hwaddr_len
!= 0)
432 lua_pushstring(lua
, daemon
->dhcp_buff
);
433 lua_setfield(lua
, -2, "mac_address");
436 lua_pushstring(lua
, daemon
->addrbuff
);
437 lua_setfield(lua
, -2, "ip_address");
439 lua_call(lua
, 2, 0); /* pass 2 values, expect 0 */
444 /* no script, just lua */
445 if (!daemon
->lease_change_command
)
448 /* possible fork errors are all temporary resource problems */
449 while ((pid
= fork()) == -1 && (errno
== EAGAIN
|| errno
== ENOMEM
))
455 /* wait for child to complete */
458 /* reap our children's children, if necessary */
462 pid_t rc
= wait(&status
);
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
);
474 if (rc
== -1 && errno
!= EINTR
)
481 if (data
.action
!= ACTION_TFTP
)
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
);
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
);
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
);
500 my_setenv("DNSMASQ_DOMAIN", domain
, &err
);
502 end
= extradata
+ data
.ed_len
;
506 buf
= grab_extradata(buf
, end
, "DNSMASQ_VENDOR_CLASS", &err
);
510 if (data
.vendorclass_count
!= 0)
512 buf
= grab_extradata(buf
, end
, "DNSMASQ_VENDOR_CLASS_ID", &err
);
513 for (i
= 0; i
< data
.vendorclass_count
- 1; i
++)
515 sprintf(daemon
->dhcp_buff2
, "DNSMASQ_VENDOR_CLASS%i", i
);
516 buf
= grab_extradata(buf
, end
, daemon
->dhcp_buff2
, &err
);
522 buf
= grab_extradata(buf
, end
, "DNSMASQ_SUPPLIED_HOSTNAME", &err
);
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
);
534 buf
= grab_extradata(buf
, end
, "DNSMASQ_TAGS", &err
);
537 buf
= grab_extradata(buf
, end
, "DNSMASQ_RELAY_ADDRESS", &err
);
539 my_setenv("DNSMASQ_RELAY_ADDRESS", data
.giaddr
.s_addr
!= 0 ? inet_ntoa(data
.giaddr
) : NULL
, &err
);
541 for (i
= 0; buf
; i
++)
543 sprintf(daemon
->dhcp_buff2
, "DNSMASQ_USER_CLASS%i", i
);
544 buf
= grab_extradata(buf
, end
, daemon
->dhcp_buff2
, &err
);
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
);
550 my_setenv("DNSMASQ_OLD_HOSTNAME", data
.action
== ACTION_OLD_HOSTNAME
? hostname
: NULL
, &err
);
551 if (data
.action
== ACTION_OLD_HOSTNAME
)
555 my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS
) ? "1" : NULL
, &err
);
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
);
562 p
= strrchr(daemon
->lease_change_command
, '/');
565 execl(daemon
->lease_change_command
,
566 p
? p
+1 : daemon
->lease_change_command
,
567 action_str
, is6
? daemon
->packet
: daemon
->dhcp_buff
,
568 daemon
->addrbuff
, hostname
, (char*)NULL
);
571 /* failed, send event so the main process logs the problem */
572 send_event(event_fd
, EVENT_EXEC_ERR
, err
, NULL
);
577 static void my_setenv(const char *name
, const char *value
, int *error
)
583 else if (setenv(name
, value
, 1) != 0)
588 static unsigned char *grab_extradata(unsigned char *buf
, unsigned char *end
, char *env
, int *err
)
590 unsigned char *next
= NULL
;
593 if (buf
&& (buf
!= end
))
595 for (next
= buf
; ; next
++)
604 if (next
&& (next
!= buf
))
607 /* No "=" in value */
608 if ((p
= strchr((char *)buf
, '=')))
614 my_setenv(env
, val
, err
);
616 return next
? next
+ 1 : NULL
;
619 #ifdef HAVE_LUASCRIPT
620 static unsigned char *grab_extradata_lua(unsigned char *buf
, unsigned char *end
, char *field
)
624 if (!buf
|| (buf
== end
))
627 for (next
= buf
; *next
!= 0; next
++)
633 lua_pushstring(lua
, (char *)buf
);
634 lua_setfield(lua
, -2, field
);
641 static void buff_alloc(size_t size
)
645 struct script_data
*new;
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;
651 if (!(new = whine_malloc(size
)))
660 /* pack up lease data into a buffer */
661 void queue_script(int action
, struct dhcp_lease
*lease
, char *hostname
, time_t now
)
664 unsigned int hostname_len
= 0, clid_len
= 0, ed_len
= 0;
665 int fd
= daemon
->dhcpfd
;
668 fd
= daemon
->dhcp6fd
;
672 if (daemon
->helperfd
== -1)
675 if (lease
->extradata
)
676 ed_len
= lease
->extradata_len
;
678 clid_len
= lease
->clid_len
;
680 hostname_len
= strlen(hostname
) + 1;
682 buff_alloc(sizeof(struct script_data
) + clid_len
+ ed_len
+ hostname_len
);
684 buf
->action
= action
;
685 buf
->flags
= lease
->flags
;
687 buf
->vendorclass_count
= lease
->vendorclass_count
;
688 buf
->addr6
= lease
->addr6
;
689 buf
->iaid
= lease
->iaid
;
691 buf
->hwaddr_len
= lease
->hwaddr_len
;
692 buf
->hwaddr_type
= lease
->hwaddr_type
;
693 buf
->clid_len
= clid_len
;
694 buf
->ed_len
= ed_len
;
695 buf
->hostname_len
= hostname_len
;
696 buf
->addr
= lease
->addr
;
697 buf
->giaddr
= lease
->giaddr
;
698 memcpy(buf
->hwaddr
, lease
->hwaddr
, DHCP_CHADDR_MAX
);
699 if (!indextoname(fd
, lease
->last_interface
, buf
->interface
))
700 buf
->interface
[0] = 0;
702 #ifdef HAVE_BROKEN_RTC
703 buf
->length
= lease
->length
;
705 buf
->expires
= lease
->expires
;
708 if (lease
->expires
!= 0)
709 buf
->remaining_time
= (unsigned int)difftime(lease
->expires
, now
);
711 buf
->remaining_time
= 0;
713 p
= (unsigned char *)(buf
+1);
716 memcpy(p
, lease
->clid
, clid_len
);
719 if (hostname_len
!= 0)
721 memcpy(p
, hostname
, hostname_len
);
726 memcpy(p
, lease
->extradata
, ed_len
);
729 bytes_in_buf
= p
- (unsigned char *)buf
;
733 /* This nastily re-uses DHCP-fields for TFTP stuff */
734 void queue_tftp(off_t file_len
, char *filename
, union mysockaddr
*peer
)
736 unsigned int filename_len
;
739 if (daemon
->helperfd
== -1)
742 filename_len
= strlen(filename
) + 1;
743 buff_alloc(sizeof(struct script_data
) + filename_len
);
744 memset(buf
, 0, sizeof(struct script_data
));
746 buf
->action
= ACTION_TFTP
;
747 buf
->hostname_len
= filename_len
;
748 buf
->file_len
= file_len
;
750 if ((buf
->flags
= peer
->sa
.sa_family
) == AF_INET
)
751 buf
->addr
= peer
->in
.sin_addr
;
754 buf
->addr6
= peer
->in6
.sin6_addr
;
757 memcpy((unsigned char *)(buf
+1), filename
, filename_len
);
759 bytes_in_buf
= sizeof(struct script_data
) + filename_len
;
763 int helper_buf_empty(void)
765 return bytes_in_buf
== 0;
768 void helper_write(void)
772 if (bytes_in_buf
== 0)
775 if ((rc
= write(daemon
->helperfd
, buf
, bytes_in_buf
)) != -1)
777 if (bytes_in_buf
!= (size_t)rc
)
778 memmove(buf
, buf
+ rc
, bytes_in_buf
- rc
);
783 if (errno
== EAGAIN
|| errno
== EINTR
)