minidlna support now Samsung TV C550/C650 (thx amir909)
[tomato.git] / release / src / router / dhcpv6 / dhcp6c_script.c
blob05ccf8c1431d21381fffa3ba13b78e7deb541fb1
1 /* $KAME: dhcp6c_script.c,v 1.11 2004/11/28 10:48:38 jinmei Exp $ */
3 /*
4 * Copyright (C) 2003 WIDE Project.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/queue.h>
35 #include <sys/wait.h>
36 #include <sys/stat.h>
38 #if TIME_WITH_SYS_TIME
39 # include <sys/time.h>
40 # include <time.h>
41 #else
42 # if HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 # else
45 # include <time.h>
46 # endif
47 #endif
49 #include <netinet/in.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <syslog.h>
57 #include <errno.h>
59 #include "dhcp6.h"
60 #include "config.h"
61 #include "common.h"
63 static char sipserver_str[] = "new_sip_servers";
64 static char sipname_str[] = "new_sip_name";
65 static char dnsserver_str[] = "new_domain_name_servers";
66 static char dnsname_str[] = "new_domain_name";
67 static char ntpserver_str[] = "new_ntp_servers";
68 static char nisserver_str[] = "new_nis_servers";
69 static char nisname_str[] = "new_nis_name";
70 static char nispserver_str[] = "new_nisp_servers";
71 static char nispname_str[] = "new_nisp_name";
72 static char bcmcsserver_str[] = "new_bcmcs_servers";
73 static char bcmcsname_str[] = "new_bcmcs_name";
75 int
76 client6_script(scriptpath, state, optinfo)
77 char *scriptpath;
78 int state;
79 struct dhcp6_optinfo *optinfo;
81 int i, dnsservers, ntpservers, dnsnamelen, envc, elen, ret = 0;
82 int sipservers, sipnamelen;
83 int nisservers, nisnamelen;
84 int nispservers, nispnamelen;
85 int bcmcsservers, bcmcsnamelen;
86 char **envp, *s;
87 char reason[] = "REASON=NBI";
88 struct dhcp6_listval *v;
89 pid_t pid, wpid;
91 /* if a script is not specified, do nothing */
92 if (scriptpath == NULL || strlen(scriptpath) == 0)
93 return -1;
95 /* initialize counters */
96 dnsservers = 0;
97 ntpservers = 0;
98 dnsnamelen = 0;
99 sipservers = 0;
100 sipnamelen = 0;
101 nisservers = 0;
102 nisnamelen = 0;
103 nispservers = 0;
104 nispnamelen = 0;
105 bcmcsservers = 0;
106 bcmcsnamelen = 0;
107 envc = 2; /* we at least include the reason and the terminator */
109 /* count the number of variables */
110 for (v = TAILQ_FIRST(&optinfo->dns_list); v; v = TAILQ_NEXT(v, link))
111 dnsservers++;
112 envc += dnsservers ? 1 : 0;
113 for (v = TAILQ_FIRST(&optinfo->dnsname_list); v;
114 v = TAILQ_NEXT(v, link)) {
115 dnsnamelen += v->val_vbuf.dv_len;
117 envc += dnsnamelen ? 1 : 0;
118 for (v = TAILQ_FIRST(&optinfo->ntp_list); v; v = TAILQ_NEXT(v, link))
119 ntpservers++;
120 envc += ntpservers ? 1 : 0;
121 for (v = TAILQ_FIRST(&optinfo->sip_list); v; v = TAILQ_NEXT(v, link))
122 sipservers++;
123 envc += sipservers ? 1 : 0;
124 for (v = TAILQ_FIRST(&optinfo->sipname_list); v;
125 v = TAILQ_NEXT(v, link)) {
126 sipnamelen += v->val_vbuf.dv_len;
128 envc += sipnamelen ? 1 : 0;
130 for (v = TAILQ_FIRST(&optinfo->nis_list); v; v = TAILQ_NEXT(v, link))
131 nisservers++;
132 envc += nisservers ? 1 : 0;
133 for (v = TAILQ_FIRST(&optinfo->nisname_list); v;
134 v = TAILQ_NEXT(v, link)) {
135 nisnamelen += v->val_vbuf.dv_len;
137 envc += nisnamelen ? 1 : 0;
139 for (v = TAILQ_FIRST(&optinfo->nisp_list); v; v = TAILQ_NEXT(v, link))
140 nispservers++;
141 envc += nispservers ? 1 : 0;
142 for (v = TAILQ_FIRST(&optinfo->nispname_list); v;
143 v = TAILQ_NEXT(v, link)) {
144 nispnamelen += v->val_vbuf.dv_len;
146 envc += nispnamelen ? 1 : 0;
148 for (v = TAILQ_FIRST(&optinfo->bcmcs_list); v; v = TAILQ_NEXT(v, link))
149 bcmcsservers++;
150 envc += bcmcsservers ? 1 : 0;
151 for (v = TAILQ_FIRST(&optinfo->bcmcsname_list); v;
152 v = TAILQ_NEXT(v, link)) {
153 bcmcsnamelen += v->val_vbuf.dv_len;
155 envc += bcmcsnamelen ? 1 : 0;
157 /* allocate an environments array */
158 if ((envp = malloc(sizeof (char *) * envc)) == NULL) {
159 dprintf(LOG_NOTICE, FNAME,
160 "failed to allocate environment buffer");
161 return -1;
163 memset(envp, 0, sizeof (char *) * envc);
166 * Copy the parameters as environment variables
168 i = 0;
169 /* reason */
170 if ((envp[i++] = strdup(reason)) == NULL) {
171 dprintf(LOG_NOTICE, FNAME,
172 "failed to allocate reason strings");
173 ret = -1;
174 goto clean;
176 /* "var=addr1 addr2 ... addrN" + null char for termination */
177 if (dnsservers) {
178 elen = sizeof (dnsserver_str) +
179 (INET6_ADDRSTRLEN + 1) * dnsservers + 1;
180 if ((s = envp[i++] = malloc(elen)) == NULL) {
181 dprintf(LOG_NOTICE, FNAME,
182 "failed to allocate strings for DNS servers");
183 ret = -1;
184 goto clean;
186 memset(s, 0, elen);
187 snprintf(s, elen, "%s=", dnsserver_str);
188 for (v = TAILQ_FIRST(&optinfo->dns_list); v;
189 v = TAILQ_NEXT(v, link)) {
190 char *addr;
192 addr = in6addr2str(&v->val_addr6, 0);
193 strlcat(s, addr, elen);
194 strlcat(s, " ", elen);
197 if (ntpservers) {
198 elen = sizeof (ntpserver_str) +
199 (INET6_ADDRSTRLEN + 1) * ntpservers + 1;
200 if ((s = envp[i++] = malloc(elen)) == NULL) {
201 dprintf(LOG_NOTICE, FNAME,
202 "failed to allocate strings for NTP servers");
203 ret = -1;
204 goto clean;
206 memset(s, 0, elen);
207 snprintf(s, elen, "%s=", ntpserver_str);
208 for (v = TAILQ_FIRST(&optinfo->ntp_list); v;
209 v = TAILQ_NEXT(v, link)) {
210 char *addr;
212 addr = in6addr2str(&v->val_addr6, 0);
213 strlcat(s, addr, elen);
214 strlcat(s, " ", elen);
218 if (dnsnamelen) {
219 elen = sizeof (dnsname_str) + dnsnamelen + 1;
220 if ((s = envp[i++] = malloc(elen)) == NULL) {
221 dprintf(LOG_NOTICE, FNAME,
222 "failed to allocate strings for DNS name");
223 ret = -1;
224 goto clean;
226 memset(s, 0, elen);
227 snprintf(s, elen, "%s=", dnsname_str);
228 for (v = TAILQ_FIRST(&optinfo->dnsname_list); v;
229 v = TAILQ_NEXT(v, link)) {
230 strlcat(s, v->val_vbuf.dv_buf, elen);
231 strlcat(s, " ", elen);
235 if (sipservers) {
236 elen = sizeof (sipserver_str) +
237 (INET6_ADDRSTRLEN + 1) * sipservers + 1;
238 if ((s = envp[i++] = malloc(elen)) == NULL) {
239 dprintf(LOG_NOTICE, FNAME,
240 "failed to allocate strings for SIP servers");
241 ret = -1;
242 goto clean;
244 memset(s, 0, elen);
245 snprintf(s, elen, "%s=", sipserver_str);
246 for (v = TAILQ_FIRST(&optinfo->sip_list); v;
247 v = TAILQ_NEXT(v, link)) {
248 char *addr;
250 addr = in6addr2str(&v->val_addr6, 0);
251 strlcat(s, addr, elen);
252 strlcat(s, " ", elen);
255 if (sipnamelen) {
256 elen = sizeof (sipname_str) + sipnamelen + 1;
257 if ((s = envp[i++] = malloc(elen)) == NULL) {
258 dprintf(LOG_NOTICE, FNAME,
259 "failed to allocate strings for SIP domain name");
260 ret = -1;
261 goto clean;
263 memset(s, 0, elen);
264 snprintf(s, elen, "%s=", sipname_str);
265 for (v = TAILQ_FIRST(&optinfo->sipname_list); v;
266 v = TAILQ_NEXT(v, link)) {
267 strlcat(s, v->val_vbuf.dv_buf, elen);
268 strlcat(s, " ", elen);
272 if (nisservers) {
273 elen = sizeof (nisserver_str) +
274 (INET6_ADDRSTRLEN + 1) * nisservers + 1;
275 if ((s = envp[i++] = malloc(elen)) == NULL) {
276 dprintf(LOG_NOTICE, FNAME,
277 "failed to allocate strings for NIS servers");
278 ret = -1;
279 goto clean;
281 memset(s, 0, elen);
282 snprintf(s, elen, "%s=", nisserver_str);
283 for (v = TAILQ_FIRST(&optinfo->nis_list); v;
284 v = TAILQ_NEXT(v, link)) {
285 char *addr;
287 addr = in6addr2str(&v->val_addr6, 0);
288 strlcat(s, addr, elen);
289 strlcat(s, " ", elen);
292 if (nisnamelen) {
293 elen = sizeof (nisname_str) + nisnamelen + 1;
294 if ((s = envp[i++] = malloc(elen)) == NULL) {
295 dprintf(LOG_NOTICE, FNAME,
296 "failed to allocate strings for NIS domain name");
297 ret = -1;
298 goto clean;
300 memset(s, 0, elen);
301 snprintf(s, elen, "%s=", nisname_str);
302 for (v = TAILQ_FIRST(&optinfo->nisname_list); v;
303 v = TAILQ_NEXT(v, link)) {
304 strlcat(s, v->val_vbuf.dv_buf, elen);
305 strlcat(s, " ", elen);
309 if (nispservers) {
310 elen = sizeof (nispserver_str) +
311 (INET6_ADDRSTRLEN + 1) * nispservers + 1;
312 if ((s = envp[i++] = malloc(elen)) == NULL) {
313 dprintf(LOG_NOTICE, FNAME,
314 "failed to allocate strings for NIS+ servers");
315 ret = -1;
316 goto clean;
318 memset(s, 0, elen);
319 snprintf(s, elen, "%s=", nispserver_str);
320 for (v = TAILQ_FIRST(&optinfo->nisp_list); v;
321 v = TAILQ_NEXT(v, link)) {
322 char *addr;
324 addr = in6addr2str(&v->val_addr6, 0);
325 strlcat(s, addr, elen);
326 strlcat(s, " ", elen);
329 if (nispnamelen) {
330 elen = sizeof (nispname_str) + nispnamelen + 1;
331 if ((s = envp[i++] = malloc(elen)) == NULL) {
332 dprintf(LOG_NOTICE, FNAME,
333 "failed to allocate strings for NIS+ domain name");
334 ret = -1;
335 goto clean;
337 memset(s, 0, elen);
338 snprintf(s, elen, "%s=", nispname_str);
339 for (v = TAILQ_FIRST(&optinfo->nispname_list); v;
340 v = TAILQ_NEXT(v, link)) {
341 strlcat(s, v->val_vbuf.dv_buf, elen);
342 strlcat(s, " ", elen);
346 if (bcmcsservers) {
347 elen = sizeof (bcmcsserver_str) +
348 (INET6_ADDRSTRLEN + 1) * bcmcsservers + 1;
349 if ((s = envp[i++] = malloc(elen)) == NULL) {
350 dprintf(LOG_NOTICE, FNAME,
351 "failed to allocate strings for BCMC servers");
352 ret = -1;
353 goto clean;
355 memset(s, 0, elen);
356 snprintf(s, elen, "%s=", bcmcsserver_str);
357 for (v = TAILQ_FIRST(&optinfo->bcmcs_list); v;
358 v = TAILQ_NEXT(v, link)) {
359 char *addr;
361 addr = in6addr2str(&v->val_addr6, 0);
362 strlcat(s, addr, elen);
363 strlcat(s, " ", elen);
366 if (bcmcsnamelen) {
367 elen = sizeof (bcmcsname_str) + bcmcsnamelen + 1;
368 if ((s = envp[i++] = malloc(elen)) == NULL) {
369 dprintf(LOG_NOTICE, FNAME,
370 "failed to allocate strings for BCMC domain name");
371 ret = -1;
372 goto clean;
374 memset(s, 0, elen);
375 snprintf(s, elen, "%s=", bcmcsname_str);
376 for (v = TAILQ_FIRST(&optinfo->bcmcsname_list); v;
377 v = TAILQ_NEXT(v, link)) {
378 strlcat(s, v->val_vbuf.dv_buf, elen);
379 strlcat(s, " ", elen);
383 /* launch the script */
384 pid = fork();
385 if (pid < 0) {
386 dprintf(LOG_ERR, FNAME, "failed to fork: %s", strerror(errno));
387 ret = -1;
388 goto clean;
389 } else if (pid) {
390 int wstatus;
392 do {
393 wpid = wait(&wstatus);
394 } while (wpid != pid && wpid > 0);
396 if (wpid < 0)
397 dprintf(LOG_ERR, FNAME, "wait: %s", strerror(errno));
398 else {
399 dprintf(LOG_DEBUG, FNAME,
400 "script \"%s\" terminated", scriptpath);
402 } else {
403 char *argv[2];
404 int fd;
406 argv[0] = scriptpath;
407 argv[1] = NULL;
409 if (safefile(scriptpath)) {
410 dprintf(LOG_ERR, FNAME,
411 "script \"%s\" cannot be executed safely",
412 scriptpath);
413 exit(1);
416 if (foreground == 0 && (fd = open("/dev/null", O_RDWR)) != -1) {
417 dup2(fd, STDIN_FILENO);
418 dup2(fd, STDOUT_FILENO);
419 dup2(fd, STDERR_FILENO);
420 if (fd > STDERR_FILENO)
421 close(fd);
424 execve(scriptpath, argv, envp);
426 dprintf(LOG_ERR, FNAME, "child: exec failed: %s",
427 strerror(errno));
428 exit(0);
431 clean:
432 for (i = 0; i < envc; i++)
433 free(envp[i]);
434 free(envp);
436 return ret;