Collapse gd_astpending and gd_reqpri together into gd_reqflags. gd_reqflags
[dragonfly.git] / usr.sbin / keyadmin / keyadmin.c
1 /*----------------------------------------------------------------------
2   key.c:   Main routines for the key(8) tool for manually managing
3            cryptographic keys and security associations inside the
4            Key Engine of the operating system.
5
6            Future Enhancements should support:
7                 multiple sensitivity levels
8                 OSPFv2 keys
9                 RIPv2 keys
10                 Triple DES for ESP
11                 DES+MD5 for ESP
12  
13            Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald,
14            All Rights Reserved.  All Rights have been assigned to the
15            US Naval Research Laboratory.  The NRL Copyright Notice and
16            License govern distribution and use of this software.
17 ----------------------------------------------------------------------*/
18 /*----------------------------------------------------------------------
19 #       @(#)COPYRIGHT   1.1a (NRL) 17 August 1995
20  
21 COPYRIGHT NOTICE
22  
23 All of the documentation and software included in this software
24 distribution from the US Naval Research Laboratory (NRL) are
25 copyrighted by their respective developers.
26  
27 This software and documentation were developed at NRL by various
28 people.  Those developers have each copyrighted the portions that they
29 developed at NRL and have assigned All Rights for those portions to
30 NRL.  Outside the USA, NRL also has copyright on the software
31 developed at NRL. The affected files all contain specific copyright
32 notices and those notices must be retained in any derived work.
33  
34 NRL LICENSE
35  
36 NRL grants permission for redistribution and use in source and binary
37 forms, with or without modification, of the software and documentation
38 created at NRL provided that the following conditions are met:
39  
40 1. Redistributions of source code must retain the above copyright
41    notice, this list of conditions and the following disclaimer.
42 2. Redistributions in binary form must reproduce the above copyright
43    notice, this list of conditions and the following disclaimer in the
44    documentation and/or other materials provided with the distribution.
45 3. All advertising materials mentioning features or use of this software
46    must display the following acknowledgement:
47  
48         This product includes software developed at the Information
49         Technology Division, US Naval Research Laboratory.
50  
51 4. Neither the name of the NRL nor the names of its contributors
52    may be used to endorse or promote products derived from this software
53    without specific prior written permission.
54  
55 THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
56 IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
58 PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
59 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
60 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
61 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
62 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
63 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
64 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
65 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66  
67 The views and conclusions contained in the software and documentation
68 are those of the authors and should not be interpreted as representing
69 official policies, either expressed or implied, of the US Naval
70 Research Laboratory (NRL).
71
72 ----------------------------------------------------------------------*/
73
74 /*
75  *      $ANA: keyadmin.c,v 1.2 1996/06/13 19:42:40 wollman Exp $
76  */
77
78 #include <sys/types.h>
79 #include <sys/stat.h>
80 #include <sys/socket.h>
81 #include <sys/socketvar.h>
82
83 #include <err.h>
84 #include <errno.h>
85 #include <fcntl.h>
86 #include <netdb.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <unistd.h>
91
92 #include <netinet/in.h>
93
94 #ifdef INET6
95 #include <netinet6/in6.h>
96 #else /* INET6 */
97 #if 0
98 #include <netinet6/in6_types.h>
99 #endif
100 #endif /* INET6 */
101
102 #ifdef IPSEC
103 #include <netsec/ipsec.h>
104 #endif
105 #include <netkey/key.h>
106
107 #ifdef INET6
108 #include <netinet6/support.h>
109 #endif
110
111 #ifndef INET6 /* XXX */
112 #define hostname2addr(a, b, c) gethostbyname(a)
113 #define addr2hostname(a, b, c, d) gethostbyaddr((a), (b), (c))
114 #endif
115
116 #include <arpa/inet.h>
117
118 int parse7 __P((int, char **));
119 int parse4 __P((int, char **));
120 int docmd __P((int, char **));
121
122 #define KEYCMD_ARG_MAX  10
123
124 #define KEYCMD_LOAD   1
125 #define KEYCMD_SAVE   2
126 #define KEYCMD_ADD    3
127 #define KEYCMD_DEL    4
128 #define KEYCMD_FLUSH  5
129 #define KEYCMD_GET    6
130 #define KEYCMD_DUMP   7
131 #define KEYCMD_HELP   8
132 #define KEYCMD_EXIT   9
133 #define KEYCMD_SHELL  10
134
135 struct nametonum {
136   char *name;
137   int num;
138   int flags;
139 };
140
141 char parse7usage[] = "<type> <spi> <src> <dst> <transform> <key> [iv]";
142 char parse4usage[] = "<type> <spi> <src> <dst>";
143
144 struct keycmd {
145   char *name;
146   int num;
147   int (*parse) __P((int, char **));
148   char *usage;
149   char *help;
150 } keycmds[] = {
151   { "add", KEYCMD_ADD, parse7, parse7usage, 
152       "Adds a specific key entry to the kernel key table." },
153   { "del", KEYCMD_DEL, parse4, parse4usage, 
154       "Removes a specific key entry from the kernel key table." },
155   { "get", KEYCMD_GET, parse4, parse4usage,
156       "Retrieves a key entry from the kernel key table." },
157   { "dump", KEYCMD_DUMP, NULL, " ",
158       "Retrieves all key entries from the kernel key table." },
159   { "load", KEYCMD_LOAD, NULL, "{ <filename> | - }",
160       "Loads keys from a file or stdin into the kernel key table." },
161   { "save", KEYCMD_SAVE, NULL, "{ <filename> | - }",
162       "Saves keys from the kernel key table to a file or stdout." },
163   { "help", KEYCMD_HELP, NULL, "[command]",
164       "Provides limited on-line help. Read the man page for more." },
165   { "flush", KEYCMD_FLUSH, NULL, NULL,
166       "Clears the kernel key table." },
167   { "!", KEYCMD_SHELL, NULL, "[command]",
168       "Executes a subshell." },
169   { "exit", KEYCMD_EXIT, NULL, NULL,
170       "Exits the program." },
171   { "quit", KEYCMD_EXIT, NULL, NULL,
172       "Exits the program." },
173   { NULL, 0, NULL, NULL, NULL }
174 };
175
176 /* flags: index into algorithmtabs */
177
178 struct nametonum keytypes[] = {
179 #ifdef IPSEC
180   { "ah", KEY_TYPE_AH, 0 },
181   { "esp", KEY_TYPE_ESP, 1 },
182 #endif
183   { "rsvp", KEY_TYPE_RSVP, 2 },
184   { "ospf", KEY_TYPE_OSPF, 3 },
185   { "rip", KEY_TYPE_RIPV2, 4 },
186   { NULL, 0, 0 }
187 };
188
189 #ifndef IPSEC_ALGTYPE_AUTH_MD5  /* XXX */
190 #define IPSEC_ALGTYPE_AUTH_MD5  1
191 #endif
192
193 /* flags: true = iv req. */
194 struct nametonum authalgorithms[] = {
195   { "md5", IPSEC_ALGTYPE_AUTH_MD5, 0 },
196 #ifdef DEBUG
197   /* These provide no security but are useful for debugging the
198      kernel's ESP and Key Engine and PF_KEY routines */
199   { "dummy", IPSEC_ALGTYPE_AUTH_DUMMY, 0 },
200   { "cksum", IPSEC_ALGTYPE_AUTH_CKSUM, 0 },
201 #endif
202   { NULL, 0, 0 }
203 };
204
205 #ifndef IPSEC_ALGTYPE_ESP_DES_CBC /* XXX */
206 #define IPSEC_ALGTYPE_ESP_DES_CBC       1
207 #endif
208
209 /* flags: true = iv req. */
210 struct nametonum encralgorithms[] = {
211   { "des-cbc", IPSEC_ALGTYPE_ESP_DES_CBC, 1 },
212 #ifdef DEBUG
213   /* These provide no security but are useful for debugging the
214      kernel's ESP and Key Engine and PF_KEY routines */
215   { "dummy", IPSEC_ALGTYPE_ESP_DUMMY, 0 },
216 #endif
217   { NULL, 0, 0 }
218 };
219
220 /*
221  * These numbers should be defined in a header file somewhere
222  * and shared with the consuming programs, once someone has
223  * actually written the support in those programs (rspvd,
224  * gated, and routed).  Probably <protocols/*>...?
225  */
226 #define RSVP_AUTHTYPE_MD5       1       /* XXX */
227 struct nametonum rsvpalgorithms[] = {
228         { "md5", RSVP_AUTHTYPE_MD5, 0 },
229         { NULL, 0, 0 }
230 };
231
232 #define OSPF_AUTHTYPE_MD5       1       /* XXX */
233 struct nametonum ospfalgorithms[] = {
234         { "md5", OSPF_AUTHTYPE_MD5, 0 },
235         { NULL, 0, 0 }
236 };
237
238 #define RIPV2_AUTHTYPE_MD5      1       /* XXX */
239 struct nametonum ripalgorithms[] = {
240         { "md5", RIPV2_AUTHTYPE_MD5, 0 },
241         { NULL, 0, 0 }
242 };
243
244 /* NB:  It is the ordering here that determines the values for the
245    flags specified above that are used to index into algorithmtabs[] */
246 struct nametonum *algorithmtabs[] = {
247   authalgorithms,
248   encralgorithms,
249   rsvpalgorithms,
250   ospfalgorithms,
251   ripalgorithms,
252   NULL
253 };
254
255 char buffer[1024] = "\0";
256
257 #define MAXRCVBUFSIZE      8 * 1024
258
259 char key_message[sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3 
260                  + MAX_KEY_SZ + MAX_IV_SZ];
261 int key_messageptr;
262
263 int keysock = -1;
264
265 int keygetseqno = 1;
266 int keydumpseqno = 1;
267 pid_t mypid;
268
269 \f
270 /*----------------------------------------------------------------------
271   help:   Print appropriate help message on stdout.
272
273 ----------------------------------------------------------------------*/
274 int help(cmdname)
275      char *cmdname;
276 {
277   int i;
278
279   if (cmdname) {
280     for (i = 0; keycmds[i].name; i++)
281       if (!strcasecmp(keycmds[i].name, cmdname))
282         break;
283
284     if (!keycmds[i].name) {
285       warnx("unknown command: %s", cmdname);
286       return 0;
287     }
288
289     printf("%s%s%s\n", keycmds[i].name, keycmds[i].usage ? " " : "",
290            keycmds[i].usage ? keycmds[i].usage : "");
291
292     if (keycmds[i].help)
293       puts(keycmds[i].help);
294   } else {
295     for (i = 0; keycmds[i].name; i++)
296       printf("\t%s%s%s\n", keycmds[i].name, keycmds[i].usage ? " " : "",
297              keycmds[i].usage ? keycmds[i].usage : "");
298   }
299
300   return 0;
301 }
302
303 /*----------------------------------------------------------------------
304   usage:  print suitable usage message on stdout.
305
306 ----------------------------------------------------------------------*/
307 static void
308 usage()
309 {
310
311   fprintf(stderr, "usage: keyadmin <command> <args>\n");
312 }
313
314 /*----------------------------------------------------------------------
315   parsekey:  parse argument into a binary key and also record
316              the length of the resulting key.
317 ----------------------------------------------------------------------*/
318 int parsekey(key, keylen, arg)
319      u_int8_t *key;
320      u_int8_t *keylen;
321      char *arg;
322 {
323   int i, j, k, l;
324   u_int8_t thisbyte;
325
326   i = strlen(arg);
327
328   if ((i == 1) && (arg[0] == '0')) {
329     *keylen = 0;
330     return 0;
331   }
332     
333   if ((i % 2)) {
334     printf("Invalid number \"%s\"\n", arg);
335     return -1;
336   }
337
338   j = 1;
339   k = l = thisbyte = 0;
340
341   while(arg[k]) {
342     if ((arg[k] >= '0') && (arg[k] <= '9'))
343       thisbyte |= arg[k] - '0';
344     else
345       if ((arg[k] >= 'a') && (arg[k] <= 'f'))
346         thisbyte |= arg[k] - 'a' + 10;
347       else
348         if ((arg[k] >= 'A') && (arg[k] <= 'F'))
349           thisbyte |= arg[k] - 'A' + 10;
350         else {
351           printf("Invalid hex number \"%s\"\n", arg);
352           return 1;
353         }
354
355     if (!(j % 2)) 
356       key[l++] = thisbyte;
357
358     thisbyte = (thisbyte << 4);
359     j++;
360     k++;
361   }
362
363   *keylen = l;
364
365   return 0;
366 }
367
368 /*----------------------------------------------------------------------
369   parsenametonum:   converts command-line name into index number.
370
371 ----------------------------------------------------------------------*/
372 int parsenametonum(tab, arg)
373      struct nametonum *tab;
374      char *arg;
375 {
376   int i;
377
378   for (i = 0; tab[i].name; i++)
379     if (!strcasecmp(tab[i].name, arg))
380       return i;
381
382   if (!tab[i].name)
383     return -1;
384 }
385
386 /*----------------------------------------------------------------------
387   parsesockaddr:  Convert hostname arg into an appropriate sockaddr.
388
389 ----------------------------------------------------------------------*/
390 int parsesockaddr(sockaddr, arg)
391      struct sockaddr *sockaddr;
392      char *arg;
393 {
394   struct hostent *hostent;
395   struct in_addr in_addr, *in_addrp;
396 #ifdef INET6
397   struct in_addr6 in_addr6, *in_addr6p;
398 #endif /* INET6 */
399
400   if ((hostent = hostname2addr(arg, AF_INET, 0)))
401     if ((hostent->h_addrtype == AF_INET) && 
402         (hostent->h_length == sizeof(struct in_addr))) {
403       in_addrp = ((struct in_addr *)hostent->h_addr_list[0]);
404       goto fillin4;
405     }
406   
407   if (ascii2addr(AF_INET, arg, (char *)&in_addr) == 
408       sizeof(struct in_addr)) {
409     in_addrp = &in_addr;
410     goto fillin4;
411   }
412
413 #ifdef INET6
414   if (hostent = hostname2addr(arg, AF_INET6))
415     if ((hostent->h_addrtype == AF_INET6) && 
416         (hostent->h_length == sizeof(struct in_addr6))) {
417       in_addr6p = ((struct in_addr6 *)hostent->h_addr_list[0]);
418       goto fillin6;
419     }
420   
421   if (ascii2addr(AF_INET6, arg, (char *)&in_addr6)
422       == sizeof(struct in_addr6)) {
423     in_addr6p = &in_addr6;
424     goto fillin6;
425   }
426 #endif /* INET6 */
427
428   warnx("unknown host \"%s\"", arg);
429   return 1;
430
431  fillin4:
432   bzero(sockaddr, sizeof(struct sockaddr_in));
433   sockaddr->sa_len = sizeof(struct sockaddr_in);
434   sockaddr->sa_family = AF_INET;
435   ((struct sockaddr_in *)sockaddr)->sin_addr = *in_addrp;
436   return 0;
437
438 #ifdef INET6
439  fillin6:
440   bzero(sockaddr, sizeof(struct sockaddr_in6));
441   sockaddr->sa_len = sizeof(struct sockaddr_in6);
442   sockaddr->sa_family = AF_INET6;
443   ((struct sockaddr_in6 *)sockaddr)->sin6_addr = *in_addr6p;
444   return 0;
445 #endif /* INET6 */
446 }
447
448 /*----------------------------------------------------------------------
449   dummyfromaddr:  Creates a zeroed sockaddr of family af.
450
451 ----------------------------------------------------------------------*/
452 void dummyfromaddr(sa, af)
453      struct sockaddr *sa;
454      int af;
455 {
456   int size;
457 #ifdef INET6
458   size = (af == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
459 #else /* INET6 */
460   size = sizeof(struct sockaddr_in);
461 #endif /* INET6 */
462   bzero((char *)sa, size);
463   sa->sa_family = af;
464   sa->sa_len = size;
465 }
466
467 /* 
468  * Macros to ensure word alignment.
469  */
470 #define ROUNDUP(a) \
471   ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
472 #define ADVANCE(x, n) \
473   { x += ROUNDUP(n); }
474
475
476 /*----------------------------------------------------------------------
477   parse4:  parse keytype, spi, src addr, and dest addr from argv (command line)
478            and stick in structure pointed to by key_messageptr.
479 ----------------------------------------------------------------------*/
480 int parse4(argc, argv)
481      int argc;
482      char *argv[];
483 {
484   int i;
485
486   if (argc < 4)
487     return 1;
488
489   if ((i = parsenametonum(keytypes, argv[0])) < 0)
490     return i;
491
492   ((struct key_msghdr *)key_message)->type = keytypes[i].num;
493
494   /* Should we zero check? */
495   ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
496
497   if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
498     return 1;
499   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
500                                                key_messageptr))->sa_len);
501   
502   if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
503     return 1;
504   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
505                                                key_messageptr))->sa_len);
506
507   /*
508    *  We need to put a dummy from address since the kernel expects
509    *  this to be in the message.
510    */
511 #ifdef INET6
512   dummyfromaddr(key_message + key_messageptr, AF_INET6);
513 #else /* INET6 */
514   dummyfromaddr(key_message + key_messageptr, AF_INET);
515 #endif /* INET6 */
516   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
517                                                key_messageptr))->sa_len);
518
519   return 0;
520 }
521
522 /*----------------------------------------------------------------------
523   parse7:  parse keytype, spi, src addr, dest addr, alg type, key, and iv
524            from argv (command line)
525            and stick in structure pointed to by key_messageptr.
526 ----------------------------------------------------------------------*/
527 int parse7(argc, argv)
528      int argc;
529      char *argv[];
530 {
531   int i, j;
532
533   if (argc < 6)
534     return 1;
535
536   if ((i = parsenametonum(keytypes, argv[0])) < 0)
537     return i;
538
539   ((struct key_msghdr *)key_message)->type = keytypes[i].num;
540
541 /* Should we zero check? */
542   ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
543
544   if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
545     return 1;
546   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
547                                                key_messageptr))->sa_len);
548
549   if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
550     return 1;
551   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
552                                                key_messageptr))->sa_len);
553
554   /*
555    *  We need to put a dummy from address since the kernel expects
556    *  this to be in the message.
557    */
558 #ifdef INET6
559   dummyfromaddr(key_message + key_messageptr, AF_INET6);
560 #else /* INET6 */
561   dummyfromaddr(key_message + key_messageptr, AF_INET);
562 #endif /* INET6 */
563   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
564                                                key_messageptr))->sa_len);  
565
566   if ((j = parsenametonum(algorithmtabs[keytypes[i].flags], argv[4])) < 0)
567     return j;
568
569   ((struct key_msghdr *)key_message)->algorithm =
570         algorithmtabs[keytypes[i].flags][j].num;
571
572   if ((argc < 7) && algorithmtabs[keytypes[i].flags][j].flags)
573     return 1;
574
575   if (parsekey(key_message + key_messageptr, 
576            &(((struct key_msghdr *)key_message)->keylen), argv[5]) != 0)
577     return 1;
578   ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->keylen);  
579
580   if (argc >= 7) {
581     if (parsekey(key_message + key_messageptr,
582              &(((struct key_msghdr *)key_message)->ivlen), argv[6]) != 0)
583       return 1;
584     ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->ivlen);
585   }
586
587   return 0;
588 }
589
590 /*----------------------------------------------------------------------
591   parsecmdline:
592
593 ----------------------------------------------------------------------*/
594 int parsecmdline(buffer, argv, argc)
595      char *buffer;
596      char **argv;
597      int *argc;
598 {
599   int i = 0, iargc = 0;
600   char *head;
601
602   head = buffer;
603
604   while(buffer[i] && (iargc < KEYCMD_ARG_MAX)) {
605     if ((buffer[i] == '\n') || (buffer[i] == '#')) {
606       buffer[i] = 0;
607       if (*head)
608         argv[iargc++] = head;
609       break;
610     }
611     if ((buffer[i] == ' ') || (buffer[i] == '\t')) {
612       buffer[i] = 0;
613       if (*head)
614         argv[iargc++] = head;
615       head = &(buffer[++i]);
616     } else
617       i++;
618   };
619   argv[iargc] = NULL;
620   *argc = iargc;
621
622   return iargc ? 0 : 1;
623 }
624
625
626 /*----------------------------------------------------------------------
627   load:   load keys from file filename into Key Engine.
628
629 ----------------------------------------------------------------------*/
630 int load(filename)
631      char *filename;
632 {
633   FILE *fh;
634   char buffer[1024], *buf, *largv[KEYCMD_ARG_MAX], *c;
635   int i, largc, left, line = 0;
636
637   if (strcmp(filename, "-")) {
638     if (!(fh = fopen(filename, "r")))
639       return -1;
640   } else
641     fh = stdin;
642
643   largv[0] = "add";
644
645   buf = buffer;
646   left = sizeof(buffer);
647
648   while(fgets(buf, left, fh)) {
649     line++;
650     if ((c = strchr(buffer, '\\'))) {
651       left = (sizeof(buffer) - 1) - (--c - buffer);
652       buf = c;
653     } else {
654       buffer[sizeof(buffer)-1] = 0;
655
656       if ((i = parsecmdline(buffer, &(largv[1]), &largc)) < 0)
657         return i;
658
659       if (!i) {
660         if ((i = docmd(++largc, largv))) {
661           if (i > 0) {
662             warnx("parse error on line %d of %s", line, filename);
663             return 0;
664           }
665           return i;
666         }
667       }
668
669       buf = buffer;
670       left = sizeof(buffer);
671     }
672   };
673
674   return 0;
675 }
676
677 /*----------------------------------------------------------------------
678   parsedata:
679
680 ----------------------------------------------------------------------*/
681 int
682 parsedata(km, kip)
683      struct key_msghdr *km;
684      struct key_msgdata *kip;
685 {
686   char *cp, *cpmax;
687  
688   if (!km)
689     return (-1);
690   if (!(km->key_msglen))
691     return (-1);
692  
693   cp = (caddr_t)(km + 1);
694   cpmax = (caddr_t)km + km->key_msglen;
695  
696 #define NEXTDATA(x, n) \
697     { x += ROUNDUP(n); if (cp >= cpmax) { \
698     warnx("kernel returned a truncated message!"); return(-1); } }
699  
700   /* Grab src addr */
701   kip->src = (struct sockaddr *)cp;
702   if (!kip->src->sa_len)
703     return(-1);
704  
705   NEXTDATA(cp, kip->src->sa_len);
706  
707   /* Grab dest addr */
708   kip->dst = (struct sockaddr *)cp;
709   if (!kip->dst->sa_len)
710      return(-1);
711  
712   NEXTDATA(cp, kip->dst->sa_len);
713  
714   /* Grab from addr */
715   kip->from = (struct sockaddr *)cp;
716   if (!kip->from->sa_len)
717     return(-1);
718  
719   NEXTDATA(cp, kip->from->sa_len);
720  
721   /* Grab key */
722   if (kip->keylen = km->keylen) {
723     kip->key = cp;
724     NEXTDATA(cp, km->keylen);
725   }
726  
727   /* Grab iv */
728   if (kip->ivlen = km->ivlen)
729     kip->iv = cp;
730
731   cp += kip->ivlen;
732
733   printf("key: parsedata: difference=%d\n", cp - cpmax);
734   return (0);
735 }
736
737
738 /*----------------------------------------------------------------------
739   printkeyiv:
740
741 ----------------------------------------------------------------------*/
742 void printkeyiv(fp, cp, len)
743      FILE *fp;
744      caddr_t cp;
745      int len;
746 {
747   int i;
748   for (i=0; i<len; i++)
749     fprintf(fp, "%02x", (u_int8_t)*(cp+i));
750 }
751
752 /*----------------------------------------------------------------------
753   printsockaddr:
754
755 ----------------------------------------------------------------------*/
756 void printsockaddr(fp, sa)
757      FILE *fp;
758      struct sockaddr *sa;
759 {
760   struct hostent *hp;
761   char *addrp;
762   int len;
763
764 #ifdef INET6
765   if (sa->sa_family == AF_INET6) {
766     len = sizeof(struct in_addr6); 
767     addrp = (char *)&(((struct sockaddr_in6 *)sa)->sin6_addr);
768   } else {
769 #endif /* INET6 */
770     len = sizeof(struct in_addr);
771     addrp = (char *)&(((struct sockaddr_in *)sa)->sin_addr);
772 #ifdef INET6
773   }
774 #endif /* INET6 */
775
776   if((hp = addr2hostname(addrp, len, sa->sa_family, 0)) != NULL)
777     fprintf(fp, "%s", hp->h_name);
778   else
779     fprintf(fp, "%s", addr2ascii(sa->sa_family, addrp, len, NULL));
780 }
781
782 /*----------------------------------------------------------------------
783   parsenumtoname:
784
785 ----------------------------------------------------------------------*/
786 char *
787 parsenumtoname(tab, num)
788      struct nametonum *tab;
789      int num;
790 {
791   int i;
792   for (i = 0; tab[i].name; i++) {
793     if (num == tab[i].num)
794       return(tab[i].name);
795   }
796   return(0);
797 }
798
799 /*----------------------------------------------------------------------
800   parsenumtoflag:
801
802 ----------------------------------------------------------------------*/
803 int
804 parsenumtoflag(tab, num)
805      struct nametonum *tab;
806      int num;
807 {
808   int i;
809   for (i = 0; tab[i].name; i++) {
810     if (num == tab[i].num)
811       return(tab[i].flags);
812   }
813   return(-1);
814 }
815
816
817 /*----------------------------------------------------------------------
818   printkeymsg:
819
820 ----------------------------------------------------------------------*/
821 void printkeymsg(kmp, kdp)
822      struct key_msghdr *kmp;
823      struct key_msgdata *kdp;
824 {
825
826   printf("type=%d(%s) ",kmp->type, parsenumtoname(keytypes, kmp->type)); 
827   printf("spi=%u ", kmp->spi);
828   printf("alogrithm=%u(%s) ", kmp->algorithm,
829          parsenumtoname(algorithmtabs[parsenumtoflag(keytypes, kmp->type)],
830                         kmp->algorithm));
831   printf("state=0x%x ",kmp->state); 
832
833   if (kmp->state != 0) {
834     if (kmp->state & K_USED)
835       printf("USED ");
836     if (kmp->state & K_UNIQUE)
837       printf("UNIQUE ");    
838     if (kmp->state & K_LARVAL)
839       printf("LARVAL ");
840     if (kmp->state & K_ZOMBIE)
841       printf("ZOMBIE ");
842     if (kmp->state & K_DEAD)
843       printf("DEAD ");
844     if (kmp->state & K_INBOUND)
845       printf("INBOUND ");
846     if (kmp->state & K_OUTBOUND)
847       printf("OUTBOUND");
848   }
849   printf("\n");
850   printf("sensitivity_label=%d ",kmp->label);
851   printf("lifetype=%d ",kmp->lifetype);
852   printf("lifetime1=%d ",kmp->lifetime1);
853   printf("lifetime2=%d\n",kmp->lifetime2);
854   printf("key (len=%d):\t",kdp->keylen);
855   printkeyiv(stdout, kdp->key, kdp->keylen);
856   printf("\n");
857   printf("iv (len=%d):\t", kdp->ivlen);
858   printkeyiv(stdout, kdp->iv, kdp->ivlen);
859   printf("\n");
860   printf("src:\t");
861   printsockaddr(stdout, (struct sockaddr *)kdp->src);
862   printf("\n");
863   printf("dst:\t");
864   printsockaddr(stdout, (struct sockaddr *)kdp->dst);
865   printf("\n");
866 /*  printf("from:\t");
867   printsockaddr(stdout, (struct sockaddr *)kdp->from); */
868   printf("\n");
869 }
870
871 /*----------------------------------------------------------------------
872   docmd:
873
874 ----------------------------------------------------------------------*/
875 int docmd(argc, argv)
876      int argc;
877      char **argv;
878 {
879   int i, j, seqno;
880   int fd;
881   FILE *fp;
882
883   if (!argv[0] || !argc)
884     return -1;
885
886   if (!argv[0][0])
887     return -1;
888
889   bzero(&key_message, sizeof(key_message));
890   key_messageptr = sizeof(struct key_msghdr);
891
892   for (i = 0; keycmds[i].name; i++)
893     if (!strcasecmp(keycmds[i].name, argv[0]))
894       break;
895
896   if (!keycmds[i].name)
897     return -1;
898
899   if (keycmds[i].parse)
900     if ((j = keycmds[i].parse(argc - 1, &(argv[1]))))
901       return j;
902
903   ((struct key_msghdr *)key_message)->key_msglen = key_messageptr;
904   ((struct key_msghdr *)key_message)->key_msgvers = 1;
905   ((struct key_msghdr *)key_message)->key_seq = 1;
906
907   switch(keycmds[i].num) {
908
909   case KEYCMD_ADD:
910 #ifndef NOSANITYCHK
911     /*
912      * For now, we do sanity check of security association 
913      * information here until we find a better place.
914      */
915     {
916       struct key_msghdr *kmp = (struct key_msghdr *)key_message;
917
918       if ((kmp->type == KEY_TYPE_AH || 
919            kmp->type == KEY_TYPE_ESP) && (kmp->spi < 256)) {
920         warnx("add: spi must be greater than 255");
921         return(0);
922       }
923
924       if (kmp->type == KEY_TYPE_ESP && 
925           (kmp->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC
926 #ifdef IPSEC_ALGTYPE_ESP_3DES
927            || kmp->algorithm == IPSEC_ALGTYPE_ESP_3DES
928 #endif
929            )) {
930         if (kmp->keylen != 8) {
931           warnx("add: key must be 8 bytes");
932           return (0);
933         }
934         if (kmp->ivlen != 4 && kmp->ivlen != 8) {
935           warnx("add: iv must be 4 or 8 bytes");
936           return (0);
937         }
938       }
939
940       if (kmp->type == KEY_TYPE_AH &&
941           kmp->algorithm == IPSEC_ALGTYPE_AUTH_MD5 && kmp->keylen == 0) {
942         warnx("add: no key specified");
943         return (0);
944       }
945     }
946 #endif
947     ((struct key_msghdr *)key_message)->key_msgtype = KEY_ADD;
948     if (write(keysock, key_message, 
949               ((struct key_msghdr *)key_message)->key_msglen) != 
950         ((struct key_msghdr *)key_message)->key_msglen) {
951       if (errno == EEXIST)
952         warnx("add: security association already exists");
953       else
954         warn("add");
955       return -1;
956     }
957     read(keysock, key_message, sizeof(key_message));
958     return (0);
959
960   case KEYCMD_DEL:
961     ((struct key_msghdr *)key_message)->key_msgtype = KEY_DELETE;
962     if (write(keysock, key_message, 
963               ((struct key_msghdr *)key_message)->key_msglen) != 
964         ((struct key_msghdr *)key_message)->key_msglen) {
965       if (errno == ESRCH) {
966         warnx("delete: security association not found");
967         return 0;
968       } else {
969         warn("delete");
970         return -1;
971       }
972     }
973     read(keysock, key_message, sizeof(key_message));
974     return (0);
975
976   case KEYCMD_GET:
977     ((struct key_msghdr *)key_message)->key_msgtype = KEY_GET;
978     ((struct key_msghdr *)key_message)->key_seq = seqno = keygetseqno++;
979     
980     if (write(keysock, key_message, 
981               ((struct key_msghdr *)key_message)->key_msglen) != 
982         ((struct key_msghdr *)key_message)->key_msglen) {
983       if (errno == ESRCH) {
984         warnx("get: security association not found");
985         return 0;
986       } else {
987         warn("get");
988         return (-1);
989       } /* endif ESRCH */
990     } /* endif write() */
991
992     {
993       int len;
994       struct key_msgdata keymsgdata;
995
996       len = sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3 
997                  + MAX_KEY_SZ + MAX_IV_SZ;
998
999 readmesg:
1000       if (read(keysock, key_message, len) < 0) {
1001         warn("read");
1002         return -1;
1003       }
1004
1005       if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1006             && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_GET)
1007             && (((struct key_msghdr *)&key_message)->key_seq==seqno))) {
1008         fprintf(stderr, ".");
1009         goto readmesg;
1010       }
1011
1012       if (((struct key_msghdr *)&key_message)->key_errno != 0) {
1013         printf("Error:  kernel reporting errno=%d\n",
1014                ((struct key_msghdr *)&key_message)->key_errno);
1015         return 0;
1016       }
1017
1018       if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1019         printf("get: can't parse reply\n");
1020         return -1;
1021       }
1022       printf("\n");
1023       printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1024     }
1025     return (0);
1026
1027   case KEYCMD_FLUSH:
1028     ((struct key_msghdr *)key_message)->key_msgtype = KEY_FLUSH;
1029     if (write(keysock, key_message, 
1030               ((struct key_msghdr *)key_message)->key_msglen) != 
1031         ((struct key_msghdr *)key_message)->key_msglen) {
1032       warn("write");
1033       return -1;
1034     }
1035     read(keysock, key_message, sizeof(key_message));
1036     return (0);
1037
1038   case KEYCMD_HELP:
1039     return help((argc > 1) ? argv[1] : NULL);
1040
1041   case KEYCMD_SHELL:
1042     if (argc > 1) {
1043       char buffer[1024], *ap, *ep, *c;
1044       int i;
1045
1046       ep = buffer + sizeof(buffer) - 1;
1047       for (i = 1, ap = buffer; (i < argc) && (ap < ep); i++) {
1048         c = argv[i];
1049         while ((*(ap++) = *(c++)) && (ap < ep));
1050         *(ap - 1) = ' ';
1051       }
1052       *(ap - 1) = 0;
1053       system(buffer);
1054     } else {
1055       char *c = getenv("SHELL");
1056       if (!c)
1057         c = "/bin/sh";
1058       system(c);
1059     }
1060     return 0;
1061
1062   case KEYCMD_EXIT:
1063     exit(0);
1064
1065   case KEYCMD_LOAD:
1066     if (argc != 2)
1067       return 1;
1068     return load(argv[1]);
1069
1070   case KEYCMD_SAVE:  
1071     if (argc != 2)
1072       return 1;
1073     if (!strcmp(argv[1], "-")) 
1074       fp = stdout;
1075     else if ((fd = open(argv[1], O_CREAT | O_RDWR | O_EXCL, 
1076                         S_IRUSR | S_IWUSR)) < 0) {
1077       warn("open");
1078       return 1;
1079     } else if (!(fp = fdopen(fd, "w"))) {
1080       warn("fdopen");
1081       return 1;
1082     }
1083
1084   case KEYCMD_DUMP:
1085     ((struct key_msghdr *)key_message)->key_msgtype = KEY_DUMP;
1086     if (write(keysock, key_message, 
1087               ((struct key_msghdr *)key_message)->key_msglen) != 
1088         ((struct key_msghdr *)key_message)->key_msglen) {
1089       warn("write");
1090       return -1;
1091     }
1092
1093     {
1094       struct key_msgdata keymsgdata;
1095
1096 readmesg2:
1097       if (read(keysock, key_message, sizeof(key_message)) < 0) {
1098         warn("read");
1099         return -1;
1100       }
1101
1102       if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1103             && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_DUMP))) 
1104         goto readmesg2;
1105
1106       /*
1107        *  Kernel is done sending secassoc if key_seq == 0
1108        */
1109       if (((struct key_msghdr *)&key_message)->key_seq == 0) {
1110         if ((keycmds[i].num == KEYCMD_SAVE) && (fp != stdout)) 
1111           fclose(fp);
1112         return 0;
1113       }
1114
1115       if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1116         printf("get: can't parse reply\n");
1117         goto readmesg2;
1118       }
1119       if (keycmds[i].num == KEYCMD_SAVE) {
1120         char *keytype, *algorithm;
1121         
1122         keytype = parsenumtoname(keytypes, 
1123                  ((struct key_msghdr *)&key_message)->type); 
1124
1125         algorithm = parsenumtoname(algorithmtabs[parsenumtoflag(keytypes, 
1126                         ((struct key_msghdr *)&key_message)->type)],
1127                         ((struct key_msghdr *)&key_message)->algorithm);
1128
1129         fprintf(fp, "%s %u ", keytype, 
1130                 ((struct key_msghdr *)&key_message)->spi);
1131         printsockaddr(fp, (struct sockaddr *)(keymsgdata.src));
1132         fprintf(fp, " ");
1133         printsockaddr(fp, (struct sockaddr *)(keymsgdata.dst));
1134         fprintf(fp, " ");
1135         fprintf(fp, "%s ", algorithm);
1136         printkeyiv(fp, keymsgdata.key, keymsgdata.keylen);
1137         fprintf(fp, " ");
1138         printkeyiv(fp, keymsgdata.iv, keymsgdata.ivlen);
1139         fprintf(fp, "\n");
1140       } else 
1141         printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1142       goto readmesg2;
1143     }
1144     return (0);
1145   }
1146   return (-1);
1147 }
1148
1149 /*----------------------------------------------------------------------
1150   main:
1151
1152 ----------------------------------------------------------------------*/
1153 int main(argc, argv)
1154      int argc;
1155      char *argv[];
1156 {
1157   int i, j;
1158   u_long rcvsize;
1159
1160   if (getuid())
1161     errx(1, "this program is intended for the superuser only");
1162
1163   if (!(keysock = socket(PF_KEY, SOCK_RAW, 0))) {
1164     warn("socket");
1165     return -1;
1166   }
1167
1168   for (rcvsize = MAXRCVBUFSIZE; rcvsize; rcvsize -= 1024) {
1169     if (setsockopt(keysock, SOL_SOCKET, SO_RCVBUF, &rcvsize, 
1170                    sizeof(rcvsize)) <= 0)
1171       break;
1172   }
1173
1174   mypid = getpid();
1175   if (mypid < 0) {
1176     warn("getpid");
1177     return -1;
1178   }
1179
1180   if (argc > 1) {
1181     /*
1182      * Attempt to do a single command, based on command line arguments.
1183      */
1184     if (strcasecmp(argv[1], "add") == 0)
1185         errx(1, "cannot add keys from the command line. RTFM for why");
1186     if ((i = docmd(argc - 1, &(argv[1])))) {
1187       if (i > 0) {
1188         for (j = 0; keycmds[j].name; j++)
1189           if (!strcasecmp(keycmds[j].name, argv[1]))
1190             break;
1191
1192         if (keycmds[j].name) {
1193           fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1194                   keycmds[j].usage ? " " : "",
1195                   keycmds[j].usage ? keycmds[j].usage : "");
1196           exit(1);
1197         }
1198       }
1199       usage();
1200     }
1201     return 0;
1202   }
1203
1204   {
1205     char buffer[1024];
1206     char *iargv[KEYCMD_ARG_MAX];
1207     int iargc;
1208
1209     while(1) {
1210       printf("key> ");
1211       if (!(fgets(buffer, sizeof(buffer), stdin)))
1212         return -1;
1213       buffer[sizeof(buffer)-1] = 0;
1214       /*
1215        * get command line, and parse into an argc/argv form.
1216        */
1217       if ((i = parsecmdline(buffer, iargv, &iargc)) < 0)
1218         exit(1);
1219       if (i > 0)
1220         continue;
1221       errno = 0;
1222       /*
1223        * given argc/argv, process argument as if it came from the command
1224        * line.
1225        */
1226       if ((i = docmd(iargc, iargv))) {
1227         if (i > 0) {
1228           for (j = 0; keycmds[j].name; j++)
1229             if (!strcasecmp(keycmds[j].name, iargv[0]))
1230               break;
1231           
1232           if (keycmds[j].name) {
1233             fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1234                     keycmds[j].usage ? " " : "",
1235                     keycmds[j].usage ? keycmds[j].usage : "");
1236           } else
1237             i = -1;
1238         }
1239         if (i < 0) {
1240           if (errno)
1241             warn("system error");
1242           else
1243             warnx("unrecognized command");
1244           warnx("type 'help' if you need help");
1245         };
1246       };
1247     };
1248   };
1249 }
1250
1251 /* EOF */