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