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