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