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
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
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.
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 $
78 #include <sys/types.h>
80 #include <sys/socket.h>
81 #include <sys/socketvar.h>
92 #include <netinet/in.h>
95 #include <netinet6/in6.h>
98 #include <netinet6/in6_types.h>
103 #include <netsec/ipsec.h>
105 #include <netkey/key.h>
108 #include <netinet6/support.h>
111 #ifndef INET6 /* XXX */
112 #define hostname2addr(a, b, c) gethostbyname(a)
113 #define addr2hostname(a, b, c, d) gethostbyaddr((a), (b), (c))
116 #include <arpa/inet.h>
118 int parse7 __P((int, char **));
119 int parse4 __P((int, char **));
120 int docmd __P((int, char **));
122 #define KEYCMD_ARG_MAX 10
124 #define KEYCMD_LOAD 1
125 #define KEYCMD_SAVE 2
128 #define KEYCMD_FLUSH 5
130 #define KEYCMD_DUMP 7
131 #define KEYCMD_HELP 8
132 #define KEYCMD_EXIT 9
133 #define KEYCMD_SHELL 10
141 char parse7usage[] = "<type> <spi> <src> <dst> <transform> <key> [iv]";
142 char parse4usage[] = "<type> <spi> <src> <dst>";
147 int (*parse) __P((int, char **));
151 { "add", KEYCMD_ADD, parse7, parse7usage,
152 "Adds a specific key entry to the kernel key table." },
153 { "del", KEYCMD_DEL, parse4, parse4usage,
154 "Removes a specific key entry from the kernel key table." },
155 { "get", KEYCMD_GET, parse4, parse4usage,
156 "Retrieves a key entry from the kernel key table." },
157 { "dump", KEYCMD_DUMP, NULL, " ",
158 "Retrieves all key entries from the kernel key table." },
159 { "load", KEYCMD_LOAD, NULL, "{ <filename> | - }",
160 "Loads keys from a file or stdin into the kernel key table." },
161 { "save", KEYCMD_SAVE, NULL, "{ <filename> | - }",
162 "Saves keys from the kernel key table to a file or stdout." },
163 { "help", KEYCMD_HELP, NULL, "[command]",
164 "Provides limited on-line help. Read the man page for more." },
165 { "flush", KEYCMD_FLUSH, NULL, NULL,
166 "Clears the kernel key table." },
167 { "!", KEYCMD_SHELL, NULL, "[command]",
168 "Executes a subshell." },
169 { "exit", KEYCMD_EXIT, NULL, NULL,
170 "Exits the program." },
171 { "quit", KEYCMD_EXIT, NULL, NULL,
172 "Exits the program." },
173 { NULL, 0, NULL, NULL, NULL }
176 /* flags: index into algorithmtabs */
178 struct nametonum keytypes[] = {
180 { "ah", KEY_TYPE_AH, 0 },
181 { "esp", KEY_TYPE_ESP, 1 },
183 { "rsvp", KEY_TYPE_RSVP, 2 },
184 { "ospf", KEY_TYPE_OSPF, 3 },
185 { "rip", KEY_TYPE_RIPV2, 4 },
189 #ifndef IPSEC_ALGTYPE_AUTH_MD5 /* XXX */
190 #define IPSEC_ALGTYPE_AUTH_MD5 1
193 /* flags: true = iv req. */
194 struct nametonum authalgorithms[] = {
195 { "md5", IPSEC_ALGTYPE_AUTH_MD5, 0 },
197 /* These provide no security but are useful for debugging the
198 kernel's ESP and Key Engine and PF_KEY routines */
199 { "dummy", IPSEC_ALGTYPE_AUTH_DUMMY, 0 },
200 { "cksum", IPSEC_ALGTYPE_AUTH_CKSUM, 0 },
205 #ifndef IPSEC_ALGTYPE_ESP_DES_CBC /* XXX */
206 #define IPSEC_ALGTYPE_ESP_DES_CBC 1
209 /* flags: true = iv req. */
210 struct nametonum encralgorithms[] = {
211 { "des-cbc", IPSEC_ALGTYPE_ESP_DES_CBC, 1 },
213 /* These provide no security but are useful for debugging the
214 kernel's ESP and Key Engine and PF_KEY routines */
215 { "dummy", IPSEC_ALGTYPE_ESP_DUMMY, 0 },
221 * These numbers should be defined in a header file somewhere
222 * and shared with the consuming programs, once someone has
223 * actually written the support in those programs (rspvd,
224 * gated, and routed). Probably <protocols/*>...?
226 #define RSVP_AUTHTYPE_MD5 1 /* XXX */
227 struct nametonum rsvpalgorithms[] = {
228 { "md5", RSVP_AUTHTYPE_MD5, 0 },
232 #define OSPF_AUTHTYPE_MD5 1 /* XXX */
233 struct nametonum ospfalgorithms[] = {
234 { "md5", OSPF_AUTHTYPE_MD5, 0 },
238 #define RIPV2_AUTHTYPE_MD5 1 /* XXX */
239 struct nametonum ripalgorithms[] = {
240 { "md5", RIPV2_AUTHTYPE_MD5, 0 },
244 /* NB: It is the ordering here that determines the values for the
245 flags specified above that are used to index into algorithmtabs[] */
246 struct nametonum *algorithmtabs[] = {
255 char buffer[1024] = "\0";
257 #define MAXRCVBUFSIZE 8 * 1024
259 char key_message[sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3
260 + MAX_KEY_SZ + MAX_IV_SZ];
266 int keydumpseqno = 1;
270 /*----------------------------------------------------------------------
271 help: Print appropriate help message on stdout.
273 ----------------------------------------------------------------------*/
280 for (i = 0; keycmds[i].name; i++)
281 if (!strcasecmp(keycmds[i].name, cmdname))
284 if (!keycmds[i].name) {
285 warnx("unknown command: %s", cmdname);
289 printf("%s%s%s\n", keycmds[i].name, keycmds[i].usage ? " " : "",
290 keycmds[i].usage ? keycmds[i].usage : "");
293 puts(keycmds[i].help);
295 for (i = 0; keycmds[i].name; i++)
296 printf("\t%s%s%s\n", keycmds[i].name, keycmds[i].usage ? " " : "",
297 keycmds[i].usage ? keycmds[i].usage : "");
303 /*----------------------------------------------------------------------
304 usage: print suitable usage message on stdout.
306 ----------------------------------------------------------------------*/
311 fprintf(stderr, "usage: keyadmin <command> <args>\n");
314 /*----------------------------------------------------------------------
315 parsekey: parse argument into a binary key and also record
316 the length of the resulting key.
317 ----------------------------------------------------------------------*/
318 int parsekey(key, keylen, arg)
328 if ((i == 1) && (arg[0] == '0')) {
334 printf("Invalid number \"%s\"\n", arg);
339 k = l = thisbyte = 0;
342 if ((arg[k] >= '0') && (arg[k] <= '9'))
343 thisbyte |= arg[k] - '0';
345 if ((arg[k] >= 'a') && (arg[k] <= 'f'))
346 thisbyte |= arg[k] - 'a' + 10;
348 if ((arg[k] >= 'A') && (arg[k] <= 'F'))
349 thisbyte |= arg[k] - 'A' + 10;
351 printf("Invalid hex number \"%s\"\n", arg);
358 thisbyte = (thisbyte << 4);
368 /*----------------------------------------------------------------------
369 parsenametonum: converts command-line name into index number.
371 ----------------------------------------------------------------------*/
372 int parsenametonum(tab, arg)
373 struct nametonum *tab;
378 for (i = 0; tab[i].name; i++)
379 if (!strcasecmp(tab[i].name, arg))
386 /*----------------------------------------------------------------------
387 parsesockaddr: Convert hostname arg into an appropriate sockaddr.
389 ----------------------------------------------------------------------*/
390 int parsesockaddr(sockaddr, arg)
391 struct sockaddr *sockaddr;
394 struct hostent *hostent;
395 struct in_addr in_addr, *in_addrp;
397 struct in_addr6 in_addr6, *in_addr6p;
400 if ((hostent = hostname2addr(arg, AF_INET, 0)))
401 if ((hostent->h_addrtype == AF_INET) &&
402 (hostent->h_length == sizeof(struct in_addr))) {
403 in_addrp = ((struct in_addr *)hostent->h_addr_list[0]);
407 if (ascii2addr(AF_INET, arg, (char *)&in_addr) ==
408 sizeof(struct in_addr)) {
414 if (hostent = hostname2addr(arg, AF_INET6))
415 if ((hostent->h_addrtype == AF_INET6) &&
416 (hostent->h_length == sizeof(struct in_addr6))) {
417 in_addr6p = ((struct in_addr6 *)hostent->h_addr_list[0]);
421 if (ascii2addr(AF_INET6, arg, (char *)&in_addr6)
422 == sizeof(struct in_addr6)) {
423 in_addr6p = &in_addr6;
428 warnx("unknown host \"%s\"", arg);
432 bzero(sockaddr, sizeof(struct sockaddr_in));
433 sockaddr->sa_len = sizeof(struct sockaddr_in);
434 sockaddr->sa_family = AF_INET;
435 ((struct sockaddr_in *)sockaddr)->sin_addr = *in_addrp;
440 bzero(sockaddr, sizeof(struct sockaddr_in6));
441 sockaddr->sa_len = sizeof(struct sockaddr_in6);
442 sockaddr->sa_family = AF_INET6;
443 ((struct sockaddr_in6 *)sockaddr)->sin6_addr = *in_addr6p;
448 /*----------------------------------------------------------------------
449 dummyfromaddr: Creates a zeroed sockaddr of family af.
451 ----------------------------------------------------------------------*/
452 void dummyfromaddr(sa, af)
458 size = (af == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
460 size = sizeof(struct sockaddr_in);
462 bzero((char *)sa, size);
468 * Macros to ensure word alignment.
471 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
472 #define ADVANCE(x, n) \
476 /*----------------------------------------------------------------------
477 parse4: parse keytype, spi, src addr, and dest addr from argv (command line)
478 and stick in structure pointed to by key_messageptr.
479 ----------------------------------------------------------------------*/
480 int parse4(argc, argv)
489 if ((i = parsenametonum(keytypes, argv[0])) < 0)
492 ((struct key_msghdr *)key_message)->type = keytypes[i].num;
494 /* Should we zero check? */
495 ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
497 if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
499 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
500 key_messageptr))->sa_len);
502 if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
504 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
505 key_messageptr))->sa_len);
508 * We need to put a dummy from address since the kernel expects
509 * this to be in the message.
512 dummyfromaddr(key_message + key_messageptr, AF_INET6);
514 dummyfromaddr(key_message + key_messageptr, AF_INET);
516 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
517 key_messageptr))->sa_len);
522 /*----------------------------------------------------------------------
523 parse7: parse keytype, spi, src addr, dest addr, alg type, key, and iv
524 from argv (command line)
525 and stick in structure pointed to by key_messageptr.
526 ----------------------------------------------------------------------*/
527 int parse7(argc, argv)
536 if ((i = parsenametonum(keytypes, argv[0])) < 0)
539 ((struct key_msghdr *)key_message)->type = keytypes[i].num;
541 /* Should we zero check? */
542 ((struct key_msghdr *)key_message)->spi = atoi(argv[1]);
544 if (parsesockaddr(key_message + key_messageptr, argv[2]) != 0)
546 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
547 key_messageptr))->sa_len);
549 if (parsesockaddr(key_message + key_messageptr, argv[3]) != 0)
551 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
552 key_messageptr))->sa_len);
555 * We need to put a dummy from address since the kernel expects
556 * this to be in the message.
559 dummyfromaddr(key_message + key_messageptr, AF_INET6);
561 dummyfromaddr(key_message + key_messageptr, AF_INET);
563 ADVANCE(key_messageptr, ((struct sockaddr *)(key_message +
564 key_messageptr))->sa_len);
566 if ((j = parsenametonum(algorithmtabs[keytypes[i].flags], argv[4])) < 0)
569 ((struct key_msghdr *)key_message)->algorithm =
570 algorithmtabs[keytypes[i].flags][j].num;
572 if ((argc < 7) && algorithmtabs[keytypes[i].flags][j].flags)
575 if (parsekey(key_message + key_messageptr,
576 &(((struct key_msghdr *)key_message)->keylen), argv[5]) != 0)
578 ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->keylen);
581 if (parsekey(key_message + key_messageptr,
582 &(((struct key_msghdr *)key_message)->ivlen), argv[6]) != 0)
584 ADVANCE(key_messageptr, ((struct key_msghdr *)key_message)->ivlen);
590 /*----------------------------------------------------------------------
593 ----------------------------------------------------------------------*/
594 int parsecmdline(buffer, argv, argc)
599 int i = 0, iargc = 0;
604 while(buffer[i] && (iargc < KEYCMD_ARG_MAX)) {
605 if ((buffer[i] == '\n') || (buffer[i] == '#')) {
608 argv[iargc++] = head;
611 if ((buffer[i] == ' ') || (buffer[i] == '\t')) {
614 argv[iargc++] = head;
615 head = &(buffer[++i]);
622 return iargc ? 0 : 1;
626 /*----------------------------------------------------------------------
627 load: load keys from file filename into Key Engine.
629 ----------------------------------------------------------------------*/
634 char buffer[1024], *buf, *largv[KEYCMD_ARG_MAX], *c;
635 int i, largc, left, line = 0;
637 if (strcmp(filename, "-")) {
638 if (!(fh = fopen(filename, "r")))
646 left = sizeof(buffer);
648 while(fgets(buf, left, fh)) {
650 if ((c = strchr(buffer, '\\'))) {
651 left = (sizeof(buffer) - 1) - (--c - buffer);
654 buffer[sizeof(buffer)-1] = 0;
656 if ((i = parsecmdline(buffer, &(largv[1]), &largc)) < 0)
660 if ((i = docmd(++largc, largv))) {
662 warnx("parse error on line %d of %s", line, filename);
670 left = sizeof(buffer);
677 /*----------------------------------------------------------------------
680 ----------------------------------------------------------------------*/
683 struct key_msghdr *km;
684 struct key_msgdata *kip;
690 if (!(km->key_msglen))
693 cp = (caddr_t)(km + 1);
694 cpmax = (caddr_t)km + km->key_msglen;
696 #define NEXTDATA(x, n) \
697 { x += ROUNDUP(n); if (cp >= cpmax) { \
698 warnx("kernel returned a truncated message!"); return(-1); } }
701 kip->src = (struct sockaddr *)cp;
702 if (!kip->src->sa_len)
705 NEXTDATA(cp, kip->src->sa_len);
708 kip->dst = (struct sockaddr *)cp;
709 if (!kip->dst->sa_len)
712 NEXTDATA(cp, kip->dst->sa_len);
715 kip->from = (struct sockaddr *)cp;
716 if (!kip->from->sa_len)
719 NEXTDATA(cp, kip->from->sa_len);
722 if (kip->keylen = km->keylen) {
724 NEXTDATA(cp, km->keylen);
728 if (kip->ivlen = km->ivlen)
733 printf("key: parsedata: difference=%d\n", cp - cpmax);
738 /*----------------------------------------------------------------------
741 ----------------------------------------------------------------------*/
742 void printkeyiv(fp, cp, len)
748 for (i=0; i<len; i++)
749 fprintf(fp, "%02x", (u_int8_t)*(cp+i));
752 /*----------------------------------------------------------------------
755 ----------------------------------------------------------------------*/
756 void printsockaddr(fp, sa)
765 if (sa->sa_family == AF_INET6) {
766 len = sizeof(struct in_addr6);
767 addrp = (char *)&(((struct sockaddr_in6 *)sa)->sin6_addr);
770 len = sizeof(struct in_addr);
771 addrp = (char *)&(((struct sockaddr_in *)sa)->sin_addr);
776 if((hp = addr2hostname(addrp, len, sa->sa_family, 0)) != NULL)
777 fprintf(fp, "%s", hp->h_name);
779 fprintf(fp, "%s", addr2ascii(sa->sa_family, addrp, len, NULL));
782 /*----------------------------------------------------------------------
785 ----------------------------------------------------------------------*/
787 parsenumtoname(tab, num)
788 struct nametonum *tab;
792 for (i = 0; tab[i].name; i++) {
793 if (num == tab[i].num)
799 /*----------------------------------------------------------------------
802 ----------------------------------------------------------------------*/
804 parsenumtoflag(tab, num)
805 struct nametonum *tab;
809 for (i = 0; tab[i].name; i++) {
810 if (num == tab[i].num)
811 return(tab[i].flags);
817 /*----------------------------------------------------------------------
820 ----------------------------------------------------------------------*/
821 void printkeymsg(kmp, kdp)
822 struct key_msghdr *kmp;
823 struct key_msgdata *kdp;
826 printf("type=%d(%s) ",kmp->type, parsenumtoname(keytypes, kmp->type));
827 printf("spi=%u ", kmp->spi);
828 printf("alogrithm=%u(%s) ", kmp->algorithm,
829 parsenumtoname(algorithmtabs[parsenumtoflag(keytypes, kmp->type)],
831 printf("state=0x%x ",kmp->state);
833 if (kmp->state != 0) {
834 if (kmp->state & K_USED)
836 if (kmp->state & K_UNIQUE)
838 if (kmp->state & K_LARVAL)
840 if (kmp->state & K_ZOMBIE)
842 if (kmp->state & K_DEAD)
844 if (kmp->state & K_INBOUND)
846 if (kmp->state & K_OUTBOUND)
850 printf("sensitivity_label=%d ",kmp->label);
851 printf("lifetype=%d ",kmp->lifetype);
852 printf("lifetime1=%d ",kmp->lifetime1);
853 printf("lifetime2=%d\n",kmp->lifetime2);
854 printf("key (len=%d):\t",kdp->keylen);
855 printkeyiv(stdout, kdp->key, kdp->keylen);
857 printf("iv (len=%d):\t", kdp->ivlen);
858 printkeyiv(stdout, kdp->iv, kdp->ivlen);
861 printsockaddr(stdout, (struct sockaddr *)kdp->src);
864 printsockaddr(stdout, (struct sockaddr *)kdp->dst);
866 /* printf("from:\t");
867 printsockaddr(stdout, (struct sockaddr *)kdp->from); */
871 /*----------------------------------------------------------------------
874 ----------------------------------------------------------------------*/
875 int docmd(argc, argv)
883 if (!argv[0] || !argc)
889 bzero(&key_message, sizeof(key_message));
890 key_messageptr = sizeof(struct key_msghdr);
892 for (i = 0; keycmds[i].name; i++)
893 if (!strcasecmp(keycmds[i].name, argv[0]))
896 if (!keycmds[i].name)
899 if (keycmds[i].parse)
900 if ((j = keycmds[i].parse(argc - 1, &(argv[1]))))
903 ((struct key_msghdr *)key_message)->key_msglen = key_messageptr;
904 ((struct key_msghdr *)key_message)->key_msgvers = 1;
905 ((struct key_msghdr *)key_message)->key_seq = 1;
907 switch(keycmds[i].num) {
912 * For now, we do sanity check of security association
913 * information here until we find a better place.
916 struct key_msghdr *kmp = (struct key_msghdr *)key_message;
918 if ((kmp->type == KEY_TYPE_AH ||
919 kmp->type == KEY_TYPE_ESP) && (kmp->spi < 256)) {
920 warnx("add: spi must be greater than 255");
924 if (kmp->type == KEY_TYPE_ESP &&
925 (kmp->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC
926 #ifdef IPSEC_ALGTYPE_ESP_3DES
927 || kmp->algorithm == IPSEC_ALGTYPE_ESP_3DES
930 if (kmp->keylen != 8) {
931 warnx("add: key must be 8 bytes");
934 if (kmp->ivlen != 4 && kmp->ivlen != 8) {
935 warnx("add: iv must be 4 or 8 bytes");
940 if (kmp->type == KEY_TYPE_AH &&
941 kmp->algorithm == IPSEC_ALGTYPE_AUTH_MD5 && kmp->keylen == 0) {
942 warnx("add: no key specified");
947 ((struct key_msghdr *)key_message)->key_msgtype = KEY_ADD;
948 if (write(keysock, key_message,
949 ((struct key_msghdr *)key_message)->key_msglen) !=
950 ((struct key_msghdr *)key_message)->key_msglen) {
952 warnx("add: security association already exists");
957 read(keysock, key_message, sizeof(key_message));
961 ((struct key_msghdr *)key_message)->key_msgtype = KEY_DELETE;
962 if (write(keysock, key_message,
963 ((struct key_msghdr *)key_message)->key_msglen) !=
964 ((struct key_msghdr *)key_message)->key_msglen) {
965 if (errno == ESRCH) {
966 warnx("delete: security association not found");
973 read(keysock, key_message, sizeof(key_message));
977 ((struct key_msghdr *)key_message)->key_msgtype = KEY_GET;
978 ((struct key_msghdr *)key_message)->key_seq = seqno = keygetseqno++;
980 if (write(keysock, key_message,
981 ((struct key_msghdr *)key_message)->key_msglen) !=
982 ((struct key_msghdr *)key_message)->key_msglen) {
983 if (errno == ESRCH) {
984 warnx("get: security association not found");
990 } /* endif write() */
994 struct key_msgdata keymsgdata;
996 len = sizeof(struct key_msghdr) + MAX_SOCKADDR_SZ * 3
997 + MAX_KEY_SZ + MAX_IV_SZ;
1000 if (read(keysock, key_message, len) < 0) {
1005 if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1006 && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_GET)
1007 && (((struct key_msghdr *)&key_message)->key_seq==seqno))) {
1008 fprintf(stderr, ".");
1012 if (((struct key_msghdr *)&key_message)->key_errno != 0) {
1013 printf("Error: kernel reporting errno=%d\n",
1014 ((struct key_msghdr *)&key_message)->key_errno);
1018 if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1019 printf("get: can't parse reply\n");
1023 printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1028 ((struct key_msghdr *)key_message)->key_msgtype = KEY_FLUSH;
1029 if (write(keysock, key_message,
1030 ((struct key_msghdr *)key_message)->key_msglen) !=
1031 ((struct key_msghdr *)key_message)->key_msglen) {
1035 read(keysock, key_message, sizeof(key_message));
1039 return help((argc > 1) ? argv[1] : NULL);
1043 char buffer[1024], *ap, *ep, *c;
1046 ep = buffer + sizeof(buffer) - 1;
1047 for (i = 1, ap = buffer; (i < argc) && (ap < ep); i++) {
1049 while ((*(ap++) = *(c++)) && (ap < ep));
1055 char *c = getenv("SHELL");
1068 return load(argv[1]);
1073 if (!strcmp(argv[1], "-"))
1075 else if ((fd = open(argv[1], O_CREAT | O_RDWR | O_EXCL,
1076 S_IRUSR | S_IWUSR)) < 0) {
1079 } else if (!(fp = fdopen(fd, "w"))) {
1085 ((struct key_msghdr *)key_message)->key_msgtype = KEY_DUMP;
1086 if (write(keysock, key_message,
1087 ((struct key_msghdr *)key_message)->key_msglen) !=
1088 ((struct key_msghdr *)key_message)->key_msglen) {
1094 struct key_msgdata keymsgdata;
1097 if (read(keysock, key_message, sizeof(key_message)) < 0) {
1102 if (!((((struct key_msghdr *)&key_message)->key_pid==mypid)
1103 && (((struct key_msghdr *)&key_message)->key_msgtype==KEY_DUMP)))
1107 * Kernel is done sending secassoc if key_seq == 0
1109 if (((struct key_msghdr *)&key_message)->key_seq == 0) {
1110 if ((keycmds[i].num == KEYCMD_SAVE) && (fp != stdout))
1115 if (parsedata((struct key_msghdr *)&key_message, &keymsgdata) < 0) {
1116 printf("get: can't parse reply\n");
1119 if (keycmds[i].num == KEYCMD_SAVE) {
1120 char *keytype, *algorithm;
1122 keytype = parsenumtoname(keytypes,
1123 ((struct key_msghdr *)&key_message)->type);
1125 algorithm = parsenumtoname(algorithmtabs[parsenumtoflag(keytypes,
1126 ((struct key_msghdr *)&key_message)->type)],
1127 ((struct key_msghdr *)&key_message)->algorithm);
1129 fprintf(fp, "%s %u ", keytype,
1130 ((struct key_msghdr *)&key_message)->spi);
1131 printsockaddr(fp, (struct sockaddr *)(keymsgdata.src));
1133 printsockaddr(fp, (struct sockaddr *)(keymsgdata.dst));
1135 fprintf(fp, "%s ", algorithm);
1136 printkeyiv(fp, keymsgdata.key, keymsgdata.keylen);
1138 printkeyiv(fp, keymsgdata.iv, keymsgdata.ivlen);
1141 printkeymsg((struct key_msghdr *)&key_message, &keymsgdata);
1149 /*----------------------------------------------------------------------
1152 ----------------------------------------------------------------------*/
1153 int main(argc, argv)
1161 errx(1, "this program is intended for the superuser only");
1163 if (!(keysock = socket(PF_KEY, SOCK_RAW, 0))) {
1168 for (rcvsize = MAXRCVBUFSIZE; rcvsize; rcvsize -= 1024) {
1169 if (setsockopt(keysock, SOL_SOCKET, SO_RCVBUF, &rcvsize,
1170 sizeof(rcvsize)) <= 0)
1182 * Attempt to do a single command, based on command line arguments.
1184 if (strcasecmp(argv[1], "add") == 0)
1185 errx(1, "cannot add keys from the command line. RTFM for why");
1186 if ((i = docmd(argc - 1, &(argv[1])))) {
1188 for (j = 0; keycmds[j].name; j++)
1189 if (!strcasecmp(keycmds[j].name, argv[1]))
1192 if (keycmds[j].name) {
1193 fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1194 keycmds[j].usage ? " " : "",
1195 keycmds[j].usage ? keycmds[j].usage : "");
1206 char *iargv[KEYCMD_ARG_MAX];
1211 if (!(fgets(buffer, sizeof(buffer), stdin)))
1213 buffer[sizeof(buffer)-1] = 0;
1215 * get command line, and parse into an argc/argv form.
1217 if ((i = parsecmdline(buffer, iargv, &iargc)) < 0)
1223 * given argc/argv, process argument as if it came from the command
1226 if ((i = docmd(iargc, iargv))) {
1228 for (j = 0; keycmds[j].name; j++)
1229 if (!strcasecmp(keycmds[j].name, iargv[0]))
1232 if (keycmds[j].name) {
1233 fprintf(stderr, "usage: %s%s%s\n", keycmds[j].name,
1234 keycmds[j].usage ? " " : "",
1235 keycmds[j].usage ? keycmds[j].usage : "");
1241 warn("system error");
1243 warnx("unrecognized command");
1244 warnx("type 'help' if you need help");