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