4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <ipsec_util.h>
34 #include <net/pfpolicy.h>
37 #include <sys/crypto/common.h>
40 #define SPDSOCK_DIAG_BUF_LEN 128
52 static const char *comma
= ",";
53 static int adddel_flags
, increment
= 0, default_keylen
;
54 static boolean_t synch_kernel
;
55 static cmd_t cmd
= CMD_NONE
;
56 static int proto_number
= -1, alg_number
= -1, alg_flags
= 0;
57 static char *proto_name
, *alg_names_string
, *block_sizes_string
;
58 static char *key_sizes_string
, *mech_name
, *exec_mode_string
;
59 static char *flag_string
;
60 static ipsecalgs_exec_mode_t proto_exec_mode
= LIBIPSEC_ALGS_EXEC_SYNC
;
61 enum param_values
{iv_len
, mac_len
, salt_bytes
, max_param
};
62 static int mech_params
[max_param
];
65 * Used by the algorithm walker callback to populate a SPD_UPDATEALGS
69 #define SYNC_REQ_SIZE 4096
71 static uint64_t sync_req_buf
[SYNC_REQ_SIZE
];
72 static struct spd_attribute
*sync_req_attr
;
73 static uint_t sync_req_alg_count
, sync_req_proto_count
;
75 #define EMIT(ap, tag, value) { \
76 (ap)->spd_attr_tag = (tag); \
77 (ap)->spd_attr_value = (value); \
79 if ((char *)(ap) + sizeof (*ap) - \
80 (char *)sync_req_buf > SYNC_REQ_SIZE) \
84 static void dump_alg(struct ipsecalgent
*);
85 static void algs_walker(void (*)(struct ipsecalgent
*), void (*)(uint_t
));
88 parse_flag(char *flag_str
, uint_t flag
)
90 static struct flagtable
{
94 {"VALID", ALG_FLAG_VALID
},
95 {"COUNTER", ALG_FLAG_COUNTERMODE
},
96 {"COMBINED", ALG_FLAG_COMBINED
},
97 {"CCM", ALG_FLAG_CCM
},
98 {"GCM", ALG_FLAG_GCM
},
101 struct flagtable
*ft
= table
;
103 if (flag_str
== NULL
) {
104 /* Print out flag labels for each flag set. */
105 if ((ALG_FLAG_KERNELCHECKED
& flag
) && !(ALG_FLAG_VALID
& flag
))
106 (void) printf("INVALID ");
107 while (ft
->token
!= 0) {
108 if (ft
->token
& flag
) {
109 (void) printf("%s ", ft
->label
);
115 /* Or, lookup flag for supplied label. */
116 while (ft
->label
!= NULL
&& strcmp(ft
->label
, flag_str
) != 0)
124 errx(EXIT_FAILURE
, gettext("Usage:\tipsecalgs\n"
127 "\tipsecalgs -a [-P protocol-number | -p protocol-name]\n"
128 "\t\t-k keylen-list [-i inc]\n"
129 "\t\t[-K default-keylen] -b blocklen-list\n"
130 "\t\t-n alg-names -N alg-number -m mech-name\n"
131 "\t\t[-M MAC length] [-S salt length] [-I IV length]\n"
132 "\t\t[-F COMBINED,COUNTER,CCM|GCM ] [-f] [-s]\n"
133 "\tipsecalgs -P protocol-number -p protocol-name\n"
134 "\t\t[-e exec-mode] [-f] [-s]\n"
135 "\tipsecalgs -r -p protocol-name -n alg-name [-s]\n"
136 "\tipsecalgs -r -p protocol-name -N alg-number [-s]\n"
137 "\tipsecalgs -R -P protocol-number [-s]\n"
138 "\tipsecalgs -R -p protocol-name [-s]\n"
139 "\tipsecalgs -e exec-mode -P protocol-number [-s]\n"
140 "\tipsecalgs -e exec-mode -p protocol-number [-s]"));
146 errx(EXIT_FAILURE
, gettext("Out of memory."));
150 * Return the number of key or block sizes in the specified array.
153 num_sizes(int *sizes
)
157 while (sizes
[nsizes
] != 0)
164 * Algorithms walker callback. Adds an algorithm to the current SPD_UPDATEALGS
168 synch_emit_alg(struct ipsecalgent
*alg
)
170 uint_t nkey_sizes
, nblock_sizes
, i
;
173 EMIT(sync_req_attr
, SPD_ATTR_ALG_ID
, alg
->a_alg_num
);
174 EMIT(sync_req_attr
, SPD_ATTR_ALG_PROTO
, alg
->a_proto_num
);
175 EMIT(sync_req_attr
, SPD_ATTR_ALG_INCRBITS
, alg
->a_key_increment
);
177 nkey_sizes
= num_sizes(alg
->a_key_sizes
);
178 EMIT(sync_req_attr
, SPD_ATTR_ALG_NKEYSIZES
, nkey_sizes
);
179 for (i
= 0; i
< nkey_sizes
; i
++)
180 EMIT(sync_req_attr
, SPD_ATTR_ALG_KEYSIZE
, alg
->a_key_sizes
[i
]);
182 nblock_sizes
= num_sizes(alg
->a_block_sizes
);
183 nparams
= num_sizes(alg
->a_mech_params
);
184 EMIT(sync_req_attr
, SPD_ATTR_ALG_NBLOCKSIZES
, nblock_sizes
);
185 for (i
= 0; i
< nblock_sizes
; i
++) {
186 EMIT(sync_req_attr
, SPD_ATTR_ALG_BLOCKSIZE
,
187 alg
->a_block_sizes
[i
]);
189 EMIT(sync_req_attr
, SPD_ATTR_ALG_NPARAMS
, nparams
);
190 for (i
= 0; i
< nparams
; i
++) {
191 EMIT(sync_req_attr
, SPD_ATTR_ALG_PARAMS
,
192 alg
->a_mech_params
[i
]);
194 EMIT(sync_req_attr
, SPD_ATTR_ALG_FLAGS
, alg
->a_alg_flags
);
196 EMIT(sync_req_attr
, SPD_ATTR_ALG_MECHNAME
, CRYPTO_MAX_MECH_NAME
);
197 (void) strncpy((char *)sync_req_attr
, alg
->a_mech_name
,
198 CRYPTO_MAX_MECH_NAME
);
199 sync_req_attr
= (struct spd_attribute
*)((uint64_t *)sync_req_attr
+
200 SPD_8TO64(CRYPTO_MAX_MECH_NAME
));
202 EMIT(sync_req_attr
, SPD_ATTR_NEXT
, 0);
204 sync_req_alg_count
++;
208 * Protocol walker callback. Add protocol related info to the current
209 * SPD_UPDATEALGS request.
212 synch_emit_proto(uint_t proto_num
)
214 ipsecalgs_exec_mode_t exec_mode
;
215 uint32_t exec_mode_spdval
;
217 EMIT(sync_req_attr
, SPD_ATTR_PROTO_ID
, proto_num
);
220 if (ipsecproto_get_exec_mode(proto_num
, &exec_mode
) != 0) {
221 errx(EXIT_FAILURE
, gettext("cannot get execution mode for "
222 "proto %d"), proto_num
);
226 case LIBIPSEC_ALGS_EXEC_SYNC
:
227 exec_mode_spdval
= SPD_ALG_EXEC_MODE_SYNC
;
229 case LIBIPSEC_ALGS_EXEC_ASYNC
:
230 exec_mode_spdval
= SPD_ALG_EXEC_MODE_ASYNC
;
233 EMIT(sync_req_attr
, SPD_ATTR_PROTO_EXEC_MODE
, exec_mode_spdval
);
235 EMIT(sync_req_attr
, SPD_ATTR_NEXT
, 0);
237 sync_req_proto_count
++;
241 * Causes the kernel to be re-synched with the contents of /etc/inet/algs
246 int sfd
= socket(PF_POLICY
, SOCK_RAW
, PF_POLICY_V1
);
249 struct spd_ext_actions
*act
;
250 struct spd_attribute
*attr
;
253 err(EXIT_FAILURE
, gettext("Unable to open policy socket"));
257 * Initialize the SPD message header and action. Some fields
258 * are set after having walked through the algorithms (number
259 * of algorithms, sizes, etc.)
261 msg
= (struct spd_msg
*)sync_req_buf
;
262 (void) memset(msg
, 0, sizeof (*msg
));
263 msg
->spd_msg_version
= PF_POLICY_V1
;
264 msg
->spd_msg_type
= SPD_UPDATEALGS
;
266 act
= (struct spd_ext_actions
*)(msg
+ 1);
267 act
->spd_actions_exttype
= SPD_EXT_ACTION
;
268 act
->spd_actions_reserved
= 0;
271 * Walk through the algorithms defined and populate the
274 sync_req_alg_count
= 0;
275 sync_req_proto_count
= 0;
276 sync_req_attr
= (struct spd_attribute
*)(act
+ 1);
277 algs_walker(synch_emit_alg
, synch_emit_proto
);
278 act
->spd_actions_count
= sync_req_alg_count
+ sync_req_proto_count
;
281 * Replace the last SPD_ATTR_NEXT attribute by a SPD_ATTR_END.
283 attr
= sync_req_attr
- 1;
284 attr
->spd_attr_tag
= SPD_ATTR_END
;
287 * Now that the message is built, compute its total length and
288 * update the length fields that depend on this value.
290 req_len
= (char *)sync_req_attr
- (char *)sync_req_buf
;
291 msg
->spd_msg_len
= SPD_8TO64(req_len
);
292 act
->spd_actions_len
= SPD_8TO64(req_len
- sizeof (*msg
));
294 /* ship the update request to spdsock */
295 cnt
= write(sfd
, sync_req_buf
, req_len
);
296 if (cnt
!= req_len
) {
298 err(EXIT_FAILURE
, gettext("algs update write failed"));
300 errx(EXIT_FAILURE
, gettext("algs update short write"));
302 /* err/errx call exit(). */
305 cnt
= read(sfd
, sync_req_buf
, req_len
);
308 err(EXIT_FAILURE
, gettext("algs update read failed"));
311 if (cnt
< sizeof (struct spd_msg
)) {
312 errx(EXIT_FAILURE
, gettext(
313 "algs update failed while reading reply (short read)"));
316 msg
= (struct spd_msg
*)sync_req_buf
;
317 if (msg
->spd_msg_errno
!= 0) {
318 errno
= msg
->spd_msg_errno
;
319 warn(gettext("algs update failed"));
320 if (msg
->spd_msg_diagnostic
!= 0) {
321 warnx("%s", spdsock_diag(msg
->spd_msg_diagnostic
));
330 list_kernel_algs(void)
332 int sfd
= socket(PF_POLICY
, SOCK_RAW
, PF_POLICY_V1
);
334 uint64_t reply_buf
[2048];
335 spd_ext_t
*exts
[SPD_EXT_MAX
+1];
337 struct spd_ext_actions
*actp
;
338 struct spd_attribute
*attr
, *endattr
;
339 uint64_t *start
, *end
;
340 struct ipsecalgent alg
;
341 uint_t cur_key
, cur_block
;
342 uint_t nkey_sizes
, nblock_sizes
, nparams
;
343 char diag_buf
[SPDSOCK_DIAG_BUF_LEN
];
346 err(EXIT_FAILURE
, gettext("Unable to open policy socket"));
349 (void) memset(&msg
, 0, sizeof (msg
));
350 msg
.spd_msg_version
= PF_POLICY_V1
;
351 msg
.spd_msg_type
= SPD_DUMPALGS
;
352 msg
.spd_msg_len
= SPD_8TO64(sizeof (msg
));
354 cnt
= write(sfd
, &msg
, sizeof (msg
));
355 if (cnt
!= sizeof (msg
)) {
357 err(EXIT_FAILURE
, gettext("dump algs write failed"));
359 errx(EXIT_FAILURE
, gettext("dump algs short write"));
361 /* err/errx call exit(). */
364 cnt
= read(sfd
, reply_buf
, sizeof (reply_buf
));
367 err(EXIT_FAILURE
, gettext("dump algs read failed"));
370 if (cnt
< sizeof (struct spd_msg
)) {
371 errx(EXIT_FAILURE
, gettext(
372 "dump algs failed while reading reply (short read)"));
377 retval
= spdsock_get_ext(exts
, (spd_msg_t
*)reply_buf
, SPD_8TO64(cnt
),
378 diag_buf
, SPDSOCK_DIAG_BUF_LEN
);
380 if (retval
== KGE_LEN
&& exts
[0]->spd_ext_len
== 0) {
382 * No algorithms are defined in the kernel, which caused
383 * the extension length to be zero, and spdsock_get_ext()
384 * to fail with a KGE_LEN error. This is not an error
385 * condition, so we return nicely.
388 } else if (retval
!= 0) {
389 if (strlen(diag_buf
) != 0)
390 warnx("%s", diag_buf
);
391 errx(EXIT_FAILURE
, gettext("invalid extension "
392 "in dump algs reply (%d)"), retval
);
395 if (exts
[SPD_EXT_ACTION
] == NULL
) {
397 gettext("action missing in dump algs reply"));
400 actp
= (struct spd_ext_actions
*)exts
[SPD_EXT_ACTION
];
401 start
= (uint64_t *)actp
;
402 end
= (start
+ actp
->spd_actions_len
);
403 endattr
= (struct spd_attribute
*)end
;
404 attr
= (struct spd_attribute
*)&actp
[1];
406 bzero(&alg
, sizeof (alg
));
407 nkey_sizes
= nblock_sizes
= 0;
409 (void) printf("Kernel list of algorithms:\n\n");
411 while (attr
< endattr
) {
412 switch (attr
->spd_attr_tag
) {
421 * Note that if the message received from the spdsock
422 * has a premature SPD_ATTR_END or SPD_ATTR_NEXT, this
423 * could cause the current algorithm to be only
424 * partially initialized.
426 alg
.a_alg_flags
|= ALG_FLAG_KERNELCHECKED
;
428 free(alg
.a_key_sizes
);
429 free(alg
.a_block_sizes
);
430 free(alg
.a_mech_name
);
431 free(alg
.a_mech_params
);
432 bzero(&alg
, sizeof (alg
));
433 nkey_sizes
= nblock_sizes
= 0;
436 case SPD_ATTR_ALG_ID
:
437 alg
.a_alg_num
= attr
->spd_attr_value
;
440 case SPD_ATTR_ALG_PROTO
:
441 alg
.a_proto_num
= attr
->spd_attr_value
;
444 case SPD_ATTR_ALG_INCRBITS
:
445 alg
.a_key_increment
= attr
->spd_attr_value
;
448 case SPD_ATTR_ALG_NKEYSIZES
:
449 nkey_sizes
= attr
->spd_attr_value
;
450 if (alg
.a_key_sizes
!= NULL
) {
451 errx(EXIT_FAILURE
, gettext("duplicate number "
452 "of keys in dump algs reply"));
454 alg
.a_key_sizes
= calloc(nkey_sizes
+ 1, sizeof (int));
455 if (alg
.a_key_sizes
== NULL
)
460 case SPD_ATTR_ALG_KEYSIZE
:
461 if (cur_key
>= nkey_sizes
) {
462 errx(EXIT_FAILURE
, gettext("too many key sizes"
463 " in dump algs reply"));
465 alg
.a_key_sizes
[cur_key
++] = attr
->spd_attr_value
;
468 case SPD_ATTR_ALG_NBLOCKSIZES
:
469 nblock_sizes
= attr
->spd_attr_value
;
470 if (alg
.a_block_sizes
!= NULL
) {
471 errx(EXIT_FAILURE
, gettext("duplicate number "
472 "of blocks in dump algs reply"));
474 alg
.a_block_sizes
= calloc(nblock_sizes
+ 1,
476 if (alg
.a_block_sizes
== NULL
)
481 case SPD_ATTR_ALG_BLOCKSIZE
:
482 if (cur_block
>= nblock_sizes
) {
483 errx(EXIT_FAILURE
, gettext("too many block "
484 "sizes in dump algs reply"));
486 alg
.a_block_sizes
[cur_block
++] = attr
->spd_attr_value
;
489 case SPD_ATTR_ALG_NPARAMS
:
490 nparams
= attr
->spd_attr_value
;
491 if (alg
.a_mech_params
!= NULL
) {
492 errx(EXIT_FAILURE
, gettext("duplicate number "
493 "of params in dump algs reply"));
495 alg
.a_mech_params
= calloc(nparams
+ 1,
497 if (alg
.a_mech_params
== NULL
)
502 case SPD_ATTR_ALG_PARAMS
:
503 if (cur_block
>= nparams
) {
504 errx(EXIT_FAILURE
, gettext("too many params "
505 "in dump algs reply"));
507 alg
.a_mech_params
[cur_block
++] = attr
->spd_attr_value
;
510 case SPD_ATTR_ALG_FLAGS
:
511 alg
.a_alg_flags
= attr
->spd_attr_value
;
514 case SPD_ATTR_ALG_MECHNAME
: {
517 if (alg
.a_mech_name
!= NULL
) {
518 errx(EXIT_FAILURE
, gettext(
519 "duplicate mech name in dump algs reply"));
522 alg
.a_mech_name
= malloc(attr
->spd_attr_value
);
523 if (alg
.a_mech_name
== NULL
)
526 mech_name
= (char *)(attr
+ 1);
527 bcopy(mech_name
, alg
.a_mech_name
, attr
->spd_attr_value
);
528 attr
= (struct spd_attribute
*)((uint64_t *)attr
+
529 SPD_8TO64(attr
->spd_attr_value
));
540 parse_intlist(char *args
, int *num_args
)
545 while ((holder
= strtok((holder
== NULL
) ? args
: NULL
, comma
)) !=
548 rc
= reallocarray(rc
, *num_args
+ 1, sizeof (int));
551 rc
[(*num_args
) - 1] = atoi(holder
);
552 if (rc
[(*num_args
) - 1] == 0)
553 usage(); /* Malformed integer list! */
563 struct ipsecalgent newbie
;
564 int num_names
= 0, num_block_sizes
= 0, num_key_sizes
= 0;
568 /* Parameter reality check... */
569 if (proto_number
== -1) {
570 if (proto_name
== NULL
) {
571 warnx(gettext("Missing protocol number."));
574 proto_number
= getipsecprotobyname(proto_name
);
575 if (proto_number
== -1) {
576 warnx(gettext("Unknown protocol."));
580 if (alg_number
== -1) {
581 warnx(gettext("Missing algorithm number."));
584 if (key_sizes_string
== NULL
) {
585 warnx(gettext("Missing key size(s)."));
588 if (alg_names_string
== NULL
) {
589 warnx(gettext("Missing algorithm name(s)."));
592 if (block_sizes_string
== NULL
) {
593 warnx(gettext("Missing block/MAC lengths"));
596 if (mech_name
== NULL
) {
597 warnx(gettext("Missing mechanism name."));
600 newbie
.a_proto_num
= proto_number
;
601 newbie
.a_alg_num
= alg_number
;
602 newbie
.a_key_increment
= increment
;
603 newbie
.a_mech_name
= mech_name
;
604 newbie
.a_alg_flags
= alg_flags
;
607 * The ALG_FLAG_VALID is somewhat irrelevant as an input from the
608 * user, the kernel will decide if the algorithm description is
609 * valid or not and set the ALG_FLAG_VALID when the user dumps
610 * the kernel tables. To avoid confusion when the user dumps the
611 * contents off the ipsecalgs file, we set the ALG_FLAG_VALID here.
613 newbie
.a_alg_flags
|= ALG_FLAG_VALID
;
614 while ((holder
= strtok((holder
== NULL
) ? flag_string
: NULL
,
616 alg_flags
= parse_flag(holder
, 0);
618 warnx(gettext("Invalid flag: %s\n"), holder
);
621 newbie
.a_alg_flags
|= alg_flags
;
623 newbie
.a_names
= NULL
;
624 while ((holder
= strtok((holder
== NULL
) ? alg_names_string
: NULL
,
626 newbie
.a_names
= reallocarray(newbie
.a_names
,
627 ++num_names
+ 1, sizeof (char *));
628 if (newbie
.a_names
== NULL
)
630 newbie
.a_names
[num_names
- 1] = holder
;
631 newbie
.a_names
[num_names
] = NULL
;
634 /* Extract block sizes. */
635 newbie
.a_block_sizes
= parse_intlist(block_sizes_string
,
637 newbie
.a_mech_params
= &mech_params
[0];
639 /* Extract key sizes. */
640 if ((holder
= strchr(key_sizes_string
, '-')) != NULL
) {
641 /* key sizes by range, key size increment required */
642 if (newbie
.a_key_increment
== 0) {
643 warnx(gettext("Missing key increment"));
646 newbie
.a_key_sizes
= calloc(sizeof (int),
647 LIBIPSEC_ALGS_KEY_NUM_VAL
);
648 if (newbie
.a_key_sizes
== NULL
)
653 * At this point, holder points to high, key_sizes_string
656 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
] =
657 atoi(key_sizes_string
);
658 if (newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
] == 0) {
659 warnx(gettext("Invalid lower key size range"));
662 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
] = atoi(holder
);
663 if (newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
] == 0) {
664 warnx(gettext("Invalid higher key size range"));
668 /* sanity check key range consistency */
669 if (newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
] >=
670 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
]) {
671 warnx(gettext("Invalid key size range (min >= max)"));
675 /* check key increment vs key range */
676 if (((newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
] -
677 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
]) %
678 newbie
.a_key_increment
) != 0) {
679 warnx(gettext("Key size increment"
680 " not consistent with key size range"));
684 /* default key size */
685 if (default_keylen
!= 0) {
686 /* check specified default key size */
688 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
] ||
690 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
] ||
692 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
]) %
693 newbie
.a_key_increment
) != 0) {
694 warnx(gettext("Default key size not consistent"
695 " with key size range"));
698 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_DEF_IDX
] =
701 /* min key size in range if not specified */
702 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_DEF_IDX
] =
703 newbie
.a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
];
706 /* key sizes by enumeration */
707 if (newbie
.a_key_increment
!= 0) {
708 warnx(gettext("Key increment must "
709 "not be specified with key sizes enumeration"));
712 newbie
.a_key_sizes
= parse_intlist(key_sizes_string
,
715 /* default key size */
716 if (default_keylen
!= 0 && default_keylen
!=
717 newbie
.a_key_sizes
[0]) {
719 * The default key size is not at the front of the
720 * list. Swap it with the first element of the list.
722 for (i
= 1; i
< num_key_sizes
; i
++) {
723 if (newbie
.a_key_sizes
[i
] == default_keylen
)
725 if (i
>= num_key_sizes
) {
726 warnx(gettext("Default key size not "
727 "in list of key sizes"));
730 newbie
.a_key_sizes
[i
] = newbie
.a_key_sizes
[0];
731 newbie
.a_key_sizes
[0] = default_keylen
;
737 if ((rc
= addipsecalg(&newbie
, adddel_flags
)) != 0) {
738 errx(EXIT_FAILURE
, gettext("addipsecalg() call failed: "
739 "%s"), ipsecalgs_diag(rc
));
742 free(newbie
.a_names
);
743 free(newbie
.a_block_sizes
);
744 free(newbie
.a_key_sizes
);
752 if ((rc
= addipsecproto(proto_name
, proto_number
, proto_exec_mode
,
755 errx(EXIT_FAILURE
, gettext(
756 "Cannot add protocol %1$d \"%2$s\": %3$s"), proto_number
,
757 proto_name
, ipsecalgs_diag(rc
));
766 if (proto_number
== -1) {
767 if (proto_name
== NULL
) {
768 warnx(gettext("Missing protocol number."));
771 proto_number
= getipsecprotobyname(proto_name
);
772 if (proto_number
== -1) {
773 errx(EXIT_FAILURE
, gettext(
774 "Unknown protocol \"%s\"."), proto_name
);
778 if (alg_number
== -1) {
779 if (alg_names_string
== NULL
) {
780 errx(EXIT_FAILURE
, gettext("Missing algorithm ID."));
782 if (strchr(alg_names_string
, ',') != NULL
) {
783 errx(EXIT_FAILURE
, gettext(
784 "Specify a single algorithm name for removal, "
787 if ((rc
= delipsecalgbyname(alg_names_string
, proto_number
))
789 errx(EXIT_FAILURE
, gettext(
790 "Could not remove algorithm %1$s: %2$s"),
791 alg_names_string
, ipsecalgs_diag(rc
));
794 if ((rc
= delipsecalgbynum(alg_number
, proto_number
)) != 0) {
795 errx(EXIT_FAILURE
, gettext(
796 "Could not remove algorithm %1$d: %2$s"),
797 alg_number
, ipsecalgs_diag(rc
));
807 if (proto_number
== -1) {
808 if (proto_name
== NULL
) {
809 warnx(gettext("Please specify protocol to remove."));
812 if ((rc
= delipsecprotobyname(proto_name
)) != 0) {
813 errx(EXIT_FAILURE
, gettext(
814 "Could not remove protocol %1$s: %2$s"),
815 proto_name
, ipsecalgs_diag(rc
));
818 if ((rc
= delipsecprotobynum(proto_number
)) != 0) {
819 errx(EXIT_FAILURE
, gettext(
820 "Could not remove protocol %1$d: %2$s"),
821 proto_number
, ipsecalgs_diag(rc
));
831 if (proto_number
== -1) {
832 if (proto_name
== NULL
) {
834 "Please specify protocol name or number."));
837 proto_number
= getipsecprotobyname(proto_name
);
838 if (proto_number
== -1) {
839 errx(EXIT_FAILURE
, gettext("Unknown protocol %s"),
844 if ((rc
= ipsecproto_set_exec_mode(proto_number
, proto_exec_mode
))
846 errx(EXIT_FAILURE
, gettext("Cannot set execution mode: %s"),
852 * Print a description of an algorithm to standard output.
855 dump_alg(struct ipsecalgent
*alg
)
860 /* protocol number */
861 (void) printf(gettext("\tProtocol number: %d\n"), alg
->a_proto_num
);
863 /* algorithm number */
864 (void) printf(gettext("\tAlgorithm number: %d\n"), alg
->a_alg_num
);
866 /* algorithm name(s) */
867 if (alg
->a_names
!= NULL
) {
868 (void) printf(gettext("\tAlgorithm names: "));
869 floater
= alg
->a_names
;
870 assert(floater
!= NULL
&& *floater
!= NULL
);
872 /* Assume at least one string. */
873 (void) printf("%s", *floater
);
874 if (*(++floater
) != NULL
)
876 } while (*floater
!= NULL
);
877 (void) putchar('\n');
881 (void) printf(gettext("\tMechanism Name: %s\n"), alg
->a_mech_name
);
883 /* block/MAC sizes */
884 (void) printf(gettext("\tBlock sizes or MAC sizes: "));
885 ifloater
= alg
->a_block_sizes
;
886 (void) list_ints(stdout
, ifloater
);
887 (void) putchar('\n');
890 (void) printf(gettext("\tKey sizes: "));
891 if (alg
->a_key_increment
!= 0)
892 /* key specified by range */
893 (void) printf(gettext(
894 "%1$d-%2$d, increment %3$d, default %4$d"),
895 alg
->a_key_sizes
[LIBIPSEC_ALGS_KEY_MIN_IDX
],
896 alg
->a_key_sizes
[LIBIPSEC_ALGS_KEY_MAX_IDX
],
897 alg
->a_key_increment
,
898 alg
->a_key_sizes
[LIBIPSEC_ALGS_KEY_DEF_IDX
]);
900 /* key specified by enumeration */
901 (void) list_ints(stdout
, alg
->a_key_sizes
);
902 (void) putchar('\n');
905 (void) printf(gettext("\tAlgorithm parameters: "));
906 ifloater
= alg
->a_mech_params
;
907 (void) list_ints(stdout
, ifloater
);
908 (void) putchar('\n');
911 (void) printf(gettext("\tAlgorithm flags: "));
912 (void) parse_flag(NULL
, alg
->a_alg_flags
);
914 (void) putchar('\n');
915 (void) putchar('\n');
919 * Print the description of a protocol.
922 dump_proto(uint_t proto_id
)
925 ipsecalgs_exec_mode_t exec_mode
;
927 /* protocol name and number */
928 proto_name
= getipsecprotobynum(proto_id
);
929 (void) printf(gettext("Protocol %1$d/%2$s "),
930 proto_id
, proto_name
!= NULL
? proto_name
: gettext("<unknown>"));
933 (void) printf("(%s", gettext("execution mode: "));
935 if (ipsecproto_get_exec_mode(proto_id
, &exec_mode
) != 0) {
936 (void) printf(gettext("<unknown>"));
939 case LIBIPSEC_ALGS_EXEC_SYNC
:
940 (void) printf("sync");
942 case LIBIPSEC_ALGS_EXEC_ASYNC
:
943 (void) printf("async");
948 (void) printf(")\n\n");
955 * Algorithm walker table. Call proto_action() for each protocol,
956 * and alg_action() for each algorithm.
959 algs_walker(void (*alg_action
)(struct ipsecalgent
*),
960 void (*proto_action
)(uint_t
))
962 int *proto_nums
, proto_count
, i
;
963 int *alg_nums
, alg_count
, j
;
964 struct ipsecalgent
*alg
;
966 proto_nums
= getipsecprotos(&proto_count
);
967 if (proto_nums
== NULL
) {
968 errx(EXIT_FAILURE
, gettext("getipsecprotos() failed."));
971 for (i
= 0; i
< proto_count
; i
++) {
973 if (proto_action
!= NULL
)
974 proto_action(proto_nums
[i
]);
976 alg_nums
= getipsecalgs(&alg_count
, proto_nums
[i
]);
977 if (alg_nums
== NULL
) {
979 errx(EXIT_FAILURE
, gettext("getipsecalgs() failed."));
982 for (j
= 0; j
< alg_count
; j
++) {
983 alg
= getipsecalgbynum(alg_nums
[j
], proto_nums
[i
],
987 if (alg_action
!= NULL
)
989 freeipsecalgent(alg
);
997 * Use just the libnsl/libipsecutil APIs to dump out all of the algorithms.
1002 /* Yes, I'm aware that this'll produce TWO newlines. */
1003 (void) puts(gettext(
1004 "List of algorithms, grouped by IPsec protocol:\n"));
1006 algs_walker(dump_alg
, dump_proto
);
1010 try_int(char *optarg
, const char *what
)
1012 int rc
= atoi(optarg
);
1015 warnx(gettext("Invalid %s value"), what
);
1022 try_cmd(cmd_t newcmd
)
1024 if (cmd
!= CMD_NONE
)
1030 main(int argc
, char *argv
[])
1036 (void) setlocale(LC_ALL
, "");
1037 #if !defined(TEXT_DOMAIN)
1038 #define TEXT_DOMAIN "SYS_TEST"
1040 (void) textdomain(TEXT_DOMAIN
);
1044 return (EXIT_SUCCESS
);
1047 while ((c
= getopt(argc
, argv
,
1048 "aflrRsb:p:P:i:k:K:m:n:N:e:S:M:I:F:")) != EOF
) {
1054 /* multiple occurences of -f are harmless */
1055 adddel_flags
= LIBIPSEC_ALGS_ADD_FORCE
;
1058 try_cmd(CMD_LIST_KERNEL
);
1064 try_cmd(CMD_DEL_PROTO
);
1067 /* multiple occurences of -s are harmless */
1068 synch_kernel
= B_TRUE
;
1071 if (alg_names_string
!= NULL
)
1073 alg_names_string
= optarg
;
1076 if (block_sizes_string
!= NULL
)
1078 block_sizes_string
= optarg
;
1081 if (proto_name
!= NULL
)
1083 proto_name
= optarg
;
1086 if (proto_number
!= -1)
1088 proto_number
= try_int(optarg
,
1089 gettext("protocol number"));
1092 if (exec_mode_string
!= NULL
)
1094 exec_mode_string
= optarg
;
1095 if (_str_to_ipsec_exec_mode(exec_mode_string
,
1096 &proto_exec_mode
) == -1) {
1097 warnx(gettext("Invalid execution mode \"%s\""),
1105 increment
= try_int(optarg
,
1106 gettext("key size increment"));
1109 if (key_sizes_string
!= NULL
)
1111 key_sizes_string
= optarg
;
1114 if (default_keylen
!= 0)
1116 default_keylen
= try_int(optarg
,
1117 gettext("default key size"));
1120 if (mech_name
!= NULL
)
1125 if (alg_number
!= -1)
1127 alg_number
= try_int(optarg
,
1128 gettext("algorithm number"));
1131 if (mech_params
[iv_len
] != 0)
1133 mech_params
[iv_len
] = try_int(optarg
,
1134 gettext("Initialization Vector length"));
1137 if (mech_params
[mac_len
] != 0)
1139 mech_params
[mac_len
] = try_int(optarg
,
1140 gettext("Integrity Check Vector length"));
1143 if (mech_params
[salt_bytes
] != 0)
1145 mech_params
[salt_bytes
] = try_int(optarg
,
1146 gettext("Salt length"));
1150 * Multiple flags can be specified, the results
1151 * are OR'd together. Flags can be specified as
1152 * number or a comma separated string
1154 flags
= atoi(optarg
);
1159 flag_string
= optarg
;
1168 * When both protocol name (-p) and protocol number (-P) are
1169 * specified, a new protocol is being defined.
1171 if (proto_number
!= -1 && proto_name
!= NULL
)
1172 try_cmd(CMD_ADD_PROTO
);
1173 else if (exec_mode_string
!= NULL
)
1174 try_cmd(CMD_EXEC_MODE
);
1177 * Process specified command.
1195 case CMD_LIST_KERNEL
:
1207 * This will only work in the global zone or
1208 * a zone with an exclusive IP stack.
1210 if ((zoneid
= getzoneid()) == 0) {
1213 if (zone_getattr(zoneid
, ZONE_ATTR_FLAGS
, &flags
,
1214 sizeof (flags
)) < 0) {
1215 err(EXIT_FAILURE
, gettext(
1216 "Unable to determine zone IP type"));
1218 if (flags
& ZF_NET_EXCL
) {
1221 (void) printf(gettext("Synchronization with "
1222 "kernel not appropriate in this zone.\n"));
1227 return (EXIT_SUCCESS
);