Remove PCVT kernel part and mop up.
[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.3 2003/11/03 19:31:37 eirikn 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 help(cmdname)
276      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()
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 parsekey(key, keylen, arg)
320      u_int8_t *key;
321      u_int8_t *keylen;
322      char *arg;
323 {
324   int i, j, k, l;
325   u_int8_t thisbyte;
326
327   i = strlen(arg);
328
329   if ((i == 1) && (arg[0] == '0')) {
330     *keylen = 0;
331     return 0;
332   }
333     
334   if ((i % 2)) {
335     printf("Invalid number \"%s\"\n", arg);
336     return -1;
337   }
338
339   j = 1;
340   k = l = thisbyte = 0;
341
342   while(arg[k]) {
343     if ((arg[k] >= '0') && (arg[k] <= '9'))
344       thisbyte |= arg[k] - '0';
345     else
346       if ((arg[k] >= 'a') && (arg[k] <= 'f'))
347         thisbyte |= arg[k] - 'a' + 10;
348       else
349         if ((arg[k] >= 'A') && (arg[k] <= 'F'))
350           thisbyte |= arg[k] - 'A' + 10;
351         else {
352           printf("Invalid hex number \"%s\"\n", arg);
353           return 1;
354         }
355
356     if (!(j % 2)) 
357       key[l++] = thisbyte;
358
359     thisbyte = (thisbyte << 4);
360     j++;
361     k++;
362   }
363
364   *keylen = l;
365
366   return 0;
367 }
368
369 /*----------------------------------------------------------------------
370   parsenametonum:   converts command-line name into index number.
371
372 ----------------------------------------------------------------------*/
373 int parsenametonum(tab, arg)
374      struct nametonum *tab;
375      char *arg;
376 {
377   int i;
378
379   for (i = 0; tab[i].name; i++)
380     if (!strcasecmp(tab[i].name, arg))
381       return i;
382
383   if (!tab[i].name)
384     return -1;
385 }
386
387 /*----------------------------------------------------------------------
388   parsesockaddr:  Convert hostname arg into an appropriate sockaddr.
389
390 ----------------------------------------------------------------------*/
391 int parsesockaddr(sockaddr, arg)
392      struct sockaddr *sockaddr;
393      char *arg;
394 {
395   struct hostent *hostent;
396   struct in_addr in_addr, *in_addrp;
397 #ifdef INET6
398   struct in_addr6 in_addr6, *in_addr6p;
399 #endif /* INET6 */
400
401   if ((hostent = hostname2addr(arg, AF_INET, 0)))
402     if ((hostent->h_addrtype == AF_INET) && 
403         (hostent->h_length == sizeof(struct in_addr))) {
404       in_addrp = ((struct in_addr *)hostent->h_addr_list[0]);
405       goto fillin4;
406     }
407   
408   if (ascii2addr(AF_INET, arg, (char *)&in_addr) == 
409       sizeof(struct in_addr)) {
410     in_addrp = &in_addr;
411     goto fillin4;
412   }
413
414 #ifdef INET6
415   if (hostent = hostname2addr(arg, AF_INET6))
416     if ((hostent->h_addrtype == AF_INET6) && 
417         (hostent->h_length == sizeof(struct in_addr6))) {
418       in_addr6p = ((struct in_addr6 *)hostent->h_addr_list[0]);
419       goto fillin6;
420     }
421   
422   if (ascii2addr(AF_INET6, arg, (char *)&in_addr6)
423       == sizeof(struct in_addr6)) {
424     in_addr6p = &in_addr6;
425     goto fillin6;
426   }
427 #endif /* INET6 */
428
429   warnx("unknown host \"%s\"", arg);
430   return 1;
431
432  fillin4:
433   bzero(sockaddr, sizeof(struct sockaddr_in));
434   sockaddr->sa_len = sizeof(struct sockaddr_in);
435   sockaddr->sa_family = AF_INET;
436   ((struct sockaddr_in *)sockaddr)->sin_addr = *in_addrp;
437   return 0;
438
439 #ifdef INET6
440  fillin6:
441   bzero(sockaddr, sizeof(struct sockaddr_in6));
442   sockaddr->sa_len = sizeof(struct sockaddr_in6);
443   sockaddr->sa_family = AF_INET6;
444   ((struct sockaddr_in6 *)sockaddr)->sin6_addr = *in_addr6p;
445   return 0;
446 #endif /* INET6 */
447 }
448
449 /*----------------------------------------------------------------------
450   dummyfromaddr:  Creates a zeroed sockaddr of family af.
451
452 ----------------------------------------------------------------------*/
453 void dummyfromaddr(sa, af)
454      struct sockaddr *sa;
455      int af;
456 {
457   int size;
458 #ifdef INET6
459   size = (af == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
460 #else /* INET6 */
461   size = sizeof(struct sockaddr_in);
462 #endif /* INET6 */
463   bzero((char *)sa, size);
464   sa->sa_family = af;
465   sa->sa_len = size;
466 }
467
468 /* 
469  * Macros to ensure word alignment.
470  */
471 #define ROUNDUP(a) \
472   ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
473 #define ADVANCE(x, n) \
474   { x += ROUNDUP(n); }
475
476
477 /*----------------------------------------------------------------------
478   parse4:  parse keytype, spi, src addr, and dest addr from argv (command line)
479            and stick in structure pointed to by key_messageptr.
480 ----------------------------------------------------------------------*/
481 int parse4(argc, argv)
482      int argc;
483      char *argv[];
484 {
485   int i;
486
487   if (argc < 4)
488     return 1;
489
490   if ((i = parsenametonum(keytypes, argv[0])) < 0)
491     return i;
492
493   ((struct key_msghdr *)key_message)->type = keytypes[i].num;
494
495   /* Should we zero check? */
496   ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
497
498   if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
499     return 1;
500   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
501                                                key_messageptr))->sa_len);
502   
503   if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
504     return 1;
505   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
506                                                key_messageptr))->sa_len);
507
508   /*
509    *  We need to put a dummy from address since the kernel expects
510    *  this to be in the message.
511    */
512 #ifdef INET6
513   dummyfromaddr(key_message + key_messageptr, AF_INET6);
514 #else /* INET6 */
515   dummyfromaddr(key_message + key_messageptr, AF_INET);
516 #endif /* INET6 */
517   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
518                                                key_messageptr))->sa_len);
519
520   return 0;
521 }
522
523 /*----------------------------------------------------------------------
524   parse7:  parse keytype, spi, src addr, dest addr, alg type, key, and iv
525            from argv (command line)
526            and stick in structure pointed to by key_messageptr.
527 ----------------------------------------------------------------------*/
528 int parse7(argc, argv)
529      int argc;
530      char *argv[];
531 {
532   int i, j;
533
534   if (argc < 6)
535     return 1;
536
537   if ((i = parsenametonum(keytypes, argv[0])) < 0)
538     return i;
539
540   ((struct key_msghdr *)key_message)->type = keytypes[i].num;
541
542 /* Should we zero check? */
543   ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
544
545   if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
546     return 1;
547   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
548                                                key_messageptr))->sa_len);
549
550   if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
551     return 1;
552   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
553                                                key_messageptr))->sa_len);
554
555   /*
556    *  We need to put a dummy from address since the kernel expects
557    *  this to be in the message.
558    */
559 #ifdef INET6
560   dummyfromaddr(key_message + key_messageptr, AF_INET6);
561 #else /* INET6 */
562   dummyfromaddr(key_message + key_messageptr, AF_INET);
563 #endif /* INET6 */
564   ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
565                                                key_messageptr))->sa_len);  
566
567   if ((j = parsenametonum(algorithmtabs[keytypes[i].flags], argv[4])) < 0)
568     return j;
569
570   ((struct key_msghdr *)key_message)->algorithm =
571         algorithmtabs[keytypes[i].flags][j].num;
572
573   if ((argc < 7) && algorithmtabs[keytypes[i].flags][j].flags)
574     return 1;
575
576   if (parsekey(key_message + key_messageptr, 
577            &(((struct key_msghdr *)key_message)->keylen), argv[5]) != 0)
578     return 1;
579   ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->keylen);  
580
581   if (argc >= 7) {
582     if (parsekey(key_message + key_messageptr,
583              &(((struct key_msghdr *)key_message)->ivlen), argv[6]) != 0)
584       return 1;
585     ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->ivlen);
586   }
587
588   return 0;
589 }
590
591 /*----------------------------------------------------------------------
592   parsecmdline:
593
594 ----------------------------------------------------------------------*/
595 int parsecmdline(buffer, argv, argc)
596      char *buffer;
597      char **argv;
598      int *argc;
599 {
600   int i = 0, iargc = 0;
601   char *head;
602
603   head = buffer;
604
605   while(buffer[i] && (iargc < KEYCMD_ARG_MAX)) {
606     if ((buffer[i] == '\n') || (buffer[i] == '#')) {
607       buffer[i] = 0;
608       if (*head)
609         argv[iargc++] = head;
610       break;
611     }
612     if ((buffer[i] == ' ') || (buffer[i] == '\t')) {
613       buffer[i] = 0;
614       if (*head)
615         argv[iargc++] = head;
616       head = &(buffer[++i]);
617     } else
618       i++;
619   };
620   argv[iargc] = NULL;
621   *argc = iargc;
622
623   return iargc ? 0 : 1;
624 }
625
626
627 /*----------------------------------------------------------------------
628   load:   load keys from file filename into Key Engine.
629
630 ----------------------------------------------------------------------*/
631 int load(filename)
632      char *filename;
633 {
634   FILE *fh;
635   char buffer[1024], *buf, *largv[KEYCMD_ARG_MAX], *c;
636   int i, largc, left, line = 0;
637
638   if (strcmp(filename, "-")) {
639     if (!(fh = fopen(filename, "r")))
640       return -1;
641   } else
642     fh = stdin;
643
644   largv[0] = "add";
645
646   buf = buffer;
647   left = sizeof(buffer);
648
649   while(fgets(buf, left, fh)) {
650     line++;
651     if ((c = strchr(buffer, '\\'))) {
652       left = (sizeof(buffer) - 1) - (--c - buffer);
653       buf = c;
654     } else {
655       buffer[sizeof(buffer)-1] = 0;
656
657       if ((i = parsecmdline(buffer, &(largv[1]), &largc)) < 0)
658         return i;
659
660       if (!i) {
661         if ((i = docmd(++largc, largv))) {
662           if (i > 0) {
663             warnx("parse error on line %d of %s", line, filename);
664             return 0;
665           }
666           return i;
667         }
668       }
669
670       buf = buffer;
671       left = sizeof(buffer);
672     }
673   };
674
675   return 0;
676 }
677
678 /*----------------------------------------------------------------------
679   parsedata:
680
681 ----------------------------------------------------------------------*/
682 int
683 parsedata(km, kip)
684      struct key_msghdr *km;
685      struct key_msgdata *kip;
686 {
687   char *cp, *cpmax;
688  
689   if (!km)
690     return (-1);
691   if (!(km->key_msglen))
692     return (-1);
693  
694   cp = (caddr_t)(km + 1);
695   cpmax = (caddr_t)km + km->key_msglen;
696  
697 #define NEXTDATA(x, n) \
698     { x += ROUNDUP(n); if (cp >= cpmax) { \
699     warnx("kernel returned a truncated message!"); return(-1); } }
700  
701   /* Grab src addr */
702   kip->src = (struct sockaddr *)cp;
703   if (!kip->src->sa_len)
704     return(-1);
705  
706   NEXTDATA(cp, kip->src->sa_len);
707  
708   /* Grab dest addr */
709   kip->dst = (struct sockaddr *)cp;
710   if (!kip->dst->sa_len)
711      return(-1);
712  
713   NEXTDATA(cp, kip->dst->sa_len);
714  
715   /* Grab from addr */
716   kip->from = (struct sockaddr *)cp;
717   if (!kip->from->sa_len)
718     return(-1);
719  
720   NEXTDATA(cp, kip->from->sa_len);
721  
722   /* Grab key */
723   if (kip->keylen = km->keylen) {
724     kip->key = cp;
725     NEXTDATA(cp, km->keylen);
726   }
727  
728   /* Grab iv */
729   if (kip->ivlen = km->ivlen)
730     kip->iv = cp;
731
732   cp += kip->ivlen;
733
734   printf("key: parsedata: difference=%d\n", cp - cpmax);
735   return (0);
736 }
737
738
739 /*----------------------------------------------------------------------
740   printkeyiv:
741
742 ----------------------------------------------------------------------*/
743 void printkeyiv(fp, cp, len)
744      FILE *fp;
745      caddr_t cp;
746      int len;
747 {
748   int i;
749   for (i=0; i<len; i++)
750     fprintf(fp, "%02x", (u_int8_t)*(cp+i));
751 }
752
753 /*----------------------------------------------------------------------
754   printsockaddr:
755
756 ----------------------------------------------------------------------*/
757 void printsockaddr(fp, sa)
758      FILE *fp;
759      struct sockaddr *sa;
760 {
761   struct hostent *hp;
762   char *addrp;
763   int len;
764
765 #ifdef INET6
766   if (sa->sa_family == AF_INET6) {
767     len = sizeof(struct in_addr6); 
768     addrp = (char *)&(((struct sockaddr_in6 *)sa)->sin6_addr);
769   } else {
770 #endif /* INET6 */
771     len = sizeof(struct in_addr);
772     addrp = (char *)&(((struct sockaddr_in *)sa)->sin_addr);
773 #ifdef INET6
774   }
775 #endif /* INET6 */
776
777   if((hp = addr2hostname(addrp, len, sa->sa_family, 0)) != NULL)
778     fprintf(fp, "%s", hp->h_name);
779   else
780     fprintf(fp, "%s", addr2ascii(sa->sa_family, addrp, len, NULL));
781 }
782
783 /*----------------------------------------------------------------------
784   parsenumtoname:
785
786 ----------------------------------------------------------------------*/
787 char *
788 parsenumtoname(tab, num)
789      struct nametonum *tab;
790      int num;
791 {
792   int i;
793   for (i = 0; tab[i].name; i++) {
794     if (num == tab[i].num)
795       return(tab[i].name);
796   }
797   return(0);
798 }
799
800 /*----------------------------------------------------------------------
801   parsenumtoflag:
802
803 ----------------------------------------------------------------------*/
804 int
805 parsenumtoflag(tab, num)
806      struct nametonum *tab;
807      int num;
808 {
809   int i;
810   for (i = 0; tab[i].name; i++) {
811     if (num == tab[i].num)
812       return(tab[i].flags);
813   }
814   return(-1);
815 }
816
817
818 /*----------------------------------------------------------------------
819   printkeymsg:
820
821 ----------------------------------------------------------------------*/
822 void printkeymsg(kmp, kdp)
823      struct key_msghdr *kmp;
824      struct key_msgdata *kdp;
825 {
826
827   printf("type=%d(%s) ",kmp->type, parsenumtoname(keytypes, kmp->type)); 
828   printf("spi=%u ", kmp->spi);
829   printf("alogrithm=%u(%s) ", kmp->algorithm,
830          parsenumtoname(algorithmtabs[parsenumtoflag(keytypes, kmp->type)],
831                         kmp->algorithm));
832   printf("state=0x%x ",kmp->state); 
833
834   if (kmp->state != 0) {
835     if (kmp->state & K_USED)
836       printf("USED ");
837     if (kmp->state & K_UNIQUE)
838       printf("UNIQUE ");    
839     if (kmp->state & K_LARVAL)
840       printf("LARVAL ");
841     if (kmp->state & K_ZOMBIE)
842       printf("ZOMBIE ");
843     if (kmp->state & K_DEAD)
844       printf("DEAD ");
845     if (kmp->state & K_INBOUND)
846       printf("INBOUND ");
847     if (kmp->state & K_OUTBOUND)
848       printf("OUTBOUND");
849   }
850   printf("\n");
851   printf("sensitivity_label=%d ",kmp->label);
852   printf("lifetype=%d ",kmp->lifetype);
853   printf("lifetime1=%d ",kmp->lifetime1);
854   printf("lifetime2=%d\n",kmp->lifetime2);
855   printf("key (len=%d):\t",kdp->keylen);
856   printkeyiv(stdout, kdp->key, kdp->keylen);
857   printf("\n");
858   printf("iv (len=%d):\t", kdp->ivlen);
859   printkeyiv(stdout, kdp->iv, kdp->ivlen);
860   printf("\n");
861   printf("src:\t");
862   printsockaddr(stdout, (struct sockaddr *)kdp->src);
863   printf("\n");
864   printf("dst:\t");
865   printsockaddr(stdout, (struct sockaddr *)kdp->dst);
866   printf("\n");
867 /*  printf("from:\t");
868   printsockaddr(stdout, (struct sockaddr *)kdp->from); */
869   printf("\n");
870 }
871
872 /*----------------------------------------------------------------------
873   docmd:
874
875 ----------------------------------------------------------------------*/
876 int docmd(argc, argv)
877      int argc;
878      char **argv;
879 {
880   int i, j, seqno;
881   int fd;
882   FILE *fp;
883
884   if (!argv[0] || !argc)
885     return -1;
886
887   if (!argv[0][0])
888     return -1;
889
890   bzero(&key_message, sizeof(key_message));
891   key_messageptr = sizeof(struct key_msghdr);
892
893   for (i = 0; keycmds[i].name; i++)
894     if (!strcasecmp(keycmds[i].name, argv[0]))
895       break;
896
897   if (!keycmds[i].name)
898     return -1;
899
900   if (keycmds[i].parse)
901     if ((j = keycmds[i].parse(argc - 1, &(argv[1]))))
902       return j;
903
904   ((struct key_msghdr *)key_message)->key_msglen = key_messageptr;
905   ((struct key_msghdr *)key_message)->key_msgvers = 1;
906   ((struct key_msghdr *)key_message)->key_seq = 1;
907
908   switch(keycmds[i].num) {
909
910   case KEYCMD_ADD:
911 #ifndef NOSANITYCHK
912     /*
913      * For now, we do sanity check of security association 
914      * information here until we find a better place.
915      */
916     {
917       struct key_msghdr *kmp = (struct key_msghdr *)key_message;
918
919       if ((kmp->type == KEY_TYPE_AH || 
920            kmp->type == KEY_TYPE_ESP) && (kmp->spi < 256)) {
921         warnx("add: spi must be greater than 255");
922         return(0);
923       }
924
925       if (kmp->type == KEY_TYPE_ESP && 
926           (kmp->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC
927 #ifdef IPSEC_ALGTYPE_ESP_3DES
928            || kmp->algorithm == IPSEC_ALGTYPE_ESP_3DES
929 #endif
930            )) {
931         if (kmp->keylen != 8) {
932           warnx("add: key must be 8 bytes");
933           return (0);
934         }
935         if (kmp->ivlen != 4 && kmp->ivlen != 8) {
936           warnx("add: iv must be 4 or 8 bytes");
937           return (0);
938         }
939       }
940
941       if (kmp->type == KEY_TYPE_AH &&
942           kmp->algorithm == IPSEC_ALGTYPE_AUTH_MD5 && kmp->keylen == 0) {
943         warnx("add: no key specified");
944         return (0);
945       }
946     }
947 #endif
948     ((struct key_msghdr *)key_message)->key_msgtype = KEY_ADD;
949     if (write(keysock, key_message, 
950               ((struct key_msghdr *)key_message)->key_msglen) != 
951         ((struct key_msghdr *)key_message)->key_msglen) {
952       if (errno == EEXIST)
953         warnx("add: security association already exists");
954       else
955         warn("add");
956       return -1;
957     }
958     read(keysock, key_message, sizeof(key_message));
959     return (0);
960
961   case KEYCMD_DEL:
962     ((struct key_msghdr *)key_message)->key_msgtype = KEY_DELETE;
963     if (write(keysock, key_message, 
964               ((struct key_msghdr *)key_message)->key_msglen) != 
965         ((struct key_msghdr *)key_message)->key_msglen) {
966       if (errno == ESRCH) {
967         warnx("delete: security association not found");
968         return 0;
969       } else {
970         warn("delete");
971         return -1;
972       }
973     }
974     read(keysock, key_message, sizeof(key_message));
975     return (0);
976
977   case KEYCMD_GET:
978     ((struct key_msghdr *)key_message)->key_msgtype = KEY_GET;
979     ((struct key_msghdr *)key_message)->key_seq = seqno = keygetseqno++;
980     
981     if (write(keysock, key_message, 
982               ((struct key_msghdr *)key_message)->key_msglen) != 
983         ((struct key_msghdr *)key_message)->key_msglen) {
984       if (errno == ESRCH) {
985         warnx("get: security association not found");
986         return 0;
987       } else {
988         warn("get");
989         return (-1);
990       } /* endif ESRCH */
991     } /* endif write() */
992
993     {
994       int len;
995       struct key_msgdata keymsgdata;
996
997       len = sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3 
998                  + MAX_KEY_SZ + MAX_IV_SZ;
999
1000 readmesg:
1001       if (read(keysock, key_message, len) < 0) {
1002         warn("read");
1003         return -1;
1004       }
1005
1006       if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1007             && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_GET)
1008             && (((struct key_msghdr *)&key_message)->key_seq==seqno))) {
1009         fprintf(stderr, ".");
1010         goto readmesg;
1011       }
1012
1013       if (((struct key_msghdr *)&key_message)->key_errno != 0) {
1014         printf("Error:  kernel reporting errno=%d\n",
1015                ((struct key_msghdr *)&key_message)->key_errno);
1016         return 0;
1017       }
1018
1019       if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1020         printf("get: can't parse reply\n");
1021         return -1;
1022       }
1023       printf("\n");
1024       printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1025     }
1026     return (0);
1027
1028   case KEYCMD_FLUSH:
1029     ((struct key_msghdr *)key_message)->key_msgtype = KEY_FLUSH;
1030     if (write(keysock, key_message, 
1031               ((struct key_msghdr *)key_message)->key_msglen) != 
1032         ((struct key_msghdr *)key_message)->key_msglen) {
1033       warn("write");
1034       return -1;
1035     }
1036     read(keysock, key_message, sizeof(key_message));
1037     return (0);
1038
1039   case KEYCMD_HELP:
1040     return help((argc > 1) ? argv[1] : NULL);
1041
1042   case KEYCMD_SHELL:
1043     if (argc > 1) {
1044       char buffer[1024], *ap, *ep, *c;
1045       int i;
1046
1047       ep = buffer + sizeof(buffer) - 1;
1048       for (i = 1, ap = buffer; (i < argc) && (ap < ep); i++) {
1049         c = argv[i];
1050         while ((*(ap++) = *(c++)) && (ap < ep));
1051         *(ap - 1) = ' ';
1052       }
1053       *(ap - 1) = 0;
1054       system(buffer);
1055     } else {
1056       char *c = getenv("SHELL");
1057       if (!c)
1058         c = "/bin/sh";
1059       system(c);
1060     }
1061     return 0;
1062
1063   case KEYCMD_EXIT:
1064     exit(0);
1065
1066   case KEYCMD_LOAD:
1067     if (argc != 2)
1068       return 1;
1069     return load(argv[1]);
1070
1071   case KEYCMD_SAVE:  
1072     if (argc != 2)
1073       return 1;
1074     if (!strcmp(argv[1], "-")) 
1075       fp = stdout;
1076     else if ((fd = open(argv[1], O_CREAT | O_RDWR | O_EXCL, 
1077                         S_IRUSR | S_IWUSR)) < 0) {
1078       warn("open");
1079       return 1;
1080     } else if (!(fp = fdopen(fd, "w"))) {
1081       warn("fdopen");
1082       return 1;
1083     }
1084
1085   case KEYCMD_DUMP:
1086     ((struct key_msghdr *)key_message)->key_msgtype = KEY_DUMP;
1087     if (write(keysock, key_message, 
1088               ((struct key_msghdr *)key_message)->key_msglen) != 
1089         ((struct key_msghdr *)key_message)->key_msglen) {
1090       warn("write");
1091       return -1;
1092     }
1093
1094     {
1095       struct key_msgdata keymsgdata;
1096
1097 readmesg2:
1098       if (read(keysock, key_message, sizeof(key_message)) < 0) {
1099         warn("read");
1100         return -1;
1101       }
1102
1103       if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1104             && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_DUMP))) 
1105         goto readmesg2;
1106
1107       /*
1108        *  Kernel is done sending secassoc if key_seq == 0
1109        */
1110       if (((struct key_msghdr *)&key_message)->key_seq == 0) {
1111         if ((keycmds[i].num == KEYCMD_SAVE) && (fp != stdout)) 
1112           fclose(fp);
1113         return 0;
1114       }
1115
1116       if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1117         printf("get: can't parse reply\n");
1118         goto readmesg2;
1119       }
1120       if (keycmds[i].num == KEYCMD_SAVE) {
1121         char *keytype, *algorithm;
1122         
1123         keytype = parsenumtoname(keytypes, 
1124                  ((struct key_msghdr *)&key_message)->type); 
1125
1126         algorithm = parsenumtoname(algorithmtabs[parsenumtoflag(keytypes, 
1127                         ((struct key_msghdr *)&key_message)->type)],
1128                         ((struct key_msghdr *)&key_message)->algorithm);
1129
1130         fprintf(fp, "%s %u ", keytype, 
1131                 ((struct key_msghdr *)&key_message)->spi);
1132         printsockaddr(fp, (struct sockaddr *)(keymsgdata.src));
1133         fprintf(fp, " ");
1134         printsockaddr(fp, (struct sockaddr *)(keymsgdata.dst));
1135         fprintf(fp, " ");
1136         fprintf(fp, "%s ", algorithm);
1137         printkeyiv(fp, keymsgdata.key, keymsgdata.keylen);
1138         fprintf(fp, " ");
1139         printkeyiv(fp, keymsgdata.iv, keymsgdata.ivlen);
1140         fprintf(fp, "\n");
1141       } else 
1142         printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1143       goto readmesg2;
1144     }
1145     return (0);
1146   }
1147   return (-1);
1148 }
1149
1150 /*----------------------------------------------------------------------
1151   main:
1152
1153 ----------------------------------------------------------------------*/
1154 int main(argc, argv)
1155      int argc;
1156      char *argv[];
1157 {
1158   int i, j;
1159   u_long rcvsize;
1160
1161   if (getuid())
1162     errx(1, "this program is intended for the superuser only");
1163
1164   if (!(keysock = socket(PF_KEY, SOCK_RAW, 0))) {
1165     warn("socket");
1166     return -1;
1167   }
1168
1169   for (rcvsize = MAXRCVBUFSIZE; rcvsize; rcvsize -= 1024) {
1170     if (setsockopt(keysock, SOL_SOCKET, SO_RCVBUF, &rcvsize, 
1171                    sizeof(rcvsize)) <= 0)
1172       break;
1173   }
1174
1175   mypid = getpid();
1176   if (mypid < 0) {
1177     warn("getpid");
1178     return -1;
1179   }
1180
1181   if (argc > 1) {
1182     /*
1183      * Attempt to do a single command, based on command line arguments.
1184      */
1185     if (strcasecmp(argv[1], "add") == 0)
1186         errx(1, "cannot add keys from the command line. RTFM for why");
1187     if ((i = docmd(argc - 1, &(argv[1])))) {
1188       if (i > 0) {
1189         for (j = 0; keycmds[j].name; j++)
1190           if (!strcasecmp(keycmds[j].name, argv[1]))
1191             break;
1192
1193         if (keycmds[j].name) {
1194           fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1195                   keycmds[j].usage ? " " : "",
1196                   keycmds[j].usage ? keycmds[j].usage : "");
1197           exit(1);
1198         }
1199       }
1200       usage();
1201     }
1202     return 0;
1203   }
1204
1205   {
1206     char buffer[1024];
1207     char *iargv[KEYCMD_ARG_MAX];
1208     int iargc;
1209
1210     while(1) {
1211       printf("key> ");
1212       if (!(fgets(buffer, sizeof(buffer), stdin)))
1213         return -1;
1214       buffer[sizeof(buffer)-1] = 0;
1215       /*
1216        * get command line, and parse into an argc/argv form.
1217        */
1218       if ((i = parsecmdline(buffer, iargv, &iargc)) < 0)
1219         exit(1);
1220       if (i > 0)
1221         continue;
1222       errno = 0;
1223       /*
1224        * given argc/argv, process argument as if it came from the command
1225        * line.
1226        */
1227       if ((i = docmd(iargc, iargv))) {
1228         if (i > 0) {
1229           for (j = 0; keycmds[j].name; j++)
1230             if (!strcasecmp(keycmds[j].name, iargv[0]))
1231               break;
1232           
1233           if (keycmds[j].name) {
1234             fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1235                     keycmds[j].usage ? " " : "",
1236                     keycmds[j].usage ? keycmds[j].usage : "");
1237           } else
1238             i = -1;
1239         }
1240         if (i < 0) {
1241           if (errno)
1242             warn("system error");
1243           else
1244             warnx("unrecognized command");
1245           warnx("type 'help' if you need help");
1246         };
1247       };
1248     };
1249   };
1250 }
1251
1252 /* EOF */