add mc
[buildroot.git] / package / dhcp / dhcp_xecute.patch
blob0daff103faed99b78aeaa75369722d7f981fb526
1 diff -urN dhcp-3.0.2.orig/common/conflex.c dhcp-3.0.2/common/conflex.c
2 --- dhcp-3.0.2.orig/common/conflex.c 2004-11-24 10:39:15.000000000 -0700
3 +++ dhcp-3.0.2/common/conflex.c 2005-02-24 12:32:12.000000000 -0700
4 @@ -676,6 +676,8 @@
5 return EVAL;
6 if (!strcasecmp (atom + 1, "ncapsulate"))
7 return ENCAPSULATE;
8 + if (!strcasecmp (atom + 1, "xecute"))
9 + return EXECUTE;
10 break;
11 case 'f':
12 if (!strcasecmp (atom + 1, "atal"))
13 diff -urN dhcp-3.0.2.orig/common/dhcp-eval.5 dhcp-3.0.2/common/dhcp-eval.5
14 --- dhcp-3.0.2.orig/common/dhcp-eval.5 2005-01-19 13:00:52.000000000 -0700
15 +++ dhcp-3.0.2/common/dhcp-eval.5 2005-02-24 12:32:12.000000000 -0700
16 @@ -409,7 +409,32 @@
17 Rebind - DHCP client is in the REBINDING state - it has an IP address,
18 and is trying to contact any server to renew it. The next message to
19 be sent will be a DHCPREQUEST, which will be broadcast.
20 -.RE
21 +.PP
22 +.B execute (\fIcommand-path\fB, \fIdata-expr1\fB ... \fIdata-exprN\fB)\fR
23 +.PP
24 +External command execution is possibly through execute expressions. Execute
25 +takes a variable number of arguments, where the first is the command
26 +name (full path or only the name of the executable) and following zero
27 +or more are data-expressions which values will be passed as external
28 +arguments. It returns the return code of the external command.
29 +.PP
30 +Execute is synchronous, and the program will block until the external
31 +command being run has finished. Please note that lengthy program
32 +execution (for example, in an "on commit" in the dhcpd) may result in
33 +bad performance and timed out clients. Try keeping the execution times
34 +short.
35 +.PP
36 +Passing user-supplied data might be dangerous. Check input buffers
37 +and make sure the external command handles all kinds of "unusual"
38 +characters (shell special characters in sh-scripts etc) correctly.
39 +.PP
40 +It is possible to use the execute expression in any context, not only
41 +on events. If you put it in a regular scope in the configuration file
42 +you will execute that command every time a scope is evaluated.
43 +.PP
44 +The execute expression is only available if you have defined ENABLE_EXECUTE
45 +in site.h before compilation.
46 +RE
47 .SH REFERENCE: LOGGING
48 Logging statements may be used to send information to the standard logging
49 channels. A logging statement includes an optional priority (\fBfatal\fR,
50 diff -urN dhcp-3.0.2.orig/common/parse.c dhcp-3.0.2/common/parse.c
51 --- dhcp-3.0.2.orig/common/parse.c 2004-09-30 14:38:31.000000000 -0600
52 +++ dhcp-3.0.2/common/parse.c 2005-02-24 12:32:12.000000000 -0700
53 @@ -3639,7 +3639,56 @@
54 return 0;
56 break;
58 + #ifdef ENABLE_EXECUTE
59 + case EXECUTE:
60 + token = next_token (&val, (unsigned *)0, cfile);
62 + if (!expression_allocate (expr, MDL))
63 + log_fatal ("can't allocate expression.");
65 + token = next_token (&val, (unsigned *)0, cfile);
66 + if (token != LPAREN) {
67 + parse_warn (cfile, "left parenthesis expected.");
68 + skip_to_semi (cfile);
69 + *lose = 1;
70 + return 0;
71 + }
72 + token = next_token (&val, (unsigned *)0, cfile);
73 + (*expr) -> data.funcall.name =
74 + dmalloc (strlen (val) + 1, MDL);
75 + if (!(*expr)->data.funcall.name)
76 + log_fatal ("can't allocate command name");
77 + strcpy ((*expr) -> data.funcall.name, val);
78 + token = next_token (&val, (unsigned *)0, cfile);
79 + ep = &((*expr) -> data.funcall.arglist);
80 + while (token == COMMA) {
81 + if (!expression_allocate (ep, MDL))
82 + log_fatal ("can't allocate expression");
83 + if (!parse_data_expression (&(*ep) -> data.arg.val,
84 + cfile, lose)) {
85 + skip_to_semi (cfile);
86 + *lose = 1;
87 + return 0;
88 + }
89 + ep = &((*ep) -> data.arg.next);
90 + token = next_token (&val, (unsigned *)0, cfile);
91 + }
92 + (*expr) -> op = expr_execute;
93 + if (token != RPAREN) {
94 + parse_warn (cfile, "right parenthesis expected.");
95 + skip_to_semi (cfile);
96 + *lose = 1;
97 + return 0;
98 + }
99 + break;
100 + #else
101 + case EXECUTE:
102 + parse_warn (cfile, "define ENABLE_EXECUTE in site.h to enable execute expressions.");
103 + skip_to_semi (cfile);
104 + *lose = 1;
105 + return 0;
106 + break;
107 + #endif
108 case ENCODE_INT:
109 token = next_token (&val, (unsigned *)0, cfile);
110 token = next_token (&val, (unsigned *)0, cfile);
111 diff -urN dhcp-3.0.2.orig/common/print.c dhcp-3.0.2/common/print.c
112 --- dhcp-3.0.2.orig/common/print.c 2004-06-17 14:54:39.000000000 -0600
113 +++ dhcp-3.0.2/common/print.c 2005-02-24 12:32:12.000000000 -0700
114 @@ -459,6 +459,7 @@
116 unsigned rv, left;
117 const char *s;
118 + struct expression* next_arg;
120 switch (expr -> op) {
121 case expr_none:
122 @@ -483,7 +484,8 @@
123 return rv;
125 break;
129 case expr_equal:
130 if (len > 6) {
131 rv = 4;
132 @@ -1024,6 +1026,29 @@
133 buf [rv++] = 0;
134 return rv;
136 + #ifdef ENABLE_EXECUTE
137 + case expr_execute:
138 + rv = 11 + strlen (expr -> data.funcall.name);
139 + if (len > rv + 2) {
140 + sprintf (buf,
141 + "(execute \"%s\"",
142 + expr -> data.funcall.name);
143 + for(next_arg = expr -> data.funcall.arglist;
144 + next_arg;
145 + next_arg = next_arg -> data.arg.next) {
146 + if (len > rv + 3)
147 + buf [rv++] = ' ';
148 + rv += print_subexpression (next_arg ->
149 + data.arg.val,
150 + buf + rv,
151 + len - rv - 2);
153 + buf [rv++] = ')';
154 + buf [rv] = 0;
155 + return rv;
157 + break;
158 + #endif
160 return 0;
162 diff -urN dhcp-3.0.2.orig/common/tree.c dhcp-3.0.2/common/tree.c
163 --- dhcp-3.0.2.orig/common/tree.c 2004-11-24 10:39:16.000000000 -0700
164 +++ dhcp-3.0.2/common/tree.c 2005-02-24 12:32:12.000000000 -0700
165 @@ -50,6 +50,113 @@
166 int resolver_inited = 0;
167 #endif
169 +#ifdef ENABLE_EXECUTE
170 +static unsigned long execute (char** args)
172 +pid_t p = fork();
173 +if (p > 0) {
174 +int status;
175 +waitpid (p, &status, 0);
176 +return WEXITSTATUS(status);
178 +else if(p == 0) {
179 +execvp (args[0], args);
180 +log_error ("Unable to execute %s: %s", args[0],
181 +strerror(errno));
182 +_exit(127);
183 +} else {
184 +log_fatal ("unable to fork");
186 +return 1; /* never reached */
189 +#define CAPACITY_INCREMENT 8
190 +static void append_to_ary (char*** ary_ptr, int* ary_size, int* ary_capacity,
191 +char* new_element)
193 +(*ary_size)++;
194 +if (*ary_size > *ary_capacity) {
195 +char** new_ary;
196 +int new_ary_capacity = *ary_capacity + CAPACITY_INCREMENT;
197 +new_ary = dmalloc(new_ary_capacity*sizeof(char *), MDL);
198 +if (!new_ary)
199 +log_fatal ("no memory for array.");
200 +if (*ary_ptr != NULL) {
201 +memcpy (new_ary, *ary_ptr,
202 +(*ary_capacity)*sizeof(char *));
203 +dfree (*ary_ptr, MDL);
205 +*ary_ptr = new_ary;
206 +*ary_capacity = new_ary_capacity;
208 +(*ary_ptr)[*ary_size-1] = new_element;
211 +static char* data_string_to_char_string (struct data_string* d)
213 +char* str = dmalloc (d->len+1, MDL);
214 +if (!str)
215 +log_fatal ("no memory for string.");
216 +/* FIXME: should one use d -> buffer -> data or d -> data? are
217 +they equivalent? */
218 +strncpy (str, d -> data, d -> len);
219 +str[d->len] = '\0';
220 +return str;
223 +static int evaluate_execute (unsigned long* result, struct packet *packet,
224 +struct lease *lease,
225 +struct client_state *client_state,
226 +struct option_state *in_options,
227 +struct option_state *cfg_options,
228 +struct binding_scope **scope,
229 +struct expression* expr)
231 +int status;
232 +int cmd_status;
233 +int i;
234 +struct data_string ds;
235 +struct expression* next_arg;
236 +char** arg_ary = NULL;
237 +int arg_ary_size = 0;
238 +int arg_ary_capacity = 0;
239 +append_to_ary (&arg_ary, &arg_ary_size, &arg_ary_capacity,
240 + expr -> data.funcall.name);
241 +for(next_arg = expr -> data.funcall.arglist;
242 +next_arg;
243 +next_arg = next_arg -> data.arg.next) {
244 +memset (&ds, 0, sizeof ds);
245 +status = (evaluate_data_expression
246 +(&ds, packet,
247 +lease, client_state, in_options,
248 +cfg_options, scope,
249 +next_arg -> data.arg.val,
250 +MDL));
251 +if (!status) {
252 +if (arg_ary) {
253 +for (i=1; i<arg_ary_size; i++)
254 +dfree (arg_ary[i], MDL);
255 +dfree(arg_ary, MDL);
257 +return 0;
259 +append_to_ary (&arg_ary, &arg_ary_size, &arg_ary_capacity,
260 + data_string_to_char_string(&ds));
261 +data_string_forget (&ds, MDL);
263 +#if defined (DEBUG_EXPRESSIONS)
264 +log_debug ("exec: execute");
265 +#endif
266 +append_to_ary (&arg_ary, &arg_ary_size, &arg_ary_capacity, NULL);
267 +*result = execute (arg_ary);
268 +for (i=1; i<arg_ary_size-1; i++)
269 +dfree (arg_ary[i], MDL);
270 +dfree(arg_ary, MDL);
271 +return 1;
273 +#endif
276 pair cons (car, cdr)
277 caddr_t car;
278 pair cdr;
279 @@ -861,6 +968,9 @@
280 case expr_extract_int8:
281 case expr_extract_int16:
282 case expr_extract_int32:
283 + #ifdef ENABLE_EXECUTE
284 + case expr_execute:
285 + #endif
286 case expr_const_int:
287 case expr_lease_time:
288 case expr_dns_transaction:
289 @@ -1224,6 +1334,9 @@
290 case expr_extract_int8:
291 case expr_extract_int16:
292 case expr_extract_int32:
293 + #ifdef ENABLE_EXECUTE
294 + case expr_execute:
295 + #endif
296 case expr_const_int:
297 case expr_lease_time:
298 case expr_dns_transaction:
299 @@ -2087,6 +2200,9 @@
300 case expr_extract_int8:
301 case expr_extract_int16:
302 case expr_extract_int32:
303 + #ifdef ENABLE_EXECUTE
304 + case expr_execute:
305 + #endif
306 case expr_const_int:
307 case expr_lease_time:
308 case expr_dns_transaction:
309 @@ -2595,7 +2711,12 @@
310 #endif
311 return 0;
314 +#ifdef ENABLE_EXECUTE
315 + case expr_execute:
316 + return evaluate_execute (result, packet, lease,
317 + client_state, in_options,
318 + cfg_options, scope, expr);
319 +#endif
320 case expr_ns_add:
321 case expr_ns_delete:
322 case expr_ns_exists:
323 @@ -3008,6 +3129,9 @@
324 return (expr -> op == expr_extract_int8 ||
325 expr -> op == expr_extract_int16 ||
326 expr -> op == expr_extract_int32 ||
327 + #ifdef ENABLE_EXECUTE
328 + expr -> op == expr_execute ||
329 + #endif
330 expr -> op == expr_const_int ||
331 expr -> op == expr_lease_time ||
332 expr -> op == expr_dns_transaction ||
333 @@ -3043,6 +3167,9 @@
334 expr -> op == expr_extract_int8 ||
335 expr -> op == expr_extract_int16 ||
336 expr -> op == expr_extract_int32 ||
337 + #ifdef ENABLE_EXECUTE
338 + expr -> op == expr_execute ||
339 + #endif
340 expr -> op == expr_dns_transaction);
343 @@ -3069,6 +3196,9 @@
344 case expr_extract_int8:
345 case expr_extract_int16:
346 case expr_extract_int32:
347 + #ifdef ENABLE_EXECUTE
348 + case expr_execute:
349 + #endif
350 case expr_encode_int8:
351 case expr_encode_int16:
352 case expr_encode_int32:
353 @@ -3165,6 +3295,9 @@
354 case expr_extract_int8:
355 case expr_extract_int16:
356 case expr_extract_int32:
357 + #ifdef ENABLE_EXECUTE
358 + case expr_execute:
359 + #endif
360 case expr_encode_int8:
361 case expr_encode_int16:
362 case expr_encode_int32:
363 @@ -3225,6 +3358,8 @@
364 int firstp;
366 struct expression *e;
367 + struct expression* next_arg;
369 const char *s;
370 char obuf [65];
371 int scol;
372 @@ -3696,7 +3831,27 @@
373 expr -> data.variable);
374 col = token_print_indent (file, col, indent, "", "", ")");
375 break;
377 + #ifdef ENABLE_EXECUTE
378 + case expr_execute:
379 + col = token_print_indent (file, col, indent, "", "","execute");
380 + col = token_print_indent (file, col, indent, " ", "","(");
381 + scol = col;
382 + /* FIXME: use token_print_indent_concat() here? */
383 + col = token_print_indent (file, col, scol, "", "","\"");
384 + col = token_print_indent (file, col, scol, "", "",expr -> data.funcall.name);
385 + col = token_print_indent (file, col, scol, "", "","\"");
386 + for(next_arg = expr -> data.funcall.arglist;
387 + next_arg;
388 + next_arg = next_arg -> data.arg.next) {
389 + col = token_print_indent (file, col, scol, "", " ",",");
390 + col = write_expression (file,
391 + next_arg -> data.arg.val,
392 + col, scol, 0);
394 + col = token_print_indent (file, col, indent, "", "",")");
396 + break;
397 +#endif
398 default:
399 log_fatal ("invalid expression type in print_expression: %d",
400 expr -> op);
401 @@ -3915,6 +4070,9 @@
402 case expr_extract_int8:
403 case expr_extract_int16:
404 case expr_extract_int32:
405 + #ifdef ENABLE_EXECUTE
406 + case expr_execute:
407 + #endif
408 case expr_encode_int8:
409 case expr_encode_int16:
410 case expr_encode_int32:
411 diff -urN dhcp-3.0.2.orig/includes/dhctoken.h dhcp-3.0.2/includes/dhctoken.h
412 --- dhcp-3.0.2.orig/includes/dhctoken.h 2004-09-21 13:25:38.000000000 -0600
413 +++ dhcp-3.0.2/includes/dhctoken.h 2005-02-24 12:33:21.000000000 -0700
414 @@ -308,7 +308,8 @@
415 DOMAIN_NAME = 613,
416 DO_FORWARD_UPDATE = 614,
417 KNOWN_CLIENTS = 615,
418 - ATSFP = 616
419 + ATSFP = 616,
420 + EXECUTE = 616
423 #define is_identifier(x) ((x) >= FIRST_TOKEN && \
424 diff -urN dhcp-3.0.2.orig/includes/site.h dhcp-3.0.2/includes/site.h
425 --- dhcp-3.0.2.orig/includes/site.h 2002-03-12 11:33:39.000000000 -0700
426 +++ dhcp-3.0.2/includes/site.h 2005-02-24 12:32:12.000000000 -0700
427 @@ -167,6 +167,12 @@
429 /* #define DHCPD_LOG_FACILITY LOG_DAEMON */
431 +/* Define this if you want to be able to execute external commands
432 + during conditional evaluation. */
434 +/* #define ENABLE_EXECUTE */
437 /* Define this if you aren't debugging and you want to save memory
438 (potentially a _lot_ of memory) by allocating leases in chunks rather
439 than one at a time. */
440 diff -urN dhcp-3.0.2.orig/includes/tree.h dhcp-3.0.2/includes/tree.h
441 --- dhcp-3.0.2.orig/includes/tree.h 2004-06-10 11:59:31.000000000 -0600
442 +++ dhcp-3.0.2/includes/tree.h 2005-02-24 12:32:12.000000000 -0700
443 @@ -150,6 +150,9 @@
444 expr_hardware,
445 expr_packet,
446 expr_const_data,
447 + #ifdef ENABLE_EXECUTE
448 + expr_execute,
449 + #endif
450 expr_extract_int8,
451 expr_extract_int16,
452 expr_extract_int32,