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