xref: /aosp_15_r20/external/dnsmasq/src/helper.c (revision c2c26c8b25cb2c9c4fe49a734c2305a522f5635e)
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