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 %s\n" 872 "\t%-20s\t%s\n\t%-20s\t%s\n\t%-20s\t", 873 "alias:", alias, "auth:", auth, 874 ((auth == gauth) ? "(defaults)" : ""), 875 "targetchapuser:", 876 chapu, "targetchapsecret:", chaps, "tpg-tags:"); 877 } else { 878 (void) printf("\t%s\t%s %s\t%s\t%s\t", 879 alias, auth, 880 ((auth == gauth) ? "(defaults)" : ""), 881 chapu, chaps); 882 } 883 884 first_tag = B_TRUE; 885 tagp = ptr->tgt_tpgt_list; 886 for (; tagp != NULL; tagp = tagp->tpgt_next) { 887 if (!first_tag) { 888 (void) printf(","); 889 } else { 890 first_tag = B_FALSE; 891 } 892 (void) printf("%s = %d", 893 tagp->tpgt_tpg_name, tagp->tpgt_tag); 894 } 895 896 if (first_tag) { 897 /* didn't find any */ 898 (void) printf("default"); 899 } 900 901 (void) printf("\n"); 902 } 903 904 if (tgt && (!found)) { 905 (void) fprintf(stderr, 906 gettext("Target %s not found!\n"), tgt); 907 (void) fprintf(stderr, "\n"); 908 ret = 1; 909 } 910 911 it_config_free(cfg); 912 913 return (ret); 914 } 915 916 int 917 delete_target(char *tgt, boolean_t force) 918 { 919 int ret; 920 it_config_t *cfg; 921 it_tgt_t *ptr; 922 char *sec = "solaris.smf.modify.stmf"; 923 924 ITADM_CHKAUTH(sec); 925 926 if (!tgt) { 927 (void) fprintf(stderr, "%s\n", 928 gettext("Error, no target specified")); 929 return (EINVAL); 930 } 931 932 ret = it_config_load(&cfg); 933 if (ret != 0) { 934 (void) fprintf(stderr, 935 gettext("Error retrieving iSCSI target configuration: %d"), 936 ret); 937 (void) fprintf(stderr, "\n"); 938 return (ret); 939 } 940 941 ptr = cfg->config_tgt_list; 942 while (ptr) { 943 if (strcmp(ptr->tgt_name, tgt) == 0) { 944 break; 945 } 946 947 ptr = ptr->tgt_next; 948 } 949 950 if (ptr) { 951 ret = it_tgt_delete(cfg, ptr, force); 952 953 if (ret != 0) { 954 if (ret == EBUSY) { 955 (void) fprintf(stderr, 956 gettext("The target is online or busy. " 957 "Use the -f (force) option, or " 958 "'stmfadm offline-target %s'"), tgt); 959 (void) fprintf(stderr, "\n"); 960 } 961 } 962 963 if (ret == 0) { 964 ret = it_config_commit(cfg); 965 STMF_STALE(ret); 966 } 967 } else { 968 (void) fprintf(stderr, 969 gettext("Target %s not found"), tgt); 970 (void) fprintf(stderr, "\n"); 971 ret = 1; 972 } 973 974 it_config_free(cfg); 975 976 return (ret); 977 } 978 979 static int 980 modify_target(char *tgt, char *newname, nvlist_t *proplist) 981 { 982 int ret; 983 it_config_t *cfg = NULL; 984 it_tgt_t *ptr = NULL; 985 it_tgt_t *tgtp; 986 char **tags = NULL; 987 uint32_t count = 0; 988 nvlist_t *errlist = NULL; 989 int i; 990 it_tpg_t *tpg = NULL; 991 uint16_t tagid; 992 it_tpgt_t *tpgt; 993 char *sec = "solaris.smf.modify.stmf"; 994 995 ITADM_CHKAUTH(sec); 996 997 /* XXX: Do we need to offline anything here too? */ 998 999 if (!tgt) { 1000 (void) fprintf(stderr, "%s\n", 1001 gettext("Error, no target specified")); 1002 return (EINVAL); 1003 } 1004 1005 ret = it_config_load(&cfg); 1006 if (ret != 0) { 1007 (void) fprintf(stderr, 1008 gettext("Error retrieving iSCSI target configuration: %d"), 1009 ret); 1010 (void) fprintf(stderr, "\n"); 1011 return (ret); 1012 } 1013 1014 /* 1015 * If newname is specified, ensure it is a valid name 1016 */ 1017 if (newname) { 1018 if (!validate_iscsi_name(newname)) { 1019 (void) fprintf(stderr, 1020 gettext("Invalid iSCSI name %s"), newname); 1021 (void) fprintf(stderr, "\n"); 1022 return (1); 1023 } 1024 } 1025 1026 /* 1027 * Loop through to verify that the target to be modified truly 1028 * exists. If this target is to be renamed, ensure the new 1029 * name is not already in use. 1030 */ 1031 ptr = cfg->config_tgt_list; 1032 while (ptr) { 1033 if (newname && (strcmp(newname, ptr->tgt_name) == 0)) { 1034 (void) fprintf(stderr, 1035 gettext("A target with name %s already exists"), 1036 newname); 1037 (void) fprintf(stderr, "\n"); 1038 ret = 1; 1039 goto done; 1040 } 1041 1042 if (strcmp(ptr->tgt_name, tgt) == 0) { 1043 tgtp = ptr; 1044 } 1045 1046 ptr = ptr ->tgt_next; 1047 } 1048 1049 if (!tgtp) { 1050 (void) fprintf(stderr, 1051 gettext("Target %s not found"), tgt); 1052 (void) fprintf(stderr, "\n"); 1053 it_config_free(cfg); 1054 return (EINVAL); 1055 } 1056 1057 /* set the target portal group tags */ 1058 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags, 1059 &count); 1060 1061 if (ret == ENOENT) { 1062 /* none specified. is this ok? */ 1063 ret = 0; 1064 } else if (ret != 0) { 1065 (void) fprintf(stderr, 1066 gettext("internal error: %d"), ret); 1067 (void) fprintf(stderr, "\n"); 1068 goto done; 1069 } 1070 1071 /* special case, remove all explicit TPGs, and don't add any */ 1072 if (tags && (strcmp("default", tags[0]) == 0)) { 1073 count = 0; 1074 } 1075 1076 for (i = 0; i < count; i++) { 1077 if (!tags[i]) { 1078 continue; 1079 } 1080 1081 /* see that all referenced groups are already defined */ 1082 tpg = cfg->config_tpg_list; 1083 while (tpg != NULL) { 1084 if (strcmp(tags[i], tpg->tpg_name) == 0) { 1085 break; 1086 } 1087 tpg = tpg->tpg_next; 1088 } 1089 if (tpg == NULL) { 1090 (void) fprintf(stderr, 1091 gettext("Invalid tpg-name %s: not defined"), 1092 tags[i]); 1093 (void) fprintf(stderr, "\n"); 1094 ret = 1; 1095 goto done; 1096 } 1097 } 1098 1099 /* 1100 * don't recreate tags that are already associated, 1101 * remove tags not requested. 1102 */ 1103 if (tags) { 1104 tpgt = tgtp->tgt_tpgt_list; 1105 while (tpgt) { 1106 for (i = 0; i < count; i++) { 1107 if (!tags[i]) { 1108 continue; 1109 } 1110 1111 if (strcmp(tpgt->tpgt_tpg_name, tags[i]) 1112 == 0) { 1113 /* non-null tags will be created */ 1114 tags[i] = NULL; 1115 break; 1116 } 1117 } 1118 if (i == count) { 1119 /* one to remove */ 1120 it_tpgt_t *ptr = tpgt; 1121 1122 tpgt = ptr->tpgt_next; 1123 it_tpgt_delete(cfg, tgtp, ptr); 1124 } else { 1125 tpgt = tpgt->tpgt_next; 1126 } 1127 } 1128 } 1129 1130 /* see if there are any left to add */ 1131 for (i = 0; i < count; i++) { 1132 if (!tags[i]) { 1133 continue; 1134 } 1135 1136 /* generate the tag number to use */ 1137 tag_name_to_num(tags[i], &tagid); 1138 1139 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid); 1140 if (ret != 0) { 1141 if (ret == E2BIG) { 1142 (void) fprintf(stderr, "%s\n", 1143 gettext("Error, no portal tag available")); 1144 } else { 1145 (void) fprintf(stderr, gettext( 1146 "Could not add target portal group" 1147 " tag %s, error %d"), tags[i], ret); 1148 (void) fprintf(stderr, "\n"); 1149 } 1150 goto done; 1151 } 1152 } 1153 1154 /* remove the tags from the proplist before continuing */ 1155 (void) nvlist_remove_all(proplist, "tpg-tag"); 1156 1157 /* 1158 * Rename this target, if requested. Save the old name in 1159 * the property list, so the kernel knows this is a renamed 1160 * target, and not a new one. 1161 */ 1162 if (newname && (strlen(newname) > 0)) { 1163 ret = nvlist_add_string(proplist, "oldtargetname", 1164 tgtp->tgt_name); 1165 if (ret != 0) { 1166 (void) fprintf(stderr, "%s\n", 1167 gettext("Error renaming target.")); 1168 goto done; 1169 } 1170 (void) strlcpy(tgtp->tgt_name, newname, 1171 sizeof (tgtp->tgt_name)); 1172 } 1173 1174 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist); 1175 if (ret != 0) { 1176 (void) fprintf(stderr, 1177 gettext("Error setting target properties: %d"), ret); 1178 (void) fprintf(stderr, "\n"); 1179 if (errlist) { 1180 nvpair_t *nvp = NULL; 1181 char *nn; 1182 char *nv; 1183 1184 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1185 != NULL) { 1186 nv = NULL; 1187 1188 nn = nvpair_name(nvp); 1189 (void) nvpair_value_string(nvp, &nv); 1190 1191 if (nv != NULL) { 1192 (void) fprintf(stderr, "\t%s: %s\n", 1193 nn, nv); 1194 } 1195 } 1196 1197 nvlist_free(errlist); 1198 } 1199 goto done; 1200 } 1201 1202 if (ret == 0) { 1203 ret = it_config_commit(cfg); 1204 STMF_STALE(ret); 1205 } 1206 1207 done: 1208 if (ret == 0) { 1209 (void) printf(gettext("Target %s successfully modified"), 1210 tgtp->tgt_name); 1211 (void) printf("\n"); 1212 } 1213 1214 it_config_free(cfg); 1215 1216 return (ret); 1217 } 1218 1219 int 1220 create_tpg(char *tpg, int addrc, char **addrs) 1221 { 1222 int ret; 1223 it_config_t *cfg; 1224 it_tpg_t *tpgp; 1225 int count = 0; 1226 it_portal_t *ptl; 1227 char *sec = "solaris.smf.modify.stmf"; 1228 1229 ITADM_CHKAUTH(sec); 1230 1231 if (!tpg) { 1232 (void) fprintf(stderr, "%s\n", 1233 gettext("Error, no target portal group specified")); 1234 return (EINVAL); 1235 } 1236 1237 if (strlen(tpg) > (MAX_TPG_NAMELEN - 1)) { 1238 (void) fprintf(stderr, 1239 gettext("Target Portal Group name must be no longer " 1240 "than %d characters."), (MAX_TPG_NAMELEN - 1)); 1241 (void) fprintf(stderr, "\n"); 1242 return (EINVAL); 1243 } 1244 1245 if (!addrs || (addrc <= 0)) { 1246 (void) fprintf(stderr, "%s\n", 1247 gettext("Error, no portal addresses specified")); 1248 return (EINVAL); 1249 } 1250 1251 ret = it_config_load(&cfg); 1252 if (ret != 0) { 1253 (void) fprintf(stderr, 1254 gettext("Error retrieving iSCSI target configuration: %d"), 1255 ret); 1256 (void) fprintf(stderr, "\n"); 1257 return (ret); 1258 } 1259 1260 tpgp = cfg->config_tpg_list; 1261 while (tpgp != NULL) { 1262 if (strcmp(tpgp->tpg_name, tpg) == 0) { 1263 (void) fprintf(stderr, 1264 gettext("Target Portal Group %s already exists"), 1265 tpg); 1266 (void) fprintf(stderr, "\n"); 1267 it_config_free(cfg); 1268 return (1); 1269 } 1270 tpgp = tpgp->tpg_next; 1271 } 1272 1273 /* 1274 * Create the portal group and first portal 1275 */ 1276 ret = it_tpg_create(cfg, &tpgp, tpg, addrs[count]); 1277 if (ret != 0) { 1278 if (ret == EEXIST) { 1279 (void) fprintf(stderr, 1280 gettext("Portal %s already in use"), 1281 addrs[count]); 1282 (void) fprintf(stderr, "\n"); 1283 } 1284 it_config_free(cfg); 1285 return (ret); 1286 } 1287 1288 /* 1289 * Add the remaining portals 1290 */ 1291 for (count = 1; count < addrc; count++) { 1292 if (!addrs[count]) { 1293 continue; 1294 } 1295 1296 ret = it_portal_create(cfg, tpgp, &ptl, addrs[count]); 1297 if (ret != 0) { 1298 if (ret == EEXIST) { 1299 (void) fprintf(stderr, 1300 gettext("Portal %s already in use"), 1301 addrs[count]); 1302 (void) fprintf(stderr, "\n"); 1303 } else { 1304 (void) fprintf(stderr, 1305 gettext("Error adding portal %s: %d"), 1306 addrs[count], ret); 1307 (void) fprintf(stderr, "\n"); 1308 break; 1309 } 1310 } 1311 } 1312 1313 if (ret == 0) { 1314 ret = it_config_commit(cfg); 1315 STMF_STALE(ret); 1316 } 1317 1318 it_config_free(cfg); 1319 1320 return (ret); 1321 } 1322 1323 static int 1324 list_tpg(char *tpg, boolean_t verbose, boolean_t script) 1325 { 1326 int ret; 1327 it_config_t *cfg; 1328 it_tpg_t *ptr; 1329 boolean_t found = B_FALSE; 1330 it_portal_t *portal; 1331 boolean_t first = B_TRUE; 1332 boolean_t first_portal; 1333 char *pstr; 1334 char *sec = "solaris.smf.read.stmf"; 1335 1336 ITADM_CHKAUTH(sec); 1337 1338 ret = it_config_load(&cfg); 1339 if (ret != 0) { 1340 (void) fprintf(stderr, 1341 gettext("Error retrieving iSCSI target configuration: %d"), 1342 ret); 1343 (void) fprintf(stderr, "\n"); 1344 return (ret); 1345 } 1346 1347 ptr = cfg->config_tpg_list; 1348 1349 for (; ptr != NULL; ptr = ptr->tpg_next) { 1350 if (found) { 1351 break; 1352 } 1353 1354 if (tpg) { 1355 if (strcmp(tpg, ptr->tpg_name) != 0) { 1356 continue; 1357 } else { 1358 found = B_TRUE; 1359 } 1360 } 1361 1362 if (!script && first) { 1363 (void) printf("%-30s%-9s\n", "TARGET PORTAL GROUP", 1364 "PORTAL COUNT"); 1365 first = B_FALSE; 1366 } 1367 1368 if (!script) { 1369 (void) printf("%-30s", ptr->tpg_name); 1370 if (strlen(ptr->tpg_name) > 30) { 1371 (void) printf("\t"); 1372 } 1373 (void) printf("%-9d", ptr->tpg_portal_count); 1374 } else { 1375 (void) printf("%s\t%d", ptr->tpg_name, 1376 ptr->tpg_portal_count); 1377 } 1378 1379 if (!verbose) { 1380 (void) printf("\n"); 1381 continue; 1382 } 1383 1384 if (!script) { 1385 (void) printf("\n portals:"); 1386 } 1387 1388 first_portal = B_TRUE; 1389 1390 portal = ptr->tpg_portal_list; 1391 for (; portal != NULL; portal = portal->next) { 1392 ret = sockaddr_to_str(&(portal->portal_addr), &pstr); 1393 if (ret != 0) { 1394 /* invalid addr? */ 1395 continue; 1396 } 1397 if (!first_portal) { 1398 (void) printf(","); 1399 } else { 1400 (void) printf("\t"); 1401 first_portal = B_FALSE; 1402 } 1403 1404 (void) printf("%s", pstr); 1405 free(pstr); 1406 } 1407 1408 if (first_portal) { 1409 /* none found */ 1410 (void) printf("\t<none>"); 1411 } 1412 1413 (void) printf("\n"); 1414 } 1415 1416 if (tpg && (!found)) { 1417 (void) fprintf(stderr, 1418 gettext("Target Portal Group %s not found!\n"), tpg); 1419 (void) fprintf(stderr, "\n"); 1420 ret = 1; 1421 } 1422 1423 it_config_free(cfg); 1424 1425 return (ret); 1426 } 1427 1428 static int 1429 delete_tpg(char *tpg, boolean_t force) 1430 { 1431 int ret; 1432 it_config_t *cfg; 1433 it_tpg_t *ptpg = NULL; 1434 char *sec = "solaris.smf.modify.stmf"; 1435 1436 ITADM_CHKAUTH(sec); 1437 1438 if (!tpg) { 1439 (void) fprintf(stderr, "%s\n", 1440 gettext("Error, no target portal group specified")); 1441 return (EINVAL); 1442 } 1443 1444 ret = it_config_load(&cfg); 1445 if (ret != 0) { 1446 (void) fprintf(stderr, 1447 gettext("Error retrieving iSCSI target configuration: %d"), 1448 ret); 1449 (void) fprintf(stderr, "\n"); 1450 return (ret); 1451 } 1452 1453 ptpg = cfg->config_tpg_list; 1454 for (; ptpg != NULL; ptpg = ptpg->tpg_next) { 1455 if (strcmp(tpg, ptpg->tpg_name) == 0) { 1456 break; 1457 } 1458 } 1459 1460 if (!ptpg) { 1461 (void) fprintf(stderr, 1462 gettext("Target portal group %s does not exist."), 1463 tpg); 1464 (void) fprintf(stderr, "\n"); 1465 ret = 1; 1466 } else { 1467 ret = it_tpg_delete(cfg, ptpg, force); 1468 if (ret == EBUSY) { 1469 (void) fprintf(stderr, "%s\n", 1470 gettext( 1471 "Target portal group associated with one or more " 1472 "targets. Cannot delete.")); 1473 } 1474 1475 if (ret == 0) { 1476 ret = it_config_commit(cfg); 1477 STMF_STALE(ret); 1478 } 1479 } 1480 1481 it_config_free(cfg); 1482 1483 return (ret); 1484 } 1485 1486 static int 1487 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create) 1488 { 1489 int ret; 1490 it_config_t *cfg; 1491 it_ini_t *inip; 1492 nvlist_t *errlist = NULL; 1493 nvpair_t *nvp = NULL; 1494 char *sec = "solaris.smf.modify.stmf"; 1495 boolean_t changed = B_TRUE; 1496 1497 ITADM_CHKAUTH(sec); 1498 1499 if (!ini) { 1500 (void) fprintf(stderr, "%s\n", 1501 gettext("Error, no initiator specified")); 1502 return (EINVAL); 1503 } else if (create) { 1504 /* 1505 * validate input name - what are the rules for EUI 1506 * and IQN values? 1507 */ 1508 if ((strncmp(ini, "eui.", 4) != 0) && 1509 (strncmp(ini, "iqn.", 4) != 0)) { 1510 (void) fprintf(stderr, gettext("Invalid name %s"), 1511 ini); 1512 (void) fprintf(stderr, "\n"); 1513 return (EINVAL); 1514 } 1515 } 1516 1517 /* 1518 * See if any properties were actually specified. 1519 */ 1520 if (proplist) { 1521 nvp = nvlist_next_nvpair(proplist, nvp); 1522 } 1523 1524 if ((nvp == NULL) && !create) { 1525 changed = B_FALSE; 1526 } 1527 1528 /* 1529 * If no properties, and this is really a modify op, verify 1530 * that the requested initiator exists, but then don't do anything. 1531 * Modifying non-existent is an error; doing nothing to a defined 1532 * initiator is not. 1533 */ 1534 1535 ret = it_config_load(&cfg); 1536 if (ret != 0) { 1537 (void) fprintf(stderr, 1538 gettext("Error retrieving iSCSI target configuration: %d"), 1539 ret); 1540 (void) fprintf(stderr, "\n"); 1541 return (ret); 1542 } 1543 1544 inip = cfg->config_ini_list; 1545 while (inip) { 1546 if (strcmp(inip->ini_name, ini) == 0) { 1547 break; 1548 } 1549 1550 inip = inip->ini_next; 1551 } 1552 1553 if (create) { 1554 if (inip) { 1555 (void) fprintf(stderr, 1556 gettext("Initiator %s already exists"), 1557 inip->ini_name); 1558 (void) fprintf(stderr, "\n"); 1559 ret = EINVAL; 1560 } else { 1561 ret = it_ini_create(cfg, &inip, ini); 1562 if (ret != 0) { 1563 if (ret == EFAULT) { 1564 (void) fprintf(stderr, 1565 gettext("Invalid iSCSI name %s"), 1566 ini); 1567 } else { 1568 (void) fprintf(stderr, 1569 gettext( 1570 "Error creating initiator: %d"), 1571 ret); 1572 } 1573 (void) fprintf(stderr, "\n"); 1574 } 1575 } 1576 } else if (!inip) { 1577 ret = ENOENT; 1578 (void) fprintf(stderr, 1579 gettext("Error, initiator %s not found."), 1580 ini); 1581 (void) fprintf(stderr, "\n"); 1582 } 1583 1584 if ((ret == 0) && nvp) { 1585 ret = it_ini_setprop(inip, proplist, &errlist); 1586 1587 if (ret != 0) { 1588 (void) fprintf(stderr, 1589 gettext("Error setting initiator properties: %d"), 1590 ret); 1591 (void) fprintf(stderr, "\n"); 1592 if (errlist) { 1593 nvpair_t *nvp = NULL; 1594 char *nn; 1595 char *nv; 1596 1597 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1598 != NULL) { 1599 nv = NULL; 1600 1601 nn = nvpair_name(nvp); 1602 (void) nvpair_value_string(nvp, &nv); 1603 1604 if (nv != NULL) { 1605 (void) fprintf(stderr, 1606 "\t%s: %s\n", nn, nv); 1607 } 1608 } 1609 1610 nvlist_free(errlist); 1611 } 1612 } 1613 } 1614 1615 if ((ret == 0) && changed) { 1616 ret = it_config_commit(cfg); 1617 STMF_STALE(ret); 1618 } 1619 1620 it_config_free(cfg); 1621 1622 return (ret); 1623 } 1624 1625 static int 1626 list_initiator(char *ini, boolean_t verbose, boolean_t script) /* ARGSUSED */ 1627 { 1628 int ret; 1629 it_config_t *cfg; 1630 it_ini_t *ptr; 1631 boolean_t found = B_FALSE; 1632 boolean_t first = B_TRUE; 1633 char *isecret; 1634 char *iuser; 1635 char *sec = "solaris.smf.read.stmf"; 1636 1637 ITADM_CHKAUTH(sec); 1638 1639 ret = it_config_load(&cfg); 1640 if (ret != 0) { 1641 (void) fprintf(stderr, 1642 gettext("Error retrieving iSCSI target configuration: %d"), 1643 ret); 1644 (void) fprintf(stderr, "\n"); 1645 return (ret); 1646 } 1647 1648 ptr = cfg->config_ini_list; 1649 1650 for (; ptr != NULL; ptr = ptr->ini_next) { 1651 isecret = "unset"; 1652 iuser = "<none>"; 1653 1654 if (found) { 1655 break; 1656 } 1657 1658 if (ini) { 1659 if (strcmp(ini, ptr->ini_name) != 0) { 1660 continue; 1661 } else { 1662 found = B_TRUE; 1663 } 1664 } 1665 1666 if (ptr->ini_properties) { 1667 if (nvlist_exists(ptr->ini_properties, "chapsecret")) { 1668 isecret = "set"; 1669 } 1670 (void) nvlist_lookup_string(ptr->ini_properties, 1671 "chapuser", &iuser); 1672 1673 } 1674 1675 /* there's nothing to print for verbose yet */ 1676 if (!script && first) { 1677 (void) printf("%-61s%-10s%-7s\n", "INITIATOR NAME", 1678 "CHAPUSER", "SECRET"); 1679 first = B_FALSE; 1680 } 1681 1682 if (!script) { 1683 /* 1684 * try not to let columns run into each other. 1685 * Stick a tab after too-long fields. 1686 * Lengths chosen are for the 'common' cases. 1687 */ 1688 (void) printf("%-61s", ptr->ini_name); 1689 1690 if (strlen(ptr->ini_name) > 60) { 1691 (void) printf("\t"); 1692 } 1693 1694 (void) printf("%-15s", iuser); 1695 if (strlen(iuser) >= 15) { 1696 (void) printf("\t"); 1697 } 1698 1699 (void) printf("%-4s", isecret); 1700 } else { 1701 (void) printf("%s\t%s\t%s", ptr->ini_name, 1702 iuser, isecret); 1703 } 1704 1705 (void) printf("\n"); 1706 } 1707 1708 if (ini && (!found)) { 1709 (void) fprintf(stderr, 1710 gettext("Initiator %s not found!"), ini); 1711 (void) fprintf(stderr, "\n"); 1712 ret = 1; 1713 } 1714 1715 it_config_free(cfg); 1716 1717 return (ret); 1718 } 1719 1720 int 1721 delete_initiator(char *ini) 1722 { 1723 int ret; 1724 it_config_t *cfg; 1725 it_ini_t *ptr; 1726 char *sec = "solaris.smf.modify.stmf"; 1727 1728 ITADM_CHKAUTH(sec); 1729 1730 if (!ini) { 1731 (void) fprintf(stderr, "%s\n", 1732 gettext("Error, no initiator specified")); 1733 return (EINVAL); 1734 } 1735 1736 ret = it_config_load(&cfg); 1737 if (ret != 0) { 1738 (void) fprintf(stderr, 1739 gettext("Error retrieving iSCSI target configuration: %d"), 1740 ret); 1741 (void) fprintf(stderr, "\n"); 1742 return (ret); 1743 } 1744 1745 ptr = cfg->config_ini_list; 1746 while (ptr) { 1747 if (strcmp(ptr->ini_name, ini) == 0) { 1748 break; 1749 } 1750 1751 ptr = ptr->ini_next; 1752 } 1753 1754 if (ptr) { 1755 it_ini_delete(cfg, ptr); 1756 1757 ret = it_config_commit(cfg); 1758 STMF_STALE(ret); 1759 } else { 1760 (void) fprintf(stderr, 1761 gettext("Initiator %s not found"), ini); 1762 (void) fprintf(stderr, "\n"); 1763 ret = 1; 1764 } 1765 1766 return (ret); 1767 } 1768 1769 static int 1770 modify_defaults(nvlist_t *proplist) 1771 { 1772 int ret; 1773 it_config_t *cfg; 1774 nvlist_t *errlist = NULL; 1775 nvpair_t *nvp = NULL; 1776 char *sec = "solaris.smf.modify.stmf"; 1777 1778 ITADM_CHKAUTH(sec); 1779 1780 if (proplist) { 1781 /* make sure at least one property is specified */ 1782 nvp = nvlist_next_nvpair(proplist, nvp); 1783 } 1784 1785 if (nvp == NULL) { 1786 /* empty list */ 1787 (void) fprintf(stderr, "%s\n", 1788 gettext("Error, no properties specified")); 1789 return (EINVAL); 1790 } 1791 1792 ret = it_config_load(&cfg); 1793 if (ret != 0) { 1794 (void) fprintf(stderr, 1795 gettext("Error retrieving iSCSI target configuration: %d"), 1796 ret); 1797 (void) fprintf(stderr, "\n"); 1798 return (ret); 1799 } 1800 1801 ret = it_config_setprop(cfg, proplist, &errlist); 1802 if (ret != 0) { 1803 (void) fprintf(stderr, 1804 gettext("Error setting global properties: %d"), 1805 ret); 1806 (void) fprintf(stderr, "\n"); 1807 if (errlist) { 1808 nvpair_t *nvp = NULL; 1809 char *nn; 1810 char *nv; 1811 1812 while ((nvp = nvlist_next_nvpair(errlist, nvp)) 1813 != NULL) { 1814 nv = NULL; 1815 1816 nn = nvpair_name(nvp); 1817 (void) nvpair_value_string(nvp, &nv); 1818 1819 if (nv != NULL) { 1820 (void) fprintf(stderr, "\t%s: %s\n", 1821 nn, nv); 1822 } 1823 } 1824 1825 nvlist_free(errlist); 1826 } 1827 } 1828 1829 if (ret == 0) { 1830 ret = it_config_commit(cfg); 1831 STMF_STALE(ret); 1832 } 1833 1834 it_config_free(cfg); 1835 1836 return (ret); 1837 } 1838 1839 static int 1840 list_defaults(boolean_t script) 1841 { 1842 int ret; 1843 it_config_t *cfg; 1844 nvlist_t *nvl; 1845 char *alias = "<none>"; 1846 char *auth = "<none>"; 1847 char *isns = "disabled"; 1848 char **isvrs = NULL; 1849 uint32_t scount = 0; 1850 char *rsvr = "<none>"; 1851 char *rsecret = "unset"; 1852 boolean_t val = B_FALSE; 1853 int i; 1854 char *sec = "solaris.smf.read.stmf"; 1855 1856 ITADM_CHKAUTH(sec); 1857 1858 ret = it_config_load(&cfg); 1859 if (ret != 0) { 1860 (void) fprintf(stderr, 1861 gettext("Error retrieving iSCSI target configuration: %d"), 1862 ret); 1863 (void) fprintf(stderr, "\n"); 1864 return (ret); 1865 } 1866 1867 nvl = cfg->config_global_properties; 1868 1869 /* look up all possible options */ 1870 (void) nvlist_lookup_string(nvl, "alias", &alias); 1871 (void) nvlist_lookup_string(nvl, "auth", &auth); 1872 (void) nvlist_lookup_boolean_value(nvl, "isns", &val); 1873 if (val == B_TRUE) { 1874 isns = "enabled"; 1875 } 1876 (void) nvlist_lookup_string_array(nvl, "isnsserver", &isvrs, 1877 &scount); 1878 (void) nvlist_lookup_string(nvl, "radiusserver", &rsvr); 1879 if (nvlist_exists(nvl, "radiussecret")) { 1880 rsecret = "set"; 1881 } 1882 1883 if (!script) { 1884 (void) printf("%s:\n\n", 1885 gettext("iSCSI Target Default Properties")); 1886 } 1887 1888 if (script) { 1889 (void) printf("%s\t%s\t%s\t%s\t%s\t", 1890 alias, auth, rsvr, rsecret, isns); 1891 } else { 1892 (void) printf("%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n" 1893 "%-15s\t%s\n%-15s\t", 1894 "alias:", alias, "auth:", auth, "radiusserver:", 1895 rsvr, "radiussecret:", rsecret, "isns:", isns, 1896 "isnsserver:"); 1897 } 1898 1899 for (i = 0; i < scount; i++) { 1900 if (!isvrs || !isvrs[i]) { 1901 break; 1902 } 1903 if (i > 0) { 1904 (void) printf(","); 1905 } 1906 (void) printf("%s", isvrs[i]); 1907 } 1908 1909 if (i == 0) { 1910 (void) printf("%s", "<none>"); 1911 } 1912 1913 (void) printf("\n"); 1914 1915 it_config_free(cfg); 1916 1917 return (0); 1918 } 1919 1920 static int 1921 itadm_get_password(nvlist_t *nvl, char *key, char *passfile, 1922 char *phrase) 1923 { 1924 int ret = 0; 1925 char *pass; 1926 char buf[1024]; 1927 int fd; 1928 struct stat64 sbuf; 1929 size_t rd; 1930 1931 if (!nvl || !key) { 1932 return (EINVAL); 1933 } 1934 1935 if (passfile) { 1936 ret = stat64(passfile, &sbuf); 1937 if ((ret != 0) || (!S_ISREG(sbuf.st_mode))) { 1938 (void) fprintf(stderr, 1939 gettext("Invalid secret file %s"), 1940 passfile); 1941 (void) fprintf(stderr, "\n"); 1942 return (EBADF); 1943 } 1944 1945 fd = open64(passfile, O_RDONLY); 1946 if (fd == -1) { 1947 ret = errno; 1948 (void) fprintf(stderr, 1949 gettext("Could not open secret file %s, %d"), 1950 passfile, ret); 1951 (void) fprintf(stderr, "\n"); 1952 return (ret); 1953 } 1954 1955 rd = read(fd, buf, sbuf.st_size); 1956 (void) close(fd); 1957 1958 if (rd != sbuf.st_size) { 1959 ret = EIO; 1960 (void) fprintf(stderr, 1961 gettext("Could not read secret file %s, %d"), 1962 passfile, ret); 1963 (void) fprintf(stderr, "\n"); 1964 return (ret); 1965 } 1966 1967 /* ensure buf is properly terminated */ 1968 buf[rd] = '\0'; 1969 1970 /* if last char is a newline, strip it off */ 1971 if (buf[rd - 1] == '\n') { 1972 buf[rd - 1] = '\0'; 1973 } 1974 1975 /* validate length */ 1976 if ((strlen(buf) > 255) || (strlen(buf) < 12)) { 1977 (void) fprintf(stderr, "%s\n", 1978 gettext( 1979 "Secret must be between 12 and 255 characters")); 1980 return (EINVAL); 1981 } 1982 } else { 1983 /* prompt for secret */ 1984 if (!phrase) { 1985 return (EINVAL); 1986 } 1987 1988 pass = getpassphrase(phrase); 1989 if (!pass) { 1990 ret = errno; 1991 (void) fprintf(stderr, 1992 gettext("Could not read secret, %d"), 1993 ret); 1994 (void) fprintf(stderr, "\n"); 1995 return (ret); 1996 } 1997 1998 /* validate length */ 1999 if ((strlen(pass) > 255) || (strlen(pass) < 12)) { 2000 (void) fprintf(stderr, "%s\n", 2001 gettext( 2002 "Secret must be between 12 and 255 characters")); 2003 return (EINVAL); 2004 } 2005 2006 (void) strlcpy(buf, pass, sizeof (buf)); 2007 2008 /* confirm entered secret */ 2009 pass = getpassphrase(gettext("Re-enter secret: ")); 2010 if (!pass) { 2011 ret = errno; 2012 (void) fprintf(stderr, 2013 gettext("Could not read secret, %d"), 2014 ret); 2015 (void) fprintf(stderr, "\n"); 2016 return (ret); 2017 } 2018 2019 if (strcmp(buf, pass) != 0) { 2020 ret = EINVAL; 2021 (void) fprintf(stderr, "%s\n", 2022 gettext("Secret validation failed")); 2023 return (ret); 2024 } 2025 2026 } 2027 2028 ret = nvlist_add_string(nvl, key, buf); 2029 2030 return (ret); 2031 } 2032 2033 static int 2034 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num) 2035 { 2036 int count; 2037 char *bufp; 2038 char **arr; 2039 2040 if (!opt || !key || !nvl) { 2041 return (EINVAL); 2042 } 2043 2044 bufp = opt; 2045 count = 1; 2046 2047 for (;;) { 2048 bufp = strchr(bufp, ','); 2049 if (!bufp) { 2050 break; 2051 } 2052 bufp++; 2053 count++; 2054 } 2055 2056 arr = calloc(count, sizeof (char *)); 2057 if (!arr) { 2058 return (ENOMEM); 2059 } 2060 2061 bufp = opt; 2062 /* set delimiter to comma */ 2063 (void) bufsplit(",", 0, NULL); 2064 2065 /* split up that buf! */ 2066 (void) bufsplit(bufp, count, arr); 2067 2068 /* if requested, return the number of array members found */ 2069 if (num) { 2070 *num = count; 2071 } 2072 2073 return (nvlist_add_string_array(nvl, key, arr, count)); 2074 } 2075 2076 static void 2077 tag_name_to_num(char *tagname, uint16_t *tagnum) 2078 { 2079 ulong_t id; 2080 char *ptr = NULL; 2081 2082 if (!tagname || !tagnum) { 2083 return; 2084 } 2085 2086 *tagnum = 0; 2087 2088 id = strtoul(tagname, &ptr, 10); 2089 2090 /* Must be entirely numeric and in-range */ 2091 if (ptr && (*ptr != '\0')) { 2092 return; 2093 } 2094 2095 if ((id <= UINT16_MAX) && (id > 1)) { 2096 *tagnum = (uint16_t)id; 2097 } 2098 } 2099