# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG = iscsiadm OBJS = cmdparse.o sun_ima.o iscsiadm_main.o SRCS =$(OBJS:%.o=%.c) POFILES= $(OBJS:%.o=%.po) POFILE= iscsiadm.po include ../Makefile.cmd LDLIBS += -lnsl -ldevinfo -lima CPPFLAGS += -DSOLARIS CPPFLAGS += -I. CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-variable CERRWARN += -Wno-unused-function CERRWARN += -Wno-switch CERRWARN += $(CNOWARN_UNINIT) # not linted SMATCH=off FILEMODE= 0555 .KEEP_STATE: all: $(PROG) install: all $(ROOTUSRSBINPROG) $(PROG): $(OBJS) $(COMMON_OBJS) $(LINK.c) -o $(PROG) $(OBJS) $(COMMON_OBJS) $(LDLIBS) $(POST_PROCESS) lint : LINTFLAGS += -u -DSOLARIS lint : LINTFLAGS64 += -u -DSOLARIS lint: $$(SRCS) $(LINT.c) $(SRCS) $(LDLIBS) $(POFILE): $(POFILES) $(RM) $@ cat $(POFILES) > $@ clean: -$(RM) $(OBJS) $(COMMON_OBJS) include $(SRC)/cmd/Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2020 Joyent Inc. */ #include #include #include #include #include #include #include #include #include #include "cmdparse.h" /* Usage types */ #define GENERAL_USAGE 1 #define HELP_USAGE 2 #define DETAIL_USAGE 3 /* printable ascii character set len */ #define MAXOPTIONS (uint_t)('~' - '!' + 1) /* * MAXOPTIONSTRING is the max length of the options string used in getopt and * will be the printable character set + ':' for each character, * providing for options with arguments. e.g. "t:Cs:hglr:" */ #define MAXOPTIONSTRING MAXOPTIONS * 2 /* standard command options table to support -?, -V */ struct option standardCmdOptions[] = { {"help", no_argument, NULL, '?'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; /* standard subcommand options table to support -? */ struct option standardSubCmdOptions[] = { {"help", no_argument, NULL, '?'}, {NULL, 0, NULL, 0} }; /* forward declarations */ static int getSubcommand(char *, subcommand_t **); static char *getExecBasename(char *); static void usage(uint_t); static void subUsage(uint_t, subcommand_t *); static void subUsageObject(uint_t, subcommand_t *, object_t *); static int getObject(char *, object_t **); static int getObjectRules(uint_t, objectRules_t **); static const char *getLongOption(int); static optionProp_t *getOptions(uint_t, uint_t); static char *getOptionArgDesc(int); extern void seeMan(void); /* global data */ static struct option *_longOptions; static subcommand_t *_subcommands; static object_t *_objects; static objectRules_t *_objectRules; static optionRules_t *_optionRules; static optionTbl_t *_clientOptionTbl; static char *commandName; /* * input: * object - object value * output: * opCmd - pointer to opCmd_t structure allocated by caller * * On successful return, opCmd contains the rules for the value in * object. On failure, the contents of opCmd is unspecified. * * Returns: * zero on success * non-zero on failure * */ static int getObjectRules(uint_t object, objectRules_t **objectRules) { objectRules_t *sp; for (sp = _objectRules; sp->value; sp++) { if (sp->value == object) { *objectRules = sp; return (0); } } return (1); } /* * input: * arg - pointer to array of char containing object string * * output: * object - pointer to object_t structure pointer * on success, contains the matching object structure based on * input object name * * Returns: * zero on success * non-zero otherwise * */ static int getObject(char *arg, object_t **object) { object_t *op; int len; for (op = _objects; op->name; op++) { len = strlen(arg); if (len == strlen(op->name) && strncasecmp(arg, op->name, len) == 0) { *object = op; return (0); } } return (1); } /* * input: * arg - pointer to array of char containing subcommand string * output: * subcommand - pointer to subcommand_t pointer * on success, contains the matching subcommand structure based on * input subcommand name * * Returns: * zero on success * non-zero on failure */ static int getSubcommand(char *arg, subcommand_t **subcommand) { subcommand_t *sp; int len; for (sp = _subcommands; sp->name; sp++) { len = strlen(arg); if (len == strlen(sp->name) && strncasecmp(arg, sp->name, len) == 0) { *subcommand = sp; return (0); } } return (1); } /* * input: * object - object for which to get options * subcommand - subcommand for which to get options * * Returns: * on success, optionsProp_t pointer to structure matching input object * value * on failure, NULL is returned */ static optionProp_t * getOptions(uint_t object, uint_t subcommand) { uint_t currObject; optionRules_t *op = _optionRules; while (op && ((currObject = op->objectValue) != 0)) { if ((currObject == object) && (op->subcommandValue == subcommand)) { return (&(op->optionProp)); } op++; } return (NULL); } /* * input: * shortOption - short option character for which to return the * associated long option string * * Returns: * on success, long option name * on failure, NULL */ static const char * getLongOption(int shortOption) { struct option *op; for (op = _longOptions; op->name; op++) { if (shortOption == op->val) { return (op->name); } } return (NULL); } /* * input * shortOption - short option character for which to return the * option argument * Returns: * on success, argument string * on failure, NULL */ static char * getOptionArgDesc(int shortOption) { optionTbl_t *op; for (op = _clientOptionTbl; op->name; op++) { if (op->val == shortOption && op->has_arg == required_argument) { return (op->argDesc); } } return (NULL); } /* * Print usage for a subcommand. * * input: * usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE * subcommand - pointer to subcommand_t structure * * Returns: * none * */ static void subUsage(uint_t usageType, subcommand_t *subcommand) { int i; object_t *objp; (void) fprintf(stdout, "%s:\t%s %s [", gettext("Usage"), commandName, subcommand->name); for (i = 0; standardSubCmdOptions[i].name; i++) { (void) fprintf(stdout, "-%c", standardSubCmdOptions[i].val); if (standardSubCmdOptions[i+1].name) (void) fprintf(stdout, ","); } (void) fprintf(stdout, "] %s [", ""); for (i = 0; standardSubCmdOptions[i].name; i++) { (void) fprintf(stdout, "-%c", standardSubCmdOptions[i].val); if (standardSubCmdOptions[i+1].name) (void) fprintf(stdout, ","); } (void) fprintf(stdout, "] %s", "[]"); (void) fprintf(stdout, "\n"); if (usageType == GENERAL_USAGE) { return; } (void) fprintf(stdout, "%s:\n", gettext("Usage by OBJECT")); /* * iterate through object table * For each object, print appropriate usage * based on rules tables */ for (objp = _objects; objp->value; objp++) { subUsageObject(usageType, subcommand, objp); } (void) atexit(seeMan); } /* * Print usage for a subcommand and object. * * input: * usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE * subcommand - pointer to subcommand_t structure * objp - pointer to a object_t structure * * Returns: * none * */ static void subUsageObject(uint_t usageType, subcommand_t *subcommand, object_t *objp) { int i; objectRules_t *objRules = NULL; opCmd_t *opCmd = NULL; optionProp_t *options; char *optionArgDesc; const char *longOpt; if (getObjectRules(objp->value, &objRules) != 0) { /* * internal subcommand rules table error * no object entry in object */ assert(0); } opCmd = &(objRules->opCmd); if (opCmd->invOpCmd & subcommand->value) { return; } options = getOptions(objp->value, subcommand->value); /* print generic subcommand usage */ (void) fprintf(stdout, "\t%s %s ", commandName, subcommand->name); /* print object */ (void) fprintf(stdout, "%s ", objp->name); /* print options if applicable */ if (options != NULL) { if (options->required) { (void) fprintf(stdout, "%s", gettext("<")); } else { (void) fprintf(stdout, "%s", gettext("[")); } (void) fprintf(stdout, "%s", gettext("OPTIONS")); if (options->required) { (void) fprintf(stdout, "%s ", gettext(">")); } else { (void) fprintf(stdout, "%s ", gettext("]")); } } /* print operand requirements */ if (opCmd->optOpCmd & subcommand->value) { (void) fprintf(stdout, gettext("[")); } if (!(opCmd->noOpCmd & subcommand->value)) { (void) fprintf(stdout, gettext("<")); if (objRules->operandDefinition) { (void) fprintf(stdout, "%s", objRules->operandDefinition); } else { /* * Missing operand description * from table */ assert(0); } } if (opCmd->multOpCmd & subcommand->value) { (void) fprintf(stdout, gettext(" ...")); } if (!(opCmd->noOpCmd & subcommand->value)) { (void) fprintf(stdout, gettext(">")); } if (opCmd->optOpCmd & subcommand->value) { (void) fprintf(stdout, gettext("]")); } if (usageType == HELP_USAGE) { (void) fprintf(stdout, "\n"); return; } /* print options for subcommand, object */ if (options != NULL && options->optionString != NULL) { (void) fprintf(stdout, "\n\t%s:", gettext("OPTIONS")); for (i = 0; i < strlen(options->optionString); i++) { if ((longOpt = getLongOption( options->optionString[i])) == NULL) { /* no long option exists for short option */ assert(0); } (void) fprintf(stdout, "\n\t\t-%c, --%s ", options->optionString[i], longOpt); optionArgDesc = getOptionArgDesc(options->optionString[i]); if (optionArgDesc != NULL) { (void) fprintf(stdout, "<%s>", optionArgDesc); } if (options->exclusive && strchr(options->exclusive, options->optionString[i])) { (void) fprintf(stdout, " (%s)", gettext("exclusive")); } } } (void) fprintf(stdout, "\n"); (void) atexit(seeMan); } /* * input: * type of usage statement to print * * Returns: * return value of subUsage */ static void usage(uint_t usageType) { int i; subcommand_t subcommand; subcommand_t *sp; /* print general command usage */ (void) fprintf(stdout, "%s:\t%s ", gettext("Usage"), commandName); for (i = 0; standardCmdOptions[i].name; i++) { (void) fprintf(stdout, "-%c", standardCmdOptions[i].val); if (standardCmdOptions[i+1].name) (void) fprintf(stdout, ","); } if (usageType == HELP_USAGE || usageType == GENERAL_USAGE) { for (i = 0; standardCmdOptions[i].name; i++) { } } (void) fprintf(stdout, "\n"); /* print all subcommand usage */ for (sp = _subcommands; sp->name; sp++) { subcommand.name = sp->name; subcommand.value = sp->value; if (usageType == HELP_USAGE) { (void) fprintf(stdout, "\n"); } subUsage(usageType, &subcommand); } (void) atexit(seeMan); } /* * input: * execFullName - exec name of program (argv[0]) * * Returns: * command name portion of execFullName */ static char * getExecBasename(char *execFullname) { char *lastSlash, *execBasename; /* guard against '/' at end of command invocation */ for (;;) { lastSlash = strrchr(execFullname, '/'); if (lastSlash == NULL) { execBasename = execFullname; break; } else { execBasename = lastSlash + 1; if (*execBasename == '\0') { *lastSlash = '\0'; continue; } break; } } return (execBasename); } /* * cmdParse is a parser that checks syntax of the input command against * various rules tables. * * It provides usage feedback based upon the passed rules tables by calling * two usage functions, usage, subUsage, and subUsageObject handling command, * subcommand and object usage respectively. * * When syntax is successfully validated, the associated function is called * using the subcommands table functions. * * Syntax is as follows: * command subcommand object [] [] * * There are two standard short and long options assumed: * -?, --help Provides usage on a command or subcommand * and stops further processing of the arguments * * -V, --version Provides version information on the command * and stops further processing of the arguments * * These options are loaded by this function. * * input: * argc, argv from main * syntax rules tables (synTables_t structure) * callArgs - void * passed by caller to be passed to subcommand function * * output: * funcRet - pointer to int that holds subcommand function return value * * Returns: * * zero on successful syntax parse and function call * * 1 on unsuccessful syntax parse (no function has been called) * This could be due to a version or help call or simply a * general usage call. * * -1 check errno, call failed * * This module is not MT-safe. * */ int cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs, int *funcRet) { int getoptargc; char **getoptargv; int opt; int operInd; int i, j; int len; char *versionString; char optionStringAll[MAXOPTIONSTRING + 1]; optionProp_t *availOptions; objectRules_t *objRules = NULL; opCmd_t *opCmd = NULL; subcommand_t *subcommand; object_t *object; cmdOptions_t cmdOptions[MAXOPTIONS + 1]; struct option *lp; optionTbl_t *optionTbl; struct option intLongOpt[MAXOPTIONS + 1]; /* * Check for NULLs on mandatory input arguments * * Note: longOptionTbl and optionRulesTbl can be NULL in the case * where there is no caller defined options * */ if (synTable.versionString == NULL || synTable.subcommandTbl == NULL || synTable.objectRulesTbl == NULL || synTable.objectTbl == NULL || funcRet == NULL) { assert(0); } versionString = synTable.versionString; /* set global command name */ commandName = getExecBasename(argv[0]); /* Set unbuffered output */ setbuf(stdout, NULL); /* load globals */ _subcommands = synTable.subcommandTbl; _objectRules = synTable.objectRulesTbl; _optionRules = synTable.optionRulesTbl; _objects = synTable.objectTbl; _clientOptionTbl = synTable.longOptionTbl; /* There must be at least two arguments */ if (argc < 2) { usage(GENERAL_USAGE); return (1); } (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt)); /* * load standard subcommand options to internal long options table * Two separate getopt_long(3C) tables are used. */ for (i = 0; standardSubCmdOptions[i].name; i++) { intLongOpt[i].name = standardSubCmdOptions[i].name; intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg; intLongOpt[i].flag = standardSubCmdOptions[i].flag; intLongOpt[i].val = standardSubCmdOptions[i].val; } /* * copy caller's long options into internal long options table * We do this for two reasons: * 1) We need to use the getopt_long option structure internally * 2) We need to prepend the table with the standard option * for all subcommands (currently -?) */ for (optionTbl = synTable.longOptionTbl; optionTbl && optionTbl->name; optionTbl++, i++) { if (i > MAXOPTIONS - 1) { /* option table too long */ assert(0); } intLongOpt[i].name = optionTbl->name; intLongOpt[i].has_arg = optionTbl->has_arg; intLongOpt[i].flag = NULL; intLongOpt[i].val = optionTbl->val; } /* set option table global */ _longOptions = &intLongOpt[0]; /* * Check for help/version request immediately following command * '+' in option string ensures POSIX compliance in getopt_long() * which means that processing will stop at first non-option * argument. */ while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions, NULL)) != EOF) { switch (opt) { case '?': /* * getopt can return a '?' when no * option letters match string. Check for * the 'real' '?' in optopt. */ if (optopt == '?') { usage(HELP_USAGE); return (0); } else { usage(GENERAL_USAGE); return (0); } case 'V': (void) fprintf(stdout, "%s: %s %s\n", commandName, gettext("Version"), versionString); (void) atexit(seeMan); return (0); default: break; } } /* * subcommand is always in the second argument. If there is no * recognized subcommand in the second argument, print error, * general usage and then return. */ if (getSubcommand(argv[1], &subcommand) != 0) { (void) fprintf(stderr, "%s: %s\n", commandName, gettext("invalid subcommand")); usage(GENERAL_USAGE); return (1); } if (argc == 2) { (void) fprintf(stderr, "%s: %s\n", commandName, gettext("missing object")); subUsage(GENERAL_USAGE, subcommand); (void) atexit(seeMan); return (1); } getoptargv = argv; getoptargv++; getoptargc = argc; getoptargc -= 1; while ((opt = getopt_long(getoptargc, getoptargv, "+?", standardSubCmdOptions, NULL)) != EOF) { switch (opt) { case '?': /* * getopt can return a '?' when no * option letters match string. Check for * the 'real' '?' in optopt. */ if (optopt == '?') { subUsage(HELP_USAGE, subcommand); return (0); } else { subUsage(GENERAL_USAGE, subcommand); return (0); } default: break; } } /* * object is always in the third argument. If there is no * recognized object in the third argument, print error, * help usage for the subcommand and then return. */ if (getObject(argv[2], &object) != 0) { (void) fprintf(stderr, "%s: %s\n", commandName, gettext("invalid object")); subUsage(HELP_USAGE, subcommand); return (1); } if (getObjectRules(object->value, &objRules) != 0) { /* * internal subcommand rules table error * no object entry in object table */ assert(0); } opCmd = &(objRules->opCmd); /* * Is command valid for this object? */ if (opCmd->invOpCmd & subcommand->value) { (void) fprintf(stderr, "%s: %s %s\n", commandName, gettext("invalid subcommand for"), object->name); subUsage(HELP_USAGE, subcommand); return (1); } /* * offset getopt arg begin since * getopt(3C) assumes options * follow first argument */ getoptargv = argv; getoptargv++; getoptargv++; getoptargc = argc; getoptargc -= 2; (void) memset(optionStringAll, 0, sizeof (optionStringAll)); (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions)); j = 0; /* * Build optionStringAll from long options table */ for (lp = _longOptions; lp->name; lp++, j++) { /* sanity check on string length */ if (j + 1 >= sizeof (optionStringAll)) { /* option table too long */ assert(0); } optionStringAll[j] = lp->val; if (lp->has_arg == required_argument) { optionStringAll[++j] = ':'; } } i = 0; /* * Run getopt for all arguments against all possible options * Store all options/option arguments in an array for retrieval * later. * Once all options are retrieved, check against object * and subcommand (option rules table) for validity. * This is done later. */ while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll, _longOptions, NULL)) != EOF) { switch (opt) { case '?': if (optopt == '?') { subUsageObject(DETAIL_USAGE, subcommand, object); return (0); } else { subUsage(GENERAL_USAGE, subcommand); return (0); } default: cmdOptions[i].optval = opt; if (optarg) { len = strlen(optarg); if (len > sizeof (cmdOptions[i].optarg) - 1) { (void) fprintf(stderr, "%s: %s\n", commandName, gettext("option too long")); errno = EINVAL; return (-1); } (void) strncpy(cmdOptions[i].optarg, optarg, len); } i++; break; } } /* * increment past last option */ operInd = optind + 2; /* * Check validity of given options, if any were given */ /* get option string for this object and subcommand */ availOptions = getOptions(object->value, subcommand->value); if (cmdOptions[0].optval != 0) { /* options were input */ if (availOptions == NULL) { /* no options permitted */ (void) fprintf(stderr, "%s: %s\n", commandName, gettext("no options permitted")); subUsageObject(HELP_USAGE, subcommand, object); return (1); } for (i = 0; cmdOptions[i].optval; i++) { /* Check for invalid options */ if (availOptions->optionString == NULL) { /* * internal option table error * There must be an option string if * there is an entry in the table */ assert(0); } /* is the option in the available option string? */ if (!(strchr(availOptions->optionString, cmdOptions[i].optval))) { (void) fprintf(stderr, "%s: '-%c': %s\n", commandName, cmdOptions[i].optval, gettext("invalid option")); subUsageObject(DETAIL_USAGE, subcommand, object); return (1); /* Check for exclusive options */ } else if (cmdOptions[1].optval != 0 && availOptions->exclusive && strchr(availOptions->exclusive, cmdOptions[i].optval)) { (void) fprintf(stderr, "%s: '-%c': %s\n", commandName, cmdOptions[i].optval, gettext("is an exclusive option")); subUsageObject(DETAIL_USAGE, subcommand, object); return (1); } } } else { /* no options were input */ if (availOptions != NULL && (availOptions->required)) { (void) fprintf(stderr, "%s: %s\n", commandName, gettext("at least one option required")); subUsageObject(DETAIL_USAGE, subcommand, object); return (1); } } /* * If there are no more arguments (operands), * check to see if this is okay */ if ((operInd == argc) && (opCmd->reqOpCmd & subcommand->value)) { (void) fprintf(stderr, "%s: %s %s %s\n", commandName, subcommand->name, object->name, gettext("requires an operand")); subUsageObject(HELP_USAGE, subcommand, object); (void) atexit(seeMan); return (1); } /* * If there are more operands, * check to see if this is okay */ if ((argc > operInd) && (opCmd->noOpCmd & subcommand->value)) { (void) fprintf(stderr, "%s: %s %s %s\n", commandName, subcommand->name, object->name, gettext("takes no operands")); subUsageObject(HELP_USAGE, subcommand, object); return (1); } /* * If there is more than one more operand, * check to see if this is okay */ if ((argc > operInd) && ((argc - operInd) != 1) && !(opCmd->multOpCmd & subcommand->value)) { (void) fprintf(stderr, "%s: %s %s %s\n", commandName, subcommand->name, object->name, gettext("accepts only a single operand")); subUsageObject(HELP_USAGE, subcommand, object); return (1); } /* Finished syntax checks */ /* Call appropriate function */ return (subcommand->handler(argc - operInd, &argv[operInd], object->value, &cmdOptions[0], callArgs, funcRet)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _CMDPARSE_H #define _CMDPARSE_H #ifdef __cplusplus extern "C" { #endif #include /* subcommands must have a single bit on and must have exclusive values */ #define SUBCOMMAND_BASE 1 #define SUBCOMMAND(x) (SUBCOMMAND_BASE << x) #define OBJECT_BASE 1 #define OBJECT(x) (OBJECT_BASE << x) /* maximum length of an option argument */ #define MAXOPTARGLEN 256 /* * Add objects here * * EXAMPLE: * object_t object[] = { * {"target", TARGET}, * {NULL, 0} * }; */ typedef struct _object { char *name; uint_t value; } object_t; /* * This structure is passed into the caller's callback function and * will contain a list of all options entered and their associated * option arguments if applicable */ typedef struct _cmdOptions { int optval; char optarg[MAXOPTARGLEN + 1]; } cmdOptions_t; /* * list of objects, subcommands, valid short options, required flag and * exlusive option string * * objectValue -> object * subcommandValue -> subcommand value * optionProp.optionString -> short options that are valid * optionProp.required -> flag indicating whether at least one option is * required * optionProp.exclusive -> short options that are required to be exclusively * entered * * * If it's not here, there are no options for that object. * * The long options table specifies whether an option argument is required. * * * EXAMPLE: * * Based on DISCOVERY entry below: * * MODIFY DISCOVERY accepts -i, -s, -t and -l * MODIFY DISCOVERY requires at least one option * MODIFY DISCOVERY has no exclusive options * * * optionRules_t optionRules[] = { * {DISCOVERY, MODIFY, "istl", B_TRUE, NULL}, * {0, 0, NULL, 0, NULL} * }; */ typedef struct _optionProp { char *optionString; boolean_t required; char *exclusive; } optionProp_t; typedef struct _optionRules { uint_t objectValue; uint_t subcommandValue; optionProp_t optionProp; } optionRules_t; /* * Rules for subcommands and object operands * * Every object requires an entry * * value, reqOpCmd, optOpCmd, noOpCmd, invCmd, multOpCmd * * value -> numeric value of object * * The following five fields are comprised of values that are * a bitwise OR of the subcommands related to the object * * reqOpCmd -> subcommands that must have an operand * optOpCmd -> subcommands that may have an operand * noOpCmd -> subcommands that will have no operand * invCmd -> subcommands that are invalid * multOpCmd -> subcommands that can accept multiple operands * operandDefinition -> Usage definition for the operand of this object * * * EXAMPLE: * * based on TARGET entry below: * MODIFY and DELETE subcomamnds require an operand * LIST optionally requires an operand * There are no subcommands that requires that no operand is specified * ADD and REMOVE are invalid subcommands for this operand * DELETE can accept multiple operands * * objectRules_t objectRules[] = { * {TARGET, MODIFY|DELETE, LIST, 0, ADD|REMOVE, DELETE, * "target-name"}, * {0, 0, 0, 0, 0, NULL} * }; */ typedef struct _opCmd { uint_t reqOpCmd; uint_t optOpCmd; uint_t noOpCmd; uint_t invOpCmd; uint_t multOpCmd; } opCmd_t; typedef struct _objectRules { uint_t value; opCmd_t opCmd; char *operandDefinition; } objectRules_t; /* * subcommand callback function * * argc - number of arguments in argv * argv - operand arguments * options - options entered on command line * callData - pointer to caller data to be passed to subcommand function */ typedef int (*handler_t)(int argc, char *argv[], int, cmdOptions_t *options, void *callData, int *funtRet); /* * Add new subcommands here * * EXAMPLE: * subcommand_t subcommands[] = { * {"add", ADD, addFunc}, * {NULL, 0, NULL} * }; */ typedef struct _subcommand { char *name; uint_t value; handler_t handler; } subcommand_t; #define required_arg required_argument #define no_arg no_argument /* * Add short options and long options here * * name -> long option name * has_arg -> required_arg, no_arg * val -> short option character * argDesc -> description of option argument * * Note: This structure may not be used if your CLI has no * options. However, -?, --help and -V, --version will still be supported * as they are standard for every CLI. * * EXAMPLE: * * optionTbl_t options[] = { * {"filename", arg_required, 'f', "out-filename"}, * {NULL, 0, 0} * }; * */ typedef struct _optionTbl { char *name; int has_arg; int val; char *argDesc; } optionTbl_t; /* * After tables are set, assign them to this structure * for passing into cmdparse() */ typedef struct _synTables { char *versionString; optionTbl_t *longOptionTbl; subcommand_t *subcommandTbl; object_t *objectTbl; objectRules_t *objectRulesTbl; optionRules_t *optionRulesTbl; } synTables_t; /* * cmdParse is a parser that checks syntax of the input command against * various rules tables. * * When syntax is successfully validated, the function associated with the * subcommand is called using the subcommands table functions. * * Syntax for the command is as follows: * * command subcommand [] object [] * * * There are two standard short and long options assumed: * -?, --help Provides usage on a command or subcommand * and stops further processing of the arguments * * -V, --version Provides version information on the command * and stops further processing of the arguments * * These options are loaded by this function. * * input: * argc, argv from main * syntax rules tables (synTables_t structure) * callArgs - void * passed by caller to be passed to subcommand function * * output: * funcRet - pointer to int that holds subcommand function return value * * Returns: * * zero on successful syntax parse and function call * * 1 on unsuccessful syntax parse (no function has been called) * This could be due to a version or help call or simply a * general usage call. * * -1 check errno, call failed * */ int cmdParse(int numOperands, char *operands[], synTables_t synTables, void *callerArgs, int *funcRet); #ifdef __cplusplus } #endif #endif /* _CMDPARSE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ISCSIADM_H #define _ISCSIADM_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #define ADD SUBCOMMAND(0) #define LIST SUBCOMMAND(1) #define MODIFY SUBCOMMAND(2) #define REMOVE SUBCOMMAND(3) #define TARGET OBJECT(0) #define NODE OBJECT(1) #define INITIATOR OBJECT(2) #define STATIC_CONFIG OBJECT(3) #define DISCOVERY_ADDRESS OBJECT(4) #define DISCOVERY OBJECT(5) #define TARGET_PARAM OBJECT(6) #define ISNS_SERVER_ADDRESS OBJECT(7) #define DATA_SEQ_IN_ORDER 0x01 #define DEFAULT_TIME_2_RETAIN 0x02 #define DEFAULT_TIME_2_WAIT 0x03 #define FIRST_BURST_LENGTH 0x04 #define IMMEDIATE_DATA 0x05 #define INITIAL_R2T 0x06 #define MAX_BURST_LENGTH 0x07 #define DATA_PDU_IN_ORDER 0x08 #define MAX_OUTSTANDING_R2T 0x09 #define MAX_RECV_DATA_SEG_LEN 0x0a #define HEADER_DIGEST 0x0b #define DATA_DIGEST 0x0c #define MAX_CONNECTIONS 0x0d #define ERROR_RECOVERY_LEVEL 0x0e #define RECV_LOGIN_RSP_TIMEOUT 0x0f #define CONN_LOGIN_MAX 0x10 #define POLLING_LOGIN_DELAY 0x11 #define AUTH_NAME 0x01 #define AUTH_PASSWORD 0x02 #define ISCSIADM_ARG_ENABLE "enable" #define ISCSIADM_ARG_DISABLE "disable" /* * This object type is not defined by IMA. */ #define SUN_IMA_OBJECT_TYPE_CONN 13 /* Currently not defined in IMA */ #define SUN_IMA_NODE_ALIAS_LEN 256 #define MAKE_IMA_ERROR(x) ((IMA_STATUS)(IMA_STATUS_ERROR | (x))) #define SUN_IMA_SYSTEM_ERROR(status) (((IMA_STATUS)(status) & \ (IMA_STATUS)SUN_IMA_ERROR_SYSTEM_ERROR) == 0x8FFF0000 \ ? IMA_TRUE : IMA_FALSE) #define SUN_GET_SYSTEM_ERROR(x) (((IMA_STATUS)(x) & 0x0000FFFF)) #define SUN_IMA_ERROR_SYSTEM_ERROR MAKE_IMA_ERROR(0x0fff0000) typedef struct _parameterTbl { char *name; int val; } parameterTbl_t; /* * The following interfaces are not defined in IMA 1.1. Some of them * are requirement candidates for the next IMA release. */ #define SUN_IMA_MAX_DIGEST_ALGORITHMS 2 /* NONE and CRC 32 */ #define SUN_IMA_IP_ADDRESS_PORT_LEN 256 #define SUN_IMA_MAX_RADIUS_SECRET_LEN 128 /* Currently not defined in IMA_TARGET_DISCOVERY_METHOD enum */ #define IMA_TARGET_DISCOVERY_METHOD_UNKNOWN 0 typedef enum { SUN_IMA_DIGEST_NONE = 0, SUN_IMA_DIGEST_CRC32 = 1 } SUN_IMA_DIGEST_ALGORITHM; typedef struct _SUN_IMA_DIGEST_ALGORITHM_VALUE { IMA_UINT defaultAlgorithmCount; SUN_IMA_DIGEST_ALGORITHM defaultAlgorithms[SUN_IMA_MAX_DIGEST_ALGORITHMS]; IMA_BOOL currentValid; IMA_UINT currentAlgorithmCount; SUN_IMA_DIGEST_ALGORITHM currentAlgorithms[SUN_IMA_MAX_DIGEST_ALGORITHMS]; IMA_BOOL negotiatedValid; IMA_UINT negotiatedAlgorithmCount; SUN_IMA_DIGEST_ALGORITHM negotiatedAlgorithms[SUN_IMA_MAX_DIGEST_ALGORITHMS]; } SUN_IMA_DIGEST_ALGORITHM_VALUE; typedef struct _SUN_IMA_DISC_ADDR_PROP_LIST { IMA_UINT discAddrCount; IMA_DISCOVERY_ADDRESS_PROPERTIES props[1]; } SUN_IMA_DISC_ADDR_PROP_LIST; typedef struct _SUN_IMA_RADIUS_CONFIG { char hostnameIpAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; IMA_BOOL isIpv6; IMA_UINT16 port; IMA_BOOL sharedSecretValid; IMA_UINT sharedSecretLength; IMA_BYTE sharedSecret[SUN_IMA_MAX_RADIUS_SECRET_LEN]; } SUN_IMA_RADIUS_CONFIG; typedef struct _SUN_IMA_DISC_ADDRESS_KEY { IMA_NODE_NAME name; IMA_ADDRESS_KEY address; IMA_UINT16 tpgt; } SUN_IMA_DISC_ADDRESS_KEY; typedef struct _SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES { IMA_UINT keyCount; SUN_IMA_DISC_ADDRESS_KEY keys[1]; } SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES; typedef struct _SUN_IMA_TARGET_ADDRESS { IMA_TARGET_ADDRESS imaStruct; IMA_BOOL defaultTpgt; /* If true, tpgt becomes irrelvant */ IMA_UINT16 tpgt; } SUN_IMA_TARGET_ADDRESS; typedef struct _SUN_IMA_STATIC_DISCOVERY_TARGET { IMA_NODE_NAME targetName; SUN_IMA_TARGET_ADDRESS targetAddress; } SUN_IMA_STATIC_DISCOVERY_TARGET; typedef struct _SUN_IMA_STATIC_DISCOVERY_TARGET_PROPERTIES { IMA_OID associatedNodeOid; IMA_OID associatedLhbaOid; SUN_IMA_STATIC_DISCOVERY_TARGET staticTarget; } SUN_IMA_STATIC_DISCOVERY_TARGET_PROPERTIES; typedef struct _SUN_IMA_CONN_PROPERTIES { IMA_UINT32 connectionID; IMA_ADDRESS_KEY local; IMA_ADDRESS_KEY peer; IMA_BOOL valuesValid; IMA_UINT32 defaultTime2Retain; IMA_UINT32 defaultTime2Wait; IMA_UINT32 errorRecoveryLevel; IMA_UINT32 firstBurstLength; IMA_UINT32 maxBurstLength; IMA_UINT32 maxConnections; IMA_UINT32 maxOutstandingR2T; IMA_UINT32 maxRecvDataSegmentLength; IMA_BOOL dataPduInOrder; IMA_BOOL dataSequenceInOrder; IMA_BOOL immediateData; IMA_BOOL initialR2T; IMA_UINT headerDigest; IMA_UINT dataDigest; } SUN_IMA_CONN_PROPERTIES; #define SUN_IMA_LU_VENDOR_ID_LEN ISCSI_INQ_VID_BUF_LEN #define SUN_IMA_LU_PRODUCT_ID_LEN ISCSI_INQ_PID_BUF_LEN typedef struct _SUN_IMA_LU_PROPERTIES { IMA_LU_PROPERTIES imaProps; IMA_CHAR vendorId[SUN_IMA_LU_VENDOR_ID_LEN]; IMA_CHAR productId[SUN_IMA_LU_PRODUCT_ID_LEN]; } SUN_IMA_LU_PROPERTIES; typedef struct _SUN_IMA_TARGET_PROPERTIES { IMA_TARGET_PROPERTIES imaProps; IMA_BOOL defaultTpgtConf; /* If true, tpgtConf is irrelevant */ IMA_UINT16 tpgtConf; IMA_BOOL defaultTpgtNego; /* If true, tpgtNego is not connected */ IMA_UINT16 tpgtNego; IMA_BYTE isid[ISCSI_ISID_LEN]; } SUN_IMA_TARGET_PROPERTIES; typedef struct _SUN_IMA_CONFIG_SESSIONS { /* True if sessions are bound to an interface */ IMA_BOOL bound; /* OUT */ /* * Memory allocated from caller. In addition * on a Set this is the number of configured * sessions. */ IMA_UINT in; /* IN */ /* Number of Configured sessions on Get */ IMA_UINT out; /* OUT */ IMA_ADDRESS_KEY bindings[1]; /* IN/OUT */ } SUN_IMA_CONFIG_SESSIONS; typedef struct _SUN_IMA_STATIC_TARGET_PROPERTIES { IMA_OID associatedNodeOid; IMA_OID associatedLhbaOid; SUN_IMA_STATIC_DISCOVERY_TARGET staticTarget; } SUN_IMA_STATIC_TARGET_PROPERTIES; #ifdef __cplusplus } #endif #endif /* _ISCSIADM_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cmdparse.h" #include "sun_ima.h" #include "iscsiadm.h" #define VERSION_STRING_MAX_LEN 10 #define MAX_LONG_CHAR_LEN 19 #define MAX_AUTH_METHODS 5 /* * Version number: * MAJOR - This should only change when there is an incompatible change made * to the interfaces or the output. * * MINOR - This should change whenever there is a new command or new feature * with no incompatible change. */ #define VERSION_STRING_MAJOR "1" #define VERSION_STRING_MINOR "0" #define OPTIONSTRING1 "yes|no" #define OPTIONSTRING2 "initiator node name" #define OPTIONSTRING3 "initiator node alias" #define OPTIONSTRING4 "enable|disable" #define OPTIONSTRING5 "key=value,..." #define OPTIONSTRING6 "none|CRC32" #define OPTIONSTRING7 "CHAP name" #define OPTIONSTRING8 "<# sessions>|[,]*" #define OPTIONSTRING9 "tunable-prop=value" #define OPTIONVAL1 "0 to 3600" #define OPTIONVAL2 "512 to 2**24 - 1" #define OPTIONVAL3 "1 to 65535" #define OPTIONVAL4 "[:port]" #define MAX_ISCSI_NAME_LEN 223 #define MAX_ADDRESS_LEN 255 #define MIN_CHAP_SECRET_LEN 12 #define MAX_CHAP_SECRET_LEN 16 #define DEFAULT_ISCSI_PORT 3260 #define ISNS_DEFAULT_SERVER_PORT 3205 #define DEFAULT_RADIUS_PORT 1812 #define MAX_CHAP_NAME_LEN 512 #define ISCSI_DEFAULT_RX_TIMEOUT_VALUE "60" #define ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX "180" #define ISCSI_DEFAULT_LOGIN_POLLING_DELAY "60" /* For listNode */ #define INF_ERROR 1 #define INVALID_NODE_NAME 2 #define IMABOOLPRINT(prop, option) \ if ((option) == PRINT_CONFIGURED_PARAMS) { \ (void) fprintf(stdout, "%s/%s\n", \ (prop).defaultValue == IMA_TRUE ? gettext("yes") : \ gettext("no"), \ (prop).currentValueValid == IMA_TRUE ? \ ((prop).currentValue == IMA_TRUE ? \ gettext("yes"): gettext("no")) : "-"); \ } else if ((option) == PRINT_NEGOTIATED_PARAMS) { \ (void) fprintf(stdout, "%s\n", \ (prop).currentValueValid == IMA_TRUE ? \ (((prop).currentValue == IMA_TRUE) ? gettext("yes") : \ gettext("no")) : "-"); \ } #define IMAMINMAXPRINT(prop, option) \ if ((option) == PRINT_CONFIGURED_PARAMS) { \ (void) fprintf(stdout, "%d/", (prop).defaultValue); \ if ((prop).currentValueValid == IMA_TRUE) { \ (void) fprintf(stdout, "%d\n", (prop).currentValue); \ } else if ((prop).currentValueValid == IMA_FALSE) { \ (void) fprintf(stdout, "%s\n", "-"); \ } \ } else if ((option) == PRINT_NEGOTIATED_PARAMS) { \ if ((prop).currentValueValid == IMA_TRUE) { \ (void) fprintf(stdout, "%d\n", (prop).currentValue); \ } else if ((prop).currentValueValid == IMA_FALSE) { \ (void) fprintf(stdout, "%s\n", "-"); \ } \ } /* forward declarations */ #define PARSE_ADDR_OK 0 #define PARSE_ADDR_MISSING_CLOSING_BRACKET 1 #define PARSE_ADDR_PORT_OUT_OF_RANGE 2 #define PARSE_TARGET_OK 0 #define PARSE_TARGET_INVALID_TPGT 1 #define PARSE_TARGET_INVALID_ADDR 2 #define PRINT_CONFIGURED_PARAMS 1 #define PRINT_NEGOTIATED_PARAMS 2 typedef enum iSCSINameCheckStatus { iSCSINameCheckOK, iSCSINameLenZero, iSCSINameLenExceededMax, iSCSINameUnknownType, iSCSINameInvalidCharacter, iSCSINameIqnFormatError, iSCSINameEUIFormatError, iSCSINameIqnDateFormatError, iSCSINameIqnSubdomainFormatError, iSCSINameIqnInvalidYearError, iSCSINameIqnInvalidMonthError, iSCSINameIqnFQDNError } iSCSINameCheckStatusType; /* Utility functions */ iSCSINameCheckStatusType iSCSINameStringProfileCheck(wchar_t *name); boolean_t isNaturalNumber(char *numberStr, uint32_t upperBound); static int parseAddress(char *address_port_str, uint16_t defaultPort, char *address_str, size_t address_str_len, uint16_t *port, boolean_t *isIpv6); int parseTarget(char *targetStr, wchar_t *targetNameStr, size_t targetNameStrLen, boolean_t *targetAddressSpecified, wchar_t *targetAddressStr, size_t targetAddressStrLen, uint16_t *port, boolean_t *tpgtSpecified, uint16_t *tpgt, boolean_t *isIpv6); static int chkConnLoginMaxPollingLoginDelay(IMA_OID oid, int key, int uintValue); /* subcommand functions */ static int addFunc(int, char **, int, cmdOptions_t *, void *, int *); static int listFunc(int, char **, int, cmdOptions_t *, void *, int *); static int modifyFunc(int, char **, int, cmdOptions_t *, void *, int *); static int removeFunc(int, char **, int, cmdOptions_t *, void *, int *); /* helper functions */ static char *getExecBasename(char *); static int getNodeProps(IMA_NODE_PROPERTIES *); static int getSecret(char *, int *, int, int); static int getTargetAddress(int, char *, IMA_TARGET_ADDRESS *); static int printLoginParameters(char *, IMA_OID, int); static void printDiscoveryMethod(char *, IMA_UINT32); static void printTargetLuns(IMA_OID_LIST *); static void printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *); static void printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *, int); static int setLoginParameter(IMA_OID, int, char *); static int setLoginParameters(IMA_OID, char *); static int setTunableParameters(IMA_OID, char *); static void printLibError(IMA_STATUS); /* LINTED E_STATIC_UNUSED */ static int sunPluginChk(IMA_OID, boolean_t *); static int sunInitiatorFind(IMA_OID *); static int getAuthMethodValue(char *, IMA_AUTHMETHOD *); static int getLoginParam(char *); static int getTunableParam(char *); static void iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status); static int modifyIndividualTargetParam(cmdOptions_t *optionList, IMA_OID targetOid, int *); static void listCHAPName(IMA_OID oid); static int printConfiguredSessions(IMA_OID); static int printTunableParameters(IMA_OID oid); /* object functions per subcommand */ static int addAddress(int, int, char *[], int *); static int addStaticConfig(int, char *[], int *); static int listDiscovery(int *); static int listDiscoveryAddress(int, char *[], cmdOptions_t *, int *); static int listISNSServerAddress(int, char *[], cmdOptions_t *, int *); static int listNode(int *); static int listStaticConfig(int, char *[], int *); static int listTarget(int, char *[], cmdOptions_t *, int *); static int listTargetParam(int, char *[], cmdOptions_t *, int *); static int modifyDiscovery(cmdOptions_t *, int *); static int modifyNodeAuthMethod(IMA_OID, char *, int *); static int modifyNodeAuthParam(IMA_OID oid, int, char *, int *); static int modifyNodeRadiusConfig(IMA_OID, char *, int *); static int modifyNodeRadiusAccess(IMA_OID, char *, int *); static int modifyNodeRadiusSharedSecret(IMA_OID, int *); static int modifyNode(cmdOptions_t *, int *); static int modifyTargetAuthMethod(IMA_OID, char *, int *); static int modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *); static int modifyTargetParam(cmdOptions_t *, char *, int *); static int removeAddress(int, int, char *[], int *); static int removeStaticConfig(int, char *[], int *); static int removeTargetParam(int, char *[], int *); static int modifyTargetBidirAuthFlag(IMA_OID, char *, int *); static int modifyConfiguredSessions(IMA_OID targetOid, char *optarg); /* LINTED E_STATIC_UNUSED */ static IMA_STATUS getISCSINodeParameter(int paramType, IMA_OID *oid, void *pProps, uint32_t paramIndex); /* LINTED E_STATIC_UNUSED */ static IMA_STATUS setISCSINodeParameter(int paramType, IMA_OID *oid, void *pProps, uint32_t paramIndex); /* LINTED E_STATIC_UNUSED */ static IMA_STATUS getDigest(IMA_OID oid, int ioctlCmd, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm); IMA_STATUS getNegotiatedDigest(int digestType, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm, SUN_IMA_CONN_PROPERTIES *connProps); /* globals */ static char *cmdName; /* * Available option letters: * * befgijklmnoquwxyz * * DEFGHIJKLMOQUVWXYZ */ /* * Add new options here */ optionTbl_t longOptions[] = { {"static", required_arg, 's', OPTIONSTRING4}, {"sendtargets", required_arg, 't', OPTIONSTRING4}, {"iSNS", required_arg, 'i', OPTIONSTRING4}, {"headerdigest", required_arg, 'h', OPTIONSTRING6}, {"datadigest", required_arg, 'd', OPTIONSTRING6}, {"login-param", required_arg, 'p', OPTIONSTRING5}, {"authentication", required_arg, 'a', "CHAP|none"}, {"bi-directional-authentication", required_arg, 'B', OPTIONSTRING4}, {"CHAP-secret", no_arg, 'C', NULL}, {"CHAP-name", required_arg, 'H', OPTIONSTRING7}, {"node-name", required_arg, 'N', OPTIONSTRING2}, {"node-alias", required_arg, 'A', OPTIONSTRING3}, {"radius-server", required_arg, 'r', OPTIONVAL4}, {"radius-access", required_arg, 'R', OPTIONSTRING4}, {"radius-shared-secret", no_arg, 'P', NULL}, {"verbose", no_arg, 'v', NULL}, {"scsi-target", no_arg, 'S', NULL}, {"configured-sessions", required_arg, 'c', OPTIONSTRING8}, {"tunable-param", required_arg, 'T', OPTIONSTRING9}, {NULL, 0, 0, 0} }; parameterTbl_t loginParams[] = { {"dataseqinorder", DATA_SEQ_IN_ORDER}, {"defaulttime2retain", DEFAULT_TIME_2_RETAIN}, {"defaulttime2wait", DEFAULT_TIME_2_WAIT}, {"firstburstlength", FIRST_BURST_LENGTH}, {"immediatedata", IMMEDIATE_DATA}, {"initialr2t", INITIAL_R2T}, {"maxburstlength", MAX_BURST_LENGTH}, {"datapduinorder", DATA_PDU_IN_ORDER}, {"maxoutstandingr2t", MAX_OUTSTANDING_R2T}, {"maxrecvdataseglen", MAX_RECV_DATA_SEG_LEN}, {"maxconnections", MAX_CONNECTIONS}, {"errorrecoverylevel", ERROR_RECOVERY_LEVEL}, {NULL, 0} }; parameterTbl_t tunableParams[] = { {"recv-login-rsp-timeout", RECV_LOGIN_RSP_TIMEOUT}, {"conn-login-max", CONN_LOGIN_MAX}, {"polling-login-delay", POLLING_LOGIN_DELAY}, {NULL, 0} }; /* * Add new subcommands here */ subcommand_t subcommands[] = { {"add", ADD, addFunc}, {"list", LIST, listFunc}, {"modify", MODIFY, modifyFunc}, {"remove", REMOVE, removeFunc}, {NULL, 0, NULL} }; /* * Add objects here */ object_t objects[] = { {"discovery", DISCOVERY}, {"discovery-address", DISCOVERY_ADDRESS}, {"isns-server", ISNS_SERVER_ADDRESS}, {"initiator-node", NODE}, {"static-config", STATIC_CONFIG}, {"target", TARGET}, {"target-param", TARGET_PARAM}, {NULL, 0} }; /* * Rules for subcommands and objects */ objectRules_t objectRules[] = { {TARGET, 0, LIST, 0, ADD|REMOVE|MODIFY, LIST, "target-name"}, {TARGET_PARAM, MODIFY|REMOVE, LIST, 0, ADD, MODIFY, "target-name"}, {DISCOVERY, 0, 0, LIST|MODIFY, ADD|REMOVE, 0, NULL}, {NODE, 0, 0, MODIFY|LIST, ADD|REMOVE, 0, NULL}, {STATIC_CONFIG, ADD|REMOVE, LIST, 0, MODIFY, ADD|REMOVE|LIST, "target-name,target-address[:port-number][,tpgt]"}, {DISCOVERY_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY, ADD|REMOVE|LIST, "IP-address[:port-number]"}, {ISNS_SERVER_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY, ADD|REMOVE|LIST, "IP-address[:port-number]"}, {0, 0, 0, 0, 0, 0} }; /* * list of objects, subcommands, valid short options, required flag and * exclusive option string * * If it's not here, there are no options for that object. */ optionRules_t optionRules[] = { {DISCOVERY, MODIFY, "sti", B_TRUE, NULL}, {DISCOVERY_ADDRESS, LIST, "v", B_FALSE, NULL}, {ISNS_SERVER_ADDRESS, LIST, "v", B_FALSE, NULL}, {TARGET, LIST, "vS", B_FALSE, NULL}, {NODE, MODIFY, "NAhdCaRrPHcT", B_TRUE, "CP"}, {TARGET_PARAM, MODIFY, "ahdBCpcHT", B_TRUE, "C"}, {TARGET_PARAM, LIST, "v", B_FALSE, NULL}, {0, 0, 0, 0, 0} }; static boolean_t targetNamesEqual(wchar_t *name1, wchar_t *name2) { int i; wchar_t wchar1, wchar2; if (name1 == NULL || name2 == NULL) { return (B_FALSE); } if (wcslen(name1) != wcslen(name2)) { return (B_FALSE); } /* * Convert names to lower case and compare */ for (i = 0; i < wcslen(name1); i++) { wchar1 = towctrans((wint_t)name1[i], wctrans("tolower")); wchar2 = towctrans((wint_t)name2[i], wctrans("tolower")); if (wchar1 != wchar2) { return (B_FALSE); } } return (B_TRUE); } static boolean_t ipAddressesEqual(IMA_TARGET_ADDRESS addr1, IMA_TARGET_ADDRESS addr2) { #define IPV4_ADDR_BYTES 4 #define IPV6_ADDR_BYTES 16 int compSize; if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address != addr2.hostnameIpAddress.id.ipAddress.ipv4Address) { return (B_FALSE); } compSize = IPV6_ADDR_BYTES; if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address) { compSize = IPV4_ADDR_BYTES; } if (bcmp(addr1.hostnameIpAddress.id.ipAddress.ipAddress, addr2.hostnameIpAddress.id.ipAddress.ipAddress, compSize) == 0) { return (B_TRUE); } return (B_FALSE); } static int getLoginParam(char *arg) { parameterTbl_t *paramp; int len; for (paramp = loginParams; paramp->name; paramp++) { len = strlen(arg); if (len == strlen(paramp->name) && strncasecmp(arg, paramp->name, len) == 0) { return (paramp->val); } } return (-1); } static int getTunableParam(char *arg) { parameterTbl_t *paramp; int len; for (paramp = tunableParams; paramp->name != NULL; paramp++) { len = strlen(arg); if (len == strlen(paramp->name) && strncasecmp(arg, paramp->name, len) == 0) { return (paramp->val); } } return (-1); } static void printLibError(IMA_STATUS status) { char *errorString; switch (status) { case IMA_ERROR_NOT_SUPPORTED: errorString = gettext("Operation currently not supported"); break; case IMA_ERROR_INSUFFICIENT_MEMORY: errorString = gettext("Insufficient memory"); break; case IMA_ERROR_UNEXPECTED_OS_ERROR: errorString = gettext("unexpected OS error"); break; case IMA_ERROR_UNKNOWN_ERROR: errorString = gettext("Unknown error"); break; case IMA_ERROR_LU_IN_USE: errorString = gettext("Logical unit in use"); break; case IMA_ERROR_INVALID_PARAMETER: errorString = gettext("Invalid parameter specified"); break; case IMA_ERROR_INVALID_OBJECT_TYPE: errorString = gettext("Internal library error: Invalid oid type specified"); break; case IMA_ERROR_INCORRECT_OBJECT_TYPE: errorString = gettext("Internal library error: Incorrect oid type specified"); break; case IMA_ERROR_OBJECT_NOT_FOUND: errorString = gettext("Internal library error: Oid not found"); break; case IMA_ERROR_NAME_TOO_LONG: errorString = gettext("Name too long"); break; default: errorString = gettext("Unknown error"); } (void) fprintf(stderr, "%s: %s\n", cmdName, errorString); } /* * input: * execFullName - exec name of program (argv[0]) * * Returns: * command name portion of execFullName */ static char * getExecBasename(char *execFullname) { char *lastSlash, *execBasename; /* guard against '/' at end of command invocation */ for (;;) { lastSlash = strrchr(execFullname, '/'); if (lastSlash == NULL) { execBasename = execFullname; break; } else { execBasename = lastSlash + 1; if (*execBasename == '\0') { *lastSlash = '\0'; continue; } break; } } return (execBasename); } /* * input: * nodeProps - pointer to caller allocated IMA_NODE_PROPERTIES * * returns: * zero on success * non-zero otherwise */ static int getNodeProps(IMA_NODE_PROPERTIES *nodeProps) { IMA_OID sharedNodeOid; IMA_STATUS status = IMA_GetSharedNodeOid(&sharedNodeOid); if (!(IMA_SUCCESS(status))) { printLibError(status); return (INF_ERROR); } status = IMA_GetNodeProperties(sharedNodeOid, nodeProps); if (!IMA_SUCCESS(status)) { printLibError(status); return (INF_ERROR); } return (0); } /* * sunInitiatorFind * Purpose: * Finds the Sun iSCSI initiator (LHBA). This CLI currently supports only * one initiator. * * output: * oid of initiator * * Returns: * zero on success with initiator found * > 0 on success with no initiator found * < 0 on failure */ static int sunInitiatorFind(IMA_OID *oid) { IMA_OID_LIST *lhbaList = NULL; IMA_STATUS status = IMA_GetLhbaOidList(&lhbaList); if (!IMA_SUCCESS(status)) { printLibError(status); return (-1); } if ((lhbaList == NULL) || (lhbaList->oidCount == 0)) { printLibError(IMA_ERROR_OBJECT_NOT_FOUND); if (lhbaList != NULL) (void) IMA_FreeMemory(lhbaList); return (-1); } *oid = lhbaList->oids[0]; (void) IMA_FreeMemory(lhbaList); return (0); } /* * input: * wcInput - wide character string containing discovery address * output: * address - IMA_TARGET_ADDRESS structure containing valid * discovery address * returns: * zero on success * non-zero on failure */ static int getTargetAddress(int addrType, char *ipStr, IMA_TARGET_ADDRESS *address) { char cCol = ':'; char cBracketL = '['; /* Open Bracket '[' */ char cBracketR = ']'; /* Close Bracket ']' */ char *colPos; char *startPos; unsigned long inputPort; int addressType = AF_INET; char *tmpStrPtr, tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN]; int rval; /* Check if this is a ipv6 address */ if (ipStr[0] == cBracketL) { addressType = AF_INET6; startPos = strchr(ipStr, cBracketR); if (!startPos) { (void) fprintf(stderr, "%s: %s: ']' %s\n", cmdName, ipStr, gettext("missing")); return (1); } (void) strlcpy(tmpStr, ipStr+1, startPos-ipStr); address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_FALSE; tmpStrPtr = tmpStr; } else { /* set start position to beginning of input object */ addressType = AF_INET; startPos = ipStr; address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_TRUE; tmpStrPtr = ipStr; } /* wcschr for ':'. If not there, use default port */ colPos = strchr(startPos, cCol); if (!colPos) { if (addrType == DISCOVERY_ADDRESS) { inputPort = DEFAULT_ISCSI_PORT; } else if (addrType == ISNS_SERVER_ADDRESS) { inputPort = ISNS_DEFAULT_SERVER_PORT; } else { *colPos = '\0'; } } else { *colPos = '\0'; } rval = inet_pton(addressType, tmpStrPtr, address->hostnameIpAddress.id.ipAddress.ipAddress); /* inet_pton returns 1 on success */ if (rval != 1) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, ipStr, gettext("invalid IP address")); return (1); } if (colPos) { char *errchr; colPos++; if (*colPos == '\0') { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, ipStr, gettext("port number missing")); return (1); } /* * convert port string to unsigned value * Note: Don't remove errno = 0 as you may get false failures. */ errno = 0; inputPort = strtol(colPos, &errchr, 10); if (errno != 0 || inputPort == 0 && errchr != NULL) { (void) fprintf(stderr, "%s: %s:%s %s\n", cmdName, ipStr, colPos, gettext("port number invalid")); return (1); } /* make sure it's in the range */ if (inputPort > USHRT_MAX) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, ipStr, gettext("port number out of range")); return (1); } } address->portNumber = inputPort; return (0); } /* * Print results of send targets command */ static void printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList) { char outBuf[INET6_ADDRSTRLEN]; int inetSize; int af; int i; for (i = 0; i < pList->keyCount; i++) { if (pList->keys[i].address.ipAddress.ipv4Address == IMA_TRUE) { af = AF_INET; inetSize = INET_ADDRSTRLEN; } else { af = AF_INET6; inetSize = INET6_ADDRSTRLEN; } (void) fprintf(stdout, gettext("\tTarget name: %ws\n"), pList->keys[i].name); (void) fprintf(stdout, "\t\t%s: %15s:%d", "Target address", inet_ntop(af, &(pList->keys[i].address.ipAddress.ipAddress), outBuf, inetSize), pList->keys[i].address.portNumber); (void) fprintf(stdout, ", %d", pList->keys[i].tpgt); (void) fprintf(stdout, "\n"); } } /* * Print all login parameters */ static int printLoginParameters(char *prefix, IMA_OID oid, int printOption) { IMA_STATUS status; IMA_BOOL_VALUE propBool; IMA_MIN_MAX_VALUE propMinMax; char longString[MAX_LONG_CHAR_LEN + 1]; SUN_IMA_CONN_PROPERTIES *connProps = NULL; IMA_OID_LIST *pConnList; (void) memset(longString, 0, sizeof (longString)); switch (printOption) { case PRINT_CONFIGURED_PARAMS: (void) fprintf(stdout, "%s%s:\n", prefix, gettext("Login Parameters (Default/Configured)")); break; case PRINT_NEGOTIATED_PARAMS: (void) fprintf(stdout, "%s%s:\n", prefix, gettext("Login Parameters (Negotiated)")); status = SUN_IMA_GetConnOidList( &oid, &pConnList); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } status = SUN_IMA_GetConnProperties(&pConnList->oids[0], &connProps); propBool.currentValueValid = connProps->valuesValid; propMinMax.currentValueValid = connProps->valuesValid; break; default: return (1); } if (printOption == PRINT_NEGOTIATED_PARAMS) { propBool.currentValue = connProps->dataSequenceInOrder; } else { status = IMA_GetDataSequenceInOrderProperties(oid, &propBool); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Data Sequence In Order")); IMABOOLPRINT(propBool, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propBool.currentValue = connProps->dataPduInOrder; } else { status = IMA_GetDataPduInOrderProperties(oid, &propBool); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Data PDU In Order")); IMABOOLPRINT(propBool, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->defaultTime2Retain; } else { status = IMA_GetDefaultTime2RetainProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Default Time To Retain")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->defaultTime2Wait; } else { status = IMA_GetDefaultTime2WaitProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Default Time To Wait")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->errorRecoveryLevel; } else { status = IMA_GetErrorRecoveryLevelProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Error Recovery Level")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->firstBurstLength; } else { status = IMA_GetFirstBurstLengthProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("First Burst Length")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propBool.currentValue = connProps->immediateData; } else { status = IMA_GetImmediateDataProperties(oid, &propBool); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Immediate Data")); IMABOOLPRINT(propBool, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propBool.currentValue = connProps->initialR2T; } else { status = IMA_GetInitialR2TProperties(oid, &propBool); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Initial Ready To Transfer (R2T)")); IMABOOLPRINT(propBool, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->maxBurstLength; } else { status = IMA_GetMaxBurstLengthProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Burst Length")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->maxOutstandingR2T; } else { status = IMA_GetMaxOutstandingR2TProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Outstanding R2T")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->maxRecvDataSegmentLength; } else { status = IMA_GetMaxRecvDataSegmentLengthProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Receive Data Segment Length")); IMAMINMAXPRINT(propMinMax, printOption); if (printOption == PRINT_NEGOTIATED_PARAMS) { propMinMax.currentValue = connProps->maxConnections; } else { status = IMA_GetMaxConnectionsProperties(oid, &propMinMax); } if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(connProps); return (1); } (void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Connections")); IMAMINMAXPRINT(propMinMax, printOption); (void) IMA_FreeMemory(connProps); return (0); } /* * Print discovery information. */ static void printDiscoveryMethod(char *prefix, IMA_UINT32 discoveryMethodFlags) { (void) fprintf(stdout, "%s%s: ", prefix, gettext("Discovery Method")); if (discoveryMethodFlags == IMA_TARGET_DISCOVERY_METHOD_UNKNOWN) { (void) fprintf(stdout, "%s\n", gettext("NA")); } else { if (!((discoveryMethodFlags & IMA_TARGET_DISCOVERY_METHOD_STATIC) ^ IMA_TARGET_DISCOVERY_METHOD_STATIC)) { (void) fprintf(stdout, "%s ", gettext("Static")); } if (!((discoveryMethodFlags & IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS) ^ IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS)) { (void) fprintf(stdout, "%s ", gettext("SendTargets")); } if (!((discoveryMethodFlags & IMA_TARGET_DISCOVERY_METHOD_ISNS) ^ IMA_TARGET_DISCOVERY_METHOD_ISNS)) { (void) fprintf(stdout, "%s ", gettext("iSNS")); } (void) fprintf(stdout, "\n"); } } /* * printConnectionList - Prints the conection list provided */ static void printConnectionList(char *prefix, IMA_OID_LIST *pConnList) { IMA_STATUS imaStatus; int i; SUN_IMA_CONN_PROPERTIES *connProps; union { char ipv4[INET_ADDRSTRLEN+1]; char ipv6[INET6_ADDRSTRLEN+1]; } tmp; for (i = 0; i < pConnList->oidCount; i++) { imaStatus = SUN_IMA_GetConnProperties(&pConnList->oids[i], &connProps); if (imaStatus != IMA_STATUS_SUCCESS) { continue; } (void) fprintf(stdout, "%sCID: %d\n", prefix, connProps->connectionID); (void) memset(&tmp, 0, sizeof (tmp)); if (connProps->local.ipAddress.ipv4Address == IMA_TRUE) { if (inet_ntop(AF_INET, &connProps->local.ipAddress.ipAddress[0], &tmp.ipv4[0], INET_ADDRSTRLEN)) { (void) fprintf(stdout, "%s %s: %s:%u\n", prefix, gettext("IP address (Local)"), &tmp.ipv4[0], ntohs(connProps->local.portNumber)); } } else { if (inet_ntop(AF_INET6, &connProps->local.ipAddress.ipAddress[0], &tmp.ipv6[0], INET6_ADDRSTRLEN)) { (void) fprintf(stdout, "%s %s: [%s]:%u\n", prefix, gettext("IP address (Local)"), &tmp.ipv6[0], ntohs(connProps->local.portNumber)); } } if (connProps->peer.ipAddress.ipv4Address == IMA_TRUE) { if (inet_ntop(AF_INET, &connProps->peer.ipAddress.ipAddress[0], &tmp.ipv4[0], INET_ADDRSTRLEN)) { (void) fprintf(stdout, "%s %s: %s:%u\n", prefix, gettext("IP address (Peer)"), &tmp.ipv4[0], ntohs(connProps->peer.portNumber)); } } else { if (inet_ntop(AF_INET6, &connProps->peer.ipAddress.ipAddress[0], &tmp.ipv6[0], INET6_ADDRSTRLEN)) { (void) fprintf(stdout, "%s %s: [%s]:%u\n", prefix, gettext("IP address (Peer)"), &tmp.ipv6[0], ntohs(connProps->peer.portNumber)); } } (void) IMA_FreeMemory(connProps); } } /* * Set login parameters on a target or initiator */ static int setLoginParameter(IMA_OID oid, int optval, char *optarg) { IMA_STATUS status = IMA_STATUS_SUCCESS; IMA_UINT uintValue; IMA_BOOL boolValue; SUN_IMA_DIGEST_ALGORITHM digestAlgList[1]; IMA_MIN_MAX_VALUE propMinMax; char *endptr; /* * for clarity, there are two switch statements * The first loads the variable and the second * calls the appropriate API */ switch (optval) { case DATA_SEQ_IN_ORDER: case IMMEDIATE_DATA: case INITIAL_R2T: case DATA_PDU_IN_ORDER: /* implement 'default'? */ if (strcasecmp(optarg, "yes") == 0) { boolValue = IMA_TRUE; } else if (strcasecmp(optarg, "no") == 0) { boolValue = IMA_FALSE; } else { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } break; case DEFAULT_TIME_2_RETAIN: case DEFAULT_TIME_2_WAIT: errno = 0; uintValue = strtoul(optarg, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } if (uintValue > 3600) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 0 and 3600")); return (1); } break; case FIRST_BURST_LENGTH: case MAX_BURST_LENGTH: case MAX_RECV_DATA_SEG_LEN: errno = 0; /* implement 'default'? */ uintValue = strtoul(optarg, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } if (uintValue < 512 || uintValue > 16777215) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 512 and 16777215")); return (1); } break; case MAX_OUTSTANDING_R2T: errno = 0; uintValue = strtoul(optarg, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } if (uintValue < 1 || uintValue > 65535) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 1 and 65535")); return (1); } break; case HEADER_DIGEST: case DATA_DIGEST: if (strcasecmp(optarg, "none") == 0) { digestAlgList[0] = SUN_IMA_DIGEST_NONE; } else if (strcasecmp(optarg, "CRC32") == 0) { digestAlgList[0] = SUN_IMA_DIGEST_CRC32; } else { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } break; case MAX_CONNECTIONS: errno = 0; uintValue = strtoul(optarg, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } if (uintValue < 1 || uintValue > 256) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 1 and 256")); return (1); } break; case ERROR_RECOVERY_LEVEL: errno = 0; uintValue = strtoul(optarg, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } if (uintValue > 2) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 0 and 2")); return (1); } break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optval, gettext("unknown option")); return (1); } switch (optval) { case DATA_PDU_IN_ORDER: status = IMA_SetDataPduInOrder(oid, boolValue); break; case DATA_SEQ_IN_ORDER: status = IMA_SetDataSequenceInOrder(oid, boolValue); break; case DEFAULT_TIME_2_RETAIN: status = IMA_SetDefaultTime2Retain(oid, uintValue); break; case DEFAULT_TIME_2_WAIT: status = IMA_SetDefaultTime2Wait(oid, uintValue); break; case FIRST_BURST_LENGTH: status = IMA_SetFirstBurstLength(oid, uintValue); /* * If this call fails check to see if it's because * the requested value is > than maxBurstLength */ if (!IMA_SUCCESS(status)) { status = IMA_GetMaxBurstLengthProperties(oid, &propMinMax); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (uintValue > propMinMax.currentValue) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("firstBurstLength must " \ "be less than or equal to than " \ "maxBurstLength")); } return (1); } break; case IMMEDIATE_DATA: status = IMA_SetImmediateData(oid, boolValue); break; case INITIAL_R2T: status = IMA_SetInitialR2T(oid, boolValue); break; case MAX_BURST_LENGTH: status = IMA_SetMaxBurstLength(oid, uintValue); /* * If this call fails check to see if it's because * the requested value is < than firstBurstLength */ if (!IMA_SUCCESS(status)) { status = IMA_GetFirstBurstLengthProperties(oid, &propMinMax); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (uintValue < propMinMax.currentValue) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("maxBurstLength must be " \ "greater than or equal to " \ "firstBurstLength")); } return (1); } break; case MAX_OUTSTANDING_R2T: status = IMA_SetMaxOutstandingR2T(oid, uintValue); break; case MAX_RECV_DATA_SEG_LEN: status = IMA_SetMaxRecvDataSegmentLength(oid, uintValue); break; case HEADER_DIGEST: status = SUN_IMA_SetHeaderDigest(oid, 1, &digestAlgList[0]); break; case DATA_DIGEST: status = SUN_IMA_SetDataDigest(oid, 1, &digestAlgList[0]); break; case MAX_CONNECTIONS: status = IMA_SetMaxConnections(oid, uintValue); break; case ERROR_RECOVERY_LEVEL: status = IMA_SetErrorRecoveryLevel(oid, uintValue); break; } if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } return (0); } static void printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *digestAlgorithms, int printOption) { int i; if (printOption == PRINT_CONFIGURED_PARAMS) { for (i = 0; i < digestAlgorithms->defaultAlgorithmCount; i++) { if (i > 0) { (void) fprintf(stdout, "|"); } switch (digestAlgorithms->defaultAlgorithms[i]) { case SUN_IMA_DIGEST_NONE: (void) fprintf(stdout, gettext("NONE")); break; case SUN_IMA_DIGEST_CRC32: (void) fprintf(stdout, gettext("CRC32")); break; default: (void) fprintf(stdout, gettext("Unknown")); break; } } (void) fprintf(stdout, "/"); if (digestAlgorithms->currentValid == IMA_TRUE) { for (i = 0; i < digestAlgorithms->currentAlgorithmCount; i++) { if (i > 0) { (void) fprintf(stdout, "|"); } switch (digestAlgorithms-> currentAlgorithms[i]) { case SUN_IMA_DIGEST_NONE: (void) fprintf(stdout, gettext("NONE")); break; case SUN_IMA_DIGEST_CRC32: (void) fprintf(stdout, gettext("CRC32")); break; default: (void) fprintf(stdout, gettext("Unknown")); break; } } } else { (void) fprintf(stdout, "-"); } (void) fprintf(stdout, "\n"); } else if (printOption == PRINT_NEGOTIATED_PARAMS) { if (digestAlgorithms->negotiatedValid == IMA_TRUE) { for (i = 0; i < digestAlgorithms->negotiatedAlgorithmCount; i++) { if (i > 0) { (void) fprintf(stdout, "|"); } switch (digestAlgorithms-> negotiatedAlgorithms[i]) { case SUN_IMA_DIGEST_NONE: (void) fprintf(stdout, gettext("NONE")); break; case SUN_IMA_DIGEST_CRC32: (void) fprintf(stdout, gettext("CRC32")); break; default: (void) fprintf(stdout, gettext("Unknown")); break; } } } else { (void) fprintf(stdout, "-"); } (void) fprintf(stdout, "\n"); } } static int setLoginParameters(IMA_OID oid, char *optarg) { char keyp[MAXOPTARGLEN]; char valp[MAXOPTARGLEN]; int key; char *nameValueString, *indexp, *delim = NULL; if ((nameValueString = strdup(optarg)) == NULL) { if (errno == ENOMEM) { (void) fprintf(stderr, "%s: %s\n", cmdName, strerror(errno)); } else { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown error")); } return (1); } indexp = nameValueString; /* * Retrieve all login params from option argument * Syntax */ while (indexp) { if (delim = strchr(indexp, ',')) { delim[0] = '\0'; } (void) memset(keyp, 0, sizeof (keyp)); (void) memset(valp, 0, sizeof (valp)); if (sscanf(indexp, gettext("%[^=]=%s"), keyp, valp) != 2) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("Unknown param"), indexp); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if ((key = getLoginParam(keyp)) == -1) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("Unknown key"), keyp); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (setLoginParameter(oid, key, valp) != 0) { if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (delim) { indexp = delim + 1; } else { indexp = NULL; } } if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (0); } /* * Print logical unit information for a specific target */ static void printTargetLuns(IMA_OID_LIST * lunList) { int j; IMA_STATUS status; SUN_IMA_LU_PROPERTIES lunProps; for (j = 0; j < lunList->oidCount; j++) { status = SUN_IMA_GetLuProperties(lunList->oids[j], &lunProps); if (!IMA_SUCCESS(status)) { printLibError(status); return; } (void) fprintf(stdout, "\tLUN: %lld\n", lunProps.imaProps.targetLun); (void) fprintf(stdout, "\t Vendor: %s\n", lunProps.vendorId); (void) fprintf(stdout, "\t Product: %s\n", lunProps.productId); /* * The lun is valid though the os Device Name is not. * Give this information to users for judgement. */ if (lunProps.imaProps.osDeviceNameValid == IMA_TRUE) { (void) fprintf(stdout, gettext("\t OS Device Name: %ws\n"), lunProps.imaProps.osDeviceName); } else { (void) fprintf(stdout, gettext("\t OS Device Name: Not" " Available\n")); } } } /* * Retrieve CHAP secret from input */ static int getSecret(char *secret, int *secretLen, int minSecretLen, int maxSecretLen) { char *chapSecret; /* get password */ chapSecret = getpassphrase(gettext("Enter secret:")); if (chapSecret == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Unable to get secret")); *secret = '\0'; return (1); } if (strlen(chapSecret) > maxSecretLen) { (void) fprintf(stderr, "%s: %s %d\n", cmdName, gettext("secret too long, maximum length is"), maxSecretLen); *secret = '\0'; return (1); } if (strlen(chapSecret) < minSecretLen) { (void) fprintf(stderr, "%s: %s %d\n", cmdName, gettext("secret too short, minimum length is"), minSecretLen); *secret = '\0'; return (1); } (void) strcpy(secret, chapSecret); chapSecret = getpassphrase(gettext("Re-enter secret:")); if (chapSecret == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Unable to get secret")); *secret = '\0'; return (1); } if (strcmp(secret, chapSecret) != 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("secrets do not match, secret not changed")); *secret = '\0'; return (1); } *secretLen = strlen(chapSecret); return (0); } /* * Lists the discovery attributes */ static int listDiscovery(int *funcRet) { IMA_OID initiatorOid; IMA_DISCOVERY_PROPERTIES discProps; int ret; IMA_STATUS status; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } /* Get discovery attributes from IMA */ status = IMA_GetDiscoveryProperties(initiatorOid, &discProps); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } (void) fprintf(stdout, "%s:\n", "Discovery"); (void) fprintf(stdout, "\tStatic: %s\n", discProps.staticDiscoveryEnabled == IMA_TRUE ? \ gettext("enabled") : gettext("disabled")); (void) fprintf(stdout, "\tSend Targets: %s\n", discProps.sendTargetsDiscoveryEnabled == IMA_TRUE ? \ gettext("enabled") : gettext("disabled")); (void) fprintf(stdout, "\tiSNS: %s\n", discProps.iSnsDiscoveryEnabled == IMA_TRUE ? \ gettext("enabled") : gettext("disabled")); return (0); } /* * Print all initiator node attributes */ static int listNode(int *funcRet) { IMA_OID initiatorOid; IMA_NODE_PROPERTIES nodeProps; IMA_STATUS status; int ret; IMA_UINT maxEntries = MAX_AUTH_METHODS; IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS]; SUN_IMA_RADIUS_CONFIG radiusConfig; SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms; IMA_BOOL radiusAccess; int i; assert(funcRet != NULL); ret = getNodeProps(&nodeProps); if (ret != 0) { return (ret); } if (nodeProps.nameValid == IMA_FALSE) { return (INVALID_NODE_NAME); } /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } /* Begin output */ (void) fprintf(stdout, gettext("%s: %ws\n"), gettext("Initiator node name"), nodeProps.name); (void) fprintf(stdout, gettext("Initiator node alias: ")); if (nodeProps.aliasValid == IMA_TRUE) { (void) fprintf(stdout, gettext("%ws\n"), nodeProps.alias); } else { (void) fprintf(stdout, "%s\n", "-"); } (void) fprintf(stdout, "\t%s:\n", gettext("Login Parameters (Default/Configured)")); /* Get Digest configuration */ status = SUN_IMA_GetHeaderDigest(initiatorOid, &digestAlgorithms); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t%s: ", gettext("Header Digest")); printDigestAlgorithm(&digestAlgorithms, PRINT_CONFIGURED_PARAMS); } else { printLibError(status); *funcRet = 1; return (ret); } status = SUN_IMA_GetDataDigest(initiatorOid, &digestAlgorithms); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t%s: ", gettext("Data Digest")); printDigestAlgorithm(&digestAlgorithms, PRINT_CONFIGURED_PARAMS); } else { printLibError(status); *funcRet = 1; return (ret); } /* Get authentication type for this lhba */ status = IMA_GetInUseInitiatorAuthMethods(initiatorOid, &maxEntries, &methodList[0]); (void) fprintf(stdout, "\t%s: ", gettext("Authentication Type")); if (!IMA_SUCCESS(status)) { /* No authentication method set - default is NONE */ (void) fprintf(stdout, gettext("NONE")); } else { for (i = 0; i < maxEntries; i++) { if (i > 0) { (void) fprintf(stdout, "|"); } switch (methodList[i]) { case IMA_AUTHMETHOD_NONE: (void) fprintf(stdout, gettext("NONE")); break; case IMA_AUTHMETHOD_CHAP: (void) fprintf(stdout, gettext("CHAP")); listCHAPName(initiatorOid); break; default: (void) fprintf(stdout, gettext("unknown type")); break; } } } (void) fprintf(stdout, "\n"); /* Get RADIUS configuration */ status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig); (void) fprintf(stdout, "\t%s: ", gettext("RADIUS Server")); if (IMA_SUCCESS(status)) { if (strlen(radiusConfig.hostnameIpAddress) > 0) { (void) fprintf(stdout, "%s:%d", radiusConfig.hostnameIpAddress, radiusConfig.port); } else { (void) fprintf(stdout, "%s", gettext("NONE")); } } else { (void) fprintf(stdout, "%s", gettext("NONE")); } (void) fprintf(stdout, "\n"); status = SUN_IMA_GetInitiatorRadiusAccess(initiatorOid, &radiusAccess); (void) fprintf(stdout, "\t%s: ", gettext("RADIUS Access")); if (IMA_SUCCESS(status)) { if (radiusAccess == IMA_TRUE) { (void) fprintf(stdout, "%s", gettext("enabled")); } else { (void) fprintf(stdout, "%s", gettext("disabled")); } } else if (status == IMA_ERROR_OBJECT_NOT_FOUND) { (void) fprintf(stdout, "%s", gettext("disabled")); } else { (void) fprintf(stdout, "%s", gettext("unknown")); } (void) fprintf(stdout, "\n"); /* print tunable parameters information. */ ret = printTunableParameters(initiatorOid); /* print configured session information. */ ret = printConfiguredSessions(initiatorOid); return (ret); } /* * Print discovery addresses */ static int listDiscoveryAddress(int objectLen, char *objects[], cmdOptions_t *options, int *funcRet) { IMA_OID initiatorOid; SUN_IMA_DISC_ADDR_PROP_LIST *discoveryAddressPropertiesList; IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps; IMA_TARGET_ADDRESS address; SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList; IMA_STATUS status; wchar_t wcInputObject[MAX_ADDRESS_LEN + 1]; int ret; boolean_t object = B_FALSE; int outerLoop; boolean_t found; boolean_t verbose = B_FALSE; int i, j; cmdOptions_t *optionList = options; char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN]; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'v': verbose = B_TRUE; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); return (1); } } /* * If there are multiple objects, execute outer 'for' loop that * many times for each target detail, otherwise, execute it only * once with summaries only */ if (objectLen > 0) { object = B_TRUE; outerLoop = objectLen; } else { object = B_FALSE; outerLoop = 1; } status = SUN_IMA_GetDiscoveryAddressPropertiesList( &discoveryAddressPropertiesList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < outerLoop; i++) { if (object) { /* initialize */ (void) memset(&wcInputObject[0], 0, sizeof (wcInputObject)); (void) memset(&address, 0, sizeof (address)); if (mbstowcs(wcInputObject, objects[i], (MAX_ADDRESS_LEN + 1)) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } /* * if one or more objects were input, * get the values */ if (getTargetAddress(DISCOVERY_ADDRESS, objects[i], &address) != 0) { ret = 1; continue; } } for (found = B_FALSE, j = 0; j < discoveryAddressPropertiesList->discAddrCount; j++) { discAddrProps = discoveryAddressPropertiesList->props[j]; /* * Compare the discovery address with the input if * one was input */ if (object && ipAddressesEqual(discAddrProps.discoveryAddress, address) && (discAddrProps.discoveryAddress. portNumber == address.portNumber)) { found = B_TRUE; } if (!object || found) { /* Print summary - always */ if (discAddrProps.discoveryAddress. hostnameIpAddress.id.ipAddress. ipv4Address) { (void) inet_ntop(AF_INET, discAddrProps. discoveryAddress.hostnameIpAddress. id.ipAddress.ipAddress, sAddr, sizeof (sAddr)); (void) fprintf(stdout, "Discovery Address: %s:%u\n", sAddr, discAddrProps. discoveryAddress.portNumber); } else { (void) inet_ntop(AF_INET6, discAddrProps. discoveryAddress.hostnameIpAddress. id.ipAddress.ipAddress, sAddr, sizeof (sAddr)); (void) fprintf(stdout, "DiscoveryAddress: [%s]:%u\n", sAddr, discAddrProps. discoveryAddress.portNumber); } } if ((!object || found) && verbose) { IMA_NODE_PROPERTIES nodeProps; if (getNodeProps(&nodeProps) != 0) { break; } /* * Issue sendTargets only when an addr is * specified. */ status = SUN_IMA_SendTargets(nodeProps.name, discAddrProps.discoveryAddress, &pList); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s\n", gettext("\tUnable to get "\ "targets.")); *funcRet = 1; continue; } printSendTargets(pList); } if (found) { /* we found the discovery address - break */ break; } } /* * There was an object entered but we didn't * find it. */ if (object && !found) { (void) fprintf(stdout, "%s: %s\n", objects[i], gettext("not found")); } } return (ret); } /* * Print ISNS Server addresses */ static int listISNSServerAddress(int objectLen, char *objects[], cmdOptions_t *options, int *funcRet) { IMA_OID initiatorOid; SUN_IMA_DISC_ADDR_PROP_LIST *discoveryAddressPropertiesList; IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps; IMA_TARGET_ADDRESS address; SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList; IMA_STATUS status; wchar_t wcInputObject[MAX_ADDRESS_LEN + 1]; int ret; boolean_t object = B_FALSE; int outerLoop; boolean_t found; boolean_t showTarget = B_FALSE; int i, j; cmdOptions_t *optionList = options; char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN]; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'v': showTarget = B_TRUE; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); return (1); } } /* * If there are multiple objects, execute outer 'for' loop that * many times for each target detail, otherwise, execute it only * once with summaries only */ if (objectLen > 0) { object = B_TRUE; outerLoop = objectLen; } else { object = B_FALSE; outerLoop = 1; } status = SUN_IMA_GetISNSServerAddressPropertiesList( &discoveryAddressPropertiesList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < outerLoop; i++) { if (object) { /* initialize */ (void) memset(&wcInputObject[0], 0, sizeof (wcInputObject)); (void) memset(&address, 0, sizeof (address)); if (mbstowcs(wcInputObject, objects[i], (MAX_ADDRESS_LEN + 1)) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } /* * if one or more objects were input, * get the values */ if (getTargetAddress(ISNS_SERVER_ADDRESS, objects[i], &address) != 0) { ret = 1; continue; } } for (found = B_FALSE, j = 0; j < discoveryAddressPropertiesList->discAddrCount; j++) { discAddrProps = discoveryAddressPropertiesList->props[j]; /* * Compare the discovery address with the input if * one was input */ if (object && ipAddressesEqual(discAddrProps.discoveryAddress, address) && (discAddrProps.discoveryAddress.portNumber == address.portNumber)) { found = B_TRUE; } if (!object || found) { /* Print summary - always */ if (discAddrProps.discoveryAddress. hostnameIpAddress.id.ipAddress. ipv4Address) { (void) inet_ntop(AF_INET, discAddrProps. discoveryAddress.hostnameIpAddress. id.ipAddress.ipAddress, sAddr, sizeof (sAddr)); } else { (void) inet_ntop(AF_INET6, discAddrProps. discoveryAddress.hostnameIpAddress. id.ipAddress.ipAddress, sAddr, sizeof (sAddr)); } (void) fprintf(stdout, "iSNS Server IP Address: %s:%u\n", sAddr, discAddrProps.discoveryAddress.portNumber); } if ((!object || found) && showTarget) { IMA_NODE_PROPERTIES nodeProps; if (getNodeProps(&nodeProps) != 0) { break; } /* * Issue sendTargets only when an addr is * specified. */ status = SUN_IMA_RetrieveISNSServerTargets( discAddrProps.discoveryAddress, &pList); if (!IMA_SUCCESS(status)) { /* * Check if the discovery mode is * disabled. */ if (status == IMA_ERROR_OBJECT_NOT_FOUND) { (void) fprintf(stderr, "%s\n", gettext("\tiSNS "\ "discovery "\ "mode "\ "disabled. "\ "No targets "\ "to report.")); } else { (void) fprintf(stderr, "%s\n", gettext("\tUnable "\ "to get "\ "targets.")); } continue; } printSendTargets(pList); } if (found) { /* we found the discovery address - break */ break; } } /* * There was an object entered but we didn't * find it. */ if (object && !found) { (void) fprintf(stdout, "%s: %s\n", objects[i], gettext("not found")); } } return (ret); } /* * Print static configuration targets */ static int listStaticConfig(int operandLen, char *operand[], int *funcRet) { IMA_STATUS status; IMA_OID initiatorOid; IMA_OID_LIST *staticTargetList; SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps; wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1]; wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; wchar_t wcCol; char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN]; int ret; boolean_t object = B_FALSE; int outerLoop; boolean_t found; /* B_TRUE if a target name is found */ boolean_t matched; /* B_TRUE if a specific target is found */ boolean_t targetAddressSpecified = B_FALSE; boolean_t tpgtSpecified = B_FALSE; boolean_t isIpv6; int i, j; IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN]; wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } /* * If there are multiple objects, execute outer 'for' loop that * many times for each static config detail, otherwise, execute it only * once with summaries only */ if (operandLen > 0) { object = B_TRUE; outerLoop = operandLen; } else { object = B_FALSE; outerLoop = 1; } /* convert ':' to wide char for wchar string search */ if (mbtowc(&wcCol, ":", sizeof (wcCol)) == -1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); return (1); } status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid, &staticTargetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < outerLoop; i++) { if (object) { if (parseTarget(operand[i], &staticTargetName[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &staticTargetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { ret = 1; continue; } } for (found = B_FALSE, j = 0; j < staticTargetList->oidCount; j++) { boolean_t isIpv6 = B_FALSE; IMA_UINT16 stpgt; IMA_BOOL defaultTpgt; matched = B_FALSE; (void) memset(&staticTargetProps, 0, sizeof (staticTargetProps)); status = SUN_IMA_GetStaticTargetProperties( staticTargetList->oids[j], &staticTargetProps); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(staticTargetList); *funcRet = 1; return (ret); } stpgt = staticTargetProps.staticTarget.targetAddress. tpgt; defaultTpgt = staticTargetProps.staticTarget. targetAddress.defaultTpgt; isIpv6 = !staticTargetProps.staticTarget.targetAddress. imaStruct.hostnameIpAddress.id.ipAddress. ipv4Address; /* * Compare the static target name with the input if * one was input */ if (object && (targetNamesEqual( staticTargetProps.staticTarget.targetName, staticTargetName) == B_TRUE)) { /* targetName found - found = B_TRUE */ found = B_TRUE; if (targetAddressSpecified == B_FALSE) { matched = B_TRUE; } else { if (staticTargetProps.staticTarget. targetAddress.imaStruct. hostnameIpAddress.id.ipAddress. ipv4Address == IMA_TRUE) { (void) inet_ntop(AF_INET, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress.id. ipAddress.ipAddress, tmpStr, sizeof (tmpStr)); } else { (void) inet_ntop(AF_INET6, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress.id. ipAddress.ipAddress, tmpStr, sizeof (tmpStr)); } if (mbstowcs(tmpTargetAddress, tmpStr, SUN_IMA_IP_ADDRESS_PORT_LEN) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } if (wcsncmp(tmpTargetAddress, staticTargetAddress, SUN_IMA_IP_ADDRESS_PORT_LEN) == 0 && staticTargetProps. staticTarget.targetAddress. imaStruct.portNumber == port) { /* * Since an object is * specified, it should also * have a tpgt specified. If * not, that means the object * specified is associated with * the default tpgt. In * either case, a tpgt * comparison should be done * before claiming that a * match is found. */ if ((tpgt == stpgt && tpgtSpecified == B_TRUE && defaultTpgt == IMA_FALSE) || (tpgt == stpgt && tpgtSpecified == B_FALSE && defaultTpgt == IMA_TRUE)) { matched = B_TRUE; } } } } if (!object || matched) { /* print summary - always */ (void) fprintf(stdout, gettext("%s: %ws,"), "Static Configuration Target", staticTargetProps.staticTarget.targetName); if (isIpv6 == B_FALSE) { (void) inet_ntop(AF_INET, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress.id. ipAddress.ipAddress, sAddr, sizeof (sAddr)); (void) fprintf(stdout, "%s:%d", sAddr, staticTargetProps.staticTarget. targetAddress.imaStruct.portNumber); } else { (void) inet_ntop(AF_INET6, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress.id. ipAddress.ipAddress, sAddr, sizeof (sAddr)); (void) fprintf(stdout, "[%s]:%d", sAddr, staticTargetProps.staticTarget. targetAddress.imaStruct.portNumber); } if (staticTargetProps.staticTarget. targetAddress. defaultTpgt == IMA_FALSE) { (void) fprintf(stdout, ",%d\n", staticTargetProps. staticTarget.targetAddress.tpgt); } else { (void) fprintf(stdout, "\n"); } } } /* * No details to display, but if there were: * if (object && found)... * */ /* * There was an object entered but we didn't * find it. */ if (object && !found) { (void) fprintf(stdout, "%s: %s\n", operand[i], gettext("not found")); ret = 1; /* DIY test fix */ } } return (ret); } /* * Print targets */ /*ARGSUSED*/ static int listTarget(int objectLen, char *objects[], cmdOptions_t *options, int *funcRet) { IMA_OID initiatorOid; IMA_OID_LIST *targetList; IMA_OID_LIST *lunList; SUN_IMA_TARGET_PROPERTIES targetProps; IMA_STATUS status; IMA_OID_LIST *pConnList; SUN_IMA_CONN_PROPERTIES *connProps; int ret; wchar_t targetName[MAX_ISCSI_NAME_LEN + 1]; wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; int outerLoop; boolean_t found; boolean_t operandEntered = B_FALSE; boolean_t verbose = B_FALSE; boolean_t scsi_target = B_FALSE; boolean_t targetAddressSpecified = B_FALSE; boolean_t isIpv6 = B_FALSE; int i, j; cmdOptions_t *optionList = options; boolean_t tpgtSpecified = B_FALSE; IMA_UINT16 port = 0; uint16_t tpgt; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'S': scsi_target = B_TRUE; break; case 'v': verbose = B_TRUE; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); return (1); } } /* * If there are multiple objects, execute outer 'for' loop that * many times for each target detail, otherwise, execute it only * once with summaries only */ if (objectLen > 0) { operandEntered = B_TRUE; outerLoop = objectLen; } else { operandEntered = B_FALSE; outerLoop = 1; } status = SUN_IMA_GetSessionOidList(initiatorOid, &targetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < outerLoop; i++) { tpgtSpecified = B_FALSE; if (operandEntered) { if (parseTarget(objects[i], &targetName[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &targetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { ret = 1; continue; } } for (found = B_FALSE, j = 0; j < targetList->oidCount; j++) { status = SUN_IMA_GetTargetProperties( targetList->oids[j], &targetProps); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } /* * Compare the target name with the input if * one was input, if they match, print the target's info * * if no target name was input, continue printing this * target */ if (operandEntered) { if (targetNamesEqual(targetProps.imaProps.name, targetName) == B_TRUE) { if (tpgtSpecified == B_TRUE) { if (targetProps. defaultTpgtConf == IMA_FALSE && targetProps. tpgtConf == tpgt) { found = B_TRUE; } else { /* * tpgt does not match, * move on to next * target */ continue; } } else { found = B_TRUE; } } else { /* * target name does not match, move on * to next target */ continue; } } /* print summary - always */ (void) fprintf(stdout, gettext("%s: %ws\n"), gettext("Target"), targetProps.imaProps.name); /* Alias */ (void) fprintf(stdout, "\t%s: ", gettext("Alias")); if (wslen(targetProps.imaProps.alias) > (size_t)0) { (void) fprintf(stdout, gettext("%ws\n"), targetProps.imaProps.alias); } else { (void) fprintf(stdout, "%s\n", "-"); } if (targetProps.defaultTpgtNego != IMA_TRUE) { (void) fprintf(stdout, "%s%s: %d\n", "\t", gettext("TPGT"), targetProps.tpgtNego); } else if (targetProps.defaultTpgtConf != IMA_TRUE) { (void) fprintf(stdout, "%s%s: %d\n", "\t", gettext("TPGT"), targetProps.tpgtConf); } (void) fprintf(stdout, "%s%s: %02x%02x%02x%02x%02x%02x\n", "\t", gettext("ISID"), targetProps.isid[0], targetProps.isid[1], targetProps.isid[2], targetProps.isid[3], targetProps.isid[4], targetProps.isid[5]); pConnList = NULL; status = SUN_IMA_GetConnOidList( &targetList->oids[j], &pConnList); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } (void) fprintf(stdout, "%s%s: %lu\n", "\t", gettext("Connections"), pConnList->oidCount); if (verbose) { SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms; printConnectionList("\t\t", pConnList); printDiscoveryMethod( "\t\t ", targetProps.imaProps.discoveryMethodFlags); (void) printLoginParameters( "\t\t ", targetList->oids[j], PRINT_NEGOTIATED_PARAMS); /* Get Digest configuration */ status = SUN_IMA_GetConnProperties( &pConnList->oids[0], &connProps); (void) getNegotiatedDigest( ISCSI_LOGIN_PARAM_HEADER_DIGEST, &digestAlgorithms, connProps); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t \t%s: ", gettext("Header Digest")); printDigestAlgorithm( &digestAlgorithms, PRINT_NEGOTIATED_PARAMS); } else { (void) IMA_FreeMemory(pConnList); (void) IMA_FreeMemory(targetList); printLibError(status); *funcRet = 1; return (ret); } (void) getNegotiatedDigest( ISCSI_LOGIN_PARAM_DATA_DIGEST, &digestAlgorithms, connProps); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t \t%s: ", gettext("Data Digest")); printDigestAlgorithm( &digestAlgorithms, PRINT_NEGOTIATED_PARAMS); } else { (void) IMA_FreeMemory(pConnList); (void) IMA_FreeMemory(targetList); printLibError(status); *funcRet = 1; return (ret); } (void) fprintf(stdout, "\n"); } if (scsi_target) { status = SUN_IMA_ReEnumeration( targetList->oids[j]); if (!IMA_SUCCESS(status)) { /* * Proceeds the listing * but indicates the * error in return value */ ret = 1; } status = IMA_GetLuOidList( targetList->oids[j], &lunList); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } if (lunList->oidCount != 0) { printTargetLuns(lunList); } (void) fprintf(stdout, "\n"); (void) IMA_FreeMemory(lunList); } } /* * did we find the object */ if (operandEntered && !found) { (void) fprintf(stdout, "%s: %s\n", objects[i], gettext("not found")); } } (void) IMA_FreeMemory(targetList); return (ret); } /* * Print configured session information */ static int printConfiguredSessions(IMA_OID oid) { IMA_STATUS status; const char *rtn; SUN_IMA_CONFIG_SESSIONS *pConfigSessions; char address[MAX_ADDRESS_LEN]; int out; /* Get configured session information */ status = SUN_IMA_GetConfigSessions(oid, &pConfigSessions); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t%s: ", gettext("Configured Sessions")); if (pConfigSessions->bound == IMA_FALSE) { /* default binding */ (void) fprintf(stdout, "%lu\n", pConfigSessions->out); } else { /* hardcoded binding */ for (out = 0; out < pConfigSessions->out; out++) { if (pConfigSessions->bindings[out]. ipAddress.ipv4Address == IMA_TRUE) { rtn = inet_ntop(AF_INET, pConfigSessions->bindings[out]. ipAddress.ipAddress, address, MAX_ADDRESS_LEN); } else { rtn = inet_ntop(AF_INET6, pConfigSessions->bindings[out]. ipAddress.ipAddress, address, MAX_ADDRESS_LEN); } if (rtn != NULL) { (void) printf("%s ", address); } } (void) fprintf(stdout, "\n"); } } else { free(pConfigSessions); printLibError(status); return (1); } free(pConfigSessions); return (0); } /* * Print target parameters */ static int listTargetParam(int operandLen, char *operand[], cmdOptions_t *options, int *funcRet) { IMA_STATUS status; IMA_OID initiatorOid; IMA_OID_LIST *targetList; IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS]; SUN_IMA_TARGET_PROPERTIES targetProps; IMA_UINT maxEntries = MAX_AUTH_METHODS; IMA_BOOL bidirAuth; int ret; wchar_t targetName[MAX_ISCSI_NAME_LEN + 1]; wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; boolean_t operandEntered = B_FALSE; boolean_t targetAddressSpecified = B_FALSE; boolean_t printObject = B_FALSE; boolean_t tpgtSpecified = B_FALSE; boolean_t isIpv6 = B_FALSE; int outerLoop; boolean_t found; int i, j; SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms; boolean_t verbose = B_FALSE; cmdOptions_t *optionList = options; IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'v': verbose = B_TRUE; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); return (1); } } /* * If there are multiple operands, execute outer 'for' loop that * many times to find each target parameter operand entered, otherwise, * execute it only once for all target parameters returned. */ if (operandLen > 0) { operandEntered = B_TRUE; outerLoop = operandLen; } else { operandEntered = B_FALSE; outerLoop = 1; } /* * Ideally there should be an interface available for obtaining * the list of target-param objects. Since the driver currently * creates a target OID and the associated session structure when * a target-param object is created, we can leverage the target * OID list and use it to manage the target-param objects. When * we stop creating a session for target-param object in the * driver, we will switch to using a different interface to * obtain target-param objects. */ status = IMA_GetTargetOidList(initiatorOid, &targetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < outerLoop; i++) { if (operandEntered) { if (parseTarget(operand[i], &targetName[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &targetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { ret = 1; continue; } } for (j = 0; j < targetList->oidCount; j++) { found = B_FALSE; printObject = B_FALSE; status = SUN_IMA_GetTargetProperties( targetList->oids[j], &targetProps); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } /* * Compare the target name with the input if * one was input */ if (operandEntered && (targetNamesEqual(targetProps.imaProps.name, targetName) == B_TRUE)) { /* * For now, regardless of whether a target * address is specified, we return B_TRUE * because IMA_TARGET_PROPERTIES does not * have a field for specifying address. */ found = B_TRUE; } /* * if no operand was entered OR * an operand was entered and it was * found, we want to print */ if (!operandEntered || found) { printObject = B_TRUE; } if (printObject) { (void) fprintf(stdout, gettext("%s: %ws\n"), gettext("Target"), targetProps.imaProps.name); (void) fprintf(stdout, "\t%s: ", gettext("Alias")); if (wslen(targetProps.imaProps.alias) > (size_t)0) { (void) fprintf(stdout, gettext("%ws\n"), targetProps.imaProps.alias); } else { (void) fprintf(stdout, "%s\n", "-"); } } if (printObject && verbose) { /* Get bidirectional authentication flag */ (void) fprintf(stdout, "\t%s: ", gettext("Bi-directional Authentication")); status = SUN_IMA_GetTargetBidirAuthFlag( targetList->oids[j], &bidirAuth); if (IMA_SUCCESS(status)) { if (bidirAuth == IMA_TRUE) { (void) fprintf(stdout, gettext("enabled")); } else { (void) fprintf(stdout, gettext("disabled")); } } else { (void) fprintf(stdout, gettext("disabled")); } (void) fprintf(stdout, "\n"); /* Get authentication type for this target */ status = SUN_IMA_GetTargetAuthMethods( initiatorOid, targetList->oids[j], &maxEntries, &methodList[0]); (void) fprintf(stdout, "\t%s: ", gettext("Authentication Type")); if (!IMA_SUCCESS(status)) { /* * No authentication method define * NONE by default. */ (void) fprintf(stdout, gettext("NONE")); } else { for (i = 0; i < maxEntries; i++) { if (i > 0) { (void) fprintf(stdout, "|"); } switch (methodList[i]) { case IMA_AUTHMETHOD_NONE: (void) fprintf(stdout, gettext("NONE")); break; case IMA_AUTHMETHOD_CHAP: (void) fprintf(stdout, gettext("CHAP")); listCHAPName( targetList-> oids[j]); break; default: (void) fprintf(stdout, gettext( "unknown " "type")); break; } } } (void) fprintf(stdout, "\n"); if (printLoginParameters("\t", targetList->oids[j], PRINT_CONFIGURED_PARAMS) != 0) { (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } /* Get Digest configuration */ status = SUN_IMA_GetHeaderDigest( targetList->oids[j], &digestAlgorithms); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t%s: ", gettext("Header Digest")); printDigestAlgorithm(&digestAlgorithms, PRINT_CONFIGURED_PARAMS); } else { printLibError(status); *funcRet = 1; return (ret); } status = SUN_IMA_GetDataDigest( targetList->oids[j], &digestAlgorithms); if (IMA_SUCCESS(status)) { (void) fprintf(stdout, "\t\t%s: ", gettext("Data Digest")); printDigestAlgorithm(&digestAlgorithms, PRINT_CONFIGURED_PARAMS); } else { printLibError(status); *funcRet = 1; return (ret); } /* print tunable parameters infomation */ if (printTunableParameters( targetList->oids[j]) != 0) { *funcRet = 1; return (ret); } /* print configured session information */ if (printConfiguredSessions( targetList->oids[j]) != 0) { *funcRet = 1; return (ret); } (void) fprintf(stdout, "\n"); } if (found) { break; } } if (operandEntered && !found) { *funcRet = 1; /* DIY message fix */ (void) fprintf(stdout, "%s: %s\n", operand[i], gettext("not found")); } } (void) IMA_FreeMemory(targetList); return (ret); } /* * Modify discovery attributes */ static int modifyDiscovery(cmdOptions_t *options, int *funcRet) { IMA_OID oid; IMA_STATUS status; IMA_BOOL setDiscovery; IMA_HOST_ID hostId; int ret; cmdOptions_t *optionList = options; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (; optionList->optval; optionList++) { /* check optarg and set bool accordingly */ if (strcasecmp(optionList->optarg, ISCSIADM_ARG_ENABLE) == 0) { setDiscovery = IMA_TRUE; } else if (strcasecmp(optionList->optarg, ISCSIADM_ARG_DISABLE) == 0) { setDiscovery = IMA_FALSE; } else { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("invalid option argument")); return (1); } switch (optionList->optval) { case 's': /* Set static discovery */ status = IMA_SetStaticDiscovery(oid, setDiscovery); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } break; case 't': /* Set send targets discovery */ status = IMA_SetSendTargetsDiscovery(oid, setDiscovery); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } break; case 'i': /* Set iSNS discovery */ (void) memset(&hostId, 0, sizeof (hostId)); status = IMA_SetIsnsDiscovery(oid, setDiscovery, IMA_ISNS_DISCOVERY_METHOD_STATIC, &hostId); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); return (1); } } return (ret); } /* * Set the initiator node's authentication method */ static int modifyNodeAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet) { IMA_INITIATOR_AUTHPARMS authParams; IMA_STATUS status; int ret; int secretLen = MAX_CHAP_SECRET_LEN; int nameLen = 0; IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1]; assert(funcRet != NULL); /* * Start with existing parameters and modify with the desired change * before passing along. We ignore any failures as they probably * are caused by non-existence of auth params for the given node. */ status = IMA_GetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP, &authParams); switch (param) { case AUTH_NAME: if (chapName == NULL) { (void) fprintf(stderr, "CHAP name cannot be NULL.\n"); return (1); } nameLen = strlen(chapName); if (nameLen == 0) { (void) fprintf(stderr, "CHAP name cannot be empty.\n"); return (1); } if (nameLen > ISCSI_MAX_C_USER_LEN) { (void) fprintf(stderr, "CHAP name is too long.\n"); return (1); } (void) memset(&authParams.chapParms.name, 0, sizeof (authParams.chapParms.name)); (void) memcpy(&authParams.chapParms.name, &chapName[0], nameLen); authParams.chapParms.nameLength = nameLen; break; case AUTH_PASSWORD : ret = getSecret((char *)&chapSecret[0], &secretLen, MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN); if (ret != 0) { return (ret); } (void) memset(&authParams.chapParms.challengeSecret, 0, sizeof (authParams.chapParms.challengeSecret)); (void) memcpy(&authParams.chapParms.challengeSecret, &chapSecret[0], secretLen); authParams.chapParms.challengeSecretLength = secretLen; break; default: (void) fprintf(stderr, "Invalid auth parameter %d\n", param); return (1); } status = IMA_SetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP, &authParams); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (ret); } /* * Set the target's authentication method */ static int modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet) { IMA_INITIATOR_AUTHPARMS authParams; IMA_STATUS status; int ret; int secretLen = MAX_CHAP_SECRET_LEN; int nameLen = 0; IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1]; assert(funcRet != NULL); /* * Start with existing parameters and modify with the desired change * before passing along. We ignore any get failures as they probably * are caused by non-existence of auth params for the given target. */ status = SUN_IMA_GetTargetAuthParms(oid, IMA_AUTHMETHOD_CHAP, &authParams); switch (param) { case AUTH_NAME: if (chapName == NULL) { (void) fprintf(stderr, "CHAP name cannot be NULL.\n"); return (1); } nameLen = strlen(chapName); if (nameLen == 0) { (void) fprintf(stderr, "CHAP name cannot be empty.\n"); return (1); } if (nameLen > ISCSI_MAX_C_USER_LEN) { (void) fprintf(stderr, "CHAP name is too long.\n"); return (1); } (void) memset(&authParams.chapParms.name, 0, sizeof (authParams.chapParms.name)); (void) memcpy(&authParams.chapParms.name, &chapName[0], nameLen); authParams.chapParms.nameLength = nameLen; break; case AUTH_PASSWORD : ret = getSecret((char *)&chapSecret[0], &secretLen, 1, MAX_CHAP_SECRET_LEN); if (ret != 0) { return (ret); } (void) memset(&authParams.chapParms.challengeSecret, 0, sizeof (authParams.chapParms.challengeSecret)); (void) memcpy(&authParams.chapParms.challengeSecret, &chapSecret[0], secretLen); authParams.chapParms.challengeSecretLength = secretLen; break; default: (void) fprintf(stderr, "Invalid auth parameter %d\n", param); return (1); } status = SUN_IMA_SetTargetAuthParams(oid, IMA_AUTHMETHOD_CHAP, &authParams); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } static int modifyTargetBidirAuthFlag(IMA_OID targetOid, char *optarg, int *funcRet) { IMA_BOOL boolValue; IMA_STATUS status; assert(funcRet != NULL); if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) { boolValue = IMA_TRUE; } else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) { boolValue = IMA_FALSE; } else { (void) fprintf(stderr, "%s: %s %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } status = SUN_IMA_SetTargetBidirAuthFlag(targetOid, &boolValue); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } static int modifyConfiguredSessions(IMA_OID targetOid, char *optarg) { SUN_IMA_CONFIG_SESSIONS *pConfigSessions; IMA_STATUS status; int sessions; int size; char tmp[1024]; boolean_t isIpv6 = B_FALSE; uint16_t port; char address[MAX_ADDRESS_LEN]; char *commaPos; char *addressPos; int rtn; /* * Strip the first int value from the string. If we sprintf * this back to a string and it matches the original string * then this command is using default binding. If not a * match we have hard coded binding or a usage error. */ sessions = atoi(optarg); (void) sprintf(tmp, "%d", sessions); if (strcmp(optarg, tmp) == 0) { /* default binding */ /* allocate the required pConfigSessions */ size = sizeof (SUN_IMA_CONFIG_SESSIONS); pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size); if (pConfigSessions == NULL) { return (1); } /* setup pConfigSessions */ pConfigSessions->bound = IMA_FALSE; pConfigSessions->in = sessions; pConfigSessions->out = 0; } else { /* hardcoded binding */ /* * First we need to determine how many bindings * are available. This can be done by scanning * for the number of ',' + 1. */ sessions = 1; commaPos = strchr(optarg, ','); while (commaPos != NULL) { sessions++; commaPos = strchr(++commaPos, ','); } /* allocate the required pConfigSessions */ size = sizeof (SUN_IMA_CONFIG_SESSIONS) + ((sessions - 1) * sizeof (IMA_ADDRESS_KEY)); pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size); if (pConfigSessions == NULL) { return (1); } /* setup pConfigSessions */ pConfigSessions->bound = IMA_TRUE; pConfigSessions->in = sessions; pConfigSessions->out = 0; /* Now fill in the binding information. */ sessions = 0; addressPos = optarg; /* * Walk thru possible address strings * stop once all strings are processed. */ while (addressPos != NULL) { /* * Check if there is another address after this * one. If so terminate the current address and * keep a pointer to the next one. */ commaPos = strchr(addressPos, ','); if (commaPos != NULL) { *commaPos++ = 0x00; } /* * Parse current address. If invalid abort * processing of addresses and free memory. */ if (parseAddress(addressPos, 0, address, MAX_ADDRESS_LEN, &port, &isIpv6) != PARSE_ADDR_OK) { free(pConfigSessions); printLibError(IMA_ERROR_INVALID_PARAMETER); return (1); } /* Convert address into binary form */ if (isIpv6 == B_FALSE) { pConfigSessions->bindings[sessions]. ipAddress.ipv4Address = IMA_TRUE; rtn = inet_pton(AF_INET, address, pConfigSessions->bindings[sessions]. ipAddress.ipAddress); } else { pConfigSessions->bindings[sessions].ipAddress. ipv4Address = IMA_FALSE; rtn = inet_pton(AF_INET6, address, pConfigSessions->bindings[sessions]. ipAddress.ipAddress); } if (rtn == 0) { /* inet_pton found address invalid */ free(pConfigSessions); printLibError(IMA_ERROR_INVALID_PARAMETER); return (1); } /* update addressPos to next address */ sessions++; addressPos = commaPos; } } /* issue SUN_IMA request */ status = SUN_IMA_SetConfigSessions(targetOid, pConfigSessions); if (!IMA_SUCCESS(status)) { printLibError(status); free(pConfigSessions); return (1); } free(pConfigSessions); return (0); } static int getAuthMethodValue(char *method, IMA_AUTHMETHOD *value) { if (strcasecmp(method, "chap") == 0) { *value = IMA_AUTHMETHOD_CHAP; return (0); } if (strcasecmp(method, "none") == 0) { *value = IMA_AUTHMETHOD_NONE; return (0); } return (1); } /* * Set the authentication method * Currently only supports CHAP and NONE */ static int modifyNodeAuthMethod(IMA_OID oid, char *optarg, int *funcRet) { IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS]; IMA_UINT methodCount = 0; IMA_STATUS status; IMA_AUTHMETHOD value; char *method; char *commaPos; assert(funcRet != NULL); /* * optarg will be a , delimited set of auth methods, in order * of preference * if any values here are incorrect, return without setting * anything. */ method = optarg; commaPos = strchr(optarg, ','); while (commaPos && methodCount < MAX_AUTH_METHODS) { *commaPos = '\0'; if (getAuthMethodValue(method, &value) != 0) { (void) fprintf(stderr, "%s: a: %s\n", cmdName, gettext("invalid option argument")); return (1); } methodList[methodCount++] = value; commaPos++; method = commaPos; commaPos = strchr(method, ','); } /* Should not find more method specified - if found, error */ if (commaPos) { (void) fprintf(stderr, "%s: -a: %s\n", cmdName, gettext("invalid option argument")); return (1); } if (getAuthMethodValue(method, &value) != 0) { (void) fprintf(stderr, "%s: -a: %s\n", cmdName, gettext("invalid option argument")); return (1); } methodList[methodCount++] = value; status = IMA_SetInitiatorAuthMethods(oid, methodCount, &methodList[0]); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } static int modifyTargetAuthMethod(IMA_OID oid, char *optarg, int *funcRet) { IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS]; IMA_UINT methodCount = 0; IMA_STATUS status; IMA_AUTHMETHOD value; char *method; char *commaPos; assert(funcRet != NULL); /* * optarg will be a , delimited set of auth methods, in order * of preference * if any values here are incorrect, return without setting * anything. */ method = optarg; commaPos = strchr(optarg, ','); while (commaPos && methodCount < MAX_AUTH_METHODS) { *commaPos = '\0'; if (getAuthMethodValue(method, &value) != 0) { (void) fprintf(stderr, "%s: a: %s\n", cmdName, gettext("invalid option argument")); return (1); } methodList[methodCount++] = value; commaPos++; method = commaPos; commaPos = strchr(method, ','); } /* Should not find more method specified - if found, error */ if (commaPos) { (void) fprintf(stderr, "%s: -a: %s\n", cmdName, gettext("invalid option argument")); return (1); } if (getAuthMethodValue(method, &value) != 0) { (void) fprintf(stderr, "%s: -a: %s\n", cmdName, gettext("invalid option argument")); return (1); } methodList[methodCount++] = value; status = SUN_IMA_SetTargetAuthMethods(oid, &methodCount, &methodList[0]); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } /* * Modify the RADIUS configuration of the initiator node. * * Return 0 on success. */ static int modifyNodeRadiusConfig(IMA_OID oid, char *optarg, int *funcRet) { SUN_IMA_RADIUS_CONFIG config; IMA_STATUS status; boolean_t isIpv6 = B_FALSE; uint16_t port; assert(funcRet != NULL); (void) memset(&config, 0, sizeof (SUN_IMA_RADIUS_CONFIG)); if (parseAddress(optarg, DEFAULT_RADIUS_PORT, &config.hostnameIpAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &isIpv6) != PARSE_ADDR_OK) { return (1); } config.port = (IMA_UINT16)port; config.isIpv6 = (isIpv6 == B_TRUE) ? IMA_TRUE : IMA_FALSE; /* Not setting shared secret here. */ config.sharedSecretValid = IMA_FALSE; status = SUN_IMA_SetInitiatorRadiusConfig(oid, &config); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } /* * Modify the RADIUS access flag of the initiator node. * * Return 0 on success. */ static int modifyNodeRadiusAccess(IMA_OID oid, char *optarg, int *funcRet) { IMA_BOOL radiusAccess; IMA_OID initiatorOid; IMA_STATUS status; SUN_IMA_RADIUS_CONFIG radiusConfig; int ret; assert(funcRet != NULL); /* Check if Radius Config is there */ ret = sunInitiatorFind(&initiatorOid); if (ret != 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); return (1); } (void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG)); status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("RADIUS server not configured yet")); *funcRet = 1; return (ret); } /* Check if Radius Shared is set */ if (radiusConfig.sharedSecretValid == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("RADIUS server secret not configured yet")); return (1); } if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) { radiusAccess = IMA_TRUE; } else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) { radiusAccess = IMA_FALSE; } else { (void) fprintf(stderr, "%s: %s %s\n", cmdName, gettext("invalid option argument"), optarg); return (1); } status = SUN_IMA_SetInitiatorRadiusAccess(oid, radiusAccess); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (ret); } /* * Modify the RADIUS shared secret. * * Returns: * zero on success. * > 0 on failure. */ static int modifyNodeRadiusSharedSecret(IMA_OID oid, int *funcRet) { IMA_BYTE radiusSharedSecret[SUN_IMA_MAX_RADIUS_SECRET_LEN + 1]; IMA_OID initiatorOid; IMA_STATUS status; SUN_IMA_RADIUS_CONFIG radiusConfig; int ret; int secretLen = SUN_IMA_MAX_RADIUS_SECRET_LEN; assert(funcRet != NULL); ret = getSecret((char *)&radiusSharedSecret[0], &secretLen, 0, SUN_IMA_MAX_RADIUS_SECRET_LEN); if (ret != 0) { return (1); } ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (1); } /* First obtain existing RADIUS configuration (if any) */ (void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG)); status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("RADIUS server not configured yet")); return (1); } /* Modify the shared secret only */ radiusConfig.sharedSecretLength = secretLen; (void) memcpy(&radiusConfig.sharedSecret, &radiusSharedSecret[0], secretLen); radiusConfig.sharedSecretValid = IMA_TRUE; status = SUN_IMA_SetInitiatorRadiusConfig(oid, &radiusConfig); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } return (0); } /* * Set initiator node attributes. */ static int modifyNode(cmdOptions_t *options, int *funcRet) { IMA_NODE_NAME nodeName; IMA_NODE_ALIAS nodeAlias; IMA_OID oid; IMA_STATUS status; cmdOptions_t *optionList = options; int ret; iSCSINameCheckStatusType nameCheckStatus; IMA_OID sharedNodeOid; int i; int lowerCase; IMA_BOOL iscsiBoot = IMA_FALSE; IMA_BOOL mpxioEnabled = IMA_FALSE; char *mb_name = NULL; int prefixlen = 0; assert(funcRet != NULL); /* Get boot session's info */ (void) SUN_IMA_GetBootIscsi(&iscsiBoot); if (iscsiBoot == IMA_TRUE) { status = SUN_IMA_GetBootMpxio(&mpxioEnabled); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get MPxIO info" " of root disk")); *funcRet = 1; return (1); } } /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret != 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); return (ret); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'N': if (strlen(optionList->optarg) >= MAX_ISCSI_NAME_LEN) { (void) fprintf(stderr, "%s: %s %d\n", cmdName, gettext("name too long, \ maximum length is:"), MAX_ISCSI_NAME_LEN); } /* Take the first operand as node name. */ (void) memset(&nodeName, 0, sizeof (IMA_NODE_NAME)); if (mbstowcs(nodeName, optionList->optarg, IMA_NODE_NAME_LEN) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); return (1); } prefixlen = strlen(ISCSI_IQN_NAME_PREFIX); mb_name = (char *)calloc(1, prefixlen + 1); if (mb_name == NULL) { return (1); } if (wcstombs(mb_name, nodeName, prefixlen) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); (void) IMA_FreeMemory(mb_name); return (1); } if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX, prefixlen) == 0) { /* * For iqn format, we should map * the upper-case characters to * their lower-case equivalents. */ for (i = 0; nodeName[i] != 0; i++) { lowerCase = tolower(nodeName[i]); nodeName[i] = lowerCase; } } (void) IMA_FreeMemory(mb_name); /* Perform string profile checks */ nameCheckStatus = iSCSINameStringProfileCheck(nodeName); iSCSINameCheckStatusDisplay(nameCheckStatus); if (nameCheckStatus != iSCSINameCheckOK) { *funcRet = 1; /* DIY message fix */ return (1); } /* * IMA_GetSharedNodeOid(&sharedNodeOid); * if (!IMA_SUCCESS(status)) { * printLibError(status); * return (INF_ERROR); * } */ if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot, not" " allowed to change" " initiator's name")); return (1); } oid.objectType = IMA_OBJECT_TYPE_NODE; status = IMA_SetNodeName(oid, nodeName); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } break; case 'A': if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot, not" " allowed to change" " initiator's alias")); return (1); } /* Take the first operand as node alias. */ if (strlen(optionList->optarg) >= MAX_ISCSI_NAME_LEN) { (void) fprintf(stderr, "%s: %s %d\n", cmdName, gettext("alias too long, maximum \ length is:"), MAX_ISCSI_NAME_LEN); } (void) memset(&nodeAlias, 0, sizeof (IMA_NODE_ALIAS)); if (mbstowcs(nodeAlias, optionList->optarg, IMA_NODE_ALIAS_LEN) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); return (1); } status = IMA_GetSharedNodeOid(&sharedNodeOid); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } status = IMA_SetNodeAlias(sharedNodeOid, nodeAlias); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } break; case 'a': if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot, not" " allowed to change authentication" " method")); return (1); } if (modifyNodeAuthMethod(oid, options->optarg, funcRet) != 0) { return (1); } break; case 'R': if (modifyNodeRadiusAccess(oid, options->optarg, funcRet) != 0) { return (1); } break; case 'r': if (modifyNodeRadiusConfig(oid, options->optarg, funcRet) != 0) { return (1); } break; case 'P': if (modifyNodeRadiusSharedSecret(oid, funcRet) != 0) { return (1); } break; case 'C': if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot, not" " allowed to change CHAP secret")); return (1); } if (modifyNodeAuthParam(oid, AUTH_PASSWORD, NULL, funcRet) != 0) { return (1); } break; case 'c': if (iscsiBoot == IMA_TRUE) { if (mpxioEnabled == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi" " boot and MPxIO" " is disabled, not allowed" " to change number of" " sessions to be" " configured")); return (1); } } if (modifyConfiguredSessions(oid, optionList->optarg) != 0) { if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot," " fail to set configured" " session")); } return (1); } break; case 'H': if (iscsiBoot == IMA_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot, not" " allowed to change CHAP name")); return (1); } if (modifyNodeAuthParam(oid, AUTH_NAME, optionList->optarg, funcRet) != 0) { return (1); } break; case 'd': if (iscsiBoot == IMA_TRUE) { if (mpxioEnabled == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi" " boot and MPxIO" " is disabled, not" " allowed to" " change initiator's" " login params")); return (1); } } if (setLoginParameter(oid, DATA_DIGEST, optionList->optarg) != 0) { return (1); } break; case 'h': if (iscsiBoot == IMA_TRUE) { if (mpxioEnabled == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi" " boot and MPxIO" " is disabled, not" " allowed to" " change initiator's" " login params")); return (1); } } if (setLoginParameter(oid, HEADER_DIGEST, optionList->optarg) != 0) { return (1); } break; case 'T': if (setTunableParameters(oid, optionList->optarg) != 0) { return (1); } break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); break; } } return (ret); } /* * Modify target parameters */ static int modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet) { IMA_OID oid; IMA_OID targetOid; IMA_STATUS status; IMA_OID_LIST *targetList; SUN_IMA_TARGET_PROPERTIES targetProps; wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1]; wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; int ret; boolean_t found; boolean_t targetAddressSpecified = B_TRUE; boolean_t tpgtSpecified = B_FALSE; boolean_t isIpv6 = B_FALSE; int i; iSCSINameCheckStatusType nameCheckStatus; IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; IMA_NODE_NAME bootTargetName; IMA_INITIATOR_AUTHPARMS bootTargetCHAP; IMA_BOOL iscsiBoot; IMA_BOOL mpxioEnabled; cmdOptions_t *optionList = options; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } if (parseTarget(targetName, &wcInputObject[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &targetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { return (1); } /* Perform string profile checks */ nameCheckStatus = iSCSINameStringProfileCheck(wcInputObject); iSCSINameCheckStatusDisplay(nameCheckStatus); if (nameCheckStatus != iSCSINameCheckOK) { return (1); } status = IMA_GetTargetOidList(oid, &targetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (0); } (void) SUN_IMA_GetBootIscsi(&iscsiBoot); if (iscsiBoot == IMA_TRUE) { status = SUN_IMA_GetBootMpxio(&mpxioEnabled); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get MPxIO info" " of root disk")); *funcRet = 1; return (ret); } status = SUN_IMA_GetBootTargetName(bootTargetName); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get boot target's" " name")); *funcRet = 1; return (ret); } status = SUN_IMA_GetBootTargetAuthParams(&bootTargetCHAP); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get boot target's" " auth param")); *funcRet = 1; return (ret); } } /* find target oid */ for (found = B_FALSE, i = 0; i < targetList->oidCount; i++) { status = SUN_IMA_GetTargetProperties(targetList->oids[i], &targetProps); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } /* * Compare the target name with the input name */ if ((targetNamesEqual(wcInputObject, targetProps.imaProps.name) == B_TRUE)) { /* * For now, regardless of whether a target address * is specified, we return B_TRUE because * IMA_TARGET_PROPERTIES does not have a field for * specifying address. */ found = B_TRUE; targetOid = targetList->oids[i]; if ((targetNamesEqual(bootTargetName, wcInputObject) == B_TRUE) && (iscsiBoot == IMA_TRUE)) { /* * iscsi booting, need changed target param is * booting target, for auth param, not allow * to change, for others dependent on mpxio */ if ((optionList->optval == 'C') || (optionList->optval == 'H') || (optionList->optval == 'B') || (optionList->optval == 'a')) { /* * -C CHAP secret set * -H CHAP name set * -a authentication * -B bi-directional-authentication */ (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot," " not allowed to modify" " authentication parameters" " of boot target")); return (1); } if (mpxioEnabled == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot and" " MPxIO is disabled, not allowed" " to modify boot target's" " parameters")); return (1); } } if (modifyIndividualTargetParam(optionList, targetOid, funcRet) != 0) { return (ret); } /* * Even after finding a matched target, keep going * since there could be multiple target objects * associated with one target name in the system * because of different TPGTs. */ } } /* If the target OID cannot be found create one */ if (!found) { status = SUN_IMA_CreateTargetOid(wcInputObject, &targetOid); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } if (modifyIndividualTargetParam(optionList, targetOid, funcRet) != 0) { return (ret); } } (void) IMA_FreeMemory(targetList); return (ret); } /* * Add one or more addresses */ static int addAddress(int addrType, int operandLen, char *operand[], int *funcRet) { IMA_STATUS status; IMA_OID oid, addressOid; SUN_IMA_TARGET_ADDRESS address; wchar_t wcInputObject[MAX_ADDRESS_LEN + 1]; int ret; int i; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } /* * Format of discovery address operand: * * : */ for (i = 0; i < operandLen; i++) { /* initialize */ (void) memset(&wcInputObject[0], 0, sizeof (wcInputObject)); (void) memset(&address, 0, sizeof (address)); if (mbstowcs(wcInputObject, operand[i], (MAX_ADDRESS_LEN + 1)) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } if (getTargetAddress(addrType, operand[i], &address.imaStruct) != 0) { ret = 1; continue; } if (addrType == DISCOVERY_ADDRESS) { status = IMA_AddDiscoveryAddress(oid, address.imaStruct, &addressOid); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } } else if (addrType == ISNS_SERVER_ADDRESS) { status = SUN_IMA_AddISNSServerAddress(address); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } } } return (ret); } /* * Add one or more static configuration targets */ static int addStaticConfig(int operandLen, char *operand[], int *funcRet) { int i; boolean_t targetAddressSpecified = B_FALSE; boolean_t tpgtSpecified = B_FALSE; boolean_t isIpv6 = B_FALSE; int ret; int addrType; IMA_STATUS status; IMA_OID oid; SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig; IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1]; wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; iSCSINameCheckStatusType nameCheckStatus; char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN]; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&oid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } /* * Format of static config operand: * ,[:port][,tpgt] */ for (i = 0; i < operandLen; i++) { if (parseTarget(operand[i], &staticTargetName[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &staticTargetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { ret = 1; continue; } if (targetAddressSpecified != B_TRUE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("missing target address")); *funcRet = 1; /* DIY message fix */ return (1); } /* Perform string profile checks */ nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName); iSCSINameCheckStatusDisplay(nameCheckStatus); if (nameCheckStatus != iSCSINameCheckOK) { *funcRet = 1; /* DIY message fix */ return (1); } (void) wcsncpy(staticConfig.targetName, staticTargetName, MAX_ISCSI_NAME_LEN + 1); (void) wcstombs(sAddr, staticTargetAddress, sizeof (sAddr)); if (isIpv6 == B_TRUE) { staticConfig.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipv4Address = B_FALSE; addrType = AF_INET6; } else { staticConfig.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipv4Address = B_TRUE; addrType = AF_INET; } if (inet_pton(addrType, sAddr, staticConfig.targetAddress. imaStruct.hostnameIpAddress.id.ipAddress.ipAddress) != 1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("static config conversion error")); ret = 1; continue; } staticConfig.targetAddress.imaStruct.portNumber = port; if (tpgtSpecified == B_TRUE) { staticConfig.targetAddress.defaultTpgt = B_FALSE; staticConfig.targetAddress.tpgt = tpgt; } else { staticConfig.targetAddress.defaultTpgt = B_TRUE; staticConfig.targetAddress.tpgt = 0; } status = SUN_IMA_AddStaticTarget(oid, staticConfig, &oid); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (1); } } if (ret != 0) { *funcRet = 1; } return (ret); } /* * Remove one or more addresses */ static int removeAddress(int addrType, int operandLen, char *operand[], int *funcRet) { IMA_STATUS status; IMA_OID initiatorOid; SUN_IMA_TARGET_ADDRESS address; wchar_t wcInputObject[MAX_ADDRESS_LEN + 1]; int ret; int i; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } for (i = 0; i < operandLen; i++) { /* initialize */ (void) memset(&wcInputObject[0], 0, sizeof (wcInputObject)); (void) memset(&address, 0, sizeof (address)); if (mbstowcs(wcInputObject, operand[i], MAX_ADDRESS_LEN + 1) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } if (getTargetAddress(addrType, operand[i], &address.imaStruct) != 0) { ret = 1; continue; } if (addrType == DISCOVERY_ADDRESS) { status = SUN_IMA_RemoveDiscoveryAddress(address); if (!IMA_SUCCESS(status)) { if (status == IMA_ERROR_OBJECT_NOT_FOUND) { (void) fprintf(stderr, "%s: %s\n", operand[i], gettext("not found")); } else { printLibError(status); } *funcRet = 1; } } else { status = SUN_IMA_RemoveISNSServerAddress(address); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; } } } return (ret); } /* * Remove one or more static configuration targets */ static int removeStaticConfig(int operandLen, char *operand[], int *funcRet) { IMA_STATUS status; IMA_OID initiatorOid; IMA_OID_LIST *staticTargetList; SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps; wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1]; wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; int ret; boolean_t atLeastFoundOne; boolean_t matched; boolean_t targetAddressSpecified = B_TRUE; boolean_t tpgtSpecified = B_FALSE; boolean_t isIpv6 = B_FALSE; int i, j; IMA_UINT16 port = 0; IMA_UINT16 tpgt = 0; iSCSINameCheckStatusType nameCheckStatus; char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN]; wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid, &staticTargetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < operandLen; i++) { if (parseTarget(operand[i], &staticTargetName[0], MAX_ISCSI_NAME_LEN + 1, &targetAddressSpecified, &staticTargetAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN, &port, &tpgtSpecified, &tpgt, &isIpv6) != PARSE_TARGET_OK) { ret = 1; continue; } /* Perform string profile checks */ nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName); iSCSINameCheckStatusDisplay(nameCheckStatus); if (nameCheckStatus != iSCSINameCheckOK) { return (1); } for (atLeastFoundOne = B_FALSE, j = 0; j < staticTargetList->oidCount; j++) { IMA_UINT16 stpgt; matched = B_FALSE; status = SUN_IMA_GetStaticTargetProperties( staticTargetList->oids[j], &staticTargetProps); if (!IMA_SUCCESS(status)) { if (status == IMA_ERROR_OBJECT_NOT_FOUND) { /* * When removing multiple static-config * entries we need to expect get * failures. These failures occur when * we are trying to get entry * information we have just removed. * Ignore the failure and continue. */ ret = 1; continue; } else { printLibError(status); (void) IMA_FreeMemory(staticTargetList); *funcRet = 1; return (ret); } } stpgt = staticTargetProps.staticTarget.targetAddress.tpgt; /* * Compare the static target name with the input if * one was input */ if ((targetNamesEqual( staticTargetProps.staticTarget.targetName, staticTargetName) == B_TRUE)) { if (targetAddressSpecified == B_FALSE) { matched = B_TRUE; } else { if (staticTargetProps.staticTarget. targetAddress.imaStruct. hostnameIpAddress. id.ipAddress.ipv4Address == IMA_TRUE) { (void) inet_ntop(AF_INET, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress. id.ipAddress.ipAddress, tmpStr, sizeof (tmpStr)); } else { (void) inet_ntop(AF_INET6, staticTargetProps. staticTarget.targetAddress. imaStruct.hostnameIpAddress. id.ipAddress.ipAddress, tmpStr, sizeof (tmpStr)); } if (mbstowcs(tmpTargetAddress, tmpStr, SUN_IMA_IP_ADDRESS_PORT_LEN) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext( "conversion error")); ret = 1; continue; } if ((wcsncmp(tmpTargetAddress, staticTargetAddress, SUN_IMA_IP_ADDRESS_PORT_LEN) == 0) && (staticTargetProps. staticTarget.targetAddress. imaStruct.portNumber == port)) { if (tpgtSpecified == B_FALSE) { matched = B_TRUE; } else { if (tpgt == stpgt) { matched = B_TRUE; } } } } if (matched) { status = IMA_RemoveStaticDiscoveryTarget( staticTargetList->oids[j]); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } atLeastFoundOne = B_TRUE; } } } if (!atLeastFoundOne) { (void) fprintf(stderr, gettext("%ws,%ws: %s\n"), staticTargetName, staticTargetAddress, gettext("not found")); } } return (ret); } /* * Remove one or more target params. */ static int removeTargetParam(int operandLen, char *operand[], int *funcRet) { char *commaPos; IMA_STATUS status; IMA_OID initiatorOid; IMA_OID_LIST *targetList; SUN_IMA_TARGET_PROPERTIES targetProps; wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1]; int ret; boolean_t found; int i, j; IMA_NODE_NAME bootTargetName; IMA_BOOL iscsiBoot = IMA_FALSE; IMA_BOOL mpxioEnabled = IMA_FALSE; /* Get boot session's info */ (void) SUN_IMA_GetBootIscsi(&iscsiBoot); if (iscsiBoot == IMA_TRUE) { status = SUN_IMA_GetBootMpxio(&mpxioEnabled); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get MPxIO info of" " root disk")); *funcRet = 1; return (1); } status = SUN_IMA_GetBootTargetName(bootTargetName); if (!IMA_SUCCESS(status)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unable to get boot" " target's name")); *funcRet = 1; return (1); } } assert(funcRet != NULL); /* Find Sun initiator */ ret = sunInitiatorFind(&initiatorOid); if (ret > 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no initiator found")); } if (ret != 0) { return (ret); } status = IMA_GetTargetOidList(initiatorOid, &targetList); if (!IMA_SUCCESS(status)) { printLibError(status); *funcRet = 1; return (ret); } for (i = 0; i < operandLen; i++) { /* initialize */ commaPos = strchr(operand[i], ','); if (commaPos) { /* Ignore IP address. */ *commaPos = '\0'; } (void) memset(&wcInputObject[0], 0, sizeof (wcInputObject)); if (mbstowcs(wcInputObject, operand[i], MAX_ISCSI_NAME_LEN + 1) == (size_t)-1) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("conversion error")); ret = 1; continue; } for (found = B_FALSE, j = 0; j < targetList->oidCount; j++) { status = SUN_IMA_GetTargetProperties( targetList->oids[j], &targetProps); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } /* * Compare the target name with the input if * one was input */ if (targetNamesEqual(targetProps.imaProps.name, wcInputObject) == B_TRUE) { found = B_TRUE; if ((targetNamesEqual(bootTargetName, wcInputObject) == B_TRUE) && (iscsiBoot == IMA_TRUE)) { /* * iscsi booting, need changed target * param is booting target, booting * session mpxio disabled, not * allow to update */ if (mpxioEnabled == IMA_FALSE) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iscsi boot" " with MPxIO disabled," " not allowed to remove" " boot sess param")); ret = 1; continue; } } status = SUN_IMA_RemoveTargetParam( targetList->oids[j]); if (!IMA_SUCCESS(status)) { printLibError(status); (void) IMA_FreeMemory(targetList); *funcRet = 1; return (ret); } } } if (!found) { /* Silently ignoring it? */ (void) fprintf(stderr, gettext("%ws: %s\n"), wcInputObject, gettext("not found")); } } (void) IMA_FreeMemory(targetList); return (ret); } /*ARGSUSED*/ static int addFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, void *addArgs, int *funcRet) { int ret; assert(funcRet != NULL); switch (object) { case DISCOVERY_ADDRESS: case ISNS_SERVER_ADDRESS: ret = addAddress(object, operandLen, operand, funcRet); break; case STATIC_CONFIG: ret = addStaticConfig(operandLen, operand, funcRet); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown object")); ret = 1; break; } return (ret); } /*ARGSUSED*/ static int listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, void *addArgs, int *funcRet) { int ret; assert(funcRet != NULL); switch (object) { case DISCOVERY: ret = listDiscovery(funcRet); break; case DISCOVERY_ADDRESS: ret = listDiscoveryAddress(operandLen, operand, options, funcRet); break; case ISNS_SERVER_ADDRESS: ret = listISNSServerAddress(operandLen, operand, options, funcRet); break; case NODE: ret = listNode(funcRet); break; case STATIC_CONFIG: ret = listStaticConfig(operandLen, operand, funcRet); break; case TARGET: ret = listTarget(operandLen, operand, options, funcRet); break; case TARGET_PARAM: ret = listTargetParam(operandLen, operand, options, funcRet); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown object")); ret = 1; break; } return (ret); } /*ARGSUSED*/ static int modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, void *addArgs, int *funcRet) { int ret, i; assert(funcRet != NULL); switch (object) { case DISCOVERY: ret = modifyDiscovery(options, funcRet); break; case NODE: ret = modifyNode(options, funcRet); break; case TARGET_PARAM: i = 0; while (operand[i]) { ret = modifyTargetParam(options, operand[i], funcRet); if (ret) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("modify failed"), operand[i]); return (ret); } i++; } break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown object")); ret = 1; break; } return (ret); } /*ARGSUSED*/ static int removeFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, void *addArgs, int *funcRet) { int ret; switch (object) { case DISCOVERY_ADDRESS: case ISNS_SERVER_ADDRESS: ret = removeAddress(object, operandLen, operand, funcRet); break; case STATIC_CONFIG: ret = removeStaticConfig(operandLen, operand, funcRet); break; case TARGET_PARAM: ret = removeTargetParam(operandLen, operand, funcRet); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown object")); ret = 1; break; } return (ret); } static void iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status) { switch (status) { case iSCSINameLenZero: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("empty iSCSI name.")); break; case iSCSINameLenExceededMax: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iSCSI name exceeded maximum length.")); break; case iSCSINameUnknownType: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown iSCSI name type.")); break; case iSCSINameInvalidCharacter: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iSCSI name invalid character used")); break; case iSCSINameIqnFormatError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("iqn formatting error.")); break; case iSCSINameIqnDateFormatError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("invalid iqn date." \ " format is: YYYY-MM")); break; case iSCSINameIqnSubdomainFormatError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("missing subdomain after \":\"")); break; case iSCSINameIqnInvalidYearError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("invalid year")); break; case iSCSINameIqnInvalidMonthError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("invalid month")); break; case iSCSINameIqnFQDNError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("missing reversed fully qualified"\ " domain name")); break; case iSCSINameEUIFormatError: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("eui formatting error.")); break; } } /* * A convenient function to modify the target parameters of an individual * target. * * Return 0 if successful * Return 1 if failed */ static int modifyIndividualTargetParam(cmdOptions_t *optionList, IMA_OID targetOid, int *funcRet) { assert(funcRet != NULL); for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'a': if (modifyTargetAuthMethod(targetOid, optionList->optarg, funcRet) != 0) { return (1); } break; case 'B': if (modifyTargetBidirAuthFlag(targetOid, optionList->optarg, funcRet) != 0) { return (1); } break; case 'C': if (modifyTargetAuthParam(targetOid, AUTH_PASSWORD, NULL, funcRet) != 0) { return (1); } break; case 'd': if (setLoginParameter(targetOid, DATA_DIGEST, optionList->optarg) != 0) { return (1); } break; case 'h': if (setLoginParameter(targetOid, HEADER_DIGEST, optionList->optarg) != 0) { return (1); } break; case 'p': /* Login parameter */ if (setLoginParameters(targetOid, optionList->optarg) != 0) { return (1); } break; case 'c': /* Modify configure sessions */ if (modifyConfiguredSessions(targetOid, optionList->optarg) != 0) { return (1); } break; case 'H': if (modifyTargetAuthParam(targetOid, AUTH_NAME, optionList->optarg, funcRet) != 0) { return (1); } break; case 'T': if (setTunableParameters(targetOid, optionList->optarg) != 0) { return (1); } break; } } return (0); } /* * This helper function could go into a utility module for general use. */ static int parseAddress(char *address_port_str, uint16_t defaultPort, char *address_str, size_t address_str_len, uint16_t *port, boolean_t *isIpv6) { char port_str[64]; int tmp_port; char *errchr; if (address_port_str[0] == '[') { /* IPv6 address */ char *close_bracket_pos; close_bracket_pos = strchr(address_port_str, ']'); if (!close_bracket_pos) { syslog(LOG_USER|LOG_DEBUG, "IP address format error: %s\n", address_str); return (PARSE_ADDR_MISSING_CLOSING_BRACKET); } *close_bracket_pos = '\0'; (void) strlcpy(address_str, &address_port_str[1], address_str_len); /* Extract the port number */ close_bracket_pos++; if (*close_bracket_pos == ':') { close_bracket_pos++; if (*close_bracket_pos != '\0') { (void) strlcpy(port_str, close_bracket_pos, 64); tmp_port = strtol(port_str, &errchr, 10); if (tmp_port == 0 && errchr != NULL) { (void) fprintf(stderr, "%s: %s:%s %s\n", cmdName, address_str, close_bracket_pos, gettext("port number invalid")); return (PARSE_ADDR_PORT_OUT_OF_RANGE); } if ((tmp_port > 0) && (tmp_port > USHRT_MAX) || (tmp_port < 0)) { /* Port number out of range */ syslog(LOG_USER|LOG_DEBUG, "Specified port out of range: %d", tmp_port); return (PARSE_ADDR_PORT_OUT_OF_RANGE); } else { *port = (uint16_t)tmp_port; } } else { *port = defaultPort; } } else { *port = defaultPort; } *isIpv6 = B_TRUE; } else { /* IPv4 address */ char *colon_pos; colon_pos = strchr(address_port_str, ':'); if (!colon_pos) { /* No port number specified. */ *port = defaultPort; (void) strlcpy(address_str, address_port_str, address_str_len); } else { *colon_pos = '\0'; (void) strlcpy(address_str, address_port_str, address_str_len); /* Extract the port number */ colon_pos++; if (*colon_pos != '\0') { (void) strlcpy(port_str, colon_pos, 64); tmp_port = strtol(port_str, &errchr, 10); if (tmp_port == 0 && errchr != NULL) { (void) fprintf(stderr, "%s: %s:%s %s\n", cmdName, address_str, colon_pos, gettext("port number invalid")); return (PARSE_ADDR_PORT_OUT_OF_RANGE); } if ((tmp_port > 0) && (tmp_port > USHRT_MAX) || (tmp_port < 0)) { /* Port number out of range */ syslog(LOG_USER|LOG_DEBUG, "Specified port out of range: %d", tmp_port); return (PARSE_ADDR_PORT_OUT_OF_RANGE); } else { *port = (uint16_t)tmp_port; } } else { *port = defaultPort; } } *isIpv6 = B_FALSE; } return (PARSE_ADDR_OK); } /* * This helper function could go into a utility module for general use. */ iSCSINameCheckStatusType iSCSINameStringProfileCheck(wchar_t *name) { char mb_name[MAX_ISCSI_NAME_LEN + 1]; size_t name_len; char *tmp; (void) wcstombs(mb_name, name, MAX_ISCSI_NAME_LEN + 1); if ((name_len = strlen(mb_name)) == 0) { return (iSCSINameLenZero); } else if (name_len > MAX_ISCSI_NAME_LEN) { return (iSCSINameLenExceededMax); } /* * check for invalid characters * According to RFC 3722 iSCSI name must be either a letter, * a digit or one of the following '-' '.' ':' */ for (tmp = mb_name; *tmp != '\0'; tmp++) { if ((isalnum(*tmp) == 0) && (*tmp != '-') && (*tmp != '.') && (*tmp != ':')) { return (iSCSINameInvalidCharacter); } } if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX, strlen(ISCSI_IQN_NAME_PREFIX)) == 0) { /* * If name is of type iqn, check date string and naming * authority. */ char *strp = NULL; /* * Don't allow the string to end with a colon. If there is a * colon then there must be a subdomain provided. */ if (mb_name[strlen(mb_name) - 1] == ':') { return (iSCSINameIqnSubdomainFormatError); } /* Date string */ strp = strtok(&mb_name[3], "."); if (strp) { char tmpYear[5], tmpMonth[3], *endPtr = NULL; int year, month; /* Date string should be in YYYY-MM format */ if (strlen(strp) != strlen("YYYY-MM") || strp[4] != '-') { return (iSCSINameIqnDateFormatError); } /* * Validate year. Only validating that the * year can be converted to a number. No * validation will be done on year's actual * value. */ (void) strncpy(tmpYear, strp, 4); tmpYear[4] = '\0'; errno = 0; year = strtol(tmpYear, &endPtr, 10); if (errno != 0 || *endPtr != '\0' || year < 0 || year > 9999) { return (iSCSINameIqnInvalidYearError); } /* * Validate month is valid. */ (void) strncpy(tmpMonth, &strp[5], 2); tmpMonth[2] = '\0'; errno = 0; month = strtol(tmpMonth, &endPtr, 10); if (errno != 0 || *endPtr != '\0' || month < 1 || month > 12) { return (iSCSINameIqnInvalidMonthError); } /* * A reversed FQDN needs to be provided. We * will only check for a "." followed by more * than two or more characters. The list of domains is * too large and changes too frequently to * add validation for. */ strp = strtok(NULL, "."); if (!strp || strlen(strp) < 2) { return (iSCSINameIqnFQDNError); } /* Name authority string */ strp = strtok(NULL, ":"); if (strp) { return (iSCSINameCheckOK); } else { return (iSCSINameIqnFQDNError); } } else { return (iSCSINameIqnFormatError); } } else if (strncmp(mb_name, ISCSI_EUI_NAME_PREFIX, strlen(ISCSI_EUI_NAME_PREFIX)) == 0) { /* If name is of type EUI, change its length */ if (strlen(mb_name) != ISCSI_EUI_NAME_LEN) { return (iSCSINameEUIFormatError); } for (tmp = mb_name + strlen(ISCSI_EUI_NAME_PREFIX) + 1; *tmp != '\0'; tmp++) { if (isxdigit(*tmp)) { continue; } return (iSCSINameEUIFormatError); } return (iSCSINameCheckOK); } else { return (iSCSINameUnknownType); } } /* * This helper function could go into a utility module for general use. * * Returns: * B_TRUE is the numberStr is an unsigned natural number and within the * specified bound. * B_FALSE otherwise. */ boolean_t isNaturalNumber(char *numberStr, uint32_t upperBound) { int i; int number_str_len; if ((number_str_len = strlen(numberStr)) == 0) { return (B_FALSE); } for (i = 0; i < number_str_len; i++) { if (numberStr[i] < 060 || numberStr[i] > 071) { return (B_FALSE); } } if (atoi(numberStr) > upperBound) { return (B_FALSE); } return (B_TRUE); } /* * This helper function could go into a utility module for general use. * It parses a target string in the format of: * * ,[[:port][,tpgt]] * * and creates wchar strings for target name and target address. It * also populates port and tpgt if found. * * Returns: * PARSE_TARGET_OK if parsing is successful. * PARSE_TARGET_INVALID_TPGT if the specified tpgt is * invalid. * PARSE_TARGET_INVALID_ADDR if the address specified is * invalid. */ int parseTarget(char *targetStr, wchar_t *targetNameStr, size_t targetNameStrLen, boolean_t *targetAddressSpecified, wchar_t *targetAddressStr, size_t targetAddressStrLen, uint16_t *port, boolean_t *tpgtSpecified, uint16_t *tpgt, boolean_t *isIpv6) { char *commaPos; char *commaPos2; char targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN]; int i; int lowerCase; (void) memset(targetNameStr, 0, targetNameStrLen * sizeof (wchar_t)); (void) memset(targetAddressStr, 0, targetAddressStrLen * sizeof (wchar_t)); commaPos = strchr(targetStr, ','); if (commaPos != NULL) { *commaPos = '\0'; commaPos++; *targetAddressSpecified = B_TRUE; /* * Checking of tpgt makes sense only when * the target address/port are specified. */ commaPos2 = strchr(commaPos, ','); if (commaPos2 != NULL) { *commaPos2 = '\0'; commaPos2++; if (isNaturalNumber(commaPos2, ISCSI_MAX_TPGT_VALUE) == B_TRUE) { *tpgt = atoi(commaPos2); *tpgtSpecified = B_TRUE; } else { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("parse target invalid TPGT")); return (PARSE_TARGET_INVALID_TPGT); } } switch (parseAddress(commaPos, ISCSI_LISTEN_PORT, &targetAddress[0], MAX_ADDRESS_LEN + 1, port, isIpv6)) { case PARSE_ADDR_PORT_OUT_OF_RANGE: return (PARSE_TARGET_INVALID_ADDR); case PARSE_ADDR_OK: break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("cannot parse target name")); return (PARSE_TARGET_INVALID_ADDR); } (void) mbstowcs(targetAddressStr, targetAddress, targetAddressStrLen); for (i = 0; targetAddressStr[i] != 0; i++) { lowerCase = tolower(targetAddressStr[i]); targetAddressStr[i] = lowerCase; } } else { *targetAddressSpecified = B_FALSE; *tpgtSpecified = B_FALSE; } (void) mbstowcs(targetNameStr, targetStr, targetNameStrLen); for (i = 0; targetNameStr[i] != 0; i++) { lowerCase = tolower(targetNameStr[i]); targetNameStr[i] = lowerCase; } return (PARSE_TARGET_OK); } /*ARGSUSED*/ static void listCHAPName(IMA_OID oid) { IMA_INITIATOR_AUTHPARMS authParams; IMA_STATUS status; IMA_BYTE chapName [MAX_CHAP_NAME_LEN + 1]; /* Get Chap Name depending upon oid object type */ if (oid.objectType == IMA_OBJECT_TYPE_LHBA) { status = IMA_GetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP, &authParams); } else { status = SUN_IMA_GetTargetAuthParms(oid, IMA_AUTHMETHOD_CHAP, &authParams); } (void) fprintf(stdout, "\n\t\t%s: ", gettext("CHAP Name")); if (IMA_SUCCESS(status)) { /* * Default chap name will be the node name. The default will * be set by the driver. */ if (authParams.chapParms.nameLength != 0) { (void) memset(chapName, 0, sizeof (chapName)); (void) memcpy(chapName, authParams.chapParms.name, authParams.chapParms.nameLength); (void) fprintf(stdout, "%s", chapName); } else { (void) fprintf(stdout, "%s", "-"); } } else { (void) fprintf(stdout, "%s", "-"); } } static boolean_t checkServiceStatus(void) { IMA_STATUS status = IMA_ERROR_UNKNOWN_ERROR; IMA_BOOL enabled = 0; status = SUN_IMA_GetSvcStatus(&enabled); if (status != IMA_STATUS_SUCCESS) { (void) fprintf(stdout, "%s\n%s\n", gettext("Unable to query the service status of" " iSCSI initiator."), gettext("For more information, please refer to" " iscsi(4D).")); return (B_FALSE); } if (enabled == 0) { (void) fprintf(stdout, "%s\n%s\n", gettext("iSCSI Initiator Service is disabled," " try 'svcadm enable network/iscsi/initiator' to" " enable the service."), gettext("For more information, please refer to" " iscsi(4D).")); return (B_FALSE); } return (B_TRUE); } /* * Prints out see manual page. * Called out through atexit(3C) so is always last thing displayed. */ void seeMan(void) { static int sent = 0; if (sent) return; (void) fprintf(stdout, "%s %s(8)\n", gettext("For more information, please see"), cmdName); sent = 1; } /* * main calls a parser that checks syntax of the input command against * various rules tables. * * The parser provides usage feedback based upon same tables by calling * two usage functions, usage and subUsage, handling command and subcommand * usage respectively. * * The parser handles all printing of usage syntactical errors * * When syntax is successfully validated, the parser calls the associated * function using the subcommands table functions. * * Syntax is as follows: * command subcommand [options] resource-type [] * * The return value from the function is placed in funcRet */ int main(int argc, char *argv[]) { synTables_t synTables; char versionString[VERSION_STRING_MAX_LEN]; int ret; int funcRet = 0; void *subcommandArgs = NULL; if (geteuid() != 0) { (void) fprintf(stderr, "%s\n", gettext("permission denied")); return (1); } if (checkServiceStatus() == B_FALSE) { return (1); } /* set global command name */ cmdName = getExecBasename(argv[0]); (void) snprintf(versionString, sizeof (versionString), "%s.%s", VERSION_STRING_MAJOR, VERSION_STRING_MINOR); synTables.versionString = versionString; synTables.longOptionTbl = &longOptions[0]; synTables.subcommandTbl = &subcommands[0]; synTables.objectTbl = &objects[0]; synTables.objectRulesTbl = &objectRules[0]; synTables.optionRulesTbl = &optionRules[0]; /* call the CLI parser */ ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); if (ret == -1) { perror(cmdName); ret = 1; } if (funcRet != 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Unable to complete operation")); ret = 1; } return (ret); } static int setTunableParameters(IMA_OID oid, char *optarg) { char keyp[MAXOPTARGLEN]; char valp[MAXOPTARGLEN]; int key; IMA_STATUS status; IMA_UINT uintValue; ISCSI_TUNABLE_PARAM tunableObj; char *nameValueString, *endptr; if ((nameValueString = strdup(optarg)) == NULL) { if (errno == ENOMEM) { (void) fprintf(stderr, "%s: %s\n", cmdName, strerror(errno)); } else { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown error")); } return (1); } (void) memset(keyp, 0, sizeof (keyp)); (void) memset(valp, 0, sizeof (valp)); if (sscanf(nameValueString, gettext("%[^=]=%s"), keyp, valp) != 2) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("Unknown param"), nameValueString); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if ((key = getTunableParam(keyp)) == -1) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("Unknown key"), keyp); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } switch (key) { case RECV_LOGIN_RSP_TIMEOUT: case CONN_LOGIN_MAX: case POLLING_LOGIN_DELAY: errno = 0; uintValue = strtoul(valp, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("invalid option argument"), optarg); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (uintValue > 3600) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("value must be between 0 and 3600")); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (chkConnLoginMaxPollingLoginDelay(oid, key, uintValue) > 0) { if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (key == RECV_LOGIN_RSP_TIMEOUT) { tunableObj.tunable_objectType = ISCSI_RX_TIMEOUT_VALUE; } else if (key == CONN_LOGIN_MAX) { tunableObj.tunable_objectType = ISCSI_CONN_DEFAULT_LOGIN_MAX; } else if (key == POLLING_LOGIN_DELAY) { tunableObj.tunable_objectType = ISCSI_LOGIN_POLLING_DELAY; } tunableObj.tunable_objectValue = valp; status = SUN_IMA_SetTunableProperties(oid, &tunableObj); break; default: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, gettext("Unsupported key"), keyp); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (!IMA_SUCCESS(status)) { printLibError(status); if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (1); } if (nameValueString) { free(nameValueString); nameValueString = NULL; } return (0); } /* * Print tunable parameters information */ static int printTunableParameters(IMA_OID oid) { ISCSI_TUNABLE_PARAM tunableObj; char value[MAXOPTARGLEN] = "\0"; IMA_STATUS status; tunableObj.tunable_objectValue = value; (void) fprintf(stdout, "\t%s:\n", gettext("Tunable Parameters (Default/Configured)")); tunableObj.tunable_objectType = ISCSI_RX_TIMEOUT_VALUE; status = SUN_IMA_GetTunableProperties(oid, &tunableObj); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (value[0] == '\0') { value[0] = '-'; value[1] = '\0'; } (void) fprintf(stdout, "\t\t%s: ", gettext("Session Login Response Time")); (void) fprintf(stdout, "%s/%s\n", ISCSI_DEFAULT_RX_TIMEOUT_VALUE, tunableObj.tunable_objectValue); value[0] = '\0'; tunableObj.tunable_objectType = ISCSI_CONN_DEFAULT_LOGIN_MAX; status = SUN_IMA_GetTunableProperties(oid, &tunableObj); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (value[0] == '\0') { value[0] = '-'; value[1] = '\0'; } (void) fprintf(stdout, "\t\t%s: ", gettext("Maximum Connection Retry Time")); (void) fprintf(stdout, "%s/%s\n", ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX, tunableObj.tunable_objectValue); value[0] = '\0'; tunableObj.tunable_objectType = ISCSI_LOGIN_POLLING_DELAY; status = SUN_IMA_GetTunableProperties(oid, &tunableObj); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (value[0] == '\0') { value[0] = '-'; value[1] = '\0'; } (void) fprintf(stdout, "\t\t%s: ", gettext("Login Retry Time Interval")); (void) fprintf(stdout, "%s/%s\n", ISCSI_DEFAULT_LOGIN_POLLING_DELAY, tunableObj.tunable_objectValue); return (0); } /* * This is helper function to check conn_login_max and polling_login_delay. */ static int chkConnLoginMaxPollingLoginDelay(IMA_OID oid, int key, int uintValue) { char valuep[MAXOPTARGLEN]; IMA_STATUS status; IMA_UINT getValue; ISCSI_TUNABLE_PARAM getObj; char *endptr; if (key == CONN_LOGIN_MAX) { getObj.tunable_objectType = ISCSI_LOGIN_POLLING_DELAY; } else if (key == POLLING_LOGIN_DELAY) { getObj.tunable_objectType = ISCSI_CONN_DEFAULT_LOGIN_MAX; } else { return (0); } valuep[0] = '\0'; getObj.tunable_objectValue = valuep; status = SUN_IMA_GetTunableProperties(oid, &getObj); if (!IMA_SUCCESS(status)) { printLibError(status); return (1); } if (valuep[0] == '\0') { if (key == CONN_LOGIN_MAX) { (void) strlcpy(valuep, ISCSI_DEFAULT_LOGIN_POLLING_DELAY, strlen(ISCSI_DEFAULT_LOGIN_POLLING_DELAY) +1); } else { (void) strlcpy(valuep, ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX, strlen(ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX) +1); } } errno = 0; getValue = strtoul(valuep, &endptr, 0); if (*endptr != '\0' || errno != 0) { (void) fprintf(stderr, "%s: %s - %s\n", cmdName, gettext("cannot convert tunable string"), valuep); return (1); } if (key == CONN_LOGIN_MAX) { if (uintValue < getValue) { (void) fprintf(stderr, "%s: %s %ld\n", cmdName, gettext("value must larger than"), getValue); return (1); } } else { if (uintValue > getValue) { (void) fprintf(stderr, "%s: %s %ld\n", cmdName, gettext("value must smaller than"), getValue); return (1); } } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iscsiadm.h" #include "sun_ima.h" #define LIBRARY_PROPERTY_SUPPORTED_IMA_VERSION 1 #define LIBRARY_PROPERTY_IMPLEMENTATION_VERSION L"1.0.0" #define LIBRARY_PROPERTY_VENDOR L"Sun Microsystems, Inc." #define DEFAULT_NODE_NAME_FORMAT "iqn.2003-13.com.ima.%s" #define PLUGIN_OWNER 1 #define MAX_CHAP_SECRET_LEN 16 /* LINTED E_STATIC_UNUSED */ static IMA_INT32 number_of_plugins = -1; /* LINTED E_STATIC_UNUSED */ static IMA_NODE_NAME sharedNodeName; /* LINTED E_STATIC_UNUSED */ static IMA_NODE_ALIAS sharedNodeAlias; /* LINTED E_STATIC_UNUSED */ static IMA_PLUGIN_PROPERTIES PluginProperties; /* LINTED E_STATIC_UNUSED */ static IMA_OID pluginOid; static IMA_OID lhbaObjectId; /* LINTED E_STATIC_UNUSED */ static boolean_t pluginInit = B_FALSE; /* Forward declaration */ #define BOOL_PARAM 1 #define MIN_MAX_PARAM 2 #define PARAM_OP_OK 0 #define PARAM_OP_FAILED 1 static int open_driver(int *fd); static IMA_STATUS getISCSINodeParameter(int paramType, IMA_OID *oid, void *pProps, uint32_t paramIndex); static IMA_STATUS setISCSINodeParameter(int paramType, IMA_OID *oid, void *pProps, uint32_t paramIndex); static IMA_STATUS getDigest(IMA_OID oid, int ioctlCmd, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm); static IMA_STATUS setAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount, const IMA_AUTHMETHOD *pMethodList); static IMA_STATUS getAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount, IMA_AUTHMETHOD *pMethodList); IMA_STATUS getNegotiatedDigest(int digestType, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm, SUN_IMA_CONN_PROPERTIES *connProps); /* OK */ #define DISC_ADDR_OK 0 /* Incorrect IP address */ #define DISC_ADDR_INTEGRITY_ERROR 1 /* Error converting text IP address to numeric binary form */ #define DISC_ADDR_IP_CONV_ERROR 2 static int prepare_discovery_entry(SUN_IMA_TARGET_ADDRESS discoveryAddress, entry_t *entry); static int prepare_discovery_entry_IMA(IMA_TARGET_ADDRESS discoveryAddress, entry_t *entry); /* LINTED E_STATIC_UNUSED */ static IMA_STATUS configure_discovery_method(IMA_BOOL enable, iSCSIDiscoveryMethod_t method); static IMA_STATUS get_target_oid_list(uint32_t targetListType, IMA_OID_LIST **ppList); static IMA_STATUS get_target_lun_oid_list(IMA_OID * targetOid, iscsi_lun_list_t **ppLunList); static int get_lun_devlink(di_devlink_t link, void *arg); static IMA_STATUS getConnOidList( IMA_OID *oid, iscsi_conn_list_t **ppConnList); static IMA_STATUS getConnProps( iscsi_if_conn_t *pConn, iscsi_conn_props_t **ppConnProps); /* LINTED E_STATIC_UNUSED */ static void libSwprintf(wchar_t *wcs, const wchar_t *lpszFormat, ...) { va_list args; va_start(args, lpszFormat); (void) vswprintf(wcs, 255, lpszFormat, args); va_end(args); } char * _strlwr(char *s) { char *t = s; while (t != NULL && *t) { if (*t >= 'A' && *t <= 'Z') *t += 32; t++; } return (s); } /* LINTED E_STATIC_UNUSED */ static void GetBuildTime(IMA_DATETIME* pdatetime) { #if defined(BUILD_DATE) if (strptime(BUILD_DATE, "%Y/%m/%d %T %Z", pdatetime) == NULL) { (void) memset(pdatetime, 0, sizeof (IMA_DATETIME)); } #else (void) memset(pdatetime, 0, sizeof (IMA_DATETIME)); #endif } /* * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_GetDiscoveryAddressPropertiesList( SUN_IMA_DISC_ADDR_PROP_LIST **ppList ) { char discovery_addr_str[256]; int fd; int i; int discovery_addr_list_size; int status; int out_cnt; iscsi_addr_list_t *ialp; /* LINTED E_FUNC_SET_NOT_USED */ IMA_IP_ADDRESS *ipAddr; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t)); if (ialp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } ialp->al_vers = ISCSI_INTERFACE_VERSION; ialp->al_in_cnt = ialp->al_out_cnt = 1; /* * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl * We have allocated space for one entry, if more than one * address is going to be returned, we will re-issue the ioctl */ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) { (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ialp->al_out_cnt > 1) { /* * we need to allocate more space, save off the out_cnt * and free ialp */ out_cnt = ialp->al_out_cnt; free(ialp); discovery_addr_list_size = sizeof (iscsi_addr_list_t); discovery_addr_list_size += (sizeof (iscsi_addr_t) * out_cnt - 1); ialp = (iscsi_addr_list_t *)calloc(1, discovery_addr_list_size); if (ialp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } ialp->al_vers = ISCSI_INTERFACE_VERSION; ialp->al_in_cnt = out_cnt; /* * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl again to obtain all * the discovery addresses. */ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) { #define ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d" free(ialp); (void) close(fd); syslog(LOG_USER|LOG_DEBUG, ERROR_STR, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); #undef ERROR_STR } } *ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)calloc(1, sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) + ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES)); if (*ppList == NULL) { free(ialp); (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } (*ppList)->discAddrCount = ialp->al_out_cnt; for (i = 0; i < ialp->al_out_cnt; i++) { if (ialp->al_addrs[i].a_addr.i_insize == sizeof (struct in_addr)) { (*ppList)->props[i].discoveryAddress.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_TRUE; } else if (ialp->al_addrs[i].a_addr.i_insize == sizeof (struct in6_addr)) { (*ppList)->props[i].discoveryAddress.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_FALSE; } else { (void) strlcpy(discovery_addr_str, "unknown", sizeof (discovery_addr_str)); } ipAddr = &(*ppList)->props[i].discoveryAddress. hostnameIpAddress.id.ipAddress; bcopy(&ialp->al_addrs[i].a_addr.i_addr, (*ppList)->props[i].discoveryAddress.hostnameIpAddress.id. ipAddress.ipAddress, sizeof (ipAddr->ipAddress)); (*ppList)->props[i].discoveryAddress.portNumber = ialp->al_addrs[i].a_port; } free(ialp); (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_API IMA_STATUS SUN_IMA_GetStaticTargetProperties( IMA_OID staticTargetOid, SUN_IMA_STATIC_TARGET_PROPERTIES *pProps ) { int fd; int status; iscsi_static_property_t prop; /* LINTED */ IMA_IP_ADDRESS *ipAddr; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&prop, 0, sizeof (iscsi_static_property_t)); prop.p_vers = ISCSI_INTERFACE_VERSION; prop.p_oid = (uint32_t)staticTargetOid.objectSequenceNumber; if (ioctl(fd, ISCSI_STATIC_GET, &prop) != 0) { status = errno; (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_STATIC_GET ioctl failed, errno: %d", status); if (status == ENOENT) { return (IMA_ERROR_OBJECT_NOT_FOUND); } else { return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } (void) close(fd); (void) mbstowcs(pProps->staticTarget.targetName, (char *)prop.p_name, sizeof (pProps->staticTarget.targetName)/sizeof (IMA_WCHAR)); if (prop.p_addr_list.al_addrs[0].a_addr.i_insize == sizeof (struct in_addr)) { /* IPv4 */ pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_TRUE; } else if (prop.p_addr_list.al_addrs[0].a_addr.i_insize == sizeof (struct in6_addr)) { /* IPv6 */ pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_FALSE; } else { /* Should not happen */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_STATIC_GET returned bad address"); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } ipAddr = &pProps->staticTarget.targetAddress.imaStruct. hostnameIpAddress.id.ipAddress; bcopy(&prop.p_addr_list.al_addrs[0].a_addr.i_addr, pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.id. ipAddress.ipAddress, sizeof (ipAddr->ipAddress)); pProps->staticTarget.targetAddress.imaStruct.portNumber = prop.p_addr_list.al_addrs[0].a_port; if (prop.p_addr_list.al_tpgt == (uint32_t)ISCSI_DEFAULT_TPGT) { pProps->staticTarget.targetAddress.defaultTpgt = IMA_TRUE; pProps->staticTarget.targetAddress.tpgt = 0; } else { pProps->staticTarget.targetAddress.defaultTpgt = IMA_FALSE; pProps->staticTarget.targetAddress.tpgt = prop.p_addr_list.al_tpgt; } return (IMA_STATUS_SUCCESS); } /*ARGSUSED*/ IMA_API IMA_STATUS SUN_IMA_AddStaticTarget( IMA_OID lhbaOid, const SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig, IMA_OID *pTargetOid ) { iscsi_target_entry_t target; int fd; int target_in_addr_size; int status; union { struct in_addr u_in4; struct in6_addr u_in6; } target_in; /* * staticConfig.address may come in with port number at its trailer. * Parse it to separate the IP address and port number. * Also translate the hostname to IP address if needed. */ if (staticConfig.targetAddress.imaStruct.hostnameIpAddress.id.ipAddress. ipv4Address == IMA_FALSE) { bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipAddress, &target_in.u_in6, sizeof (target_in.u_in6)); target_in_addr_size = sizeof (struct in6_addr); } else { bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress. id.ipAddress.ipAddress, &target_in.u_in4, sizeof (target_in.u_in4)); target_in_addr_size = sizeof (struct in_addr); } (void) memset(&target, 0, sizeof (iscsi_target_entry_t)); target.te_entry.e_vers = ISCSI_INTERFACE_VERSION; target.te_entry.e_oid = ISCSI_OID_NOTSET; (void) wcstombs((char *)target.te_name, staticConfig.targetName, ISCSI_MAX_NAME_LEN); target.te_entry.e_insize = target_in_addr_size; if (target.te_entry.e_insize == sizeof (struct in_addr)) { target.te_entry.e_u.u_in4.s_addr = target_in.u_in4.s_addr; } else if (target.te_entry.e_insize == sizeof (struct in6_addr)) { bcopy(target_in.u_in6.s6_addr, target.te_entry.e_u.u_in6.s6_addr, sizeof (struct in6_addr)); } else { return (IMA_ERROR_INVALID_PARAMETER); } target.te_entry.e_port = staticConfig.targetAddress.imaStruct.portNumber; if (staticConfig.targetAddress.defaultTpgt == IMA_TRUE) { target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT; } else { target.te_entry.e_tpgt = staticConfig.targetAddress.tpgt; } if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } if (ioctl(fd, ISCSI_STATIC_SET, &target)) { /* * Encountered problem setting the IP address and port for * the target just added. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_STATIC_SET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } pTargetOid->objectType = IMA_OBJECT_TYPE_TARGET; pTargetOid->ownerId = 1; pTargetOid->objectSequenceNumber = target.te_entry.e_oid; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_API IMA_STATUS SUN_IMA_GetTargetProperties( IMA_OID targetId, SUN_IMA_TARGET_PROPERTIES *pProps ) { int fd; int status; iscsi_property_t prop; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&prop, 0, sizeof (iscsi_property_t)); prop.p_vers = ISCSI_INTERFACE_VERSION; prop.p_oid = (uint32_t)targetId.objectSequenceNumber; if (ioctl(fd, ISCSI_TARGET_PROPS_GET, &prop) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) mbstowcs(pProps->imaProps.name, (char *)prop.p_name, IMA_NODE_NAME_LEN); (void) memset(pProps->imaProps.alias, 0, (sizeof (IMA_WCHAR) * SUN_IMA_NODE_ALIAS_LEN)); if (prop.p_alias_len > 0) { (void) mbstowcs(pProps->imaProps.alias, (char *)prop.p_alias, SUN_IMA_NODE_ALIAS_LEN); } /* Initialize the discovery method to unknown method. */ pProps->imaProps.discoveryMethodFlags = IMA_TARGET_DISCOVERY_METHOD_UNKNOWN; if (!((prop.p_discovery & iSCSIDiscoveryMethodStatic) ^ iSCSIDiscoveryMethodStatic)) { pProps->imaProps.discoveryMethodFlags |= IMA_TARGET_DISCOVERY_METHOD_STATIC; } if (!((prop.p_discovery & iSCSIDiscoveryMethodSLP) ^ iSCSIDiscoveryMethodSLP)) { pProps->imaProps.discoveryMethodFlags |= IMA_TARGET_DISCOVERY_METHOD_SLP; } if (!((prop.p_discovery & iSCSIDiscoveryMethodISNS) ^ iSCSIDiscoveryMethodISNS)) { pProps->imaProps.discoveryMethodFlags |= iSCSIDiscoveryMethodISNS; } if (!((prop.p_discovery & iSCSIDiscoveryMethodSendTargets) ^ iSCSIDiscoveryMethodSendTargets)) { pProps->imaProps.discoveryMethodFlags |= iSCSIDiscoveryMethodSendTargets; } if (prop.p_tpgt_conf == ISCSI_DEFAULT_TPGT) { pProps->defaultTpgtConf = IMA_TRUE; pProps->tpgtConf = 0; } else { pProps->defaultTpgtConf = IMA_FALSE; pProps->tpgtConf = prop.p_tpgt_conf; } if (prop.p_tpgt_nego == ISCSI_DEFAULT_TPGT) { pProps->defaultTpgtNego = IMA_TRUE; pProps->tpgtNego = 0; } else { pProps->defaultTpgtNego = IMA_FALSE; pProps->tpgtNego = prop.p_tpgt_nego; } bcopy(prop.p_isid, pProps->isid, ISCSI_ISID_LEN); (void) close(fd); return (IMA_STATUS_SUCCESS); } /* * This function only sets CHAP params since we only support CHAP for now. */ IMA_STATUS SUN_IMA_SetTargetAuthParams( IMA_OID targetOid, IMA_AUTHMETHOD method, const IMA_INITIATOR_AUTHPARMS *pParms ) { int fd; iscsi_chap_props_t chap_p; if (method != IMA_AUTHMETHOD_CHAP) return (IMA_ERROR_INVALID_PARAMETER); if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t)); chap_p.c_vers = ISCSI_INTERFACE_VERSION; chap_p.c_oid = (uint32_t)targetOid.objectSequenceNumber; chap_p.c_user_len = pParms->chapParms.nameLength; (void) memcpy(chap_p.c_user, pParms->chapParms.name, chap_p.c_user_len); chap_p.c_secret_len = pParms->chapParms.challengeSecretLength; (void) memcpy(chap_p.c_secret, pParms->chapParms.challengeSecret, chap_p.c_secret_len); if (ioctl(fd, ISCSI_CHAP_SET, &chap_p) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_CHAP_SET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetTargetAuthMethods( IMA_OID lhbaOid, IMA_OID targetOid, IMA_UINT *pMethodCount, IMA_AUTHMETHOD *pMethodList ) { if (getAuthMethods(targetOid, pMethodCount, pMethodList) != IMA_STATUS_SUCCESS) { return (getAuthMethods(lhbaOid, pMethodCount, pMethodList)); } return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_SetInitiatorRadiusConfig( IMA_OID lhbaOid, SUN_IMA_RADIUS_CONFIG *config ) { int af; int fd; int status; iscsi_radius_props_t radius; union { struct in_addr u_in4; struct in6_addr u_in6; } radius_in; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&radius, 0, sizeof (iscsi_radius_props_t)); radius.r_vers = ISCSI_INTERFACE_VERSION; radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber; /* Get first because other data fields may already exist */ if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) { /* EMPTY */ /* It's fine if other data fields are not there. */ } if (config->isIpv6 == IMA_TRUE) { af = AF_INET6; } else { af = AF_INET; } if (inet_pton(af, config->hostnameIpAddress, &radius_in.u_in4) != 1) { return (IMA_ERROR_INVALID_PARAMETER); } switch (af) { case AF_INET: radius.r_addr.u_in4.s_addr = radius_in.u_in4.s_addr; radius.r_insize = sizeof (struct in_addr); break; case AF_INET6: (void) memcpy(radius.r_addr.u_in6.s6_addr, radius_in.u_in6.s6_addr, 16); radius.r_insize = sizeof (struct in6_addr); break; } radius.r_port = config->port; radius.r_radius_config_valid = B_TRUE; /* Allow resetting the RADIUS shared secret to NULL */ if (config->sharedSecretValid == IMA_TRUE) { radius.r_shared_secret_len = config->sharedSecretLength; (void) memset(&radius.r_shared_secret[0], 0, MAX_RAD_SHARED_SECRET_LEN); (void) memcpy(&radius.r_shared_secret[0], config->sharedSecret, config->sharedSecretLength); } if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_RADIUS_SET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetInitiatorRadiusConfig( IMA_OID lhbaOid, SUN_IMA_RADIUS_CONFIG *config ) { int af; int fd; int status; iscsi_radius_props_t radius; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&radius, 0, sizeof (iscsi_radius_props_t)); radius.r_vers = ISCSI_INTERFACE_VERSION; radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber; if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) { (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memset(config, 0, sizeof (SUN_IMA_RADIUS_CONFIG)); if (radius.r_insize == sizeof (struct in_addr)) { /* IPv4 */ af = AF_INET; } else if (radius.r_insize == sizeof (struct in6_addr)) { /* IPv6 */ af = AF_INET6; } else { /* * It's legitimate that the existing RADIUS record does not * have configuration data. */ config->hostnameIpAddress[0] = '\0'; config->port = 0; (void) close(fd); return (IMA_STATUS_SUCCESS); } (void) inet_ntop(af, (void *)&radius.r_addr.u_in4, config->hostnameIpAddress, 256); config->port = radius.r_port; (void) memcpy(config->sharedSecret, &radius.r_shared_secret[0], radius.r_shared_secret_len); config->sharedSecretLength = radius.r_shared_secret_len; config->sharedSecretValid = B_TRUE; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_SetInitiatorRadiusAccess( IMA_OID lhbaOid, IMA_BOOL radiusAccess ) { int fd; int status; iscsi_radius_props_t radius; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&radius, 0, sizeof (iscsi_radius_props_t)); radius.r_vers = ISCSI_INTERFACE_VERSION; radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber; /* Get first because other data fields may already exist */ if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) { if (radiusAccess == IMA_TRUE) { /* * Cannot enable RADIUS if no RADIUS configuration * can be found. */ syslog(LOG_USER|LOG_DEBUG, "RADIUS config data not found - " "cannot enable RADIUS, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } else { /* EMPTY */ /* Otherwise it's fine to disable RADIUS */ } } if ((radius.r_insize != sizeof (struct in_addr)) && (radius.r_insize != sizeof (struct in6_addr))) { /* * Cannot enable RADIUS if no RADIUS configuration * can be found. */ if (radiusAccess == IMA_TRUE) { syslog(LOG_USER|LOG_DEBUG, "RADIUS config data not found - " "cannot enable RADIUS"); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } radius.r_radius_access = (radiusAccess == IMA_TRUE) ? B_TRUE : B_FALSE; if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_RADIUS_SET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetInitiatorRadiusAccess( IMA_OID lhbaOid, IMA_BOOL *radiusAccess ) { int fd; int status; iscsi_radius_props_t radius; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&radius, 0, sizeof (iscsi_radius_props_t)); radius.r_vers = ISCSI_INTERFACE_VERSION; radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber; if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) { (void) close(fd); if (errno == ENOENT) { return (IMA_ERROR_OBJECT_NOT_FOUND); } else { return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } *radiusAccess = (radius.r_radius_access == B_TRUE) ? IMA_TRUE : IMA_FALSE; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_SendTargets( IMA_NODE_NAME nodeName, IMA_TARGET_ADDRESS address, SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList ) { char *colonPos; char discAddrStr[256]; char nodeNameStr[ISCSI_MAX_NAME_LEN]; int fd; int ctr; int stl_sz; int status; iscsi_sendtgts_list_t *stl_hdr = NULL; IMA_BOOL retry = IMA_TRUE; /* LINTED */ IMA_IP_ADDRESS *ipAddr; #define SENDTGTS_DEFAULT_NUM_TARGETS 10 stl_sz = sizeof (*stl_hdr) + ((SENDTGTS_DEFAULT_NUM_TARGETS - 1) * sizeof (iscsi_sendtgts_entry_t)); stl_hdr = (iscsi_sendtgts_list_t *)calloc(1, stl_sz); if (stl_hdr == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION; stl_hdr->stl_in_cnt = SENDTGTS_DEFAULT_NUM_TARGETS; (void) wcstombs(nodeNameStr, nodeName, ISCSI_MAX_NAME_LEN); colonPos = strchr(discAddrStr, ':'); if (colonPos == NULL) { /* IPv4 */ stl_hdr->stl_entry.e_insize = sizeof (struct in_addr); } else { /* IPv6 */ stl_hdr->stl_entry.e_insize = sizeof (struct in6_addr); } ipAddr = &address.hostnameIpAddress.id.ipAddress; bcopy(address.hostnameIpAddress.id.ipAddress.ipAddress, &stl_hdr->stl_entry.e_u, sizeof (ipAddr->ipAddress)); stl_hdr->stl_entry.e_port = address.portNumber; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } retry_sendtgts: /* * Issue ioctl to obtain the SendTargets list */ if (ioctl(fd, ISCSI_SENDTGTS_GET, stl_hdr) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_SENDTGTS_GET ioctl failed, errno: %d", errno); (void) close(fd); free(stl_hdr); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } /* check if all targets received */ if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) { if (retry == IMA_TRUE) { stl_sz = sizeof (*stl_hdr) + ((stl_hdr->stl_out_cnt - 1) * sizeof (iscsi_sendtgts_entry_t)); stl_hdr = (iscsi_sendtgts_list_t *) realloc(stl_hdr, stl_sz); if (stl_hdr == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } stl_hdr->stl_in_cnt = stl_hdr->stl_out_cnt; retry = IMA_FALSE; goto retry_sendtgts; } else { /* * don't retry after 2 attempts. The target list * shouldn't continue to growing. Justs continue * on and display what was found. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_SENDTGTS_GET overflow: " "failed to obtain all targets"); stl_hdr->stl_out_cnt = stl_hdr->stl_in_cnt; } } (void) close(fd); /* allocate for caller return buffer */ *ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1, sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) + stl_hdr->stl_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY)); if (*ppList == NULL) { free(stl_hdr); return (IMA_ERROR_INSUFFICIENT_MEMORY); } (*ppList)->keyCount = stl_hdr->stl_out_cnt; for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) { (void) mbstowcs((*ppList)->keys[ctr].name, (char *)stl_hdr->stl_list[ctr].ste_name, IMA_NODE_NAME_LEN); (*ppList)->keys[ctr].tpgt = stl_hdr->stl_list[ctr].ste_tpgt; (*ppList)->keys[ctr].address.portNumber = stl_hdr->stl_list[ctr].ste_ipaddr.a_port; if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize == sizeof (struct in_addr)) { (*ppList)->keys[ctr].address.ipAddress.ipv4Address = IMA_TRUE; } else if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize == sizeof (struct in6_addr)) { (*ppList)->keys[ctr].address.ipAddress.ipv4Address = IMA_FALSE; } else { free(stl_hdr); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress, &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr), stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize); } free(stl_hdr); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_SetTargetBidirAuthFlag( IMA_OID targetOid, IMA_BOOL *bidirAuthFlag ) { int fd; int status; iscsi_auth_props_t auth; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&auth, 0, sizeof (iscsi_auth_props_t)); auth.a_vers = ISCSI_INTERFACE_VERSION; auth.a_oid = (uint32_t)targetOid.objectSequenceNumber; /* Get first because other data fields may already exist */ if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) { /* EMPTY */ /* It is fine if there is no other data fields. */ } auth.a_bi_auth = (*bidirAuthFlag == IMA_TRUE) ? B_TRUE : B_FALSE; if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_AUTH_SET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetTargetBidirAuthFlag( IMA_OID targetOid, IMA_BOOL *bidirAuthFlag ) { int fd; int status; iscsi_auth_props_t auth; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&auth, 0, sizeof (iscsi_auth_props_t)); auth.a_vers = ISCSI_INTERFACE_VERSION; auth.a_oid = (uint32_t)targetOid.objectSequenceNumber; if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) { (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } *bidirAuthFlag = (auth.a_bi_auth == B_TRUE) ? IMA_TRUE : IMA_FALSE; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_CreateTargetOid( IMA_NODE_NAME targetName, IMA_OID *targetOid ) { int fd; int status; iscsi_oid_t oid; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&oid, 0, sizeof (iscsi_oid_t)); (void) wcstombs((char *)oid.o_name, targetName, ISCSI_MAX_NAME_LEN); oid.o_tpgt = ISCSI_DEFAULT_TPGT; oid.o_vers = ISCSI_INTERFACE_VERSION; if (ioctl(fd, ISCSI_CREATE_OID, &oid) == -1) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_CREATE_OID ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } targetOid->objectType = IMA_OBJECT_TYPE_TARGET; targetOid->ownerId = 1; targetOid->objectSequenceNumber = oid.o_oid; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_RemoveTargetParam( IMA_OID targetOid ) { entry_t entry; int fd; int status; iscsi_auth_props_t auth_p; iscsi_chap_props_t chap_p; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&entry, 0, sizeof (entry_t)); entry.e_vers = ISCSI_INTERFACE_VERSION; entry.e_oid = (uint32_t)targetOid.objectSequenceNumber; if (ioctl(fd, ISCSI_TARGET_PARAM_CLEAR, &entry)) { /* * It could be that the target exists but the associated * target_param does not, and that is legitimate. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_TARGET_PARAM_CLEAR ioctl failed, errno: %d", errno); } /* Issue ISCSI_CHAP_CLEAR ioctl */ (void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t)); chap_p.c_vers = ISCSI_INTERFACE_VERSION; chap_p.c_oid = (uint32_t)targetOid.objectSequenceNumber; if (ioctl(fd, ISCSI_CHAP_CLEAR, &chap_p) != 0) { /* * It could be that the CHAP of this target has never * been set. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_CHAP_CLEAR ioctl failed, errno: %d", errno); } /* * Issue ISCSI_AUTH_CLEAR ioctl, in which the authentication information * is removed and the target that is not discovered by initiator * is removed from the memory. So this ioctl should be called at last */ (void) memset(&auth_p, 0, sizeof (iscsi_auth_props_t)); auth_p.a_vers = ISCSI_INTERFACE_VERSION; auth_p.a_oid = (uint32_t)targetOid.objectSequenceNumber; if (ioctl(fd, ISCSI_AUTH_CLEAR, &auth_p) != 0) { /* * It could be that the auth data of this target has * never been set. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno); } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_API IMA_STATUS SUN_IMA_SetHeaderDigest( IMA_OID oid, IMA_UINT algorithmCount, const SUN_IMA_DIGEST_ALGORITHM *algorithmList ) { IMA_MIN_MAX_VALUE mv; uint32_t digest_algorithm; /* We only support one preference of digest algorithm. */ if (algorithmCount > 1) { syslog(LOG_USER|LOG_DEBUG, "More than one digest algorithm specified."); return (IMA_ERROR_NOT_SUPPORTED); } switch (algorithmList[0]) { case SUN_IMA_DIGEST_NONE: digest_algorithm = ISCSI_DIGEST_NONE; break; case SUN_IMA_DIGEST_CRC32: digest_algorithm = ISCSI_DIGEST_CRC32C; break; default: digest_algorithm = ISCSI_DIGEST_NONE; break; } mv.currentValue = digest_algorithm; return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv, ISCSI_LOGIN_PARAM_HEADER_DIGEST)); } IMA_API IMA_STATUS SUN_IMA_SetDataDigest( IMA_OID oid, IMA_UINT algorithmCount, const SUN_IMA_DIGEST_ALGORITHM *algorithmList ) { IMA_MIN_MAX_VALUE mv; uint32_t digest_algorithm; /* We only support one preference of digest algorithm. */ if (algorithmCount > 1) { syslog(LOG_USER|LOG_DEBUG, "More than one digest algorithm specified."); return (IMA_ERROR_NOT_SUPPORTED); } switch (algorithmList[0]) { case SUN_IMA_DIGEST_NONE: digest_algorithm = ISCSI_DIGEST_NONE; break; case SUN_IMA_DIGEST_CRC32: digest_algorithm = ISCSI_DIGEST_CRC32C; break; default: digest_algorithm = ISCSI_DIGEST_NONE; break; } mv.currentValue = digest_algorithm; return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv, ISCSI_LOGIN_PARAM_DATA_DIGEST)); } IMA_API IMA_STATUS SUN_IMA_GetHeaderDigest( IMA_OID oid, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm ) { return (getDigest(oid, ISCSI_LOGIN_PARAM_HEADER_DIGEST, algorithm)); } IMA_API IMA_STATUS SUN_IMA_GetDataDigest( IMA_OID oid, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm ) { return (getDigest(oid, ISCSI_LOGIN_PARAM_DATA_DIGEST, algorithm)); } typedef struct walk_devlink { char *path; size_t len; char **linkpp; } walk_devlink_t; IMA_STATUS SUN_IMA_GetLuProperties( IMA_OID luId, SUN_IMA_LU_PROPERTIES *pProps ) { IMA_STATUS status; iscsi_lun_list_t *pLunList; int j; IMA_BOOL lunMatch = IMA_FALSE; int fd; int openStatus; iscsi_lun_props_t lun; di_devlink_handle_t hdl; walk_devlink_t warg; char *minor_path, *devlinkp, lunpath[MAXPATHLEN]; if (luId.objectType != IMA_OBJECT_TYPE_LU) { return (IMA_ERROR_INCORRECT_OBJECT_TYPE); } /* * get list of lun oids for all targets */ status = get_target_lun_oid_list(NULL, &pLunList); if (!IMA_SUCCESS(status)) { return (status); } for (j = 0; j < pLunList->ll_out_cnt; j++) { /* * for each lun, check if match is found */ if (pLunList->ll_luns[j].l_oid == luId.objectSequenceNumber) { /* * match found, break out of lun loop */ lunMatch = IMA_TRUE; break; } } if (lunMatch == IMA_TRUE) { (void) memset(&lun, 0, sizeof (iscsi_lun_props_t)); lun.lp_vers = ISCSI_INTERFACE_VERSION; lun.lp_tgt_oid = pLunList->ll_luns[j].l_tgt_oid; lun.lp_oid = pLunList->ll_luns[j].l_oid; } free(pLunList); if (lunMatch == IMA_FALSE) { return (IMA_ERROR_OBJECT_NOT_FOUND); } /* * get lun properties */ if ((openStatus = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | openStatus); } if (ioctl(fd, ISCSI_LUN_PROPS_GET, &lun)) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_LUN_PROPS_GET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); /* * set property values */ pProps->imaProps.associatedTargetOid.objectType = IMA_OBJECT_TYPE_TARGET; pProps->imaProps.associatedTargetOid.ownerId = 1; pProps->imaProps.associatedTargetOid.objectSequenceNumber = lun.lp_oid; pProps->imaProps.targetLun = (IMA_UINT64)lun.lp_num; (void) strncpy(pProps->vendorId, lun.lp_vid, SUN_IMA_LU_VENDOR_ID_LEN); (void) strncpy(pProps->productId, lun.lp_pid, SUN_IMA_LU_PRODUCT_ID_LEN); /* * lun.lp_status is defined as * LunValid = 0 * LunDoesNotExist = 1 * IMA_LU_PROPS.exposedtoOS is defined as an IMA_BOOL * IMA_TRUE = 1 * IMA_FALSE = 0 */ pProps->imaProps.exposedToOs = !lun.lp_status; if (gmtime_r(&lun.lp_time_online, &pProps->imaProps.timeExposedToOs) == NULL) { (void) memset(&pProps->imaProps.timeExposedToOs, 0, sizeof (pProps->imaProps.timeExposedToOs)); } if (lun.lp_status == LunValid) { if ((strlen(lun.lp_pathname) + strlen("/devices")) > (MAXPATHLEN -1)) { /* * lun.lp_pathname length too long */ pProps->imaProps.osDeviceNameValid = IMA_FALSE; pProps->imaProps.osParallelIdsValid = IMA_FALSE; return (IMA_STATUS_SUCCESS); } if ((strstr(lun.lp_pathname, "st@") != NULL) || (strstr(lun.lp_pathname, "tape@") != NULL)) { (void) strlcat(lun.lp_pathname, ":n", MAXPATHLEN); } else if ((strstr(lun.lp_pathname, "sd@") != NULL) || (strstr(lun.lp_pathname, "ssd@") != NULL) || (strstr(lun.lp_pathname, "disk@") != NULL)) { /* * modify returned pathname to obtain the 2nd slice * of the raw disk */ (void) strlcat(lun.lp_pathname, ":c,raw", MAXPATHLEN); } else if ((strstr(lun.lp_pathname, "ses@") != NULL) || (strstr(lun.lp_pathname, "enclosure@") != NULL)) { (void) strlcat(lun.lp_pathname, ":0", MAXPATHLEN); } (void) snprintf(lunpath, sizeof (lun.lp_pathname), "/devices%s", lun.lp_pathname); if (strchr(lunpath, ':')) { minor_path = lunpath; if (strstr(minor_path, "/devices") != NULL) { minor_path = lunpath + strlen("/devices"); } else { minor_path = lunpath; } warg.path = NULL; } else { minor_path = NULL; warg.len = strlen(lunpath); warg.path = lunpath; } devlinkp = NULL; warg.linkpp = &devlinkp; /* * Pathname returned by driver is the physical device path. * This name needs to be converted to the OS device name. */ if (hdl = di_devlink_init(lun.lp_pathname, DI_MAKE_LINK)) { pProps->imaProps.osDeviceName[0] = L'\0'; (void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK, (void *)&warg, get_lun_devlink); if (devlinkp != NULL) { (void) mbstowcs(pProps->imaProps.osDeviceName, devlinkp, MAXPATHLEN); free(devlinkp); pProps->imaProps.osDeviceNameValid = IMA_TRUE; } else { /* OS device name is asynchronously made */ pProps->imaProps.osDeviceNameValid = IMA_FALSE; } (void) di_devlink_fini(&hdl); } else { pProps->imaProps.osDeviceNameValid = IMA_FALSE; } } else { pProps->imaProps.osDeviceNameValid = IMA_FALSE; } pProps->imaProps.osParallelIdsValid = IMA_FALSE; return (IMA_STATUS_SUCCESS); } static int get_lun_devlink(di_devlink_t link, void *arg) { walk_devlink_t *warg = (walk_devlink_t *)arg; if (warg->path) { char *content = (char *)di_devlink_content(link); char *start = strstr(content, "/devices"); if (start == NULL || strncmp(start, warg->path, warg->len) != 0 || start[warg->len] != ':') return (DI_WALK_CONTINUE); } *(warg->linkpp) = strdup(di_devlink_path(link)); return (DI_WALK_TERMINATE); } /* * SUN_IMA_GetConnectionOidList - * * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_GetConnOidList( IMA_OID *oid, IMA_OID_LIST **ppList ) { IMA_STATUS imaStatus; IMA_OID_LIST *imaOidList; iscsi_conn_list_t *iscsiConnList = NULL; int i; size_t allocLen; if ((lhbaObjectId.objectType == oid->objectType) && (lhbaObjectId.ownerId == oid->ownerId) && (lhbaObjectId.objectSequenceNumber == oid->objectSequenceNumber)) { imaStatus = getConnOidList(NULL, &iscsiConnList); } else { if (oid->objectType == IMA_OBJECT_TYPE_TARGET) { imaStatus = getConnOidList(oid, &iscsiConnList); } else { return (IMA_ERROR_INCORRECT_OBJECT_TYPE); } } if (imaStatus != IMA_STATUS_SUCCESS) { return (imaStatus); } /* * Based on the results a SUN_IMA_CONN_LIST structure is allocated. */ allocLen = iscsiConnList->cl_out_cnt * sizeof (IMA_OID); allocLen += sizeof (IMA_OID_LIST) - sizeof (IMA_OID); imaOidList = (IMA_OID_LIST *)calloc(1, allocLen); if (imaOidList == NULL) { free(iscsiConnList); return (IMA_ERROR_INSUFFICIENT_MEMORY); } /* The data is transfered from iscsiConnList to imaConnList. */ imaOidList->oidCount = iscsiConnList->cl_out_cnt; for (i = 0; i < iscsiConnList->cl_out_cnt; i++) { imaOidList->oids[i].objectType = SUN_IMA_OBJECT_TYPE_CONN; imaOidList->oids[i].ownerId = 1; imaOidList->oids[i].objectSequenceNumber = iscsiConnList->cl_list[i].c_oid; } /* The pointer to the SUN_IMA_CONN_LIST structure is returned. */ *ppList = imaOidList; free(iscsiConnList); return (IMA_STATUS_SUCCESS); } /* * SUN_IMA_GetConnProperties - * * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_GetConnProperties( IMA_OID *connOid, SUN_IMA_CONN_PROPERTIES **pProps ) { iscsi_conn_list_t *pConnList; iscsi_conn_props_t *pConnProps; /* LINTED */ struct sockaddr_in6 *addrIn6; /* LINTED */ struct sockaddr_in *addrIn; SUN_IMA_CONN_PROPERTIES *pImaConnProps; IMA_STATUS imaStatus; int i; /* If there is any error *pProps should be set to NULL */ *pProps = NULL; pImaConnProps = (SUN_IMA_CONN_PROPERTIES *)calloc(1, sizeof (SUN_IMA_CONN_PROPERTIES)); if (pImaConnProps == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } imaStatus = getConnOidList(NULL, &pConnList); if (imaStatus != IMA_STATUS_SUCCESS) { free(pImaConnProps); return (imaStatus); } /* * Walk the list returned to find our connection. */ for (i = 0; i < pConnList->cl_out_cnt; i++) { if (pConnList->cl_list[i].c_oid == (uint32_t)connOid->objectSequenceNumber) { /* This is our connection. */ imaStatus = getConnProps(&pConnList->cl_list[i], &pConnProps); if (imaStatus != IMA_STATUS_SUCCESS) { free(pConnList); free(pImaConnProps); return (imaStatus); } pImaConnProps->connectionID = pConnProps->cp_cid; /* * Local Propeties */ if (pConnProps->cp_local.soa4.sin_family == AF_INET) { pImaConnProps->local.ipAddress.ipv4Address = IMA_TRUE; pImaConnProps->local.portNumber = pConnProps->cp_local.soa4.sin_port; addrIn = &(pConnProps->cp_local.soa4); bcopy(&pConnProps->cp_local.soa4.sin_addr, pImaConnProps->local.ipAddress.ipAddress, sizeof (addrIn->sin_addr)); } else { pImaConnProps->local.ipAddress.ipv4Address = IMA_FALSE; pImaConnProps->local.portNumber = pConnProps->cp_local.soa6.sin6_port; addrIn6 = &(pConnProps->cp_local.soa6); bcopy(&pConnProps->cp_local.soa6.sin6_addr, pImaConnProps->local.ipAddress.ipAddress, sizeof (addrIn6->sin6_addr)); } /* * Peer Propeties */ if (pConnProps->cp_peer.soa4.sin_family == AF_INET) { pImaConnProps->peer.ipAddress.ipv4Address = IMA_TRUE; pImaConnProps->peer.portNumber = pConnProps->cp_peer.soa4.sin_port; addrIn = &(pConnProps->cp_local.soa4); bcopy(&pConnProps->cp_peer.soa4.sin_addr, pImaConnProps->peer.ipAddress.ipAddress, sizeof (addrIn->sin_addr)); } else { pImaConnProps->peer.ipAddress.ipv4Address = IMA_FALSE; pImaConnProps->peer.portNumber = pConnProps->cp_peer.soa6.sin6_port; addrIn6 = &pConnProps->cp_local.soa6; bcopy(&pConnProps->cp_peer.soa6.sin6_addr, pImaConnProps->peer.ipAddress.ipAddress, sizeof (addrIn6->sin6_addr)); } pImaConnProps->valuesValid = pConnProps->cp_params_valid; pImaConnProps->defaultTime2Retain = pConnProps->cp_params.default_time_to_retain; pImaConnProps->defaultTime2Wait = pConnProps->cp_params.default_time_to_wait; pImaConnProps->errorRecoveryLevel = pConnProps->cp_params.error_recovery_level; pImaConnProps->firstBurstLength = pConnProps->cp_params.first_burst_length; pImaConnProps->maxBurstLength = pConnProps->cp_params.max_burst_length; pImaConnProps->maxConnections = pConnProps->cp_params.max_connections; pImaConnProps->maxOutstandingR2T = pConnProps->cp_params.max_outstanding_r2t; pImaConnProps->maxRecvDataSegmentLength = pConnProps->cp_params.max_recv_data_seg_len; pImaConnProps->dataPduInOrder = pConnProps->cp_params.data_pdu_in_order; pImaConnProps->dataSequenceInOrder = pConnProps->cp_params.data_sequence_in_order; pImaConnProps->immediateData = pConnProps->cp_params.immediate_data; pImaConnProps->initialR2T = pConnProps->cp_params.initial_r2t; pImaConnProps->headerDigest = pConnProps->cp_params.header_digest; pImaConnProps->dataDigest = pConnProps->cp_params.data_digest; free(pConnProps); break; } } free(pConnList); *pProps = pImaConnProps; return (IMA_STATUS_SUCCESS); } /* * SUN_IMA_GetConfigSessions - * * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_GetConfigSessions( IMA_OID targetOid, SUN_IMA_CONFIG_SESSIONS **pConfigSessions ) { int fd; int status; iscsi_config_sess_t *ics; int size, idx; /* Allocate and setup initial buffer */ size = sizeof (*ics); ics = (iscsi_config_sess_t *)calloc(1, size); if (ics == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } ics->ics_ver = ISCSI_INTERFACE_VERSION; ics->ics_oid = targetOid.objectSequenceNumber; ics->ics_in = 1; /* Open driver devctl for ioctl */ if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } /* Issue ioctl request */ if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d", errno); (void) close(fd); free(ics); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } /* Check if we need to collect more information */ idx = ics->ics_out; if (idx > 1) { /* Free old buffer and reallocate re-sized buffer */ free(ics); size = ISCSI_SESSION_CONFIG_SIZE(idx); ics = (iscsi_config_sess_t *)calloc(1, size); if (ics == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } ics->ics_ver = ISCSI_INTERFACE_VERSION; ics->ics_oid = targetOid.objectSequenceNumber; ics->ics_in = idx; /* Issue ioctl request */ if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d", errno); (void) close(fd); free(ics); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } (void) close(fd); /* Allocate output buffer */ size = sizeof (SUN_IMA_CONFIG_SESSIONS) + ((ics->ics_out - 1) * sizeof (IMA_ADDRESS_KEY)); *pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size); if ((*pConfigSessions) == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } /* Copy output information */ (*pConfigSessions)->bound = (ics->ics_bound == B_TRUE ? IMA_TRUE : IMA_FALSE); (*pConfigSessions)->in = ics->ics_in; (*pConfigSessions)->out = ics->ics_out; for (idx = 0; idx < ics->ics_in; idx++) { if (ics->ics_bindings[idx].i_insize == sizeof (struct in_addr)) { (*pConfigSessions)->bindings[idx].ipAddress. ipv4Address = IMA_TRUE; bcopy(&ics->ics_bindings[idx].i_addr.in4, (*pConfigSessions)->bindings[idx].ipAddress. ipAddress, sizeof (struct in_addr)); } else { (*pConfigSessions)->bindings[idx].ipAddress. ipv4Address = IMA_FALSE; bcopy(&ics->ics_bindings[idx].i_addr.in6, (*pConfigSessions)->bindings[idx].ipAddress. ipAddress, sizeof (struct in6_addr)); } } free(ics); return (IMA_STATUS_SUCCESS); } /* * SUN_IMA_SetConfigSessions - * * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_SetConfigSessions( IMA_OID targetOid, SUN_IMA_CONFIG_SESSIONS *pConfigSessions ) { int fd; int status; iscsi_config_sess_t *ics; int idx, size; /* verify allowed range of sessions */ if ((pConfigSessions->in < ISCSI_MIN_CONFIG_SESSIONS) || (pConfigSessions->in > ISCSI_MAX_CONFIG_SESSIONS)) { return (IMA_ERROR_INVALID_PARAMETER); } /* allocate record config_sess size */ size = ISCSI_SESSION_CONFIG_SIZE(pConfigSessions->in); ics = (iscsi_config_sess_t *)malloc(size); /* setup config_sess information */ (void) memset(ics, 0, sizeof (iscsi_config_sess_t)); ics->ics_ver = ISCSI_INTERFACE_VERSION; ics->ics_oid = targetOid.objectSequenceNumber; ics->ics_bound = (pConfigSessions->bound == IMA_TRUE ? B_TRUE : B_FALSE); ics->ics_in = pConfigSessions->in; for (idx = 0; idx < ics->ics_in; idx++) { if (pConfigSessions->bindings[idx].ipAddress. ipv4Address == IMA_TRUE) { ics->ics_bindings[idx].i_insize = sizeof (struct in_addr); bcopy(pConfigSessions->bindings[idx]. ipAddress.ipAddress, &ics->ics_bindings[idx].i_addr.in4, sizeof (struct in_addr)); } else { ics->ics_bindings[idx].i_insize = sizeof (struct in6_addr); bcopy(pConfigSessions->bindings[idx]. ipAddress.ipAddress, &ics->ics_bindings[idx].i_addr.in6, sizeof (struct in6_addr)); } } /* open driver */ if ((status = open_driver(&fd))) { free(ics); return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } /* issue ioctl request */ if (ioctl(fd, ISCSI_SET_CONFIG_SESSIONS, ics) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_SET_CONFIG_SESSIONS ioctl failed, errno: %d", errno); (void) close(fd); free(ics); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); free(ics); return (IMA_STATUS_SUCCESS); } /* A helper function to obtain iSCSI node parameters. */ static IMA_STATUS getISCSINodeParameter( int paramType, IMA_OID *oid, void *pProps, uint32_t paramIndex ) { int fd; int status; iscsi_param_get_t pg; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&pg, 0, sizeof (iscsi_param_get_t)); pg.g_vers = ISCSI_INTERFACE_VERSION; pg.g_oid = (uint32_t)oid->objectSequenceNumber; pg.g_param = paramIndex; pg.g_param_type = ISCSI_SESS_PARAM; if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_PARAM_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } switch (paramType) { IMA_BOOL_VALUE *bp; IMA_MIN_MAX_VALUE *mp; case MIN_MAX_PARAM: mp = (IMA_MIN_MAX_VALUE *)pProps; mp->currentValueValid = (pg.g_value.v_valid == B_TRUE) ? IMA_TRUE : IMA_FALSE; mp->currentValue = pg.g_value.v_integer.i_current; mp->defaultValue = pg.g_value.v_integer.i_default; mp->minimumValue = pg.g_value.v_integer.i_min; mp->maximumValue = pg.g_value.v_integer.i_max; mp->incrementValue = pg.g_value.v_integer.i_incr; break; case BOOL_PARAM: bp = (IMA_BOOL_VALUE *)pProps; bp->currentValueValid = (pg.g_value.v_valid == B_TRUE) ? IMA_TRUE : IMA_FALSE; bp->currentValue = pg.g_value.v_bool.b_current; bp->defaultValue = pg.g_value.v_bool.b_default; break; default: break; } /* Issue ISCSI_PARAM_GET ioctl again to obtain connection parameters. */ pg.g_param_type = ISCSI_CONN_PARAM; if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_PARAM_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } /* A helper function to set iSCSI node parameters. */ static IMA_STATUS setISCSINodeParameter( int paramType, IMA_OID *oid, void *pProp, uint32_t paramIndex ) { int fd; int status; iscsi_param_set_t ps; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&ps, 0, sizeof (iscsi_param_set_t)); ps.s_vers = ISCSI_INTERFACE_VERSION; ps.s_oid = (uint32_t)oid->objectSequenceNumber; ps.s_param = paramIndex; switch (paramType) { IMA_BOOL_VALUE *bp; IMA_MIN_MAX_VALUE *mp; case MIN_MAX_PARAM: mp = (IMA_MIN_MAX_VALUE *)pProp; ps.s_value.v_integer = mp->currentValue; break; case BOOL_PARAM: bp = (IMA_BOOL_VALUE *)pProp; ps.s_value.v_bool = (bp->currentValue == IMA_TRUE) ? B_TRUE : B_FALSE; break; default: break; } if (ioctl(fd, ISCSI_PARAM_SET, &ps)) { (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_PARAM_SET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } static int prepare_discovery_entry( SUN_IMA_TARGET_ADDRESS discoveryAddress, entry_t *entry ) { return (prepare_discovery_entry_IMA(discoveryAddress.imaStruct, entry)); } static int prepare_discovery_entry_IMA( IMA_TARGET_ADDRESS discoveryAddress, entry_t *entry ) { (void) memset(entry, 0, sizeof (entry_t)); entry->e_vers = ISCSI_INTERFACE_VERSION; entry->e_oid = ISCSI_OID_NOTSET; if (discoveryAddress.hostnameIpAddress.id.ipAddress. ipv4Address == IMA_FALSE) { bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress. ipAddress, entry->e_u.u_in6.s6_addr, sizeof (entry->e_u.u_in6.s6_addr)); entry->e_insize = sizeof (struct in6_addr); } else { bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress. ipAddress, &entry->e_u.u_in4.s_addr, sizeof (entry->e_u.u_in4.s_addr)); entry->e_insize = sizeof (struct in_addr); } entry->e_port = discoveryAddress.portNumber; entry->e_tpgt = 0; return (DISC_ADDR_OK); } static IMA_STATUS configure_discovery_method( IMA_BOOL enable, iSCSIDiscoveryMethod_t method ) { int fd, status; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } if (enable == IMA_FALSE) { if (ioctl(fd, ISCSI_DISCOVERY_CLEAR, &method)) { status = errno; (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_CLEAR ioctl failed, errno: %d", status); if (status == EBUSY) { return (IMA_ERROR_LU_IN_USE); } else { return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } (void) close(fd); return (IMA_STATUS_SUCCESS); } else { /* Set the discovery method */ if (ioctl(fd, ISCSI_DISCOVERY_SET, &method)) { status = errno; (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_SET ioctl failed, errno: %d", status); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } } /* LINTED E_STATIC_UNUSED */ static IMA_BOOL authMethodMatch( IMA_AUTHMETHOD matchingMethod, IMA_AUTHMETHOD *methodList, IMA_UINT maxEntries ) { IMA_UINT i; for (i = 0; i < maxEntries; i++) { if (methodList[i] == matchingMethod) { return (IMA_TRUE); } } return (IMA_FALSE); } static IMA_STATUS get_target_oid_list( uint32_t targetListType, IMA_OID_LIST **ppList) { int fd; int i; int target_list_size; int status; int out_cnt; iscsi_target_list_t *idlp; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } idlp = (iscsi_target_list_t *)calloc(1, sizeof (iscsi_target_list_t)); if (idlp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } idlp->tl_vers = ISCSI_INTERFACE_VERSION; idlp->tl_in_cnt = idlp->tl_out_cnt = 1; idlp->tl_tgt_list_type = targetListType; /* * Issue ioctl. Space has been allocted for one entry. * If more than one entry should be returned, we will re-issue the * entry with the right amount of space allocted */ if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) { (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d", targetListType, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (idlp->tl_out_cnt > 1) { out_cnt = idlp->tl_out_cnt; free(idlp); target_list_size = sizeof (iscsi_target_list_t); target_list_size += (sizeof (uint32_t) * out_cnt - 1); idlp = (iscsi_target_list_t *)calloc(1, target_list_size); if (idlp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } idlp->tl_vers = ISCSI_INTERFACE_VERSION; idlp->tl_in_cnt = out_cnt; idlp->tl_tgt_list_type = targetListType; /* Issue the same ioctl again to obtain all the OIDs. */ if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) { #define ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d" free(idlp); (void) close(fd); syslog(LOG_USER|LOG_DEBUG, ERROR_STR, targetListType, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); #undef ERROR_STR } } *ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) + idlp->tl_out_cnt * sizeof (IMA_OID)); (*ppList)->oidCount = idlp->tl_out_cnt; for (i = 0; i < idlp->tl_out_cnt; i++) { (*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET; (*ppList)->oids[i].ownerId = 1; (*ppList)->oids[i].objectSequenceNumber = idlp->tl_oid_list[i]; } free(idlp); (void) close(fd); return (IMA_STATUS_SUCCESS); } static IMA_STATUS get_target_lun_oid_list( IMA_OID * targetOid, iscsi_lun_list_t **ppLunList) { int fd; iscsi_lun_list_t *illp, *illp_saved; int lun_list_size; int status; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } illp = (iscsi_lun_list_t *)calloc(1, sizeof (iscsi_lun_list_t)); if (illp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } illp->ll_vers = ISCSI_INTERFACE_VERSION; if (targetOid == NULL) { /* get lun oid list for all targets */ illp->ll_all_tgts = B_TRUE; } else { /* get lun oid list for single target */ illp->ll_all_tgts = B_FALSE; illp->ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber; } illp->ll_in_cnt = illp->ll_out_cnt = 1; /* * Issue ioctl to retrieve the target luns. Space has been allocted * for one entry. If more than one entry should be returned, we * will re-issue the entry with the right amount of space allocted */ if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) { (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (illp->ll_out_cnt > 1) { illp_saved = illp; lun_list_size = sizeof (iscsi_lun_list_t); lun_list_size += (sizeof (iscsi_if_lun_t) * (illp->ll_out_cnt - 1)); illp = (iscsi_lun_list_t *)calloc(1, lun_list_size); if (illp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } illp->ll_vers = ISCSI_INTERFACE_VERSION; illp->ll_all_tgts = illp_saved->ll_all_tgts; illp->ll_tgt_oid = illp_saved->ll_tgt_oid; illp->ll_in_cnt = illp_saved->ll_out_cnt; free(illp_saved); /* Issue the same ioctl again to get all the target LUN list */ if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) { free(illp); (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } *ppLunList = illp; (void) close(fd); return (IMA_STATUS_SUCCESS); } /* A helper function to obtain digest algorithms. */ static IMA_STATUS getDigest( IMA_OID oid, int ioctlCmd, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm ) { IMA_MIN_MAX_VALUE pProps; IMA_STATUS status; if ((status = getISCSINodeParameter(MIN_MAX_PARAM, &oid, &pProps, ioctlCmd)) != IMA_STATUS_SUCCESS) { return (status); } switch (pProps.defaultValue) { case ISCSI_DIGEST_NONE: algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->defaultAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C: algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->defaultAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C_NONE: algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_NONE; algorithm->defaultAlgorithmCount = 2; break; case ISCSI_DIGEST_NONE_CRC32C: algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_CRC32C; algorithm->defaultAlgorithmCount = 2; break; default: /* Error */ syslog(LOG_USER|LOG_DEBUG, "Invalid default digest: %d", pProps.defaultValue); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } /* The configured value */ if (pProps.currentValueValid == IMA_TRUE) { algorithm->currentValid = IMA_TRUE; switch (pProps.currentValue) { case ISCSI_DIGEST_NONE: algorithm->currentAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->currentAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C: algorithm->currentAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->currentAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C_NONE: algorithm->currentAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->currentAlgorithms[1] = ISCSI_DIGEST_NONE; algorithm->currentAlgorithmCount = 2; break; case ISCSI_DIGEST_NONE_CRC32C: algorithm->currentAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->currentAlgorithms[1] = ISCSI_DIGEST_CRC32C; algorithm->currentAlgorithmCount = 2; break; default: /* Error */ syslog(LOG_USER|LOG_DEBUG, "Invalid configured digest: %d", pProps.defaultValue); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } else { algorithm->currentValid = IMA_FALSE; } return (IMA_STATUS_SUCCESS); } /* * getConnOidList - */ static IMA_STATUS getConnOidList( IMA_OID *sessOid, iscsi_conn_list_t **ppConnList ) { iscsi_conn_list_t *iscsiConnList = NULL; size_t allocLen; int fd; int status; int out_cnt; /* Preset it to NULL to prepare for the case of failure */ *ppConnList = NULL; /* We try to open the driver now. */ if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } iscsiConnList = (iscsi_conn_list_t *)calloc(1, sizeof (iscsi_conn_list_t)); if (iscsiConnList == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION; iscsiConnList->cl_in_cnt = iscsiConnList->cl_out_cnt = 1; if (sessOid == NULL) { iscsiConnList->cl_all_sess = B_TRUE; } else { iscsiConnList->cl_all_sess = B_FALSE; iscsiConnList->cl_sess_oid = (uint32_t)sessOid->objectSequenceNumber; } /* * Issue ioctl to retrieve the connection OIDs. Space has been * allocated for one entry. If more than one entry should be * returned, we will re-issue the entry with the right amount of * space allocted */ if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d", errno); *ppConnList = NULL; (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (iscsiConnList->cl_out_cnt > 1) { out_cnt = iscsiConnList->cl_out_cnt; free(iscsiConnList); allocLen = sizeof (iscsi_conn_list_t); allocLen += (sizeof (iscsi_if_conn_t) * out_cnt - 1); iscsiConnList = (iscsi_conn_list_t *)calloc(1, allocLen); if (iscsiConnList == NULL) { *ppConnList = NULL; (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION; iscsiConnList->cl_in_cnt = out_cnt; if (sessOid == NULL) { iscsiConnList->cl_all_sess = B_TRUE; } else { iscsiConnList->cl_all_sess = B_FALSE; iscsiConnList->cl_sess_oid = (uint32_t)sessOid->objectSequenceNumber; } /* Issue the same ioctl again to obtain all the OIDs */ if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d", errno); *ppConnList = NULL; free(iscsiConnList); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (out_cnt < iscsiConnList->cl_out_cnt) { /* * The connection list grew between the first and second * ioctls. */ syslog(LOG_USER|LOG_DEBUG, "The connection list has grown. There could be " "more connections than listed."); } } (void) close(fd); *ppConnList = iscsiConnList; return (IMA_STATUS_SUCCESS); } /* * getConnProps - */ static IMA_STATUS getConnProps( iscsi_if_conn_t *pConn, iscsi_conn_props_t **ppConnProps ) { iscsi_conn_props_t *iscsiConnProps; int fd; int status; /* We try to open the driver. */ if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } iscsiConnProps = (iscsi_conn_props_t *)calloc(1, sizeof (*iscsiConnProps)); if (iscsiConnProps == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } iscsiConnProps->cp_vers = ISCSI_INTERFACE_VERSION; iscsiConnProps->cp_oid = pConn->c_oid; iscsiConnProps->cp_cid = pConn->c_cid; iscsiConnProps->cp_sess_oid = pConn->c_sess_oid; /* The IOCTL is submitted. */ if (ioctl(fd, ISCSI_CONN_PROPS_GET, iscsiConnProps) != 0) { /* IOCTL failed */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno); free(iscsiConnProps); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); *ppConnProps = iscsiConnProps; return (IMA_STATUS_SUCCESS); } /* A helper function to set authentication method. */ static IMA_STATUS setAuthMethods( IMA_OID oid, IMA_UINT *pMethodCount, const IMA_AUTHMETHOD *pMethodList ) { int fd; int i; int status; iscsi_auth_props_t auth; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&auth, 0, sizeof (iscsi_auth_props_t)); auth.a_vers = ISCSI_INTERFACE_VERSION; auth.a_oid = (uint32_t)oid.objectSequenceNumber; /* * Get the current auth fields so they don't need to be reset * here. */ if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) { /* EMPTY */ /* Initializing auth structure with current settings */ } auth.a_auth_method = authMethodNone; for (i = 0; i < *pMethodCount; i++) { switch (pMethodList[i]) { case IMA_AUTHMETHOD_CHAP: auth.a_auth_method |= authMethodCHAP; break; default: break; } } if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_AUTH_SET failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } /* A helper function to set authentication method. */ static IMA_STATUS getAuthMethods( IMA_OID oid, IMA_UINT *pMethodCount, IMA_AUTHMETHOD *pMethodList ) { int fd; int status; iscsi_auth_props_t auth; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) memset(&auth, 0, sizeof (iscsi_auth_props_t)); auth.a_vers = ISCSI_INTERFACE_VERSION; auth.a_oid = (uint32_t)oid.objectSequenceNumber; if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_AUTH_GET failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (auth.a_auth_method == authMethodNone) { pMethodList[0] = IMA_AUTHMETHOD_NONE; *pMethodCount = 1; } else { int i = 0; if (!((auth.a_auth_method & authMethodCHAP)^authMethodCHAP)) { pMethodList[i++] = IMA_AUTHMETHOD_CHAP; } *pMethodCount = i; } (void) close(fd); return (IMA_STATUS_SUCCESS); } /* Helper function to open driver */ int open_driver( int *fd ) { int ret = 0; if ((*fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { ret = errno; syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)", ISCSI_DRIVER_DEVCTL, ret); } return (ret); } /* * Iscsi driver does not support OID for discovery address. Create * a modified version of IMA_RemoveDiscoveryAddress that takes * discoveryAddress (instead of an OID) as input argument. */ IMA_API IMA_STATUS SUN_IMA_RemoveDiscoveryAddress( SUN_IMA_TARGET_ADDRESS discoveryAddress ) { entry_t entry; int fd; int status, i, addr_list_size, insize; iscsi_addr_list_t *idlp, al_info; iscsi_addr_t *matched_addr = NULL; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } if (prepare_discovery_entry(discoveryAddress, &entry) != DISC_ADDR_OK) { (void) close(fd); return (IMA_ERROR_INVALID_PARAMETER); } (void) memset(&al_info, 0, sizeof (al_info)); al_info.al_vers = ISCSI_INTERFACE_VERSION; al_info.al_in_cnt = 0; /* * Issue ioctl to get the number of discovery address. */ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d", ISCSI_DISCOVERY_ADDR_LIST_GET, errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (al_info.al_out_cnt == 0) { (void) close(fd); return (IMA_ERROR_OBJECT_NOT_FOUND); } addr_list_size = sizeof (iscsi_addr_list_t); if (al_info.al_out_cnt > 1) { addr_list_size += (sizeof (iscsi_addr_t) * (al_info.al_out_cnt - 1)); } idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size); if (idlp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } idlp->al_vers = ISCSI_INTERFACE_VERSION; idlp->al_in_cnt = al_info.al_out_cnt; /* issue the same ioctl to get all the discovery addresses */ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d", ISCSI_DISCOVERY_ADDR_LIST_GET, errno); free(idlp); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } /* * find the matched discovery address */ for (i = 0; i < idlp->al_out_cnt; i++) { insize = idlp->al_addrs[i].a_addr.i_insize; if (insize != entry.e_insize) { continue; } if (insize == sizeof (struct in_addr)) { if (idlp->al_addrs[i].a_addr.i_addr.in4.s_addr == entry.e_u.u_in4.s_addr) { matched_addr = &(idlp->al_addrs[i]); break; } } if (insize == sizeof (struct in6_addr)) { if (bcmp(entry.e_u.u_in6.s6_addr, idlp->al_addrs[i].a_addr.i_addr.in6.s6_addr, insize) == 0) { matched_addr = &(idlp->al_addrs[i]); break; } } } free(idlp); if (matched_addr == NULL) { (void) close(fd); return (IMA_ERROR_OBJECT_NOT_FOUND); } if (ioctl(fd, ISCSI_DISCOVERY_ADDR_CLEAR, &entry)) { status = errno; (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_DISCOVERY_ADDR_CLEAR ioctl failed, errno: %d", errno); if (status == EBUSY) { return (IMA_ERROR_LU_IN_USE); } else { return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_SetTargetAuthMethods( IMA_OID targetOid, IMA_UINT *methodCount, const IMA_AUTHMETHOD *pMethodList ) { return (setAuthMethods(targetOid, methodCount, pMethodList)); } IMA_STATUS getNegotiatedDigest( int digestType, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm, SUN_IMA_CONN_PROPERTIES *connProps) { IMA_UINT digest; if (connProps->valuesValid == IMA_TRUE) { algorithm->negotiatedValid = IMA_TRUE; if (digestType == ISCSI_LOGIN_PARAM_HEADER_DIGEST) { digest = connProps->headerDigest; } else { digest = connProps->dataDigest; } switch (digest) { case ISCSI_DIGEST_NONE: algorithm->negotiatedAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->negotiatedAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C: algorithm->negotiatedAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->negotiatedAlgorithmCount = 1; break; case ISCSI_DIGEST_CRC32C_NONE: algorithm->negotiatedAlgorithms[0] = ISCSI_DIGEST_CRC32C; algorithm->negotiatedAlgorithms[1] = ISCSI_DIGEST_NONE; algorithm->negotiatedAlgorithmCount = 2; break; case ISCSI_DIGEST_NONE_CRC32C: algorithm->negotiatedAlgorithms[0] = ISCSI_DIGEST_NONE; algorithm->negotiatedAlgorithms[1] = ISCSI_DIGEST_CRC32C; algorithm->negotiatedAlgorithmCount = 2; break; default: syslog(LOG_USER|LOG_DEBUG, "Invalid negotiated digest: %d", digest); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } else { algorithm->negotiatedValid = IMA_FALSE; } return (IMA_STATUS_SUCCESS); } /* * Non-IMA defined function. */ IMA_API IMA_STATUS SUN_IMA_GetISNSServerAddressPropertiesList( SUN_IMA_DISC_ADDR_PROP_LIST **ppList ) { char isns_server_addr_str[256]; int fd; int i; int isns_server_addr_list_size; int status; int out_cnt; iscsi_addr_list_t *ialp; /* LINTED */ IMA_IP_ADDRESS *ipAddr; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t)); if (ialp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } ialp->al_vers = ISCSI_INTERFACE_VERSION; ialp->al_in_cnt = ialp->al_out_cnt = 1; /* * Issue ioctl to retrieve the isns server addresses. Space has been * allocted for one entry. If more than one entry should be returned, * we will re-issue the entry with the right amount of space allocted */ if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) { (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } isns_server_addr_list_size = sizeof (iscsi_addr_list_t); if (ialp->al_out_cnt > 1) { out_cnt = ialp->al_out_cnt; free(ialp); isns_server_addr_list_size += (sizeof (iscsi_addr_t) * out_cnt - 1); ialp = (iscsi_addr_list_t *)calloc(1, isns_server_addr_list_size); if (ialp == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } ialp->al_vers = ISCSI_INTERFACE_VERSION; ialp->al_in_cnt = out_cnt; /* * Issue ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl again to obtain * the list of all the iSNS server addresses */ if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) { free(ialp); (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, " "errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } *ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)calloc(1, sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) + ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES)); if (*ppList == NULL) { free(ialp); (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } (*ppList)->discAddrCount = ialp->al_out_cnt; for (i = 0; i < ialp->al_out_cnt; i++) { if (ialp->al_addrs[i].a_addr.i_insize == sizeof (struct in_addr)) { (*ppList)->props[i].discoveryAddress.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_TRUE; } else if (ialp->al_addrs[i].a_addr.i_insize == sizeof (struct in6_addr)) { (*ppList)->props[i].discoveryAddress.hostnameIpAddress. id.ipAddress.ipv4Address = IMA_FALSE; } else { (void) strlcpy(isns_server_addr_str, "unknown", sizeof (isns_server_addr_str)); } ipAddr = &(*ppList)->props[i].discoveryAddress. hostnameIpAddress.id.ipAddress; bcopy(&ialp->al_addrs[i].a_addr.i_addr, (*ppList)->props[i].discoveryAddress.hostnameIpAddress.id. ipAddress.ipAddress, sizeof (ipAddr->ipAddress)); (*ppList)->props[i].discoveryAddress.portNumber = ialp->al_addrs[i].a_port; } free(ialp); (void) close(fd); return (IMA_STATUS_SUCCESS); } /*ARGSUSED*/ /* * Remove iSNS Server Address */ IMA_API IMA_STATUS SUN_IMA_RemoveISNSServerAddress( SUN_IMA_TARGET_ADDRESS isnsServerAddress ) { entry_t entry; int fd, status; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } if (prepare_discovery_entry(isnsServerAddress, &entry) != DISC_ADDR_OK) { (void) close(fd); return (IMA_ERROR_INVALID_PARAMETER); } if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_CLEAR, &entry)) { status = errno; (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_ISNS_SERVER_ADDR_CLEAR ioctl failed, errno: %d", status); if (status == EBUSY) { return (IMA_ERROR_LU_IN_USE); } else { return (IMA_ERROR_UNEXPECTED_OS_ERROR); } } (void) close(fd); return (IMA_STATUS_SUCCESS); } /*ARGSUSED*/ IMA_API IMA_STATUS SUN_IMA_AddISNSServerAddress( const SUN_IMA_TARGET_ADDRESS isnsServerAddress ) { entry_t entry; int fd; int status; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } if (prepare_discovery_entry(isnsServerAddress, &entry) != DISC_ADDR_OK) { (void) close(fd); return (IMA_ERROR_INVALID_PARAMETER); } if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_SET, &entry)) { /* * Encountered problem setting the discovery address. */ (void) close(fd); syslog(LOG_USER|LOG_DEBUG, "ISCSI_ISNS_SERVER_ADDR_SET ioctl failed, errno: %d", errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_RetrieveISNSServerTargets( IMA_TARGET_ADDRESS serverAddress, SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList ) { int fd; int ctr; int server_pg_list_sz; int status; isns_server_portal_group_list_t *server_pg_list = NULL; isns_portal_group_list_t *pg_list = NULL; IMA_BOOL retry = IMA_TRUE; entry_t entry; #define ISNS_SERVER_DEFAULT_NUM_TARGETS 50 server_pg_list_sz = sizeof (*server_pg_list) + ((ISNS_SERVER_DEFAULT_NUM_TARGETS - 1) * sizeof (isns_portal_group_t)); server_pg_list = (isns_server_portal_group_list_t *)calloc(1, server_pg_list_sz); if (server_pg_list == NULL) { return (IMA_ERROR_INSUFFICIENT_MEMORY); } server_pg_list->addr_port_list.pg_in_cnt = ISNS_SERVER_DEFAULT_NUM_TARGETS; if ((prepare_discovery_entry_IMA(serverAddress, &entry) != DISC_ADDR_OK)) { free(server_pg_list); return (IMA_ERROR_INVALID_PARAMETER); } server_pg_list->addr.a_port = entry.e_port; server_pg_list->addr.a_addr.i_insize = entry.e_insize; if (entry.e_insize == sizeof (struct in_addr)) { server_pg_list->addr.a_addr.i_addr.in4.s_addr = (entry.e_u.u_in4.s_addr); } else if (entry.e_insize == sizeof (struct in6_addr)) { bcopy(&entry.e_u.u_in6.s6_addr, server_pg_list->addr.a_addr.i_addr.in6.s6_addr, 16); } if ((status = open_driver(&fd))) { free(server_pg_list); return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } retry_isns: /* * Issue ioctl to obtain the ISNS Portal Group List list */ if (ioctl(fd, ISCSI_ISNS_SERVER_GET, server_pg_list) != 0) { int tmp_errno = errno; IMA_STATUS return_status; syslog(LOG_USER|LOG_DEBUG, "ISCSI_ISNS_SERVER_GET ioctl failed, errno: %d", tmp_errno); if (tmp_errno == EACCES) { return_status = IMA_ERROR_OBJECT_NOT_FOUND; } else { return_status = IMA_ERROR_UNEXPECTED_OS_ERROR; } (void) close(fd); free(server_pg_list); return (return_status); } pg_list = &server_pg_list->addr_port_list; /* check if all targets received */ if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) { if (retry == IMA_TRUE) { server_pg_list_sz = sizeof (*server_pg_list) + ((pg_list->pg_out_cnt - 1) * sizeof (isns_server_portal_group_list_t)); server_pg_list = (isns_server_portal_group_list_t *) realloc(server_pg_list, server_pg_list_sz); if (server_pg_list == NULL) { (void) close(fd); return (IMA_ERROR_INSUFFICIENT_MEMORY); } pg_list = &server_pg_list->addr_port_list; pg_list->pg_in_cnt = pg_list->pg_out_cnt; retry = IMA_FALSE; goto retry_isns; } else { /* * don't retry after 2 attempts. The target list * shouldn't continue growing. Just continue * on and display what was found. */ syslog(LOG_USER|LOG_DEBUG, "ISCSI_SENDTGTS_GET overflow: " "failed to obtain all targets"); pg_list->pg_out_cnt = pg_list->pg_in_cnt; } } (void) close(fd); /* allocate for caller return buffer */ *ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1, sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) + pg_list->pg_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY)); if (*ppList == NULL) { free(server_pg_list); return (IMA_ERROR_INSUFFICIENT_MEMORY); } (*ppList)->keyCount = pg_list->pg_out_cnt; for (ctr = 0; ctr < pg_list->pg_out_cnt; ctr++) { (void) mbstowcs((*ppList)->keys[ctr].name, (char *)pg_list->pg_list[ctr].pg_iscsi_name, IMA_NODE_NAME_LEN); (*ppList)->keys[ctr].tpgt = pg_list->pg_list[ctr].pg_tag; (*ppList)->keys[ctr].address.portNumber = pg_list->pg_list[ctr].pg_port; if (pg_list->pg_list[ctr].insize == sizeof (struct in_addr)) { (*ppList)->keys[ctr].address.ipAddress.ipv4Address = IMA_TRUE; } else if (pg_list->pg_list[ctr].insize == sizeof (struct in6_addr)) { (*ppList)->keys[ctr].address.ipAddress.ipv4Address = IMA_FALSE; } else { free(pg_list); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress, &(pg_list->pg_list[ctr].pg_ip_addr), pg_list->pg_list[ctr].insize); } free(server_pg_list); return (IMA_STATUS_SUCCESS); } /* ARGSUSED */ IMA_STATUS SUN_IMA_GetSessionOidList( IMA_OID initiatorOid, IMA_OID_LIST **ppList ) { return (get_target_oid_list(ISCSI_TGT_OID_LIST, ppList)); } /*ARGSUSED*/ IMA_API IMA_STATUS SUN_IMA_GetTargetAuthParms( IMA_OID oid, IMA_AUTHMETHOD method, IMA_INITIATOR_AUTHPARMS *pParms ) { int fd; iscsi_chap_props_t chap_p; if (pParms == NULL) { return (IMA_ERROR_INVALID_PARAMETER); } if (oid.objectType != IMA_OBJECT_TYPE_TARGET) { return (IMA_ERROR_INCORRECT_OBJECT_TYPE); } if (method != IMA_AUTHMETHOD_CHAP) { return (IMA_ERROR_INVALID_PARAMETER); } if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t)); chap_p.c_vers = ISCSI_INTERFACE_VERSION; chap_p.c_oid = (uint32_t)oid.objectSequenceNumber; if (ioctl(fd, ISCSI_CHAP_GET, &chap_p) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_CHAP_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } (void) memcpy(pParms->chapParms.name, chap_p.c_user, chap_p.c_user_len); pParms->chapParms.nameLength = chap_p.c_user_len; (void) memcpy(pParms->chapParms.challengeSecret, chap_p.c_secret, chap_p.c_secret_len); pParms->chapParms.challengeSecretLength = chap_p.c_secret_len; return (IMA_STATUS_SUCCESS); } IMA_API IMA_STATUS SUN_IMA_GetBootTargetName( IMA_NODE_NAME tgtName ) { int fd; IMA_STATUS rtn; iscsi_boot_property_t bootProp; bootProp.tgt_name.n_name[0] = '\0'; bootProp.tgt_chap.c_user[0] = '\0'; tgtName[0] = L'\0'; rtn = IMA_ERROR_UNEXPECTED_OS_ERROR; if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if ((bootProp.tgt_name.n_name[0] != '\0') && (tgtName != NULL)) { if (mbstowcs(tgtName, (const char *)bootProp.tgt_name.n_name, IMA_NODE_NAME_LEN) == (size_t)-1) { syslog(LOG_USER|LOG_DEBUG, "ISCSI Target name covert to WCHAR fail"); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } else { rtn = IMA_STATUS_SUCCESS; } } return (rtn); } IMA_API IMA_STATUS SUN_IMA_GetBootTargetAuthParams( IMA_INITIATOR_AUTHPARMS *pTgtCHAP ) { int fd; IMA_STATUS rtn; iscsi_boot_property_t bootProp; bootProp.tgt_name.n_name[0] = '\0'; bootProp.tgt_chap.c_user[0] = '\0'; bootProp.tgt_chap.c_secret[0] = '\0'; rtn = IMA_ERROR_UNEXPECTED_OS_ERROR; if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (pTgtCHAP != NULL) { if (bootProp.tgt_chap.c_user[0] != '\0') { (void) memcpy(pTgtCHAP->chapParms.name, bootProp.tgt_chap.c_user, ISCSI_MAX_NAME_LEN); } else { pTgtCHAP->chapParms.name[0] = '\0'; } if (bootProp.tgt_chap.c_secret[0] != '\0') { (void) memcpy(pTgtCHAP->chapParms.challengeSecret, bootProp.tgt_chap.c_secret, MAX_CHAP_SECRET_LEN); } else { pTgtCHAP->chapParms.challengeSecret[0] = '\0'; } rtn = IMA_STATUS_SUCCESS; } return (rtn); } IMA_STATUS SUN_IMA_GetBootMpxio( IMA_BOOL *pMpxioEnabled ) { int fd; iscsi_boot_property_t bootProp; bootProp.hba_mpxio_enabled = B_FALSE; *pMpxioEnabled = IMA_UNKNOWN; if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (bootProp.hba_mpxio_enabled) { *pMpxioEnabled = IMA_TRUE; } else { *pMpxioEnabled = IMA_FALSE; } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetBootIscsi( IMA_BOOL *pIscsiBoot ) { int fd; iscsi_boot_property_t bootProp; bootProp.iscsiboot = 0; *pIscsiBoot = 0; if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_BOOTPROP_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } *pIscsiBoot = bootProp.iscsiboot; (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_GetSvcStatus( IMA_BOOL *pSvcEnabled) { int fd; uint32_t status = ISCSI_SERVICE_DISABLED; if (pSvcEnabled == NULL) return (IMA_ERROR_UNEXPECTED_OS_ERROR); *pSvcEnabled = 0; if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) { syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)", ISCSI_DRIVER_DEVCTL, errno); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (ioctl(fd, ISCSI_SMF_GET, &status) != 0) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_SVC_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } if (status == ISCSI_SERVICE_ENABLED) { *pSvcEnabled = 1; } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_STATUS SUN_IMA_ReEnumeration( IMA_OID targetId ) { int fd; int status; iscsi_reen_t reet; reet.re_ver = ISCSI_INTERFACE_VERSION; reet.re_oid = (uint32_t)targetId.objectSequenceNumber; if ((status = open_driver(&fd))) { return (SUN_IMA_ERROR_SYSTEM_ERROR | status); } (void) ioctl(fd, ISCSI_TARGET_REENUM, &reet); (void) close(fd); return (IMA_STATUS_SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SUN_IMA_H #define _SUN_IMA_H #include #ifdef __cplusplus extern "C" { #endif IMA_API IMA_STATUS SUN_IMA_GetDiscoveryAddressPropertiesList( SUN_IMA_DISC_ADDR_PROP_LIST **ppList); IMA_API IMA_STATUS SUN_IMA_GetStaticTargetProperties( IMA_OID staticTargetOid, SUN_IMA_STATIC_TARGET_PROPERTIES *pProps); IMA_API IMA_STATUS SUN_IMA_AddStaticTarget( IMA_OID lhbaOid, const SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig, IMA_OID *pTargetOid); IMA_API IMA_STATUS SUN_IMA_GetTargetProperties( IMA_OID targetId, SUN_IMA_TARGET_PROPERTIES *pProps); IMA_STATUS SUN_IMA_SetTargetAuthParams( IMA_OID targetOid, IMA_AUTHMETHOD method, const IMA_INITIATOR_AUTHPARMS *pParms); IMA_STATUS SUN_IMA_GetTargetAuthMethods( IMA_OID lhbaOid, IMA_OID targetOid, IMA_UINT *pMethodCount, IMA_AUTHMETHOD *pMethodList); IMA_STATUS SUN_IMA_SetInitiatorRadiusConfig( IMA_OID lhbaOid, SUN_IMA_RADIUS_CONFIG *config); IMA_STATUS SUN_IMA_GetInitiatorRadiusConfig( IMA_OID lhbaOid, SUN_IMA_RADIUS_CONFIG *config); IMA_STATUS SUN_IMA_SetInitiatorRadiusAccess( IMA_OID lhbaOid, IMA_BOOL radiusAccess); IMA_STATUS SUN_IMA_GetInitiatorRadiusAccess( IMA_OID lhbaOid, IMA_BOOL *radiusAccess); IMA_STATUS SUN_IMA_SendTargets( IMA_NODE_NAME nodeName, IMA_TARGET_ADDRESS address, SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList); IMA_STATUS SUN_IMA_SetTargetBidirAuthFlag( IMA_OID targetOid, IMA_BOOL *bidirAuthFlag); IMA_STATUS SUN_IMA_GetTargetBidirAuthFlag( IMA_OID targetOid, IMA_BOOL *bidirAuthFlag); IMA_STATUS SUN_IMA_CreateTargetOid( IMA_NODE_NAME targetName, IMA_OID *targetOid); IMA_STATUS SUN_IMA_RemoveTargetParam( IMA_OID targetOid); IMA_API IMA_STATUS SUN_IMA_SetHeaderDigest( IMA_OID oid, IMA_UINT algorithmCount, const SUN_IMA_DIGEST_ALGORITHM *algorithmList); IMA_API IMA_STATUS SUN_IMA_SetDataDigest( IMA_OID oid, IMA_UINT algorithmCount, const SUN_IMA_DIGEST_ALGORITHM *algorithmList); IMA_API IMA_STATUS SUN_IMA_GetHeaderDigest( IMA_OID oid, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm); IMA_API IMA_STATUS SUN_IMA_GetDataDigest( IMA_OID oid, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm); IMA_STATUS SUN_IMA_GetLuProperties( IMA_OID luId, SUN_IMA_LU_PROPERTIES *pProps); IMA_API IMA_STATUS SUN_IMA_GetConnOidList( IMA_OID *oid, IMA_OID_LIST **ppList); IMA_API IMA_STATUS SUN_IMA_GetConnProperties( IMA_OID *connOid, SUN_IMA_CONN_PROPERTIES **pProps); IMA_API IMA_STATUS SUN_IMA_GetConfigSessions( IMA_OID targetOid, SUN_IMA_CONFIG_SESSIONS **pConfigSessions); IMA_API IMA_STATUS SUN_IMA_SetConfigSessions( IMA_OID targetOid, SUN_IMA_CONFIG_SESSIONS *pConfigSessions); IMA_API IMA_STATUS SUN_IMA_RemoveDiscoveryAddress( SUN_IMA_TARGET_ADDRESS discoveryAddress); IMA_STATUS SUN_IMA_SetTargetAuthMethods( IMA_OID targetOid, IMA_UINT *methodCount, const IMA_AUTHMETHOD *pMethodList); IMA_STATUS getNegotiatedDigest( int digestType, SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm, SUN_IMA_CONN_PROPERTIES *connProps); IMA_API IMA_STATUS SUN_IMA_GetISNSServerAddressPropertiesList( SUN_IMA_DISC_ADDR_PROP_LIST **ppList); IMA_API IMA_STATUS SUN_IMA_RemoveISNSServerAddress( SUN_IMA_TARGET_ADDRESS isnsServerAddress); IMA_API IMA_STATUS SUN_IMA_AddISNSServerAddress( const SUN_IMA_TARGET_ADDRESS isnsServerAddress); IMA_STATUS SUN_IMA_RetrieveISNSServerTargets( IMA_TARGET_ADDRESS serverAddress, SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList); IMA_STATUS SUN_IMA_GetSessionOidList( IMA_OID initiatorOid, IMA_OID_LIST **ppList); IMA_API IMA_STATUS SUN_IMA_GetTargetAuthParms( IMA_OID oid, IMA_AUTHMETHOD method, IMA_INITIATOR_AUTHPARMS *pParms); IMA_STATUS SUN_IMA_GetBootTargetName( IMA_NODE_NAME tgtName); IMA_STATUS SUN_IMA_GetBootTargetAuthParams( IMA_INITIATOR_AUTHPARMS *pTgtCHAP); IMA_STATUS SUN_IMA_GetBootMpxio( IMA_BOOL *pMpxioEnabled); IMA_STATUS SUN_IMA_GetBootIscsi( IMA_BOOL *pIscsiBoot); IMA_STATUS SUN_IMA_GetSvcStatus( IMA_BOOL *pSvcEnabled); IMA_STATUS SUN_IMA_ReEnumeration( IMA_OID targetId); #ifdef __cplusplus } #endif #endif /* _SUN_IMA_H */