]> git.ipfire.org Git - thirdparty/dhcp.git/blob - dhcpctl/omshell.c
- Silence benign static analysis warnings.
[thirdparty/dhcp.git] / dhcpctl / omshell.c
1 /* omshell.c
2
3 Examine and modify omapi objects. */
4
5 /*
6 * Copyright (c) 2009-2011,2013 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2001-2003 by Internet Software Consortium
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
28 * This software has been written for Internet Systems Consortium
29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
34 */
35
36 #include "config.h"
37
38 #include <time.h>
39 #include <sys/time.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <string.h>
44 //#include "result.h"
45 #include <syslog.h>
46 #include "dhcpctl.h"
47 #include "dhcpd.h"
48
49 /* Fixups */
50 isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
51 {
52 return 0;
53 }
54 int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
55 {
56 return 0;
57 }
58 void dhcp (struct packet *packet) { }
59 void bootp (struct packet *packet) { }
60
61 #ifdef DHCPv6
62 /* XXX: should we warn or something here? */
63 void dhcpv6(struct packet *packet) { }
64 #endif /* DHCPv6 */
65
66 int check_collection (struct packet *p, struct lease *l, struct collection *c)
67 {
68 return 0;
69 }
70 void classify (struct packet *packet, struct class *class) { }
71
72 static void usage (char *s) {
73 fprintf (stderr, "Usage: %s\n", s);
74 exit (1);
75 }
76
77 static void check (isc_result_t status, const char *func) {
78 if (status != ISC_R_SUCCESS) {
79 fprintf (stderr, "%s: %s\n", func, isc_result_totext (status));
80 exit (1);
81 }
82 }
83
84 int
85 main(int argc, char **argv) {
86 isc_result_t status, waitstatus;
87 dhcpctl_handle connection;
88 dhcpctl_handle authenticator;
89 dhcpctl_handle oh;
90 struct data_string secret;
91 const char *name = 0, *algorithm = "hmac-md5";
92 int i;
93 int port = 7911;
94 const char *server = "127.0.0.1";
95 struct parse *cfile;
96 enum dhcp_token token;
97 const char *val;
98 char *s;
99 char buf[1024];
100 char s1[1024];
101 int connected = 0;
102 char hex_buf[1025];
103
104 for (i = 1; i < argc; i++) {
105 usage(argv[0]);
106 }
107
108 /* Initially, log errors to stderr as well as to syslogd. */
109 openlog ("omshell", LOG_NDELAY, DHCPD_LOG_FACILITY);
110 status = dhcpctl_initialize ();
111 if (status != ISC_R_SUCCESS) {
112 fprintf (stderr, "dhcpctl_initialize: %s\n",
113 isc_result_totext (status));
114 exit (1);
115 }
116
117 memset (&oh, 0, sizeof oh);
118
119 do {
120 if (!connected) {
121 } else if (oh == NULL) {
122 printf ("obj: <null>\n");
123 } else {
124 dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)oh;
125 omapi_generic_object_t *g =
126 (omapi_generic_object_t *)(r -> inner);
127
128 printf ("obj: ");
129
130 if (r -> rtype -> type != omapi_datatype_string) {
131 printf ("?\n");
132 } else {
133 printf ("%.*s\n",
134 (int)(r -> rtype -> u . buffer . len),
135 r -> rtype -> u . buffer . value);
136 }
137
138 for (i = 0; i < g -> nvalues; i++) {
139 omapi_value_t *v = g -> values [i];
140
141 if (!g -> values [i])
142 continue;
143
144 printf ("%.*s = ", (int)v -> name -> len,
145 v -> name -> value);
146
147 if (!v -> value) {
148 printf ("<null>\n");
149 continue;
150 }
151 switch (v -> value -> type) {
152 case omapi_datatype_int:
153 printf ("%d\n",
154 v -> value -> u . integer);
155 break;
156
157 case omapi_datatype_string:
158 printf ("\"%.*s\"\n",
159 (int) v -> value -> u.buffer.len,
160 v -> value -> u.buffer.value);
161 break;
162
163 case omapi_datatype_data:
164 print_hex_or_string(v->value->u.buffer.len,
165 v->value->u.buffer.value,
166 sizeof(hex_buf), hex_buf);
167 printf("%s\n", hex_buf);
168 break;
169
170 case omapi_datatype_object:
171 printf ("<obj>\n");
172 break;
173 }
174 }
175 }
176
177 fputs ("> ", stdout);
178 fflush (stdout);
179 if (fgets (buf, sizeof(buf), stdin) == NULL)
180 break;
181
182 status = new_parse (&cfile, -1, buf, strlen(buf), "<STDIN>", 1);
183 check(status, "new_parse()");
184
185 token = next_token (&val, (unsigned *)0, cfile);
186 switch (token) {
187 default:
188 parse_warn (cfile, "unknown token: %s", val);
189 skip_to_semi (cfile);
190 break;
191
192 case END_OF_FILE:
193 case ENDOFLINE: /* EOL: */
194 break;
195
196 case TOKEN_HELP:
197 case QUESTIONMARK: /* '?': */
198 printf ("Commands:\n");
199 printf (" port <server omapi port>\n");
200 printf (" server <server address>\n");
201 printf (" key <key name> <key value>\n");
202 printf (" connect\n");
203 printf (" new <object-type>\n");
204 printf (" set <name> = <value>\n");
205 printf (" create\n");
206 printf (" open\n");
207 printf (" update\n");
208 printf (" unset <name>\n");
209 printf (" refresh\n");
210 printf (" remove\n");
211 skip_to_semi (cfile);
212 break;
213
214 case PORT:
215 token = next_token (&val, (unsigned *)0, cfile);
216 if (is_identifier (token)) {
217 struct servent *se;
218 se = getservbyname (val, "tcp");
219 if (se)
220 port = ntohs (se -> s_port);
221 else {
222 printf ("unknown service name: %s\n", val);
223 break;
224 }
225 } else if (token == NUMBER) {
226 port = atoi (val);
227 } else {
228 skip_to_semi (cfile);
229 printf ("usage: port <port>\n");
230 break;
231 }
232 token = next_token (&val, (unsigned *)0, cfile);
233 if (token != END_OF_FILE && token != EOL) {
234 printf ("usage: port <server>\n");
235 skip_to_semi (cfile);
236 break;
237 }
238 break;
239
240 case TOKEN_SERVER:
241 token = next_token (&val, (unsigned *)0, cfile);
242 if (token == NUMBER) {
243 int alen = (sizeof buf) - 1;
244 int len;
245
246 s = &buf [0];
247 len = strlen (val);
248 if (len + 1 > alen) {
249 baddq:
250 printf ("usage: server <server>\n");
251 skip_to_semi (cfile);
252 break;
253 } strcpy (buf, val);
254 s += len;
255 token = next_token (&val, (unsigned *)0, cfile);
256 if (token != DOT)
257 goto baddq;
258 *s++ = '.';
259 token = next_token (&val, (unsigned *)0, cfile);
260 if (token != NUMBER)
261 goto baddq;
262 len = strlen (val);
263 if (len + 1 > alen)
264 goto baddq;
265 strcpy (s, val);
266 s += len;
267 token = next_token (&val, (unsigned *)0, cfile);
268 if (token != DOT)
269 goto baddq;
270 *s++ = '.';
271 token = next_token (&val, (unsigned *)0, cfile);
272 if (token != NUMBER)
273 goto baddq;
274 len = strlen (val);
275 if (len + 1 > alen)
276 goto baddq;
277 strcpy (s, val);
278 s += len;
279 token = next_token (&val, (unsigned *)0, cfile);
280 if (token != DOT)
281 goto baddq;
282 *s++ = '.';
283 token = next_token (&val, (unsigned *)0, cfile);
284 if (token != NUMBER)
285 goto baddq;
286 len = strlen (val);
287 if (len + 1 > alen)
288 goto baddq;
289 strcpy (s, val);
290 val = &buf [0];
291 } else if (is_identifier (token)) {
292 /* Use val directly. */
293 } else {
294 printf ("usage: server <server>\n");
295 skip_to_semi (cfile);
296 break;
297 }
298
299 s = dmalloc (strlen (val) + 1, MDL);
300 if (!server) {
301 printf ("no memory to store server name.\n");
302 skip_to_semi (cfile);
303 break;
304 }
305 strcpy (s, val);
306 server = s;
307
308 token = next_token (&val, (unsigned *)0, cfile);
309 if (token != END_OF_FILE && token != EOL) {
310 printf ("usage: server <server>\n");
311 skip_to_semi (cfile);
312 break;
313 }
314 break;
315
316 case KEY:
317 token = peek_token(&val, (unsigned *)0, cfile);
318 if (token == STRING) {
319 token = next_token (&val, (unsigned *)0, cfile);
320 if (!is_identifier (token)) {
321 printf ("usage: key <name> <value>\n");
322 skip_to_semi (cfile);
323 break;
324 }
325 s = dmalloc (strlen (val) + 1, MDL);
326 if (!s) {
327 printf ("no memory for key name.\n");
328 skip_to_semi (cfile);
329 break;
330 }
331 strcpy (s, val);
332 } else {
333 s = parse_host_name(cfile);
334 if (s == NULL) {
335 printf ("usage: key <name> <value>\n");
336 skip_to_semi(cfile);
337 break;
338 }
339 }
340 name = s;
341
342 memset (&secret, 0, sizeof secret);
343 if (!parse_base64 (&secret, cfile)) {
344 skip_to_semi (cfile);
345 break;
346 }
347 token = next_token (&val, (unsigned *)0, cfile);
348 if (token != END_OF_FILE && token != EOL) {
349 printf ("usage: key <name> <secret>\n");
350 skip_to_semi (cfile);
351 break;
352 }
353 break;
354
355 case CONNECT:
356 token = next_token (&val, (unsigned *)0, cfile);
357 if (token != END_OF_FILE && token != EOL) {
358 printf ("usage: connect\n");
359 skip_to_semi (cfile);
360 break;
361 }
362
363 authenticator = dhcpctl_null_handle;
364
365 if (name) {
366 status = dhcpctl_new_authenticator (&authenticator,
367 name, algorithm,
368 secret.data,
369 secret.len);
370
371 if (status != ISC_R_SUCCESS) {
372 fprintf (stderr,
373 "Cannot create authenticator: %s\n",
374 isc_result_totext (status));
375 break;
376 }
377 }
378
379 memset (&connection, 0, sizeof connection);
380 status = dhcpctl_connect (&connection,
381 server, port, authenticator);
382 if (status != ISC_R_SUCCESS) {
383 fprintf (stderr, "dhcpctl_connect: %s\n",
384 isc_result_totext (status));
385 break;
386 }
387 connected = 1;
388 break;
389
390 case TOKEN_NEW:
391 token = next_token (&val, (unsigned *)0, cfile);
392 if ((!is_identifier (token) && token != STRING)) {
393 printf ("usage: new <object-type>\n");
394 break;
395 }
396
397 if (oh) {
398 printf ("an object is already open.\n");
399 skip_to_semi (cfile);
400 break;
401 }
402
403 if (!connected) {
404 printf ("not connected.\n");
405 skip_to_semi (cfile);
406 break;
407 }
408
409 status = dhcpctl_new_object (&oh, connection, val);
410 if (status != ISC_R_SUCCESS) {
411 printf ("can't create object: %s\n",
412 isc_result_totext (status));
413 break;
414 }
415
416 token = next_token (&val, (unsigned *)0, cfile);
417 if (token != END_OF_FILE && token != EOL) {
418 printf ("usage: new <object-type>\n");
419 skip_to_semi (cfile);
420 break;
421 }
422 break;
423
424 case TOKEN_CLOSE:
425 token = next_token (&val, (unsigned *)0, cfile);
426 if (token != END_OF_FILE && token != EOL) {
427 printf ("usage: close\n");
428 skip_to_semi (cfile);
429 break;
430 }
431
432 if (!connected) {
433 printf ("not connected.\n");
434 skip_to_semi (cfile);
435 break;
436 }
437
438 if (!oh) {
439 printf ("not open.\n");
440 skip_to_semi (cfile);
441 break;
442 }
443 omapi_object_dereference (&oh, MDL);
444
445 break;
446
447 case TOKEN_SET:
448 token = next_token (&val, (unsigned *)0, cfile);
449
450 if ((!is_identifier (token) && token != STRING)) {
451 set_usage:
452 printf ("usage: set <name> = <value>\n");
453 skip_to_semi (cfile);
454 break;
455 }
456
457 if (oh == NULL) {
458 printf ("no open object.\n");
459 skip_to_semi (cfile);
460 break;
461 }
462
463 if (!connected) {
464 printf ("not connected.\n");
465 skip_to_semi (cfile);
466 break;
467 }
468
469 #ifdef HAVE_STRLCPY
470 strlcpy (s1, val, sizeof(s1));
471 #else
472 s1[0] = 0;
473 strncat (s1, val, sizeof(s1)-strlen(s1)-1);
474 #endif
475
476 token = next_token (&val, (unsigned *)0, cfile);
477 if (token != EQUAL)
478 goto set_usage;
479
480 token = next_token (&val, (unsigned *)0, cfile);
481 switch (token) {
482 case STRING:
483 dhcpctl_set_string_value (oh, val, s1);
484 token = next_token (&val, (unsigned *)0, cfile);
485 break;
486
487 case NUMBER:
488 strcpy (buf, val);
489 token = peek_token (&val, (unsigned *)0, cfile);
490 /* Colon-separated hex list? */
491 if (token == COLON)
492 goto cshl;
493 else if (token == DOT) {
494 s = buf;
495 val = buf;
496 do {
497 int intval = atoi (val);
498 if (intval > 255) {
499 parse_warn (cfile,
500 "dotted octet > 255: %s",
501 val);
502 skip_to_semi (cfile);
503 goto badnum;
504 }
505 *s++ = intval;
506 token = next_token (&val,
507 (unsigned *)0, cfile);
508 if (token != DOT)
509 break;
510 /* DOT is zero. */
511 while ((token = next_token (&val,
512 (unsigned *)0, cfile)) == DOT)
513 *s++ = 0;
514 } while (token == NUMBER);
515 dhcpctl_set_data_value (oh, buf,
516 (unsigned)(s - buf),
517 s1);
518 break;
519 }
520 dhcpctl_set_int_value (oh, atoi (buf), s1);
521 token = next_token (&val, (unsigned *)0, cfile);
522 badnum:
523 break;
524
525 case NUMBER_OR_NAME:
526 strcpy (buf, val);
527 cshl:
528 s = buf;
529 val = buf;
530 do {
531 convert_num (cfile, (unsigned char *)s,
532 val, 16, 8);
533 ++s;
534 token = next_token (&val,
535 (unsigned *)0, cfile);
536 if (token != COLON)
537 break;
538 token = next_token (&val,
539 (unsigned *)0, cfile);
540 } while (token == NUMBER ||
541 token == NUMBER_OR_NAME);
542 dhcpctl_set_data_value (oh, buf,
543 (unsigned)(s - buf), s1);
544 break;
545
546 default:
547 printf ("invalid value.\n");
548 skip_to_semi (cfile);
549 }
550
551 if (token != END_OF_FILE && token != EOL)
552 goto set_usage;
553 break;
554
555 case UNSET:
556 token = next_token (&val, (unsigned *)0, cfile);
557
558 if ((!is_identifier (token) && token != STRING)) {
559 unset_usage:
560 printf ("usage: unset <name>\n");
561 skip_to_semi (cfile);
562 break;
563 }
564
565 if (!oh) {
566 printf ("no open object.\n");
567 skip_to_semi (cfile);
568 break;
569 }
570
571 if (!connected) {
572 printf ("not connected.\n");
573 skip_to_semi (cfile);
574 break;
575 }
576
577 #if HAVE_STRLCPY
578 strlcpy (s1, val, sizeof(s1));
579 #else
580 s1[0] = 0;
581 strncat (s1, val, sizeof(s1)-strlen(s1)-1);
582 #endif
583
584 token = next_token (&val, (unsigned *)0, cfile);
585 if (token != END_OF_FILE && token != EOL)
586 goto unset_usage;
587
588 dhcpctl_set_null_value (oh, s1);
589 break;
590
591
592 case TOKEN_CREATE:
593 case TOKEN_OPEN:
594 i = token;
595 token = next_token (&val, (unsigned *)0, cfile);
596 if (token != END_OF_FILE && token != EOL) {
597 printf ("usage: %s\n", val);
598 skip_to_semi (cfile);
599 break;
600 }
601
602 if (!connected) {
603 printf ("not connected.\n");
604 skip_to_semi (cfile);
605 break;
606 }
607
608 if (!oh) {
609 printf ("you must make a new object first!\n");
610 skip_to_semi (cfile);
611 break;
612 }
613
614 if (i == TOKEN_CREATE)
615 i = DHCPCTL_CREATE | DHCPCTL_EXCL;
616 else
617 i = 0;
618
619 status = dhcpctl_open_object (oh, connection, i);
620 if (status == ISC_R_SUCCESS)
621 status = dhcpctl_wait_for_completion
622 (oh, &waitstatus);
623 if (status == ISC_R_SUCCESS)
624 status = waitstatus;
625 if (status != ISC_R_SUCCESS) {
626 printf ("can't open object: %s\n",
627 isc_result_totext (status));
628 break;
629 }
630
631 break;
632
633 case UPDATE:
634 token = next_token (&val, (unsigned *)0, cfile);
635 if (token != END_OF_FILE && token != EOL) {
636 printf ("usage: %s\n", val);
637 skip_to_semi (cfile);
638 break;
639 }
640
641 if (!connected) {
642 printf ("not connected.\n");
643 skip_to_semi (cfile);
644 break;
645 }
646
647 if (!oh) {
648 printf ("you haven't opened an object yet!\n");
649 skip_to_semi (cfile);
650 break;
651 }
652
653 status = dhcpctl_object_update(connection, oh);
654 if (status == ISC_R_SUCCESS)
655 status = dhcpctl_wait_for_completion
656 (oh, &waitstatus);
657 if (status == ISC_R_SUCCESS)
658 status = waitstatus;
659 if (status != ISC_R_SUCCESS) {
660 printf ("can't update object: %s\n",
661 isc_result_totext (status));
662 break;
663 }
664
665 break;
666
667 case REMOVE:
668 token = next_token (&val, (unsigned *)0, cfile);
669 if (token != END_OF_FILE && token != EOL) {
670 printf ("usage: remove\n");
671 skip_to_semi (cfile);
672 break;
673 }
674
675 if (!connected) {
676 printf ("not connected.\n");
677 break;
678 }
679
680 if (!oh) {
681 printf ("no object.\n");
682 break;
683 }
684
685 status = dhcpctl_object_remove(connection, oh);
686 if (status == ISC_R_SUCCESS)
687 status = dhcpctl_wait_for_completion
688 (oh, &waitstatus);
689 if (status == ISC_R_SUCCESS)
690 status = waitstatus;
691 if (status != ISC_R_SUCCESS) {
692 printf ("can't destroy object: %s\n",
693 isc_result_totext (status));
694 break;
695 }
696 omapi_object_dereference (&oh, MDL);
697 break;
698
699 case REFRESH:
700 token = next_token (&val, (unsigned *)0, cfile);
701 if (token != END_OF_FILE && token != EOL) {
702 printf ("usage: refresh\n");
703 skip_to_semi (cfile);
704 break;
705 }
706
707 if (!connected) {
708 printf ("not connected.\n");
709 break;
710 }
711
712 if (!oh) {
713 printf ("no object.\n");
714 break;
715 }
716
717 status = dhcpctl_object_refresh(connection, oh);
718 if (status == ISC_R_SUCCESS)
719 status = dhcpctl_wait_for_completion
720 (oh, &waitstatus);
721 if (status == ISC_R_SUCCESS)
722 status = waitstatus;
723 if (status != ISC_R_SUCCESS) {
724 printf ("can't refresh object: %s\n",
725 isc_result_totext (status));
726 break;
727 }
728
729 break;
730 }
731 end_parse (&cfile);
732 } while (1);
733
734 exit (0);
735 }
736
737 /* Sigh */
738 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
739 control_object_state_t newstate)
740 {
741 return ISC_R_SUCCESS;
742 }