1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #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 /* 468 * XXX - this should probably get pushed down to the library 469 * depending on the decision to allow/disallow configuratoin 470 * without the service running. 471 */ 472 /* 473 * Make sure iSCSI target service is enabled before 474 * proceeding. 475 */ 476 smfstate = smf_get_state(ISCSIT_SVC); 477 if (!smfstate || 478 (strcmp(smfstate, SCF_STATE_STRING_ONLINE) != 0)) { 479 (void) fprintf(stderr, "%s\n", 480 gettext("The iSCSI target service must be online " 481 "before running this command.")); 482 (void) fprintf(stderr, 483 gettext("Use 'svcadm enable -r %s'"), ISCSIT_SVC); 484 (void) fprintf(stderr, "\n"); 485 (void) fprintf(stderr, "%s\n", 486 gettext("to enable the service and its prerequisite " 487 "services and/or")); 488 (void) fprintf(stderr, 489 gettext("'svcs -x %s' to determine why it is not online."), 490 ISCSIT_SVC); 491 (void) fprintf(stderr, "\n"); 492 493 return (1); 494 } 495 496 switch ((itadm_sub_t)idx) { 497 case CREATE_TGT: 498 if (targetname) { 499 ret = create_target(targetname, proplist); 500 } else { 501 /* 502 * OK for objp to be NULL here. If the 503 * user did not specify a target name, 504 * one will be generated. 505 */ 506 ret = create_target(objp, proplist); 507 } 508 break; 509 case MODIFY_TGT: 510 ret = modify_target(objp, targetname, proplist); 511 break; 512 case DELETE_TGT: 513 ret = delete_target(objp, force); 514 break; 515 case LIST_TGT: 516 ret = list_target(objp, verbose, scripting); 517 break; 518 case CREATE_TPG: 519 ret = create_tpg(objp, newargc - 1, &(newargv[1])); 520 break; 521 case DELETE_TPG: 522 ret = delete_tpg(objp, force); 523 break; 524 case LIST_TPG: 525 ret = list_tpg(objp, verbose, scripting); 526 break; 527 case CREATE_INI: 528 ret = modify_initiator(objp, proplist, B_TRUE); 529 break; 530 case MODIFY_INI: 531 ret = modify_initiator(objp, proplist, B_FALSE); 532 break; 533 case LIST_INI: 534 ret = list_initiator(objp, verbose, scripting); 535 break; 536 case DELETE_INI: 537 ret = delete_initiator(objp); 538 break; 539 case MODIFY_DEF: 540 ret = modify_defaults(proplist); 541 break; 542 case LIST_DEF: 543 ret = list_defaults(scripting); 544 break; 545 default: 546 ret = 1; 547 goto usage_error; 548 } 549 550 if (ret != 0) { 551 (void) fprintf(stderr, 552 gettext("itadm %s failed with error %d"), 553 subcmds[idx].name, ret); 554 (void) fprintf(stderr, "\n"); 555 } 556 return (ret); 557 558 usage_error: 559 if (subcmds[idx].name) { 560 (void) printf("%s\n", gettext(subcmds[idx].usemsg)); 561 } else { 562 /* overall usage */ 563 (void) printf("%s\n\n", gettext("itadm usage:")); 564 for (idx = 0; subcmds[idx].name != NULL; idx++) { 565 if (!subcmds[idx].usemsg) { 566 continue; 567 } 568 (void) printf("\t%s\n", gettext(subcmds[idx].usemsg)); 569 } 570 } 571 572 return (ret); 573 } 574 575 static int 576 create_target(char *tgt, nvlist_t *proplist) 577 { 578 int ret; 579 it_config_t *cfg = NULL; 580 it_tgt_t *tgtp; 581 char **tags = NULL; 582 uint32_t count = 0; 583 nvlist_t *errlist = NULL; 584 int i; 585 it_tpg_t *tpg = NULL; 586 uint16_t tagid = 0; 587 it_tpgt_t *tpgt; 588 char *sec = "solaris.smf.modify.stmf"; 589 590 ITADM_CHKAUTH(sec); 591 592 if (tgt) { 593 /* 594 * validate input name - what are the rules for EUI 595 * and IQN values? 596 */ 597 if ((strncmp(tgt, "eui.", 4) != 0) && 598 (strncmp(tgt, "iqn.", 4) != 0)) { 599 (void) fprintf(stderr, gettext("Invalid name %s"), 600 tgt); 601 (void) fprintf(stderr, "\n"); 602 return (EINVAL); 603 } 604 } 605 606 ret = it_config_load(&cfg); 607 if (ret != 0) { 608 (void) fprintf(stderr, 609 gettext("Error retrieving iSCSI target configuration: %d"), 610 ret); 611 (void) fprintf(stderr, "\n"); 612 return (ret); 613 } 614 615 ret = it_tgt_create(cfg, &tgtp, tgt); 616 if (ret != 0) { 617 if (ret == EFAULT) { 618 (void) fprintf(stderr, 619 gettext("Invalid iSCSI name %s"), tgt); 620 } else if (ret == EEXIST) { 621 (void) fprintf(stderr, 622 gettext("iSCSI target %s already configured"), 623 tgt); 624 } else { 625 (void) fprintf(stderr, 626 gettext("Error creating target: %d"), ret); 627 } 628 (void) fprintf(stderr, "\n"); 629 goto done; 630 } 631 632 /* set the target portal group tags */ 633 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags, 634 &count); 635 636 if (ret == ENOENT) { 637 /* none specified. is this ok? */ 638 ret = 0; 639 } else if (ret != 0) { 640 (void) fprintf(stderr, 641 gettext("internal error: %d"), ret); 642 (void) fprintf(stderr, "\n"); 643 goto done; 644 } 645 646 /* special case, don't set any TPGs */ 647 if (tags && (strcmp("default", tags[0]) == 0)) { 648 count = 0; 649 } 650 651 for (i = 0; i < count; i++) { 652 if (!tags[i]) { 653 continue; 654 } 655 656 /* see that all referenced groups are already defined */ 657 tpg = cfg->config_tpg_list; 658 while (tpg != NULL) { 659 if (strcmp(tags[i], tpg->tpg_name) == 0) { 660 break; 661 } 662 663 tpg = tpg->tpg_next; 664 } 665 if (tpg == NULL) { 666 (void) fprintf(stderr, 667 gettext("Invalid tpg-tag %s, tag not defined"), 668 tags[i]); 669 (void) fprintf(stderr, "\n"); 670 ret = 1; 671 goto done; 672 } 673 674 /* generate the tag number to use */ 675 tag_name_to_num(tags[i], &tagid); 676 677 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid); 678 if (ret != 0) { 679 (void) fprintf(stderr, 680 gettext("Could not add target portal group" 681 "tag %s, error %d"), tags[i], ret); 682 (void) fprintf(stderr, "\n"); 683 goto done; 684 } 685 tagid++; 686 } 687 688 /* remove the tags from the proplist before continuing */ 689 if (tags) { 690 (void) nvlist_remove_all(proplist, "tpg-tag"); 691 } 692 693 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist); 694 if (ret != 0) { 695 (void) fprintf(stderr, 696 gettext("Error setting target properties, %d"), ret); 697 (void) fprintf(stderr, "\n"); 698 if (errlist) { 699 nvpair_t *nvp = NULL; 700 char *nn; 701 char *nv; 702 703 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 704 != NULL) { 705 nv = NULL; 706 707 nn = nvpair_name(nvp); 708 (void) nvpair_value_string(nvp, &nv); 709 710 if (nv != NULL) { 711 (void) fprintf(stderr, "\t%s: %s\n", 712 nn, nv); 713 } 714 } 715 716 nvlist_free(errlist); 717 } 718 goto done; 719 } 720 721 if (ret == 0) { 722 ret = it_config_commit(cfg); 723 STMF_STALE(ret); 724 } 725 726 done: 727 if (ret == 0) { 728 (void) printf(gettext("Target %s successfully created"), 729 tgtp->tgt_name); 730 (void) printf("\n"); 731 } 732 733 it_config_free(cfg); 734 735 return (ret); 736 } 737 738 int 739 list_target(char *tgt, boolean_t verbose, boolean_t script) 740 { 741 int ret; 742 it_config_t *cfg; 743 it_tgt_t *ptr; 744 boolean_t found = B_FALSE; 745 boolean_t first = B_TRUE; 746 boolean_t first_tag = B_TRUE; 747 char *gauth = "none"; 748 char *galias = "-"; 749 char *auth; 750 char *alias; 751 char *chapu; 752 char *chaps; 753 it_tpgt_t *tagp; 754 char *sec = "solaris.smf.read.stmf"; 755 stmfDevid devid; 756 stmfSessionList *sess = NULL; 757 stmfTargetProperties props; 758 char *state; 759 int num_sessions; 760 761 ITADM_CHKAUTH(sec); 762 763 ret = it_config_load(&cfg); 764 if (ret != 0) { 765 (void) fprintf(stderr, 766 gettext("Error retrieving iSCSI target configuration: %d"), 767 ret); 768 (void) fprintf(stderr, "\n"); 769 return (ret); 770 } 771 772 ptr = cfg->config_tgt_list; 773 774 /* grab global defaults for auth, alias */ 775 if (cfg->config_global_properties) { 776 (void) nvlist_lookup_string(cfg->config_global_properties, 777 "alias", &galias); 778 (void) nvlist_lookup_string(cfg->config_global_properties, 779 "auth", &gauth); 780 } 781 782 for (; ptr != NULL; ptr = ptr->tgt_next) { 783 if (found) { 784 break; 785 } 786 787 if (tgt) { 788 if (strcmp(tgt, ptr->tgt_name) != 0) { 789 continue; 790 } else { 791 found = B_TRUE; 792 } 793 } 794 795 state = "-"; 796 num_sessions = 0; 797 sess = NULL; 798 799 /* 800 * make a best effort to retrieve target status and 801 * number of active sessions from STMF. 802 */ 803 ret = stmfDevidFromIscsiName(ptr->tgt_name, &devid); 804 if (ret == STMF_STATUS_SUCCESS) { 805 ret = stmfGetTargetProperties(&devid, &props); 806 if (ret == STMF_STATUS_SUCCESS) { 807 if (props.status == STMF_TARGET_PORT_ONLINE) { 808 state = "online"; 809 } else { 810 state = "offline"; 811 } 812 } 813 } 814 if (ret == STMF_STATUS_SUCCESS) { 815 ret = stmfGetSessionList(&devid, &sess); 816 if (ret == STMF_STATUS_SUCCESS) { 817 num_sessions = sess->cnt; 818 free(sess); 819 } 820 } 821 822 /* reset ret so we don't return an error */ 823 ret = 0; 824 825 if (!script && first) { 826 (void) printf("%-61s%-9s%-9s\n", "TARGET NAME", 827 "STATE", "SESSIONS"); 828 first = B_FALSE; 829 } 830 831 if (!script) { 832 /* 833 * try not to let columns run into each other. 834 * Stick a tab after too-long fields. 835 * Lengths chosen are for the 'common' cases. 836 */ 837 (void) printf("%-61s", ptr->tgt_name); 838 if (strlen(ptr->tgt_name) > 60) { 839 (void) printf("\t"); 840 } 841 (void) printf("%-9s%-9d", state, num_sessions); 842 } else { 843 (void) printf("%s\t%s\t%d", ptr->tgt_name, 844 state, num_sessions); 845 } 846 847 if (!verbose) { 848 (void) printf("\n"); 849 continue; 850 } 851 852 auth = gauth; 853 alias = galias; 854 chapu = "-"; 855 chaps = "unset"; 856 857 if (ptr->tgt_properties) { 858 (void) nvlist_lookup_string(ptr->tgt_properties, 859 "auth", &auth); 860 (void) nvlist_lookup_string(ptr->tgt_properties, 861 "alias", &alias); 862 if (nvlist_exists(ptr->tgt_properties, 863 "targetchapsecret")) { 864 chaps = "set"; 865 } 866 (void) nvlist_lookup_string(ptr->tgt_properties, 867 "targetchapuser", &chapu); 868 } 869 870 if (!script) { 871 (void) printf("\n\t%-20s\t%s\n\t%-20s\t%s\n" 872 "\t%-20s\t%s\n\t%-20s\t%s\n\t%-20s\t", 873 "alias:", alias, "auth:", auth, "targetchapuser:", 874 chapu, "targetchapsecret:", chaps, "tpg-tags:"); 875 } else { 876 (void) printf("\t%s\t%s\t%s\t%s\t", 877 alias, auth, chapu, chaps); 878 } 879 880 first_tag = B_TRUE; 881 tagp = ptr->tgt_tpgt_list; 882 for (; tagp != NULL; tagp = tagp->tpgt_next) { 883 if (!first_tag) { 884 (void) printf(","); 885 } else { 886 first_tag = B_FALSE; 887 } 888 (void) printf("%s", tagp->tpgt_tpg_name); 889 } 890 891 if (first_tag) { 892 /* didn't find any */ 893 (void) printf("default"); 894 } 895 896 (void) printf("\n"); 897 } 898 899 if (tgt && (!found)) { 900 (void) fprintf(stderr, 901 gettext("Target %s not found!\n"), tgt); 902 (void) fprintf(stderr, "\n"); 903 ret = 1; 904 } 905 906 it_config_free(cfg); 907 908 return (ret); 909 } 910 911 int 912 delete_target(char *tgt, boolean_t force) 913 { 914 int ret; 915 it_config_t *cfg; 916 it_tgt_t *ptr; 917 char *sec = "solaris.smf.modify.stmf"; 918 919 ITADM_CHKAUTH(sec); 920 921 if (!tgt) { 922 (void) fprintf(stderr, "%s\n", 923 gettext("Error, no target specified")); 924 return (EINVAL); 925 } 926 927 ret = it_config_load(&cfg); 928 if (ret != 0) { 929 (void) fprintf(stderr, 930 gettext("Error retrieving iSCSI target configuration: %d"), 931 ret); 932 (void) fprintf(stderr, "\n"); 933 return (ret); 934 } 935 936 ptr = cfg->config_tgt_list; 937 while (ptr) { 938 if (strcmp(ptr->tgt_name, tgt) == 0) { 939 break; 940 } 941 942 ptr = ptr->tgt_next; 943 } 944 945 if (ptr) { 946 ret = it_tgt_delete(cfg, ptr, force); 947 948 if (ret != 0) { 949 if (ret == EBUSY) { 950 (void) fprintf(stderr, 951 gettext("The target is online or busy. " 952 "Use the -f (force) option, or " 953 "'stmfadm offline-target %s'"), tgt); 954 (void) fprintf(stderr, "\n"); 955 } 956 } 957 958 if (ret == 0) { 959 ret = it_config_commit(cfg); 960 STMF_STALE(ret); 961 } 962 } else { 963 (void) fprintf(stderr, 964 gettext("Target %s not found"), tgt); 965 (void) fprintf(stderr, "\n"); 966 ret = 1; 967 } 968 969 it_config_free(cfg); 970 971 return (ret); 972 } 973 974 static int 975 modify_target(char *tgt, char *newname, nvlist_t *proplist) 976 { 977 int ret; 978 it_config_t *cfg = NULL; 979 it_tgt_t *ptr = NULL; 980 it_tgt_t *tgtp; 981 char **tags = NULL; 982 uint32_t count = 0; 983 nvlist_t *errlist = NULL; 984 int i; 985 it_tpg_t *tpg = NULL; 986 uint16_t tagid; 987 it_tpgt_t *tpgt; 988 char *sec = "solaris.smf.modify.stmf"; 989 990 ITADM_CHKAUTH(sec); 991 992 /* XXX: Do we need to offline anything here too? */ 993 994 if (!tgt) { 995 (void) fprintf(stderr, "%s\n", 996 gettext("Error, no target specified")); 997 return (EINVAL); 998 } 999 1000 ret = it_config_load(&cfg); 1001 if (ret != 0) { 1002 (void) fprintf(stderr, 1003 gettext("Error retrieving iSCSI target configuration: %d"), 1004 ret); 1005 (void) fprintf(stderr, "\n"); 1006 return (ret); 1007 } 1008 1009 /* 1010 * If newname is specified, ensure it is a valid name 1011 */ 1012 if (newname) { 1013 if (!validate_iscsi_name(newname)) { 1014 (void) fprintf(stderr, 1015 gettext("Invalid iSCSI name %s"), newname); 1016 (void) fprintf(stderr, "\n"); 1017 return (1); 1018 } 1019 } 1020 1021 /* 1022 * Loop through to verify that the target to be modified truly 1023 * exists. If this target is to be renamed, ensure the new 1024 * name is not already in use. 1025 */ 1026 ptr = cfg->config_tgt_list; 1027 while (ptr) { 1028 if (newname && (strcmp(newname, ptr->tgt_name) == 0)) { 1029 (void) fprintf(stderr, 1030 gettext("A target with name %s already exists"), 1031 newname); 1032 (void) fprintf(stderr, "\n"); 1033 ret = 1; 1034 goto done; 1035 } 1036 1037 if (strcmp(ptr->tgt_name, tgt) == 0) { 1038 tgtp = ptr; 1039 } 1040 1041 ptr = ptr ->tgt_next; 1042 } 1043 1044 if (!tgtp) { 1045 (void) fprintf(stderr, 1046 gettext("Target %s not found"), tgt); 1047 (void) fprintf(stderr, "\n"); 1048 it_config_free(cfg); 1049 return (EINVAL); 1050 } 1051 1052 /* set the target portal group tags */ 1053 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags, 1054 &count); 1055 1056 if (ret == ENOENT) { 1057 /* none specified. is this ok? */ 1058 ret = 0; 1059 } else if (ret != 0) { 1060 (void) fprintf(stderr, 1061 gettext("internal error: %d"), ret); 1062 (void) fprintf(stderr, "\n"); 1063 goto done; 1064 } 1065 1066 /* special case, remove all explicit TPGs, and don't add any */ 1067 if (tags && (strcmp("default", tags[0]) == 0)) { 1068 count = 0; 1069 } 1070 1071 for (i = 0; i < count; i++) { 1072 if (!tags[i]) { 1073 continue; 1074 } 1075 1076 /* see that all referenced groups are already defined */ 1077 tpg = cfg->config_tpg_list; 1078 while (tpg != NULL) { 1079 if (strcmp(tags[i], tpg->tpg_name) == 0) { 1080 break; 1081 } 1082 tpg = tpg->tpg_next; 1083 } 1084 if (tpg == NULL) { 1085 (void) fprintf(stderr, 1086 gettext("Invalid tpg-name %s: not defined"), 1087 tags[i]); 1088 (void) fprintf(stderr, "\n"); 1089 ret = 1; 1090 goto done; 1091 } 1092 } 1093 1094 /* 1095 * don't recreate tags that are already associated, 1096 * remove tags not requested. 1097 */ 1098 if (tags) { 1099 tpgt = tgtp->tgt_tpgt_list; 1100 while (tpgt) { 1101 for (i = 0; i < count; i++) { 1102 if (!tags[i]) { 1103 continue; 1104 } 1105 1106 if (strcmp(tpgt->tpgt_tpg_name, tags[i]) 1107 == 0) { 1108 /* non-null tags will be created */ 1109 tags[i] = NULL; 1110 break; 1111 } 1112 } 1113 if (i == count) { 1114 /* one to remove */ 1115 it_tpgt_t *ptr = tpgt; 1116 1117 tpgt = ptr->tpgt_next; 1118 it_tpgt_delete(cfg, tgtp, ptr); 1119 } else { 1120 tpgt = tpgt->tpgt_next; 1121 } 1122 } 1123 } 1124 1125 /* see if there are any left to add */ 1126 for (i = 0; i < count; i++) { 1127 if (!tags[i]) { 1128 continue; 1129 } 1130 1131 /* generate the tag number to use */ 1132 tag_name_to_num(tags[i], &tagid); 1133 1134 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid); 1135 if (ret != 0) { 1136 if (ret == E2BIG) { 1137 (void) fprintf(stderr, "%s\n", 1138 gettext("Error, no portal tag available")); 1139 } else { 1140 (void) fprintf(stderr, gettext( 1141 "Could not add target portal group" 1142 " tag %s, error %d"), tags[i], ret); 1143 (void) fprintf(stderr, "\n"); 1144 } 1145 goto done; 1146 } 1147 } 1148 1149 /* remove the tags from the proplist before continuing */ 1150 (void) nvlist_remove_all(proplist, "tpg-tag"); 1151 1152 /* 1153 * Rename this target, if requested. Save the old name in 1154 * the property list, so the kernel knows this is a renamed 1155 * target, and not a new one. 1156 */ 1157 if (newname && (strlen(newname) > 0)) { 1158 ret = nvlist_add_string(proplist, "oldtargetname", 1159 tgtp->tgt_name); 1160 if (ret != 0) { 1161 (void) fprintf(stderr, "%s\n", 1162 gettext("Error renaming target.")); 1163 goto done; 1164 } 1165 (void) strlcpy(tgtp->tgt_name, newname, 1166 sizeof (tgtp->tgt_name)); 1167 } 1168 1169 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist); 1170 if (ret != 0) { 1171 (void) fprintf(stderr, 1172 gettext("Error setting target properties: %d"), ret); 1173 (void) fprintf(stderr, "\n"); 1174 if (errlist) { 1175 nvpair_t *nvp = NULL; 1176 char *nn; 1177 char *nv; 1178 1179 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1180 != NULL) { 1181 nv = NULL; 1182 1183 nn = nvpair_name(nvp); 1184 (void) nvpair_value_string(nvp, &nv); 1185 1186 if (nv != NULL) { 1187 (void) fprintf(stderr, "\t%s: %s\n", 1188 nn, nv); 1189 } 1190 } 1191 1192 nvlist_free(errlist); 1193 } 1194 goto done; 1195 } 1196 1197 if (ret == 0) { 1198 ret = it_config_commit(cfg); 1199 STMF_STALE(ret); 1200 } 1201 1202 done: 1203 if (ret == 0) { 1204 (void) printf(gettext("Target %s successfully modified"), 1205 tgtp->tgt_name); 1206 (void) printf("\n"); 1207 } 1208 1209 it_config_free(cfg); 1210 1211 return (ret); 1212 } 1213 1214 int 1215 create_tpg(char *tpg, int addrc, char **addrs) 1216 { 1217 int ret; 1218 it_config_t *cfg; 1219 it_tpg_t *tpgp; 1220 int count = 0; 1221 it_portal_t *ptl; 1222 char *sec = "solaris.smf.modify.stmf"; 1223 1224 ITADM_CHKAUTH(sec); 1225 1226 if (!tpg) { 1227 (void) fprintf(stderr, "%s\n", 1228 gettext("Error, no target portal group specified")); 1229 return (EINVAL); 1230 } 1231 1232 if (strlen(tpg) > (MAX_TPG_NAMELEN - 1)) { 1233 (void) fprintf(stderr, 1234 gettext("Target Portal Group name must be no longer " 1235 "than %d characters."), (MAX_TPG_NAMELEN - 1)); 1236 (void) fprintf(stderr, "\n"); 1237 return (EINVAL); 1238 } 1239 1240 if (!addrs || (addrc <= 0)) { 1241 (void) fprintf(stderr, "%s\n", 1242 gettext("Error, no portal addresses specified")); 1243 return (EINVAL); 1244 } 1245 1246 ret = it_config_load(&cfg); 1247 if (ret != 0) { 1248 (void) fprintf(stderr, 1249 gettext("Error retrieving iSCSI target configuration: %d"), 1250 ret); 1251 (void) fprintf(stderr, "\n"); 1252 return (ret); 1253 } 1254 1255 tpgp = cfg->config_tpg_list; 1256 while (tpgp != NULL) { 1257 if (strcmp(tpgp->tpg_name, tpg) == 0) { 1258 (void) fprintf(stderr, 1259 gettext("Target Portal Group %s already exists"), 1260 tpg); 1261 (void) fprintf(stderr, "\n"); 1262 it_config_free(cfg); 1263 return (1); 1264 } 1265 tpgp = tpgp->tpg_next; 1266 } 1267 1268 /* 1269 * Create the portal group and first portal 1270 */ 1271 ret = it_tpg_create(cfg, &tpgp, tpg, addrs[count]); 1272 if (ret != 0) { 1273 if (ret == EEXIST) { 1274 (void) fprintf(stderr, 1275 gettext("Portal %s already in use"), 1276 addrs[count]); 1277 (void) fprintf(stderr, "\n"); 1278 } 1279 it_config_free(cfg); 1280 return (ret); 1281 } 1282 1283 /* 1284 * Add the remaining portals 1285 */ 1286 for (count = 1; count < addrc; count++) { 1287 if (!addrs[count]) { 1288 continue; 1289 } 1290 1291 ret = it_portal_create(cfg, tpgp, &ptl, addrs[count]); 1292 if (ret != 0) { 1293 if (ret == EEXIST) { 1294 (void) fprintf(stderr, 1295 gettext("Portal %s already in use"), 1296 addrs[count]); 1297 (void) fprintf(stderr, "\n"); 1298 } else { 1299 (void) fprintf(stderr, 1300 gettext("Error adding portal %s: %d"), 1301 addrs[count], ret); 1302 (void) fprintf(stderr, "\n"); 1303 break; 1304 } 1305 } 1306 } 1307 1308 if (ret == 0) { 1309 ret = it_config_commit(cfg); 1310 STMF_STALE(ret); 1311 } 1312 1313 it_config_free(cfg); 1314 1315 return (ret); 1316 } 1317 1318 static int 1319 list_tpg(char *tpg, boolean_t verbose, boolean_t script) 1320 { 1321 int ret; 1322 it_config_t *cfg; 1323 it_tpg_t *ptr; 1324 boolean_t found = B_FALSE; 1325 it_portal_t *portal; 1326 boolean_t first = B_TRUE; 1327 boolean_t first_portal; 1328 char *pstr; 1329 char *sec = "solaris.smf.read.stmf"; 1330 1331 ITADM_CHKAUTH(sec); 1332 1333 ret = it_config_load(&cfg); 1334 if (ret != 0) { 1335 (void) fprintf(stderr, 1336 gettext("Error retrieving iSCSI target configuration: %d"), 1337 ret); 1338 (void) fprintf(stderr, "\n"); 1339 return (ret); 1340 } 1341 1342 ptr = cfg->config_tpg_list; 1343 1344 for (; ptr != NULL; ptr = ptr->tpg_next) { 1345 if (found) { 1346 break; 1347 } 1348 1349 if (tpg) { 1350 if (strcmp(tpg, ptr->tpg_name) != 0) { 1351 continue; 1352 } else { 1353 found = B_TRUE; 1354 } 1355 } 1356 1357 if (!script && first) { 1358 (void) printf("%-30s%-9s\n", "TARGET PORTAL GROUP", 1359 "PORTAL COUNT"); 1360 first = B_FALSE; 1361 } 1362 1363 if (!script) { 1364 (void) printf("%-30s", ptr->tpg_name); 1365 if (strlen(ptr->tpg_name) > 30) { 1366 (void) printf("\t"); 1367 } 1368 (void) printf("%-9d", ptr->tpg_portal_count); 1369 } else { 1370 (void) printf("%s\t%d", ptr->tpg_name, 1371 ptr->tpg_portal_count); 1372 } 1373 1374 if (!verbose) { 1375 (void) printf("\n"); 1376 continue; 1377 } 1378 1379 if (!script) { 1380 (void) printf("\n portals:"); 1381 } 1382 1383 first_portal = B_TRUE; 1384 1385 portal = ptr->tpg_portal_list; 1386 for (; portal != NULL; portal = portal->next) { 1387 ret = sockaddr_to_str(&(portal->portal_addr), &pstr); 1388 if (ret != 0) { 1389 /* invalid addr? */ 1390 continue; 1391 } 1392 if (!first_portal) { 1393 (void) printf(","); 1394 } else { 1395 (void) printf("\t"); 1396 first_portal = B_FALSE; 1397 } 1398 1399 (void) printf("%s", pstr); 1400 free(pstr); 1401 } 1402 1403 if (first_portal) { 1404 /* none found */ 1405 (void) printf("\t<none>"); 1406 } 1407 1408 (void) printf("\n"); 1409 } 1410 1411 if (tpg && (!found)) { 1412 (void) fprintf(stderr, 1413 gettext("Target Portal Group %s not found!\n"), tpg); 1414 (void) fprintf(stderr, "\n"); 1415 ret = 1; 1416 } 1417 1418 it_config_free(cfg); 1419 1420 return (ret); 1421 } 1422 1423 static int 1424 delete_tpg(char *tpg, boolean_t force) 1425 { 1426 int ret; 1427 it_config_t *cfg; 1428 it_tpg_t *ptpg = NULL; 1429 char *sec = "solaris.smf.modify.stmf"; 1430 1431 ITADM_CHKAUTH(sec); 1432 1433 if (!tpg) { 1434 (void) fprintf(stderr, "%s\n", 1435 gettext("Error, no target portal group specified")); 1436 return (EINVAL); 1437 } 1438 1439 ret = it_config_load(&cfg); 1440 if (ret != 0) { 1441 (void) fprintf(stderr, 1442 gettext("Error retrieving iSCSI target configuration: %d"), 1443 ret); 1444 (void) fprintf(stderr, "\n"); 1445 return (ret); 1446 } 1447 1448 ptpg = cfg->config_tpg_list; 1449 for (; ptpg != NULL; ptpg = ptpg->tpg_next) { 1450 if (strcmp(tpg, ptpg->tpg_name) == 0) { 1451 break; 1452 } 1453 } 1454 1455 if (!ptpg) { 1456 (void) fprintf(stderr, 1457 gettext("Target portal group %s does not exist."), 1458 tpg); 1459 (void) fprintf(stderr, "\n"); 1460 ret = 1; 1461 } else { 1462 ret = it_tpg_delete(cfg, ptpg, force); 1463 if (ret == EBUSY) { 1464 (void) fprintf(stderr, "%s\n", 1465 gettext( 1466 "Target portal group associated with one or more " 1467 "targets. Cannot delete.")); 1468 } 1469 1470 if (ret == 0) { 1471 ret = it_config_commit(cfg); 1472 STMF_STALE(ret); 1473 } 1474 } 1475 1476 it_config_free(cfg); 1477 1478 return (ret); 1479 } 1480 1481 static int 1482 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create) 1483 { 1484 int ret; 1485 it_config_t *cfg; 1486 it_ini_t *inip; 1487 nvlist_t *errlist = NULL; 1488 nvpair_t *nvp = NULL; 1489 char *sec = "solaris.smf.modify.stmf"; 1490 boolean_t changed = B_TRUE; 1491 1492 ITADM_CHKAUTH(sec); 1493 1494 if (!ini) { 1495 (void) fprintf(stderr, "%s\n", 1496 gettext("Error, no initiator specified")); 1497 return (EINVAL); 1498 } else if (create) { 1499 /* 1500 * validate input name - what are the rules for EUI 1501 * and IQN values? 1502 */ 1503 if ((strncmp(ini, "eui.", 4) != 0) && 1504 (strncmp(ini, "iqn.", 4) != 0)) { 1505 (void) fprintf(stderr, gettext("Invalid name %s"), 1506 ini); 1507 (void) fprintf(stderr, "\n"); 1508 return (EINVAL); 1509 } 1510 } 1511 1512 /* 1513 * See if any properties were actually specified. 1514 */ 1515 if (proplist) { 1516 nvp = nvlist_next_nvpair(proplist, nvp); 1517 } 1518 1519 if ((nvp == NULL) && !create) { 1520 changed = B_FALSE; 1521 } 1522 1523 /* 1524 * If no properties, and this is really a modify op, verify 1525 * that the requested initiator exists, but then don't do anything. 1526 * Modifying non-existent is an error; doing nothing to a defined 1527 * initiator is not. 1528 */ 1529 1530 ret = it_config_load(&cfg); 1531 if (ret != 0) { 1532 (void) fprintf(stderr, 1533 gettext("Error retrieving iSCSI target configuration: %d"), 1534 ret); 1535 (void) fprintf(stderr, "\n"); 1536 return (ret); 1537 } 1538 1539 inip = cfg->config_ini_list; 1540 while (inip) { 1541 if (strcmp(inip->ini_name, ini) == 0) { 1542 break; 1543 } 1544 1545 inip = inip->ini_next; 1546 } 1547 1548 if (create) { 1549 if (inip) { 1550 (void) fprintf(stderr, 1551 gettext("Initiator %s already exists"), 1552 inip->ini_name); 1553 (void) fprintf(stderr, "\n"); 1554 ret = EINVAL; 1555 } else { 1556 ret = it_ini_create(cfg, &inip, ini); 1557 if (ret != 0) { 1558 if (ret == EFAULT) { 1559 (void) fprintf(stderr, 1560 gettext("Invalid iSCSI name %s"), 1561 ini); 1562 } else { 1563 (void) fprintf(stderr, 1564 gettext( 1565 "Error creating initiator: %d"), 1566 ret); 1567 } 1568 (void) fprintf(stderr, "\n"); 1569 } 1570 } 1571 } else if (!inip) { 1572 ret = ENOENT; 1573 (void) fprintf(stderr, 1574 gettext("Error, initiator %s not found."), 1575 ini); 1576 (void) fprintf(stderr, "\n"); 1577 } 1578 1579 if ((ret == 0) && nvp) { 1580 ret = it_ini_setprop(inip, proplist, &errlist); 1581 1582 if (ret != 0) { 1583 (void) fprintf(stderr, 1584 gettext("Error setting initiator properties: %d"), 1585 ret); 1586 (void) fprintf(stderr, "\n"); 1587 if (errlist) { 1588 nvpair_t *nvp = NULL; 1589 char *nn; 1590 char *nv; 1591 1592 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1593 != NULL) { 1594 nv = NULL; 1595 1596 nn = nvpair_name(nvp); 1597 (void) nvpair_value_string(nvp, &nv); 1598 1599 if (nv != NULL) { 1600 (void) fprintf(stderr, 1601 "\t%s: %s\n", nn, nv); 1602 } 1603 } 1604 1605 nvlist_free(errlist); 1606 } 1607 } 1608 } 1609 1610 if ((ret == 0) && changed) { 1611 ret = it_config_commit(cfg); 1612 STMF_STALE(ret); 1613 } 1614 1615 it_config_free(cfg); 1616 1617 return (ret); 1618 } 1619 1620 static int 1621 list_initiator(char *ini, boolean_t verbose, boolean_t script) /* ARGSUSED */ 1622 { 1623 int ret; 1624 it_config_t *cfg; 1625 it_ini_t *ptr; 1626 boolean_t found = B_FALSE; 1627 boolean_t first = B_TRUE; 1628 char *isecret; 1629 char *iuser; 1630 char *sec = "solaris.smf.read.stmf"; 1631 1632 ITADM_CHKAUTH(sec); 1633 1634 ret = it_config_load(&cfg); 1635 if (ret != 0) { 1636 (void) fprintf(stderr, 1637 gettext("Error retrieving iSCSI target configuration: %d"), 1638 ret); 1639 (void) fprintf(stderr, "\n"); 1640 return (ret); 1641 } 1642 1643 ptr = cfg->config_ini_list; 1644 1645 for (; ptr != NULL; ptr = ptr->ini_next) { 1646 isecret = "unset"; 1647 iuser = "<none>"; 1648 1649 if (found) { 1650 break; 1651 } 1652 1653 if (ini) { 1654 if (strcmp(ini, ptr->ini_name) != 0) { 1655 continue; 1656 } else { 1657 found = B_TRUE; 1658 } 1659 } 1660 1661 if (ptr->ini_properties) { 1662 if (nvlist_exists(ptr->ini_properties, "chapsecret")) { 1663 isecret = "set"; 1664 } 1665 (void) nvlist_lookup_string(ptr->ini_properties, 1666 "chapuser", &iuser); 1667 1668 } 1669 1670 /* there's nothing to print for verbose yet */ 1671 if (!script && first) { 1672 (void) printf("%-61s%-10s%-7s\n", "INITIATOR NAME", 1673 "CHAPUSER", "SECRET"); 1674 first = B_FALSE; 1675 } 1676 1677 if (!script) { 1678 /* 1679 * try not to let columns run into each other. 1680 * Stick a tab after too-long fields. 1681 * Lengths chosen are for the 'common' cases. 1682 */ 1683 (void) printf("%-61s", ptr->ini_name); 1684 1685 if (strlen(ptr->ini_name) > 60) { 1686 (void) printf("\t"); 1687 } 1688 1689 (void) printf("%-15s", iuser); 1690 if (strlen(iuser) >= 15) { 1691 (void) printf("\t"); 1692 } 1693 1694 (void) printf("%-4s", isecret); 1695 } else { 1696 (void) printf("%s\t%s\t%s", ptr->ini_name, 1697 iuser, isecret); 1698 } 1699 1700 (void) printf("\n"); 1701 } 1702 1703 if (ini && (!found)) { 1704 (void) fprintf(stderr, 1705 gettext("Initiator %s not found!"), ini); 1706 (void) fprintf(stderr, "\n"); 1707 ret = 1; 1708 } 1709 1710 it_config_free(cfg); 1711 1712 return (ret); 1713 } 1714 1715 int 1716 delete_initiator(char *ini) 1717 { 1718 int ret; 1719 it_config_t *cfg; 1720 it_ini_t *ptr; 1721 char *sec = "solaris.smf.modify.stmf"; 1722 1723 ITADM_CHKAUTH(sec); 1724 1725 if (!ini) { 1726 (void) fprintf(stderr, "%s\n", 1727 gettext("Error, no initiator specified")); 1728 return (EINVAL); 1729 } 1730 1731 ret = it_config_load(&cfg); 1732 if (ret != 0) { 1733 (void) fprintf(stderr, 1734 gettext("Error retrieving iSCSI target configuration: %d"), 1735 ret); 1736 (void) fprintf(stderr, "\n"); 1737 return (ret); 1738 } 1739 1740 ptr = cfg->config_ini_list; 1741 while (ptr) { 1742 if (strcmp(ptr->ini_name, ini) == 0) { 1743 break; 1744 } 1745 1746 ptr = ptr->ini_next; 1747 } 1748 1749 if (ptr) { 1750 it_ini_delete(cfg, ptr); 1751 1752 ret = it_config_commit(cfg); 1753 STMF_STALE(ret); 1754 } else { 1755 (void) fprintf(stderr, 1756 gettext("Initiator %s not found"), ini); 1757 (void) fprintf(stderr, "\n"); 1758 ret = 1; 1759 } 1760 1761 return (ret); 1762 } 1763 1764 static int 1765 modify_defaults(nvlist_t *proplist) 1766 { 1767 int ret; 1768 it_config_t *cfg; 1769 nvlist_t *errlist = NULL; 1770 nvpair_t *nvp = NULL; 1771 char *sec = "solaris.smf.modify.stmf"; 1772 1773 ITADM_CHKAUTH(sec); 1774 1775 if (proplist) { 1776 /* make sure at least one property is specified */ 1777 nvp = nvlist_next_nvpair(proplist, nvp); 1778 } 1779 1780 if (nvp == NULL) { 1781 /* empty list */ 1782 (void) fprintf(stderr, "%s\n", 1783 gettext("Error, no properties specified")); 1784 return (EINVAL); 1785 } 1786 1787 ret = it_config_load(&cfg); 1788 if (ret != 0) { 1789 (void) fprintf(stderr, 1790 gettext("Error retrieving iSCSI target configuration: %d"), 1791 ret); 1792 (void) fprintf(stderr, "\n"); 1793 return (ret); 1794 } 1795 1796 ret = it_config_setprop(cfg, proplist, &errlist); 1797 if (ret != 0) { 1798 (void) fprintf(stderr, 1799 gettext("Error setting global properties: %d"), 1800 ret); 1801 (void) fprintf(stderr, "\n"); 1802 if (errlist) { 1803 nvpair_t *nvp = NULL; 1804 char *nn; 1805 char *nv; 1806 1807 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1808 != NULL) { 1809 nv = NULL; 1810 1811 nn = nvpair_name(nvp); 1812 (void) nvpair_value_string(nvp, &nv); 1813 1814 if (nv != NULL) { 1815 (void) fprintf(stderr, "\t%s: %s\n", 1816 nn, nv); 1817 } 1818 } 1819 1820 nvlist_free(errlist); 1821 } 1822 } 1823 1824 if (ret == 0) { 1825 ret = it_config_commit(cfg); 1826 STMF_STALE(ret); 1827 } 1828 1829 it_config_free(cfg); 1830 1831 return (ret); 1832 } 1833 1834 static int 1835 list_defaults(boolean_t script) 1836 { 1837 int ret; 1838 it_config_t *cfg; 1839 nvlist_t *nvl; 1840 char *alias = "<none>"; 1841 char *auth = "<none>"; 1842 char *isns = "disabled"; 1843 char **isvrs = NULL; 1844 uint32_t scount = 0; 1845 char *rsvr = "<none>"; 1846 char *rsecret = "unset"; 1847 boolean_t val = B_FALSE; 1848 int i; 1849 char *sec = "solaris.smf.read.stmf"; 1850 1851 ITADM_CHKAUTH(sec); 1852 1853 ret = it_config_load(&cfg); 1854 if (ret != 0) { 1855 (void) fprintf(stderr, 1856 gettext("Error retrieving iSCSI target configuration: %d"), 1857 ret); 1858 (void) fprintf(stderr, "\n"); 1859 return (ret); 1860 } 1861 1862 nvl = cfg->config_global_properties; 1863 1864 /* look up all possible options */ 1865 (void) nvlist_lookup_string(nvl, "alias", &alias); 1866 (void) nvlist_lookup_string(nvl, "auth", &auth); 1867 (void) nvlist_lookup_boolean_value(nvl, "isns", &val); 1868 if (val == B_TRUE) { 1869 isns = "enabled"; 1870 } 1871 (void) nvlist_lookup_string_array(nvl, "isnsserver", &isvrs, 1872 &scount); 1873 (void) nvlist_lookup_string(nvl, "radiusserver", &rsvr); 1874 if (nvlist_exists(nvl, "radiussecret")) { 1875 rsecret = "set"; 1876 } 1877 1878 if (!script) { 1879 (void) printf("%s:\n\n", 1880 gettext("iSCSI Target Default Properties")); 1881 } 1882 1883 if (script) { 1884 (void) printf("%s\t%s\t%s\t%s\t%s\t", 1885 alias, auth, rsvr, rsecret, isns); 1886 } else { 1887 (void) printf("%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n" 1888 "%-15s\t%s\n%-15s\t", 1889 "alias:", alias, "auth:", auth, "radiusserver:", 1890 rsvr, "radiussecret:", rsecret, "isns:", isns, 1891 "isnsserver:"); 1892 } 1893 1894 for (i = 0; i < scount; i++) { 1895 if (!isvrs || !isvrs[i]) { 1896 break; 1897 } 1898 if (i > 0) { 1899 (void) printf(","); 1900 } 1901 (void) printf("%s", isvrs[i]); 1902 } 1903 1904 if (i == 0) { 1905 (void) printf("%s", "<none>"); 1906 } 1907 1908 (void) printf("\n"); 1909 1910 it_config_free(cfg); 1911 1912 return (0); 1913 } 1914 1915 static int 1916 itadm_get_password(nvlist_t *nvl, char *key, char *passfile, 1917 char *phrase) 1918 { 1919 int ret = 0; 1920 char *pass; 1921 char buf[1024]; 1922 int fd; 1923 struct stat64 sbuf; 1924 size_t rd; 1925 1926 if (!nvl || !key) { 1927 return (EINVAL); 1928 } 1929 1930 if (passfile) { 1931 ret = stat64(passfile, &sbuf); 1932 if ((ret != 0) || (!S_ISREG(sbuf.st_mode))) { 1933 (void) fprintf(stderr, 1934 gettext("Invalid secret file %s"), 1935 passfile); 1936 (void) fprintf(stderr, "\n"); 1937 return (EBADF); 1938 } 1939 1940 fd = open64(passfile, O_RDONLY); 1941 if (fd == -1) { 1942 ret = errno; 1943 (void) fprintf(stderr, 1944 gettext("Could not open secret file %s, %d"), 1945 passfile, ret); 1946 (void) fprintf(stderr, "\n"); 1947 return (ret); 1948 } 1949 1950 rd = read(fd, buf, sbuf.st_size); 1951 (void) close(fd); 1952 1953 if (rd != sbuf.st_size) { 1954 ret = EIO; 1955 (void) fprintf(stderr, 1956 gettext("Could not read secret file %s, %d"), 1957 passfile, ret); 1958 (void) fprintf(stderr, "\n"); 1959 return (ret); 1960 } 1961 1962 /* ensure buf is properly terminated */ 1963 buf[rd] = '\0'; 1964 1965 /* if last char is a newline, strip it off */ 1966 if (buf[rd - 1] == '\n') { 1967 buf[rd - 1] = '\0'; 1968 } 1969 1970 /* validate length */ 1971 if ((strlen(buf) > 255) || (strlen(buf) < 12)) { 1972 (void) fprintf(stderr, "%s\n", 1973 gettext( 1974 "Secret must be between 12 and 255 characters")); 1975 return (EINVAL); 1976 } 1977 } else { 1978 /* prompt for secret */ 1979 if (!phrase) { 1980 return (EINVAL); 1981 } 1982 1983 pass = getpassphrase(phrase); 1984 if (!pass) { 1985 ret = errno; 1986 (void) fprintf(stderr, 1987 gettext("Could not read secret, %d"), 1988 ret); 1989 (void) fprintf(stderr, "\n"); 1990 return (ret); 1991 } 1992 1993 /* validate length */ 1994 if ((strlen(pass) > 255) || (strlen(pass) < 12)) { 1995 (void) fprintf(stderr, "%s\n", 1996 gettext( 1997 "Secret must be between 12 and 255 characters")); 1998 return (EINVAL); 1999 } 2000 2001 (void) strlcpy(buf, pass, sizeof (buf)); 2002 2003 /* confirm entered secret */ 2004 pass = getpassphrase(gettext("Re-enter secret: ")); 2005 if (!pass) { 2006 ret = errno; 2007 (void) fprintf(stderr, 2008 gettext("Could not read secret, %d"), 2009 ret); 2010 (void) fprintf(stderr, "\n"); 2011 return (ret); 2012 } 2013 2014 if (strcmp(buf, pass) != 0) { 2015 ret = EINVAL; 2016 (void) fprintf(stderr, "%s\n", 2017 gettext("Secret validation failed")); 2018 return (ret); 2019 } 2020 2021 } 2022 2023 ret = nvlist_add_string(nvl, key, buf); 2024 2025 return (ret); 2026 } 2027 2028 static int 2029 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num) 2030 { 2031 int count; 2032 char *bufp; 2033 char **arr; 2034 2035 if (!opt || !key || !nvl) { 2036 return (EINVAL); 2037 } 2038 2039 bufp = opt; 2040 count = 1; 2041 2042 for (;;) { 2043 bufp = strchr(bufp, ','); 2044 if (!bufp) { 2045 break; 2046 } 2047 bufp++; 2048 count++; 2049 } 2050 2051 arr = calloc(count, sizeof (char *)); 2052 if (!arr) { 2053 return (ENOMEM); 2054 } 2055 2056 bufp = opt; 2057 /* set delimiter to comma */ 2058 (void) bufsplit(",", 0, NULL); 2059 2060 /* split up that buf! */ 2061 (void) bufsplit(bufp, count, arr); 2062 2063 /* if requested, return the number of array members found */ 2064 if (num) { 2065 *num = count; 2066 } 2067 2068 return (nvlist_add_string_array(nvl, key, arr, count)); 2069 } 2070 2071 static void 2072 tag_name_to_num(char *tagname, uint16_t *tagnum) 2073 { 2074 ulong_t id; 2075 char *ptr = NULL; 2076 2077 if (!tagname || !tagnum) { 2078 return; 2079 } 2080 2081 *tagnum = 0; 2082 2083 id = strtoul(tagname, &ptr, 10); 2084 2085 /* Must be entirely numeric and in-range */ 2086 if (ptr && (*ptr != '\0')) { 2087 return; 2088 } 2089 2090 if ((id <= UINT16_MAX) && (id > 1)) { 2091 *tagnum = (uint16_t)id; 2092 } 2093 } 2094