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