1*c2c26c8bSAndroid Build Coastguard Worker /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2*c2c26c8bSAndroid Build Coastguard Worker
3*c2c26c8bSAndroid Build Coastguard Worker This program is free software; you can redistribute it and/or modify
4*c2c26c8bSAndroid Build Coastguard Worker it under the terms of the GNU General Public License as published by
5*c2c26c8bSAndroid Build Coastguard Worker the Free Software Foundation; version 2 dated June, 1991, or
6*c2c26c8bSAndroid Build Coastguard Worker (at your option) version 3 dated 29 June, 2007.
7*c2c26c8bSAndroid Build Coastguard Worker
8*c2c26c8bSAndroid Build Coastguard Worker This program is distributed in the hope that it will be useful,
9*c2c26c8bSAndroid Build Coastguard Worker but WITHOUT ANY WARRANTY; without even the implied warranty of
10*c2c26c8bSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11*c2c26c8bSAndroid Build Coastguard Worker GNU General Public License for more details.
12*c2c26c8bSAndroid Build Coastguard Worker
13*c2c26c8bSAndroid Build Coastguard Worker You should have received a copy of the GNU General Public License
14*c2c26c8bSAndroid Build Coastguard Worker along with this program. If not, see <http://www.gnu.org/licenses/>.
15*c2c26c8bSAndroid Build Coastguard Worker */
16*c2c26c8bSAndroid Build Coastguard Worker
17*c2c26c8bSAndroid Build Coastguard Worker #include "dnsmasq.h"
18*c2c26c8bSAndroid Build Coastguard Worker
19*c2c26c8bSAndroid Build Coastguard Worker /* This file has code to fork a helper process which recieves data via a pipe
20*c2c26c8bSAndroid Build Coastguard Worker shared with the main process and which is responsible for calling a script when
21*c2c26c8bSAndroid Build Coastguard Worker DHCP leases change.
22*c2c26c8bSAndroid Build Coastguard Worker
23*c2c26c8bSAndroid Build Coastguard Worker The helper process is forked before the main process drops root, so it retains root
24*c2c26c8bSAndroid Build Coastguard Worker privs to pass on to the script. For this reason it tries to be paranoid about
25*c2c26c8bSAndroid Build Coastguard Worker data received from the main process, in case that has been compromised. We don't
26*c2c26c8bSAndroid Build Coastguard Worker want the helper to give an attacker root. In particular, the script to be run is
27*c2c26c8bSAndroid Build Coastguard Worker not settable via the pipe, once the fork has taken place it is not alterable by the
28*c2c26c8bSAndroid Build Coastguard Worker main process.
29*c2c26c8bSAndroid Build Coastguard Worker */
30*c2c26c8bSAndroid Build Coastguard Worker
31*c2c26c8bSAndroid Build Coastguard Worker #if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
32*c2c26c8bSAndroid Build Coastguard Worker
33*c2c26c8bSAndroid Build Coastguard Worker static void my_setenv(const char* name, const char* value, int* error);
34*c2c26c8bSAndroid Build Coastguard Worker
35*c2c26c8bSAndroid Build Coastguard Worker struct script_data {
36*c2c26c8bSAndroid Build Coastguard Worker unsigned char action, hwaddr_len, hwaddr_type;
37*c2c26c8bSAndroid Build Coastguard Worker unsigned char clid_len, hostname_len, uclass_len, vclass_len, shost_len;
38*c2c26c8bSAndroid Build Coastguard Worker struct in_addr addr, giaddr;
39*c2c26c8bSAndroid Build Coastguard Worker unsigned int remaining_time;
40*c2c26c8bSAndroid Build Coastguard Worker #ifdef HAVE_BROKEN_RTC
41*c2c26c8bSAndroid Build Coastguard Worker unsigned int length;
42*c2c26c8bSAndroid Build Coastguard Worker #else
43*c2c26c8bSAndroid Build Coastguard Worker time_t expires;
44*c2c26c8bSAndroid Build Coastguard Worker #endif
45*c2c26c8bSAndroid Build Coastguard Worker unsigned char hwaddr[DHCP_CHADDR_MAX];
46*c2c26c8bSAndroid Build Coastguard Worker char interface[IF_NAMESIZE];
47*c2c26c8bSAndroid Build Coastguard Worker };
48*c2c26c8bSAndroid Build Coastguard Worker
49*c2c26c8bSAndroid Build Coastguard Worker static struct script_data* buf = NULL;
50*c2c26c8bSAndroid Build Coastguard Worker static size_t bytes_in_buf = 0, buf_size = 0;
51*c2c26c8bSAndroid Build Coastguard Worker
create_helper(int event_fd,int err_fd,uid_t uid,gid_t gid,long max_fd)52*c2c26c8bSAndroid Build Coastguard Worker int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) {
53*c2c26c8bSAndroid Build Coastguard Worker pid_t pid;
54*c2c26c8bSAndroid Build Coastguard Worker int i, pipefd[2];
55*c2c26c8bSAndroid Build Coastguard Worker struct sigaction sigact;
56*c2c26c8bSAndroid Build Coastguard Worker
57*c2c26c8bSAndroid Build Coastguard Worker /* create the pipe through which the main program sends us commands,
58*c2c26c8bSAndroid Build Coastguard Worker then fork our process. */
59*c2c26c8bSAndroid Build Coastguard Worker if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1) {
60*c2c26c8bSAndroid Build Coastguard Worker send_event(err_fd, EVENT_PIPE_ERR, errno);
61*c2c26c8bSAndroid Build Coastguard Worker _exit(0);
62*c2c26c8bSAndroid Build Coastguard Worker }
63*c2c26c8bSAndroid Build Coastguard Worker
64*c2c26c8bSAndroid Build Coastguard Worker if (pid != 0) {
65*c2c26c8bSAndroid Build Coastguard Worker close(pipefd[0]); /* close reader side */
66*c2c26c8bSAndroid Build Coastguard Worker return pipefd[1];
67*c2c26c8bSAndroid Build Coastguard Worker }
68*c2c26c8bSAndroid Build Coastguard Worker
69*c2c26c8bSAndroid Build Coastguard Worker /* ignore SIGTERM, so that we can clean up when the main process gets hit
70*c2c26c8bSAndroid Build Coastguard Worker and SIGALRM so that we can use sleep() */
71*c2c26c8bSAndroid Build Coastguard Worker sigact.sa_handler = SIG_IGN;
72*c2c26c8bSAndroid Build Coastguard Worker sigact.sa_flags = 0;
73*c2c26c8bSAndroid Build Coastguard Worker sigemptyset(&sigact.sa_mask);
74*c2c26c8bSAndroid Build Coastguard Worker sigaction(SIGTERM, &sigact, NULL);
75*c2c26c8bSAndroid Build Coastguard Worker sigaction(SIGALRM, &sigact, NULL);
76*c2c26c8bSAndroid Build Coastguard Worker
77*c2c26c8bSAndroid Build Coastguard Worker if (!(daemon->options & OPT_DEBUG) && uid != 0) {
78*c2c26c8bSAndroid Build Coastguard Worker gid_t unused;
79*c2c26c8bSAndroid Build Coastguard Worker if (setgroups(0, &unused) == -1 || setgid(gid) == -1 || setuid(uid) == -1) {
80*c2c26c8bSAndroid Build Coastguard Worker if (daemon->options & OPT_NO_FORK) /* send error to daemon process if no-fork */
81*c2c26c8bSAndroid Build Coastguard Worker send_event(event_fd, EVENT_HUSER_ERR, errno);
82*c2c26c8bSAndroid Build Coastguard Worker else {
83*c2c26c8bSAndroid Build Coastguard Worker /* kill daemon */
84*c2c26c8bSAndroid Build Coastguard Worker send_event(event_fd, EVENT_DIE, 0);
85*c2c26c8bSAndroid Build Coastguard Worker /* return error */
86*c2c26c8bSAndroid Build Coastguard Worker send_event(err_fd, EVENT_HUSER_ERR, errno);
87*c2c26c8bSAndroid Build Coastguard Worker }
88*c2c26c8bSAndroid Build Coastguard Worker _exit(0);
89*c2c26c8bSAndroid Build Coastguard Worker }
90*c2c26c8bSAndroid Build Coastguard Worker }
91*c2c26c8bSAndroid Build Coastguard Worker
92*c2c26c8bSAndroid Build Coastguard Worker /* close all the sockets etc, we don't need them here. This closes err_fd, so that
93*c2c26c8bSAndroid Build Coastguard Worker main process can return. */
94*c2c26c8bSAndroid Build Coastguard Worker for (max_fd--; max_fd >= 0; max_fd--)
95*c2c26c8bSAndroid Build Coastguard Worker if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
96*c2c26c8bSAndroid Build Coastguard Worker max_fd != pipefd[0] && max_fd != event_fd)
97*c2c26c8bSAndroid Build Coastguard Worker close(max_fd);
98*c2c26c8bSAndroid Build Coastguard Worker
99*c2c26c8bSAndroid Build Coastguard Worker /* loop here */
100*c2c26c8bSAndroid Build Coastguard Worker while (1) {
101*c2c26c8bSAndroid Build Coastguard Worker struct script_data data;
102*c2c26c8bSAndroid Build Coastguard Worker char *p, *action_str, *hostname = NULL;
103*c2c26c8bSAndroid Build Coastguard Worker unsigned char* buf = (unsigned char*) daemon->namebuff;
104*c2c26c8bSAndroid Build Coastguard Worker int err = 0;
105*c2c26c8bSAndroid Build Coastguard Worker
106*c2c26c8bSAndroid Build Coastguard Worker /* we read zero bytes when pipe closed: this is our signal to exit */
107*c2c26c8bSAndroid Build Coastguard Worker if (!read_write(pipefd[0], (unsigned char*) &data, sizeof(data), 1)) _exit(0);
108*c2c26c8bSAndroid Build Coastguard Worker
109*c2c26c8bSAndroid Build Coastguard Worker if (data.action == ACTION_DEL)
110*c2c26c8bSAndroid Build Coastguard Worker action_str = "del";
111*c2c26c8bSAndroid Build Coastguard Worker else if (data.action == ACTION_ADD)
112*c2c26c8bSAndroid Build Coastguard Worker action_str = "add";
113*c2c26c8bSAndroid Build Coastguard Worker else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
114*c2c26c8bSAndroid Build Coastguard Worker action_str = "old";
115*c2c26c8bSAndroid Build Coastguard Worker else
116*c2c26c8bSAndroid Build Coastguard Worker continue;
117*c2c26c8bSAndroid Build Coastguard Worker
118*c2c26c8bSAndroid Build Coastguard Worker /* stringify MAC into dhcp_buff */
119*c2c26c8bSAndroid Build Coastguard Worker p = daemon->dhcp_buff;
120*c2c26c8bSAndroid Build Coastguard Worker if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
121*c2c26c8bSAndroid Build Coastguard Worker p += sprintf(p, "%.2x-", data.hwaddr_type);
122*c2c26c8bSAndroid Build Coastguard Worker for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) {
123*c2c26c8bSAndroid Build Coastguard Worker p += sprintf(p, "%.2x", data.hwaddr[i]);
124*c2c26c8bSAndroid Build Coastguard Worker if (i != data.hwaddr_len - 1) p += sprintf(p, ":");
125*c2c26c8bSAndroid Build Coastguard Worker }
126*c2c26c8bSAndroid Build Coastguard Worker
127*c2c26c8bSAndroid Build Coastguard Worker /* and CLID into packet */
128*c2c26c8bSAndroid Build Coastguard Worker if (!read_write(pipefd[0], buf, data.clid_len, 1)) continue;
129*c2c26c8bSAndroid Build Coastguard Worker for (p = daemon->packet, i = 0; i < data.clid_len; i++) {
130*c2c26c8bSAndroid Build Coastguard Worker p += sprintf(p, "%.2x", buf[i]);
131*c2c26c8bSAndroid Build Coastguard Worker if (i != data.clid_len - 1) p += sprintf(p, ":");
132*c2c26c8bSAndroid Build Coastguard Worker }
133*c2c26c8bSAndroid Build Coastguard Worker
134*c2c26c8bSAndroid Build Coastguard Worker /* and expiry or length into dhcp_buff2 */
135*c2c26c8bSAndroid Build Coastguard Worker #ifdef HAVE_BROKEN_RTC
136*c2c26c8bSAndroid Build Coastguard Worker sprintf(daemon->dhcp_buff2, "%u ", data.length);
137*c2c26c8bSAndroid Build Coastguard Worker #else
138*c2c26c8bSAndroid Build Coastguard Worker sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long) data.expires);
139*c2c26c8bSAndroid Build Coastguard Worker #endif
140*c2c26c8bSAndroid Build Coastguard Worker
141*c2c26c8bSAndroid Build Coastguard Worker if (!read_write(pipefd[0], buf,
142*c2c26c8bSAndroid Build Coastguard Worker data.hostname_len + data.uclass_len + data.vclass_len + data.shost_len, 1))
143*c2c26c8bSAndroid Build Coastguard Worker continue;
144*c2c26c8bSAndroid Build Coastguard Worker
145*c2c26c8bSAndroid Build Coastguard Worker /* possible fork errors are all temporary resource problems */
146*c2c26c8bSAndroid Build Coastguard Worker while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM)) sleep(2);
147*c2c26c8bSAndroid Build Coastguard Worker
148*c2c26c8bSAndroid Build Coastguard Worker if (pid == -1) continue;
149*c2c26c8bSAndroid Build Coastguard Worker
150*c2c26c8bSAndroid Build Coastguard Worker /* wait for child to complete */
151*c2c26c8bSAndroid Build Coastguard Worker if (pid != 0) {
152*c2c26c8bSAndroid Build Coastguard Worker /* reap our children's children, if necessary */
153*c2c26c8bSAndroid Build Coastguard Worker while (1) {
154*c2c26c8bSAndroid Build Coastguard Worker int status;
155*c2c26c8bSAndroid Build Coastguard Worker pid_t rc = wait(&status);
156*c2c26c8bSAndroid Build Coastguard Worker
157*c2c26c8bSAndroid Build Coastguard Worker if (rc == pid) {
158*c2c26c8bSAndroid Build Coastguard Worker /* On error send event back to main process for logging */
159*c2c26c8bSAndroid Build Coastguard Worker if (WIFSIGNALED(status))
160*c2c26c8bSAndroid Build Coastguard Worker send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
161*c2c26c8bSAndroid Build Coastguard Worker else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
162*c2c26c8bSAndroid Build Coastguard Worker send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
163*c2c26c8bSAndroid Build Coastguard Worker break;
164*c2c26c8bSAndroid Build Coastguard Worker }
165*c2c26c8bSAndroid Build Coastguard Worker
166*c2c26c8bSAndroid Build Coastguard Worker if (rc == -1 && errno != EINTR) break;
167*c2c26c8bSAndroid Build Coastguard Worker }
168*c2c26c8bSAndroid Build Coastguard Worker
169*c2c26c8bSAndroid Build Coastguard Worker continue;
170*c2c26c8bSAndroid Build Coastguard Worker }
171*c2c26c8bSAndroid Build Coastguard Worker
172*c2c26c8bSAndroid Build Coastguard Worker if (data.clid_len != 0) my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
173*c2c26c8bSAndroid Build Coastguard Worker
174*c2c26c8bSAndroid Build Coastguard Worker if (strlen(data.interface) != 0) my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
175*c2c26c8bSAndroid Build Coastguard Worker
176*c2c26c8bSAndroid Build Coastguard Worker #ifdef HAVE_BROKEN_RTC
177*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
178*c2c26c8bSAndroid Build Coastguard Worker #else
179*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
180*c2c26c8bSAndroid Build Coastguard Worker #endif
181*c2c26c8bSAndroid Build Coastguard Worker
182*c2c26c8bSAndroid Build Coastguard Worker if (data.vclass_len != 0) {
183*c2c26c8bSAndroid Build Coastguard Worker buf[data.vclass_len - 1] = 0; /* don't trust zero-term */
184*c2c26c8bSAndroid Build Coastguard Worker /* cannot have = chars in env - truncate if found . */
185*c2c26c8bSAndroid Build Coastguard Worker if ((p = strchr((char*) buf, '='))) *p = 0;
186*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_VENDOR_CLASS", (char*) buf, &err);
187*c2c26c8bSAndroid Build Coastguard Worker buf += data.vclass_len;
188*c2c26c8bSAndroid Build Coastguard Worker }
189*c2c26c8bSAndroid Build Coastguard Worker
190*c2c26c8bSAndroid Build Coastguard Worker if (data.uclass_len != 0) {
191*c2c26c8bSAndroid Build Coastguard Worker unsigned char* end = buf + data.uclass_len;
192*c2c26c8bSAndroid Build Coastguard Worker buf[data.uclass_len - 1] = 0; /* don't trust zero-term */
193*c2c26c8bSAndroid Build Coastguard Worker
194*c2c26c8bSAndroid Build Coastguard Worker for (i = 0; buf < end;) {
195*c2c26c8bSAndroid Build Coastguard Worker size_t len = strlen((char*) buf) + 1;
196*c2c26c8bSAndroid Build Coastguard Worker if ((p = strchr((char*) buf, '='))) *p = 0;
197*c2c26c8bSAndroid Build Coastguard Worker if (strlen((char*) buf) != 0) {
198*c2c26c8bSAndroid Build Coastguard Worker sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i++);
199*c2c26c8bSAndroid Build Coastguard Worker my_setenv(daemon->dhcp_buff2, (char*) buf, &err);
200*c2c26c8bSAndroid Build Coastguard Worker }
201*c2c26c8bSAndroid Build Coastguard Worker buf += len;
202*c2c26c8bSAndroid Build Coastguard Worker }
203*c2c26c8bSAndroid Build Coastguard Worker }
204*c2c26c8bSAndroid Build Coastguard Worker
205*c2c26c8bSAndroid Build Coastguard Worker if (data.shost_len != 0) {
206*c2c26c8bSAndroid Build Coastguard Worker buf[data.shost_len - 1] = 0; /* don't trust zero-term */
207*c2c26c8bSAndroid Build Coastguard Worker /* cannot have = chars in env - truncate if found . */
208*c2c26c8bSAndroid Build Coastguard Worker if ((p = strchr((char*) buf, '='))) *p = 0;
209*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_SUPPLIED_HOSTNAME", (char*) buf, &err);
210*c2c26c8bSAndroid Build Coastguard Worker buf += data.shost_len;
211*c2c26c8bSAndroid Build Coastguard Worker }
212*c2c26c8bSAndroid Build Coastguard Worker
213*c2c26c8bSAndroid Build Coastguard Worker if (data.giaddr.s_addr != 0)
214*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
215*c2c26c8bSAndroid Build Coastguard Worker
216*c2c26c8bSAndroid Build Coastguard Worker sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
217*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
218*c2c26c8bSAndroid Build Coastguard Worker
219*c2c26c8bSAndroid Build Coastguard Worker if (data.hostname_len != 0) {
220*c2c26c8bSAndroid Build Coastguard Worker char* dot;
221*c2c26c8bSAndroid Build Coastguard Worker hostname = (char*) buf;
222*c2c26c8bSAndroid Build Coastguard Worker hostname[data.hostname_len - 1] = 0;
223*c2c26c8bSAndroid Build Coastguard Worker if (!legal_hostname(hostname))
224*c2c26c8bSAndroid Build Coastguard Worker hostname = NULL;
225*c2c26c8bSAndroid Build Coastguard Worker else if ((dot = strchr(hostname, '.'))) {
226*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_DOMAIN", dot + 1, &err);
227*c2c26c8bSAndroid Build Coastguard Worker *dot = 0;
228*c2c26c8bSAndroid Build Coastguard Worker }
229*c2c26c8bSAndroid Build Coastguard Worker }
230*c2c26c8bSAndroid Build Coastguard Worker
231*c2c26c8bSAndroid Build Coastguard Worker if (data.action == ACTION_OLD_HOSTNAME && hostname) {
232*c2c26c8bSAndroid Build Coastguard Worker my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
233*c2c26c8bSAndroid Build Coastguard Worker hostname = NULL;
234*c2c26c8bSAndroid Build Coastguard Worker }
235*c2c26c8bSAndroid Build Coastguard Worker
236*c2c26c8bSAndroid Build Coastguard Worker /* we need to have the event_fd around if exec fails */
237*c2c26c8bSAndroid Build Coastguard Worker if ((i = fcntl(event_fd, F_GETFD)) != -1) fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
238*c2c26c8bSAndroid Build Coastguard Worker close(pipefd[0]);
239*c2c26c8bSAndroid Build Coastguard Worker
240*c2c26c8bSAndroid Build Coastguard Worker p = strrchr(daemon->lease_change_command, '/');
241*c2c26c8bSAndroid Build Coastguard Worker if (err == 0) {
242*c2c26c8bSAndroid Build Coastguard Worker execl(daemon->lease_change_command, p ? p + 1 : daemon->lease_change_command,
243*c2c26c8bSAndroid Build Coastguard Worker action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*) NULL);
244*c2c26c8bSAndroid Build Coastguard Worker err = errno;
245*c2c26c8bSAndroid Build Coastguard Worker }
246*c2c26c8bSAndroid Build Coastguard Worker /* failed, send event so the main process logs the problem */
247*c2c26c8bSAndroid Build Coastguard Worker send_event(event_fd, EVENT_EXEC_ERR, err);
248*c2c26c8bSAndroid Build Coastguard Worker _exit(0);
249*c2c26c8bSAndroid Build Coastguard Worker }
250*c2c26c8bSAndroid Build Coastguard Worker }
251*c2c26c8bSAndroid Build Coastguard Worker
my_setenv(const char * name,const char * value,int * error)252*c2c26c8bSAndroid Build Coastguard Worker static void my_setenv(const char* name, const char* value, int* error) {
253*c2c26c8bSAndroid Build Coastguard Worker if (*error == 0 && setenv(name, value, 1) != 0) *error = errno;
254*c2c26c8bSAndroid Build Coastguard Worker }
255*c2c26c8bSAndroid Build Coastguard Worker
256*c2c26c8bSAndroid Build Coastguard Worker /* pack up lease data into a buffer */
queue_script(int action,struct dhcp_lease * lease,char * hostname,time_t now)257*c2c26c8bSAndroid Build Coastguard Worker void queue_script(int action, struct dhcp_lease* lease, char* hostname, time_t now) {
258*c2c26c8bSAndroid Build Coastguard Worker unsigned char* p;
259*c2c26c8bSAndroid Build Coastguard Worker size_t size;
260*c2c26c8bSAndroid Build Coastguard Worker unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0;
261*c2c26c8bSAndroid Build Coastguard Worker unsigned int uclass_len = 0, shost_len = 0;
262*c2c26c8bSAndroid Build Coastguard Worker
263*c2c26c8bSAndroid Build Coastguard Worker /* no script */
264*c2c26c8bSAndroid Build Coastguard Worker if (daemon->helperfd == -1) return;
265*c2c26c8bSAndroid Build Coastguard Worker
266*c2c26c8bSAndroid Build Coastguard Worker if (lease->vendorclass) vclass_len = lease->vendorclass_len;
267*c2c26c8bSAndroid Build Coastguard Worker if (lease->userclass) uclass_len = lease->userclass_len;
268*c2c26c8bSAndroid Build Coastguard Worker if (lease->supplied_hostname) shost_len = lease->supplied_hostname_len;
269*c2c26c8bSAndroid Build Coastguard Worker if (lease->clid) clid_len = lease->clid_len;
270*c2c26c8bSAndroid Build Coastguard Worker if (hostname) hostname_len = strlen(hostname) + 1;
271*c2c26c8bSAndroid Build Coastguard Worker
272*c2c26c8bSAndroid Build Coastguard Worker size =
273*c2c26c8bSAndroid Build Coastguard Worker sizeof(struct script_data) + clid_len + vclass_len + uclass_len + shost_len + hostname_len;
274*c2c26c8bSAndroid Build Coastguard Worker
275*c2c26c8bSAndroid Build Coastguard Worker if (size > buf_size) {
276*c2c26c8bSAndroid Build Coastguard Worker struct script_data* new;
277*c2c26c8bSAndroid Build Coastguard Worker
278*c2c26c8bSAndroid Build Coastguard Worker /* start with reasonable size, will almost never need extending. */
279*c2c26c8bSAndroid Build Coastguard Worker if (size < sizeof(struct script_data) + 200) size = sizeof(struct script_data) + 200;
280*c2c26c8bSAndroid Build Coastguard Worker
281*c2c26c8bSAndroid Build Coastguard Worker if (!(new = whine_malloc(size))) return;
282*c2c26c8bSAndroid Build Coastguard Worker if (buf) free(buf);
283*c2c26c8bSAndroid Build Coastguard Worker buf = new;
284*c2c26c8bSAndroid Build Coastguard Worker buf_size = size;
285*c2c26c8bSAndroid Build Coastguard Worker }
286*c2c26c8bSAndroid Build Coastguard Worker
287*c2c26c8bSAndroid Build Coastguard Worker buf->action = action;
288*c2c26c8bSAndroid Build Coastguard Worker buf->hwaddr_len = lease->hwaddr_len;
289*c2c26c8bSAndroid Build Coastguard Worker buf->hwaddr_type = lease->hwaddr_type;
290*c2c26c8bSAndroid Build Coastguard Worker buf->clid_len = clid_len;
291*c2c26c8bSAndroid Build Coastguard Worker buf->vclass_len = vclass_len;
292*c2c26c8bSAndroid Build Coastguard Worker buf->uclass_len = uclass_len;
293*c2c26c8bSAndroid Build Coastguard Worker buf->shost_len = shost_len;
294*c2c26c8bSAndroid Build Coastguard Worker buf->hostname_len = hostname_len;
295*c2c26c8bSAndroid Build Coastguard Worker buf->addr = lease->addr;
296*c2c26c8bSAndroid Build Coastguard Worker buf->giaddr = lease->giaddr;
297*c2c26c8bSAndroid Build Coastguard Worker memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
298*c2c26c8bSAndroid Build Coastguard Worker buf->interface[0] = 0;
299*c2c26c8bSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_NETWORK
300*c2c26c8bSAndroid Build Coastguard Worker if (lease->last_interface != 0) {
301*c2c26c8bSAndroid Build Coastguard Worker struct ifreq ifr;
302*c2c26c8bSAndroid Build Coastguard Worker ifr.ifr_ifindex = lease->last_interface;
303*c2c26c8bSAndroid Build Coastguard Worker if (ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) != -1)
304*c2c26c8bSAndroid Build Coastguard Worker strncpy(buf->interface, ifr.ifr_name, IF_NAMESIZE);
305*c2c26c8bSAndroid Build Coastguard Worker }
306*c2c26c8bSAndroid Build Coastguard Worker #else
307*c2c26c8bSAndroid Build Coastguard Worker if (lease->last_interface != 0) if_indextoname(lease->last_interface, buf->interface);
308*c2c26c8bSAndroid Build Coastguard Worker #endif
309*c2c26c8bSAndroid Build Coastguard Worker
310*c2c26c8bSAndroid Build Coastguard Worker #ifdef HAVE_BROKEN_RTC
311*c2c26c8bSAndroid Build Coastguard Worker buf->length = lease->length;
312*c2c26c8bSAndroid Build Coastguard Worker #else
313*c2c26c8bSAndroid Build Coastguard Worker buf->expires = lease->expires;
314*c2c26c8bSAndroid Build Coastguard Worker #endif
315*c2c26c8bSAndroid Build Coastguard Worker buf->remaining_time = (unsigned int) difftime(lease->expires, now);
316*c2c26c8bSAndroid Build Coastguard Worker
317*c2c26c8bSAndroid Build Coastguard Worker p = (unsigned char*) (buf + 1);
318*c2c26c8bSAndroid Build Coastguard Worker if (clid_len != 0) {
319*c2c26c8bSAndroid Build Coastguard Worker memcpy(p, lease->clid, clid_len);
320*c2c26c8bSAndroid Build Coastguard Worker p += clid_len;
321*c2c26c8bSAndroid Build Coastguard Worker }
322*c2c26c8bSAndroid Build Coastguard Worker if (vclass_len != 0) {
323*c2c26c8bSAndroid Build Coastguard Worker memcpy(p, lease->vendorclass, vclass_len);
324*c2c26c8bSAndroid Build Coastguard Worker p += vclass_len;
325*c2c26c8bSAndroid Build Coastguard Worker }
326*c2c26c8bSAndroid Build Coastguard Worker if (uclass_len != 0) {
327*c2c26c8bSAndroid Build Coastguard Worker memcpy(p, lease->userclass, uclass_len);
328*c2c26c8bSAndroid Build Coastguard Worker p += uclass_len;
329*c2c26c8bSAndroid Build Coastguard Worker }
330*c2c26c8bSAndroid Build Coastguard Worker if (shost_len != 0) {
331*c2c26c8bSAndroid Build Coastguard Worker memcpy(p, lease->supplied_hostname, shost_len);
332*c2c26c8bSAndroid Build Coastguard Worker p += shost_len;
333*c2c26c8bSAndroid Build Coastguard Worker }
334*c2c26c8bSAndroid Build Coastguard Worker if (hostname_len != 0) {
335*c2c26c8bSAndroid Build Coastguard Worker memcpy(p, hostname, hostname_len);
336*c2c26c8bSAndroid Build Coastguard Worker p += hostname_len;
337*c2c26c8bSAndroid Build Coastguard Worker }
338*c2c26c8bSAndroid Build Coastguard Worker
339*c2c26c8bSAndroid Build Coastguard Worker bytes_in_buf = p - (unsigned char*) buf;
340*c2c26c8bSAndroid Build Coastguard Worker }
341*c2c26c8bSAndroid Build Coastguard Worker
helper_buf_empty(void)342*c2c26c8bSAndroid Build Coastguard Worker int helper_buf_empty(void) {
343*c2c26c8bSAndroid Build Coastguard Worker return bytes_in_buf == 0;
344*c2c26c8bSAndroid Build Coastguard Worker }
345*c2c26c8bSAndroid Build Coastguard Worker
helper_write(void)346*c2c26c8bSAndroid Build Coastguard Worker void helper_write(void) {
347*c2c26c8bSAndroid Build Coastguard Worker ssize_t rc;
348*c2c26c8bSAndroid Build Coastguard Worker
349*c2c26c8bSAndroid Build Coastguard Worker if (bytes_in_buf == 0) return;
350*c2c26c8bSAndroid Build Coastguard Worker
351*c2c26c8bSAndroid Build Coastguard Worker if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1) {
352*c2c26c8bSAndroid Build Coastguard Worker if (bytes_in_buf != (size_t) rc) memmove(buf, buf + rc, bytes_in_buf - rc);
353*c2c26c8bSAndroid Build Coastguard Worker bytes_in_buf -= rc;
354*c2c26c8bSAndroid Build Coastguard Worker } else {
355*c2c26c8bSAndroid Build Coastguard Worker if (errno == EAGAIN || errno == EINTR) return;
356*c2c26c8bSAndroid Build Coastguard Worker bytes_in_buf = 0;
357*c2c26c8bSAndroid Build Coastguard Worker }
358*c2c26c8bSAndroid Build Coastguard Worker }
359*c2c26c8bSAndroid Build Coastguard Worker
360*c2c26c8bSAndroid Build Coastguard Worker #endif
361