diff options
Diffstat (limited to 'networking/udhcp/script.c')
-rw-r--r-- | networking/udhcp/script.c | 283 |
1 files changed, 0 insertions, 283 deletions
diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c deleted file mode 100644 index 400fd2b9b..000000000 --- a/networking/udhcp/script.c +++ /dev/null | |||
@@ -1,283 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* script.c | ||
3 | * | ||
4 | * Functions to call the DHCP client notification scripts | ||
5 | * | ||
6 | * Russ Dill <Russ.Dill@asu.edu> July 2001 | ||
7 | * | ||
8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
9 | */ | ||
10 | |||
11 | #include "common.h" | ||
12 | #include "dhcpc.h" | ||
13 | #include "options.h" | ||
14 | |||
15 | |||
16 | /* get a rough idea of how long an option will be (rounding up...) */ | ||
17 | static const uint8_t len_of_option_as_string[] = { | ||
18 | [OPTION_IP] = sizeof("255.255.255.255 "), | ||
19 | [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, | ||
20 | [OPTION_STATIC_ROUTES]= sizeof("255.255.255.255/32 255.255.255.255 "), | ||
21 | [OPTION_STRING] = 1, | ||
22 | #if ENABLE_FEATURE_UDHCP_RFC3397 | ||
23 | [OPTION_STR1035] = 1, | ||
24 | #endif | ||
25 | [OPTION_BOOLEAN] = sizeof("yes "), | ||
26 | [OPTION_U8] = sizeof("255 "), | ||
27 | [OPTION_U16] = sizeof("65535 "), | ||
28 | [OPTION_S16] = sizeof("-32768 "), | ||
29 | [OPTION_U32] = sizeof("4294967295 "), | ||
30 | [OPTION_S32] = sizeof("-2147483684 "), | ||
31 | }; | ||
32 | |||
33 | |||
34 | /* note: ip is a pointer to an IP in network order, possibly misaliged */ | ||
35 | static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) | ||
36 | { | ||
37 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); | ||
38 | } | ||
39 | |||
40 | |||
41 | /* really simple implementation, just count the bits */ | ||
42 | static int mton(uint32_t mask) | ||
43 | { | ||
44 | int i = 0; | ||
45 | mask = ntohl(mask); /* 111110000-like bit pattern */ | ||
46 | while (mask) { | ||
47 | i++; | ||
48 | mask <<= 1; | ||
49 | } | ||
50 | return i; | ||
51 | } | ||
52 | |||
53 | |||
54 | /* Create "opt_name=opt_value" string */ | ||
55 | static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name) | ||
56 | { | ||
57 | unsigned upper_length; | ||
58 | int len, type, optlen; | ||
59 | uint16_t val_u16; | ||
60 | int16_t val_s16; | ||
61 | uint32_t val_u32; | ||
62 | int32_t val_s32; | ||
63 | char *dest, *ret; | ||
64 | |||
65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ | ||
66 | len = option[OPT_LEN - OPT_DATA]; | ||
67 | type = type_p->flags & OPTION_TYPE_MASK; | ||
68 | optlen = dhcp_option_lengths[type]; | ||
69 | upper_length = len_of_option_as_string[type] * (len / optlen); | ||
70 | |||
71 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); | ||
72 | dest += sprintf(ret, "%s=", opt_name); | ||
73 | |||
74 | while (len >= optlen) { | ||
75 | switch (type) { | ||
76 | case OPTION_IP_PAIR: | ||
77 | dest += sprint_nip(dest, "", option); | ||
78 | *dest++ = '/'; | ||
79 | option += 4; | ||
80 | optlen = 4; | ||
81 | case OPTION_IP: | ||
82 | dest += sprint_nip(dest, "", option); | ||
83 | // TODO: it can be a list only if (type_p->flags & OPTION_LIST). | ||
84 | // Should we bail out/warn if we see multi-ip option which is | ||
85 | // not allowed to be such? For example, DHCP_BROADCAST... | ||
86 | break; | ||
87 | case OPTION_BOOLEAN: | ||
88 | dest += sprintf(dest, *option ? "yes" : "no"); | ||
89 | break; | ||
90 | case OPTION_U8: | ||
91 | dest += sprintf(dest, "%u", *option); | ||
92 | break; | ||
93 | case OPTION_U16: | ||
94 | move_from_unaligned16(val_u16, option); | ||
95 | dest += sprintf(dest, "%u", ntohs(val_u16)); | ||
96 | break; | ||
97 | case OPTION_S16: | ||
98 | move_from_unaligned16(val_s16, option); | ||
99 | dest += sprintf(dest, "%d", ntohs(val_s16)); | ||
100 | break; | ||
101 | case OPTION_U32: | ||
102 | move_from_unaligned32(val_u32, option); | ||
103 | dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32)); | ||
104 | break; | ||
105 | case OPTION_S32: | ||
106 | move_from_unaligned32(val_s32, option); | ||
107 | dest += sprintf(dest, "%ld", (long) ntohl(val_s32)); | ||
108 | break; | ||
109 | case OPTION_STRING: | ||
110 | memcpy(dest, option, len); | ||
111 | dest[len] = '\0'; | ||
112 | return ret; /* Short circuit this case */ | ||
113 | case OPTION_STATIC_ROUTES: { | ||
114 | /* Option binary format: | ||
115 | * mask [one byte, 0..32] | ||
116 | * ip [big endian, 0..4 bytes depending on mask] | ||
117 | * router [big endian, 4 bytes] | ||
118 | * may be repeated | ||
119 | * | ||
120 | * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2" | ||
121 | */ | ||
122 | const char *pfx = ""; | ||
123 | |||
124 | while (len >= 1 + 4) { /* mask + 0-byte ip + router */ | ||
125 | uint32_t nip; | ||
126 | uint8_t *p; | ||
127 | unsigned mask; | ||
128 | int bytes; | ||
129 | |||
130 | mask = *option++; | ||
131 | if (mask > 32) | ||
132 | break; | ||
133 | len--; | ||
134 | |||
135 | nip = 0; | ||
136 | p = (void*) &nip; | ||
137 | bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */ | ||
138 | while (--bytes >= 0) { | ||
139 | *p++ = *option++; | ||
140 | len--; | ||
141 | } | ||
142 | if (len < 4) | ||
143 | break; | ||
144 | |||
145 | /* print ip/mask */ | ||
146 | dest += sprint_nip(dest, pfx, (void*) &nip); | ||
147 | pfx = " "; | ||
148 | dest += sprintf(dest, "/%u ", mask); | ||
149 | /* print router */ | ||
150 | dest += sprint_nip(dest, "", option); | ||
151 | option += 4; | ||
152 | len -= 4; | ||
153 | } | ||
154 | |||
155 | return ret; | ||
156 | } | ||
157 | #if ENABLE_FEATURE_UDHCP_RFC3397 | ||
158 | case OPTION_STR1035: | ||
159 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ | ||
160 | dest = dname_dec(option, len, ret); | ||
161 | if (dest) { | ||
162 | free(ret); | ||
163 | return dest; | ||
164 | } | ||
165 | /* error. return "optname=" string */ | ||
166 | return ret; | ||
167 | #endif | ||
168 | } | ||
169 | option += optlen; | ||
170 | len -= optlen; | ||
171 | if (len <= 0) | ||
172 | break; | ||
173 | *dest++ = ' '; | ||
174 | *dest = '\0'; | ||
175 | } | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | |||
180 | /* put all the parameters into the environment */ | ||
181 | static char **fill_envp(struct dhcp_packet *packet) | ||
182 | { | ||
183 | int num_options = 0; | ||
184 | int i; | ||
185 | char **envp, **curr; | ||
186 | const char *opt_name; | ||
187 | uint8_t *temp; | ||
188 | uint8_t over = 0; | ||
189 | |||
190 | if (packet) { | ||
191 | for (i = 0; dhcp_options[i].code; i++) { | ||
192 | if (get_option(packet, dhcp_options[i].code)) { | ||
193 | num_options++; | ||
194 | if (dhcp_options[i].code == DHCP_SUBNET) | ||
195 | num_options++; /* for mton */ | ||
196 | } | ||
197 | } | ||
198 | if (packet->siaddr_nip) | ||
199 | num_options++; | ||
200 | temp = get_option(packet, DHCP_OPTION_OVERLOAD); | ||
201 | if (temp) | ||
202 | over = *temp; | ||
203 | if (!(over & FILE_FIELD) && packet->file[0]) | ||
204 | num_options++; | ||
205 | if (!(over & SNAME_FIELD) && packet->sname[0]) | ||
206 | num_options++; | ||
207 | } | ||
208 | |||
209 | curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); | ||
210 | *curr = xasprintf("interface=%s", client_config.interface); | ||
211 | putenv(*curr++); | ||
212 | |||
213 | if (packet == NULL) | ||
214 | return envp; | ||
215 | |||
216 | *curr = xmalloc(sizeof("ip=255.255.255.255")); | ||
217 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); | ||
218 | putenv(*curr++); | ||
219 | |||
220 | opt_name = dhcp_option_strings; | ||
221 | i = 0; | ||
222 | while (*opt_name) { | ||
223 | temp = get_option(packet, dhcp_options[i].code); | ||
224 | if (!temp) | ||
225 | goto next; | ||
226 | *curr = xmalloc_optname_optval(temp, &dhcp_options[i], opt_name); | ||
227 | putenv(*curr++); | ||
228 | |||
229 | /* Fill in a subnet bits option for things like /24 */ | ||
230 | if (dhcp_options[i].code == DHCP_SUBNET) { | ||
231 | uint32_t subnet; | ||
232 | move_from_unaligned32(subnet, temp); | ||
233 | *curr = xasprintf("mask=%d", mton(subnet)); | ||
234 | putenv(*curr++); | ||
235 | } | ||
236 | next: | ||
237 | opt_name += strlen(opt_name) + 1; | ||
238 | i++; | ||
239 | } | ||
240 | if (packet->siaddr_nip) { | ||
241 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); | ||
242 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | ||
243 | putenv(*curr++); | ||
244 | } | ||
245 | if (!(over & FILE_FIELD) && packet->file[0]) { | ||
246 | /* watch out for invalid packets */ | ||
247 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | ||
248 | putenv(*curr++); | ||
249 | } | ||
250 | if (!(over & SNAME_FIELD) && packet->sname[0]) { | ||
251 | /* watch out for invalid packets */ | ||
252 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | ||
253 | putenv(*curr++); | ||
254 | } | ||
255 | return envp; | ||
256 | } | ||
257 | |||
258 | |||
259 | /* Call a script with a par file and env vars */ | ||
260 | void FAST_FUNC udhcp_run_script(struct dhcp_packet *packet, const char *name) | ||
261 | { | ||
262 | char **envp, **curr; | ||
263 | char *argv[3]; | ||
264 | |||
265 | if (client_config.script == NULL) | ||
266 | return; | ||
267 | |||
268 | envp = fill_envp(packet); | ||
269 | |||
270 | /* call script */ | ||
271 | log1("Executing %s %s", client_config.script, name); | ||
272 | argv[0] = (char*) client_config.script; | ||
273 | argv[1] = (char*) name; | ||
274 | argv[2] = NULL; | ||
275 | spawn_and_wait(argv); | ||
276 | |||
277 | for (curr = envp; *curr; curr++) { | ||
278 | log2(" %s", *curr); | ||
279 | bb_unsetenv(*curr); | ||
280 | free(*curr); | ||
281 | } | ||
282 | free(envp); | ||
283 | } | ||