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