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