Fix some NULL pointer dereferences, most of the in debug code though.
[dragonfly/netmp.git] / usr.sbin / keyadmin / keyadmin.c
blob81ce5ca28a4a40055353559ccf5e214488580631
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.
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
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
21 COPYRIGHT NOTICE
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.
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.
34 NRL LICENSE
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:
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:
48 This product includes software developed at the Information
49 Technology Division, US Naval Research Laboratory.
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.
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.
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).
72 ----------------------------------------------------------------------*/
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 $
79 #include <sys/types.h>
80 #include <sys/stat.h>
81 #include <sys/socket.h>
82 #include <sys/socketvar.h>
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>
93 #include <netinet/in.h>
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 */
103 #ifdef IPSEC
104 #include <netsec/ipsec.h>
105 #endif
106 #include <netkey/key.h>
108 #ifdef INET6
109 #include <netinet6/support.h>
110 #endif
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
117 #include <arpa/inet.h>
119 int parse7(int, char **);
120 int parse4(int, char **);
121 int docmd(int, char **);
123 #define KEYCMD_ARG_MAX 10
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
136 struct nametonum {
137 char *name;
138 int num;
139 int flags;
142 char parse7usage[] = "<type> <spi> <src> <dst> <transform> <key> [iv]";
143 char parse4usage[] = "<type> <spi> <src> <dst>";
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 }
177 /* flags: index into algorithmtabs */
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 }
190 #ifndef IPSEC_ALGTYPE_AUTH_MD5 /* XXX */
191 #define IPSEC_ALGTYPE_AUTH_MD5 1
192 #endif
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 }
206 #ifndef IPSEC_ALGTYPE_ESP_DES_CBC /* XXX */
207 #define IPSEC_ALGTYPE_ESP_DES_CBC 1
208 #endif
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 }
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/*>...?
227 #define RSVP_AUTHTYPE_MD5 1 /* XXX */
228 struct nametonum rsvpalgorithms[] = {
229 { "md5", RSVP_AUTHTYPE_MD5, 0 },
230 { NULL, 0, 0 }
233 #define OSPF_AUTHTYPE_MD5 1 /* XXX */
234 struct nametonum ospfalgorithms[] = {
235 { "md5", OSPF_AUTHTYPE_MD5, 0 },
236 { NULL, 0, 0 }
239 #define RIPV2_AUTHTYPE_MD5 1 /* XXX */
240 struct nametonum ripalgorithms[] = {
241 { "md5", RIPV2_AUTHTYPE_MD5, 0 },
242 { NULL, 0, 0 }
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
256 char buffer[1024] = "\0";
258 #define MAXRCVBUFSIZE 8 * 1024
260 char key_message[sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3
261 + MAX_KEY_SZ + MAX_IV_SZ];
262 int key_messageptr;
264 int keysock = -1;
266 int keygetseqno = 1;
267 int keydumpseqno = 1;
268 pid_t mypid;
271 /*----------------------------------------------------------------------
272 help: Print appropriate help message on stdout.
274 ----------------------------------------------------------------------*/
276 help(char *cmdname)
278 int i;
280 if (cmdname) {
281 for (i = 0; keycmds[i].name; i++)
282 if (!strcasecmp(keycmds[i].name, cmdname))
283 break;
285 if (!keycmds[i].name) {
286 warnx("unknown command: %s", cmdname);
287 return 0;
290 printf("%s%s%s\n", keycmds[i].name, keycmds[i].usage ? " " : "",
291 keycmds[i].usage ? keycmds[i].usage : "");
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 : "");
301 return 0;
304 /*----------------------------------------------------------------------
305 usage: print suitable usage message on stdout.
307 ----------------------------------------------------------------------*/
308 static void
309 usage(void)
312 fprintf(stderr, "usage: keyadmin <command> <args>\n");
315 /*----------------------------------------------------------------------
316 parsekey: parse argument into a binary key and also record
317 the length of the resulting key.
318 ----------------------------------------------------------------------*/
320 parsekey(u_int8_t *key, u_int8_t *keylen, char *arg)
322 int i, j, k, l;
323 u_int8_t thisbyte;
325 i = strlen(arg);
327 if ((i == 1) && (arg[0] == '0')) {
328 *keylen = 0;
329 return 0;
332 if ((i % 2)) {
333 printf("Invalid number \"%s\"\n", arg);
334 return -1;
337 j = 1;
338 k = l = thisbyte = 0;
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;
354 if (!(j % 2))
355 key[l++] = thisbyte;
357 thisbyte = (thisbyte << 4);
358 j++;
359 k++;
362 *keylen = l;
364 return 0;
367 /*----------------------------------------------------------------------
368 parsenametonum: converts command-line name into index number.
370 ----------------------------------------------------------------------*/
372 parsenametonum(struct nametonum *tab, char *arg)
374 int i;
376 for (i = 0; tab[i].name; i++)
377 if (!strcasecmp(tab[i].name, arg))
378 return i;
380 if (!tab[i].name)
381 return -1;
384 /*----------------------------------------------------------------------
385 parsesockaddr: Convert hostname arg into an appropriate sockaddr.
387 ----------------------------------------------------------------------*/
389 parsesockaddr(struct sockaddr *sockaddr, char *arg)
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 */
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;
404 if (ascii2addr(AF_INET, arg, (char *)&in_addr) ==
405 sizeof(struct in_addr)) {
406 in_addrp = &in_addr;
407 goto fillin4;
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;
418 if (ascii2addr(AF_INET6, arg, (char *)&in_addr6)
419 == sizeof(struct in_addr6)) {
420 in_addr6p = &in_addr6;
421 goto fillin6;
423 #endif /* INET6 */
425 warnx("unknown host \"%s\"", arg);
426 return 1;
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;
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 */
445 /*----------------------------------------------------------------------
446 dummyfromaddr: Creates a zeroed sockaddr of family af.
448 ----------------------------------------------------------------------*/
449 void
450 dummyfromaddr(struct sockaddr *sa, int af)
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;
464 * Macros to ensure word alignment.
466 #define ROUNDUP(a) \
467 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
468 #define ADVANCE(x, n) \
469 { x += ROUNDUP(n); }
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 ----------------------------------------------------------------------*/
477 parse4(int argc, char *argv[])
479 int i;
481 if (argc < 4)
482 return 1;
484 if ((i = parsenametonum(keytypes, argv[0])) < 0)
485 return i;
487 ((struct key_msghdr *)key_message)->type = keytypes[i].num;
489 /* Should we zero check? */
490 ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
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);
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);
503 * We need to put a dummy from address since the kernel expects
504 * this to be in the message.
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);
514 return 0;
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 ----------------------------------------------------------------------*/
523 parse7(int argc, char *argv[])
525 int i, j;
527 if (argc < 6)
528 return 1;
530 if ((i = parsenametonum(keytypes, argv[0])) < 0)
531 return i;
533 ((struct key_msghdr *)key_message)->type = keytypes[i].num;
535 /* Should we zero check? */
536 ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
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);
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);
549 * We need to put a dummy from address since the kernel expects
550 * this to be in the message.
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);
560 if ((j = parsenametonum(algorithmtabs[keytypes[i].flags], argv[4])) < 0)
561 return j;
563 ((struct key_msghdr *)key_message)->algorithm =
564 algorithmtabs[keytypes[i].flags][j].num;
566 if ((argc < 7) && algorithmtabs[keytypes[i].flags][j].flags)
567 return 1;
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);
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);
581 return 0;
584 /*----------------------------------------------------------------------
585 parsecmdline:
587 ----------------------------------------------------------------------*/
589 parsecmdline(char *buffer, char **argv, int *argc)
591 int i = 0, iargc = 0;
592 char *head;
594 head = buffer;
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;
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++;
611 argv[iargc] = NULL;
612 *argc = iargc;
614 return iargc ? 0 : 1;
618 /*----------------------------------------------------------------------
619 load: load keys from file filename into Key Engine.
621 ----------------------------------------------------------------------*/
623 load(char *filename)
625 FILE *fh;
626 char buffer[1024], *buf, *largv[KEYCMD_ARG_MAX], *c;
627 int i, largc, left, line = 0;
629 if (strcmp(filename, "-")) {
630 if (!(fh = fopen(filename, "r")))
631 return -1;
632 } else
633 fh = stdin;
635 largv[0] = "add";
637 buf = buffer;
638 left = sizeof(buffer);
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;
648 if ((i = parsecmdline(buffer, &(largv[1]), &largc)) < 0)
649 return i;
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;
657 return i;
661 buf = buffer;
662 left = sizeof(buffer);
666 return 0;
669 /*----------------------------------------------------------------------
670 parsedata:
672 ----------------------------------------------------------------------*/
674 parsedata(struct key_msghdr *km, struct key_msgdata *kip)
676 char *cp, *cpmax;
678 if (!km)
679 return (-1);
680 if (!(km->key_msglen))
681 return (-1);
683 cp = (caddr_t)(km + 1);
684 cpmax = (caddr_t)km + km->key_msglen;
686 #define NEXTDATA(x, n) \
687 { x += ROUNDUP(n); if (cp >= cpmax) { \
688 warnx("kernel returned a truncated message!"); return(-1); } }
690 /* Grab src addr */
691 kip->src = (struct sockaddr *)cp;
692 if (!kip->src->sa_len)
693 return(-1);
695 NEXTDATA(cp, kip->src->sa_len);
697 /* Grab dest addr */
698 kip->dst = (struct sockaddr *)cp;
699 if (!kip->dst->sa_len)
700 return(-1);
702 NEXTDATA(cp, kip->dst->sa_len);
704 /* Grab from addr */
705 kip->from = (struct sockaddr *)cp;
706 if (!kip->from->sa_len)
707 return(-1);
709 NEXTDATA(cp, kip->from->sa_len);
711 /* Grab key */
712 if (kip->keylen = km->keylen) {
713 kip->key = cp;
714 NEXTDATA(cp, km->keylen);
717 /* Grab iv */
718 if (kip->ivlen = km->ivlen)
719 kip->iv = cp;
721 cp += kip->ivlen;
723 printf("key: parsedata: difference=%d\n", cp - cpmax);
724 return (0);
728 /*----------------------------------------------------------------------
729 printkeyiv:
731 ----------------------------------------------------------------------*/
732 void
733 printkeyiv(FILE *fp, caddr_t cp, int len)
735 int i;
736 for (i=0; i<len; i++)
737 fprintf(fp, "%02x", (u_int8_t)*(cp+i));
740 /*----------------------------------------------------------------------
741 printsockaddr:
743 ----------------------------------------------------------------------*/
744 void
745 printsockaddr(FILE *fp, struct sockaddr *sa)
747 struct hostent *hp;
748 char *addrp;
749 int len;
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
761 #endif /* INET6 */
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));
769 /*----------------------------------------------------------------------
770 parsenumtoname:
772 ----------------------------------------------------------------------*/
773 char *
774 parsenumtoname(struct nametonum *tab, int num)
776 int i;
777 for (i = 0; tab[i].name; i++) {
778 if (num == tab[i].num)
779 return(tab[i].name);
781 return(0);
784 /*----------------------------------------------------------------------
785 parsenumtoflag:
787 ----------------------------------------------------------------------*/
789 parsenumtoflag(struct nametonum *tab, int num)
791 int i;
792 for (i = 0; tab[i].name; i++) {
793 if (num == tab[i].num)
794 return(tab[i].flags);
796 return(-1);
800 /*----------------------------------------------------------------------
801 printkeymsg:
803 ----------------------------------------------------------------------*/
804 void
805 printkeymsg(struct key_msghdr *kmp, struct key_msgdata *kdp)
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);
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");
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");
853 /*----------------------------------------------------------------------
854 docmd:
856 ----------------------------------------------------------------------*/
858 docmd(int argc, char **argv)
860 int i, j, seqno;
861 int fd;
862 FILE *fp;
864 if (!argv[0] || !argc)
865 return -1;
867 if (!argv[0][0])
868 return -1;
870 bzero(&key_message, sizeof(key_message));
871 key_messageptr = sizeof(struct key_msghdr);
873 for (i = 0; keycmds[i].name; i++)
874 if (!strcasecmp(keycmds[i].name, argv[0]))
875 break;
877 if (!keycmds[i].name)
878 return -1;
880 if (keycmds[i].parse)
881 if ((j = keycmds[i].parse(argc - 1, &(argv[1]))))
882 return j;
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;
888 switch(keycmds[i].num) {
890 case KEYCMD_ADD:
891 #ifndef NOSANITYCHK
893 * For now, we do sanity check of security association
894 * information here until we find a better place.
897 struct key_msghdr *kmp = (struct key_msghdr *)key_message;
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);
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);
915 if (kmp->ivlen != 4 && kmp->ivlen != 8) {
916 warnx("add: iv must be 4 or 8 bytes");
917 return (0);
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);
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;
938 read(keysock, key_message, sizeof(key_message));
939 return (0);
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;
954 read(keysock, key_message, sizeof(key_message));
955 return (0);
957 case KEYCMD_GET:
958 ((struct key_msghdr *)key_message)->key_msgtype = KEY_GET;
959 ((struct key_msghdr *)key_message)->key_seq = seqno = keygetseqno++;
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() */
974 int len;
975 struct key_msgdata keymsgdata;
977 len = sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3
978 + MAX_KEY_SZ + MAX_IV_SZ;
980 readmesg:
981 if (read(keysock, key_message, len) < 0) {
982 warn("read");
983 return -1;
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;
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;
999 if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1000 printf("get: can't parse reply\n");
1001 return -1;
1003 printf("\n");
1004 printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1006 return (0);
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;
1016 read(keysock, key_message, sizeof(key_message));
1017 return (0);
1019 case KEYCMD_HELP:
1020 return help((argc > 1) ? argv[1] : NULL);
1022 case KEYCMD_SHELL:
1023 if (argc > 1) {
1024 char buffer[1024], *ap, *ep, *c;
1025 int i;
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) = ' ';
1033 *(ap - 1) = 0;
1034 system(buffer);
1035 } else {
1036 char *c = getenv("SHELL");
1037 if (!c)
1038 c = "/bin/sh";
1039 system(c);
1041 return 0;
1043 case KEYCMD_EXIT:
1044 exit(0);
1046 case KEYCMD_LOAD:
1047 if (argc != 2)
1048 return 1;
1049 return load(argv[1]);
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;
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;
1075 struct key_msgdata keymsgdata;
1077 readmesg2:
1078 if (read(keysock, key_message, sizeof(key_message)) < 0) {
1079 warn("read");
1080 return -1;
1083 if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1084 && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_DUMP)))
1085 goto readmesg2;
1088 * Kernel is done sending secassoc if key_seq == 0
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;
1096 if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1097 printf("get: can't parse reply\n");
1098 goto readmesg2;
1100 if (keycmds[i].num == KEYCMD_SAVE) {
1101 char *keytype, *algorithm;
1103 keytype = parsenumtoname(keytypes,
1104 ((struct key_msghdr *)&key_message)->type);
1106 algorithm = parsenumtoname(algorithmtabs[parsenumtoflag(keytypes,
1107 ((struct key_msghdr *)&key_message)->type)],
1108 ((struct key_msghdr *)&key_message)->algorithm);
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;
1125 return (0);
1127 return (-1);
1130 /*----------------------------------------------------------------------
1131 main:
1133 ----------------------------------------------------------------------*/
1135 main(int argc, char *argv[])
1137 int i, j;
1138 u_long rcvsize;
1140 if (getuid())
1141 errx(1, "this program is intended for the superuser only");
1143 if (!(keysock = socket(PF_KEY, SOCK_RAW, 0))) {
1144 warn("socket");
1145 return -1;
1148 for (rcvsize = MAXRCVBUFSIZE; rcvsize; rcvsize -= 1024) {
1149 if (setsockopt(keysock, SOL_SOCKET, SO_RCVBUF, &rcvsize,
1150 sizeof(rcvsize)) <= 0)
1151 break;
1154 mypid = getpid();
1155 if (mypid < 0) {
1156 warn("getpid");
1157 return -1;
1160 if (argc > 1) {
1162 * Attempt to do a single command, based on command line arguments.
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;
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);
1179 usage();
1181 return 0;
1185 char buffer[1024];
1186 char *iargv[KEYCMD_ARG_MAX];
1187 int iargc;
1189 while(1) {
1190 printf("key> ");
1191 if (!(fgets(buffer, sizeof(buffer), stdin)))
1192 return -1;
1193 buffer[sizeof(buffer)-1] = 0;
1195 * get command line, and parse into an argc/argv form.
1197 if ((i = parsecmdline(buffer, iargv, &iargc)) < 0)
1198 exit(1);
1199 if (i > 0)
1200 continue;
1201 errno = 0;
1203 * given argc/argv, process argument as if it came from the command
1204 * line.
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;
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;
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");
1231 /* EOF */