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