1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #include <stdlib.h> 26 #include <stdio.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <errno.h> 32 #include <string.h> 33 #include <getopt.h> 34 #include <strings.h> 35 #include <ctype.h> 36 #include <libnvpair.h> 37 #include <libintl.h> 38 #include <libgen.h> 39 #include <pwd.h> 40 #include <auth_attr.h> 41 #include <secdb.h> 42 #include <libscf.h> 43 #include <limits.h> 44 #include <locale.h> 45 46 #include <libstmf.h> 47 #include <libiscsit.h> 48 49 /* what's this used for?? */ 50 #define ITADM_VERSION "1.0" 51 52 /* SMF service info */ 53 #define ISCSIT_SVC "svc:/network/iscsi/target:default" 54 55 #define STMF_STALE(ret) {\ 56 if (ret == STMF_ERROR_PROV_DATA_STALE) {\ 57 (void) fprintf(stderr, "%s\n",\ 58 gettext("Configuration changed during processing. "\ 59 "Check the configuration, then retry this command "\ 60 "if appropriate."));\ 61 }\ 62 } 63 64 #define ITADM_CHKAUTH(sec) {\ 65 if (!chkauthattr(sec, itadm_uname)) {\ 66 (void) fprintf(stderr,\ 67 gettext("Error, operation requires authorization %s"),\ 68 sec);\ 69 (void) fprintf(stderr, "\n");\ 70 return (1);\ 71 }\ 72 } 73 74 static struct option itadm_long[] = { 75 {"alias", required_argument, NULL, 'l'}, 76 {"auth-method", required_argument, NULL, 'a'}, 77 {"chap-secret", no_argument, NULL, 's'}, 78 {"chap-secret-file", required_argument, NULL, 'S'}, 79 {"chap-user", required_argument, NULL, 'u'}, 80 {"force", no_argument, NULL, 'f'}, 81 {"help", no_argument, NULL, 'h'}, 82 {"help", no_argument, NULL, '?'}, 83 {"isns", required_argument, NULL, 'i'}, 84 {"isns-server", required_argument, NULL, 'I'}, 85 {"node-name", required_argument, NULL, 'n'}, 86 {"radius-secret", no_argument, NULL, 'd'}, 87 {"radius-secret-file", required_argument, NULL, 'D'}, 88 {"radius-server", required_argument, NULL, 'r'}, 89 {"tpg-tag", required_argument, NULL, 't'}, 90 {"verbose", no_argument, NULL, 'v'}, 91 {"version", no_argument, NULL, 'V'}, 92 {NULL, 0, NULL, 0} 93 }; 94 95 char c_tgt[] = "itadm create-target [-a radius|chap|none|default] [-s] \ 96 [-S chap-secret-path] [-u chap-username] [-n target-node-name] \ 97 [-l alias] [-t tpg-name[,tpg-name,...]]"; 98 99 static char m_tgt[] = "itadm modify-target [-a radius|chap|none|default] [-s] \ 100 [-S chap-secret-path] [-u chap-username] [-n new-target-node-name] \ 101 [-l alias] [-t tpg-name[,tpg-name,...]] target-node-name"; 102 103 static char d_tgt[] = "itadm delete-target [-f] target-node-name"; 104 105 static char l_tgt[] = "itadm list-target [-v] [target-node-name"; 106 107 static char c_tpg[] = "itadm create-tpg tpg-name IP-address[:port] \ 108 [IP-address[:port]] [...]"; 109 110 static char l_tpg[] = "itadm list-tpg [-v] [tpg-name]"; 111 112 static char d_tpg[] = "itadm delete-tpg [-f] tpg-name"; 113 114 static char c_ini[] = "itadm create-initiator [-s] [-S chap-secret-path] \ 115 [-u chap-username] initiator-node-name"; 116 117 static char m_ini[] = "itadm modify-initiator [-s] [-S chap-secret-path] \ 118 [-u chap-username] initiator-node-name"; 119 120 static char l_ini[] = "itadm list-initiator [-v] initiator-node-name"; 121 122 static char d_ini[] = "itadm delete-inititator initiator-node-name"; 123 124 static char m_def[] = "itadm modify-defaults [-a radius|chap|none] \ 125 [-r IP-address[:port]] [-d] [-D radius-secret-path] [-i enable|disable] \ 126 [-I IP-address[:port][,IP-adddress[:port]]]"; 127 128 static char l_def[] = "itadm list-defaults"; 129 130 131 /* keep the order of this enum in the same order as the 'subcmds' struct */ 132 typedef enum { 133 CREATE_TGT, 134 MODIFY_TGT, 135 DELETE_TGT, 136 LIST_TGT, 137 CREATE_TPG, 138 DELETE_TPG, 139 LIST_TPG, 140 CREATE_INI, 141 MODIFY_INI, 142 LIST_INI, 143 DELETE_INI, 144 MODIFY_DEF, 145 LIST_DEF, 146 NULL_SUBCMD /* must always be last! */ 147 } itadm_sub_t; 148 149 typedef struct { 150 char *name; 151 char *shortopts; 152 char *usemsg; 153 } itadm_subcmds_t; 154 155 static itadm_subcmds_t subcmds[] = { 156 {"create-target", ":a:sS:u:n:l:t:h?", c_tgt}, 157 {"modify-target", ":a:sS:u:n:l:t:h?", m_tgt}, 158 {"delete-target", ":fh?", d_tgt}, 159 {"list-target", ":vh?", l_tgt}, 160 {"create-tpg", ":h?", c_tpg}, 161 {"delete-tpg", ":fh?", d_tpg}, 162 {"list-tpg", ":vh?", l_tpg}, 163 {"create-initiator", ":sS:u:h?", c_ini}, 164 {"modify-initiator", ":sS:u:h?", m_ini}, 165 {"list-initiator", ":vh?", l_ini}, 166 {"delete-initiator", ":h?", d_ini}, 167 {"modify-defaults", ":a:r:dD:i:I:h?", m_def}, 168 {"list-defaults", ":h?", l_def}, 169 {NULL, ":h?", NULL}, 170 }; 171 172 /* used for checking if user is authorized */ 173 static char *itadm_uname = NULL; 174 175 /* prototypes */ 176 static int 177 itadm_get_password(nvlist_t *nvl, char *key, char *passfile, 178 char *phrase); 179 180 static int 181 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num); 182 183 static int 184 create_target(char *tgt, nvlist_t *proplist); 185 186 static int 187 modify_target(char *tgt, char *new, nvlist_t *proplist); 188 189 static int 190 delete_target(char *tgt, boolean_t force); 191 192 static int 193 list_target(char *tgt, boolean_t verbose, boolean_t script); 194 195 static int 196 create_tpg(char *tpg, int addrc, char **addrs); 197 198 static int 199 list_tpg(char *tpg, boolean_t verbose, boolean_t script); 200 201 static int 202 delete_tpg(char *tpg, boolean_t force); 203 204 static int 205 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create); 206 207 static int 208 list_initiator(char *ini, boolean_t verbose, boolean_t script); 209 210 static int 211 delete_initiator(char *ini); 212 213 static int 214 modify_defaults(nvlist_t *proplist); 215 216 static int 217 list_defaults(boolean_t script); 218 219 static void 220 tag_name_to_num(char *tagname, uint16_t *tagnum); 221 222 /* prototype from iscsit_common.h */ 223 extern int 224 sockaddr_to_str(struct sockaddr_storage *sa, char **addr); 225 226 int 227 main(int argc, char *argv[]) 228 { 229 int ret = 0; 230 int idx = NULL_SUBCMD; 231 char c; 232 int newargc = argc; 233 char **newargv = NULL; 234 char *objp; 235 int itind = 0; 236 nvlist_t *proplist = NULL; 237 boolean_t verbose = B_FALSE; 238 boolean_t scripting = B_FALSE; 239 boolean_t tbool; 240 char *targetname = NULL; 241 char *propname; 242 boolean_t force = B_FALSE; 243 struct passwd *pwd = NULL; 244 uint32_t count = 0; 245 char *smfstate = NULL; 246 247 (void) setlocale(LC_ALL, ""); 248 (void) textdomain(TEXT_DOMAIN); 249 250 if (argc < 2) { 251 ret = 1; 252 goto usage_error; 253 } 254 255 for (idx = 0; subcmds[idx].name != NULL; idx++) { 256 if (strcmp(argv[1], subcmds[idx].name) == 0) { 257 break; 258 } 259 } 260 261 262 /* get the caller's user name for subsequent chkauthattr() calls */ 263 pwd = getpwuid(getuid()); 264 if (pwd == NULL) { 265 (void) fprintf(stderr, "%s\n", 266 gettext("Could not determine callers user name.")); 267 return (1); 268 } 269 270 itadm_uname = strdup(pwd->pw_name); 271 272 /* increment past command & subcommand */ 273 newargc--; 274 newargv = &(argv[1]); 275 276 ret = nvlist_alloc(&proplist, NV_UNIQUE_NAME, 0); 277 if (ret != 0) { 278 ret = errno; 279 (void) fprintf(stderr, 280 gettext("Could not allocate nvlist, errno = %d"), 281 ret); 282 (void) fprintf(stderr, "\n"); 283 ret = 1; 284 goto usage_error; 285 } 286 287 while ((ret == 0) && (newargv)) { 288 c = getopt_long(newargc, newargv, subcmds[idx].shortopts, 289 itadm_long, &itind); 290 if (c == -1) { 291 break; 292 } 293 294 switch (c) { 295 case 0: 296 /* flag set by getopt */ 297 break; 298 case 'a': 299 ret = nvlist_add_string(proplist, 300 "auth", optarg); 301 break; 302 case 'd': 303 ret = itadm_get_password(proplist, 304 "radiussecret", NULL, 305 gettext("Enter RADIUS secret: ")); 306 break; 307 case 'D': 308 ret = itadm_get_password(proplist, 309 "radiussecret", optarg, NULL); 310 break; 311 case 'f': 312 force = B_TRUE; 313 break; 314 case '?': 315 /* 316 * '?' is returned for both unrecognized 317 * options and if explicitly provided on 318 * the command line. The latter should 319 * be handled the same as -h. 320 */ 321 if (strcmp(newargv[optind-1], "-?") != 0) { 322 (void) fprintf(stderr, 323 gettext("Unrecognized option %s"), 324 newargv[optind-1]); 325 (void) fprintf(stderr, "\n"); 326 ret = 1; 327 } 328 goto usage_error; 329 case 'h': 330 goto usage_error; 331 case 'i': 332 if (strncmp(optarg, "enable", strlen(optarg)) 333 == 0) { 334 tbool = B_TRUE; 335 } else if (strncmp(optarg, "disable", 336 strlen(optarg)) == 0) { 337 tbool = B_FALSE; 338 } else { 339 (void) fprintf(stderr, "%s\n", 340 gettext("invalid value for -i")); 341 ret = 1; 342 break; 343 } 344 ret = nvlist_add_boolean_value(proplist, 345 "isns", tbool); 346 break; 347 case 'I': 348 /* possibly multi-valued */ 349 ret = itadm_opt_to_arr(proplist, 350 "isnsserver", optarg, &count); 351 if ((ret == 0) && (count > 8)) { 352 (void) fprintf(stderr, "%s\n", 353 gettext( 354 "Too many iSNS servers specified, " 355 "maximum of 8 allowed")); 356 ret = 1; 357 } 358 break; 359 case 'l': 360 ret = nvlist_add_string(proplist, 361 "alias", optarg); 362 break; 363 case 'n': 364 targetname = strdup(optarg); 365 if (targetname == NULL) { 366 ret = ENOMEM; 367 } 368 break; 369 case 'r': 370 ret = nvlist_add_string(proplist, 371 "radiusserver", optarg); 372 break; 373 case 's': 374 if ((idx == CREATE_TGT) || 375 (idx == MODIFY_TGT)) { 376 propname = "targetchapsecret"; 377 } else { 378 propname = "chapsecret"; 379 } 380 ret = itadm_get_password(proplist, 381 propname, NULL, 382 gettext("Enter CHAP secret: ")); 383 break; 384 case 'S': 385 if ((idx == CREATE_TGT) || 386 (idx == MODIFY_TGT)) { 387 propname = "targetchapsecret"; 388 } else { 389 propname = "chapsecret"; 390 } 391 ret = itadm_get_password(proplist, 392 propname, optarg, NULL); 393 break; 394 case 't': 395 /* possibly multi-valued */ 396 ret = itadm_opt_to_arr(proplist, 397 "tpg-tag", optarg, NULL); 398 break; 399 case 'u': 400 if ((idx == CREATE_TGT) || 401 (idx == MODIFY_TGT)) { 402 propname = "targetchapuser"; 403 } else { 404 propname = "chapuser"; 405 } 406 ret = nvlist_add_string(proplist, 407 propname, optarg); 408 break; 409 case 'v': 410 verbose = B_TRUE; 411 break; 412 case ':': 413 (void) fprintf(stderr, 414 gettext("Option %s requires an operand."), 415 newargv[optind-1]); 416 (void) fprintf(stderr, "\n"); 417 418 /* fall through to default */ 419 default: 420 ret = 1; 421 break; 422 } 423 } 424 425 if (ret != 0) { 426 goto usage_error; 427 } 428 429 /* after getopt() to allow handling of -h option */ 430 if ((itadm_sub_t)idx == NULL_SUBCMD) { 431 (void) fprintf(stderr, "%s\n", 432 gettext("Error, no subcommand specified")); 433 ret = 1; 434 goto usage_error; 435 } 436 437 /* 438 * some subcommands take multiple operands, so adjust now that 439 * getopt is complete 440 */ 441 newargc -= optind; 442 if (newargc == 0) { 443 newargv = NULL; 444 objp = NULL; 445 } else { 446 newargv = &(newargv[optind]); 447 objp = newargv[0]; 448 } 449 450 if (objp == NULL) { 451 switch ((itadm_sub_t)idx) { 452 case MODIFY_TGT: 453 case DELETE_TGT: 454 case CREATE_TPG: 455 case DELETE_TPG: 456 case CREATE_INI: 457 case MODIFY_INI: 458 case DELETE_INI: 459 /* These subcommands need operands */ 460 ret = 1; 461 goto usage_error; 462 default: 463 break; 464 } 465 } 466 467 if (newargc > 1) { 468 switch ((itadm_sub_t)idx) { 469 case MODIFY_TGT: 470 case DELETE_TGT: 471 case LIST_TGT: 472 case DELETE_TPG: 473 case LIST_TPG: 474 case CREATE_INI: 475 case MODIFY_INI: 476 case LIST_INI: 477 case DELETE_INI: 478 /* These subcommands should have at most one operand */ 479 ret = 1; 480 goto usage_error; 481 482 default: 483 break; 484 } 485 } 486 487 /* 488 * XXX - this should probably get pushed down to the library 489 * depending on the decision to allow/disallow configuratoin 490 * without the service running. 491 */ 492 /* 493 * Make sure iSCSI target service is enabled before 494 * proceeding. 495 */ 496 smfstate = smf_get_state(ISCSIT_SVC); 497 if (!smfstate || 498 (strcmp(smfstate, SCF_STATE_STRING_ONLINE) != 0)) { 499 (void) fprintf(stderr, "%s\n", 500 gettext("The iSCSI target service must be online " 501 "before running this command.")); 502 (void) fprintf(stderr, 503 gettext("Use 'svcadm enable -r %s'"), ISCSIT_SVC); 504 (void) fprintf(stderr, "\n"); 505 (void) fprintf(stderr, "%s\n", 506 gettext("to enable the service and its prerequisite " 507 "services and/or")); 508 (void) fprintf(stderr, 509 gettext("'svcs -x %s' to determine why it is not online."), 510 ISCSIT_SVC); 511 (void) fprintf(stderr, "\n"); 512 513 return (1); 514 } 515 516 switch ((itadm_sub_t)idx) { 517 case CREATE_TGT: 518 if (targetname) { 519 ret = create_target(targetname, proplist); 520 } else { 521 /* 522 * OK for objp to be NULL here. If the 523 * user did not specify a target name, 524 * one will be generated. 525 */ 526 ret = create_target(objp, proplist); 527 } 528 break; 529 case MODIFY_TGT: 530 ret = modify_target(objp, targetname, proplist); 531 break; 532 case DELETE_TGT: 533 ret = delete_target(objp, force); 534 break; 535 case LIST_TGT: 536 ret = list_target(objp, verbose, scripting); 537 break; 538 case CREATE_TPG: 539 ret = create_tpg(objp, newargc - 1, &(newargv[1])); 540 break; 541 case DELETE_TPG: 542 ret = delete_tpg(objp, force); 543 break; 544 case LIST_TPG: 545 ret = list_tpg(objp, verbose, scripting); 546 break; 547 case CREATE_INI: 548 ret = modify_initiator(objp, proplist, B_TRUE); 549 break; 550 case MODIFY_INI: 551 ret = modify_initiator(objp, proplist, B_FALSE); 552 break; 553 case LIST_INI: 554 ret = list_initiator(objp, verbose, scripting); 555 break; 556 case DELETE_INI: 557 ret = delete_initiator(objp); 558 break; 559 case MODIFY_DEF: 560 ret = modify_defaults(proplist); 561 break; 562 case LIST_DEF: 563 ret = list_defaults(scripting); 564 break; 565 default: 566 ret = 1; 567 goto usage_error; 568 } 569 570 if (ret != 0) { 571 (void) fprintf(stderr, 572 gettext("itadm %s failed with error %d"), 573 subcmds[idx].name, ret); 574 (void) fprintf(stderr, "\n"); 575 } 576 return (ret); 577 578 usage_error: 579 if (subcmds[idx].name) { 580 (void) printf("%s\n", gettext(subcmds[idx].usemsg)); 581 } else { 582 /* overall usage */ 583 (void) printf("%s\n\n", gettext("itadm usage:")); 584 for (idx = 0; subcmds[idx].name != NULL; idx++) { 585 if (!subcmds[idx].usemsg) { 586 continue; 587 } 588 (void) printf("\t%s\n", gettext(subcmds[idx].usemsg)); 589 } 590 } 591 592 return (ret); 593 } 594 595 static int 596 create_target(char *tgt, nvlist_t *proplist) 597 { 598 int ret; 599 it_config_t *cfg = NULL; 600 it_tgt_t *tgtp; 601 char **tags = NULL; 602 uint32_t count = 0; 603 nvlist_t *errlist = NULL; 604 int i; 605 it_tpg_t *tpg = NULL; 606 uint16_t tagid = 0; 607 it_tpgt_t *tpgt; 608 char *sec = "solaris.smf.modify.stmf"; 609 610 ITADM_CHKAUTH(sec); 611 612 if (tgt) { 613 /* 614 * validate input name - what are the rules for EUI 615 * and IQN values? 616 */ 617 if ((strncmp(tgt, "eui.", 4) != 0) && 618 (strncmp(tgt, "iqn.", 4) != 0)) { 619 (void) fprintf(stderr, gettext("Invalid name %s"), 620 tgt); 621 (void) fprintf(stderr, "\n"); 622 return (EINVAL); 623 } 624 } 625 626 ret = it_config_load(&cfg); 627 if (ret != 0) { 628 (void) fprintf(stderr, 629 gettext("Error retrieving iSCSI target configuration: %d"), 630 ret); 631 (void) fprintf(stderr, "\n"); 632 return (ret); 633 } 634 635 ret = it_tgt_create(cfg, &tgtp, tgt); 636 if (ret != 0) { 637 if (ret == EFAULT) { 638 (void) fprintf(stderr, 639 gettext("Invalid iSCSI name %s"), tgt); 640 } else if (ret == EEXIST) { 641 (void) fprintf(stderr, 642 gettext("iSCSI target %s already configured"), 643 tgt); 644 } else if (ret == E2BIG) { 645 (void) fprintf(stderr, 646 gettext("Maximum of %d iSCSI targets"), 647 MAX_TARGETS); 648 } else { 649 (void) fprintf(stderr, 650 gettext("Error creating target: %d"), ret); 651 } 652 (void) fprintf(stderr, "\n"); 653 goto done; 654 } 655 656 /* set the target portal group tags */ 657 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags, 658 &count); 659 660 if (ret == ENOENT) { 661 /* none specified. is this ok? */ 662 ret = 0; 663 } else if (ret != 0) { 664 (void) fprintf(stderr, 665 gettext("internal error: %d"), ret); 666 (void) fprintf(stderr, "\n"); 667 goto done; 668 } 669 670 /* special case, don't set any TPGs */ 671 if (tags && (strcmp("default", tags[0]) == 0)) { 672 count = 0; 673 } 674 675 for (i = 0; i < count; i++) { 676 if (!tags[i]) { 677 continue; 678 } 679 680 /* see that all referenced groups are already defined */ 681 tpg = cfg->config_tpg_list; 682 while (tpg != NULL) { 683 if (strcmp(tags[i], tpg->tpg_name) == 0) { 684 break; 685 } 686 687 tpg = tpg->tpg_next; 688 } 689 if (tpg == NULL) { 690 (void) fprintf(stderr, 691 gettext("Invalid tpg-tag %s, tag not defined"), 692 tags[i]); 693 (void) fprintf(stderr, "\n"); 694 ret = 1; 695 goto done; 696 } 697 698 /* generate the tag number to use */ 699 tag_name_to_num(tags[i], &tagid); 700 701 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid); 702 if (ret != 0) { 703 (void) fprintf(stderr, 704 gettext("Could not add target portal group" 705 "tag %s, error %d"), tags[i], ret); 706 (void) fprintf(stderr, "\n"); 707 goto done; 708 } 709 tagid++; 710 } 711 712 /* remove the tags from the proplist before continuing */ 713 if (tags) { 714 (void) nvlist_remove_all(proplist, "tpg-tag"); 715 } 716 717 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist); 718 if (ret != 0) { 719 (void) fprintf(stderr, 720 gettext("Error setting target properties, %d"), ret); 721 (void) fprintf(stderr, "\n"); 722 if (errlist) { 723 nvpair_t *nvp = NULL; 724 char *nn; 725 char *nv; 726 727 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 728 != NULL) { 729 nv = NULL; 730 731 nn = nvpair_name(nvp); 732 (void) nvpair_value_string(nvp, &nv); 733 734 if (nv != NULL) { 735 (void) fprintf(stderr, "\t%s: %s\n", 736 nn, nv); 737 } 738 } 739 740 nvlist_free(errlist); 741 } 742 goto done; 743 } 744 745 if (ret == 0) { 746 ret = it_config_commit(cfg); 747 STMF_STALE(ret); 748 } 749 750 done: 751 if (ret == 0) { 752 (void) printf(gettext("Target %s successfully created"), 753 tgtp->tgt_name); 754 (void) printf("\n"); 755 } 756 757 it_config_free(cfg); 758 759 return (ret); 760 } 761 762 int 763 list_target(char *tgt, boolean_t verbose, boolean_t script) 764 { 765 int ret; 766 it_config_t *cfg; 767 it_tgt_t *ptr; 768 boolean_t found = B_FALSE; 769 boolean_t first = B_TRUE; 770 boolean_t first_tag = B_TRUE; 771 char *gauth = "none"; 772 char *galias = "-"; 773 char *auth; 774 char *alias; 775 char *chapu; 776 char *chaps; 777 it_tpgt_t *tagp; 778 char *sec = "solaris.smf.read.stmf"; 779 stmfDevid devid; 780 stmfSessionList *sess = NULL; 781 stmfTargetProperties props; 782 char *state; 783 int num_sessions; 784 785 ITADM_CHKAUTH(sec); 786 787 ret = it_config_load(&cfg); 788 if (ret != 0) { 789 (void) fprintf(stderr, 790 gettext("Error retrieving iSCSI target configuration: %d"), 791 ret); 792 (void) fprintf(stderr, "\n"); 793 return (ret); 794 } 795 796 ptr = cfg->config_tgt_list; 797 798 /* grab global defaults for auth, alias */ 799 if (cfg->config_global_properties) { 800 (void) nvlist_lookup_string(cfg->config_global_properties, 801 "alias", &galias); 802 (void) nvlist_lookup_string(cfg->config_global_properties, 803 "auth", &gauth); 804 } 805 806 for (; ptr != NULL; ptr = ptr->tgt_next) { 807 if (found) { 808 break; 809 } 810 811 if (tgt) { 812 if (strcmp(tgt, ptr->tgt_name) != 0) { 813 continue; 814 } else { 815 found = B_TRUE; 816 } 817 } 818 819 state = "-"; 820 num_sessions = 0; 821 sess = NULL; 822 823 /* 824 * make a best effort to retrieve target status and 825 * number of active sessions from STMF. 826 */ 827 ret = stmfDevidFromIscsiName(ptr->tgt_name, &devid); 828 if (ret == STMF_STATUS_SUCCESS) { 829 ret = stmfGetTargetProperties(&devid, &props); 830 if (ret == STMF_STATUS_SUCCESS) { 831 if (props.status == STMF_TARGET_PORT_ONLINE) { 832 state = "online"; 833 } else { 834 state = "offline"; 835 } 836 } 837 } 838 if (ret == STMF_STATUS_SUCCESS) { 839 ret = stmfGetSessionList(&devid, &sess); 840 if (ret == STMF_STATUS_SUCCESS) { 841 num_sessions = sess->cnt; 842 free(sess); 843 } 844 } 845 846 /* reset ret so we don't return an error */ 847 ret = 0; 848 849 if (!script && first) { 850 (void) printf("%-61s%-9s%-9s\n", "TARGET NAME", 851 "STATE", "SESSIONS"); 852 first = B_FALSE; 853 } 854 855 if (!script) { 856 /* 857 * try not to let columns run into each other. 858 * Stick a tab after too-long fields. 859 * Lengths chosen are for the 'common' cases. 860 */ 861 (void) printf("%-61s", ptr->tgt_name); 862 if (strlen(ptr->tgt_name) > 60) { 863 (void) printf("\t"); 864 } 865 (void) printf("%-9s%-9d", state, num_sessions); 866 } else { 867 (void) printf("%s\t%s\t%d", ptr->tgt_name, 868 state, num_sessions); 869 } 870 871 if (!verbose) { 872 (void) printf("\n"); 873 continue; 874 } 875 876 auth = gauth; 877 alias = galias; 878 chapu = "-"; 879 chaps = "unset"; 880 881 if (ptr->tgt_properties) { 882 (void) nvlist_lookup_string(ptr->tgt_properties, 883 "auth", &auth); 884 (void) nvlist_lookup_string(ptr->tgt_properties, 885 "alias", &alias); 886 if (nvlist_exists(ptr->tgt_properties, 887 "targetchapsecret")) { 888 chaps = "set"; 889 } 890 (void) nvlist_lookup_string(ptr->tgt_properties, 891 "targetchapuser", &chapu); 892 } 893 894 if (!script) { 895 (void) printf("\n\t%-20s\t%s\n\t%-20s\t%s %s\n" 896 "\t%-20s\t%s\n\t%-20s\t%s\n\t%-20s\t", 897 "alias:", alias, "auth:", auth, 898 ((auth == gauth) ? "(defaults)" : ""), 899 "targetchapuser:", 900 chapu, "targetchapsecret:", chaps, "tpg-tags:"); 901 } else { 902 (void) printf("\t%s\t%s %s\t%s\t%s\t", 903 alias, auth, 904 ((auth == gauth) ? "(defaults)" : ""), 905 chapu, chaps); 906 } 907 908 first_tag = B_TRUE; 909 tagp = ptr->tgt_tpgt_list; 910 for (; tagp != NULL; tagp = tagp->tpgt_next) { 911 if (!first_tag) { 912 (void) printf(","); 913 } else { 914 first_tag = B_FALSE; 915 } 916 (void) printf("%s = %d", 917 tagp->tpgt_tpg_name, tagp->tpgt_tag); 918 } 919 920 if (first_tag) { 921 /* didn't find any */ 922 (void) printf("default"); 923 } 924 925 (void) printf("\n"); 926 } 927 928 if (tgt && (!found)) { 929 (void) fprintf(stderr, 930 gettext("Target %s not found!\n"), tgt); 931 (void) fprintf(stderr, "\n"); 932 ret = 1; 933 } 934 935 it_config_free(cfg); 936 937 return (ret); 938 } 939 940 int 941 delete_target(char *tgt, boolean_t force) 942 { 943 int ret; 944 it_config_t *cfg; 945 it_tgt_t *ptr; 946 char *sec = "solaris.smf.modify.stmf"; 947 948 ITADM_CHKAUTH(sec); 949 950 if (!tgt) { 951 (void) fprintf(stderr, "%s\n", 952 gettext("Error, no target specified")); 953 return (EINVAL); 954 } 955 956 ret = it_config_load(&cfg); 957 if (ret != 0) { 958 (void) fprintf(stderr, 959 gettext("Error retrieving iSCSI target configuration: %d"), 960 ret); 961 (void) fprintf(stderr, "\n"); 962 return (ret); 963 } 964 965 ptr = cfg->config_tgt_list; 966 while (ptr) { 967 if (strcmp(ptr->tgt_name, tgt) == 0) { 968 break; 969 } 970 971 ptr = ptr->tgt_next; 972 } 973 974 if (ptr) { 975 ret = it_tgt_delete(cfg, ptr, force); 976 977 if (ret != 0) { 978 if (ret == EBUSY) { 979 (void) fprintf(stderr, 980 gettext("The target is online or busy. " 981 "Use the -f (force) option, or " 982 "'stmfadm offline-target %s'"), tgt); 983 (void) fprintf(stderr, "\n"); 984 } 985 } 986 987 if (ret == 0) { 988 ret = it_config_commit(cfg); 989 STMF_STALE(ret); 990 } 991 } else { 992 (void) fprintf(stderr, 993 gettext("Target %s not found"), tgt); 994 (void) fprintf(stderr, "\n"); 995 ret = 1; 996 } 997 998 it_config_free(cfg); 999 1000 return (ret); 1001 } 1002 1003 static int 1004 modify_target(char *tgt, char *newname, nvlist_t *proplist) 1005 { 1006 int ret; 1007 it_config_t *cfg = NULL; 1008 it_tgt_t *ptr = NULL; 1009 it_tgt_t *tgtp = NULL; 1010 char **tags = NULL; 1011 uint32_t count = 0; 1012 nvlist_t *errlist = NULL; 1013 int i; 1014 it_tpg_t *tpg = NULL; 1015 uint16_t tagid; 1016 it_tpgt_t *tpgt = NULL; 1017 char *sec = "solaris.smf.modify.stmf"; 1018 1019 ITADM_CHKAUTH(sec); 1020 1021 /* XXX: Do we need to offline anything here too? */ 1022 1023 if (!tgt) { 1024 (void) fprintf(stderr, "%s\n", 1025 gettext("Error, no target specified")); 1026 return (EINVAL); 1027 } 1028 1029 ret = it_config_load(&cfg); 1030 if (ret != 0) { 1031 (void) fprintf(stderr, 1032 gettext("Error retrieving iSCSI target configuration: %d"), 1033 ret); 1034 (void) fprintf(stderr, "\n"); 1035 return (ret); 1036 } 1037 1038 /* 1039 * If newname is specified, ensure it is a valid name 1040 */ 1041 if (newname) { 1042 if (!validate_iscsi_name(newname)) { 1043 (void) fprintf(stderr, 1044 gettext("Invalid iSCSI name %s"), newname); 1045 (void) fprintf(stderr, "\n"); 1046 return (1); 1047 } 1048 } 1049 1050 /* 1051 * Loop through to verify that the target to be modified truly 1052 * exists. If this target is to be renamed, ensure the new 1053 * name is not already in use. 1054 */ 1055 ptr = cfg->config_tgt_list; 1056 while (ptr) { 1057 if (newname && (strcmp(newname, ptr->tgt_name) == 0)) { 1058 (void) fprintf(stderr, 1059 gettext("A target with name %s already exists"), 1060 newname); 1061 (void) fprintf(stderr, "\n"); 1062 ret = 1; 1063 goto done; 1064 } 1065 1066 if (strcmp(ptr->tgt_name, tgt) == 0) { 1067 tgtp = ptr; 1068 } 1069 1070 ptr = ptr ->tgt_next; 1071 } 1072 1073 if (!tgtp) { 1074 (void) fprintf(stderr, 1075 gettext("Target %s not found"), tgt); 1076 (void) fprintf(stderr, "\n"); 1077 it_config_free(cfg); 1078 return (EINVAL); 1079 } 1080 1081 /* set the target portal group tags */ 1082 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags, 1083 &count); 1084 1085 if (ret == ENOENT) { 1086 /* none specified. is this ok? */ 1087 ret = 0; 1088 } else if (ret != 0) { 1089 (void) fprintf(stderr, 1090 gettext("internal error: %d"), ret); 1091 (void) fprintf(stderr, "\n"); 1092 goto done; 1093 } 1094 1095 /* special case, remove all explicit TPGs, and don't add any */ 1096 if (tags && (strcmp("default", tags[0]) == 0)) { 1097 count = 0; 1098 } 1099 1100 for (i = 0; i < count; i++) { 1101 if (!tags[i]) { 1102 continue; 1103 } 1104 1105 /* see that all referenced groups are already defined */ 1106 tpg = cfg->config_tpg_list; 1107 while (tpg != NULL) { 1108 if (strcmp(tags[i], tpg->tpg_name) == 0) { 1109 break; 1110 } 1111 tpg = tpg->tpg_next; 1112 } 1113 if (tpg == NULL) { 1114 (void) fprintf(stderr, 1115 gettext("Invalid tpg-name %s: not defined"), 1116 tags[i]); 1117 (void) fprintf(stderr, "\n"); 1118 ret = 1; 1119 goto done; 1120 } 1121 } 1122 1123 /* 1124 * don't recreate tags that are already associated, 1125 * remove tags not requested. 1126 */ 1127 if (tags) { 1128 tpgt = tgtp->tgt_tpgt_list; 1129 while (tpgt) { 1130 for (i = 0; i < count; i++) { 1131 if (!tags[i]) { 1132 continue; 1133 } 1134 1135 if (strcmp(tpgt->tpgt_tpg_name, tags[i]) 1136 == 0) { 1137 /* non-null tags will be created */ 1138 tags[i] = NULL; 1139 break; 1140 } 1141 } 1142 if (i == count) { 1143 /* one to remove */ 1144 it_tpgt_t *ptr = tpgt; 1145 1146 tpgt = ptr->tpgt_next; 1147 it_tpgt_delete(cfg, tgtp, ptr); 1148 } else { 1149 tpgt = tpgt->tpgt_next; 1150 } 1151 } 1152 } 1153 1154 /* see if there are any left to add */ 1155 for (i = 0; i < count; i++) { 1156 if (!tags[i]) { 1157 continue; 1158 } 1159 1160 /* generate the tag number to use */ 1161 tag_name_to_num(tags[i], &tagid); 1162 1163 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid); 1164 if (ret != 0) { 1165 if (ret == E2BIG) { 1166 (void) fprintf(stderr, "%s\n", 1167 gettext("Error, no portal tag available")); 1168 } else { 1169 (void) fprintf(stderr, gettext( 1170 "Could not add target portal group" 1171 " tag %s, error %d"), tags[i], ret); 1172 (void) fprintf(stderr, "\n"); 1173 } 1174 goto done; 1175 } 1176 } 1177 1178 /* remove the tags from the proplist before continuing */ 1179 (void) nvlist_remove_all(proplist, "tpg-tag"); 1180 1181 /* 1182 * Rename this target, if requested. Save the old name in 1183 * the property list, so the kernel knows this is a renamed 1184 * target, and not a new one. 1185 */ 1186 if (newname && (strlen(newname) > 0)) { 1187 ret = nvlist_add_string(proplist, "oldtargetname", 1188 tgtp->tgt_name); 1189 if (ret != 0) { 1190 (void) fprintf(stderr, "%s\n", 1191 gettext("Error renaming target.")); 1192 goto done; 1193 } 1194 (void) strlcpy(tgtp->tgt_name, newname, 1195 sizeof (tgtp->tgt_name)); 1196 } 1197 1198 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist); 1199 if (ret != 0) { 1200 (void) fprintf(stderr, 1201 gettext("Error setting target properties: %d"), ret); 1202 (void) fprintf(stderr, "\n"); 1203 if (errlist) { 1204 nvpair_t *nvp = NULL; 1205 char *nn; 1206 char *nv; 1207 1208 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1209 != NULL) { 1210 nv = NULL; 1211 1212 nn = nvpair_name(nvp); 1213 (void) nvpair_value_string(nvp, &nv); 1214 1215 if (nv != NULL) { 1216 (void) fprintf(stderr, "\t%s: %s\n", 1217 nn, nv); 1218 } 1219 } 1220 1221 nvlist_free(errlist); 1222 } 1223 goto done; 1224 } 1225 1226 if (ret == 0) { 1227 ret = it_config_commit(cfg); 1228 STMF_STALE(ret); 1229 } 1230 1231 done: 1232 if (ret == 0) { 1233 (void) printf(gettext("Target %s successfully modified"), 1234 tgtp->tgt_name); 1235 (void) printf("\n"); 1236 } 1237 1238 it_config_free(cfg); 1239 1240 return (ret); 1241 } 1242 1243 int 1244 create_tpg(char *tpg, int addrc, char **addrs) 1245 { 1246 int ret; 1247 it_config_t *cfg; 1248 it_tpg_t *tpgp; 1249 int count = 0; 1250 it_portal_t *ptl; 1251 char *sec = "solaris.smf.modify.stmf"; 1252 int i = 0; 1253 1254 ITADM_CHKAUTH(sec); 1255 1256 if (!tpg) { 1257 (void) fprintf(stderr, "%s\n", 1258 gettext("Error, no target portal group specified")); 1259 return (EINVAL); 1260 } 1261 1262 if (strlen(tpg) > (MAX_TPG_NAMELEN - 1)) { 1263 (void) fprintf(stderr, 1264 gettext("Target Portal Group name must be no longer " 1265 "than %d characters."), (MAX_TPG_NAMELEN - 1)); 1266 (void) fprintf(stderr, "\n"); 1267 return (EINVAL); 1268 } 1269 1270 if (!addrs || (addrc <= 0)) { 1271 (void) fprintf(stderr, "%s\n", 1272 gettext("Error, no portal addresses specified")); 1273 return (EINVAL); 1274 } 1275 1276 ret = it_config_load(&cfg); 1277 if (ret != 0) { 1278 (void) fprintf(stderr, 1279 gettext("Error retrieving iSCSI target configuration: %d"), 1280 ret); 1281 (void) fprintf(stderr, "\n"); 1282 return (ret); 1283 } 1284 1285 tpgp = cfg->config_tpg_list; 1286 while (tpgp != NULL) { 1287 if (strcmp(tpgp->tpg_name, tpg) == 0) { 1288 (void) fprintf(stderr, 1289 gettext("Target Portal Group %s already exists"), 1290 tpg); 1291 (void) fprintf(stderr, "\n"); 1292 it_config_free(cfg); 1293 return (1); 1294 } 1295 tpgp = tpgp->tpg_next; 1296 } 1297 1298 /* 1299 * Ensure that the addrs don't contain commas. 1300 */ 1301 for (i = 0; i < addrc; i++) { 1302 if (strchr(addrs[i], ',')) { 1303 (void) fprintf(stderr, 1304 gettext("Bad portal name %s"), 1305 addrs[i]); 1306 (void) fprintf(stderr, "\n"); 1307 1308 it_config_free(cfg); 1309 return (EINVAL); 1310 } 1311 } 1312 1313 /* 1314 * Create the portal group and first portal 1315 */ 1316 ret = it_tpg_create(cfg, &tpgp, tpg, addrs[count]); 1317 if (ret != 0) { 1318 if (ret == EEXIST) { 1319 (void) fprintf(stderr, 1320 gettext("Portal %s already in use"), 1321 addrs[count]); 1322 (void) fprintf(stderr, "\n"); 1323 } 1324 it_config_free(cfg); 1325 return (ret); 1326 } 1327 1328 /* 1329 * Add the remaining portals 1330 */ 1331 for (count = 1; count < addrc; count++) { 1332 if (!addrs[count]) { 1333 continue; 1334 } 1335 1336 ret = it_portal_create(cfg, tpgp, &ptl, addrs[count]); 1337 if (ret != 0) { 1338 if (ret == EEXIST) { 1339 (void) fprintf(stderr, 1340 gettext("Portal %s already in use"), 1341 addrs[count]); 1342 (void) fprintf(stderr, "\n"); 1343 } else { 1344 (void) fprintf(stderr, 1345 gettext("Error adding portal %s: %d"), 1346 addrs[count], ret); 1347 (void) fprintf(stderr, "\n"); 1348 break; 1349 } 1350 } 1351 } 1352 1353 if (ret == 0) { 1354 ret = it_config_commit(cfg); 1355 STMF_STALE(ret); 1356 } 1357 1358 it_config_free(cfg); 1359 1360 return (ret); 1361 } 1362 1363 static int 1364 list_tpg(char *tpg, boolean_t verbose, boolean_t script) 1365 { 1366 int ret; 1367 it_config_t *cfg; 1368 it_tpg_t *ptr; 1369 boolean_t found = B_FALSE; 1370 it_portal_t *portal; 1371 boolean_t first = B_TRUE; 1372 boolean_t first_portal; 1373 char *pstr; 1374 char *sec = "solaris.smf.read.stmf"; 1375 1376 ITADM_CHKAUTH(sec); 1377 1378 ret = it_config_load(&cfg); 1379 if (ret != 0) { 1380 (void) fprintf(stderr, 1381 gettext("Error retrieving iSCSI target configuration: %d"), 1382 ret); 1383 (void) fprintf(stderr, "\n"); 1384 return (ret); 1385 } 1386 1387 ptr = cfg->config_tpg_list; 1388 1389 for (; ptr != NULL; ptr = ptr->tpg_next) { 1390 if (found) { 1391 break; 1392 } 1393 1394 if (tpg) { 1395 if (strcmp(tpg, ptr->tpg_name) != 0) { 1396 continue; 1397 } else { 1398 found = B_TRUE; 1399 } 1400 } 1401 1402 if (!script && first) { 1403 (void) printf("%-30s%-9s\n", "TARGET PORTAL GROUP", 1404 "PORTAL COUNT"); 1405 first = B_FALSE; 1406 } 1407 1408 if (!script) { 1409 (void) printf("%-30s", ptr->tpg_name); 1410 if (strlen(ptr->tpg_name) > 30) { 1411 (void) printf("\t"); 1412 } 1413 (void) printf("%-9d", ptr->tpg_portal_count); 1414 } else { 1415 (void) printf("%s\t%d", ptr->tpg_name, 1416 ptr->tpg_portal_count); 1417 } 1418 1419 if (!verbose) { 1420 (void) printf("\n"); 1421 continue; 1422 } 1423 1424 if (!script) { 1425 (void) printf("\n portals:"); 1426 } 1427 1428 first_portal = B_TRUE; 1429 1430 portal = ptr->tpg_portal_list; 1431 for (; portal != NULL; portal = portal->next) { 1432 ret = sockaddr_to_str(&(portal->portal_addr), &pstr); 1433 if (ret != 0) { 1434 /* invalid addr? */ 1435 continue; 1436 } 1437 if (!first_portal) { 1438 (void) printf(","); 1439 } else { 1440 (void) printf("\t"); 1441 first_portal = B_FALSE; 1442 } 1443 1444 (void) printf("%s", pstr); 1445 free(pstr); 1446 } 1447 1448 if (first_portal) { 1449 /* none found */ 1450 (void) printf("\t<none>"); 1451 } 1452 1453 (void) printf("\n"); 1454 } 1455 1456 if (tpg && (!found)) { 1457 (void) fprintf(stderr, 1458 gettext("Target Portal Group %s not found!\n"), tpg); 1459 (void) fprintf(stderr, "\n"); 1460 ret = 1; 1461 } 1462 1463 it_config_free(cfg); 1464 1465 return (ret); 1466 } 1467 1468 static int 1469 delete_tpg(char *tpg, boolean_t force) 1470 { 1471 int ret; 1472 it_config_t *cfg; 1473 it_tpg_t *ptpg = NULL; 1474 char *sec = "solaris.smf.modify.stmf"; 1475 1476 ITADM_CHKAUTH(sec); 1477 1478 if (!tpg) { 1479 (void) fprintf(stderr, "%s\n", 1480 gettext("Error, no target portal group specified")); 1481 return (EINVAL); 1482 } 1483 1484 ret = it_config_load(&cfg); 1485 if (ret != 0) { 1486 (void) fprintf(stderr, 1487 gettext("Error retrieving iSCSI target configuration: %d"), 1488 ret); 1489 (void) fprintf(stderr, "\n"); 1490 return (ret); 1491 } 1492 1493 ptpg = cfg->config_tpg_list; 1494 for (; ptpg != NULL; ptpg = ptpg->tpg_next) { 1495 if (strcmp(tpg, ptpg->tpg_name) == 0) { 1496 break; 1497 } 1498 } 1499 1500 if (!ptpg) { 1501 (void) fprintf(stderr, 1502 gettext("Target portal group %s does not exist."), 1503 tpg); 1504 (void) fprintf(stderr, "\n"); 1505 ret = 1; 1506 } else { 1507 ret = it_tpg_delete(cfg, ptpg, force); 1508 if (ret == EBUSY) { 1509 (void) fprintf(stderr, "%s\n", 1510 gettext( 1511 "Target portal group associated with one or more " 1512 "targets. Cannot delete.")); 1513 } 1514 1515 if (ret == 0) { 1516 ret = it_config_commit(cfg); 1517 STMF_STALE(ret); 1518 } 1519 } 1520 1521 it_config_free(cfg); 1522 1523 return (ret); 1524 } 1525 1526 static int 1527 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create) 1528 { 1529 int ret; 1530 it_config_t *cfg; 1531 it_ini_t *inip; 1532 nvlist_t *errlist = NULL; 1533 nvpair_t *nvp = NULL; 1534 char *sec = "solaris.smf.modify.stmf"; 1535 boolean_t changed = B_TRUE; 1536 1537 ITADM_CHKAUTH(sec); 1538 1539 if (!ini) { 1540 (void) fprintf(stderr, "%s\n", 1541 gettext("Error, no initiator specified")); 1542 return (EINVAL); 1543 } else if (create) { 1544 /* 1545 * validate input name - what are the rules for EUI 1546 * and IQN values? 1547 */ 1548 if ((strncmp(ini, "eui.", 4) != 0) && 1549 (strncmp(ini, "iqn.", 4) != 0)) { 1550 (void) fprintf(stderr, gettext("Invalid name %s"), 1551 ini); 1552 (void) fprintf(stderr, "\n"); 1553 return (EINVAL); 1554 } 1555 } 1556 1557 /* 1558 * See if any properties were actually specified. 1559 */ 1560 if (proplist) { 1561 nvp = nvlist_next_nvpair(proplist, nvp); 1562 } 1563 1564 if ((nvp == NULL) && !create) { 1565 changed = B_FALSE; 1566 } 1567 1568 /* 1569 * If no properties, and this is really a modify op, verify 1570 * that the requested initiator exists, but then don't do anything. 1571 * Modifying non-existent is an error; doing nothing to a defined 1572 * initiator is not. 1573 */ 1574 1575 ret = it_config_load(&cfg); 1576 if (ret != 0) { 1577 (void) fprintf(stderr, 1578 gettext("Error retrieving iSCSI target configuration: %d"), 1579 ret); 1580 (void) fprintf(stderr, "\n"); 1581 return (ret); 1582 } 1583 1584 inip = cfg->config_ini_list; 1585 while (inip) { 1586 if (strcmp(inip->ini_name, ini) == 0) { 1587 break; 1588 } 1589 1590 inip = inip->ini_next; 1591 } 1592 1593 if (create) { 1594 if (inip) { 1595 (void) fprintf(stderr, 1596 gettext("Initiator %s already exists"), 1597 inip->ini_name); 1598 (void) fprintf(stderr, "\n"); 1599 ret = EINVAL; 1600 } else { 1601 ret = it_ini_create(cfg, &inip, ini); 1602 if (ret != 0) { 1603 if (ret == EFAULT) { 1604 (void) fprintf(stderr, 1605 gettext("Invalid iSCSI name %s"), 1606 ini); 1607 } else { 1608 (void) fprintf(stderr, 1609 gettext( 1610 "Error creating initiator: %d"), 1611 ret); 1612 } 1613 (void) fprintf(stderr, "\n"); 1614 } 1615 } 1616 } else if (!inip) { 1617 ret = ENOENT; 1618 (void) fprintf(stderr, 1619 gettext("Error, initiator %s not found."), 1620 ini); 1621 (void) fprintf(stderr, "\n"); 1622 } 1623 1624 if ((ret == 0) && nvp) { 1625 ret = it_ini_setprop(inip, proplist, &errlist); 1626 1627 if (ret != 0) { 1628 (void) fprintf(stderr, 1629 gettext("Error setting initiator properties: %d"), 1630 ret); 1631 (void) fprintf(stderr, "\n"); 1632 if (errlist) { 1633 nvpair_t *nvp = NULL; 1634 char *nn; 1635 char *nv; 1636 1637 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1638 != NULL) { 1639 nv = NULL; 1640 1641 nn = nvpair_name(nvp); 1642 (void) nvpair_value_string(nvp, &nv); 1643 1644 if (nv != NULL) { 1645 (void) fprintf(stderr, 1646 "\t%s: %s\n", nn, nv); 1647 } 1648 } 1649 1650 nvlist_free(errlist); 1651 } 1652 } 1653 } 1654 1655 if ((ret == 0) && changed) { 1656 ret = it_config_commit(cfg); 1657 STMF_STALE(ret); 1658 } 1659 1660 it_config_free(cfg); 1661 1662 return (ret); 1663 } 1664 1665 static int 1666 list_initiator(char *ini, boolean_t verbose, boolean_t script) /* ARGSUSED */ 1667 { 1668 int ret; 1669 it_config_t *cfg; 1670 it_ini_t *ptr; 1671 boolean_t found = B_FALSE; 1672 boolean_t first = B_TRUE; 1673 char *isecret; 1674 char *iuser; 1675 char *sec = "solaris.smf.read.stmf"; 1676 1677 ITADM_CHKAUTH(sec); 1678 1679 ret = it_config_load(&cfg); 1680 if (ret != 0) { 1681 (void) fprintf(stderr, 1682 gettext("Error retrieving iSCSI target configuration: %d"), 1683 ret); 1684 (void) fprintf(stderr, "\n"); 1685 return (ret); 1686 } 1687 1688 ptr = cfg->config_ini_list; 1689 1690 for (; ptr != NULL; ptr = ptr->ini_next) { 1691 isecret = "unset"; 1692 iuser = "<none>"; 1693 1694 if (found) { 1695 break; 1696 } 1697 1698 if (ini) { 1699 if (strcmp(ini, ptr->ini_name) != 0) { 1700 continue; 1701 } else { 1702 found = B_TRUE; 1703 } 1704 } 1705 1706 if (ptr->ini_properties) { 1707 if (nvlist_exists(ptr->ini_properties, "chapsecret")) { 1708 isecret = "set"; 1709 } 1710 (void) nvlist_lookup_string(ptr->ini_properties, 1711 "chapuser", &iuser); 1712 1713 } 1714 1715 /* there's nothing to print for verbose yet */ 1716 if (!script && first) { 1717 (void) printf("%-61s%-10s%-7s\n", "INITIATOR NAME", 1718 "CHAPUSER", "SECRET"); 1719 first = B_FALSE; 1720 } 1721 1722 if (!script) { 1723 /* 1724 * try not to let columns run into each other. 1725 * Stick a tab after too-long fields. 1726 * Lengths chosen are for the 'common' cases. 1727 */ 1728 (void) printf("%-61s", ptr->ini_name); 1729 1730 if (strlen(ptr->ini_name) > 60) { 1731 (void) printf("\t"); 1732 } 1733 1734 (void) printf("%-15s", iuser); 1735 if (strlen(iuser) >= 15) { 1736 (void) printf("\t"); 1737 } 1738 1739 (void) printf("%-4s", isecret); 1740 } else { 1741 (void) printf("%s\t%s\t%s", ptr->ini_name, 1742 iuser, isecret); 1743 } 1744 1745 (void) printf("\n"); 1746 } 1747 1748 if (ini && (!found)) { 1749 (void) fprintf(stderr, 1750 gettext("Initiator %s not found!"), ini); 1751 (void) fprintf(stderr, "\n"); 1752 ret = 1; 1753 } 1754 1755 it_config_free(cfg); 1756 1757 return (ret); 1758 } 1759 1760 int 1761 delete_initiator(char *ini) 1762 { 1763 int ret; 1764 it_config_t *cfg; 1765 it_ini_t *ptr; 1766 char *sec = "solaris.smf.modify.stmf"; 1767 1768 ITADM_CHKAUTH(sec); 1769 1770 if (!ini) { 1771 (void) fprintf(stderr, "%s\n", 1772 gettext("Error, no initiator specified")); 1773 return (EINVAL); 1774 } 1775 1776 ret = it_config_load(&cfg); 1777 if (ret != 0) { 1778 (void) fprintf(stderr, 1779 gettext("Error retrieving iSCSI target configuration: %d"), 1780 ret); 1781 (void) fprintf(stderr, "\n"); 1782 return (ret); 1783 } 1784 1785 ptr = cfg->config_ini_list; 1786 while (ptr) { 1787 if (strcmp(ptr->ini_name, ini) == 0) { 1788 break; 1789 } 1790 1791 ptr = ptr->ini_next; 1792 } 1793 1794 if (ptr) { 1795 it_ini_delete(cfg, ptr); 1796 1797 ret = it_config_commit(cfg); 1798 STMF_STALE(ret); 1799 } else { 1800 (void) fprintf(stderr, 1801 gettext("Initiator %s not found"), ini); 1802 (void) fprintf(stderr, "\n"); 1803 ret = 1; 1804 } 1805 1806 return (ret); 1807 } 1808 1809 static int 1810 modify_defaults(nvlist_t *proplist) 1811 { 1812 int ret; 1813 it_config_t *cfg; 1814 nvlist_t *errlist = NULL; 1815 nvpair_t *nvp = NULL; 1816 char *sec = "solaris.smf.modify.stmf"; 1817 1818 ITADM_CHKAUTH(sec); 1819 1820 if (proplist) { 1821 /* make sure at least one property is specified */ 1822 nvp = nvlist_next_nvpair(proplist, nvp); 1823 } 1824 1825 if (nvp == NULL) { 1826 /* empty list */ 1827 (void) fprintf(stderr, "%s\n", 1828 gettext("Error, no properties specified")); 1829 return (EINVAL); 1830 } 1831 1832 ret = it_config_load(&cfg); 1833 if (ret != 0) { 1834 (void) fprintf(stderr, 1835 gettext("Error retrieving iSCSI target configuration: %d"), 1836 ret); 1837 (void) fprintf(stderr, "\n"); 1838 return (ret); 1839 } 1840 1841 ret = it_config_setprop(cfg, proplist, &errlist); 1842 if (ret != 0) { 1843 (void) fprintf(stderr, 1844 gettext("Error setting global properties: %d"), 1845 ret); 1846 (void) fprintf(stderr, "\n"); 1847 if (errlist) { 1848 nvpair_t *nvp = NULL; 1849 char *nn; 1850 char *nv; 1851 1852 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1853 != NULL) { 1854 nv = NULL; 1855 1856 nn = nvpair_name(nvp); 1857 (void) nvpair_value_string(nvp, &nv); 1858 1859 if (nv != NULL) { 1860 (void) fprintf(stderr, "\t%s: %s\n", 1861 nn, nv); 1862 } 1863 } 1864 1865 nvlist_free(errlist); 1866 } 1867 } 1868 1869 if (ret == 0) { 1870 ret = it_config_commit(cfg); 1871 STMF_STALE(ret); 1872 } 1873 1874 it_config_free(cfg); 1875 1876 return (ret); 1877 } 1878 1879 static int 1880 list_defaults(boolean_t script) 1881 { 1882 int ret; 1883 it_config_t *cfg; 1884 nvlist_t *nvl; 1885 char *alias = "<none>"; 1886 char *auth = "<none>"; 1887 char *isns = "disabled"; 1888 char **isvrs = NULL; 1889 uint32_t scount = 0; 1890 char *rsvr = "<none>"; 1891 char *rsecret = "unset"; 1892 boolean_t val = B_FALSE; 1893 int i; 1894 char *sec = "solaris.smf.read.stmf"; 1895 1896 ITADM_CHKAUTH(sec); 1897 1898 ret = it_config_load(&cfg); 1899 if (ret != 0) { 1900 (void) fprintf(stderr, 1901 gettext("Error retrieving iSCSI target configuration: %d"), 1902 ret); 1903 (void) fprintf(stderr, "\n"); 1904 return (ret); 1905 } 1906 1907 nvl = cfg->config_global_properties; 1908 1909 /* look up all possible options */ 1910 (void) nvlist_lookup_string(nvl, "alias", &alias); 1911 (void) nvlist_lookup_string(nvl, "auth", &auth); 1912 (void) nvlist_lookup_boolean_value(nvl, "isns", &val); 1913 if (val == B_TRUE) { 1914 isns = "enabled"; 1915 } 1916 (void) nvlist_lookup_string_array(nvl, "isnsserver", &isvrs, 1917 &scount); 1918 (void) nvlist_lookup_string(nvl, "radiusserver", &rsvr); 1919 if (nvlist_exists(nvl, "radiussecret")) { 1920 rsecret = "set"; 1921 } 1922 1923 if (!script) { 1924 (void) printf("%s:\n\n", 1925 gettext("iSCSI Target Default Properties")); 1926 } 1927 1928 if (script) { 1929 (void) printf("%s\t%s\t%s\t%s\t%s\t", 1930 alias, auth, rsvr, rsecret, isns); 1931 } else { 1932 (void) printf("%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n" 1933 "%-15s\t%s\n%-15s\t", 1934 "alias:", alias, "auth:", auth, "radiusserver:", 1935 rsvr, "radiussecret:", rsecret, "isns:", isns, 1936 "isnsserver:"); 1937 } 1938 1939 for (i = 0; i < scount; i++) { 1940 if (!isvrs || !isvrs[i]) { 1941 break; 1942 } 1943 if (i > 0) { 1944 (void) printf(","); 1945 } 1946 (void) printf("%s", isvrs[i]); 1947 } 1948 1949 if (i == 0) { 1950 (void) printf("%s", "<none>"); 1951 } 1952 1953 (void) printf("\n"); 1954 1955 it_config_free(cfg); 1956 1957 return (0); 1958 } 1959 1960 static int 1961 itadm_get_password(nvlist_t *nvl, char *key, char *passfile, 1962 char *phrase) 1963 { 1964 int ret = 0; 1965 char *pass; 1966 char buf[1024]; 1967 int fd; 1968 struct stat64 sbuf; 1969 size_t rd; 1970 1971 if (!nvl || !key) { 1972 return (EINVAL); 1973 } 1974 1975 if (passfile) { 1976 ret = stat64(passfile, &sbuf); 1977 if ((ret != 0) || (!S_ISREG(sbuf.st_mode))) { 1978 (void) fprintf(stderr, 1979 gettext("Invalid secret file %s"), 1980 passfile); 1981 (void) fprintf(stderr, "\n"); 1982 return (EBADF); 1983 } 1984 1985 fd = open64(passfile, O_RDONLY); 1986 if (fd == -1) { 1987 ret = errno; 1988 (void) fprintf(stderr, 1989 gettext("Could not open secret file %s, %d"), 1990 passfile, ret); 1991 (void) fprintf(stderr, "\n"); 1992 return (ret); 1993 } 1994 1995 rd = read(fd, buf, sbuf.st_size); 1996 (void) close(fd); 1997 1998 if (rd != sbuf.st_size) { 1999 ret = EIO; 2000 (void) fprintf(stderr, 2001 gettext("Could not read secret file %s, %d"), 2002 passfile, ret); 2003 (void) fprintf(stderr, "\n"); 2004 return (ret); 2005 } 2006 2007 /* ensure buf is properly terminated */ 2008 buf[rd] = '\0'; 2009 2010 /* if last char is a newline, strip it off */ 2011 if (buf[rd - 1] == '\n') { 2012 buf[rd - 1] = '\0'; 2013 } 2014 2015 /* validate length */ 2016 if ((strlen(buf) > 255) || (strlen(buf) < 12)) { 2017 (void) fprintf(stderr, "%s\n", 2018 gettext( 2019 "Secret must be between 12 and 255 characters")); 2020 return (EINVAL); 2021 } 2022 } else { 2023 /* prompt for secret */ 2024 if (!phrase) { 2025 return (EINVAL); 2026 } 2027 2028 pass = getpassphrase(phrase); 2029 if (!pass) { 2030 ret = errno; 2031 (void) fprintf(stderr, 2032 gettext("Could not read secret, %d"), 2033 ret); 2034 (void) fprintf(stderr, "\n"); 2035 return (ret); 2036 } 2037 2038 /* validate length */ 2039 if ((strlen(pass) > 255) || (strlen(pass) < 12)) { 2040 (void) fprintf(stderr, "%s\n", 2041 gettext( 2042 "Secret must be between 12 and 255 characters")); 2043 return (EINVAL); 2044 } 2045 2046 (void) strlcpy(buf, pass, sizeof (buf)); 2047 2048 /* confirm entered secret */ 2049 pass = getpassphrase(gettext("Re-enter secret: ")); 2050 if (!pass) { 2051 ret = errno; 2052 (void) fprintf(stderr, 2053 gettext("Could not read secret, %d"), 2054 ret); 2055 (void) fprintf(stderr, "\n"); 2056 return (ret); 2057 } 2058 2059 if (strcmp(buf, pass) != 0) { 2060 ret = EINVAL; 2061 (void) fprintf(stderr, "%s\n", 2062 gettext("Secret validation failed")); 2063 return (ret); 2064 } 2065 2066 } 2067 2068 ret = nvlist_add_string(nvl, key, buf); 2069 2070 return (ret); 2071 } 2072 2073 static int 2074 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num) 2075 { 2076 int count; 2077 char *bufp; 2078 char **arr; 2079 2080 if (!opt || !key || !nvl) { 2081 return (EINVAL); 2082 } 2083 2084 bufp = opt; 2085 count = 1; 2086 2087 for (;;) { 2088 bufp = strchr(bufp, ','); 2089 if (!bufp) { 2090 break; 2091 } 2092 bufp++; 2093 count++; 2094 } 2095 2096 arr = calloc(count, sizeof (char *)); 2097 if (!arr) { 2098 return (ENOMEM); 2099 } 2100 2101 bufp = opt; 2102 /* set delimiter to comma */ 2103 (void) bufsplit(",", 0, NULL); 2104 2105 /* split up that buf! */ 2106 (void) bufsplit(bufp, count, arr); 2107 2108 /* if requested, return the number of array members found */ 2109 if (num) { 2110 *num = count; 2111 } 2112 2113 return (nvlist_add_string_array(nvl, key, arr, count)); 2114 } 2115 2116 static void 2117 tag_name_to_num(char *tagname, uint16_t *tagnum) 2118 { 2119 ulong_t id; 2120 char *ptr = NULL; 2121 2122 if (!tagname || !tagnum) { 2123 return; 2124 } 2125 2126 *tagnum = 0; 2127 2128 id = strtoul(tagname, &ptr, 10); 2129 2130 /* Must be entirely numeric and in-range */ 2131 if (ptr && (*ptr != '\0')) { 2132 return; 2133 } 2134 2135 if ((id <= UINT16_MAX) && (id > 1)) { 2136 *tagnum = (uint16_t)id; 2137 } 2138 } 2139