blob: ad76e254b0b916fb6ed3283bcd8f2bb398f31c62 [file] [log] [blame]
San Mehatffd68722010-01-20 09:56:15 -08001Index: src/dnsmasq.c
2===================================================================
3--- src/dnsmasq.c (revision 696)
4+++ src/dnsmasq.c (revision 821)
5@@ -59,7 +59,6 @@
6 static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
7 static void check_dns_listeners(fd_set *set, time_t now);
8 static void sig_handler(int sig);
9-static void async_event(int pipe, time_t now);
10 static void fatal_event(struct event_desc *ev);
11 static void poll_resolv(void);
12
13@@ -275,7 +274,7 @@
14 piperead = pipefd[0];
15 pipewrite = pipefd[1];
16 /* prime the pipe to load stuff first time. */
17- send_event(pipewrite, EVENT_RELOAD, 0);
18+ send_event(pipewrite, EVENT_RELOAD, 0, 0);
19
20 err_pipe[1] = -1;
21
22@@ -340,7 +339,7 @@
23 }
24 else if (getuid() == 0)
25 {
26- send_event(err_pipe[1], EVENT_PIDFILE, errno);
27+ send_event(err_pipe[1], EVENT_PIDFILE, errno, 0);
28 _exit(0);
29 }
30 }
31@@ -372,7 +371,7 @@
32 (setgroups(0, &dummy) == -1 ||
33 setgid(gp->gr_gid) == -1))
34 {
35- send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
36+ send_event(err_pipe[1], EVENT_GROUP_ERR, errno, 0);
37 _exit(0);
38 }
39
40@@ -415,14 +414,14 @@
41
42 if (bad_capabilities != 0)
43 {
44- send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
45+ send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, 0);
46 _exit(0);
47 }
48
49 /* finally drop root */
50 if (setuid(ent_pw->pw_uid) == -1)
51 {
52- send_event(err_pipe[1], EVENT_USER_ERR, errno);
53+ send_event(err_pipe[1], EVENT_USER_ERR, errno, 0);
54 _exit(0);
55 }
56
57@@ -434,7 +433,7 @@
58 /* lose the setuid and setgid capbilities */
59 if (capset(hdr, data) == -1)
60 {
61- send_event(err_pipe[1], EVENT_CAP_ERR, errno);
62+ send_event(err_pipe[1], EVENT_CAP_ERR, errno, 0);
63 _exit(0);
64 }
65 #endif
66@@ -647,7 +646,7 @@
67 }
68
69 if (FD_ISSET(piperead, &rset))
70- async_event(piperead, now);
71+ async_event(piperead, now, NULL, 0);
72
73 #ifdef HAVE_LINUX_NETWORK
74 if (FD_ISSET(daemon->netlinkfd, &rset))
75@@ -674,7 +673,7 @@
76 #endif
77
78 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
79- dhcp_packet(now);
80+ dhcp_packet(piperead, now);
81
82 #ifndef NO_FORK
83 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
84@@ -719,17 +718,18 @@
85 else
86 return;
87
88- send_event(pipewrite, event, 0);
89+ send_event(pipewrite, event, 0, 0);
90 errno = errsave;
91 }
92 }
93
94-void send_event(int fd, int event, int data)
95+void send_event(int fd, int event, int data, int priv)
96 {
97 struct event_desc ev;
98
99 ev.event = event;
100 ev.data = data;
101+ ev.priv = priv;
102
103 /* error pipe, debug mode. */
104 if (fd == -1)
105@@ -771,14 +771,17 @@
106 die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
107 }
108 }
109-
110-static void async_event(int pipe, time_t now)
111+
112+/* returns the private data of the event
113+ */
114+int async_event(int pipe, time_t now, struct event_desc* event, unsigned int secs)
115 {
116 pid_t p;
117 struct event_desc ev;
118 int i;
119
120- if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
121+ if (read_timeout(pipe, (unsigned char *)&ev, sizeof(ev), now, secs) > 0)
122+ {
123 switch (ev.event)
124 {
125 case EVENT_RELOAD:
126@@ -872,6 +875,14 @@
127 flush_log();
128 exit(EC_GOOD);
129 }
130+ }
131+ else
132+ return -1; /* timeout */
133+
134+ if (event)
135+ memcpy( event, &ev, sizeof(ev));
136+
137+ return 0;
138 }
139
140 static void poll_resolv()
141Index: src/config.h
142===================================================================
143--- src/config.h (revision 696)
144+++ src/config.h (revision 821)
145@@ -51,6 +51,8 @@
146 #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
147 #define LOG_MAX 5 /* log-queue length */
148 #define RANDFILE "/dev/urandom"
149+#define SCRIPT_TIMEOUT 6
150+#define LEASE_CHECK_TIMEOUT 10
151
152 /* DBUS interface specifics */
153 #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
154Index: src/dnsmasq.h
155===================================================================
156--- src/dnsmasq.h (revision 696)
157+++ src/dnsmasq.h (revision 821)
158@@ -116,6 +116,7 @@
159 /* Async event queue */
160 struct event_desc {
161 int event, data;
162+ unsigned int priv;
163 };
164
165 #define EVENT_RELOAD 1
166@@ -390,6 +391,7 @@
167 #define ACTION_OLD_HOSTNAME 2
168 #define ACTION_OLD 3
169 #define ACTION_ADD 4
170+#define ACTION_ACCESS 5
171
172 #define DHCP_CHADDR_MAX 16
173
174@@ -709,6 +711,7 @@
175 char *print_mac(char *buff, unsigned char *mac, int len);
176 void bump_maxfd(int fd, int *max);
177 int read_write(int fd, unsigned char *packet, int size, int rw);
178+int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs);
179
180 /* log.c */
181 void die(char *message, char *arg1, int exit_code);
182@@ -748,7 +751,7 @@
183
184 /* dhcp.c */
185 void dhcp_init(void);
186-void dhcp_packet(time_t now);
187+void dhcp_packet(int piperead, time_t now);
188
189 struct dhcp_context *address_available(struct dhcp_context *context,
190 struct in_addr addr,
191@@ -792,14 +795,16 @@
192 void rerun_scripts(void);
193
194 /* rfc2131.c */
195-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
196+size_t dhcp_reply(int pipefd, struct dhcp_context *context, char *iface_name, int int_index,
197 size_t sz, time_t now, int unicast_dest, int *is_inform);
198
199 /* dnsmasq.c */
200 int make_icmp_sock(void);
201 int icmp_ping(struct in_addr addr);
202-void send_event(int fd, int event, int data);
203+void send_event(int fd, int event, int data, int priv);
204 void clear_cache_and_reload(time_t now);
205+int wait_for_child(int pipe);
206+int async_event(int pipe, time_t now, struct event_desc*, unsigned int timeout);
207
208 /* isc.c */
209 #ifdef HAVE_ISC_READER
210@@ -832,9 +837,9 @@
211 /* helper.c */
212 #ifndef NO_FORK
213 int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
214-void helper_write(void);
215+int helper_write(void);
216 void queue_script(int action, struct dhcp_lease *lease,
217- char *hostname, time_t now);
218+ char *hostname, time_t now, unsigned int uid);
219 int helper_buf_empty(void);
220 #endif
221
222Index: src/util.c
223===================================================================
224--- src/util.c (revision 696)
225+++ src/util.c (revision 821)
226@@ -444,3 +444,38 @@
227 return 1;
228 }
229
230+int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs)
231+{
232+ ssize_t n, done;
233+ time_t expire;
234+
235+ expire = now + secs;
236+
237+ for (done = 0; done < size; done += n)
238+ {
239+ retry:
240+ if (secs > 0) alarm(secs);
241+ n = read(fd, &packet[done], (size_t)(size - done));
242+
243+ if (n == 0)
244+ return 0;
245+ else if (n == -1)
246+ {
247+ if (errno == EINTR) {
248+ my_syslog(LOG_INFO, _("read timed out (errno %d)"), errno);
249+ return 0;
250+ }
251+
252+ if (retry_send() || errno == ENOMEM || errno == ENOBUFS || errno == EAGAIN)
253+ {
254+ if (secs == 0 || (secs > 0 && dnsmasq_time() < expire))
255+ goto retry;
256+ }
257+
258+ my_syslog(LOG_INFO, _("error in read (timeout %d, errno %d)"), secs, errno);
259+ return 0;
260+ }
261+ }
262+ return 1;
263+}
264+
265Index: src/dhcp.c
266===================================================================
267--- src/dhcp.c (revision 696)
268+++ src/dhcp.c (revision 821)
269@@ -103,7 +103,7 @@
270 daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
271 }
272
273-void dhcp_packet(time_t now)
274+void dhcp_packet(int piperead, time_t now)
275 {
276 struct dhcp_packet *mess;
277 struct dhcp_context *context;
278@@ -239,7 +239,8 @@
279 if (!iface_enumerate(&parm, complete_context, NULL))
280 return;
281 lease_prune(NULL, now); /* lose any expired leases */
282- iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
283+
284+ iov.iov_len = dhcp_reply(piperead, parm.current, ifr.ifr_name, iface_index, (size_t)sz,
285 now, unicast_dest, &is_inform);
286 lease_update_file(now);
287 lease_update_dns();
288Index: src/helper.c
289===================================================================
290--- src/helper.c (revision 696)
291+++ src/helper.c (revision 821)
292@@ -45,6 +45,7 @@
293 #endif
294 unsigned char hwaddr[DHCP_CHADDR_MAX];
295 char interface[IF_NAMESIZE];
296+ unsigned int uid;
297 };
298
299 static struct script_data *buf = NULL;
300@@ -60,7 +61,7 @@
301 then fork our process. */
302 if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
303 {
304- send_event(err_fd, EVENT_PIPE_ERR, errno);
305+ send_event(err_fd, EVENT_PIPE_ERR, errno, 0);
306 _exit(0);
307 }
308
309@@ -87,13 +88,13 @@
310 {
311 if (daemon->options & OPT_NO_FORK)
312 /* send error to daemon process if no-fork */
313- send_event(event_fd, EVENT_HUSER_ERR, errno);
314+ send_event(event_fd, EVENT_HUSER_ERR, errno, 0);
315 else
316 {
317 /* kill daemon */
318- send_event(event_fd, EVENT_DIE, 0);
319+ send_event(event_fd, EVENT_DIE, 0, 0);
320 /* return error */
321- send_event(err_fd, EVENT_HUSER_ERR, errno);;
322+ send_event(err_fd, EVENT_HUSER_ERR, errno, 0);
323 }
324 _exit(0);
325 }
326@@ -122,6 +123,8 @@
327 action_str = "del";
328 else if (data.action == ACTION_ADD)
329 action_str = "add";
330+ else if (data.action == ACTION_ACCESS)
331+ action_str = "access";
332 else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
333 action_str = "old";
334 else
335@@ -178,9 +181,11 @@
336 {
337 /* On error send event back to main process for logging */
338 if (WIFSIGNALED(status))
339- send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
340- else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
341- send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
342+ send_event(event_fd, EVENT_KILLED, WTERMSIG(status), data.uid);
343+ else if (WIFEXITED(status))
344+ send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), data.uid);
345+ else
346+ send_event(event_fd, EVENT_EXITED, -1, data.uid);
347 break;
348 }
349
350@@ -263,7 +268,7 @@
351 err = errno;
352 }
353 /* failed, send event so the main process logs the problem */
354- send_event(event_fd, EVENT_EXEC_ERR, err);
355+ send_event(event_fd, EVENT_EXEC_ERR, err, data.uid);
356 _exit(0);
357 }
358 }
359@@ -295,7 +300,7 @@
360 }
361
362 /* pack up lease data into a buffer */
363-void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
364+void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now, unsigned int uid)
365 {
366 unsigned char *p;
367 size_t size;
368@@ -332,6 +337,7 @@
369 buf_size = size;
370 }
371
372+ buf->uid = uid;
373 buf->action = action;
374 buf->hwaddr_len = lease->hwaddr_len;
375 buf->hwaddr_type = lease->hwaddr_type;
376@@ -393,12 +399,15 @@
377 return bytes_in_buf == 0;
378 }
379
380-void helper_write(void)
381+/* returns -1 if write failed for a reason, 1 if no data exist
382+ * and 0 if everything was ok.
383+ */
384+int helper_write(void)
385 {
386 ssize_t rc;
387
388 if (bytes_in_buf == 0)
389- return;
390+ return 1;
391
392 if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
393 {
394@@ -409,9 +418,11 @@
395 else
396 {
397 if (errno == EAGAIN || errno == EINTR)
398- return;
399+ return -1;
400 bytes_in_buf = 0;
401 }
402+
403+ return 0;
404 }
405
406 #endif
407Index: src/rfc2131.c
408===================================================================
409--- src/rfc2131.c (revision 696)
410+++ src/rfc2131.c (revision 821)
411@@ -100,8 +100,49 @@
412 int clid_len, unsigned char *clid, int *len_out);
413 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
414
415+static int check_access_script( int piperead, struct dhcp_lease *lease, struct dhcp_packet *mess, time_t now)
416+{
417+#ifndef NO_FORK
418+unsigned int uid;
419+struct event_desc ev;
420+int ret;
421+struct dhcp_lease _lease;
422+
423+ if (daemon->lease_change_command == NULL) return 0; /* ok */
424+
425+ if (!lease) { /* if host has not been seen before lease is NULL */
426+ memset(&_lease, 0, sizeof(_lease));
427+ lease = &_lease;
428+ lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
429+ }
430+
431+ uid = rand16();
432+ queue_script(ACTION_ACCESS, lease, NULL, now, uid);
433+
434+ /* send all data to helper process */
435+ do
436+ {
437+ helper_write();
438+ } while (helper_buf_empty() == 0);
439+
440+ /* wait for our event */
441+ ret = 0;
442+ do
443+ {
444+ ret = async_event( piperead, now, &ev, SCRIPT_TIMEOUT);
445+ }
446+ while(ev.priv != uid && ret >= 0);
447+
448+ if (ret < 0 || ev.data != 0) /* timeout or error */
449+ {
450+ return -1;
451+ }
452+
453+#endif
454+ return 0; /* ok */
455+}
456
457-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
458+size_t dhcp_reply(int piperead, struct dhcp_context *context, char *iface_name, int int_index,
459 size_t sz, time_t now, int unicast_dest, int *is_inform)
460 {
461 unsigned char *opt, *clid = NULL;
462@@ -252,7 +293,7 @@
463 mac->netid.next = netid;
464 netid = &mac->netid;
465 }
466-
467+
468 /* Determine network for this packet. Our caller will have already linked all the
469 contexts which match the addresses of the receiving interface but if the
470 machine has an address already, or came via a relay, or we have a subnet selector,
471@@ -329,7 +370,7 @@
472 my_syslog(LOG_INFO, _("Available DHCP range: %s -- %s"), daemon->namebuff, inet_ntoa(context_tmp->end));
473 }
474 }
475-
476+
477 mess->op = BOOTREPLY;
478
479 config = find_config(daemon->dhcp_conf, context, clid, clid_len,
480@@ -418,7 +459,7 @@
481 else
482 mess->yiaddr = lease->addr;
483 }
484-
485+
486 if (!message &&
487 !lease &&
488 (!(lease = lease_allocate(mess->yiaddr))))
489@@ -641,7 +682,14 @@
490 memcpy(req_options, option_ptr(opt, 0), option_len(opt));
491 req_options[option_len(opt)] = OPTION_END;
492 }
493-
494+
495+ if (mess_type == DHCPREQUEST || mess_type == DHCPDISCOVER)
496+ if (check_access_script(piperead, lease, mess, now) < 0)
497+ {
498+ my_syslog(LOG_INFO, _("Ignoring client due to access script"));
499+ return 0;
500+ }
501+
502 switch (mess_type)
503 {
504 case DHCPDECLINE:
505Index: src/log.c
506===================================================================
507--- src/log.c (revision 696)
508+++ src/log.c (revision 821)
509@@ -73,7 +73,7 @@
510
511 if (!log_reopen(daemon->log_file))
512 {
513- send_event(errfd, EVENT_LOG_ERR, errno);
514+ send_event(errfd, EVENT_LOG_ERR, errno, 0);
515 _exit(0);
516 }
517
518Index: src/lease.c
519===================================================================
520--- src/lease.c (revision 696)
521+++ src/lease.c (revision 821)
522@@ -511,7 +511,7 @@
523 if (lease->old_hostname)
524 {
525 #ifndef NO_FORK
526- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
527+ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
528 #endif
529 free(lease->old_hostname);
530 lease->old_hostname = NULL;
531@@ -520,7 +520,7 @@
532 else
533 {
534 #ifndef NO_FORK
535- queue_script(ACTION_DEL, lease, lease->hostname, now);
536+ queue_script(ACTION_DEL, lease, lease->hostname, now, 0);
537 #endif
538 old_leases = lease->next;
539
540@@ -540,7 +540,7 @@
541 if (lease->old_hostname)
542 {
543 #ifndef NO_FORK
544- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
545+ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
546 #endif
547 free(lease->old_hostname);
548 lease->old_hostname = NULL;
549@@ -552,7 +552,7 @@
550 (lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
551 {
552 #ifndef NO_FORK
553- queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
554+ queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now, 0);
555 #endif
556 lease->new = lease->changed = lease->aux_changed = 0;
557
558Index: man/dnsmasq.8
559===================================================================
560--- man/dnsmasq.8 (revision 696)
561+++ man/dnsmasq.8 (revision 821)
562@@ -724,12 +724,15 @@
563 .B \-6 --dhcp-script=<path>
564 Whenever a new DHCP lease is created, or an old one destroyed, the
565 binary specified by this option is run. The arguments to the process
566-are "add", "old" or "del", the MAC
567+are "add", "old", "access" or "del", the MAC
568 address of the host (or "<null>"), the IP address, and the hostname,
569 if known. "add" means a lease has been created, "del" means it has
570 been destroyed, "old" is a notification of an existing lease when
571 dnsmasq starts or a change to MAC address or hostname of an existing
572 lease (also, lease length or expiry and client-id, if leasefile-ro is set).
573+The "access" keyword means that a request was just received and depending
574+on the script exit status request for address will be granted, if exit status
575+is zero or not if it is non-zero.
576 The process is run as root (assuming that dnsmasq was originally run as
577 root) even if dnsmasq is configured to change UID to an unprivileged user.
578 The environment is inherited from the invoker of dnsmasq, and if the