1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <wchar.h>
29 #include <widec.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <libintl.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <syslog.h>
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <wctype.h>
45 #include <assert.h>
46 
47 #include <ima.h>
48 #include <sys/scsi/adapters/iscsi_protocol.h>
49 #include <sys/scsi/adapters/iscsi_if.h>
50 
51 #include "cmdparse.h"
52 #include "sun_ima.h"
53 #include "iscsiadm.h"
54 
55 #define	VERSION_STRING_MAX_LEN	10
56 #define	MAX_LONG_CHAR_LEN 19
57 
58 #define	MAX_AUTH_METHODS 5
59 /*
60  * Version number:
61  *  MAJOR - This should only change when there is an incompatible change made
62  *  to the interfaces or the output.
63  *
64  *  MINOR - This should change whenever there is a new command or new feature
65  *  with no incompatible change.
66  */
67 #define	VERSION_STRING_MAJOR	    "1"
68 #define	VERSION_STRING_MINOR	    "0"
69 
70 #define	OPTIONSTRING1	"yes|no"
71 #define	OPTIONSTRING2	"initiator node name"
72 #define	OPTIONSTRING3	"initiator node alias"
73 #define	OPTIONSTRING4	"enable|disable"
74 #define	OPTIONSTRING5	"key=value,..."
75 #define	OPTIONSTRING6	"none|CRC32"
76 #define	OPTIONSTRING7	"CHAP name"
77 #define	OPTIONSTRING8	"<# sessions>|<IP Address>[,<IP Address>]*"
78 #define	OPTIONVAL1	"0 to 3600"
79 #define	OPTIONVAL2	"512 to 2**24 - 1"
80 #define	OPTIONVAL3	"1 to 65535"
81 #define	OPTIONVAL4	"<IP address>[:port]"
82 
83 #define	MAX_ISCSI_NAME_LEN	    223
84 #define	MAX_ADDRESS_LEN		    255
85 #define	MIN_CHAP_SECRET_LEN	    12
86 #define	MAX_CHAP_SECRET_LEN	    16
87 #define	DEFAULT_ISCSI_PORT	    3260
88 #define	ISNS_DEFAULT_SERVER_PORT    3205
89 #define	DEFAULT_RADIUS_PORT	    1812
90 #define	MAX_CHAP_NAME_LEN	    512
91 
92 /* For listNode */
93 #define	INF_ERROR		1
94 #define	INVALID_NODE_NAME	2
95 
96 #define	IMABOOLPRINT(prop, option)	 \
97 	if ((option) == PRINT_CONFIGURED_PARAMS) { \
98 		(void) fprintf(stdout, "%s/%s\n", \
99 		(prop).defaultValue == IMA_TRUE ? gettext("yes") : \
100 			gettext("no"), \
101 		(prop).currentValueValid == IMA_TRUE ? \
102 			((prop).currentValue == IMA_TRUE ? \
103 			gettext("yes"): gettext("no")) : "-"); \
104 	} else if ((option) == PRINT_NEGOTIATED_PARAMS) { \
105 		(void) fprintf(stdout, "%s\n", \
106 		(prop).currentValueValid == IMA_TRUE ? \
107 		(((prop).currentValue == IMA_TRUE) ? gettext("yes") : \
108 		gettext("no")) : "-"); \
109 	}
110 
111 #define	IMAMINMAXPRINT(prop, option) \
112 	if ((option) == PRINT_CONFIGURED_PARAMS) { \
113 		(void) fprintf(stdout, "%d/", (prop).defaultValue); \
114 		if ((prop).currentValueValid == IMA_TRUE) { \
115 			(void) fprintf(stdout, "%d\n", (prop).currentValue); \
116 		} else if ((prop).currentValueValid == IMA_FALSE) { \
117 			(void) fprintf(stdout, "%s\n", "-"); \
118 		} \
119 	} else if ((option) == PRINT_NEGOTIATED_PARAMS) { \
120 		if ((prop).currentValueValid == IMA_TRUE) { \
121 			(void) fprintf(stdout, "%d\n", (prop).currentValue); \
122 		} else if ((prop).currentValueValid == IMA_FALSE) { \
123 			(void) fprintf(stdout, "%s\n", "-"); \
124 		} \
125 	}
126 
127 /* forward declarations */
128 #define	PARSE_ADDR_OK				0
129 #define	PARSE_ADDR_MISSING_CLOSING_BRACKET	1
130 #define	PARSE_ADDR_PORT_OUT_OF_RANGE		2
131 #define	PARSE_TARGET_OK				0
132 #define	PARSE_TARGET_INVALID_TPGT		1
133 #define	PARSE_TARGET_INVALID_ADDR		2
134 
135 #define	PRINT_CONFIGURED_PARAMS			1
136 #define	PRINT_NEGOTIATED_PARAMS			2
137 
138 typedef enum iSCSINameCheckStatus {
139 	iSCSINameCheckOK,
140 	iSCSINameLenZero,
141 	iSCSINameLenExceededMax,
142 	iSCSINameUnknownType,
143 	iSCSINameInvalidCharacter,
144 	iSCSINameIqnFormatError,
145 	iSCSINameEUIFormatError,
146 	iSCSINameIqnDateFormatError,
147 	iSCSINameIqnSubdomainFormatError,
148 	iSCSINameIqnInvalidYearError,
149 	iSCSINameIqnInvalidMonthError,
150 	iSCSINameIqnFQDNError
151 } iSCSINameCheckStatusType;
152 
153 /* Utility functions */
154 iSCSINameCheckStatusType iSCSINameStringProfileCheck(wchar_t *name);
155 boolean_t isNaturalNumber(char *numberStr, uint32_t upperBound);
156 static int parseAddress(char *address_port_str, uint16_t defaultPort,
157     char *address_str, size_t address_str_len,
158     uint16_t *port, boolean_t *isIpv6);
159 int parseTarget(char *targetStr,
160     wchar_t *targetNameStr,
161     size_t targetNameStrLen,
162     boolean_t *targetAddressSpecified,
163     wchar_t *targetAddressStr,
164     size_t targetAddressStrLen,
165     uint16_t *port,
166     boolean_t *tpgtSpecified,
167     uint16_t *tpgt,
168     boolean_t *isIpv6);
169 
170 /* subcommand functions */
171 static int addFunc(int, char **, int, cmdOptions_t *, void *, int *);
172 static int listFunc(int, char **, int, cmdOptions_t *, void *, int *);
173 static int modifyFunc(int, char **, int, cmdOptions_t *, void *, int *);
174 static int removeFunc(int, char **, int, cmdOptions_t *, void *, int *);
175 
176 /* helper functions */
177 static char *getExecBasename(char *);
178 static int getNodeProps(IMA_NODE_PROPERTIES *);
179 static int getSecret(char *, int *, int, int);
180 static int getTargetAddress(int, char *, IMA_TARGET_ADDRESS *);
181 static int printLoginParameters(char *, IMA_OID, int);
182 static void printDiscoveryMethod(char *, IMA_UINT32);
183 static void printTargetLuns(IMA_OID_LIST *);
184 static void printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *);
185 static void printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *, int);
186 static int setLoginParameter(IMA_OID, int, char *);
187 static int setLoginParameters(IMA_OID, char *);
188 static void printLibError(IMA_STATUS);
189 /* LINTED E_STATIC_UNUSED */
190 static int sunPluginChk(IMA_OID, boolean_t *);
191 static int sunInitiatorFind(IMA_OID *);
192 static int getAuthMethodValue(char *, IMA_AUTHMETHOD *);
193 static int getLoginParam(char *);
194 static void iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status);
195 static int modifyIndividualTargetParam(cmdOptions_t *optionList,
196     IMA_OID targetOid, int *);
197 static void listCHAPName(IMA_OID oid);
198 static int printConfiguredSessions(IMA_OID);
199 
200 /* object functions per subcommand */
201 static int addAddress(int, int, char *[], int *);
202 static int addStaticConfig(int, char *[], int *);
203 static int listDiscovery(int *);
204 static int listDiscoveryAddress(int, char *[], cmdOptions_t *, int *);
205 static int listISNSServerAddress(int, char *[], cmdOptions_t *, int *);
206 static int listNode(int *);
207 static int listStaticConfig(int, char *[], int *);
208 static int listTarget(int, char *[], cmdOptions_t *, int *);
209 static int listTargetParam(int, char *[], cmdOptions_t *, int *);
210 static int modifyDiscovery(cmdOptions_t *, int *);
211 static int modifyNodeAuthMethod(IMA_OID, char *, int *);
212 static int modifyNodeAuthParam(IMA_OID oid, int, char *, int *);
213 static int modifyNodeRadiusConfig(IMA_OID, char *, int *);
214 static int modifyNodeRadiusAccess(IMA_OID, char *, int *);
215 static int modifyNodeRadiusSharedSecret(IMA_OID, int *);
216 static int modifyNode(cmdOptions_t *, int *);
217 static int modifyTargetAuthMethod(IMA_OID, char *, int *);
218 static int modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *);
219 static int modifyTargetParam(cmdOptions_t *, char *, int *);
220 static int removeAddress(int, int, char *[], int *);
221 static int removeStaticConfig(int, char *[], int *);
222 static int removeTargetParam(int, char *[], int *);
223 static int modifyTargetBidirAuthFlag(IMA_OID, char *, int *);
224 static int modifyConfiguredSessions(IMA_OID targetOid, char *optarg);
225 
226 /* LINTED E_STATIC_UNUSED */
227 static IMA_STATUS getISCSINodeParameter(int paramType,
228     IMA_OID *oid,
229     void *pProps,
230     uint32_t paramIndex);
231 /* LINTED E_STATIC_UNUSED */
232 static IMA_STATUS setISCSINodeParameter(int paramType,
233     IMA_OID *oid,
234     void *pProps,
235     uint32_t paramIndex);
236 /* LINTED E_STATIC_UNUSED */
237 static IMA_STATUS getDigest(IMA_OID oid, int ioctlCmd,
238     SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm);
239 
240 IMA_STATUS getNegotiatedDigest(int digestType,
241 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
242 	SUN_IMA_CONN_PROPERTIES *connProps);
243 
244 /* globals */
245 static char *cmdName;
246 
247 /*
248  * Available option letters:
249  *
250  * bcefgijklmnoquwxyz
251  *
252  * DEFGHIJKLMOQTUVWXYZ
253  */
254 
255 /*
256  * Add new options here
257  */
258 optionTbl_t longOptions[] = {
259 	{"static", required_arg, 's', OPTIONSTRING4},
260 	{"sendtargets", required_arg, 't', OPTIONSTRING4},
261 	{"iSNS", required_arg, 'i', OPTIONSTRING4},
262 	{"headerdigest", required_arg, 'h', OPTIONSTRING6},
263 	{"datadigest", required_arg, 'd', OPTIONSTRING6},
264 	{"login-param", required_arg, 'p', OPTIONSTRING5},
265 	{"authentication", required_arg, 'a', "CHAP|none"},
266 	{"bi-directional-authentication", required_arg, 'B', OPTIONSTRING4},
267 	{"CHAP-secret", no_arg, 'C', NULL},
268 	{"CHAP-name", required_arg, 'H', OPTIONSTRING7},
269 	{"node-name", required_arg, 'N', OPTIONSTRING2},
270 	{"node-alias", required_arg, 'A', OPTIONSTRING3},
271 	{"radius-server", required_arg, 'r', OPTIONVAL4},
272 	{"radius-access", required_arg, 'R', OPTIONSTRING4},
273 	{"radius-shared-secret", no_arg, 'P', NULL},
274 	{"verbose", no_arg, 'v', NULL},
275 	{"scsi-target", no_arg, 'S', NULL},
276 	{"configured-sessions", required_arg, 'c', OPTIONSTRING8},
277 	{NULL, 0, 0, 0}
278 };
279 
280 parameterTbl_t loginParams[] = {
281 	{"dataseqinorder", DATA_SEQ_IN_ORDER},
282 	{"defaulttime2retain", DEFAULT_TIME_2_RETAIN},
283 	{"defaulttime2wait", DEFAULT_TIME_2_WAIT},
284 	{"firstburstlength", FIRST_BURST_LENGTH},
285 	{"immediatedata", IMMEDIATE_DATA},
286 	{"initialr2t", INITIAL_R2T},
287 	{"maxburstlength", MAX_BURST_LENGTH},
288 	{"datapduinorder", DATA_PDU_IN_ORDER},
289 	{"maxoutstandingr2t", MAX_OUTSTANDING_R2T},
290 	{"maxrecvdataseglen", MAX_RECV_DATA_SEG_LEN},
291 	{"maxconnections", MAX_CONNECTIONS},
292 	{"errorrecoverylevel", ERROR_RECOVERY_LEVEL},
293 	{NULL, 0}
294 };
295 
296 /*
297  * Add new subcommands here
298  */
299 subcommand_t subcommands[] = {
300 	{"add", ADD, addFunc},
301 	{"list", LIST, listFunc},
302 	{"modify", MODIFY, modifyFunc},
303 	{"remove", REMOVE, removeFunc},
304 	{NULL, 0, NULL}
305 };
306 
307 /*
308  * Add objects here
309  */
310 object_t objects[] = {
311 	{"discovery", DISCOVERY},
312 	{"discovery-address", DISCOVERY_ADDRESS},
313 	{"isns-server", ISNS_SERVER_ADDRESS},
314 	{"initiator-node", NODE},
315 	{"static-config", STATIC_CONFIG},
316 	{"target", TARGET},
317 	{"target-param", TARGET_PARAM},
318 	{NULL, 0}
319 };
320 
321 /*
322  * Rules for subcommands and objects
323  */
324 objectRules_t objectRules[] = {
325 	{TARGET, 0, LIST, 0, ADD|REMOVE|MODIFY, LIST,
326 	"target-name"},
327 	{TARGET_PARAM, MODIFY|REMOVE, LIST, 0, ADD, MODIFY,
328 	"target-name"},
329 	{DISCOVERY, 0, 0, LIST|MODIFY, ADD|REMOVE, 0, NULL},
330 	{NODE, 0, 0, MODIFY|LIST, ADD|REMOVE, 0, NULL},
331 	{STATIC_CONFIG, ADD|REMOVE, LIST, 0, MODIFY, ADD|REMOVE|LIST,
332 	"target-name,target-address[:port-number][,tpgt]"},
333 	{DISCOVERY_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY,
334 	ADD|REMOVE|LIST, "IP-address[:port-number]"},
335 	{ISNS_SERVER_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY,
336 	ADD|REMOVE|LIST, "IP-address[:port-number]"},
337 	{0, 0, 0, 0, 0, NULL}
338 };
339 
340 /*
341  * list of objects, subcommands, valid short options, required flag and
342  * exclusive option string
343  *
344  * If it's not here, there are no options for that object.
345  */
346 optionRules_t optionRules[] = {
347 	{DISCOVERY, MODIFY, "sti", B_TRUE, NULL},
348 	{DISCOVERY_ADDRESS, LIST, "v", B_FALSE, NULL},
349 	{ISNS_SERVER_ADDRESS, LIST, "v", B_FALSE, NULL},
350 	{TARGET, LIST, "vS", B_FALSE, NULL},
351 	{NODE, MODIFY, "NAhdCaRrPHc", B_TRUE, "CP"},
352 	{TARGET_PARAM, MODIFY, "ahdBCpcH", B_TRUE, "C"},
353 	{TARGET_PARAM, LIST, "v", B_FALSE, NULL},
354 	{0, 0, 0, 0, 0}
355 };
356 
357 
358 static boolean_t
359 targetNamesEqual(wchar_t *name1, wchar_t *name2)
360 {
361 	int i;
362 	wchar_t wchar1, wchar2;
363 
364 	if (name1 == NULL || name2 == NULL) {
365 		return (B_FALSE);
366 	}
367 
368 	if (wcslen(name1) != wcslen(name2)) {
369 		return (B_FALSE);
370 	}
371 
372 	/*
373 	 * Convert names to lower case and compare
374 	 */
375 	for (i = 0; i < wcslen(name1); i++) {
376 		wchar1 = towctrans((wint_t)name1[i], wctrans("tolower"));
377 		wchar2 = towctrans((wint_t)name2[i], wctrans("tolower"));
378 
379 		if (wchar1 != wchar2) {
380 			return (B_FALSE);
381 		}
382 	}
383 
384 	return (B_TRUE);
385 }
386 
387 static boolean_t
388 ipAddressesEqual(IMA_TARGET_ADDRESS addr1, IMA_TARGET_ADDRESS addr2)
389 {
390 #define	IPV4_ADDR_BYTES 4
391 #define	IPV6_ADDR_BYTES 16
392 
393 	int compSize;
394 
395 	if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address !=
396 	    addr2.hostnameIpAddress.id.ipAddress.ipv4Address) {
397 		return (B_FALSE);
398 	}
399 
400 	compSize = IPV6_ADDR_BYTES;
401 	if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address) {
402 		compSize = IPV4_ADDR_BYTES;
403 	}
404 
405 	if (bcmp(addr1.hostnameIpAddress.id.ipAddress.ipAddress,
406 	    addr2.hostnameIpAddress.id.ipAddress.ipAddress, compSize) == 0) {
407 		return (B_TRUE);
408 	}
409 
410 	return (B_FALSE);
411 }
412 
413 static int
414 getLoginParam(char *arg)
415 {
416 	parameterTbl_t *paramp;
417 	int len;
418 
419 	for (paramp = loginParams; paramp->name; paramp++) {
420 		len = strlen(arg);
421 		if (len == strlen(paramp->name) &&
422 		    strncasecmp(arg, paramp->name, len) == 0) {
423 			return (paramp->val);
424 		}
425 	}
426 	return (-1);
427 }
428 
429 static void
430 printLibError(IMA_STATUS status)
431 {
432 	char *errorString;
433 	switch (status) {
434 	case IMA_ERROR_NOT_SUPPORTED:
435 		errorString =
436 		gettext("Operation currently not supported");
437 		break;
438 	case IMA_ERROR_INSUFFICIENT_MEMORY:
439 		errorString = gettext("Insufficient memory");
440 		break;
441 	case IMA_ERROR_UNEXPECTED_OS_ERROR:
442 		errorString = gettext("unexpected OS error");
443 		break;
444 	case IMA_ERROR_UNKNOWN_ERROR:
445 		errorString = gettext("Unknown error");
446 		break;
447 	case IMA_ERROR_LU_IN_USE:
448 		errorString = gettext("Logical unit in use");
449 		break;
450 	case IMA_ERROR_INVALID_PARAMETER:
451 		errorString = gettext("Invalid parameter specified");
452 		break;
453 	case IMA_ERROR_INVALID_OBJECT_TYPE:
454 		errorString =
455 		gettext("Internal library error: Invalid oid type specified");
456 		break;
457 	case IMA_ERROR_INCORRECT_OBJECT_TYPE:
458 		errorString =
459 		gettext("Internal library error: Incorrect oid type specified");
460 		break;
461 	case IMA_ERROR_OBJECT_NOT_FOUND:
462 		errorString = gettext("Internal library error: Oid not found");
463 		break;
464 	case IMA_ERROR_NAME_TOO_LONG:
465 		errorString = gettext("Name too long");
466 		break;
467 	default:
468 		errorString = gettext("Unknown error");
469 	}
470 	(void) fprintf(stderr, "%s: %s\n", cmdName, errorString);
471 }
472 
473 /*
474  * input:
475  *  execFullName - exec name of program (argv[0])
476  *
477  * Returns:
478  *  command name portion of execFullName
479  */
480 static char *
481 getExecBasename(char *execFullname)
482 {
483 	char *lastSlash, *execBasename;
484 
485 	/* guard against '/' at end of command invocation */
486 	for (;;) {
487 		lastSlash = strrchr(execFullname, '/');
488 		if (lastSlash == NULL) {
489 			execBasename = execFullname;
490 			break;
491 		} else {
492 			execBasename = lastSlash + 1;
493 			if (*execBasename == '\0') {
494 				*lastSlash = '\0';
495 				continue;
496 			}
497 			break;
498 		}
499 	}
500 	return (execBasename);
501 }
502 
503 
504 /*
505  * input:
506  *  nodeProps - pointer to caller allocated IMA_NODE_PROPERTIES
507  *
508  * returns:
509  *  zero on success
510  *  non-zero otherwise
511  */
512 static int
513 getNodeProps(IMA_NODE_PROPERTIES *nodeProps)
514 {
515 	IMA_OID sharedNodeOid;
516 
517 	IMA_STATUS status = IMA_GetSharedNodeOid(&sharedNodeOid);
518 	if (!(IMA_SUCCESS(status))) {
519 		printLibError(status);
520 		return (INF_ERROR);
521 	}
522 
523 	status = IMA_GetNodeProperties(sharedNodeOid, nodeProps);
524 	if (!IMA_SUCCESS(status)) {
525 		printLibError(status);
526 		return (INF_ERROR);
527 	}
528 
529 	return (0);
530 }
531 
532 /*
533  * sunInitiatorFind
534  * Purpose:
535  *  Finds the Sun iSCSI initiator (LHBA). This CLI currently supports only
536  *  one initiator.
537  *
538  * output:
539  *  oid of initiator
540  *
541  * Returns:
542  *  zero on success with initiator found
543  *  > 0 on success with no initiator found
544  *  < 0 on failure
545  */
546 static int
547 sunInitiatorFind(IMA_OID *oid)
548 {
549 	IMA_OID_LIST *lhbaList;
550 
551 	IMA_STATUS status = IMA_GetLhbaOidList(&lhbaList);
552 	if (!IMA_SUCCESS(status)) {
553 		printLibError(status);
554 		return (-1);
555 	}
556 
557 	*oid = lhbaList->oids[0];
558 
559 	return (0);
560 }
561 
562 /*
563  * input:
564  *  wcInput - wide character string containing discovery address
565  * output:
566  *  address - IMA_TARGET_ADDRESS structure containing valid
567  *	discovery address
568  * returns:
569  *  zero on success
570  *  non-zero on failure
571  */
572 
573 static int
574 getTargetAddress(int addrType, char *ipStr, IMA_TARGET_ADDRESS *address)
575 {
576 	char cCol = ':';
577 	char cBracketL = '['; /* Open Bracket '[' */
578 	char cBracketR = ']'; /* Close Bracket ']' */
579 	char *colPos;
580 	char *startPos;
581 	unsigned long inputPort;
582 	int addressType = AF_INET;
583 	char *tmpStrPtr, tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
584 	int rval;
585 
586 	/* Check if this is a ipv6 address */
587 	if (ipStr[0] == cBracketL) {
588 		addressType = AF_INET6;
589 		startPos = strchr(ipStr, cBracketR);
590 		if (!startPos) {
591 			(void) fprintf(stderr, "%s: %s: ']' %s\n",
592 			    cmdName, ipStr, gettext("missing"));
593 			return (1);
594 		}
595 		(void) strlcpy(tmpStr, ipStr+1, startPos-ipStr);
596 		address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_FALSE;
597 		tmpStrPtr = tmpStr;
598 	} else {
599 		/* set start position to beginning of input object */
600 		addressType = AF_INET;
601 		startPos = ipStr;
602 		address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_TRUE;
603 		tmpStrPtr = ipStr;
604 	}
605 	/* wcschr for ':'. If not there, use default port */
606 	colPos = strchr(startPos, cCol);
607 
608 	if (!colPos) {
609 		if (addrType == DISCOVERY_ADDRESS) {
610 			inputPort = DEFAULT_ISCSI_PORT;
611 		} else if (addrType == ISNS_SERVER_ADDRESS) {
612 			inputPort = ISNS_DEFAULT_SERVER_PORT;
613 		} else {
614 			*colPos = NULL;
615 		}
616 	} else {
617 		*colPos = NULL;
618 	}
619 
620 	rval = inet_pton(addressType, tmpStrPtr,
621 	    address->hostnameIpAddress.id.ipAddress.ipAddress);
622 	/* inet_pton returns 1 on success */
623 	if (rval != 1) {
624 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName, ipStr,
625 		    gettext("invalid IP address"));
626 		return (1);
627 	}
628 
629 
630 	if (colPos) {
631 		char *errchr;
632 
633 		colPos++;
634 		if (*colPos == NULL) {
635 			(void) fprintf(stderr, "%s: %s: %s\n",
636 			    cmdName, ipStr,
637 			    gettext("port number missing"));
638 			return (1);
639 		}
640 
641 		/*
642 		 * convert port string to unsigned value
643 		 * Note:  Don't remove errno = 0 as you may get false failures.
644 		 */
645 		errno = 0;
646 		inputPort = strtol(colPos, &errchr, 10);
647 		if (errno != 0 || inputPort == 0 && errchr != NULL) {
648 			(void) fprintf(stderr, "%s: %s:%s %s\n",
649 			    cmdName, ipStr, colPos,
650 			    gettext("port number invalid"));
651 			return (1);
652 		}
653 		/* make sure it's in the range */
654 		if (inputPort > USHRT_MAX) {
655 			(void) fprintf(stderr, "%s: %s: %s\n",
656 			    cmdName, ipStr,
657 			    gettext("port number out of range"));
658 			return (1);
659 		}
660 	}
661 	address->portNumber  = inputPort;
662 
663 	return (0);
664 }
665 
666 /*
667  * Print results of send targets command
668  */
669 static void
670 printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList)
671 {
672 	char outBuf[INET6_ADDRSTRLEN];
673 	int inetSize;
674 	int af;
675 	int i;
676 
677 	for (i = 0; i < pList->keyCount; i++) {
678 		if (pList->keys[i].address.ipAddress.ipv4Address == IMA_TRUE) {
679 			af = AF_INET;
680 			inetSize = INET_ADDRSTRLEN;
681 		} else {
682 			af = AF_INET6;
683 			inetSize = INET6_ADDRSTRLEN;
684 		}
685 		(void) fprintf(stdout, gettext("\tTarget name: %ws\n"),
686 		    pList->keys[i].name);
687 		(void) fprintf(stdout, "\t\t%s: %15s:%d", "Target address",
688 		    inet_ntop(af, &(pList->keys[i].address.ipAddress.ipAddress),
689 		    outBuf, inetSize), pList->keys[i].address.portNumber);
690 		(void) fprintf(stdout, ", %d", pList->keys[i].tpgt);
691 		(void) fprintf(stdout, "\n");
692 	}
693 }
694 
695 
696 /*
697  * Print all login parameters
698  */
699 static int
700 printLoginParameters(char *prefix, IMA_OID oid, int printOption)
701 {
702 	IMA_STATUS status;
703 	IMA_BOOL_VALUE propBool;
704 	IMA_MIN_MAX_VALUE propMinMax;
705 	char longString[MAX_LONG_CHAR_LEN + 1];
706 	SUN_IMA_CONN_PROPERTIES	*connProps = NULL;
707 	IMA_OID_LIST *pConnList;
708 
709 	(void) memset(longString, 0, sizeof (longString));
710 
711 	switch (printOption) {
712 		case PRINT_CONFIGURED_PARAMS:
713 			(void) fprintf(stdout, "%s%s:\n",
714 			    prefix,
715 			    gettext("Login Parameters (Default/Configured)"));
716 			break;
717 		case PRINT_NEGOTIATED_PARAMS:
718 			(void) fprintf(stdout, "%s%s:\n",
719 			    prefix,
720 			    gettext("Login Parameters (Negotiated)"));
721 			status = SUN_IMA_GetConnOidList(
722 			    &oid,
723 			    &pConnList);
724 
725 			if (!IMA_SUCCESS(status)) {
726 				printLibError(status);
727 				return (1);
728 			}
729 
730 			status = SUN_IMA_GetConnProperties(&pConnList->oids[0],
731 			    &connProps);
732 			propBool.currentValueValid = connProps->valuesValid;
733 			propMinMax.currentValueValid = connProps->valuesValid;
734 			break;
735 		default:
736 			return (1);
737 	}
738 
739 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
740 		propBool.currentValue = connProps->dataSequenceInOrder;
741 	} else {
742 		status = IMA_GetDataSequenceInOrderProperties(oid, &propBool);
743 	}
744 	if (!IMA_SUCCESS(status)) {
745 		printLibError(status);
746 		(void) IMA_FreeMemory(connProps);
747 		return (1);
748 	}
749 	(void) fprintf(stdout, "%s\t%s: ", prefix,
750 	    gettext("Data Sequence In Order"));
751 	IMABOOLPRINT(propBool, printOption);
752 
753 
754 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
755 		propBool.currentValue = connProps->dataPduInOrder;
756 	} else {
757 		status = IMA_GetDataPduInOrderProperties(oid, &propBool);
758 	}
759 	if (!IMA_SUCCESS(status)) {
760 		printLibError(status);
761 		(void) IMA_FreeMemory(connProps);
762 		return (1);
763 	}
764 	(void) fprintf(stdout, "%s\t%s: ", prefix,
765 	    gettext("Data PDU In Order"));
766 	IMABOOLPRINT(propBool, printOption);
767 
768 
769 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
770 		propMinMax.currentValue = connProps->defaultTime2Retain;
771 	} else {
772 		status = IMA_GetDefaultTime2RetainProperties(oid, &propMinMax);
773 	}
774 	if (!IMA_SUCCESS(status)) {
775 		printLibError(status);
776 		(void) IMA_FreeMemory(connProps);
777 		return (1);
778 	}
779 	(void) fprintf(stdout, "%s\t%s: ", prefix,
780 	    gettext("Default Time To Retain"));
781 	IMAMINMAXPRINT(propMinMax, printOption);
782 
783 
784 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
785 		propMinMax.currentValue = connProps->defaultTime2Wait;
786 	} else {
787 		status = IMA_GetDefaultTime2WaitProperties(oid, &propMinMax);
788 	}
789 	if (!IMA_SUCCESS(status)) {
790 		printLibError(status);
791 		(void) IMA_FreeMemory(connProps);
792 		return (1);
793 	}
794 	(void) fprintf(stdout, "%s\t%s: ", prefix,
795 	    gettext("Default Time To Wait"));
796 	IMAMINMAXPRINT(propMinMax, printOption);
797 
798 
799 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
800 		propMinMax.currentValue = connProps->errorRecoveryLevel;
801 	} else {
802 		status = IMA_GetErrorRecoveryLevelProperties(oid, &propMinMax);
803 	}
804 	if (!IMA_SUCCESS(status)) {
805 		printLibError(status);
806 		(void) IMA_FreeMemory(connProps);
807 		return (1);
808 	}
809 	(void) fprintf(stdout, "%s\t%s: ", prefix,
810 	    gettext("Error Recovery Level"));
811 	IMAMINMAXPRINT(propMinMax, printOption);
812 
813 
814 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
815 		propMinMax.currentValue = connProps->firstBurstLength;
816 	} else {
817 		status = IMA_GetFirstBurstLengthProperties(oid,
818 		    &propMinMax);
819 	}
820 	if (!IMA_SUCCESS(status)) {
821 		printLibError(status);
822 		(void) IMA_FreeMemory(connProps);
823 		return (1);
824 	}
825 	(void) fprintf(stdout, "%s\t%s: ",
826 	    prefix, gettext("First Burst Length"));
827 	IMAMINMAXPRINT(propMinMax, printOption);
828 
829 
830 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
831 		propBool.currentValue = connProps->immediateData;
832 	} else {
833 		status = IMA_GetImmediateDataProperties(oid, &propBool);
834 	}
835 	if (!IMA_SUCCESS(status)) {
836 		printLibError(status);
837 		(void) IMA_FreeMemory(connProps);
838 		return (1);
839 	}
840 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Immediate Data"));
841 	IMABOOLPRINT(propBool, printOption);
842 
843 
844 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
845 		propBool.currentValue = connProps->initialR2T;
846 	} else {
847 		status = IMA_GetInitialR2TProperties(oid, &propBool);
848 	}
849 	if (!IMA_SUCCESS(status)) {
850 		printLibError(status);
851 		(void) IMA_FreeMemory(connProps);
852 		return (1);
853 	}
854 	(void) fprintf(stdout, "%s\t%s: ", prefix,
855 	    gettext("Initial Ready To Transfer (R2T)"));
856 	IMABOOLPRINT(propBool, printOption);
857 
858 
859 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
860 		propMinMax.currentValue = connProps->maxBurstLength;
861 	} else {
862 		status = IMA_GetMaxBurstLengthProperties(oid, &propMinMax);
863 	}
864 	if (!IMA_SUCCESS(status)) {
865 		printLibError(status);
866 		(void) IMA_FreeMemory(connProps);
867 		return (1);
868 	}
869 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Burst Length"));
870 	IMAMINMAXPRINT(propMinMax, printOption);
871 
872 
873 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
874 		propMinMax.currentValue = connProps->maxOutstandingR2T;
875 	} else {
876 		status = IMA_GetMaxOutstandingR2TProperties(oid, &propMinMax);
877 	}
878 	if (!IMA_SUCCESS(status)) {
879 		printLibError(status);
880 		(void) IMA_FreeMemory(connProps);
881 		return (1);
882 	}
883 	(void) fprintf(stdout, "%s\t%s: ", prefix,
884 	    gettext("Max Outstanding R2T"));
885 	IMAMINMAXPRINT(propMinMax, printOption);
886 
887 
888 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
889 		propMinMax.currentValue = connProps->maxRecvDataSegmentLength;
890 	} else {
891 		status = IMA_GetMaxRecvDataSegmentLengthProperties(oid,
892 		    &propMinMax);
893 	}
894 	if (!IMA_SUCCESS(status)) {
895 		printLibError(status);
896 		(void) IMA_FreeMemory(connProps);
897 		return (1);
898 	}
899 	(void) fprintf(stdout, "%s\t%s: ", prefix,
900 	    gettext("Max Receive Data Segment Length"));
901 	IMAMINMAXPRINT(propMinMax, printOption);
902 
903 
904 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
905 		propMinMax.currentValue = connProps->maxConnections;
906 	} else {
907 		status = IMA_GetMaxConnectionsProperties(oid, &propMinMax);
908 	}
909 	if (!IMA_SUCCESS(status)) {
910 		printLibError(status);
911 		(void) IMA_FreeMemory(connProps);
912 		return (1);
913 	}
914 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Connections"));
915 	IMAMINMAXPRINT(propMinMax, printOption);
916 
917 	(void) IMA_FreeMemory(connProps);
918 	return (0);
919 }
920 
921 /*
922  * Print discovery information.
923  */
924 static void
925 printDiscoveryMethod(char *prefix, IMA_UINT32 discoveryMethodFlags)
926 {
927 	(void) fprintf(stdout, "%s%s: ", prefix, gettext("Discovery Method"));
928 	if (discoveryMethodFlags == IMA_TARGET_DISCOVERY_METHOD_UNKNOWN) {
929 		(void) fprintf(stdout, "%s\n", gettext("NA"));
930 	} else {
931 		if (!((discoveryMethodFlags &
932 		    IMA_TARGET_DISCOVERY_METHOD_STATIC) ^
933 		    IMA_TARGET_DISCOVERY_METHOD_STATIC)) {
934 			(void) fprintf(stdout, "%s ", gettext("Static"));
935 		}
936 		if (!((discoveryMethodFlags &
937 		    IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS) ^
938 		    IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS)) {
939 			(void) fprintf(stdout, "%s ", gettext("SendTargets"));
940 		}
941 		if (!((discoveryMethodFlags &
942 		    IMA_TARGET_DISCOVERY_METHOD_ISNS) ^
943 		    IMA_TARGET_DISCOVERY_METHOD_ISNS)) {
944 			(void) fprintf(stdout, "%s ", gettext("iSNS"));
945 		}
946 		(void) fprintf(stdout, "\n");
947 	}
948 }
949 
950 /*
951  * printConnectionList - Prints the conection list provided
952  */
953 static void
954 printConnectionList(char *prefix, IMA_OID_LIST *pConnList)
955 {
956 	IMA_STATUS		imaStatus;
957 	int			i;
958 	SUN_IMA_CONN_PROPERTIES	*connProps;
959 	union {
960 		char	ipv4[INET_ADDRSTRLEN+1];
961 		char	ipv6[INET6_ADDRSTRLEN+1];
962 	} tmp;
963 
964 	for (i = 0; i < pConnList->oidCount; i++) {
965 		imaStatus = SUN_IMA_GetConnProperties(&pConnList->oids[i],
966 		    &connProps);
967 
968 		if (imaStatus != IMA_STATUS_SUCCESS) {
969 			continue;
970 		}
971 
972 		(void) fprintf(stdout, "%sCID: %d\n", prefix,
973 		    connProps->connectionID);
974 
975 		(void) memset(&tmp, 0, sizeof (tmp));
976 		if (connProps->local.ipAddress.ipv4Address == IMA_TRUE) {
977 			if (inet_ntop(AF_INET,
978 			    &connProps->local.ipAddress.ipAddress[0],
979 			    &tmp.ipv4[0],
980 			    INET_ADDRSTRLEN)) {
981 				(void) fprintf(stdout,
982 				    "%s  %s: %s:%u\n",
983 				    prefix,
984 				    gettext("IP address (Local)"),
985 				    &tmp.ipv4[0],
986 				    ntohs(connProps->local.portNumber));
987 			}
988 		} else {
989 			if (inet_ntop(AF_INET6,
990 			    &connProps->local.ipAddress.ipAddress[0],
991 			    &tmp.ipv6[0],
992 			    INET6_ADDRSTRLEN)) {
993 				(void) fprintf(stdout,
994 				    "%s  %s: [%s]:%u\n",
995 				    prefix,
996 				    gettext("IP address (Local)"),
997 				    &tmp.ipv6[0],
998 				    ntohs(connProps->local.portNumber));
999 			}
1000 		}
1001 		if (connProps->peer.ipAddress.ipv4Address == IMA_TRUE) {
1002 			if (inet_ntop(AF_INET,
1003 			    &connProps->peer.ipAddress.ipAddress[0],
1004 			    &tmp.ipv4[0],
1005 			    INET_ADDRSTRLEN)) {
1006 				(void) fprintf(stdout,
1007 				    "%s  %s: %s:%u\n",
1008 				    prefix,
1009 				    gettext("IP address (Peer)"),
1010 				    &tmp.ipv4[0],
1011 				    ntohs(connProps->peer.portNumber));
1012 			}
1013 		} else {
1014 			if (inet_ntop(AF_INET6,
1015 			    &connProps->peer.ipAddress.ipAddress[0],
1016 			    &tmp.ipv6[0],
1017 			    INET6_ADDRSTRLEN)) {
1018 				(void) fprintf(stdout,
1019 				    "%s  %s: [%s]:%u\n",
1020 				    prefix,
1021 				    gettext("IP address (Peer)"),
1022 				    &tmp.ipv6[0],
1023 				    ntohs(connProps->peer.portNumber));
1024 			}
1025 		}
1026 
1027 		(void) IMA_FreeMemory(connProps);
1028 	}
1029 }
1030 
1031 /*
1032  * Set login parameters on a target or initiator
1033  */
1034 static int
1035 setLoginParameter(IMA_OID oid, int optval, char *optarg)
1036 {
1037 	IMA_STATUS status = IMA_STATUS_SUCCESS;
1038 	IMA_UINT uintValue;
1039 	IMA_BOOL boolValue;
1040 	SUN_IMA_DIGEST_ALGORITHM digestAlgList[1];
1041 	IMA_MIN_MAX_VALUE propMinMax;
1042 	char *endptr;
1043 
1044 	/*
1045 	 * for clarity, there are two switch statements
1046 	 * The first loads the variable and the second
1047 	 * calls the appropriate API
1048 	 */
1049 	switch (optval) {
1050 		case DATA_SEQ_IN_ORDER:
1051 		case IMMEDIATE_DATA:
1052 		case INITIAL_R2T:
1053 		case DATA_PDU_IN_ORDER:
1054 			/* implement 'default'? */
1055 			if (strcasecmp(optarg, "yes") == 0) {
1056 				boolValue = IMA_TRUE;
1057 			} else if (strcasecmp(optarg, "no") == 0) {
1058 				boolValue = IMA_FALSE;
1059 			} else {
1060 				(void) fprintf(stderr, "%s: %s - %s\n",
1061 				    cmdName,
1062 				    gettext("invalid option argument"),
1063 				    optarg);
1064 				return (1);
1065 			}
1066 			break;
1067 		case DEFAULT_TIME_2_RETAIN:
1068 		case DEFAULT_TIME_2_WAIT:
1069 			errno = 0;
1070 			uintValue = strtoul(optarg, &endptr, 0);
1071 			if (*endptr != '\0' || errno != 0) {
1072 				(void) fprintf(stderr, "%s: %s - %s\n",
1073 				    cmdName,
1074 				    gettext("invalid option argument"),
1075 				    optarg);
1076 				return (1);
1077 			}
1078 			if (uintValue > 3600) {
1079 				(void) fprintf(stderr, "%s: %s\n",
1080 				    cmdName,
1081 gettext("value must be between 0 and 3600"));
1082 				return (1);
1083 			}
1084 			break;
1085 		case FIRST_BURST_LENGTH:
1086 		case MAX_BURST_LENGTH:
1087 		case MAX_RECV_DATA_SEG_LEN:
1088 			errno = 0;
1089 			/* implement 'default'? */
1090 			uintValue = strtoul(optarg, &endptr, 0);
1091 			if (*endptr != '\0' || errno != 0) {
1092 				(void) fprintf(stderr, "%s: %s - %s\n",
1093 				    cmdName,
1094 				    gettext("invalid option argument"),
1095 				    optarg);
1096 				return (1);
1097 			}
1098 			if (uintValue < 512 || uintValue > 16777215) {
1099 				(void) fprintf(stderr, "%s: %s\n",
1100 				    cmdName,
1101 gettext("value must be between 512 and 16777215"));
1102 				return (1);
1103 			}
1104 			break;
1105 		case MAX_OUTSTANDING_R2T:
1106 			errno = 0;
1107 			uintValue = strtoul(optarg, &endptr, 0);
1108 			if (*endptr != '\0' || errno != 0) {
1109 				(void) fprintf(stderr, "%s: %s - %s\n",
1110 				    cmdName,
1111 				    gettext("invalid option argument"),
1112 				    optarg);
1113 				return (1);
1114 			}
1115 			if (uintValue < 1 || uintValue > 65535) {
1116 				(void) fprintf(stderr, "%s: %s\n",
1117 				    cmdName,
1118 gettext("value must be between 1 and 65535"));
1119 				return (1);
1120 			}
1121 			break;
1122 		case HEADER_DIGEST:
1123 		case DATA_DIGEST:
1124 			if (strcasecmp(optarg, "none") == 0) {
1125 				digestAlgList[0] = SUN_IMA_DIGEST_NONE;
1126 			} else if (strcasecmp(optarg, "CRC32") == 0) {
1127 				digestAlgList[0] = SUN_IMA_DIGEST_CRC32;
1128 			} else {
1129 				(void) fprintf(stderr, "%s: %s - %s\n",
1130 				    cmdName,
1131 				    gettext("invalid option argument"),
1132 				    optarg);
1133 				return (1);
1134 			}
1135 			break;
1136 		case MAX_CONNECTIONS:
1137 			errno = 0;
1138 			uintValue = strtoul(optarg, &endptr, 0);
1139 			if (*endptr != '\0' || errno != 0) {
1140 				(void) fprintf(stderr, "%s: %s - %s\n",
1141 				    cmdName,
1142 				    gettext("invalid option argument"),
1143 				    optarg);
1144 				return (1);
1145 			}
1146 			if (uintValue < 1 || uintValue > 256) {
1147 				(void) fprintf(stderr, "%s: %s\n",
1148 				    cmdName,
1149 gettext("value must be between 1 and 256"));
1150 				return (1);
1151 			}
1152 			break;
1153 		case ERROR_RECOVERY_LEVEL:
1154 			errno = 0;
1155 			uintValue = strtoul(optarg, &endptr, 0);
1156 			if (*endptr != '\0' || errno != 0) {
1157 				(void) fprintf(stderr, "%s: %s - %s\n",
1158 				    cmdName,
1159 				    gettext("invalid option argument"),
1160 				    optarg);
1161 				return (1);
1162 			}
1163 			if (uintValue > 2) {
1164 				(void) fprintf(stderr, "%s: %s\n",
1165 				    cmdName,
1166 gettext("value must be between 0 and 2"));
1167 				return (1);
1168 			}
1169 			break;
1170 		default:
1171 			(void) fprintf(stderr, "%s: %c: %s\n",
1172 			    cmdName, optval, gettext("unknown option"));
1173 			return (1);
1174 	}
1175 
1176 	switch (optval) {
1177 		case DATA_PDU_IN_ORDER:
1178 			status = IMA_SetDataPduInOrder(oid, boolValue);
1179 			break;
1180 		case DATA_SEQ_IN_ORDER:
1181 			status = IMA_SetDataSequenceInOrder(oid, boolValue);
1182 			break;
1183 		case DEFAULT_TIME_2_RETAIN:
1184 			status = IMA_SetDefaultTime2Retain(oid, uintValue);
1185 			break;
1186 		case DEFAULT_TIME_2_WAIT:
1187 			status = IMA_SetDefaultTime2Wait(oid, uintValue);
1188 			break;
1189 		case FIRST_BURST_LENGTH:
1190 			status = IMA_SetFirstBurstLength(oid, uintValue);
1191 
1192 			/*
1193 			 * If this call fails check to see if it's because
1194 			 * the requested value is > than maxBurstLength
1195 			 */
1196 			if (!IMA_SUCCESS(status)) {
1197 				status = IMA_GetMaxBurstLengthProperties(oid,
1198 				    &propMinMax);
1199 				if (!IMA_SUCCESS(status)) {
1200 					printLibError(status);
1201 					return (1);
1202 				}
1203 				if (uintValue > propMinMax.currentValue) {
1204 					(void) fprintf(stderr,
1205 					    "%s: %s\n", cmdName,
1206 					    gettext("firstBurstLength must " \
1207 					    "be less than or equal to than " \
1208 					    "maxBurstLength"));
1209 				}
1210 				return (1);
1211 			}
1212 
1213 			break;
1214 		case IMMEDIATE_DATA:
1215 			status = IMA_SetImmediateData(oid, boolValue);
1216 			break;
1217 		case INITIAL_R2T:
1218 			status = IMA_SetInitialR2T(oid, boolValue);
1219 			break;
1220 		case MAX_BURST_LENGTH:
1221 			status = IMA_SetMaxBurstLength(oid, uintValue);
1222 			/*
1223 			 * If this call fails check to see if it's because
1224 			 * the requested value is < than firstBurstLength
1225 			 */
1226 			if (!IMA_SUCCESS(status)) {
1227 				status = IMA_GetFirstBurstLengthProperties(oid,
1228 				    &propMinMax);
1229 				if (!IMA_SUCCESS(status)) {
1230 					printLibError(status);
1231 					return (1);
1232 				}
1233 				if (uintValue < propMinMax.currentValue) {
1234 					(void) fprintf(stderr, "%s: %s\n",
1235 					    cmdName,
1236 					    gettext("maxBurstLength must be " \
1237 					    "greater than or equal to " \
1238 					    "firstBurstLength"));
1239 				}
1240 				return (1);
1241 			}
1242 			break;
1243 
1244 		case MAX_OUTSTANDING_R2T:
1245 			status = IMA_SetMaxOutstandingR2T(oid, uintValue);
1246 			break;
1247 		case MAX_RECV_DATA_SEG_LEN:
1248 			status = IMA_SetMaxRecvDataSegmentLength(oid,
1249 			    uintValue);
1250 			break;
1251 		case HEADER_DIGEST:
1252 			status = SUN_IMA_SetHeaderDigest(oid, 1,
1253 			    &digestAlgList[0]);
1254 			break;
1255 		case DATA_DIGEST:
1256 			status = SUN_IMA_SetDataDigest(oid, 1,
1257 			    &digestAlgList[0]);
1258 			break;
1259 		case MAX_CONNECTIONS:
1260 			status = IMA_SetMaxConnections(oid, uintValue);
1261 			break;
1262 		case ERROR_RECOVERY_LEVEL:
1263 			status = IMA_SetErrorRecoveryLevel(oid, uintValue);
1264 			break;
1265 	}
1266 	if (!IMA_SUCCESS(status)) {
1267 		printLibError(status);
1268 		return (1);
1269 	}
1270 	return (0);
1271 }
1272 
1273 static void
1274 printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *digestAlgorithms,
1275     int printOption)
1276 {
1277 	int i;
1278 
1279 	if (printOption == PRINT_CONFIGURED_PARAMS) {
1280 		for (i = 0; i < digestAlgorithms->defaultAlgorithmCount; i++) {
1281 			if (i > 0) {
1282 				(void) fprintf(stdout, "|");
1283 			}
1284 			switch (digestAlgorithms->defaultAlgorithms[i]) {
1285 				case SUN_IMA_DIGEST_NONE:
1286 					(void) fprintf(stdout,
1287 					    gettext("NONE"));
1288 					break;
1289 				case SUN_IMA_DIGEST_CRC32:
1290 					(void) fprintf(stdout,
1291 					    gettext("CRC32"));
1292 					break;
1293 				default:
1294 					(void) fprintf(stdout,
1295 					    gettext("Unknown"));
1296 					break;
1297 			}
1298 		}
1299 		(void) fprintf(stdout, "/");
1300 		if (digestAlgorithms->currentValid == IMA_TRUE) {
1301 			for (i = 0;
1302 			    i < digestAlgorithms->currentAlgorithmCount; i++) {
1303 				if (i > 0) {
1304 					(void) fprintf(stdout, "|");
1305 				}
1306 				switch (digestAlgorithms->
1307 				    currentAlgorithms[i]) {
1308 					case SUN_IMA_DIGEST_NONE:
1309 						(void) fprintf(stdout,
1310 						    gettext("NONE"));
1311 						break;
1312 					case SUN_IMA_DIGEST_CRC32:
1313 						(void) fprintf(stdout,
1314 						    gettext("CRC32"));
1315 						break;
1316 					default:
1317 						(void) fprintf(stdout,
1318 						    gettext("Unknown"));
1319 						break;
1320 				}
1321 			}
1322 		} else {
1323 			(void) fprintf(stdout, "-");
1324 		}
1325 		(void) fprintf(stdout, "\n");
1326 	} else if (printOption == PRINT_NEGOTIATED_PARAMS) {
1327 
1328 		if (digestAlgorithms->negotiatedValid == IMA_TRUE) {
1329 			for (i = 0;
1330 			    i < digestAlgorithms->negotiatedAlgorithmCount;
1331 			    i++) {
1332 				if (i > 0) {
1333 					(void) fprintf(stdout, "|");
1334 				}
1335 				switch (digestAlgorithms->
1336 				    negotiatedAlgorithms[i]) {
1337 					case SUN_IMA_DIGEST_NONE:
1338 						(void) fprintf(stdout,
1339 						    gettext("NONE"));
1340 						break;
1341 					case SUN_IMA_DIGEST_CRC32:
1342 						(void) fprintf(stdout,
1343 						    gettext("CRC32"));
1344 						break;
1345 					default:
1346 						(void) fprintf(stdout,
1347 						    gettext("Unknown"));
1348 						break;
1349 				}
1350 			}
1351 		} else {
1352 			(void) fprintf(stdout, "-");
1353 		}
1354 		(void) fprintf(stdout, "\n");
1355 	}
1356 }
1357 
1358 static int
1359 setLoginParameters(IMA_OID oid, char *optarg)
1360 {
1361 	char keyp[MAXOPTARGLEN];
1362 	char valp[MAXOPTARGLEN];
1363 	int key;
1364 	char *nameValueString, *indexp, *delim = NULL;
1365 
1366 	if ((nameValueString = strdup(optarg)) == NULL) {
1367 		if (errno == ENOMEM) {
1368 			(void) fprintf(stderr, "%s: %s\n",
1369 			    cmdName, strerror(errno));
1370 		} else {
1371 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1372 			    gettext("unknown error"));
1373 		}
1374 		return (1);
1375 	}
1376 
1377 	indexp = nameValueString;
1378 
1379 	/*
1380 	 * Retrieve all login params from option argument
1381 	 * Syntax <key=value,...>
1382 	 */
1383 	while (indexp) {
1384 		if (delim = strchr(indexp, ',')) {
1385 			delim[0] = '\0';
1386 		}
1387 		(void) memset(keyp, 0, sizeof (keyp));
1388 		(void) memset(valp, 0, sizeof (valp));
1389 		if (sscanf(indexp, gettext("%[^=]=%s"), keyp, valp) != 2) {
1390 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1391 			    gettext("Unknown param"), indexp);
1392 			return (1);
1393 		}
1394 		if ((key = getLoginParam(keyp)) == -1) {
1395 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1396 			    gettext("Unknown key"), keyp);
1397 			return (1);
1398 		}
1399 		if (setLoginParameter(oid, key, valp) != 0) {
1400 			return (1);
1401 		}
1402 		if (delim) {
1403 			indexp = delim + 1;
1404 		} else {
1405 			indexp = NULL;
1406 		}
1407 	}
1408 
1409 	return (0);
1410 }
1411 
1412 /*
1413  * Print logical unit information for a specific target
1414  */
1415 static void
1416 printTargetLuns(IMA_OID_LIST * lunList)
1417 {
1418 	int	j;
1419 	IMA_STATUS status;
1420 	SUN_IMA_LU_PROPERTIES	lunProps;
1421 
1422 	for (j = 0; j < lunList->oidCount; j++) {
1423 		status = SUN_IMA_GetLuProperties(lunList->oids[j],
1424 		    &lunProps);
1425 		if (!IMA_SUCCESS(status)) {
1426 			printLibError(status);
1427 			return;
1428 		}
1429 
1430 		if (lunProps.imaProps.osDeviceNameValid == IMA_TRUE) {
1431 			(void) fprintf(stdout, "\tLUN: %lld\n",
1432 			    lunProps.imaProps.targetLun);
1433 			(void) fprintf(stdout, "\t     Vendor:  %s\n",
1434 			    lunProps.vendorId);
1435 			(void) fprintf(stdout, "\t     Product: %s\n",
1436 			    lunProps.productId);
1437 			(void) fprintf(stdout,
1438 			    gettext("\t     OS Device Name: %ws\n"),
1439 			    lunProps.imaProps.osDeviceName);
1440 		}
1441 	}
1442 }
1443 
1444 /*
1445  * Retrieve CHAP secret from input
1446  */
1447 static int
1448 getSecret(char *secret, int *secretLen, int minSecretLen, int maxSecretLen)
1449 {
1450 	char *chapSecret;
1451 
1452 	/* get password */
1453 	chapSecret = getpassphrase(gettext("Enter secret:"));
1454 
1455 	if (strlen(chapSecret) > maxSecretLen) {
1456 		(void) fprintf(stderr, "%s: %s %d\n", cmdName,
1457 		    gettext("secret too long, maximum length is"),
1458 		    maxSecretLen);
1459 		*secret = NULL;
1460 		return (1);
1461 	}
1462 
1463 	if (strlen(chapSecret) < minSecretLen) {
1464 		(void) fprintf(stderr, "%s: %s %d\n", cmdName,
1465 		    gettext("secret too short, minimum length is"),
1466 		    minSecretLen);
1467 		*secret = NULL;
1468 		return (1);
1469 	}
1470 
1471 	(void) strcpy(secret, chapSecret);
1472 
1473 	chapSecret = getpassphrase(gettext("Re-enter secret:"));
1474 	if (strcmp(secret, chapSecret) != 0) {
1475 		(void) fprintf(stderr, "%s: %s\n", cmdName,
1476 		    gettext("secrets do not match, secret not changed"));
1477 		*secret = NULL;
1478 		return (1);
1479 	}
1480 	*secretLen = strlen(chapSecret);
1481 	return (0);
1482 }
1483 
1484 /*
1485  * Lists the discovery attributes
1486  */
1487 static int
1488 listDiscovery(int *funcRet)
1489 {
1490 	IMA_OID	initiatorOid;
1491 	IMA_DISCOVERY_PROPERTIES discProps;
1492 	int ret;
1493 	IMA_STATUS status;
1494 
1495 	assert(funcRet != NULL);
1496 
1497 
1498 	/* Find Sun initiator */
1499 	ret = sunInitiatorFind(&initiatorOid);
1500 	if (ret > 0) {
1501 		(void) fprintf(stderr, "%s: %s\n",
1502 		    cmdName, gettext("no initiator found"));
1503 	}
1504 
1505 	if (ret != 0) {
1506 		return (ret);
1507 	}
1508 
1509 	/* Get discovery attributes from IMA */
1510 	status = IMA_GetDiscoveryProperties(initiatorOid, &discProps);
1511 	if (!IMA_SUCCESS(status)) {
1512 		printLibError(status);
1513 		*funcRet = 1;
1514 		return (ret);
1515 	}
1516 
1517 
1518 	(void) fprintf(stdout, "%s:\n", "Discovery");
1519 	(void) fprintf(stdout, "\tStatic: %s\n",
1520 	    discProps.staticDiscoveryEnabled == IMA_TRUE ? \
1521 	    gettext("enabled") : gettext("disabled"));
1522 	(void) fprintf(stdout, "\tSend Targets: %s\n",
1523 	    discProps.sendTargetsDiscoveryEnabled == IMA_TRUE ? \
1524 	    gettext("enabled") : gettext("disabled"));
1525 	(void) fprintf(stdout, "\tiSNS: %s\n",
1526 	    discProps.iSnsDiscoveryEnabled == IMA_TRUE ? \
1527 	    gettext("enabled") : gettext("disabled"));
1528 
1529 	return (0);
1530 }
1531 
1532 /*
1533  * Print all initiator node attributes
1534  */
1535 static int
1536 listNode(int *funcRet)
1537 {
1538 	IMA_OID	initiatorOid;
1539 	IMA_NODE_PROPERTIES nodeProps;
1540 	IMA_STATUS status;
1541 	int ret;
1542 	IMA_UINT maxEntries = MAX_AUTH_METHODS;
1543 	IMA_AUTHMETHOD	methodList[MAX_AUTH_METHODS];
1544 	SUN_IMA_RADIUS_CONFIG radiusConfig;
1545 	SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
1546 	IMA_BOOL radiusAccess;
1547 
1548 	int i;
1549 
1550 	assert(funcRet != NULL);
1551 
1552 	ret = getNodeProps(&nodeProps);
1553 	if (ret != 0) {
1554 		return (ret);
1555 	}
1556 
1557 	if (nodeProps.nameValid == IMA_FALSE) {
1558 		return (INVALID_NODE_NAME);
1559 	}
1560 
1561 	/* Find Sun initiator */
1562 	ret = sunInitiatorFind(&initiatorOid);
1563 	if (ret > 0) {
1564 		(void) fprintf(stderr, "%s: %s\n",
1565 		    cmdName, gettext("no initiator found"));
1566 	}
1567 
1568 	if (ret != 0) {
1569 		return (ret);
1570 	}
1571 	/* Begin output */
1572 	(void) fprintf(stdout, gettext("%s: %ws\n"),
1573 	    gettext("Initiator node name"),
1574 	    nodeProps.name);
1575 	(void) fprintf(stdout, gettext("Initiator node alias: "));
1576 	if (nodeProps.aliasValid == IMA_TRUE) {
1577 		(void) fprintf(stdout, gettext("%ws\n"), nodeProps.alias);
1578 	} else {
1579 		(void) fprintf(stdout, "%s\n", "-");
1580 	}
1581 	(void) fprintf(stdout, "\t%s:\n",
1582 	    gettext("Login Parameters (Default/Configured)"));
1583 
1584 	/* Get Digest configuration */
1585 	status = SUN_IMA_GetHeaderDigest(initiatorOid, &digestAlgorithms);
1586 	if (IMA_SUCCESS(status)) {
1587 		(void) fprintf(stdout, "\t\t%s: ", gettext("Header Digest"));
1588 		printDigestAlgorithm(&digestAlgorithms,
1589 		    PRINT_CONFIGURED_PARAMS);
1590 	} else {
1591 		printLibError(status);
1592 		*funcRet = 1;
1593 		return (ret);
1594 	}
1595 
1596 	status = SUN_IMA_GetDataDigest(initiatorOid, &digestAlgorithms);
1597 	if (IMA_SUCCESS(status)) {
1598 		(void) fprintf(stdout, "\t\t%s: ", gettext("Data Digest"));
1599 		printDigestAlgorithm(&digestAlgorithms,
1600 		    PRINT_CONFIGURED_PARAMS);
1601 	} else {
1602 		printLibError(status);
1603 		*funcRet = 1;
1604 		return (ret);
1605 	}
1606 
1607 	/* Get authentication type for this lhba */
1608 	status = IMA_GetInUseInitiatorAuthMethods(initiatorOid, &maxEntries,
1609 	    &methodList[0]);
1610 	(void) fprintf(stdout, "\t%s: ", gettext("Authentication Type"));
1611 	if (!IMA_SUCCESS(status)) {
1612 		/* No authentication method set - default is NONE */
1613 		(void) fprintf(stdout, gettext("NONE"));
1614 	} else {
1615 		for (i = 0; i < maxEntries; i++) {
1616 			if (i > 0) {
1617 				(void) fprintf(stdout, "|");
1618 			}
1619 			switch (methodList[i]) {
1620 				case IMA_AUTHMETHOD_NONE:
1621 					(void) fprintf(stdout, gettext("NONE"));
1622 					break;
1623 				case IMA_AUTHMETHOD_CHAP:
1624 					(void) fprintf(stdout, gettext("CHAP"));
1625 					listCHAPName(initiatorOid);
1626 					break;
1627 				default:
1628 					(void) fprintf(stdout,
1629 					    gettext("unknown type"));
1630 					break;
1631 			}
1632 		}
1633 	}
1634 	(void) fprintf(stdout, "\n");
1635 
1636 
1637 	/* Get RADIUS configuration */
1638 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
1639 	(void) fprintf(stdout, "\t%s: ", gettext("RADIUS Server"));
1640 	if (IMA_SUCCESS(status)) {
1641 		if (strlen(radiusConfig.hostnameIpAddress) > 0) {
1642 			(void) fprintf(stdout, "%s:%d",
1643 			    radiusConfig.hostnameIpAddress,
1644 			    radiusConfig.port);
1645 		} else {
1646 			(void) fprintf(stdout, "%s", gettext("NONE"));
1647 		}
1648 	} else {
1649 		(void) fprintf(stdout, "%s", gettext("NONE"));
1650 	}
1651 	(void) fprintf(stdout, "\n");
1652 
1653 	status = SUN_IMA_GetInitiatorRadiusAccess(initiatorOid,
1654 	    &radiusAccess);
1655 	(void) fprintf(stdout, "\t%s: ", gettext("RADIUS Access"));
1656 	if (IMA_SUCCESS(status)) {
1657 		if (radiusAccess == IMA_TRUE) {
1658 			(void) fprintf(stdout, "%s", gettext("enabled"));
1659 		} else {
1660 			(void) fprintf(stdout, "%s", gettext("disabled"));
1661 		}
1662 	} else if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
1663 		(void) fprintf(stdout, "%s", gettext("disabled"));
1664 	} else {
1665 		(void) fprintf(stdout, "%s", gettext("unknown"));
1666 	}
1667 	(void) fprintf(stdout, "\n");
1668 
1669 	/* print configured session information. */
1670 	ret = printConfiguredSessions(initiatorOid);
1671 
1672 	return (ret);
1673 }
1674 
1675 /*
1676  * Print discovery addresses
1677  */
1678 static int
1679 listDiscoveryAddress(int objectLen, char *objects[], cmdOptions_t *options,
1680     int *funcRet)
1681 {
1682 	IMA_OID	initiatorOid;
1683 	SUN_IMA_DISC_ADDR_PROP_LIST *discoveryAddressPropertiesList;
1684 	IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps;
1685 	IMA_TARGET_ADDRESS address;
1686 	SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
1687 	IMA_STATUS status;
1688 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
1689 	int ret;
1690 	boolean_t object = B_FALSE;
1691 	int outerLoop;
1692 	boolean_t found;
1693 	boolean_t verbose = B_FALSE;
1694 	int i, j;
1695 	cmdOptions_t *optionList = options;
1696 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
1697 
1698 	assert(funcRet != NULL);
1699 
1700 	/* Find Sun initiator */
1701 	ret = sunInitiatorFind(&initiatorOid);
1702 	if (ret > 0) {
1703 		(void) fprintf(stderr, "%s: %s\n",
1704 		    cmdName, gettext("no initiator found"));
1705 	}
1706 
1707 	if (ret != 0) {
1708 		return (ret);
1709 	}
1710 
1711 	for (; optionList->optval; optionList++) {
1712 		switch (optionList->optval) {
1713 			case 'v':
1714 				verbose = B_TRUE;
1715 				break;
1716 			default:
1717 				(void) fprintf(stderr, "%s: %c: %s\n",
1718 				    cmdName, optionList->optval,
1719 				    gettext("unknown option"));
1720 				return (1);
1721 		}
1722 	}
1723 
1724 	/*
1725 	 * If there are multiple objects, execute outer 'for' loop that
1726 	 * many times for each target detail, otherwise, execute it only
1727 	 * once with summaries only
1728 	 */
1729 	if (objectLen > 0) {
1730 		object = B_TRUE;
1731 		outerLoop = objectLen;
1732 	} else {
1733 		object = B_FALSE;
1734 		outerLoop = 1;
1735 	}
1736 
1737 	status = SUN_IMA_GetDiscoveryAddressPropertiesList(
1738 	    &discoveryAddressPropertiesList);
1739 	if (!IMA_SUCCESS(status)) {
1740 		printLibError(status);
1741 		*funcRet = 1;
1742 		return (ret);
1743 	}
1744 
1745 	for (i = 0; i < outerLoop; i++) {
1746 		if (object) {
1747 			/* initialize */
1748 			(void) memset(&wcInputObject[0], 0,
1749 			    sizeof (wcInputObject));
1750 			(void) memset(&address, 0, sizeof (address));
1751 			if (mbstowcs(wcInputObject, objects[i],
1752 			    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
1753 				(void) fprintf(stderr, "%s: %s\n",
1754 				    cmdName,
1755 				    gettext("conversion error"));
1756 				ret = 1;
1757 				continue;
1758 			}
1759 
1760 			/*
1761 			 * if one or more objects were input,
1762 			 * get the values
1763 			 */
1764 			if (getTargetAddress(DISCOVERY_ADDRESS,
1765 			    objects[i], &address) != 0) {
1766 				ret = 1;
1767 				continue;
1768 			}
1769 		}
1770 		for (found = B_FALSE, j = 0;
1771 		    j < discoveryAddressPropertiesList->discAddrCount;
1772 		    j++) {
1773 			discAddrProps =
1774 			    discoveryAddressPropertiesList->props[j];
1775 
1776 			/*
1777 			 * Compare the discovery address with the input if
1778 			 * one was input
1779 			 */
1780 			if (object &&
1781 			    ipAddressesEqual(discAddrProps.discoveryAddress,
1782 			    address) && (discAddrProps.discoveryAddress.
1783 			    portNumber == address.portNumber)) {
1784 				found = B_TRUE;
1785 			}
1786 
1787 			if (!object || found) {
1788 				/* Print summary - always */
1789 				if (discAddrProps.discoveryAddress.
1790 				    hostnameIpAddress.id.ipAddress.
1791 				    ipv4Address) {
1792 					(void) inet_ntop(AF_INET, discAddrProps.
1793 					    discoveryAddress.hostnameIpAddress.
1794 					    id.ipAddress.ipAddress, sAddr,
1795 					    sizeof (sAddr));
1796 					(void) fprintf(stdout,
1797 					    "Discovery Address: %s:%u\n",
1798 					    sAddr, discAddrProps.
1799 					    discoveryAddress.portNumber);
1800 				} else {
1801 					(void) inet_ntop(AF_INET6,
1802 					    discAddrProps.
1803 					    discoveryAddress.hostnameIpAddress.
1804 					    id.ipAddress.ipAddress, sAddr,
1805 					    sizeof (sAddr));
1806 					(void) fprintf(stdout,
1807 					    "DiscoveryAddress: [%s]:%u\n",
1808 					    sAddr, discAddrProps.
1809 					    discoveryAddress.portNumber);
1810 				}
1811 			}
1812 
1813 			if ((!object || found) && verbose) {
1814 				IMA_NODE_PROPERTIES nodeProps;
1815 
1816 				if (getNodeProps(&nodeProps) != 0) {
1817 					break;
1818 				}
1819 
1820 				/*
1821 				 * Issue sendTargets only when an addr is
1822 				 * specified.
1823 				 */
1824 				status = SUN_IMA_SendTargets(nodeProps.name,
1825 				    discAddrProps.discoveryAddress, &pList);
1826 				if (!IMA_SUCCESS(status)) {
1827 					(void) fprintf(stderr, "%s\n",
1828 					    gettext("\tUnable to get "\
1829 					    "targets."));
1830 					*funcRet = 1;
1831 					continue;
1832 				}
1833 				printSendTargets(pList);
1834 			}
1835 
1836 			if (found) {
1837 				/* we found the discovery address - break */
1838 				break;
1839 			}
1840 		}
1841 		/*
1842 		 * There was an object entered but we didn't
1843 		 * find it.
1844 		 */
1845 		if (object && !found) {
1846 			(void) fprintf(stdout, "%s: %s\n",
1847 			    objects[i], gettext("not found"));
1848 		}
1849 	}
1850 	return (ret);
1851 }
1852 
1853 /*
1854  * Print ISNS Server addresses
1855  */
1856 static int
1857 listISNSServerAddress(int objectLen, char *objects[], cmdOptions_t *options,
1858     int *funcRet)
1859 {
1860 	IMA_OID	initiatorOid;
1861 	SUN_IMA_DISC_ADDR_PROP_LIST	    *discoveryAddressPropertiesList;
1862 	IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps;
1863 	IMA_TARGET_ADDRESS address;
1864 	SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
1865 	IMA_STATUS status;
1866 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
1867 	int ret;
1868 	boolean_t object = B_FALSE;
1869 	int outerLoop;
1870 	boolean_t found;
1871 	boolean_t showTarget = B_FALSE;
1872 	int i, j;
1873 	cmdOptions_t *optionList = options;
1874 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
1875 
1876 	assert(funcRet != NULL);
1877 
1878 	/* Find Sun initiator */
1879 	ret = sunInitiatorFind(&initiatorOid);
1880 	if (ret > 0) {
1881 		(void) fprintf(stderr, "%s: %s\n",
1882 		    cmdName, gettext("no initiator found"));
1883 	}
1884 
1885 	if (ret != 0) {
1886 		return (ret);
1887 	}
1888 
1889 	for (; optionList->optval; optionList++) {
1890 		switch (optionList->optval) {
1891 			case 'v':
1892 				showTarget = B_TRUE;
1893 				break;
1894 			default:
1895 				(void) fprintf(stderr, "%s: %c: %s\n",
1896 				    cmdName, optionList->optval,
1897 				    gettext("unknown option"));
1898 				return (1);
1899 		}
1900 	}
1901 
1902 	/*
1903 	 * If there are multiple objects, execute outer 'for' loop that
1904 	 * many times for each target detail, otherwise, execute it only
1905 	 * once with summaries only
1906 	 */
1907 	if (objectLen > 0) {
1908 		object = B_TRUE;
1909 		outerLoop = objectLen;
1910 	} else {
1911 		object = B_FALSE;
1912 		outerLoop = 1;
1913 	}
1914 
1915 	status = SUN_IMA_GetISNSServerAddressPropertiesList(
1916 	    &discoveryAddressPropertiesList);
1917 	if (!IMA_SUCCESS(status)) {
1918 		printLibError(status);
1919 		*funcRet = 1;
1920 		return (ret);
1921 	}
1922 
1923 	for (i = 0; i < outerLoop; i++) {
1924 		if (object) {
1925 			/* initialize */
1926 			(void) memset(&wcInputObject[0], 0,
1927 			    sizeof (wcInputObject));
1928 			(void) memset(&address, 0, sizeof (address));
1929 			if (mbstowcs(wcInputObject, objects[i],
1930 			    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
1931 				(void) fprintf(stderr, "%s: %s\n",
1932 				    cmdName,
1933 				    gettext("conversion error"));
1934 				ret = 1;
1935 				continue;
1936 			}
1937 
1938 			/*
1939 			 * if one or more objects were input,
1940 			 * get the values
1941 			 */
1942 			if (getTargetAddress(ISNS_SERVER_ADDRESS,
1943 			    objects[i], &address) != 0) {
1944 				ret = 1;
1945 				continue;
1946 			}
1947 		}
1948 		for (found = B_FALSE, j = 0;
1949 		    j < discoveryAddressPropertiesList->discAddrCount;
1950 		    j++) {
1951 			discAddrProps =
1952 			    discoveryAddressPropertiesList->props[j];
1953 
1954 			/*
1955 			 * Compare the discovery address with the input if
1956 			 * one was input
1957 			 */
1958 			if (object &&
1959 			    ipAddressesEqual(discAddrProps.discoveryAddress,
1960 			    address) &&
1961 			    (discAddrProps.discoveryAddress.portNumber ==
1962 			    address.portNumber)) {
1963 				found = B_TRUE;
1964 			}
1965 
1966 			if (!object || found) {
1967 				/* Print summary - always */
1968 				if (discAddrProps.discoveryAddress.
1969 				    hostnameIpAddress.id.ipAddress.
1970 				    ipv4Address) {
1971 					(void) inet_ntop(AF_INET, discAddrProps.
1972 					    discoveryAddress.hostnameIpAddress.
1973 					    id.ipAddress.ipAddress, sAddr,
1974 					    sizeof (sAddr));
1975 				} else {
1976 					(void) inet_ntop(AF_INET6,
1977 					    discAddrProps.
1978 					    discoveryAddress.hostnameIpAddress.
1979 					    id.ipAddress.ipAddress, sAddr,
1980 					    sizeof (sAddr));
1981 				}
1982 				(void) fprintf(stdout,
1983 				    "iSNS Server IP Address: %s:%u\n",
1984 				    sAddr,
1985 				    discAddrProps.discoveryAddress.portNumber);
1986 			}
1987 
1988 			if ((!object || found) && showTarget) {
1989 				IMA_NODE_PROPERTIES nodeProps;
1990 
1991 				if (getNodeProps(&nodeProps) != 0) {
1992 					break;
1993 				}
1994 
1995 				/*
1996 				 * Issue sendTargets only when an addr is
1997 				 * specified.
1998 				 */
1999 				status = SUN_IMA_RetrieveISNSServerTargets(
2000 				    discAddrProps.discoveryAddress,
2001 				    &pList);
2002 				if (!IMA_SUCCESS(status)) {
2003 					/*
2004 					 * Check if the discovery mode is
2005 					 * disabled.
2006 					 */
2007 					if (status ==
2008 					    IMA_ERROR_OBJECT_NOT_FOUND) {
2009 						(void) fprintf(stderr, "%s\n",
2010 						    gettext("\tiSNS "\
2011 						    "discovery "\
2012 						    "mode "\
2013 						    "disabled. "\
2014 						    "No targets "\
2015 						    "to report."));
2016 
2017 					} else {
2018 						(void) fprintf(stderr, "%s\n",
2019 						    gettext("\tUnable "\
2020 						    "to get "\
2021 						    "targets."));
2022 					}
2023 					continue;
2024 				}
2025 				printSendTargets(pList);
2026 			}
2027 
2028 			if (found) {
2029 				/* we found the discovery address - break */
2030 				break;
2031 			}
2032 		}
2033 		/*
2034 		 * There was an object entered but we didn't
2035 		 * find it.
2036 		 */
2037 		if (object && !found) {
2038 			(void) fprintf(stdout, "%s: %s\n",
2039 			    objects[i], gettext("not found"));
2040 		}
2041 	}
2042 	return (ret);
2043 }
2044 
2045 /*
2046  * Print static configuration targets
2047  */
2048 static int
2049 listStaticConfig(int operandLen, char *operand[], int *funcRet)
2050 {
2051 	IMA_STATUS status;
2052 	IMA_OID	initiatorOid;
2053 	IMA_OID_LIST *staticTargetList;
2054 	SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps;
2055 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
2056 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2057 	wchar_t wcCol;
2058 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
2059 	int ret;
2060 	boolean_t object = B_FALSE;
2061 	int outerLoop;
2062 	boolean_t found; /* B_TRUE if a target name is found */
2063 	boolean_t matched; /* B_TRUE if a specific target is found */
2064 	boolean_t targetAddressSpecified = B_FALSE;
2065 	boolean_t tpgtSpecified = B_FALSE;
2066 	boolean_t isIpv6;
2067 	int i, j;
2068 	IMA_UINT16 port = 0;
2069 	IMA_UINT16 tpgt = 0;
2070 	char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
2071 	wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2072 
2073 	assert(funcRet != NULL);
2074 
2075 	/* Find Sun initiator */
2076 	ret = sunInitiatorFind(&initiatorOid);
2077 	if (ret > 0) {
2078 		(void) fprintf(stderr, "%s: %s\n",
2079 		    cmdName, gettext("no initiator found"));
2080 	}
2081 
2082 	if (ret != 0) {
2083 		return (ret);
2084 	}
2085 
2086 	/*
2087 	 * If there are multiple objects, execute outer 'for' loop that
2088 	 * many times for each static config detail, otherwise, execute it only
2089 	 * once with summaries only
2090 	 */
2091 	if (operandLen > 0) {
2092 		object = B_TRUE;
2093 		outerLoop = operandLen;
2094 	} else {
2095 		object = B_FALSE;
2096 		outerLoop = 1;
2097 	}
2098 
2099 	/* convert ':' to wide char for wchar string search */
2100 	if (mbtowc(&wcCol, ":", sizeof (wcCol)) == -1) {
2101 		(void) fprintf(stderr, "%s: %s\n",
2102 		    cmdName, gettext("conversion error"));
2103 		return (1);
2104 	}
2105 
2106 	status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid,
2107 	    &staticTargetList);
2108 	if (!IMA_SUCCESS(status)) {
2109 		printLibError(status);
2110 		*funcRet = 1;
2111 		return (ret);
2112 	}
2113 
2114 	for (i = 0; i < outerLoop; i++) {
2115 		if (object) {
2116 			if (parseTarget(operand[i],
2117 			    &staticTargetName[0],
2118 			    MAX_ISCSI_NAME_LEN + 1,
2119 			    &targetAddressSpecified,
2120 			    &staticTargetAddress[0],
2121 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2122 			    &port,
2123 			    &tpgtSpecified,
2124 			    &tpgt,
2125 			    &isIpv6) != PARSE_TARGET_OK) {
2126 				ret = 1;
2127 				continue;
2128 			}
2129 		}
2130 
2131 		for (found = B_FALSE, j = 0; j < staticTargetList->oidCount;
2132 		    j++) {
2133 			boolean_t isIpv6 = B_FALSE;
2134 			IMA_UINT16 stpgt;
2135 			IMA_BOOL defaultTpgt;
2136 
2137 			matched = B_FALSE;
2138 			(void) memset(&staticTargetProps, 0,
2139 			    sizeof (staticTargetProps));
2140 
2141 			status = SUN_IMA_GetStaticTargetProperties(
2142 			    staticTargetList->oids[j], &staticTargetProps);
2143 			if (!IMA_SUCCESS(status)) {
2144 				printLibError(status);
2145 				(void) IMA_FreeMemory(staticTargetList);
2146 				*funcRet = 1;
2147 				return (ret);
2148 			}
2149 
2150 			stpgt = staticTargetProps.staticTarget.targetAddress.
2151 			    tpgt;
2152 
2153 			defaultTpgt = staticTargetProps.staticTarget.
2154 			    targetAddress.defaultTpgt;
2155 
2156 			isIpv6 = !staticTargetProps.staticTarget.targetAddress.
2157 			    imaStruct.hostnameIpAddress.id.ipAddress.
2158 			    ipv4Address;
2159 
2160 			/*
2161 			 * Compare the static target name with the input if
2162 			 * one was input
2163 			 */
2164 
2165 			if (object &&
2166 			    (targetNamesEqual(
2167 			    staticTargetProps.staticTarget.targetName,
2168 			    staticTargetName) == B_TRUE)) {
2169 				/* targetName found - found = B_TRUE */
2170 				found = B_TRUE;
2171 				if (targetAddressSpecified == B_FALSE) {
2172 					matched = B_TRUE;
2173 				} else {
2174 
2175 				if (staticTargetProps.staticTarget.
2176 				    targetAddress.imaStruct.
2177 				    hostnameIpAddress.id.ipAddress.
2178 				    ipv4Address == IMA_TRUE) {
2179 					(void) inet_ntop(AF_INET,
2180 					    staticTargetProps.
2181 					    staticTarget.targetAddress.
2182 					    imaStruct.hostnameIpAddress.id.
2183 					    ipAddress.ipAddress, tmpStr,
2184 					    sizeof (tmpStr));
2185 				} else {
2186 					(void) inet_ntop(AF_INET6,
2187 					    staticTargetProps.
2188 					    staticTarget.targetAddress.
2189 					    imaStruct.hostnameIpAddress.id.
2190 					    ipAddress.ipAddress, tmpStr,
2191 					    sizeof (tmpStr));
2192 				}
2193 
2194 				if (mbstowcs(tmpTargetAddress, tmpStr,
2195 				    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
2196 				    (size_t)-1) {
2197 					(void) fprintf(stderr, "%s: %s\n",
2198 					    cmdName,
2199 					gettext("conversion error"));
2200 					ret = 1;
2201 					continue;
2202 				}
2203 
2204 				if (wcsncmp(tmpTargetAddress,
2205 				    staticTargetAddress,
2206 				    SUN_IMA_IP_ADDRESS_PORT_LEN)
2207 				    == 0 &&
2208 				    staticTargetProps.
2209 				    staticTarget.targetAddress.
2210 				    imaStruct.portNumber == port) {
2211 					/*
2212 					 * Since an object is
2213 					 * specified, it should also
2214 					 * have a tpgt specified. If
2215 					 * not, that means the object
2216 					 * specified is associated with
2217 					 * the default tpgt. In
2218 					 * either case, a tpgt
2219 					 * comparison should be done
2220 					 * before claiming that a
2221 					 * match is found.
2222 					 */
2223 					if ((tpgt == stpgt &&
2224 					    tpgtSpecified == B_TRUE &&
2225 					    defaultTpgt == IMA_FALSE) ||
2226 					    (tpgt == stpgt &&
2227 					    tpgtSpecified == B_FALSE &&
2228 					    defaultTpgt == IMA_TRUE)) {
2229 						matched = B_TRUE;
2230 					}
2231 				}
2232 
2233 				}
2234 			}
2235 
2236 			if (!object || matched) {
2237 				/* print summary - always */
2238 				(void) fprintf(stdout, gettext("%s: %ws,"),
2239 				    "Static Configuration Target",
2240 				    staticTargetProps.staticTarget.targetName);
2241 
2242 				if (isIpv6 == B_FALSE) {
2243 					(void) inet_ntop(AF_INET,
2244 					    staticTargetProps.
2245 					    staticTarget.targetAddress.
2246 					    imaStruct.hostnameIpAddress.id.
2247 					    ipAddress.ipAddress, sAddr,
2248 					    sizeof (sAddr));
2249 					(void) fprintf(stdout, "%s:%d",
2250 					    sAddr,
2251 					    staticTargetProps.staticTarget.
2252 					    targetAddress.imaStruct.portNumber);
2253 				} else {
2254 					(void) inet_ntop(AF_INET6,
2255 					    staticTargetProps.
2256 					    staticTarget.targetAddress.
2257 					    imaStruct.hostnameIpAddress.id.
2258 					    ipAddress.ipAddress, sAddr,
2259 					    sizeof (sAddr));
2260 					(void) fprintf(stdout, "[%s]:%d",
2261 					    sAddr,
2262 					    staticTargetProps.staticTarget.
2263 					    targetAddress.imaStruct.portNumber);
2264 				}
2265 
2266 				if (staticTargetProps.staticTarget.
2267 				    targetAddress.
2268 				    defaultTpgt == IMA_FALSE) {
2269 					(void) fprintf(stdout, ",%d\n",
2270 					    staticTargetProps.
2271 					    staticTarget.targetAddress.tpgt);
2272 				} else {
2273 					(void) fprintf(stdout, "\n");
2274 				}
2275 			}
2276 
2277 		}
2278 		/*
2279 		 * No details to display, but if there were:
2280 		 *  if (object && found)...
2281 		 *
2282 		 */
2283 
2284 		/*
2285 		 * There was an object entered but we didn't
2286 		 * find it.
2287 		 */
2288 		if (object && !found) {
2289 			(void) fprintf(stdout, "%s: %s\n",
2290 			    operand[i], gettext("not found"));
2291 			ret = 1; /* DIY test fix */
2292 		}
2293 	}
2294 	return (ret);
2295 }
2296 
2297 /*
2298  * Print targets
2299  */
2300 /*ARGSUSED*/
2301 static int
2302 listTarget(int objectLen, char *objects[], cmdOptions_t *options, int *funcRet)
2303 {
2304 	IMA_OID	initiatorOid;
2305 	IMA_OID_LIST *targetList;
2306 	IMA_OID_LIST *lunList;
2307 	SUN_IMA_TARGET_PROPERTIES targetProps;
2308 	IMA_STATUS status;
2309 	IMA_OID_LIST *pConnList;
2310 	SUN_IMA_CONN_PROPERTIES *connProps;
2311 
2312 	int ret;
2313 	wchar_t targetName[MAX_ISCSI_NAME_LEN + 1];
2314 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2315 	int outerLoop;
2316 	boolean_t found;
2317 	boolean_t operandEntered = B_FALSE;
2318 	boolean_t verbose = B_FALSE;
2319 	boolean_t scsi_target = B_FALSE;
2320 	boolean_t targetAddressSpecified = B_FALSE;
2321 	boolean_t isIpv6 = B_FALSE;
2322 	int i, j;
2323 	cmdOptions_t *optionList = options;
2324 	boolean_t tpgtSpecified = B_FALSE;
2325 	IMA_UINT16 port = 0;
2326 	uint16_t tpgt;
2327 
2328 	assert(funcRet != NULL);
2329 
2330 	/* Find Sun initiator */
2331 	ret = sunInitiatorFind(&initiatorOid);
2332 	if (ret > 0) {
2333 		(void) fprintf(stderr, "%s: %s\n",
2334 		    cmdName, gettext("no initiator found"));
2335 	}
2336 
2337 	if (ret != 0) {
2338 		return (ret);
2339 	}
2340 
2341 	for (; optionList->optval; optionList++) {
2342 		switch (optionList->optval) {
2343 			case 'S':
2344 				scsi_target = B_TRUE;
2345 				break;
2346 			case 'v':
2347 				verbose = B_TRUE;
2348 				break;
2349 			default:
2350 				(void) fprintf(stderr, "%s: %c: %s\n",
2351 				    cmdName, optionList->optval,
2352 				    gettext("unknown option"));
2353 				return (1);
2354 		}
2355 	}
2356 
2357 	/*
2358 	 * If there are multiple objects, execute outer 'for' loop that
2359 	 * many times for each target detail, otherwise, execute it only
2360 	 * once with summaries only
2361 	 */
2362 	if (objectLen > 0) {
2363 		operandEntered = B_TRUE;
2364 		outerLoop = objectLen;
2365 	} else {
2366 		operandEntered = B_FALSE;
2367 		outerLoop = 1;
2368 	}
2369 
2370 	status = SUN_IMA_GetSessionOidList(initiatorOid, &targetList);
2371 	if (!IMA_SUCCESS(status)) {
2372 		printLibError(status);
2373 		*funcRet = 1;
2374 		return (ret);
2375 	}
2376 
2377 	for (i = 0; i < outerLoop; i++) {
2378 
2379 		tpgtSpecified = B_FALSE;
2380 		if (operandEntered) {
2381 			if (parseTarget(objects[i],
2382 			    &targetName[0],
2383 			    MAX_ISCSI_NAME_LEN + 1,
2384 			    &targetAddressSpecified,
2385 			    &targetAddress[0],
2386 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2387 			    &port,
2388 			    &tpgtSpecified,
2389 			    &tpgt,
2390 			    &isIpv6) != PARSE_TARGET_OK) {
2391 				ret = 1;
2392 				continue;
2393 			}
2394 		}
2395 		for (found = B_FALSE, j = 0; j < targetList->oidCount; j++) {
2396 			status = SUN_IMA_GetTargetProperties(
2397 			    targetList->oids[j],
2398 			    &targetProps);
2399 			if (!IMA_SUCCESS(status)) {
2400 				printLibError(status);
2401 				(void) IMA_FreeMemory(targetList);
2402 				*funcRet = 1;
2403 				return (ret);
2404 			}
2405 
2406 			/*
2407 			 * Compare the target name with the input if
2408 			 * one was input, if they match, print the target's info
2409 			 *
2410 			 * if no target name was input, continue printing this
2411 			 * target
2412 			 */
2413 			if (operandEntered) {
2414 				if (targetNamesEqual(targetProps.imaProps.name,
2415 				    targetName) == B_TRUE) {
2416 					if (tpgtSpecified == B_TRUE) {
2417 						if (targetProps.
2418 						    defaultTpgtConf ==
2419 						    IMA_FALSE &&
2420 						    targetProps.
2421 						    tpgtConf == tpgt) {
2422 							found = B_TRUE;
2423 						} else {
2424 							/*
2425 							 * tpgt does not match,
2426 							 * move on to next
2427 							 * target
2428 							 */
2429 							continue;
2430 						}
2431 					} else {
2432 						found = B_TRUE;
2433 					}
2434 				} else {
2435 					/*
2436 					 * target name does not match, move on
2437 					 * to next target
2438 					 */
2439 					continue;
2440 				}
2441 			}
2442 
2443 			/* print summary - always */
2444 			(void) fprintf(stdout, gettext("%s: %ws\n"),
2445 			    gettext("Target"), targetProps.imaProps.name);
2446 
2447 			/* Alias */
2448 			(void) fprintf(stdout, "\t%s: ", gettext("Alias"));
2449 			if (wslen(targetProps.imaProps.alias) > (size_t)0) {
2450 				(void) fprintf(stdout, gettext("%ws\n"),
2451 				    targetProps.imaProps.alias);
2452 			} else {
2453 				(void) fprintf(stdout, "%s\n", "-");
2454 			}
2455 
2456 			if (targetProps.defaultTpgtNego != IMA_TRUE) {
2457 				(void) fprintf(stdout, "%s%s: %d\n",
2458 				    "\t", gettext("TPGT"),
2459 				    targetProps.tpgtNego);
2460 			} else if (targetProps.defaultTpgtConf != IMA_TRUE) {
2461 				(void) fprintf(stdout, "%s%s: %d\n",
2462 				    "\t", gettext("TPGT"),
2463 				    targetProps.tpgtConf);
2464 			}
2465 
2466 			(void) fprintf(stdout,
2467 			    "%s%s: %02x%02x%02x%02x%02x%02x\n",
2468 			    "\t", gettext("ISID"),
2469 			    targetProps.isid[0], targetProps.isid[1],
2470 			    targetProps.isid[2], targetProps.isid[3],
2471 			    targetProps.isid[4], targetProps.isid[5]);
2472 
2473 			pConnList = NULL;
2474 			status = SUN_IMA_GetConnOidList(
2475 			    &targetList->oids[j],
2476 			    &pConnList);
2477 
2478 			if (!IMA_SUCCESS(status)) {
2479 				printLibError(status);
2480 				(void) IMA_FreeMemory(targetList);
2481 				*funcRet = 1;
2482 				return (ret);
2483 			}
2484 
2485 			(void) fprintf(stdout, "%s%s: %lu\n",
2486 			    "\t",
2487 			    gettext("Connections"),
2488 			    pConnList->oidCount);
2489 
2490 			if (verbose) {
2491 				SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
2492 
2493 				printConnectionList("\t\t", pConnList);
2494 				printDiscoveryMethod(
2495 				    "\t\t  ",
2496 				    targetProps.imaProps.discoveryMethodFlags);
2497 				(void) printLoginParameters(
2498 				    "\t\t  ",
2499 				    targetList->oids[j],
2500 				    PRINT_NEGOTIATED_PARAMS);
2501 
2502 				/* Get Digest configuration */
2503 				status = SUN_IMA_GetConnProperties(
2504 				    &pConnList->oids[0], &connProps);
2505 
2506 				(void) getNegotiatedDigest(
2507 				    ISCSI_LOGIN_PARAM_HEADER_DIGEST,
2508 				    &digestAlgorithms, connProps);
2509 
2510 				if (IMA_SUCCESS(status)) {
2511 					(void) fprintf(stdout, "\t\t  \t%s: ",
2512 					    gettext("Header Digest"));
2513 					printDigestAlgorithm(
2514 					    &digestAlgorithms,
2515 					    PRINT_NEGOTIATED_PARAMS);
2516 				} else {
2517 					(void) IMA_FreeMemory(pConnList);
2518 					(void) IMA_FreeMemory(targetList);
2519 					printLibError(status);
2520 					*funcRet = 1;
2521 					return (ret);
2522 				}
2523 
2524 				(void) getNegotiatedDigest(
2525 				    ISCSI_LOGIN_PARAM_DATA_DIGEST,
2526 				    &digestAlgorithms, connProps);
2527 
2528 				if (IMA_SUCCESS(status)) {
2529 					(void) fprintf(stdout, "\t\t  \t%s: ",
2530 					    gettext("Data Digest"));
2531 					printDigestAlgorithm(
2532 					    &digestAlgorithms,
2533 					    PRINT_NEGOTIATED_PARAMS);
2534 				} else {
2535 					(void) IMA_FreeMemory(pConnList);
2536 					(void) IMA_FreeMemory(targetList);
2537 					printLibError(status);
2538 					*funcRet = 1;
2539 					return (ret);
2540 				}
2541 
2542 				(void) fprintf(stdout, "\n");
2543 			}
2544 
2545 			if (scsi_target) {
2546 				status = IMA_GetLuOidList(
2547 				    targetList->oids[j],
2548 				    &lunList);
2549 				if (!IMA_SUCCESS(status)) {
2550 					printLibError(status);
2551 					(void) IMA_FreeMemory(targetList);
2552 					*funcRet = 1;
2553 					return (ret);
2554 				}
2555 				if (lunList->oidCount != 0) {
2556 					printTargetLuns(lunList);
2557 				}
2558 				(void) fprintf(stdout, "\n");
2559 				(void) IMA_FreeMemory(lunList);
2560 			}
2561 		}
2562 		/*
2563 		 * did we find the object
2564 		 */
2565 
2566 		if (operandEntered && !found) {
2567 			(void) fprintf(stdout, "%s: %s\n",
2568 			    objects[i], gettext("not found"));
2569 		}
2570 	}
2571 
2572 	(void) IMA_FreeMemory(targetList);
2573 	return (ret);
2574 }
2575 
2576 
2577 /*
2578  * Print configured session information
2579  */
2580 static int
2581 printConfiguredSessions(IMA_OID oid)
2582 {
2583 	IMA_STATUS		status;
2584 	const char		*rtn;
2585 	SUN_IMA_CONFIG_SESSIONS	*pConfigSessions;
2586 	char			address[MAX_ADDRESS_LEN];
2587 	int			out;
2588 
2589 	/* Get configured session information */
2590 	status = SUN_IMA_GetConfigSessions(oid, &pConfigSessions);
2591 
2592 	if (IMA_SUCCESS(status)) {
2593 		(void) fprintf(stdout, "\t%s: ",
2594 		    gettext("Configured Sessions"));
2595 		if (pConfigSessions->bound == IMA_FALSE) {
2596 			/* default binding */
2597 			(void) fprintf(stdout, "%lu\n", pConfigSessions->out);
2598 		} else {
2599 			/* hardcoded binding */
2600 			for (out = 0;
2601 			    out < pConfigSessions->out; out++) {
2602 				if (pConfigSessions->bindings[out].
2603 				    ipAddress.ipv4Address == IMA_TRUE) {
2604 					rtn = inet_ntop(AF_INET,
2605 					    pConfigSessions->bindings[out].
2606 					    ipAddress.ipAddress, address,
2607 					    MAX_ADDRESS_LEN);
2608 				} else {
2609 					rtn = inet_ntop(AF_INET6,
2610 					    pConfigSessions->bindings[out].
2611 					    ipAddress.ipAddress, address,
2612 					    MAX_ADDRESS_LEN);
2613 				}
2614 				if (rtn != NULL) {
2615 					(void) printf("%s ", address);
2616 				}
2617 			}
2618 			(void) fprintf(stdout, "\n");
2619 		}
2620 	} else {
2621 		free(pConfigSessions);
2622 		printLibError(status);
2623 		return (1);
2624 	}
2625 
2626 	free(pConfigSessions);
2627 	return (0);
2628 }
2629 
2630 /*
2631  * Print target parameters
2632  */
2633 static int
2634 listTargetParam(int operandLen, char *operand[], cmdOptions_t *options,
2635     int *funcRet)
2636 {
2637 	IMA_STATUS status;
2638 	IMA_OID	initiatorOid;
2639 	IMA_OID_LIST *targetList;
2640 	IMA_AUTHMETHOD	methodList[MAX_AUTH_METHODS];
2641 	SUN_IMA_TARGET_PROPERTIES targetProps;
2642 	IMA_UINT maxEntries = MAX_AUTH_METHODS;
2643 	IMA_BOOL bidirAuth;
2644 	int ret;
2645 	wchar_t targetName[MAX_ISCSI_NAME_LEN + 1];
2646 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2647 	boolean_t operandEntered = B_FALSE;
2648 	boolean_t targetAddressSpecified = B_FALSE;
2649 	boolean_t printObject = B_FALSE;
2650 	boolean_t tpgtSpecified = B_FALSE;
2651 	boolean_t isIpv6 = B_FALSE;
2652 	int outerLoop;
2653 	boolean_t found;
2654 	int i, j;
2655 	SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
2656 	boolean_t verbose = B_FALSE;
2657 	cmdOptions_t *optionList = options;
2658 	IMA_UINT16 port = 0;
2659 	IMA_UINT16 tpgt = 0;
2660 
2661 	assert(funcRet != NULL);
2662 
2663 	/* Find Sun initiator */
2664 	ret = sunInitiatorFind(&initiatorOid);
2665 	if (ret > 0) {
2666 		(void) fprintf(stderr, "%s: %s\n",
2667 		    cmdName, gettext("no initiator found"));
2668 	}
2669 
2670 	if (ret != 0) {
2671 		return (ret);
2672 	}
2673 
2674 	for (; optionList->optval; optionList++) {
2675 		switch (optionList->optval) {
2676 			case 'v':
2677 				verbose = B_TRUE;
2678 				break;
2679 			default:
2680 				(void) fprintf(stderr, "%s: %c: %s\n",
2681 				    cmdName, optionList->optval,
2682 				    gettext("unknown option"));
2683 				return (1);
2684 		}
2685 	}
2686 
2687 	/*
2688 	 * If there are multiple operands, execute outer 'for' loop that
2689 	 * many times to find each target parameter operand entered, otherwise,
2690 	 * execute it only once for all target parameters returned.
2691 	 */
2692 	if (operandLen > 0) {
2693 		operandEntered = B_TRUE;
2694 		outerLoop = operandLen;
2695 	} else {
2696 		operandEntered = B_FALSE;
2697 		outerLoop = 1;
2698 	}
2699 
2700 	/*
2701 	 * Ideally there should be an interface available for obtaining
2702 	 * the list of target-param objects. Since the driver currently
2703 	 * creates a target OID and the associated session structure when
2704 	 * a target-param object is created, we can leverage the target
2705 	 * OID list and use it to manage the target-param objects. When
2706 	 * we stop creating a session for target-param object in the
2707 	 * driver, we will switch to using a different interface to
2708 	 * obtain target-param objects.
2709 	 */
2710 	status = IMA_GetTargetOidList(initiatorOid, &targetList);
2711 	if (!IMA_SUCCESS(status)) {
2712 		printLibError(status);
2713 		*funcRet = 1;
2714 		return (ret);
2715 	}
2716 
2717 	for (i = 0; i < outerLoop; i++) {
2718 		if (operandEntered) {
2719 			if (parseTarget(operand[i],
2720 			    &targetName[0],
2721 			    MAX_ISCSI_NAME_LEN + 1,
2722 			    &targetAddressSpecified,
2723 			    &targetAddress[0],
2724 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2725 			    &port,
2726 			    &tpgtSpecified,
2727 			    &tpgt,
2728 			    &isIpv6) != PARSE_TARGET_OK) {
2729 				ret = 1;
2730 				continue;
2731 			}
2732 		}
2733 		for (j = 0; j < targetList->oidCount; j++) {
2734 			found = B_FALSE;
2735 			printObject = B_FALSE;
2736 			status = SUN_IMA_GetTargetProperties(
2737 			    targetList->oids[j],
2738 			    &targetProps);
2739 			if (!IMA_SUCCESS(status)) {
2740 				printLibError(status);
2741 				(void) IMA_FreeMemory(targetList);
2742 				*funcRet = 1;
2743 				return (ret);
2744 			}
2745 
2746 			/*
2747 			 * Compare the target name with the input if
2748 			 * one was input
2749 			 */
2750 			if (operandEntered &&
2751 			    (targetNamesEqual(targetProps.imaProps.name,
2752 			    targetName) == B_TRUE)) {
2753 				/*
2754 				 * For now, regardless of whether a target
2755 				 * address is specified, we return B_TRUE
2756 				 * because IMA_TARGET_PROPERTIES does not
2757 				 * have a field for specifying address.
2758 				 */
2759 				found = B_TRUE;
2760 			}
2761 
2762 			/*
2763 			 * if no operand was entered OR
2764 			 * an operand was entered and it was
2765 			 * found, we want to print
2766 			 */
2767 			if (!operandEntered || found) {
2768 				printObject = B_TRUE;
2769 			}
2770 
2771 			if (printObject) {
2772 				(void) fprintf(stdout, gettext("%s: %ws\n"),
2773 				    gettext("Target"),
2774 				    targetProps.imaProps.name);
2775 
2776 				(void) fprintf(stdout,
2777 				    "\t%s: ", gettext("Alias"));
2778 				if (wslen(targetProps.imaProps.alias) >
2779 				    (size_t)0) {
2780 					(void) fprintf(stdout,
2781 					    gettext("%ws\n"),
2782 					    targetProps.imaProps.alias);
2783 				} else {
2784 					(void) fprintf(stdout, "%s\n", "-");
2785 				}
2786 			}
2787 
2788 			if (printObject && verbose) {
2789 				/* Get bidirectional authentication flag */
2790 				(void) fprintf(stdout, "\t%s: ",
2791 				    gettext("Bi-directional Authentication"));
2792 				status = SUN_IMA_GetTargetBidirAuthFlag(
2793 				    targetList->oids[j],
2794 				    &bidirAuth);
2795 				if (IMA_SUCCESS(status)) {
2796 					if (bidirAuth == IMA_TRUE) {
2797 						(void) fprintf(stdout,
2798 						    gettext("enabled"));
2799 					} else {
2800 						(void) fprintf(stdout,
2801 						    gettext("disabled"));
2802 					}
2803 				} else {
2804 					(void) fprintf(stdout,
2805 					    gettext("disabled"));
2806 				}
2807 				(void) fprintf(stdout, "\n");
2808 
2809 				/* Get authentication type for this target */
2810 				status = SUN_IMA_GetTargetAuthMethods(
2811 				    initiatorOid,
2812 				    targetList->oids[j],
2813 				    &maxEntries,
2814 				    &methodList[0]);
2815 				(void) fprintf(stdout, "\t%s: ",
2816 				    gettext("Authentication Type"));
2817 				if (!IMA_SUCCESS(status)) {
2818 					/*
2819 					 * No authentication method define
2820 					 * NONE by default.
2821 					 */
2822 					(void) fprintf(stdout, gettext("NONE"));
2823 				} else {
2824 					for (i = 0; i < maxEntries; i++) {
2825 						if (i > 0) {
2826 							(void) fprintf(stdout,
2827 							    "|");
2828 						}
2829 						switch (methodList[i]) {
2830 						case IMA_AUTHMETHOD_NONE:
2831 							(void) fprintf(stdout,
2832 							    gettext("NONE"));
2833 							break;
2834 
2835 						case IMA_AUTHMETHOD_CHAP:
2836 							(void) fprintf(stdout,
2837 							    gettext("CHAP"));
2838 							listCHAPName(
2839 							    targetList->
2840 							    oids[j]);
2841 							break;
2842 
2843 						default:
2844 							(void) fprintf(stdout,
2845 							    gettext(
2846 							    "unknown "
2847 							    "type"));
2848 							break;
2849 						}
2850 					}
2851 				}
2852 				(void) fprintf(stdout, "\n");
2853 				if (printLoginParameters("\t",
2854 				    targetList->oids[j],
2855 				    PRINT_CONFIGURED_PARAMS)
2856 				    != 0) {
2857 					(void) IMA_FreeMemory(targetList);
2858 					*funcRet = 1;
2859 					return (ret);
2860 				}
2861 
2862 				/* Get Digest configuration */
2863 				status = SUN_IMA_GetHeaderDigest(
2864 				    targetList->oids[j],
2865 				    &digestAlgorithms);
2866 				if (IMA_SUCCESS(status)) {
2867 					(void) fprintf(stdout, "\t\t%s: ",
2868 					    gettext("Header Digest"));
2869 					printDigestAlgorithm(&digestAlgorithms,
2870 					    PRINT_CONFIGURED_PARAMS);
2871 				} else {
2872 					printLibError(status);
2873 					*funcRet = 1;
2874 					return (ret);
2875 				}
2876 
2877 				status = SUN_IMA_GetDataDigest(
2878 				    targetList->oids[j],
2879 				    &digestAlgorithms);
2880 				if (IMA_SUCCESS(status)) {
2881 					(void) fprintf(stdout, "\t\t%s: ",
2882 					    gettext("Data Digest"));
2883 					printDigestAlgorithm(&digestAlgorithms,
2884 					    PRINT_CONFIGURED_PARAMS);
2885 				} else {
2886 					printLibError(status);
2887 					*funcRet = 1;
2888 					return (ret);
2889 				}
2890 
2891 				/* print configured session information */
2892 				if (printConfiguredSessions(
2893 				    targetList->oids[j]) != 0) {
2894 					*funcRet = 1;
2895 					return (ret);
2896 				}
2897 
2898 				(void) fprintf(stdout, "\n");
2899 			}
2900 
2901 			if (found) {
2902 				break;
2903 			}
2904 		}
2905 		if (operandEntered && !found) {
2906 			*funcRet = 1; /* DIY message fix */
2907 			(void) fprintf(stdout, "%s: %s\n",
2908 			    operand[i], gettext("not found"));
2909 		}
2910 	}
2911 
2912 	(void) IMA_FreeMemory(targetList);
2913 	return (ret);
2914 }
2915 
2916 /*
2917  * Modify discovery attributes
2918  */
2919 static int
2920 modifyDiscovery(cmdOptions_t *options, int *funcRet)
2921 {
2922 	IMA_OID oid;
2923 	IMA_STATUS status;
2924 	IMA_BOOL setDiscovery;
2925 	IMA_HOST_ID hostId;
2926 
2927 	int ret;
2928 	cmdOptions_t *optionList = options;
2929 
2930 	assert(funcRet != NULL);
2931 
2932 	/* Find Sun initiator */
2933 	ret = sunInitiatorFind(&oid);
2934 	if (ret > 0) {
2935 		(void) fprintf(stderr, "%s: %s\n",
2936 		    cmdName, gettext("no initiator found"));
2937 	}
2938 
2939 	if (ret != 0) {
2940 		return (ret);
2941 	}
2942 
2943 	for (; optionList->optval; optionList++) {
2944 		/* check optarg and set bool accordingly */
2945 		if (strcasecmp(optionList->optarg, ISCSIADM_ARG_ENABLE) == 0) {
2946 			setDiscovery = IMA_TRUE;
2947 		} else if (strcasecmp(optionList->optarg, ISCSIADM_ARG_DISABLE)
2948 		    == 0) {
2949 			setDiscovery = IMA_FALSE;
2950 		} else {
2951 			(void) fprintf(stderr, "%s: %s\n",
2952 			    cmdName, gettext("invalid option argument"));
2953 			return (1);
2954 		}
2955 
2956 		switch (optionList->optval) {
2957 			case 's':
2958 				/* Set static discovery */
2959 				status = IMA_SetStaticDiscovery(oid,
2960 				    setDiscovery);
2961 				if (!IMA_SUCCESS(status)) {
2962 					printLibError(status);
2963 					*funcRet = 1;
2964 					return (ret);
2965 				}
2966 				break;
2967 			case 't':
2968 				/* Set send targets discovery */
2969 				status = IMA_SetSendTargetsDiscovery(oid,
2970 				    setDiscovery);
2971 				if (!IMA_SUCCESS(status)) {
2972 					printLibError(status);
2973 					*funcRet = 1;
2974 					return (ret);
2975 				}
2976 				break;
2977 			case 'i':
2978 				/* Set iSNS discovery */
2979 				(void) memset(&hostId, 0, sizeof (hostId));
2980 				status = IMA_SetIsnsDiscovery(oid, setDiscovery,
2981 				    IMA_ISNS_DISCOVERY_METHOD_STATIC, &hostId);
2982 				if (!IMA_SUCCESS(status)) {
2983 					printLibError(status);
2984 					*funcRet = 1;
2985 					return (ret);
2986 				}
2987 				break;
2988 			default:
2989 				(void) fprintf(stderr, "%s: %c: %s\n",
2990 				    cmdName, optionList->optval,
2991 				    gettext("unknown option"));
2992 				return (1);
2993 		}
2994 	}
2995 
2996 	return (ret);
2997 }
2998 
2999 /*
3000  * Set the initiator node's authentication method
3001  */
3002 static int
3003 modifyNodeAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet)
3004 {
3005 	IMA_INITIATOR_AUTHPARMS authParams;
3006 	IMA_STATUS status;
3007 	int ret;
3008 	int secretLen = MAX_CHAP_SECRET_LEN;
3009 
3010 	IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1];
3011 
3012 	assert(funcRet != NULL);
3013 
3014 	/*
3015 	 * Start with existing parameters and modify with the desired change
3016 	 * before passing along.  We ignore any failures as they probably
3017 	 * are caused by non-existence of auth params for the given node.
3018 	 */
3019 	status = IMA_GetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3020 	    &authParams);
3021 
3022 	switch (param) {
3023 	case AUTH_NAME:
3024 		if (chapName == NULL) {
3025 			(void) fprintf(stderr, "CHAP name cannot be NULL.\n");
3026 			return (1);
3027 		}
3028 		(void) memset(&authParams.chapParms.name, 0,
3029 		    sizeof (authParams.chapParms.name));
3030 		(void) memcpy(&authParams.chapParms.name,
3031 		    &chapName[0], strlen(chapName));
3032 		authParams.chapParms.nameLength = strlen(chapName);
3033 		break;
3034 
3035 	case AUTH_PASSWORD :
3036 		ret = getSecret((char *)&chapSecret[0], &secretLen,
3037 		    MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN);
3038 
3039 		if (ret != 0) {
3040 			return (ret);
3041 		}
3042 
3043 		(void) memset(&authParams.chapParms.challengeSecret, 0,
3044 		    sizeof (authParams.chapParms.challengeSecret));
3045 		(void) memcpy(&authParams.chapParms.challengeSecret,
3046 		    &chapSecret[0], secretLen);
3047 		authParams.chapParms.challengeSecretLength = secretLen;
3048 		break;
3049 
3050 	default:
3051 		(void) fprintf(stderr, "Invalid auth parameter %d\n", param);
3052 		return (1);
3053 	}
3054 
3055 	status = IMA_SetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3056 	    &authParams);
3057 	if (!IMA_SUCCESS(status)) {
3058 		printLibError(status);
3059 		*funcRet = 1;
3060 	}
3061 	return (ret);
3062 }
3063 
3064 /*
3065  * Set the target's authentication method
3066  */
3067 static int
3068 modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet)
3069 {
3070 	IMA_INITIATOR_AUTHPARMS authParams;
3071 	IMA_STATUS status;
3072 	int ret;
3073 	int secretLen = MAX_CHAP_SECRET_LEN;
3074 
3075 	IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1];
3076 
3077 	assert(funcRet != NULL);
3078 
3079 	/*
3080 	 * Start with existing parameters and modify with the desired change
3081 	 * before passing along.  We ignore any get failures as they probably
3082 	 * are caused by non-existence of auth params for the given target.
3083 	 */
3084 	status = SUN_IMA_GetTargetAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3085 	    &authParams);
3086 
3087 	switch (param) {
3088 	case AUTH_NAME:
3089 		if (chapName == NULL) {
3090 			(void) fprintf(stderr, "CHAP name cannot be NULL.\n");
3091 			return (1);
3092 		}
3093 		(void) memset(&authParams.chapParms.name, 0,
3094 		    sizeof (authParams.chapParms.name));
3095 		(void) memcpy(&authParams.chapParms.name,
3096 		    &chapName[0], strlen(chapName));
3097 		authParams.chapParms.nameLength = strlen(chapName);
3098 		break;
3099 
3100 	case AUTH_PASSWORD :
3101 		ret = getSecret((char *)&chapSecret[0], &secretLen,
3102 		    1, MAX_CHAP_SECRET_LEN);
3103 
3104 		if (ret != 0) {
3105 			return (ret);
3106 		}
3107 
3108 		(void) memset(&authParams.chapParms.challengeSecret, 0,
3109 		    sizeof (authParams.chapParms.challengeSecret));
3110 		(void) memcpy(&authParams.chapParms.challengeSecret,
3111 		    &chapSecret[0], secretLen);
3112 		authParams.chapParms.challengeSecretLength = secretLen;
3113 		break;
3114 
3115 	default:
3116 		(void) fprintf(stderr, "Invalid auth parameter %d\n", param);
3117 		return (1);
3118 	}
3119 
3120 	status = SUN_IMA_SetTargetAuthParams(oid, IMA_AUTHMETHOD_CHAP,
3121 	    &authParams);
3122 	if (!IMA_SUCCESS(status)) {
3123 		printLibError(status);
3124 		*funcRet = 1;
3125 	}
3126 	return (0);
3127 }
3128 
3129 static int
3130 modifyTargetBidirAuthFlag(IMA_OID targetOid, char *optarg, int *funcRet)
3131 {
3132 	IMA_BOOL boolValue;
3133 	IMA_STATUS status;
3134 
3135 	assert(funcRet != NULL);
3136 
3137 	if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) {
3138 		boolValue = IMA_TRUE;
3139 	} else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) {
3140 		boolValue = IMA_FALSE;
3141 	} else {
3142 		(void) fprintf(stderr, "%s: %s %s\n",
3143 		    cmdName, gettext("invalid option argument"), optarg);
3144 		return (1);
3145 	}
3146 
3147 	status = SUN_IMA_SetTargetBidirAuthFlag(targetOid, &boolValue);
3148 	if (!IMA_SUCCESS(status)) {
3149 		printLibError(status);
3150 		*funcRet = 1;
3151 	}
3152 	return (0);
3153 }
3154 
3155 static int
3156 modifyConfiguredSessions(IMA_OID targetOid, char *optarg)
3157 {
3158 	SUN_IMA_CONFIG_SESSIONS *pConfigSessions;
3159 	IMA_STATUS		status;
3160 	int			sessions;
3161 	int			size;
3162 	char			tmp[1024];
3163 	boolean_t		isIpv6 = B_FALSE;
3164 	uint16_t		port;
3165 	char			address[MAX_ADDRESS_LEN];
3166 	char			*commaPos;
3167 	char			*addressPos;
3168 	int			rtn;
3169 
3170 	/*
3171 	 * Strip the first int value from the string.  If we sprintf
3172 	 * this back to a string and it matches the original string
3173 	 * then this command is using default binding.  If not a
3174 	 * match we have hard coded binding or a usage error.
3175 	 */
3176 	sessions = atoi(optarg);
3177 	(void) sprintf(tmp, "%d", sessions);
3178 	if (strcmp(optarg, tmp) == 0) {
3179 		/* default binding */
3180 
3181 		/* allocate the required pConfigSessions */
3182 		size = sizeof (SUN_IMA_CONFIG_SESSIONS);
3183 		pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
3184 		if (pConfigSessions == NULL) {
3185 			return (1);
3186 		}
3187 
3188 		/* setup pConfigSessions */
3189 		pConfigSessions->bound	= IMA_FALSE;
3190 		pConfigSessions->in	= sessions;
3191 		pConfigSessions->out	= 0;
3192 	} else {
3193 		/* hardcoded binding */
3194 
3195 		/*
3196 		 * First we need to determine how many bindings
3197 		 * are available.  This can be done by scanning
3198 		 * for the number of ',' + 1.
3199 		 */
3200 		sessions = 1;
3201 		commaPos = strchr(optarg, ',');
3202 		while (commaPos != NULL) {
3203 			sessions++;
3204 			commaPos = strchr(++commaPos, ',');
3205 		}
3206 
3207 		/* allocate the required pConfigSessions */
3208 		size = sizeof (SUN_IMA_CONFIG_SESSIONS) + ((sessions - 1) *
3209 		    sizeof (IMA_ADDRESS_KEY));
3210 		pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
3211 		if (pConfigSessions == NULL) {
3212 			return (1);
3213 		}
3214 
3215 		/* setup pConfigSessions */
3216 		pConfigSessions->bound	= IMA_TRUE;
3217 		pConfigSessions->in	= sessions;
3218 		pConfigSessions->out	= 0;
3219 
3220 		/* Now fill in the binding information.  */
3221 		sessions = 0;
3222 		addressPos = optarg;
3223 		/*
3224 		 * Walk thru possible address strings
3225 		 * stop once all strings are processed.
3226 		 */
3227 		while (addressPos != NULL) {
3228 			/*
3229 			 * Check if there is another address after this
3230 			 * one. If so terminate the current address and
3231 			 * keep a pointer to the next one.
3232 			 */
3233 			commaPos = strchr(addressPos, ',');
3234 			if (commaPos != NULL) {
3235 				*commaPos++ = 0x00;
3236 			}
3237 
3238 			/*
3239 			 * Parse current address.  If invalid abort
3240 			 * processing of addresses and free memory.
3241 			 */
3242 			if (parseAddress(addressPos, 0, address,
3243 			    MAX_ADDRESS_LEN, &port, &isIpv6) != PARSE_ADDR_OK) {
3244 				free(pConfigSessions);
3245 				printLibError(IMA_ERROR_INVALID_PARAMETER);
3246 				return (1);
3247 			}
3248 
3249 			/* Convert address into binary form */
3250 			if (isIpv6 == B_FALSE) {
3251 				pConfigSessions->bindings[sessions].
3252 				    ipAddress.ipv4Address = IMA_TRUE;
3253 				rtn = inet_pton(AF_INET, address,
3254 				    pConfigSessions->bindings[sessions].
3255 				    ipAddress.ipAddress);
3256 			} else {
3257 				pConfigSessions->bindings[sessions].ipAddress.
3258 				    ipv4Address =
3259 				    IMA_FALSE;
3260 				rtn = inet_pton(AF_INET6, address,
3261 				    pConfigSessions->bindings[sessions].
3262 				    ipAddress.ipAddress);
3263 			}
3264 			if (rtn == 0) {
3265 				/* inet_pton found address invalid */
3266 				free(pConfigSessions);
3267 				printLibError(IMA_ERROR_INVALID_PARAMETER);
3268 				return (1);
3269 			}
3270 
3271 			/* update addressPos to next address */
3272 			sessions++;
3273 			addressPos = commaPos;
3274 		}
3275 	}
3276 
3277 	/* issue SUN_IMA request */
3278 	status = SUN_IMA_SetConfigSessions(targetOid,
3279 	    pConfigSessions);
3280 	if (!IMA_SUCCESS(status)) {
3281 		printLibError(status);
3282 		free(pConfigSessions);
3283 		return (1);
3284 	}
3285 
3286 	free(pConfigSessions);
3287 	return (0);
3288 }
3289 
3290 static int
3291 getAuthMethodValue(char *method, IMA_AUTHMETHOD *value)
3292 {
3293 	if (strcasecmp(method, "chap") == 0) {
3294 		*value = IMA_AUTHMETHOD_CHAP;
3295 		return (0);
3296 	}
3297 
3298 	if (strcasecmp(method, "none") == 0) {
3299 		*value =  IMA_AUTHMETHOD_NONE;
3300 		return (0);
3301 	}
3302 
3303 	return (1);
3304 }
3305 
3306 
3307 /*
3308  * Set the authentication method
3309  * Currently only supports CHAP and NONE
3310  */
3311 static int
3312 modifyNodeAuthMethod(IMA_OID oid, char *optarg, int *funcRet)
3313 {
3314 	IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS];
3315 	IMA_UINT methodCount = 0;
3316 	IMA_STATUS status;
3317 	IMA_AUTHMETHOD value;
3318 	char *method;
3319 	char *commaPos;
3320 
3321 	assert(funcRet != NULL);
3322 
3323 	/*
3324 	 * optarg will be a , delimited set of auth methods, in order
3325 	 * of preference
3326 	 * if any values here are incorrect, return without setting
3327 	 * anything.
3328 	 */
3329 	method = optarg;
3330 
3331 	commaPos = strchr(optarg, ',');
3332 
3333 	while (commaPos && methodCount < MAX_AUTH_METHODS) {
3334 		*commaPos = NULL;
3335 		if (getAuthMethodValue(method, &value) != 0) {
3336 			(void) fprintf(stderr, "%s: a: %s\n",
3337 			    cmdName, gettext("invalid option argument"));
3338 			return (1);
3339 		}
3340 		methodList[methodCount++] = value;
3341 		commaPos++;
3342 		method = commaPos;
3343 		commaPos = strchr(method, ',');
3344 	}
3345 	/* Should not find more method specified - if found, error */
3346 	if (commaPos) {
3347 		(void) fprintf(stderr, "%s: -a: %s\n",
3348 		    cmdName, gettext("invalid option argument"));
3349 		return (1);
3350 	}
3351 	if (getAuthMethodValue(method, &value) != 0) {
3352 		(void) fprintf(stderr, "%s: -a: %s\n",
3353 		    cmdName, gettext("invalid option argument"));
3354 		return (1);
3355 	}
3356 	methodList[methodCount++] = value;
3357 
3358 	status = IMA_SetInitiatorAuthMethods(oid, methodCount, &methodList[0]);
3359 	if (!IMA_SUCCESS(status)) {
3360 		printLibError(status);
3361 		*funcRet = 1;
3362 	}
3363 	return (0);
3364 }
3365 
3366 static int
3367 modifyTargetAuthMethod(IMA_OID oid, char *optarg, int *funcRet)
3368 {
3369 	IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS];
3370 	IMA_UINT methodCount = 0;
3371 	IMA_STATUS status;
3372 	IMA_AUTHMETHOD value;
3373 	char *method;
3374 	char *commaPos;
3375 
3376 	assert(funcRet != NULL);
3377 
3378 	/*
3379 	 * optarg will be a , delimited set of auth methods, in order
3380 	 * of preference
3381 	 * if any values here are incorrect, return without setting
3382 	 * anything.
3383 	 */
3384 	method = optarg;
3385 
3386 	commaPos = strchr(optarg, ',');
3387 
3388 	while (commaPos && methodCount < MAX_AUTH_METHODS) {
3389 		*commaPos = NULL;
3390 		if (getAuthMethodValue(method, &value) != 0) {
3391 			(void) fprintf(stderr, "%s: a: %s\n",
3392 			    cmdName, gettext("invalid option argument"));
3393 			return (1);
3394 		}
3395 		methodList[methodCount++] = value;
3396 		commaPos++;
3397 		method = commaPos;
3398 		commaPos = strchr(method, ',');
3399 	}
3400 	/* Should not find more method specified - if found, error */
3401 	if (commaPos) {
3402 		(void) fprintf(stderr, "%s: -a: %s\n",
3403 		    cmdName, gettext("invalid option argument"));
3404 		return (1);
3405 	}
3406 	if (getAuthMethodValue(method, &value) != 0) {
3407 		(void) fprintf(stderr, "%s: -a: %s\n",
3408 		    cmdName, gettext("invalid option argument"));
3409 		return (1);
3410 	}
3411 	methodList[methodCount++] = value;
3412 
3413 	status = SUN_IMA_SetTargetAuthMethods(oid, &methodCount,
3414 	    &methodList[0]);
3415 	if (!IMA_SUCCESS(status)) {
3416 		printLibError(status);
3417 		*funcRet = 1;
3418 	}
3419 	return (0);
3420 }
3421 
3422 /*
3423  * Modify the RADIUS configuration of the initiator node.
3424  *
3425  * Return 0 on success.
3426  */
3427 static int
3428 modifyNodeRadiusConfig(IMA_OID oid, char *optarg, int *funcRet)
3429 {
3430 	SUN_IMA_RADIUS_CONFIG config;
3431 	IMA_STATUS status;
3432 	boolean_t isIpv6 = B_FALSE;
3433 	uint16_t port;
3434 
3435 	assert(funcRet != NULL);
3436 
3437 	(void) memset(&config, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3438 	if (parseAddress(optarg, DEFAULT_RADIUS_PORT,
3439 	    &config.hostnameIpAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN,
3440 	    &port, &isIpv6) !=
3441 	    PARSE_ADDR_OK) {
3442 		return (1);
3443 	}
3444 	config.port = (IMA_UINT16)port;
3445 	config.isIpv6 = (isIpv6 == B_TRUE) ? IMA_TRUE : IMA_FALSE;
3446 	/* Not setting shared secret here. */
3447 	config.sharedSecretValid = IMA_FALSE;
3448 
3449 	status = SUN_IMA_SetInitiatorRadiusConfig(oid, &config);
3450 	if (!IMA_SUCCESS(status)) {
3451 		printLibError(status);
3452 		*funcRet = 1;
3453 	}
3454 
3455 	return (0);
3456 }
3457 
3458 /*
3459  * Modify the RADIUS access flag of the initiator node.
3460  *
3461  * Return 0 on success.
3462  */
3463 static int
3464 modifyNodeRadiusAccess(IMA_OID oid, char *optarg, int *funcRet)
3465 {
3466 	IMA_BOOL radiusAccess;
3467 	IMA_OID initiatorOid;
3468 	IMA_STATUS status;
3469 	SUN_IMA_RADIUS_CONFIG radiusConfig;
3470 	int ret;
3471 
3472 	assert(funcRet != NULL);
3473 
3474 	/* Check if Radius Config is there */
3475 	ret = sunInitiatorFind(&initiatorOid);
3476 	if (ret != 0) {
3477 		(void) fprintf(stderr, "%s: %s\n",
3478 		    cmdName, gettext("no initiator found"));
3479 		return (1);
3480 	}
3481 	(void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3482 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
3483 	if (!IMA_SUCCESS(status)) {
3484 		(void) fprintf(stderr, "%s: %s\n",
3485 		    cmdName, gettext("RADIUS server not configured yet"));
3486 		*funcRet = 1;
3487 		return (ret);
3488 	}
3489 
3490 	/* Check if Radius Shared is set */
3491 	if (radiusConfig.sharedSecretValid == IMA_FALSE) {
3492 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3493 		    gettext("RADIUS server secret not configured yet"));
3494 		return (1);
3495 	}
3496 
3497 	if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) {
3498 		radiusAccess = IMA_TRUE;
3499 	} else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) {
3500 		radiusAccess = IMA_FALSE;
3501 	} else {
3502 		(void) fprintf(stderr, "%s: %s %s\n",
3503 		    cmdName,
3504 		    gettext("invalid option argument"),
3505 		    optarg);
3506 		return (1);
3507 	}
3508 	status = SUN_IMA_SetInitiatorRadiusAccess(oid, radiusAccess);
3509 	if (!IMA_SUCCESS(status)) {
3510 		printLibError(status);
3511 		*funcRet = 1;
3512 	}
3513 
3514 	return (ret);
3515 }
3516 
3517 /*
3518  * Modify the RADIUS shared secret.
3519  *
3520  * Returns:
3521  *  zero on success.
3522  *  > 0 on failure.
3523  */
3524 static int
3525 modifyNodeRadiusSharedSecret(IMA_OID oid, int *funcRet)
3526 {
3527 	IMA_BYTE radiusSharedSecret[SUN_IMA_MAX_RADIUS_SECRET_LEN + 1];
3528 	IMA_OID initiatorOid;
3529 	IMA_STATUS status;
3530 	SUN_IMA_RADIUS_CONFIG radiusConfig;
3531 	int ret;
3532 	int secretLen = SUN_IMA_MAX_RADIUS_SECRET_LEN;
3533 
3534 	assert(funcRet != NULL);
3535 
3536 	ret = getSecret((char *)&radiusSharedSecret[0], &secretLen,
3537 	    0, SUN_IMA_MAX_RADIUS_SECRET_LEN);
3538 	if (ret != 0) {
3539 		return (1);
3540 	}
3541 
3542 	ret = sunInitiatorFind(&initiatorOid);
3543 	if (ret > 0) {
3544 		(void) fprintf(stderr, "%s: %s\n",
3545 		    cmdName, gettext("no initiator found"));
3546 	}
3547 	if (ret != 0) {
3548 		return (1);
3549 	}
3550 	/* First obtain existing RADIUS configuration (if any) */
3551 	(void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3552 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
3553 	if (!IMA_SUCCESS(status)) {
3554 		(void) fprintf(stderr, "%s: %s\n",
3555 		    cmdName, gettext("RADIUS server not configured yet"));
3556 		return (1);
3557 	}
3558 
3559 	/* Modify the shared secret only */
3560 	radiusConfig.sharedSecretLength = secretLen;
3561 	(void) memcpy(&radiusConfig.sharedSecret,
3562 	    &radiusSharedSecret[0], secretLen);
3563 	radiusConfig.sharedSecretValid = IMA_TRUE;
3564 	status = SUN_IMA_SetInitiatorRadiusConfig(oid, &radiusConfig);
3565 	if (!IMA_SUCCESS(status)) {
3566 		printLibError(status);
3567 		*funcRet = 1;
3568 	}
3569 
3570 	return (0);
3571 }
3572 
3573 /*
3574  * Set initiator node attributes.
3575  */
3576 static int
3577 modifyNode(cmdOptions_t *options, int *funcRet)
3578 {
3579 	IMA_NODE_NAME	nodeName;
3580 	IMA_NODE_ALIAS	nodeAlias;
3581 	IMA_OID		oid;
3582 	IMA_STATUS	status;
3583 	cmdOptions_t	*optionList = options;
3584 	int		ret;
3585 	iSCSINameCheckStatusType nameCheckStatus;
3586 	IMA_OID sharedNodeOid;
3587 	int i;
3588 	int lowerCase;
3589 
3590 	assert(funcRet != NULL);
3591 
3592 	/* Find Sun initiator */
3593 	ret = sunInitiatorFind(&oid);
3594 	if (ret > 0) {
3595 		(void) fprintf(stderr, "%s: %s\n",
3596 		    cmdName, gettext("no initiator found"));
3597 	}
3598 
3599 	if (ret != 0) {
3600 		return (ret);
3601 	}
3602 
3603 	for (; optionList->optval; optionList++) {
3604 		switch (optionList->optval) {
3605 			case 'N':
3606 				if (strlen(optionList->optarg) >=
3607 				    MAX_ISCSI_NAME_LEN) {
3608 					(void) fprintf(stderr, "%s: %s %d\n",
3609 					    cmdName,
3610 					    gettext("name too long, \
3611 					    maximum length is:"),
3612 					    MAX_ISCSI_NAME_LEN);
3613 				}
3614 
3615 				/* Take the first operand as node name. */
3616 				(void) memset(&nodeName, 0,
3617 				    sizeof (IMA_NODE_NAME));
3618 				if (mbstowcs(nodeName, optionList->optarg,
3619 				    IMA_NODE_NAME_LEN) == (size_t)-1) {
3620 					(void) fprintf(stderr, "%s: %s\n",
3621 					    cmdName,
3622 					    gettext("conversion error"));
3623 					return (1);
3624 				}
3625 
3626 				for (i = 0; nodeName[i] != 0; i++) {
3627 					lowerCase = tolower(nodeName[i]);
3628 					nodeName[i] = lowerCase;
3629 				}
3630 				/* Perform string profile checks */
3631 				nameCheckStatus =
3632 				    iSCSINameStringProfileCheck(nodeName);
3633 				iSCSINameCheckStatusDisplay(nameCheckStatus);
3634 				if (nameCheckStatus != iSCSINameCheckOK) {
3635 					*funcRet = 1; /* DIY message fix */
3636 					return (1);
3637 				}
3638 
3639 				/*
3640 				 * IMA_GetSharedNodeOid(&sharedNodeOid);
3641 				 * if (!IMA_SUCCESS(status)) {
3642 				 *   printLibError(status);
3643 				 *   return (INF_ERROR);
3644 				 * }
3645 				 */
3646 				oid.objectType = IMA_OBJECT_TYPE_NODE;
3647 				status = IMA_SetNodeName(oid, nodeName);
3648 				if (!IMA_SUCCESS(status)) {
3649 					printLibError(status);
3650 					*funcRet = 1;
3651 					return (ret);
3652 				}
3653 				break;
3654 
3655 			case 'A':
3656 				/* Take the first operand as node alias. */
3657 				if (strlen(optionList->optarg) >=
3658 				    MAX_ISCSI_NAME_LEN) {
3659 					(void) fprintf(stderr, "%s: %s %d\n",
3660 					    cmdName,
3661 					    gettext("alias too long, maximum  \
3662 					    length is:"),
3663 					    MAX_ISCSI_NAME_LEN);
3664 				}
3665 
3666 				(void) memset(&nodeAlias, 0,
3667 				    sizeof (IMA_NODE_ALIAS));
3668 				if (mbstowcs(nodeAlias, optionList->optarg,
3669 				    IMA_NODE_ALIAS_LEN) == (size_t)-1) {
3670 					(void) fprintf(stderr, "%s: %s\n",
3671 					    cmdName,
3672 					    gettext("conversion error"));
3673 					return (1);
3674 				}
3675 
3676 				status = IMA_GetSharedNodeOid(&sharedNodeOid);
3677 				if (!IMA_SUCCESS(status)) {
3678 					printLibError(status);
3679 					*funcRet = 1;
3680 					return (ret);
3681 				}
3682 
3683 				status = IMA_SetNodeAlias(sharedNodeOid,
3684 				    nodeAlias);
3685 				if (!IMA_SUCCESS(status)) {
3686 					printLibError(status);
3687 					*funcRet = 1;
3688 					return (ret);
3689 				}
3690 				break;
3691 
3692 			case 'a':
3693 				if (modifyNodeAuthMethod(oid, options->optarg,
3694 				    funcRet) != 0) {
3695 					return (1);
3696 				}
3697 				break;
3698 
3699 			case 'R':
3700 				if (modifyNodeRadiusAccess(oid, options->optarg,
3701 				    funcRet) != 0) {
3702 					return (1);
3703 				}
3704 				break;
3705 
3706 			case 'r':
3707 				if (modifyNodeRadiusConfig(oid, options->optarg,
3708 				    funcRet) != 0) {
3709 					return (1);
3710 				}
3711 				break;
3712 
3713 			case 'P':
3714 				if (modifyNodeRadiusSharedSecret(oid, funcRet)
3715 				    != 0) {
3716 					return (1);
3717 				}
3718 				break;
3719 
3720 			case 'C':
3721 				if (modifyNodeAuthParam(oid, AUTH_PASSWORD,
3722 				    NULL, funcRet) != 0) {
3723 					return (1);
3724 				}
3725 				break;
3726 
3727 			case 'c':
3728 				if (modifyConfiguredSessions(oid,
3729 				    optionList->optarg) != 0) {
3730 					return (1);
3731 				}
3732 				break;
3733 
3734 			case 'H':
3735 				if (modifyNodeAuthParam(oid, AUTH_NAME,
3736 				    optionList->optarg, funcRet) != 0) {
3737 					return (1);
3738 				}
3739 				break;
3740 
3741 			case 'd':
3742 				if (setLoginParameter(oid, DATA_DIGEST,
3743 				    optionList->optarg) != 0) {
3744 					return (1);
3745 				}
3746 				break;
3747 
3748 			case 'h':
3749 				if (setLoginParameter(oid, HEADER_DIGEST,
3750 				    optionList->optarg) != 0) {
3751 					return (1);
3752 				}
3753 				break;
3754 
3755 			default:
3756 				(void) fprintf(stderr, "%s: %c: %s\n",
3757 				    cmdName, optionList->optval,
3758 				    gettext("unknown option"));
3759 				break;
3760 		}
3761 	}
3762 
3763 	return (ret);
3764 }
3765 
3766 /*
3767  * Modify target parameters
3768  */
3769 static int
3770 modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet)
3771 {
3772 	IMA_OID oid;
3773 	IMA_OID targetOid;
3774 	IMA_STATUS status;
3775 	IMA_OID_LIST *targetList;
3776 	SUN_IMA_TARGET_PROPERTIES targetProps;
3777 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
3778 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
3779 	int ret;
3780 	boolean_t found;
3781 	boolean_t targetAddressSpecified = B_TRUE;
3782 	boolean_t tpgtSpecified = B_FALSE;
3783 	boolean_t isIpv6 = B_FALSE;
3784 	int i;
3785 	iSCSINameCheckStatusType nameCheckStatus;
3786 	IMA_UINT16 port = 0;
3787 	IMA_UINT16 tpgt = 0;
3788 
3789 	cmdOptions_t *optionList = options;
3790 
3791 	assert(funcRet != NULL);
3792 
3793 	/* Find Sun initiator */
3794 	ret = sunInitiatorFind(&oid);
3795 	if (ret > 0) {
3796 		(void) fprintf(stderr, "%s: %s\n",
3797 		    cmdName, gettext("no initiator found"));
3798 	}
3799 
3800 	if (ret != 0) {
3801 		return (ret);
3802 	}
3803 
3804 	if (parseTarget(targetName,
3805 	    &wcInputObject[0],
3806 	    MAX_ISCSI_NAME_LEN + 1,
3807 	    &targetAddressSpecified,
3808 	    &targetAddress[0],
3809 	    SUN_IMA_IP_ADDRESS_PORT_LEN,
3810 	    &port,
3811 	    &tpgtSpecified,
3812 	    &tpgt,
3813 	    &isIpv6) != PARSE_TARGET_OK) {
3814 		return (1);
3815 	}
3816 
3817 	/* Perform string profile checks */
3818 	nameCheckStatus = iSCSINameStringProfileCheck(wcInputObject);
3819 	iSCSINameCheckStatusDisplay(nameCheckStatus);
3820 	if (nameCheckStatus != iSCSINameCheckOK) {
3821 		return (1);
3822 	}
3823 
3824 	status = IMA_GetTargetOidList(oid, &targetList);
3825 	if (!IMA_SUCCESS(status)) {
3826 		printLibError(status);
3827 		*funcRet = 1;
3828 		return (0);
3829 	}
3830 
3831 	/* find target oid */
3832 	for (found = B_FALSE, i = 0; i < targetList->oidCount; i++) {
3833 		status = SUN_IMA_GetTargetProperties(targetList->oids[i],
3834 		    &targetProps);
3835 		if (!IMA_SUCCESS(status)) {
3836 			printLibError(status);
3837 			(void) IMA_FreeMemory(targetList);
3838 			*funcRet = 1;
3839 			return (ret);
3840 		}
3841 
3842 		/*
3843 		 * Compare the target name with the input name
3844 		 */
3845 		if ((targetNamesEqual(wcInputObject, targetProps.imaProps.name)
3846 		    == B_TRUE)) {
3847 			/*
3848 			 * For now, regardless of whether a target address
3849 			 * is specified, we return B_TRUE because
3850 			 * IMA_TARGET_PROPERTIES does not have a field for
3851 			 * specifying address.
3852 			 */
3853 			found = B_TRUE;
3854 			targetOid = targetList->oids[i];
3855 			if (modifyIndividualTargetParam(optionList, targetOid,
3856 			    funcRet) != 0) {
3857 				return (ret);
3858 			}
3859 
3860 			/*
3861 			 * Even after finding a matched target, keep going
3862 			 * since there could be multiple target objects
3863 			 * associated with one target name in the system
3864 			 * because of different TPGTs.
3865 			 */
3866 		}
3867 	}
3868 
3869 	/* If the target OID cannot be found create one */
3870 	if (!found) {
3871 		status = SUN_IMA_CreateTargetOid(wcInputObject, &targetOid);
3872 		if (!IMA_SUCCESS(status)) {
3873 			printLibError(status);
3874 			(void) IMA_FreeMemory(targetList);
3875 			*funcRet = 1;
3876 			return (ret);
3877 		}
3878 		if (modifyIndividualTargetParam(optionList, targetOid,
3879 		    funcRet) != 0) {
3880 				return (ret);
3881 		}
3882 	}
3883 
3884 	(void) IMA_FreeMemory(targetList);
3885 	return (ret);
3886 }
3887 
3888 /*
3889  * Add one or more addresses
3890  */
3891 static int
3892 addAddress(int addrType, int operandLen, char *operand[], int *funcRet)
3893 {
3894 	IMA_STATUS status;
3895 	IMA_OID oid, addressOid;
3896 	SUN_IMA_TARGET_ADDRESS address;
3897 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
3898 	int ret;
3899 	int i;
3900 
3901 	assert(funcRet != NULL);
3902 
3903 	/* Find Sun initiator */
3904 	ret = sunInitiatorFind(&oid);
3905 	if (ret > 0) {
3906 		(void) fprintf(stderr, "%s: %s\n",
3907 		    cmdName, gettext("no initiator found"));
3908 	}
3909 
3910 	if (ret != 0) {
3911 		return (ret);
3912 	}
3913 
3914 	/*
3915 	 * Format of discovery address operand:
3916 	 *
3917 	 * <IP address|hostname>:<port>
3918 	 */
3919 	for (i = 0; i < operandLen; i++) {
3920 		/* initialize */
3921 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
3922 		(void) memset(&address, 0, sizeof (address));
3923 
3924 		if (mbstowcs(wcInputObject, operand[i],
3925 		    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
3926 			(void) fprintf(stderr, "%s: %s\n",
3927 			    cmdName, gettext("conversion error"));
3928 			ret = 1;
3929 			continue;
3930 		}
3931 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
3932 		    != 0) {
3933 			ret = 1;
3934 			continue;
3935 		}
3936 		if (addrType == DISCOVERY_ADDRESS) {
3937 			status = IMA_AddDiscoveryAddress(oid,
3938 			    address.imaStruct, &addressOid);
3939 			if (!IMA_SUCCESS(status)) {
3940 				printLibError(status);
3941 				*funcRet = 1;
3942 				return (ret);
3943 			}
3944 		} else if (addrType == ISNS_SERVER_ADDRESS) {
3945 			status = SUN_IMA_AddISNSServerAddress(address);
3946 			if (!IMA_SUCCESS(status)) {
3947 				printLibError(status);
3948 				*funcRet = 1;
3949 				return (ret);
3950 			}
3951 		}
3952 	}
3953 	return (ret);
3954 }
3955 
3956 /*
3957  * Add one or more static configuration targets
3958  */
3959 static int
3960 addStaticConfig(int operandLen, char *operand[], int *funcRet)
3961 {
3962 	int i;
3963 	boolean_t targetAddressSpecified = B_FALSE;
3964 	boolean_t tpgtSpecified = B_FALSE;
3965 	boolean_t isIpv6 = B_FALSE;
3966 	int ret;
3967 	int addrType;
3968 	IMA_STATUS status;
3969 	IMA_OID oid;
3970 	SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig;
3971 	IMA_UINT16 port = 0;
3972 	IMA_UINT16 tpgt = 0;
3973 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
3974 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
3975 	iSCSINameCheckStatusType nameCheckStatus;
3976 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
3977 
3978 	assert(funcRet != NULL);
3979 
3980 	/* Find Sun initiator */
3981 	ret = sunInitiatorFind(&oid);
3982 	if (ret > 0) {
3983 		(void) fprintf(stderr, "%s: %s\n",
3984 		    cmdName, gettext("no initiator found"));
3985 	}
3986 
3987 	if (ret != 0) {
3988 		return (ret);
3989 	}
3990 
3991 	/*
3992 	 * Format of static config operand:
3993 	 *  <target-name>,<IP address|hostname>[:port][,tpgt]
3994 	 */
3995 	for (i = 0; i < operandLen; i++) {
3996 		if (parseTarget(operand[i],
3997 		    &staticTargetName[0],
3998 		    MAX_ISCSI_NAME_LEN + 1,
3999 		    &targetAddressSpecified,
4000 		    &staticTargetAddress[0],
4001 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4002 		    &port,
4003 		    &tpgtSpecified,
4004 		    &tpgt,
4005 		    &isIpv6) != PARSE_TARGET_OK) {
4006 			ret = 1;
4007 			continue;
4008 		}
4009 
4010 		if (targetAddressSpecified != B_TRUE) {
4011 			(void) fprintf(stderr, "%s: %s\n",
4012 			    cmdName, gettext("missing target address"));
4013 			*funcRet = 1; /* DIY message fix */
4014 			return (1);
4015 		}
4016 		/* Perform string profile checks */
4017 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4018 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4019 		if (nameCheckStatus != iSCSINameCheckOK) {
4020 			*funcRet = 1; /* DIY message fix */
4021 			return (1);
4022 		}
4023 		(void) wcsncpy(staticConfig.targetName, staticTargetName,
4024 		    MAX_ISCSI_NAME_LEN + 1);
4025 
4026 		(void) wcstombs(sAddr, staticTargetAddress, sizeof (sAddr));
4027 
4028 		if (isIpv6 == B_TRUE) {
4029 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4030 			    id.ipAddress.ipv4Address = B_FALSE;
4031 			addrType = AF_INET6;
4032 		} else {
4033 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4034 			    id.ipAddress.ipv4Address = B_TRUE;
4035 			addrType = AF_INET;
4036 		}
4037 
4038 		if (inet_pton(addrType, sAddr, staticConfig.targetAddress.
4039 		    imaStruct.hostnameIpAddress.id.ipAddress.ipAddress) != 1) {
4040 			(void) fprintf(stderr, "%s: %s\n",
4041 			    cmdName, gettext("static config conversion error"));
4042 			ret = 1;
4043 			continue;
4044 		}
4045 
4046 		staticConfig.targetAddress.imaStruct.portNumber = port;
4047 		if (tpgtSpecified == B_TRUE) {
4048 			staticConfig.targetAddress.defaultTpgt = B_FALSE;
4049 			staticConfig.targetAddress.tpgt = tpgt;
4050 		} else {
4051 			staticConfig.targetAddress.defaultTpgt = B_TRUE;
4052 			staticConfig.targetAddress.tpgt = 0;
4053 		}
4054 
4055 		status = SUN_IMA_AddStaticTarget(oid, staticConfig, &oid);
4056 		if (!IMA_SUCCESS(status)) {
4057 			printLibError(status);
4058 			*funcRet = 1;
4059 			return (1);
4060 		}
4061 	}
4062 	return (ret);
4063 }
4064 
4065 /*
4066  * Remove one or more addresses
4067  */
4068 static int
4069 removeAddress(int addrType, int operandLen, char *operand[], int *funcRet)
4070 {
4071 	IMA_STATUS status;
4072 	IMA_OID initiatorOid;
4073 	SUN_IMA_TARGET_ADDRESS address;
4074 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
4075 	int ret;
4076 	int i;
4077 
4078 	assert(funcRet != NULL);
4079 
4080 	/* Find Sun initiator */
4081 	ret = sunInitiatorFind(&initiatorOid);
4082 	if (ret > 0) {
4083 		(void) fprintf(stderr, "%s: %s\n",
4084 		    cmdName, gettext("no initiator found"));
4085 	}
4086 
4087 	if (ret != 0) {
4088 		return (ret);
4089 	}
4090 
4091 	for (i = 0; i < operandLen; i++) {
4092 		/* initialize */
4093 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4094 		(void) memset(&address, 0, sizeof (address));
4095 
4096 		if (mbstowcs(wcInputObject, operand[i],
4097 		    MAX_ADDRESS_LEN + 1) == (size_t)-1) {
4098 			(void) fprintf(stderr, "%s: %s\n",
4099 			    cmdName, gettext("conversion error"));
4100 			ret = 1;
4101 			continue;
4102 		}
4103 
4104 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
4105 		    != 0) {
4106 			ret = 1;
4107 			continue;
4108 		}
4109 
4110 		if (addrType == DISCOVERY_ADDRESS) {
4111 			status = SUN_IMA_RemoveDiscoveryAddress(address);
4112 			if (!IMA_SUCCESS(status)) {
4113 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4114 					(void) fprintf(stderr, "%s: %s\n",
4115 					    operand[i], gettext("not found"));
4116 				} else {
4117 					printLibError(status);
4118 				}
4119 				*funcRet = 1;
4120 			}
4121 		} else {
4122 			status = SUN_IMA_RemoveISNSServerAddress(address);
4123 			if (!IMA_SUCCESS(status)) {
4124 				printLibError(status);
4125 				*funcRet = 1;
4126 			}
4127 		}
4128 	}
4129 	return (ret);
4130 }
4131 
4132 /*
4133  * Remove one or more static configuration targets
4134  */
4135 static int
4136 removeStaticConfig(int operandLen, char *operand[], int *funcRet)
4137 {
4138 	IMA_STATUS status;
4139 	IMA_OID initiatorOid;
4140 	IMA_OID_LIST *staticTargetList;
4141 	SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps;
4142 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
4143 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4144 	int ret;
4145 	boolean_t atLeastFoundOne;
4146 	boolean_t matched;
4147 	boolean_t targetAddressSpecified = B_TRUE;
4148 	boolean_t tpgtSpecified = B_FALSE;
4149 	boolean_t isIpv6 = B_FALSE;
4150 	int i, j;
4151 	IMA_UINT16 port = 0;
4152 	IMA_UINT16 tpgt = 0;
4153 	iSCSINameCheckStatusType nameCheckStatus;
4154 	char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
4155 	wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4156 
4157 	assert(funcRet != NULL);
4158 
4159 	/* Find Sun initiator */
4160 	ret = sunInitiatorFind(&initiatorOid);
4161 	if (ret > 0) {
4162 		(void) fprintf(stderr, "%s: %s\n",
4163 		    cmdName, gettext("no initiator found"));
4164 	}
4165 
4166 	if (ret != 0) {
4167 		return (ret);
4168 	}
4169 
4170 	status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid,
4171 	    &staticTargetList);
4172 	if (!IMA_SUCCESS(status)) {
4173 		printLibError(status);
4174 		*funcRet = 1;
4175 		return (ret);
4176 	}
4177 
4178 	for (i = 0; i < operandLen; i++) {
4179 		if (parseTarget(operand[i],
4180 		    &staticTargetName[0],
4181 		    MAX_ISCSI_NAME_LEN + 1,
4182 		    &targetAddressSpecified,
4183 		    &staticTargetAddress[0],
4184 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4185 		    &port,
4186 		    &tpgtSpecified,
4187 		    &tpgt,
4188 		    &isIpv6) != PARSE_TARGET_OK) {
4189 			ret = 1;
4190 			continue;
4191 		}
4192 
4193 		/* Perform string profile checks */
4194 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4195 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4196 		if (nameCheckStatus != iSCSINameCheckOK) {
4197 			return (1);
4198 		}
4199 
4200 		for (atLeastFoundOne = B_FALSE, j = 0;
4201 		    j < staticTargetList->oidCount;
4202 		    j++) {
4203 			IMA_UINT16 stpgt;
4204 
4205 			matched = B_FALSE;
4206 			status = SUN_IMA_GetStaticTargetProperties(
4207 			    staticTargetList->oids[j], &staticTargetProps);
4208 			if (!IMA_SUCCESS(status)) {
4209 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4210 					/*
4211 					 * When removing multiple static-config
4212 					 * entries we need to expect get
4213 					 * failures. These failures occur when
4214 					 * we are trying to get entry
4215 					 * information we have just removed.
4216 					 * Ignore the failure and continue.
4217 					 */
4218 					ret = 1;
4219 					continue;
4220 				} else {
4221 					printLibError(status);
4222 					(void) IMA_FreeMemory(staticTargetList);
4223 					*funcRet = 1;
4224 					return (ret);
4225 				}
4226 			}
4227 
4228 			stpgt =
4229 			    staticTargetProps.staticTarget.targetAddress.tpgt;
4230 
4231 			/*
4232 			 * Compare the static target name with the input if
4233 			 * one was input
4234 			 */
4235 			if ((targetNamesEqual(
4236 			    staticTargetProps.staticTarget.targetName,
4237 			    staticTargetName) == B_TRUE)) {
4238 				if (targetAddressSpecified == B_FALSE) {
4239 					matched = B_TRUE;
4240 				} else {
4241 
4242 					if (staticTargetProps.staticTarget.
4243 					    targetAddress.imaStruct.
4244 					    hostnameIpAddress.
4245 					    id.ipAddress.ipv4Address ==
4246 					    IMA_TRUE) {
4247 						(void) inet_ntop(AF_INET,
4248 						    staticTargetProps.
4249 						    staticTarget.targetAddress.
4250 						    imaStruct.hostnameIpAddress.
4251 						    id.ipAddress.ipAddress,
4252 						    tmpStr,
4253 						    sizeof (tmpStr));
4254 					} else {
4255 						(void) inet_ntop(AF_INET6,
4256 						    staticTargetProps.
4257 						    staticTarget.targetAddress.
4258 						    imaStruct.hostnameIpAddress.
4259 						    id.ipAddress.ipAddress,
4260 						    tmpStr,
4261 						    sizeof (tmpStr));
4262 					}
4263 
4264 					if (mbstowcs(tmpTargetAddress, tmpStr,
4265 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4266 					    (size_t)-1) {
4267 						(void) fprintf(stderr,
4268 						    "%s: %s\n",
4269 						    cmdName, gettext(
4270 						    "conversion error"));
4271 						ret = 1;
4272 						continue;
4273 					}
4274 
4275 					if ((wcsncmp(tmpTargetAddress,
4276 					    staticTargetAddress,
4277 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4278 					    0) && (staticTargetProps.
4279 					    staticTarget.targetAddress.
4280 					    imaStruct.portNumber == port)) {
4281 						if (tpgtSpecified == B_FALSE) {
4282 							matched = B_TRUE;
4283 						} else {
4284 							if (tpgt == stpgt) {
4285 								matched =
4286 								    B_TRUE;
4287 							}
4288 						}
4289 					}
4290 				}
4291 
4292 				if (matched) {
4293 					status =
4294 					    IMA_RemoveStaticDiscoveryTarget(
4295 					    staticTargetList->oids[j]);
4296 					if (!IMA_SUCCESS(status)) {
4297 						printLibError(status);
4298 						*funcRet = 1;
4299 						return (ret);
4300 					}
4301 					atLeastFoundOne = B_TRUE;
4302 				}
4303 			}
4304 		}
4305 		if (!atLeastFoundOne) {
4306 			(void) fprintf(stderr, gettext("%ws,%ws: %s\n"),
4307 			    staticTargetName, staticTargetAddress,
4308 			    gettext("not found"));
4309 		}
4310 	}
4311 	return (ret);
4312 }
4313 
4314 /*
4315  * Remove one or more target params.
4316  */
4317 static int
4318 removeTargetParam(int operandLen, char *operand[], int *funcRet)
4319 {
4320 	char *commaPos;
4321 	IMA_STATUS status;
4322 	IMA_OID initiatorOid;
4323 	IMA_OID_LIST *targetList;
4324 	SUN_IMA_TARGET_PROPERTIES targetProps;
4325 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
4326 	int ret;
4327 	boolean_t found;
4328 	int i, j;
4329 
4330 	assert(funcRet != NULL);
4331 
4332 	/* Find Sun initiator */
4333 	ret = sunInitiatorFind(&initiatorOid);
4334 	if (ret > 0) {
4335 		(void) fprintf(stderr, "%s: %s\n",
4336 		    cmdName, gettext("no initiator found"));
4337 	}
4338 
4339 	if (ret != 0) {
4340 		return (ret);
4341 	}
4342 
4343 	status = IMA_GetTargetOidList(initiatorOid, &targetList);
4344 	if (!IMA_SUCCESS(status)) {
4345 		printLibError(status);
4346 		*funcRet = 1;
4347 		return (ret);
4348 	}
4349 
4350 	for (i = 0; i < operandLen; i++) {
4351 		/* initialize */
4352 		commaPos = strchr(operand[i], ',');
4353 		if (commaPos) {
4354 			/* Ignore IP address. */
4355 			*commaPos = NULL;
4356 		}
4357 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4358 		if (mbstowcs(wcInputObject, operand[i],
4359 		    MAX_ISCSI_NAME_LEN + 1) == (size_t)-1) {
4360 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4361 			    gettext("conversion error"));
4362 			ret = 1;
4363 			continue;
4364 		}
4365 
4366 		for (found = B_FALSE, j = 0; j < targetList->oidCount;
4367 		    j++) {
4368 			status = SUN_IMA_GetTargetProperties(
4369 			    targetList->oids[j], &targetProps);
4370 			if (!IMA_SUCCESS(status)) {
4371 				printLibError(status);
4372 				(void) IMA_FreeMemory(targetList);
4373 				*funcRet = 1;
4374 				return (ret);
4375 			}
4376 
4377 			/*
4378 			 * Compare the target name with the input if
4379 			 * one was input
4380 			 */
4381 			if (targetNamesEqual(targetProps.imaProps.name,
4382 			    wcInputObject) == B_TRUE) {
4383 				found = B_TRUE;
4384 				status = SUN_IMA_RemoveTargetParam(
4385 				    targetList->oids[j]);
4386 				if (!IMA_SUCCESS(status)) {
4387 					printLibError(status);
4388 					(void) IMA_FreeMemory(targetList);
4389 					*funcRet = 1;
4390 					return (ret);
4391 				}
4392 			}
4393 		}
4394 		if (!found) {
4395 			/* Silently ignoring it? */
4396 			(void) fprintf(stderr, gettext("%ws: %s\n"),
4397 			    wcInputObject, gettext("not found"));
4398 		}
4399 	}
4400 
4401 	(void) IMA_FreeMemory(targetList);
4402 	return (ret);
4403 }
4404 
4405 /*ARGSUSED*/
4406 static int
4407 addFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4408     void *addArgs, int *funcRet)
4409 {
4410 	int ret;
4411 
4412 	assert(funcRet != NULL);
4413 
4414 	switch (object) {
4415 		case DISCOVERY_ADDRESS:
4416 		case ISNS_SERVER_ADDRESS:
4417 			ret = addAddress(object, operandLen, operand, funcRet);
4418 			break;
4419 		case STATIC_CONFIG:
4420 			ret = addStaticConfig(operandLen, operand, funcRet);
4421 			break;
4422 		default:
4423 			(void) fprintf(stderr, "%s: %s\n",
4424 			    cmdName, gettext("unknown object"));
4425 			ret = 1;
4426 			break;
4427 	}
4428 	return (ret);
4429 }
4430 
4431 /*ARGSUSED*/
4432 static int
4433 listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4434     void *addArgs, int *funcRet)
4435 {
4436 	int ret;
4437 
4438 	assert(funcRet != NULL);
4439 
4440 	switch (object) {
4441 	case DISCOVERY:
4442 		ret = listDiscovery(funcRet);
4443 		break;
4444 	case DISCOVERY_ADDRESS:
4445 		ret = listDiscoveryAddress(operandLen, operand, options,
4446 		    funcRet);
4447 		break;
4448 	case ISNS_SERVER_ADDRESS:
4449 		ret = listISNSServerAddress(operandLen, operand, options,
4450 		    funcRet);
4451 		break;
4452 	case NODE:
4453 		ret = listNode(funcRet);
4454 		break;
4455 	case STATIC_CONFIG:
4456 		ret = listStaticConfig(operandLen, operand, funcRet);
4457 		break;
4458 	case TARGET:
4459 		ret = listTarget(operandLen, operand, options, funcRet);
4460 		break;
4461 	case TARGET_PARAM:
4462 		ret = listTargetParam(operandLen, operand, options, funcRet);
4463 		break;
4464 	default:
4465 		(void) fprintf(stderr, "%s: %s\n",
4466 		    cmdName, gettext("unknown object"));
4467 		ret = 1;
4468 		break;
4469 	}
4470 	return (ret);
4471 }
4472 
4473 /*ARGSUSED*/
4474 static int
4475 modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4476     void *addArgs, int *funcRet)
4477 {
4478 	int ret, i;
4479 
4480 	assert(funcRet != NULL);
4481 
4482 	switch (object) {
4483 	case DISCOVERY:
4484 		ret = modifyDiscovery(options, funcRet);
4485 		break;
4486 	case NODE:
4487 		ret = modifyNode(options, funcRet);
4488 		break;
4489 	case TARGET_PARAM:
4490 		i = 0;
4491 		while (operand[i]) {
4492 			ret = modifyTargetParam(options, operand[i], funcRet);
4493 
4494 			if (ret) {
4495 				(void) fprintf(stderr, "%s: %s: %s\n",
4496 				    cmdName, gettext("modify failed"),
4497 				    operand[i]);
4498 				return (ret);
4499 			}
4500 			i++;
4501 		}
4502 
4503 		break;
4504 	default:
4505 		(void) fprintf(stderr, "%s: %s\n",
4506 		    cmdName, gettext("unknown object"));
4507 		ret = 1;
4508 		break;
4509 	}
4510 	return (ret);
4511 }
4512 
4513 /*ARGSUSED*/
4514 static int
4515 removeFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4516     void *addArgs, int *funcRet)
4517 {
4518 	int ret;
4519 
4520 	switch (object) {
4521 		case DISCOVERY_ADDRESS:
4522 		case ISNS_SERVER_ADDRESS:
4523 			ret = removeAddress(object, operandLen, operand,
4524 			    funcRet);
4525 			break;
4526 		case STATIC_CONFIG:
4527 			ret = removeStaticConfig(operandLen, operand, funcRet);
4528 			break;
4529 		case TARGET_PARAM:
4530 			ret = removeTargetParam(operandLen, operand, funcRet);
4531 			break;
4532 		default:
4533 			(void) fprintf(stderr, "%s: %s\n",
4534 			    cmdName, gettext("unknown object"));
4535 			ret = 1;
4536 			break;
4537 	}
4538 	return (ret);
4539 }
4540 
4541 static void
4542 iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status)
4543 {
4544 	switch (status) {
4545 		case iSCSINameLenZero:
4546 			(void) fprintf(stderr, "%s: %s\n",
4547 			    cmdName, gettext("empty iSCSI name."));
4548 			break;
4549 		case iSCSINameLenExceededMax:
4550 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4551 			    gettext("iSCSI name exceeded maximum length."));
4552 			break;
4553 		case iSCSINameUnknownType:
4554 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4555 			    gettext("unknown iSCSI name type."));
4556 			break;
4557 		case iSCSINameInvalidCharacter:
4558 			(void) fprintf(stderr, "%s: %s\n",
4559 			    cmdName,
4560 			    gettext("iSCSI name invalid character used"));
4561 			break;
4562 		case iSCSINameIqnFormatError:
4563 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4564 			    gettext("iqn formatting error."));
4565 			break;
4566 		case iSCSINameIqnDateFormatError:
4567 			(void) fprintf(stderr, "%s: %s\n",
4568 			    cmdName, gettext("invalid iqn date." \
4569 			    "  format is: YYYY-MM"));
4570 			break;
4571 		case iSCSINameIqnSubdomainFormatError:
4572 			(void) fprintf(stderr, "%s: %s\n",
4573 			    cmdName, gettext("missing subdomain after \":\""));
4574 			break;
4575 		case iSCSINameIqnInvalidYearError:
4576 			(void) fprintf(stderr, "%s: %s\n",
4577 			    cmdName, gettext("invalid year"));
4578 			break;
4579 		case iSCSINameIqnInvalidMonthError:
4580 			(void) fprintf(stderr, "%s: %s\n",
4581 			    cmdName, gettext("invalid month"));
4582 			break;
4583 		case iSCSINameIqnFQDNError:
4584 			(void) fprintf(stderr, "%s: %s\n",
4585 			    cmdName, gettext("missing reversed fully qualified"\
4586 			    " domain name"));
4587 			break;
4588 		case iSCSINameEUIFormatError:
4589 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4590 			    gettext("eui formatting error."));
4591 			break;
4592 	}
4593 }
4594 
4595 /*
4596  * A convenient function to modify the target parameters of an individual
4597  * target.
4598  *
4599  * Return 0 if successful
4600  * Return 1 if failed
4601  */
4602 static int
4603 modifyIndividualTargetParam(cmdOptions_t *optionList, IMA_OID targetOid,
4604     int *funcRet)
4605 {
4606 	assert(funcRet != NULL);
4607 
4608 	for (; optionList->optval; optionList++) {
4609 		switch (optionList->optval) {
4610 			case 'a':
4611 				if (modifyTargetAuthMethod(targetOid,
4612 				    optionList->optarg, funcRet) != 0) {
4613 					return (1);
4614 				}
4615 				break;
4616 			case 'B':
4617 				if (modifyTargetBidirAuthFlag(targetOid,
4618 				    optionList->optarg, funcRet) != 0) {
4619 					return (1);
4620 				}
4621 				break;
4622 			case 'C':
4623 				if (modifyTargetAuthParam(targetOid,
4624 				    AUTH_PASSWORD, NULL, funcRet) != 0) {
4625 					return (1);
4626 				}
4627 				break;
4628 			case 'd':
4629 				if (setLoginParameter(targetOid, DATA_DIGEST,
4630 				    optionList->optarg) != 0) {
4631 					return (1);
4632 				}
4633 				break;
4634 			case 'h':
4635 				if (setLoginParameter(targetOid, HEADER_DIGEST,
4636 				    optionList->optarg) != 0) {
4637 					return (1);
4638 				}
4639 				break;
4640 			case 'p':
4641 				/* Login parameter */
4642 				if (setLoginParameters(targetOid,
4643 				    optionList->optarg) != 0) {
4644 					return (1);
4645 				}
4646 				break;
4647 			case 'c':
4648 				/* Modify configure sessions */
4649 				if (modifyConfiguredSessions(targetOid,
4650 				    optionList->optarg) != 0) {
4651 					return (1);
4652 				}
4653 				break;
4654 			case 'H':
4655 				if (modifyTargetAuthParam(targetOid, AUTH_NAME,
4656 				    optionList->optarg, funcRet) != 0) {
4657 					return (1);
4658 				}
4659 				break;
4660 		}
4661 	}
4662 
4663 	return (0);
4664 }
4665 
4666 /*
4667  * This helper function could go into a utility module for general use.
4668  */
4669 static int
4670 parseAddress(char *address_port_str,
4671     uint16_t defaultPort,
4672     char *address_str,
4673     size_t address_str_len,
4674     uint16_t *port,
4675     boolean_t *isIpv6)
4676 {
4677 	char port_str[64];
4678 	int tmp_port;
4679 	char *errchr;
4680 
4681 	if (address_port_str[0] == '[') {
4682 		/* IPv6 address */
4683 		char *close_bracket_pos;
4684 		close_bracket_pos = strchr(address_port_str, ']');
4685 		if (!close_bracket_pos) {
4686 			syslog(LOG_USER|LOG_DEBUG,
4687 			    "IP address format error: %s\n", address_str);
4688 			return (PARSE_ADDR_MISSING_CLOSING_BRACKET);
4689 		}
4690 
4691 		*close_bracket_pos = NULL;
4692 		(void) strlcpy(address_str, &address_port_str[1],
4693 		    address_str_len);
4694 
4695 		/* Extract the port number */
4696 		close_bracket_pos++;
4697 		if (*close_bracket_pos == ':') {
4698 			close_bracket_pos++;
4699 			if (*close_bracket_pos != NULL) {
4700 				(void) strlcpy(port_str, close_bracket_pos, 64);
4701 				tmp_port = strtol(port_str, &errchr, 10);
4702 				if (tmp_port == 0 && errchr != NULL) {
4703 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4704 					    cmdName, address_str,
4705 					    close_bracket_pos,
4706 					    gettext("port number invalid"));
4707 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4708 				}
4709 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4710 				    (tmp_port < 0)) {
4711 					/* Port number out of range */
4712 					syslog(LOG_USER|LOG_DEBUG,
4713 					    "Specified port out of range: %d",
4714 					    tmp_port);
4715 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4716 				} else {
4717 					*port = (uint16_t)tmp_port;
4718 				}
4719 			} else {
4720 				*port = defaultPort;
4721 			}
4722 		} else {
4723 			*port = defaultPort;
4724 		}
4725 
4726 		*isIpv6 = B_TRUE;
4727 	} else {
4728 		/* IPv4 address */
4729 		char *colon_pos;
4730 		colon_pos = strchr(address_port_str, ':');
4731 		if (!colon_pos) {
4732 			/* No port number specified. */
4733 			*port = defaultPort;
4734 			(void) strlcpy(address_str, address_port_str,
4735 			    address_str_len);
4736 		} else {
4737 			*colon_pos = (char)NULL;
4738 			(void) strlcpy(address_str, address_port_str,
4739 			    address_str_len);
4740 
4741 			/* Extract the port number */
4742 			colon_pos++;
4743 			if (*colon_pos != NULL) {
4744 
4745 				(void) strlcpy(port_str, colon_pos, 64);
4746 				tmp_port = strtol(port_str, &errchr, 10);
4747 				if (tmp_port == 0 && errchr != NULL) {
4748 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4749 					    cmdName, address_str, colon_pos,
4750 					    gettext("port number invalid"));
4751 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4752 				}
4753 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4754 				    (tmp_port < 0)) {
4755 					/* Port number out of range */
4756 					syslog(LOG_USER|LOG_DEBUG,
4757 					    "Specified port out of range: %d",
4758 					    tmp_port);
4759 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4760 				} else {
4761 					*port = (uint16_t)tmp_port;
4762 				}
4763 			} else {
4764 				*port = defaultPort;
4765 			}
4766 		}
4767 
4768 		*isIpv6 = B_FALSE;
4769 	}
4770 
4771 	return (PARSE_ADDR_OK);
4772 }
4773 
4774 /*
4775  * This helper function could go into a utility module for general use.
4776  */
4777 iSCSINameCheckStatusType
4778 iSCSINameStringProfileCheck(wchar_t *name)
4779 {
4780 	char mb_name[MAX_ISCSI_NAME_LEN + 1];
4781 	size_t name_len;
4782 	char *tmp;
4783 
4784 	(void) wcstombs(mb_name, name, MAX_ISCSI_NAME_LEN + 1);
4785 
4786 	if ((name_len = strlen(mb_name)) == 0) {
4787 		return (iSCSINameLenZero);
4788 	} else if (name_len > MAX_ISCSI_NAME_LEN) {
4789 		return (iSCSINameLenExceededMax);
4790 	}
4791 
4792 	/*
4793 	 * check for invalid characters
4794 	 * According to RFC 3722 iSCSI name must be either a letter,
4795 	 * a digit or one of the following '-' '.' ':'
4796 	 */
4797 	for (tmp = mb_name; *tmp != NULL; tmp++) {
4798 		if ((isalnum(*tmp) == 0) &&
4799 		    (*tmp != '-') &&
4800 		    (*tmp != '.') &&
4801 		    (*tmp != ':')) {
4802 			return (iSCSINameInvalidCharacter);
4803 		}
4804 	}
4805 
4806 	if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX,
4807 	    strlen(ISCSI_IQN_NAME_PREFIX)) == 0) {
4808 		/*
4809 		 * If name is of type iqn, check date string and naming
4810 		 * authority.
4811 		 */
4812 		char *strp = NULL;
4813 
4814 		/*
4815 		 * Don't allow the string to end with a colon.  If there is a
4816 		 * colon then there must be a subdomain provided.
4817 		 */
4818 		if (mb_name[strlen(mb_name) - 1] == ':') {
4819 			return (iSCSINameIqnSubdomainFormatError);
4820 		}
4821 
4822 		/* Date string */
4823 		strp = strtok(&mb_name[3], ".");
4824 		if (strp) {
4825 			char tmpYear[5], tmpMonth[3], *endPtr = NULL;
4826 			int year, month;
4827 
4828 			/* Date string should be in YYYY-MM format */
4829 			if (strlen(strp) != strlen("YYYY-MM") ||
4830 			    strp[4] != '-') {
4831 				return (iSCSINameIqnDateFormatError);
4832 			}
4833 
4834 			/*
4835 			 * Validate year.  Only validating that the
4836 			 * year can be converted to a number.  No
4837 			 * validation will be done on year's actual
4838 			 * value.
4839 			 */
4840 			(void) strncpy(tmpYear, strp, 4);
4841 			tmpYear[4] = '\0';
4842 
4843 			errno = 0;
4844 			year = strtol(tmpYear, &endPtr, 10);
4845 			if (errno != 0 || *endPtr != '\0' ||
4846 			    year < 0 || year > 9999) {
4847 				return (iSCSINameIqnInvalidYearError);
4848 			}
4849 
4850 			/*
4851 			 * Validate month is valid.
4852 			 */
4853 			(void) strncpy(tmpMonth, &strp[5], 2);
4854 			tmpMonth[2] = '\0';
4855 			errno = 0;
4856 			month = strtol(tmpMonth, &endPtr, 10);
4857 
4858 			if (errno != 0 || *endPtr != '\0' ||
4859 			    month < 1 || month > 12) {
4860 				return (iSCSINameIqnInvalidMonthError);
4861 			}
4862 
4863 			/*
4864 			 * A reversed FQDN needs to be provided.  We
4865 			 * will only check for a "." followed by more
4866 			 * than two or more characters.  The list of domains is
4867 			 * too large and changes too frequently to
4868 			 * add validation for.
4869 			 */
4870 			strp = strtok(NULL, ".");
4871 			if (!strp || strlen(strp) < 2) {
4872 				return (iSCSINameIqnFQDNError);
4873 			}
4874 
4875 			/* Name authority string */
4876 			strp = strtok(NULL, ":");
4877 			if (strp) {
4878 				return (iSCSINameCheckOK);
4879 			} else {
4880 				return (iSCSINameIqnFQDNError);
4881 			}
4882 		} else {
4883 			return (iSCSINameIqnFormatError);
4884 		}
4885 	} else if (strncmp(mb_name, ISCSI_EUI_NAME_PREFIX,
4886 	    strlen(ISCSI_EUI_NAME_PREFIX)) == 0) {
4887 		/* If name is of type EUI, change its length */
4888 
4889 		if (strlen(mb_name) != ISCSI_EUI_NAME_LEN) {
4890 			return (iSCSINameEUIFormatError);
4891 		}
4892 
4893 		for (tmp = mb_name + strlen(ISCSI_EUI_NAME_PREFIX) + 1;
4894 		    *tmp != '\0'; tmp++) {
4895 			if (isxdigit(*tmp)) {
4896 				continue;
4897 			}
4898 			return (iSCSINameEUIFormatError);
4899 		}
4900 
4901 		return (iSCSINameCheckOK);
4902 	} else {
4903 		return (iSCSINameUnknownType);
4904 	}
4905 }
4906 
4907 /*
4908  * This helper function could go into a utility module for general use.
4909  *
4910  * Returns:
4911  * B_TRUE is the numberStr is an unsigned natural number and within the
4912  * specified bound.
4913  * B_FALSE otherwise.
4914  */
4915 boolean_t
4916 isNaturalNumber(char *numberStr, uint32_t upperBound)
4917 {
4918 	int i;
4919 	int number_str_len;
4920 
4921 	if ((number_str_len = strlen(numberStr)) == 0) {
4922 		return (B_FALSE);
4923 	}
4924 
4925 	for (i = 0; i < number_str_len; i++) {
4926 		if (numberStr[i] < 060 || numberStr[i] > 071) {
4927 			return (B_FALSE);
4928 		}
4929 	}
4930 
4931 	if (atoi(numberStr) > upperBound) {
4932 		return (B_FALSE);
4933 	}
4934 
4935 	return (B_TRUE);
4936 }
4937 
4938 /*
4939  * This helper function could go into a utility module for general use.
4940  * It parses a target string in the format of:
4941  *
4942  * 	<target_name>,[<ip_address>[:port][,tpgt]]
4943  *
4944  * and creates wchar strings for target name and target address. It
4945  * also populates port and tpgt if found.
4946  *
4947  * Returns:
4948  * 	PARSE_TARGET_OK if parsing is successful.
4949  *	PARSE_TARGET_INVALID_TPGT if the specified tpgt is
4950  *	invalid.
4951  * 	PARSE_TARGET_INVALID_ADDR if the address specified is
4952  *	invalid.
4953  */
4954 int
4955 parseTarget(char *targetStr,
4956 		wchar_t *targetNameStr,
4957 		size_t targetNameStrLen,
4958 		boolean_t *targetAddressSpecified,
4959 		wchar_t *targetAddressStr,
4960 		size_t targetAddressStrLen,
4961 		uint16_t *port,
4962 		boolean_t *tpgtSpecified,
4963 		uint16_t *tpgt,
4964 		boolean_t *isIpv6)
4965 {
4966 	char *commaPos;
4967 	char *commaPos2;
4968 	char targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4969 	int i;
4970 	int lowerCase;
4971 
4972 	(void) memset(targetNameStr, 0,
4973 	    targetNameStrLen * sizeof (wchar_t));
4974 	(void) memset(targetAddressStr, 0,
4975 	    targetAddressStrLen * sizeof (wchar_t));
4976 
4977 	commaPos = strchr(targetStr, ',');
4978 	if (commaPos != NULL) {
4979 		*commaPos = NULL;
4980 		commaPos++;
4981 		*targetAddressSpecified = B_TRUE;
4982 
4983 		/*
4984 		 * Checking of tpgt makes sense only when
4985 		 * the target address/port are specified.
4986 		 */
4987 		commaPos2 = strchr(commaPos, ',');
4988 		if (commaPos2 != NULL) {
4989 			*commaPos2 = NULL;
4990 			commaPos2++;
4991 			if (isNaturalNumber(commaPos2, ISCSI_MAX_TPGT_VALUE) ==
4992 			    B_TRUE) {
4993 				*tpgt = atoi(commaPos2);
4994 				*tpgtSpecified = B_TRUE;
4995 			} else {
4996 				return (PARSE_TARGET_INVALID_TPGT);
4997 			}
4998 		}
4999 
5000 		switch (parseAddress(commaPos, ISCSI_LISTEN_PORT,
5001 		    &targetAddress[0], MAX_ADDRESS_LEN + 1, port, isIpv6)) {
5002 		case PARSE_ADDR_PORT_OUT_OF_RANGE:
5003 			return (PARSE_TARGET_INVALID_ADDR);
5004 		case PARSE_ADDR_OK:
5005 			break;
5006 		default:
5007 			(void) fprintf(stderr, "%s: %s\n",
5008 			    cmdName, gettext("cannot parse target name"));
5009 			return (PARSE_TARGET_INVALID_ADDR);
5010 		}
5011 		(void) mbstowcs(targetAddressStr, targetAddress,
5012 		    targetAddressStrLen);
5013 		for (i = 0; targetAddressStr[i] != 0; i++) {
5014 			lowerCase = tolower(targetAddressStr[i]);
5015 			targetAddressStr[i] = lowerCase;
5016 		}
5017 	} else {
5018 		*targetAddressSpecified = B_FALSE;
5019 		*tpgtSpecified = B_FALSE;
5020 	}
5021 
5022 	(void) mbstowcs(targetNameStr, targetStr, targetNameStrLen);
5023 	for (i = 0; targetNameStr[i] != 0; i++) {
5024 		lowerCase = tolower(targetNameStr[i]);
5025 		targetNameStr[i] = lowerCase;
5026 	}
5027 
5028 	return (PARSE_TARGET_OK);
5029 }
5030 
5031 /*ARGSUSED*/
5032 static void
5033 listCHAPName(IMA_OID oid)
5034 {
5035 	IMA_INITIATOR_AUTHPARMS authParams;
5036 	IMA_STATUS status;
5037 	IMA_BYTE chapName [MAX_CHAP_NAME_LEN + 1];
5038 
5039 	/* Get Chap Name depending upon oid object type */
5040 	if (oid.objectType == IMA_OBJECT_TYPE_LHBA) {
5041 		status = IMA_GetInitiatorAuthParms(oid,
5042 		    IMA_AUTHMETHOD_CHAP, &authParams);
5043 	} else {
5044 		status = SUN_IMA_GetTargetAuthParms(oid,
5045 		    IMA_AUTHMETHOD_CHAP, &authParams);
5046 	}
5047 
5048 	(void) fprintf(stdout, "\n\t\t%s: ", gettext("CHAP Name"));
5049 
5050 	if (IMA_SUCCESS(status)) {
5051 		/*
5052 		 * Default chap name will be the node name.  The default will
5053 		 * be set by the driver.
5054 		 */
5055 		if (authParams.chapParms.nameLength != 0) {
5056 			(void) memset(chapName, 0, sizeof (chapName));
5057 			(void) memcpy(chapName, authParams.chapParms.name,
5058 			    authParams.chapParms.nameLength);
5059 			(void) fprintf(stdout, "%s", chapName);
5060 
5061 		} else {
5062 			(void) fprintf(stdout, "%s", "-");
5063 		}
5064 	} else {
5065 		(void) fprintf(stdout, "%s", "-");
5066 	}
5067 }
5068 
5069 /*
5070  * Prints out see manual page.
5071  * Called out through atexit(3C) so is always last thing displayed.
5072  */
5073 void
5074 seeMan(void)
5075 {
5076 	static int sent = 0;
5077 
5078 	if (sent)
5079 		return;
5080 
5081 	(void) fprintf(stdout, "%s %s(1M)\n",
5082 	    gettext("For more information, please see"), cmdName);
5083 
5084 	sent = 1;
5085 }
5086 
5087 
5088 /*
5089  * main calls a parser that checks syntax of the input command against
5090  * various rules tables.
5091  *
5092  * The parser provides usage feedback based upon same tables by calling
5093  * two usage functions, usage and subUsage, handling command and subcommand
5094  * usage respectively.
5095  *
5096  * The parser handles all printing of usage syntactical errors
5097  *
5098  * When syntax is successfully validated, the parser calls the associated
5099  * function using the subcommands table functions.
5100  *
5101  * Syntax is as follows:
5102  *	command subcommand [options] resource-type [<object>]
5103  *
5104  * The return value from the function is placed in funcRet
5105  */
5106 int
5107 main(int argc, char *argv[])
5108 {
5109 	synTables_t synTables;
5110 	char versionString[VERSION_STRING_MAX_LEN];
5111 	int ret;
5112 	int funcRet = 0;
5113 	void *subcommandArgs = NULL;
5114 
5115 	if (geteuid() != 0) {
5116 		(void) fprintf(stderr, "%s\n", gettext("permission denied"));
5117 		return (1);
5118 	}
5119 
5120 	/* set global command name */
5121 	cmdName = getExecBasename(argv[0]);
5122 
5123 	(void) snprintf(versionString, sizeof (versionString), "%s.%s",
5124 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
5125 	synTables.versionString = versionString;
5126 	synTables.longOptionTbl = &longOptions[0];
5127 	synTables.subcommandTbl = &subcommands[0];
5128 	synTables.objectTbl = &objects[0];
5129 	synTables.objectRulesTbl = &objectRules[0];
5130 	synTables.optionRulesTbl = &optionRules[0];
5131 
5132 	/* call the CLI parser */
5133 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
5134 	if (ret == -1) {
5135 		perror(cmdName);
5136 		ret = 1;
5137 	}
5138 
5139 	if (funcRet != 0) {
5140 		(void) fprintf(stderr, "%s: %s\n",
5141 		    cmdName, gettext("Unable to complete operation"));
5142 		ret = 1;
5143 	}
5144 	return (ret);
5145 }
5146