changeset 864:75df3e9f93de

PSARC/2005/290 pktool(1) alternate token support PSARC/2005/634 pktool CLI update 6288840 pktool(1) alternate token support 6332420 change pktool CLI to use attr=value format
author dinak
date Mon, 07 Nov 2005 17:38:08 -0800
parents 56b591ba4423
children 4223fbdac5f3
files usr/src/cmd/cmd-crypto/pktool/common.c usr/src/cmd/cmd-crypto/pktool/common.h usr/src/cmd/cmd-crypto/pktool/delete.c usr/src/cmd/cmd-crypto/pktool/export.c usr/src/cmd/cmd-crypto/pktool/import.c usr/src/cmd/cmd-crypto/pktool/list.c usr/src/cmd/cmd-crypto/pktool/pktool.c usr/src/cmd/cmd-crypto/pktool/setpin.c
diffstat 8 files changed, 491 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-crypto/pktool/common.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/common.c	Mon Nov 07 17:38:08 2005 -0800
@@ -53,6 +53,20 @@
 static boolean_t	session_writable = B_FALSE;
 static boolean_t	logged_in = B_FALSE;
 
+/* Supporting structures and global variables for getopt_av(). */
+typedef struct	av_opts_s {
+	int		shortnm;	/* short name character */
+	char		*longnm;	/* long name string, NOT terminated */
+	int		longnm_len;	/* length of long name string */
+	boolean_t	has_arg;	/* takes optional argument */
+} av_opts;
+static av_opts		*opts_av = NULL;
+static const char	*_save_optstr = NULL;
+static int		_save_numopts = 0;
+
+int			optind_av = 1;
+char			*optarg_av = NULL;
+
 /*
  * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
  * along with setting/resetting state variables.
@@ -604,6 +618,120 @@
 }
 
 /*
+ * Returns pointer to either null-terminator or next unescaped colon.  The
+ * string to be extracted starts at the beginning and goes until one character
+ * before this pointer.  If NULL is returned, the string itself is NULL.
+ */
+static char *
+find_unescaped_colon(char *str)
+{
+	char *end;
+
+	if (str == NULL)
+		return (NULL);
+
+	while ((end = strchr(str, ':')) != NULL) {
+		if (end != str && *(end-1) != '\\')
+			return (end);
+		str = end + 1;		/* could point to null-terminator */
+	}
+	if (end == NULL)
+		end = strchr(str, '\0');
+	return (end);
+}
+
+/*
+ * Compresses away any characters escaped with backslash from given string.
+ * The string is altered in-place.  Example, "ab\:\\e" becomes "ab:\e".
+ */
+static void
+unescape_str(char *str)
+{
+	boolean_t	escaped = B_FALSE;
+	char		*mark;
+
+	if (str == NULL)
+		return;
+
+	for (mark = str; *str != '\0'; str++) {
+		if (*str != '\\' || escaped == B_TRUE) {
+			*mark++ = *str;
+			escaped = B_FALSE;
+		} else {
+			escaped = B_TRUE;
+		}
+	}
+	*mark = '\0';
+}
+
+/*
+ * Given a colon-separated token specifier, this functions splits it into
+ * its label, manufacturer ID (if any), and serial number (if any).  Literal
+ * colons within the label/manuf/serial can be escaped with a backslash.
+ * Fields can left blank and trailing colons can be omitted, however leading
+ * colons are required as placeholders.  For example, these are equivalent:
+ *	(a) "lbl", "lbl:", "lbl::"	(b) "lbl:man", "lbl:man:"
+ * but these are not:
+ *	(c) "man", ":man"	(d) "ser", "::ser"
+ * Furthermore, the token label is required always.
+ *
+ * The buffer containing the token specifier is altered by replacing the
+ * colons to null-terminators, and pointers returned are pointers into this
+ * string.  No new memory is allocated.
+ */
+int
+parse_token_spec(char *token_spec, char **token_name, char **manuf_id,
+	char **serial_no)
+{
+	char	*mark;
+
+	if (token_spec == NULL || *token_spec == '\0') {
+		cryptodebug("token specifier is empty");
+		return (-1);
+	}
+
+	*token_name = NULL;
+	*manuf_id = NULL;
+	*serial_no = NULL;
+
+	/* Token label (required) */
+	mark = find_unescaped_colon(token_spec);
+	*token_name = token_spec;
+	if (*mark != '\0')
+		*mark++ = '\0';		/* mark points to next field, if any */
+	unescape_str(*token_name);
+
+	if (*(*token_name) == '\0') {	/* token label is required */
+		cryptodebug("no token label found");
+		return (-1);
+	}
+
+	if (*mark == '\0' || *(mark+1) == '\0')		/* no more fields */
+		return (0);
+	token_spec = mark;
+
+	/* Manufacturer identifier (optional) */
+	mark = find_unescaped_colon(token_spec);
+	*manuf_id = token_spec;
+	if (*mark != '\0')
+		*mark++ = '\0';		/* mark points to next field, if any */
+	unescape_str(*manuf_id);
+
+	if (*mark == '\0' || *(mark+1) == '\0')		/* no more fields */
+		return (0);
+	token_spec = mark;
+
+	/* Serial number (optional) */
+	mark = find_unescaped_colon(token_spec);
+	*serial_no = token_spec;
+	if (*mark != '\0')
+		*mark++ = '\0';		/* null-terminate, just in case */
+	unescape_str(*serial_no);
+
+	return (0);
+}
+
+/*
  * Constructs a fully qualified token name from its label, manufacturer ID
  * (if any), and its serial number (if any).  Note that the given buf must
  * be big enough.  Do NOT i18n/l10n.
@@ -1081,3 +1209,116 @@
 	*buf = (CK_DATE *)attr->pValue;
 	*buflen = attr->ulValueLen;
 }
+
+/*
+ * Breaks out the getopt-style option string into a structure that can be
+ * traversed later for calls to getopt_av().  Option string is NOT altered,
+ * but the struct fields point to locations within option string.
+ */
+static int
+populate_opts(char *optstring)
+{
+	int		i;
+	av_opts		*temp;
+	char		*marker;
+
+	if (optstring == NULL || *optstring == '\0')
+		return (0);
+
+	/*
+	 * This tries to imitate getopt(3c) Each option must conform to:
+	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
+	 * If long name is missing, the short name is used for long name.
+	 */
+	for (i = 0; *optstring != '\0'; i++) {
+		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
+		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
+			free(opts_av);
+			opts_av = NULL;
+			return (0);
+		} else
+			opts_av = (av_opts *)temp;
+
+		marker = optstring;		/* may need optstring later */
+
+		opts_av[i].shortnm = *marker++;	/* set short name */
+
+		if (*marker == ':') {		/* check for opt arg */
+			marker++;
+			opts_av[i].has_arg = B_TRUE;
+		}
+
+		if (*marker == '(') {		/* check and set long name */
+			marker++;
+			opts_av[i].longnm = marker;
+			opts_av[i].longnm_len = strcspn(marker, ")");
+			optstring = marker + opts_av[i].longnm_len + 1;
+		} else {
+			/* use short name option character */
+			opts_av[i].longnm = optstring;
+			opts_av[i].longnm_len = 1;
+			optstring = marker;
+		}
+	}
+
+	return (i);
+}
+
+/*
+ * getopt_av() is very similar to getopt(3c) in that the takes an option
+ * string, compares command line arguments for matches, and returns a single
+ * letter option when a match is found.  However, getopt_av() differs from
+ * getopt(3c) by requiring that only longname options and values be found
+ * on the command line and all leading dashes are omitted.  In other words,
+ * it tries to enforce only longname "option=value" arguments on the command
+ * line.  Boolean options are not allowed either.
+ */
+int
+getopt_av(int argc, char * const *argv, const char *optstring)
+{
+	int	i;
+	int	len;
+
+	if (optind_av >= argc)
+		return (EOF);
+
+	/* First time or when optstring changes from previous one */
+	if (_save_optstr != optstring) {
+		if (opts_av != NULL)
+		    free(opts_av);
+		opts_av = NULL;
+		_save_optstr = optstring;
+		_save_numopts = populate_opts((char *)optstring);
+	}
+
+	for (i = 0; i < _save_numopts; i++) {
+		if (strcmp(argv[optind_av], "--") == 0) {
+			optind_av++;
+			break;
+		}
+
+		len = strcspn(argv[optind_av], "=");
+
+		if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
+		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
+			/* matched */
+			if (!opts_av[i].has_arg) {
+				optind_av++;
+				return (opts_av[i].shortnm);
+			}
+
+			/* needs optarg */
+			if (argv[optind_av][len] == '=') {
+				optarg_av = &(argv[optind_av][len+1]);
+				optind_av++;
+				return (opts_av[i].shortnm);
+			}
+
+			optarg_av = NULL;
+			optind_av++;
+			return ((int)'?');
+		}
+	}
+
+	return (EOF);
+}
--- a/usr/src/cmd/cmd-crypto/pktool/common.h	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/common.h	Mon Nov 07 17:38:08 2005 -0800
@@ -104,6 +104,8 @@
 extern CK_RV	find_objs(CK_SESSION_HANDLE sess, int obj_type,
 		    CK_BYTE *label, CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count);
 
+extern int	parse_token_spec(char *spec, char **label, char **manuf,
+		    char **buf);
 extern void	full_token_name(char *token, char *manuf, char *serial,
 		    char *buf);
 
@@ -124,6 +126,10 @@
 extern void	copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf,
 		    CK_ULONG *buflen);
 
+extern int	getopt_av(int argc, char * const argv[], const char *optstring);
+extern char	*optarg_av;
+extern int	optind_av;
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/cmd/cmd-crypto/pktool/delete.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/delete.c	Mon Nov 07 17:38:08 2005 -0800
@@ -45,11 +45,13 @@
 pk_delete(int argc, char *argv[])
 {
 	int		opt;
-	extern int	optind;
-	extern char	*optarg;
+	extern int	optind_av;
+	extern char	*optarg_av;
+	char		*token_spec = NULL;
 	char		*token_name = NULL;
 	char		*manuf_id = NULL;
 	char		*serial_no = NULL;
+	char		*type_spec = NULL;
 	char		full_name[FULL_NAME_LEN];
 	boolean_t	public_objs = B_FALSE;
 	boolean_t	private_objs = B_FALSE;
@@ -69,21 +71,23 @@
 	cryptodebug("inside pk_delete");
 
 	/* Parse command line options.  Do NOT i18n/l10n. */
-	while ((opt = getopt(argc, argv, "p(private)P(public)l:(label)")) !=
-	    EOF) {
+	while ((opt = getopt_av(argc, argv,
+	    "T:(token)y:(objtype)l:(label)")) != EOF) {
 		switch (opt) {
-		case 'p':	/* private objects */
-			private_objs = B_TRUE;
-			obj_type |= PK_PRIVATE_OBJ;
+		case 'T':	/* token specifier */
+			if (token_spec)
+				return (PK_ERR_USAGE);
+			token_spec = optarg_av;
 			break;
-		case 'P':	/* public objects */
-			public_objs = B_TRUE;
-			obj_type |= PK_PUBLIC_OBJ;
+		case 'y':	/* object type:  public, private, both */
+			if (type_spec)
+				return (PK_ERR_USAGE);
+			type_spec = optarg_av;
 			break;
 		case 'l':	/* objects with specific label */
 			if (object_label)
 				return (PK_ERR_USAGE);
-			object_label = (CK_BYTE *)optarg;
+			object_label = (CK_BYTE *)optarg_av;
 			break;
 		default:
 			return (PK_ERR_USAGE);
@@ -91,6 +95,45 @@
 		}
 	}
 
+	/* If no token is specified, default is to use softtoken. */
+	if (token_spec == NULL) {
+		token_name = SOFT_TOKEN_LABEL;
+		manuf_id = SOFT_MANUFACTURER_ID;
+		serial_no = SOFT_TOKEN_SERIAL;
+	} else {
+		/*
+		 * Parse token specifier into token_name, manuf_id, serial_no.
+		 * Token_name is required; manuf_id and serial_no are optional.
+		 */
+		if (parse_token_spec(token_spec, &token_name, &manuf_id,
+		    &serial_no) < 0)
+			return (PK_ERR_USAGE);
+	}
+
+	/* If no object type specified, default is public objects. */
+	if (!type_spec) {
+		public_objs = B_TRUE;
+	} else {
+		/*
+		 * Otherwise, the object type must be "public", "private",
+		 * or "both".
+		 */
+		if (strcmp(type_spec, "private") == 0) {
+			private_objs = B_TRUE;
+		} else if (strcmp(type_spec, "public") == 0) {
+			public_objs = B_TRUE;
+		} else if (strcmp(type_spec, "both") == 0) {
+			private_objs = B_TRUE;
+			public_objs = B_TRUE;
+		} else
+			return (PK_ERR_USAGE);
+	}
+
+	if (private_objs)
+		obj_type |= PK_PRIVATE_OBJ;
+	if (public_objs)
+		obj_type |= PK_PUBLIC_OBJ;
+
 	/* At least one of public, private, or object label is required. */
 	if (!private_objs && !public_objs && object_label == NULL)
 		return (PK_ERR_USAGE);
@@ -103,19 +146,12 @@
 		obj_type = PK_ALL_OBJ;
 
 	/* No additional args allowed. */
-	argc -= optind;
-	argv += optind;
+	argc -= optind_av;
+	argv += optind_av;
 	if (argc)
 		return (PK_ERR_USAGE);
 	/* Done parsing command line options. */
 
-	/* Delete operation only supported on softtoken. */
-	if (token_name == NULL)
-		token_name = SOFT_TOKEN_LABEL;
-	if (manuf_id == NULL)
-		manuf_id = SOFT_MANUFACTURER_ID;
-	if (serial_no == NULL)
-		serial_no = SOFT_TOKEN_SERIAL;
 	full_token_name(token_name, manuf_id, serial_no, full_name);
 
 	/* Find the slot with token. */
--- a/usr/src/cmd/cmd-crypto/pktool/export.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/export.c	Mon Nov 07 17:38:08 2005 -0800
@@ -1201,6 +1201,10 @@
 int
 pk_export(int argc, char *argv[])
 {
+	int		opt;
+	extern int	optind_av;
+	extern char	*optarg_av;
+	char		*token_spec = NULL;
 	char		*token_name = NULL;
 	char		*manuf_id = NULL;
 	char		*serial_no = NULL;
@@ -1230,15 +1234,49 @@
 
 	cryptodebug("inside pk_export");
 
-	/* Get rid of subcommand work "export". */
-	argc--;
-	argv++;
+	/* Parse command line options.  Do NOT i18n/l10n. */
+	while ((opt = getopt_av(argc, argv, "T:(token)o:(outfile)")) != EOF) {
+		switch (opt) {
+		case 'T':	/* token specifier */
+			if (token_spec)
+				return (PK_ERR_USAGE);
+			token_spec = optarg_av;
+			break;
+		case 'o':	/* output file name */
+			if (filename)
+				return (PK_ERR_USAGE);
+			filename = optarg_av;
+			break;
+		default:
+			return (PK_ERR_USAGE);
+			break;
+		}
+	}
 
-	/* One additional arg required:  filename. */
-	if (argc != 1)
+	/* If nothing is specified, default is to use softtoken. */
+	if (token_spec == NULL) {
+		token_name = SOFT_TOKEN_LABEL;
+		manuf_id = SOFT_MANUFACTURER_ID;
+		serial_no = SOFT_TOKEN_SERIAL;
+	} else {
+		/*
+		 * Parse token specifier into token_name, manuf_id, serial_no.
+		 * Token_name is required; manuf_id and serial_no are optional.
+		 */
+		if (parse_token_spec(token_spec, &token_name, &manuf_id,
+		    &serial_no) < 0)
+			return (PK_ERR_USAGE);
+	}
+
+	/* Filename arg is required. */
+	if (filename == NULL)
 		return (PK_ERR_USAGE);
 
-	filename = argv[0];
+	/* No additional args allowed. */
+	argc -= optind_av;
+	argv += optind_av;
+	if (argc)
+		return (PK_ERR_USAGE);
 	/* Done parsing command line options. */
 
 	/* Check if the file exists and might be overwritten. */
@@ -1251,13 +1289,6 @@
 		}
 	}
 
-	/* Export operation only supported on softtoken. */
-	if (token_name == NULL)
-		token_name = SOFT_TOKEN_LABEL;
-	if (manuf_id == NULL)
-		manuf_id = SOFT_MANUFACTURER_ID;
-	if (serial_no == NULL)
-		serial_no = SOFT_TOKEN_SERIAL;
 	full_token_name(token_name, manuf_id, serial_no, full_name);
 
 	/* Find the slot with token. */
--- a/usr/src/cmd/cmd-crypto/pktool/import.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/import.c	Mon Nov 07 17:38:08 2005 -0800
@@ -789,6 +789,10 @@
 int
 pk_import(int argc, char *argv[])
 {
+	int		opt;
+	extern int	optind_av;
+	extern char	*optarg_av;
+	char		*token_spec = NULL;
 	char		*token_name = NULL;
 	char		*manuf_id = NULL;
 	char		*serial_no = NULL;
@@ -812,15 +816,49 @@
 
 	cryptodebug("inside pk_import");
 
-	/* Get rid of subcommand word "import". */
-	argc--;
-	argv++;
+	/* Parse command line options.  Do NOT i18n/l10n. */
+	while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)")) != EOF) {
+		switch (opt) {
+		case 'T':	/* token specifier */
+			if (token_spec)
+				return (PK_ERR_USAGE);
+			token_spec = optarg_av;
+			break;
+		case 'i':	/* input file name */
+			if (filename)
+				return (PK_ERR_USAGE);
+			filename = optarg_av;
+			break;
+		default:
+			return (PK_ERR_USAGE);
+			break;
+		}
+	}
 
-	/* One additional arg required:  filename. */
-	if (argc != 1)
+	/* If nothing is specified, default is to use softtoken. */
+	if (token_spec == NULL) {
+		token_name = SOFT_TOKEN_LABEL;
+		manuf_id = SOFT_MANUFACTURER_ID;
+		serial_no = SOFT_TOKEN_SERIAL;
+	} else {
+		/*
+		 * Parse token specifier into token_name, manuf_id, serial_no.
+		 * Token_name is required; manuf_id and serial_no are optional.
+		 */
+		if (parse_token_spec(token_spec, &token_name, &manuf_id,
+		    &serial_no) < 0)
+			return (PK_ERR_USAGE);
+	}
+
+	/* Filename arg is required. */
+	if (filename == NULL)
 		return (PK_ERR_USAGE);
 
-	filename = argv[0];
+	/* No additional args allowed. */
+	argc -= optind_av;
+	argv += optind_av;
+	if (argc)
+		return (PK_ERR_USAGE);
 	/* Done parsing command line options. */
 
 	/* Check that the file exists and is non-empty. */
@@ -840,13 +878,6 @@
 		return (CKR_OK);
 	}
 
-	/* Import operation only supported on softtoken. */
-	if (token_name == NULL)
-		token_name = SOFT_TOKEN_LABEL;
-	if (manuf_id == NULL)
-		manuf_id = SOFT_MANUFACTURER_ID;
-	if (serial_no == NULL)
-		serial_no = SOFT_TOKEN_SERIAL;
 	full_token_name(token_name, manuf_id, serial_no, full_name);
 
 	/* Find the slot with token. */
--- a/usr/src/cmd/cmd-crypto/pktool/list.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/list.c	Mon Nov 07 17:38:08 2005 -0800
@@ -837,11 +837,13 @@
 pk_list(int argc, char *argv[])
 {
 	int			opt;
-	extern int		optind;
-	extern char		*optarg;
+	extern int		optind_av;
+	extern char		*optarg_av;
+	char			*token_spec = NULL;
 	char			*token_name = NULL;
 	char			*manuf_id = NULL;
 	char			*serial_no = NULL;
+	char			*type_spec = NULL;
 	char			full_name[FULL_NAME_LEN];
 	boolean_t		public_objs = B_FALSE;
 	boolean_t		private_objs = B_FALSE;
@@ -863,21 +865,23 @@
 	cryptodebug("inside pk_list");
 
 	/* Parse command line options.  Do NOT i18n/l10n. */
-	while ((opt = getopt(argc, argv, "p(private)P(public)l:(label)")) !=
-	    EOF) {
+	while ((opt = getopt_av(argc, argv,
+	    "T:(token)y:(objtype)l:(label)")) != EOF) {
 		switch (opt) {
-		case 'p':	/* private objects */
-			private_objs = B_TRUE;
-			obj_type |= PK_PRIVATE_OBJ;
+		case 'T':	/* token specifier */
+			if (token_spec)
+				return (PK_ERR_USAGE);
+			token_spec = optarg_av;
 			break;
-		case 'P':	/* public objects */
-			public_objs = B_TRUE;
-			obj_type |= PK_PUBLIC_OBJ;
+		case 'y':	/* object type:  public, private, both */
+			if (type_spec)
+				return (PK_ERR_USAGE);
+			type_spec = optarg_av;
 			break;
 		case 'l':	/* object with specific label */
 			if (list_label)
 				return (PK_ERR_USAGE);
-			list_label = (CK_BYTE *)optarg;
+			list_label = (CK_BYTE *)optarg_av;
 			break;
 		default:
 			return (PK_ERR_USAGE);
@@ -885,26 +889,52 @@
 		}
 	}
 
-	/* If nothing specified, default is public objects. */
-	if (!public_objs && !private_objs) {
-		public_objs = B_TRUE;
-		obj_type |= PK_PUBLIC_OBJ;
+	/* If no token is specified, default is to use softtoken. */
+	if (token_spec == NULL) {
+		token_name = SOFT_TOKEN_LABEL;
+		manuf_id = SOFT_MANUFACTURER_ID;
+		serial_no = SOFT_TOKEN_SERIAL;
+	} else {
+		/*
+		 * Parse token specifier into token_name, manuf_id, serial_no.
+		 * Token_name is required; manuf_id and serial_no are optional.
+		 */
+		if (parse_token_spec(token_spec, &token_name, &manuf_id,
+		    &serial_no) < 0)
+			return (PK_ERR_USAGE);
 	}
 
+	/* If no object type specified, default is public objects. */
+	if (!type_spec) {
+		public_objs = B_TRUE;
+	} else {
+		/*
+		 * Otherwise, the object type must be "public", "private",
+		 * or "both".
+		 */
+		if (strcmp(type_spec, "private") == 0) {
+			private_objs = B_TRUE;
+		} else if (strcmp(type_spec, "public") == 0) {
+			public_objs = B_TRUE;
+		} else if (strcmp(type_spec, "both") == 0) {
+			private_objs = B_TRUE;
+			public_objs = B_TRUE;
+		} else
+			return (PK_ERR_USAGE);
+	}
+
+	if (private_objs)
+		obj_type |= PK_PRIVATE_OBJ;
+	if (public_objs)
+		obj_type |= PK_PUBLIC_OBJ;
+
 	/* No additional args allowed. */
-	argc -= optind;
-	argv += optind;
+	argc -= optind_av;
+	argv += optind_av;
 	if (argc)
 		return (PK_ERR_USAGE);
 	/* Done parsing command line options. */
 
-	/* List operation only supported on softtoken. */
-	if (token_name == NULL)
-		token_name = SOFT_TOKEN_LABEL;
-	if (manuf_id == NULL)
-		manuf_id = SOFT_MANUFACTURER_ID;
-	if (serial_no == NULL)
-		serial_no = SOFT_TOKEN_SERIAL;
 	full_token_name(token_name, manuf_id, serial_no, full_name);
 
 	/* Find the slot with token. */
--- a/usr/src/cmd/cmd-crypto/pktool/pktool.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/pktool.c	Mon Nov 07 17:38:08 2005 -0800
@@ -69,15 +69,19 @@
 /* Command structure for verbs and their actions.  Do NOT i18n/l10n. */
 static verbcmd	cmds[] = {
 	{ "tokens",	pk_tokens,	0,	"tokens" },
-	{ "setpin",	pk_setpin,	0,	"setpin" },
-	{ "list",	pk_list,	0,	"list [-p] [-P] [-l <label>]"
-	    "\n\t\tor list [--public] [--private] [--label[=]<label>]" },
+	{ "setpin",	pk_setpin,	0,
+	    "setpin [token=<token>[:<manuf>[:<serial>]]]" },
+	{ "list",	pk_list,	0,
+	    "list [token=<token>[:<manuf>[:<serial>]]] "
+	    "[objtype=private|public|both] [label=<label>]" },
 	{ "delete",	pk_delete,	0,
-	    "delete { [-p] [-P] [-l <label>] }"
-	    "\n\t\tor delete { [--public] [--private] [--label[=]<label>] }" },
-	{ "import",	pk_import,	0,	"import <file>" },
-	{ "export",	pk_export,	0,	"export <file>" },
-	{ "-?",		pk_help,	0,	"--help\t(help and usage)" },
+	    "delete [token=<token>[:<manuf>[:<serial>]]] "
+	    "{ [objtype=private|public|both] [label=<label>] }" },
+	{ "import",	pk_import,	0,
+	    "import [token=<token>[:<manuf>[:<serial>]]] infile=<file>" },
+	{ "export",	pk_export,	0,
+	    "export [token=<token>[:<manuf>[:<serial>]]] outfile=<file>" },
+	{ "-?",		pk_help,	0,	"help\t(help and usage)" },
 };
 static int	num_cmds = sizeof (cmds) / sizeof (verbcmd);
 
--- a/usr/src/cmd/cmd-crypto/pktool/setpin.c	Mon Nov 07 17:36:34 2005 -0800
+++ b/usr/src/cmd/cmd-crypto/pktool/setpin.c	Mon Nov 07 17:38:08 2005 -0800
@@ -48,6 +48,10 @@
 pk_setpin(int argc, char *argv[])
 /* ARGSUSED */
 {
+	int		opt;
+	extern int	optind_av;
+	extern char	*optarg_av;
+	char		*token_spec = NULL;
 	char		*token_name = NULL;
 	char		*manuf_id = NULL;
 	char		*serial_no = NULL;
@@ -61,26 +65,42 @@
 
 	cryptodebug("inside pk_setpin");
 
-	/* Get rid of subcommand word "setpin". */
-	argc--;
-	argv++;
+	/* Parse command line options.  Do NOT i18n/l10n. */
+	while ((opt = getopt_av(argc, argv, "T:(token)")) != EOF) {
+		switch (opt) {
+		case 'T':	/* token specifier */
+			if (token_spec)
+				return (PK_ERR_USAGE);
+			token_spec = optarg_av;
+			break;
+		default:
+			return (PK_ERR_USAGE);
+			break;
+		}
+	}
+
+	/* If nothing is specified, default is to use softtoken. */
+	if (token_spec == NULL) {
+		token_name = SOFT_TOKEN_LABEL;
+		manuf_id = SOFT_MANUFACTURER_ID;
+		serial_no = SOFT_TOKEN_SERIAL;
+	} else {
+		/*
+		 * Parse token specifier into token_name, manuf_id, serial_no.
+		 * Token_name is required; manuf_id and serial_no are optional.
+		 */
+		if (parse_token_spec(token_spec, &token_name, &manuf_id,
+		    &serial_no) < 0)
+			return (PK_ERR_USAGE);
+	}
 
 	/* No additional args allowed. */
+	argc -= optind_av;
+	argv += optind_av;
 	if (argc != 0)
 		return (PK_ERR_USAGE);
 	/* Done parsing command line options. */
 
-	/*
-	 * Token_name, manuf_id, and serial_no are all optional.
-	 * If unspecified, token_name must have a default value
-	 * at least, so set it to the default softtoken value.
-	 */
-	if (token_name == NULL)
-		token_name = SOFT_TOKEN_LABEL;
-	if (manuf_id == NULL)
-		manuf_id = SOFT_MANUFACTURER_ID;
-	if (serial_no == NULL)
-		serial_no = SOFT_TOKEN_SERIAL;
 	full_token_name(token_name, manuf_id, serial_no, full_name);
 
 	/* Find the slot with token. */