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