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 $
76 * $DragonFly: src/usr.sbin/keyadmin/keyadmin.c,v 1.4 2005/12/05 01:04:01 swildner Exp $
79 #include <sys/types.h>
81 #include <sys/socket.h>
82 #include <sys/socketvar.h>
93 #include <netinet/in.h>
96 #include <netinet6/in6.h>
99 #include <netinet6/in6_types.h>
104 #include <netsec/ipsec.h>
106 #include <netkey/key.h>
109 #include <netinet6/support.h>
112 #ifndef INET6 /* XXX */
113 #define hostname2addr(a, b, c) gethostbyname(a)
114 #define addr2hostname(a, b, c, d) gethostbyaddr((a), (b), (c))
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
129 #define KEYCMD_FLUSH 5
131 #define KEYCMD_DUMP 7
132 #define KEYCMD_HELP 8
133 #define KEYCMD_EXIT 9
134 #define KEYCMD_SHELL 10
142 char parse7usage
[] = "<type> <spi> <src> <dst> <transform> <key> [iv]";
143 char parse4usage
[] = "<type> <spi> <src> <dst>";
148 int (*parse
)(int, char **);
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
[] = {
181 { "ah", KEY_TYPE_AH
, 0 },
182 { "esp", KEY_TYPE_ESP
, 1 },
184 { "rsvp", KEY_TYPE_RSVP
, 2 },
185 { "ospf", KEY_TYPE_OSPF
, 3 },
186 { "rip", KEY_TYPE_RIPV2
, 4 },
190 #ifndef IPSEC_ALGTYPE_AUTH_MD5 /* XXX */
191 #define IPSEC_ALGTYPE_AUTH_MD5 1
194 /* flags: true = iv req. */
195 struct nametonum authalgorithms
[] = {
196 { "md5", IPSEC_ALGTYPE_AUTH_MD5
, 0 },
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 },
206 #ifndef IPSEC_ALGTYPE_ESP_DES_CBC /* XXX */
207 #define IPSEC_ALGTYPE_ESP_DES_CBC 1
210 /* flags: true = iv req. */
211 struct nametonum encralgorithms
[] = {
212 { "des-cbc", IPSEC_ALGTYPE_ESP_DES_CBC
, 1 },
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 },
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 },
233 #define OSPF_AUTHTYPE_MD5 1 /* XXX */
234 struct nametonum ospfalgorithms
[] = {
235 { "md5", OSPF_AUTHTYPE_MD5
, 0 },
239 #define RIPV2_AUTHTYPE_MD5 1 /* XXX */
240 struct nametonum ripalgorithms
[] = {
241 { "md5", RIPV2_AUTHTYPE_MD5
, 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
[] = {
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
];
267 int keydumpseqno
= 1;
271 /*----------------------------------------------------------------------
272 help: Print appropriate help message on stdout.
274 ----------------------------------------------------------------------*/
281 for (i
= 0; keycmds
[i
].name
; i
++)
282 if (!strcasecmp(keycmds
[i
].name
, cmdname
))
285 if (!keycmds
[i
].name
) {
286 warnx("unknown command: %s", cmdname
);
290 printf("%s%s%s\n", keycmds
[i
].name
, keycmds
[i
].usage
? " " : "",
291 keycmds
[i
].usage
? keycmds
[i
].usage
: "");
294 puts(keycmds
[i
].help
);
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
: "");
304 /*----------------------------------------------------------------------
305 usage: print suitable usage message on stdout.
307 ----------------------------------------------------------------------*/
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
)
327 if ((i
== 1) && (arg
[0] == '0')) {
333 printf("Invalid number \"%s\"\n", arg
);
338 k
= l
= thisbyte
= 0;
341 if ((arg
[k
] >= '0') && (arg
[k
] <= '9'))
342 thisbyte
|= arg
[k
] - '0';
344 if ((arg
[k
] >= 'a') && (arg
[k
] <= 'f'))
345 thisbyte
|= arg
[k
] - 'a' + 10;
347 if ((arg
[k
] >= 'A') && (arg
[k
] <= 'F'))
348 thisbyte
|= arg
[k
] - 'A' + 10;
350 printf("Invalid hex number \"%s\"\n", arg
);
357 thisbyte
= (thisbyte
<< 4);
367 /*----------------------------------------------------------------------
368 parsenametonum: converts command-line name into index number.
370 ----------------------------------------------------------------------*/
372 parsenametonum(struct nametonum
*tab
, char *arg
)
376 for (i
= 0; tab
[i
].name
; i
++)
377 if (!strcasecmp(tab
[i
].name
, arg
))
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
;
394 struct in_addr6 in_addr6
, *in_addr6p
;
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]);
404 if (ascii2addr(AF_INET
, arg
, (char *)&in_addr
) ==
405 sizeof(struct in_addr
)) {
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]);
418 if (ascii2addr(AF_INET6
, arg
, (char *)&in_addr6
)
419 == sizeof(struct in_addr6
)) {
420 in_addr6p
= &in_addr6
;
425 warnx("unknown host \"%s\"", arg
);
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
;
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
;
445 /*----------------------------------------------------------------------
446 dummyfromaddr: Creates a zeroed sockaddr of family af.
448 ----------------------------------------------------------------------*/
450 dummyfromaddr(struct sockaddr
*sa
, int af
)
454 size
= (af
== AF_INET6
) ? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
));
456 size
= sizeof(struct sockaddr_in
);
458 bzero((char *)sa
, size
);
464 * Macros to ensure word alignment.
467 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
468 #define ADVANCE(x, 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
[])
484 if ((i
= parsenametonum(keytypes
, argv
[0])) < 0)
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)
494 ADVANCE(key_messageptr
, ((struct sockaddr
*)(key_message
+
495 key_messageptr
))->sa_len
);
497 if (parsesockaddr(key_message
+ key_messageptr
, argv
[3]) != 0)
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.
507 dummyfromaddr(key_message
+ key_messageptr
, AF_INET6
);
509 dummyfromaddr(key_message
+ key_messageptr
, AF_INET
);
511 ADVANCE(key_messageptr
, ((struct sockaddr
*)(key_message
+
512 key_messageptr
))->sa_len
);
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
[])
530 if ((i
= parsenametonum(keytypes
, argv
[0])) < 0)
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)
540 ADVANCE(key_messageptr
, ((struct sockaddr
*)(key_message
+
541 key_messageptr
))->sa_len
);
543 if (parsesockaddr(key_message
+ key_messageptr
, argv
[3]) != 0)
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.
553 dummyfromaddr(key_message
+ key_messageptr
, AF_INET6
);
555 dummyfromaddr(key_message
+ key_messageptr
, AF_INET
);
557 ADVANCE(key_messageptr
, ((struct sockaddr
*)(key_message
+
558 key_messageptr
))->sa_len
);
560 if ((j
= parsenametonum(algorithmtabs
[keytypes
[i
].flags
], argv
[4])) < 0)
563 ((struct key_msghdr
*)key_message
)->algorithm
=
564 algorithmtabs
[keytypes
[i
].flags
][j
].num
;
566 if ((argc
< 7) && algorithmtabs
[keytypes
[i
].flags
][j
].flags
)
569 if (parsekey(key_message
+ key_messageptr
,
570 &(((struct key_msghdr
*)key_message
)->keylen
), argv
[5]) != 0)
572 ADVANCE(key_messageptr
, ((struct key_msghdr
*)key_message
)->keylen
);
575 if (parsekey(key_message
+ key_messageptr
,
576 &(((struct key_msghdr
*)key_message
)->ivlen
), argv
[6]) != 0)
578 ADVANCE(key_messageptr
, ((struct key_msghdr
*)key_message
)->ivlen
);
584 /*----------------------------------------------------------------------
587 ----------------------------------------------------------------------*/
589 parsecmdline(char *buffer
, char **argv
, int *argc
)
591 int i
= 0, iargc
= 0;
596 while(buffer
[i
] && (iargc
< KEYCMD_ARG_MAX
)) {
597 if ((buffer
[i
] == '\n') || (buffer
[i
] == '#')) {
600 argv
[iargc
++] = head
;
603 if ((buffer
[i
] == ' ') || (buffer
[i
] == '\t')) {
606 argv
[iargc
++] = head
;
607 head
= &(buffer
[++i
]);
614 return iargc
? 0 : 1;
618 /*----------------------------------------------------------------------
619 load: load keys from file filename into Key Engine.
621 ----------------------------------------------------------------------*/
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")))
638 left
= sizeof(buffer
);
640 while(fgets(buf
, left
, fh
)) {
642 if ((c
= strchr(buffer
, '\\'))) {
643 left
= (sizeof(buffer
) - 1) - (--c
- buffer
);
646 buffer
[sizeof(buffer
)-1] = 0;
648 if ((i
= parsecmdline(buffer
, &(largv
[1]), &largc
)) < 0)
652 if ((i
= docmd(++largc
, largv
))) {
654 warnx("parse error on line %d of %s", line
, filename
);
662 left
= sizeof(buffer
);
669 /*----------------------------------------------------------------------
672 ----------------------------------------------------------------------*/
674 parsedata(struct key_msghdr
*km
, struct key_msgdata
*kip
)
680 if (!(km
->key_msglen
))
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); } }
691 kip
->src
= (struct sockaddr
*)cp
;
692 if (!kip
->src
->sa_len
)
695 NEXTDATA(cp
, kip
->src
->sa_len
);
698 kip
->dst
= (struct sockaddr
*)cp
;
699 if (!kip
->dst
->sa_len
)
702 NEXTDATA(cp
, kip
->dst
->sa_len
);
705 kip
->from
= (struct sockaddr
*)cp
;
706 if (!kip
->from
->sa_len
)
709 NEXTDATA(cp
, kip
->from
->sa_len
);
712 if (kip
->keylen
= km
->keylen
) {
714 NEXTDATA(cp
, km
->keylen
);
718 if (kip
->ivlen
= km
->ivlen
)
723 printf("key: parsedata: difference=%d\n", cp
- cpmax
);
728 /*----------------------------------------------------------------------
731 ----------------------------------------------------------------------*/
733 printkeyiv(FILE *fp
, caddr_t cp
, int len
)
736 for (i
=0; i
<len
; i
++)
737 fprintf(fp
, "%02x", (u_int8_t
)*(cp
+i
));
740 /*----------------------------------------------------------------------
743 ----------------------------------------------------------------------*/
745 printsockaddr(FILE *fp
, struct sockaddr
*sa
)
752 if (sa
->sa_family
== AF_INET6
) {
753 len
= sizeof(struct in_addr6
);
754 addrp
= (char *)&(((struct sockaddr_in6
*)sa
)->sin6_addr
);
757 len
= sizeof(struct in_addr
);
758 addrp
= (char *)&(((struct sockaddr_in
*)sa
)->sin_addr
);
763 if((hp
= addr2hostname(addrp
, len
, sa
->sa_family
, 0)) != NULL
)
764 fprintf(fp
, "%s", hp
->h_name
);
766 fprintf(fp
, "%s", addr2ascii(sa
->sa_family
, addrp
, len
, NULL
));
769 /*----------------------------------------------------------------------
772 ----------------------------------------------------------------------*/
774 parsenumtoname(struct nametonum
*tab
, int num
)
777 for (i
= 0; tab
[i
].name
; i
++) {
778 if (num
== tab
[i
].num
)
784 /*----------------------------------------------------------------------
787 ----------------------------------------------------------------------*/
789 parsenumtoflag(struct nametonum
*tab
, int num
)
792 for (i
= 0; tab
[i
].name
; i
++) {
793 if (num
== tab
[i
].num
)
794 return(tab
[i
].flags
);
800 /*----------------------------------------------------------------------
803 ----------------------------------------------------------------------*/
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
)],
813 printf("state=0x%x ",kmp
->state
);
815 if (kmp
->state
!= 0) {
816 if (kmp
->state
& K_USED
)
818 if (kmp
->state
& K_UNIQUE
)
820 if (kmp
->state
& K_LARVAL
)
822 if (kmp
->state
& K_ZOMBIE
)
824 if (kmp
->state
& K_DEAD
)
826 if (kmp
->state
& K_INBOUND
)
828 if (kmp
->state
& K_OUTBOUND
)
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
);
839 printf("iv (len=%d):\t", kdp
->ivlen
);
840 printkeyiv(stdout
, kdp
->iv
, kdp
->ivlen
);
843 printsockaddr(stdout
, (struct sockaddr
*)kdp
->src
);
846 printsockaddr(stdout
, (struct sockaddr
*)kdp
->dst
);
848 /* printf("from:\t");
849 printsockaddr(stdout, (struct sockaddr *)kdp->from); */
853 /*----------------------------------------------------------------------
856 ----------------------------------------------------------------------*/
858 docmd(int argc
, char **argv
)
864 if (!argv
[0] || !argc
)
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]))
877 if (!keycmds
[i
].name
)
880 if (keycmds
[i
].parse
)
881 if ((j
= keycmds
[i
].parse(argc
- 1, &(argv
[1]))))
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
) {
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");
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
911 if (kmp
->keylen
!= 8) {
912 warnx("add: key must be 8 bytes");
915 if (kmp
->ivlen
!= 4 && kmp
->ivlen
!= 8) {
916 warnx("add: iv must be 4 or 8 bytes");
921 if (kmp
->type
== KEY_TYPE_AH
&&
922 kmp
->algorithm
== IPSEC_ALGTYPE_AUTH_MD5
&& kmp
->keylen
== 0) {
923 warnx("add: no key specified");
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
) {
933 warnx("add: security association already exists");
938 read(keysock
, key_message
, sizeof(key_message
));
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");
954 read(keysock
, key_message
, sizeof(key_message
));
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");
971 } /* endif write() */
975 struct key_msgdata keymsgdata
;
977 len
= sizeof(struct key_msghdr
) + MAX_SOCKADDR_SZ
* 3
978 + MAX_KEY_SZ
+ MAX_IV_SZ
;
981 if (read(keysock
, key_message
, len
) < 0) {
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
, ".");
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
);
999 if (parsedata((struct key_msghdr
*)&key_message
, &keymsgdata
) < 0) {
1000 printf("get: can't parse reply\n");
1004 printkeymsg((struct key_msghdr
*)&key_message
, &keymsgdata
);
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
) {
1016 read(keysock
, key_message
, sizeof(key_message
));
1020 return help((argc
> 1) ? argv
[1] : NULL
);
1024 char buffer
[1024], *ap
, *ep
, *c
;
1027 ep
= buffer
+ sizeof(buffer
) - 1;
1028 for (i
= 1, ap
= buffer
; (i
< argc
) && (ap
< ep
); i
++) {
1030 while ((*(ap
++) = *(c
++)) && (ap
< ep
));
1036 char *c
= getenv("SHELL");
1049 return load(argv
[1]);
1054 if (!strcmp(argv
[1], "-"))
1056 else if ((fd
= open(argv
[1], O_CREAT
| O_RDWR
| O_EXCL
,
1057 S_IRUSR
| S_IWUSR
)) < 0) {
1060 } else if (!(fp
= fdopen(fd
, "w"))) {
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
) {
1075 struct key_msgdata keymsgdata
;
1078 if (read(keysock
, key_message
, sizeof(key_message
)) < 0) {
1083 if (!((((struct key_msghdr
*)&key_message
)->key_pid
==mypid
)
1084 && (((struct key_msghdr
*)&key_message
)->key_msgtype
==KEY_DUMP
)))
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
))
1096 if (parsedata((struct key_msghdr
*)&key_message
, &keymsgdata
) < 0) {
1097 printf("get: can't parse reply\n");
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
));
1114 printsockaddr(fp
, (struct sockaddr
*)(keymsgdata
.dst
));
1116 fprintf(fp
, "%s ", algorithm
);
1117 printkeyiv(fp
, keymsgdata
.key
, keymsgdata
.keylen
);
1119 printkeyiv(fp
, keymsgdata
.iv
, keymsgdata
.ivlen
);
1122 printkeymsg((struct key_msghdr
*)&key_message
, &keymsgdata
);
1130 /*----------------------------------------------------------------------
1133 ----------------------------------------------------------------------*/
1135 main(int argc
, char *argv
[])
1141 errx(1, "this program is intended for the superuser only");
1143 if (!(keysock
= socket(PF_KEY
, SOCK_RAW
, 0))) {
1148 for (rcvsize
= MAXRCVBUFSIZE
; rcvsize
; rcvsize
-= 1024) {
1149 if (setsockopt(keysock
, SOL_SOCKET
, SO_RCVBUF
, &rcvsize
,
1150 sizeof(rcvsize
)) <= 0)
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])))) {
1168 for (j
= 0; keycmds
[j
].name
; j
++)
1169 if (!strcasecmp(keycmds
[j
].name
, argv
[1]))
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
: "");
1186 char *iargv
[KEYCMD_ARG_MAX
];
1191 if (!(fgets(buffer
, sizeof(buffer
), stdin
)))
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)
1203 * given argc/argv, process argument as if it came from the command
1206 if ((i
= docmd(iargc
, iargv
))) {
1208 for (j
= 0; keycmds
[j
].name
; j
++)
1209 if (!strcasecmp(keycmds
[j
].name
, iargv
[0]))
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
: "");
1221 warn("system error");
1223 warnx("unrecognized command");
1224 warnx("type 'help' if you need help");