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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <time.h> 29 #include <sys/utsname.h> 30 #include <unistd.h> 31 #include <sys/param.h> 32 #include <fcntl.h> 33 #include <sys/stat.h> 34 #include <errno.h> 35 #include <strings.h> 36 #include <assert.h> 37 #include <sys/socket.h> 38 #include <netdb.h> 39 #include <libgen.h> 40 #include <libzfs.h> 41 #include <syslog.h> 42 43 #include <iscsitgt_impl.h> 44 #include "queue.h" 45 #include "utility.h" 46 #include "iscsi_cmd.h" 47 #include "target.h" 48 #include "errcode.h" 49 #include "isns_client.h" 50 #include "mgmt_scf.h" 51 52 static char *modify_target(tgt_node_t *x, ucred_t *cred); 53 static char *modify_initiator(tgt_node_t *x); 54 static char *modify_admin(tgt_node_t *x); 55 static char *modify_tpgt(tgt_node_t *x); 56 static char *modify_zfs(tgt_node_t *x, ucred_t *cred); 57 static char *validate_zfs_iscsitgt(tgt_node_t *x); 58 static Boolean_t modify_element(char *, char *, tgt_node_t *, match_type_t); 59 static Boolean_t delete_element(char *, tgt_node_t *, match_type_t); 60 61 /* 62 * []---- 63 * | modify_func -- dispatch routine for objects 64 * []---- 65 */ 66 /*ARGSUSED*/ 67 void 68 modify_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, 69 ucred_t *cred) 70 { 71 tgt_node_t *x; 72 char *reply_msg = NULL; 73 74 x = p->x_child; 75 76 if (p->x_child == NULL) { 77 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 78 } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { 79 reply_msg = modify_zfs(x, cred); 80 } else if (check_auth_modify(cred) != True) { 81 xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); 82 } else { 83 if (x->x_name == NULL) { 84 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 85 } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { 86 reply_msg = modify_target(x, cred); 87 } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { 88 reply_msg = modify_initiator(x); 89 } else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) { 90 reply_msg = modify_admin(x); 91 } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { 92 reply_msg = modify_tpgt(x); 93 } else { 94 xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); 95 } 96 } 97 queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); 98 } 99 100 /* 101 * []---- 102 * | modify_target -- updates one or more properties for a target 103 * []---- 104 */ 105 static char * 106 modify_target(tgt_node_t *x, ucred_t *cred) 107 { 108 char *msg = NULL; 109 char *name = NULL; 110 char iscsi_path[MAXPATHLEN]; 111 char targ_name[64]; 112 char *iscsi = NULL; 113 char *prop = NULL; 114 char path[MAXPATHLEN]; 115 char *m; 116 char buf[512]; /* one sector size block */ 117 tgt_node_t *t = NULL; 118 tgt_node_t *list = NULL; 119 tgt_node_t *c = NULL; 120 tgt_node_t *node = NULL; 121 tgt_node_t *tpgt = NULL; 122 Boolean_t change_made = False; 123 int lun = 0; 124 int fd; 125 uint64_t val, new_lu_size, cur_lu_size; 126 struct stat st; 127 uint32_t isns_mods = 0; 128 129 (void) pthread_rwlock_wrlock(&targ_config_mutex); 130 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 131 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 132 goto error; 133 } 134 135 while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, 136 t)) != NULL) { 137 if (strcmp(t->x_value, name) == 0) { 138 break; 139 } 140 } 141 if (t == NULL) { 142 free(name); 143 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 144 goto error; 145 } 146 147 if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) { 148 if (strcmp(m, "true") == 0) { 149 free(m); 150 free(name); 151 (void) pthread_rwlock_unlock(&targ_config_mutex); 152 return (modify_zfs(x, cred)); 153 } 154 free(m); 155 } 156 157 /* 158 * Under base dir, file 'target name' is a symbolic link 159 * to the real directory 'IQN name' which stores params and back 160 * storage. Therefore we can easily get IQN name from target 161 * name by read the symbolic link content. 162 */ 163 (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name); 164 bzero(iscsi_path, sizeof (iscsi_path)); 165 (void) readlink(path, iscsi_path, sizeof (iscsi_path)); 166 iscsi = basename(iscsi_path); 167 168 /* ---- Finished with these so go ahead and release the memory ---- */ 169 (void) strncpy(targ_name, name, sizeof (targ_name)); 170 free(name); 171 172 /* 173 * Grow the LU. We currently do not support shrinking the LU and 174 * that is only because it's unknown if any applications could support 175 * that type of data loss. To support shrinking all that would be 176 * needed is to remove the new/old size check and perform a truncation. 177 * The actually truncation request should be shipped off to the T10 178 * layer so that the LU thread can remap the smaller size without 179 * anyone accessing the data. 180 */ 181 if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) { 182 if (prop == NULL) { 183 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); 184 goto error; 185 } 186 if (strtoll_multiplier(prop, &new_lu_size) == False) { 187 free(prop); 188 xml_rtn_msg(&msg, ERR_INVALID_SIZE); 189 goto error; 190 } 191 free(prop); 192 if ((new_lu_size % 512LL) != 0) { 193 xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK); 194 goto error; 195 } 196 new_lu_size /= 512LL; 197 198 /* ---- default to LUN 0 ---- */ 199 (void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun); 200 201 /* ---- read in current parameters ---- */ 202 if (mgmt_get_param(&node, targ_name, lun) == False) { 203 xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED); 204 goto error; 205 } 206 207 /* ---- validate that we're indeed growing the LU ---- */ 208 if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) == 209 False) { 210 xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); 211 goto error; 212 } 213 if (strtoll_multiplier(prop, &cur_lu_size) == False) { 214 free(prop); 215 xml_rtn_msg(&msg, ERR_INVALID_SIZE); 216 goto error; 217 } 218 free(prop); 219 220 if (new_lu_size < cur_lu_size) { 221 xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU); 222 goto error; 223 } 224 225 /* ---- check that this LU is of type 'disk' or 'tape' ---- */ 226 if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) == 227 False) { 228 xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); 229 goto error; 230 } 231 if ((strcmp(prop, TGT_TYPE_DISK) != 0) && 232 (strcmp(prop, TGT_TYPE_TAPE) != 0)) { 233 xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE); 234 free(prop); 235 goto error; 236 } 237 free(prop); 238 239 /* ---- validate the backing store is a regular file ---- */ 240 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", 241 target_basedir, iscsi, LUNBASE, lun); 242 if (stat(path, &st) == -1) { 243 xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED); 244 goto error; 245 } 246 if ((st.st_mode & S_IFMT) != S_IFREG) { 247 xml_rtn_msg(&msg, 248 ERR_DISK_BACKING_MUST_BE_REGULAR_FILE); 249 goto error; 250 } 251 252 /* ---- update the parameter node with new size ---- */ 253 if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size)) 254 == NULL) { 255 xml_rtn_msg(&msg, ERR_NO_MEM); 256 goto error; 257 } 258 tgt_node_replace(node, c, MatchName); 259 tgt_node_free(c); 260 261 /* ---- now update params file ---- */ 262 (void) mgmt_param_save2scf(node, targ_name, lun); 263 264 /* ---- grow lu backing store ---- */ 265 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", 266 target_basedir, iscsi, LUNBASE, lun); 267 if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) { 268 xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND); 269 goto error; 270 } 271 (void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0); 272 bzero(buf, sizeof (buf)); 273 if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { 274 xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN); 275 (void) close(fd); 276 goto error; 277 } 278 (void) close(fd); 279 280 /* ---- send updates to current initiators via ASC/ASCQ ---- */ 281 iscsi_capacity_change(iscsi, lun); 282 283 prop = NULL; 284 tgt_node_free(node); 285 node = NULL; 286 change_made = True; 287 } 288 289 if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { 290 if (prop == NULL) { 291 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); 292 goto error; 293 } 294 295 /* 296 * Validate that the Target Portal Group Tag is reasonable. 297 */ 298 val = strtoll(prop, &m, 0); 299 if ((val < TPGT_MIN) || (val > TPGT_MAX) || 300 ((m != NULL) && (*m != '\0'))) { 301 xml_rtn_msg(&msg, ERR_INVALID_TPGT); 302 free(prop); 303 goto error; 304 } 305 306 /* update isns only if TPGT contains ip_addr */ 307 tpgt = NULL; 308 while ((tpgt = tgt_node_next_child(main_config, 309 XML_ELEMENT_TPGT, tpgt)) != NULL) { 310 if (strcmp(prop, tpgt->x_value) != 0) 311 continue; 312 if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL) 313 != NULL) { 314 isns_mods |= ISNS_MOD_TPGT; 315 break; 316 } else { 317 xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); 318 free(prop); 319 goto error; 320 } 321 } 322 323 if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == 324 NULL) { 325 free(prop); 326 xml_rtn_msg(&msg, ERR_NO_MEM); 327 goto error; 328 } 329 330 if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, 331 NULL)) != NULL) { 332 tgt_node_replace(list, c, MatchBoth); 333 /* 334 * tgt_node_replace will duplicate the child node 335 * tgt_node_add which is used below just links it 336 * into the tree. 337 */ 338 tgt_node_free(c); 339 } else { 340 list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); 341 if (list == NULL) { 342 free(prop); 343 xml_rtn_msg(&msg, ERR_NO_MEM); 344 goto error; 345 } 346 tgt_node_add(list, c); 347 tgt_node_add(t, list); 348 } 349 350 free(prop); 351 prop = NULL; 352 change_made = True; 353 } 354 355 if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { 356 if (prop == NULL) { 357 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); 358 goto error; 359 } 360 361 c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); 362 if (c == NULL) { 363 xml_rtn_msg(&msg, ERR_NO_MEM); 364 free(prop); 365 goto error; 366 } 367 if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, 368 NULL)) != NULL) { 369 tgt_node_replace(list, c, MatchBoth); 370 /* ---- See above usage ---- */ 371 tgt_node_free(c); 372 } else { 373 list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); 374 if (list == NULL) { 375 xml_rtn_msg(&msg, ERR_NO_MEM); 376 free(prop); 377 goto error; 378 } 379 tgt_node_add(list, c); 380 tgt_node_add(t, list); 381 } 382 free(prop); 383 prop = NULL; 384 change_made = True; 385 } 386 387 if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) { 388 if (prop == NULL) { 389 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS); 390 goto error; 391 } 392 393 if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) == 394 False) { 395 xml_rtn_msg(&msg, ERR_NO_MEM); 396 free(prop); 397 goto error; 398 } 399 free(prop); 400 prop = NULL; 401 isns_mods |= ISNS_MOD_ALIAS; 402 change_made = True; 403 } 404 405 if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) { 406 if (prop == NULL) { 407 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV); 408 goto error; 409 } 410 411 if ((strtoll_multiplier(prop, &val) == False) || 412 (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) { 413 free(prop); 414 xml_rtn_msg(&msg, ERR_INVALID_MAXRECV); 415 goto error; 416 } 417 free(prop); 418 if ((prop = malloc(32)) == NULL) { 419 xml_rtn_msg(&msg, ERR_NO_MEM); 420 goto error; 421 } 422 (void) snprintf(prop, 32, "%d", val); 423 424 if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) == 425 False) { 426 free(prop); 427 xml_rtn_msg(&msg, ERR_NO_MEM); 428 goto error; 429 } 430 free(prop); 431 prop = NULL; 432 change_made = True; 433 } 434 435 if (change_made == True) { 436 if (mgmt_config_save2scf() == False) { 437 xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED); 438 goto error; 439 } 440 if (isns_enabled() == True) { 441 if (isns_dev_update(t->x_value, isns_mods) != 0) { 442 xml_rtn_msg(&msg, ERR_ISNS_ERROR); 443 goto error; 444 } 445 } 446 xml_rtn_msg(&msg, ERR_SUCCESS); 447 } else { 448 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 449 } 450 451 error: 452 (void) pthread_rwlock_unlock(&targ_config_mutex); 453 if (node) 454 tgt_node_free(node); 455 return (msg); 456 } 457 458 /* 459 * []---- 460 * | modify_initiator -- store the CHAP information for an initiator 461 * []---- 462 */ 463 static char * 464 modify_initiator(tgt_node_t *x) 465 { 466 char *msg = NULL; 467 char *name = NULL; 468 char *prop = NULL; 469 tgt_node_t *inode = NULL; 470 Boolean_t changes_made = False; 471 472 (void) pthread_rwlock_wrlock(&targ_config_mutex); 473 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 474 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 475 goto error; 476 } 477 478 while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, 479 inode)) != NULL) { 480 if (strcmp(inode->x_value, name) == 0) 481 break; 482 } 483 484 /* 485 * We no longer need the name since we should have found the node 486 * it refers to and this way we don't have to worry about freeing 487 * the storage later. 488 */ 489 free(name); 490 491 if (inode == NULL) { 492 xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); 493 goto error; 494 } 495 496 if (tgt_find_value_str(x, XML_ELEMENT_CHAPSECRET, &prop) == True) { 497 if (prop == NULL) { 498 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPSECRET); 499 goto error; 500 } 501 502 if (modify_element(XML_ELEMENT_CHAPSECRET, prop, inode, 503 MatchName) == False) { 504 free(prop); 505 xml_rtn_msg(&msg, ERR_NO_MEM); 506 goto error; 507 } 508 free(prop); 509 changes_made = True; 510 } 511 512 if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPSECRET, 513 &prop) == True) { 514 if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { 515 if (prop != NULL) 516 free(prop); 517 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 518 goto error; 519 } 520 free(prop); 521 522 if (delete_element(XML_ELEMENT_CHAPSECRET, inode, 523 MatchName) == False) { 524 xml_rtn_msg(&msg, ERR_NO_MEM); 525 goto error; 526 } 527 changes_made = True; 528 } 529 530 if (tgt_find_value_str(x, XML_ELEMENT_CHAPNAME, &prop) == True) { 531 if (prop == NULL) { 532 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPNAME); 533 goto error; 534 } 535 536 if (modify_element(XML_ELEMENT_CHAPNAME, prop, inode, 537 MatchName) == False) { 538 xml_rtn_msg(&msg, ERR_NO_MEM); 539 free(prop); 540 goto error; 541 } 542 free(prop); 543 changes_made = True; 544 } 545 546 if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPNAME, &prop) == True) { 547 if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { 548 if (prop != NULL) 549 free(prop); 550 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 551 goto error; 552 } 553 free(prop); 554 555 556 if (delete_element(XML_ELEMENT_CHAPNAME, inode, 557 MatchName) == False) { 558 xml_rtn_msg(&msg, ERR_NO_MEM); 559 goto error; 560 } 561 changes_made = True; 562 } 563 564 if (changes_made == True) { 565 if (mgmt_config_save2scf() == True) { 566 xml_rtn_msg(&msg, ERR_SUCCESS); 567 } else { 568 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 569 } 570 } else { 571 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 572 } 573 574 error: 575 (void) pthread_rwlock_unlock(&targ_config_mutex); 576 return (msg); 577 } 578 579 /* 580 * []---- 581 * | modify_admin -- modify one or more of the admin related props 582 * []---- 583 */ 584 static char * 585 modify_admin(tgt_node_t *x) 586 { 587 char *msg = NULL; 588 char *prop; 589 Boolean_t changes_made = False; 590 Boolean_t update_isns = False; 591 admin_table_t *ap; 592 593 for (ap = admin_prop_list; ap->name; ap++) { 594 if (tgt_find_value_str(x, ap->name, &prop) == True) { 595 596 if ((prop == NULL) || (strlen(prop) == 0)) 597 break; 598 599 /* 600 * Do the function call first if it exists which 601 * will allow possible checking to be done first. 602 */ 603 if (ap->func) { 604 msg = (*ap->func)(ap->name, prop); 605 if (msg != NULL) { 606 free(prop); 607 return (msg); 608 } 609 } 610 611 (void) pthread_rwlock_wrlock(&targ_config_mutex); 612 if (ap->delete_name == NULL) { 613 if (modify_element(ap->name, prop, main_config, 614 MatchName) == False) { 615 xml_rtn_msg(&msg, ERR_NO_MEM); 616 free(prop); 617 (void) pthread_rwlock_unlock( 618 &targ_config_mutex); 619 return (msg); 620 } 621 } else { 622 if (strcmp(prop, XML_VALUE_TRUE) != 0) { 623 xml_rtn_msg(&msg, 624 ERR_SYNTAX_MISSING_OPERAND); 625 free(prop); 626 (void) pthread_rwlock_unlock( 627 &targ_config_mutex); 628 return (msg); 629 } 630 if (delete_element(ap->delete_name, 631 main_config, MatchName) == False) { 632 xml_rtn_msg(&msg, ERR_NO_MEM); 633 free(prop); 634 (void) pthread_rwlock_unlock( 635 &targ_config_mutex); 636 return (msg); 637 } 638 } 639 (void) pthread_rwlock_unlock(&targ_config_mutex); 640 if (0 == strcmp(ap->name, XML_ELEMENT_ISNS_ACCESS) || 641 0 == strcmp(ap->name, XML_ELEMENT_ISNS_SERV)) { 642 update_isns = True; 643 } 644 free(prop); 645 changes_made = True; 646 } 647 } 648 649 if (changes_made == True) { 650 /* isns_update updates isns_access & isns server name */ 651 if (update_isns == True) { 652 if (isns_update() != 0) { 653 xml_rtn_msg(&msg, ERR_ISNS_ERROR); 654 return (msg); 655 } 656 } 657 if (mgmt_config_save2scf() == True) { 658 xml_rtn_msg(&msg, ERR_SUCCESS); 659 } else { 660 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 661 } 662 } else { 663 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 664 } 665 666 return (msg); 667 } 668 669 /* 670 * []---- 671 * | modify_tpgt -- add an IP-address to a target portal group 672 * []---- 673 */ 674 static char * 675 modify_tpgt(tgt_node_t *x) 676 { 677 struct addrinfo *res = NULL; 678 char *msg = NULL; 679 char *name = NULL; 680 char *ip_str = NULL; 681 tgt_node_t *tnode = NULL; 682 tgt_node_t *list = NULL; 683 684 (void) pthread_rwlock_wrlock(&targ_config_mutex); 685 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 686 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 687 goto error; 688 } 689 if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) { 690 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR); 691 goto error; 692 } 693 if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) { 694 xml_rtn_msg(&msg, ERR_INVALID_IP); 695 goto error; 696 } 697 while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, 698 tnode)) != NULL) { 699 if (strcmp(tnode->x_value, name) == 0) 700 break; 701 } 702 if (tnode == NULL) { 703 xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); 704 goto error; 705 } 706 707 if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL)) 708 == NULL) { 709 list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, ""); 710 if (list == NULL) { 711 xml_rtn_msg(&msg, ERR_NO_MEM); 712 goto error; 713 } 714 tgt_node_add(tnode, list); 715 } 716 if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) == 717 False) { 718 xml_rtn_msg(&msg, ERR_NO_MEM); 719 goto error; 720 } 721 722 if (mgmt_config_save2scf() == True) { 723 xml_rtn_msg(&msg, ERR_SUCCESS); 724 } else { 725 /* tpgt change should be updated to smf */ 726 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 727 } 728 729 /* 730 * Re-register all targets, currently there's no method to 731 * update TPGT for individual target 732 */ 733 if (isns_enabled() == True) { 734 (void) isns_reg_all(); 735 } 736 737 error: 738 if (name) 739 free(name); 740 if (ip_str) 741 free(ip_str); 742 if (res) 743 freeaddrinfo(res); 744 (void) pthread_rwlock_unlock(&targ_config_mutex); 745 return (msg); 746 } 747 748 /* 749 * modify_zfs -- test for the existence of a certain dataset being shared 750 * 751 * Called when someone uses the iscsitgt_is_shared() function from libiscsitgt. 752 * All that 753 */ 754 static char * 755 modify_zfs(tgt_node_t *x, ucred_t *cred) 756 { 757 char *msg = NULL; 758 char *dataset = NULL; 759 char *prop; 760 char *m; 761 tgt_node_t *n = NULL; 762 tgt_node_t *t = NULL; 763 tgt_node_t *list = NULL; 764 tgt_node_t *c1, *c2; 765 Boolean_t change_made = False; 766 uint64_t size; 767 int status; 768 int val; 769 char *tru = "true"; 770 771 (void) pthread_rwlock_wrlock(&targ_config_mutex); 772 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { 773 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 774 goto error; 775 } 776 777 /* 778 * Validate request 779 */ 780 if (tgt_find_value_str(x, XML_ELEMENT_VALIDATE, &tru)) { 781 (void) pthread_rwlock_unlock(&targ_config_mutex); 782 if (tru) 783 free(tru); 784 free(dataset); 785 return (validate_zfs_iscsitgt(x)); 786 } 787 788 /* 789 * Check for existance of ZFS shareiscsi properties 790 */ 791 status = get_zfs_shareiscsi(dataset, &n, &size, cred); 792 if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) { 793 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 794 goto error; 795 } 796 797 while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) 798 != NULL) { 799 if (strcmp(t->x_value, dataset) == 0) 800 break; 801 } 802 if (t == NULL) { 803 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 804 goto error; 805 } 806 807 if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { 808 if (prop == NULL) { 809 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); 810 goto error; 811 } 812 813 /* 814 * Validate that the Target Portal Group Tag is reasonable. 815 */ 816 val = strtoll(prop, &m, 0); 817 if ((val < TPGT_MIN) || (val > TPGT_MAX) || 818 ((m != NULL) && (*m != '\0'))) { 819 xml_rtn_msg(&msg, ERR_INVALID_TPGT); 820 goto error; 821 } 822 823 if ((c1 = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == 824 NULL) { 825 xml_rtn_msg(&msg, ERR_NO_MEM); 826 goto error; 827 } 828 829 /* 830 * Due to the fact that the targets_config differs from the 831 * ZVOL properties stored in zfs_shareiscsi, two lists need to 832 * be updated 833 */ 834 c2 = tgt_node_dup(c1); 835 if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) 836 != NULL) { 837 /* 838 * tgt_node_replace will duplicate the child node 839 * tgt_node_add which is used below just links it 840 * into the tree. 841 */ 842 tgt_node_replace(list, c1, MatchBoth); 843 tgt_node_free(c1); 844 } else { 845 list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); 846 if (list == NULL) { 847 xml_rtn_msg(&msg, ERR_NO_MEM); 848 goto error; 849 } 850 tgt_node_add(list, c1); 851 tgt_node_add(t, list); 852 } 853 if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL)) 854 != NULL) { 855 /* 856 * tgt_node_replace will duplicate the child node 857 * tgt_node_add which is used below just links it 858 * into the tree. 859 */ 860 tgt_node_replace(list, c2, MatchBoth); 861 tgt_node_free(c2); 862 } else { 863 list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); 864 if (list == NULL) { 865 xml_rtn_msg(&msg, ERR_NO_MEM); 866 goto error; 867 } 868 tgt_node_add(list, c2); 869 tgt_node_add(n, list); 870 } 871 change_made = True; 872 } 873 874 if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { 875 if (prop == NULL) { 876 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); 877 goto error; 878 } 879 880 c1 = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); 881 if (c1 == NULL) { 882 xml_rtn_msg(&msg, ERR_NO_MEM); 883 goto error; 884 } 885 886 /* 887 * Due to the fact that the targets_config differs from the 888 * ZVOL properties stored in zfs_shareiscsi, two lists need to 889 * be updated 890 */ 891 c2 = tgt_node_dup(c1); 892 if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) 893 != NULL) { 894 /* 895 * tgt_node_replace will duplicate the child node 896 * tgt_node_add which is used below just links it 897 * into the tree. 898 */ 899 tgt_node_replace(list, c1, MatchBoth); 900 tgt_node_free(c1); 901 } else { 902 list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); 903 if (list == NULL) { 904 xml_rtn_msg(&msg, ERR_NO_MEM); 905 goto error; 906 } 907 tgt_node_add(list, c1); 908 tgt_node_add(t, list); 909 } 910 if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL)) 911 != NULL) { 912 /* 913 * tgt_node_replace will duplicate the child node 914 * tgt_node_add which is used below just links it 915 * into the tree. 916 */ 917 tgt_node_replace(list, c2, MatchBoth); 918 tgt_node_free(c2); 919 } else { 920 list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); 921 if (list == NULL) { 922 xml_rtn_msg(&msg, ERR_NO_MEM); 923 goto error; 924 } 925 tgt_node_add(list, c2); 926 tgt_node_add(n, list); 927 } 928 929 change_made = True; 930 } 931 932 if (change_made == True) { 933 status = put_zfs_shareiscsi(dataset, n); 934 if (status != ERR_SUCCESS) { 935 xml_rtn_msg(&msg, status); 936 goto error; 937 } else { 938 xml_rtn_msg(&msg, ERR_SUCCESS); 939 } 940 } else { 941 xml_rtn_msg(&msg, ERR_SUCCESS); 942 } 943 944 error: 945 if (n) 946 tgt_node_free(n); 947 if (dataset) 948 free(dataset); 949 950 (void) pthread_rwlock_unlock(&targ_config_mutex); 951 return (msg); 952 } 953 954 /* 955 * Just checking the existance of the given target. Here we check whether 956 * both zfs and iscsitarget aware of the given target/volume. It neither 957 * care about the credentials nor SHAREISCSI properties. 958 */ 959 static char * 960 validate_zfs_iscsitgt(tgt_node_t *x) 961 { 962 char *msg = NULL; 963 char *prop = NULL; 964 char *dataset = NULL; 965 libzfs_handle_t *zh = NULL; 966 zfs_handle_t *zfsh = NULL; 967 tgt_node_t *n = NULL; 968 969 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { 970 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 971 return (msg); 972 } 973 974 if (((zh = libzfs_init()) == NULL) || 975 ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { 976 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 977 goto error; 978 } 979 980 while ((n = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, n)) != 981 NULL) { 982 if (strcmp(n->x_value, dataset) == 0) 983 break; 984 } 985 if (n == NULL) { 986 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 987 goto error; 988 } 989 990 xml_rtn_msg(&msg, ERR_SUCCESS); 991 992 error: 993 if (zfsh) 994 zfs_close(zfsh); 995 if (prop) 996 free(prop); 997 if (zh) 998 libzfs_fini(zh); 999 if (dataset) 1000 free(dataset); 1001 1002 return (msg); 1003 1004 } 1005 1006 1007 /* 1008 * []---- 1009 * | modify_element -- helper function to create node and add it to parent 1010 * | 1011 * | A False return value indicates a failure to allocate enough memory. 1012 * []---- 1013 */ 1014 static Boolean_t 1015 modify_element(char *name, char *value, tgt_node_t *p, match_type_t m) 1016 { 1017 tgt_node_t *c; 1018 1019 1020 if ((c = tgt_node_alloc(name, String, value)) == NULL) { 1021 return (False); 1022 } else { 1023 tgt_node_replace(p, c, m); 1024 tgt_node_free(c); 1025 return (True); 1026 } 1027 } 1028 1029 /* 1030 * []---- 1031 * | delete_element -- helper function to remove a node from a parent 1032 * | 1033 * | A False return value indicates a failure to allocate enough memory. 1034 * []---- 1035 */ 1036 static Boolean_t 1037 delete_element(char *name, tgt_node_t *p, match_type_t m) 1038 { 1039 tgt_node_t *c; 1040 1041 if ((c = tgt_node_alloc(name, String, NULL)) == NULL) { 1042 return (False); 1043 } 1044 tgt_node_remove(p, c, m); 1045 tgt_node_free(c); 1046 return (True); 1047 } 1048 1049 /* 1050 * []---- 1051 * | update_basedir -- update the global target directory 1052 * | 1053 * | Most of the properties when updated require no futher processing. The 1054 * | target base directory however must be updated if it hasn't been set. 1055 * | On a new system the daemon will not have any location to place the 1056 * | backing store and target configuration files. On a live system we would 1057 * | screw things up if we changed the global variable if it was already 1058 * | in use, so we only allow the updating to occur if there are no targets. 1059 * []---- 1060 */ 1061 /*ARGSUSED*/ 1062 char * 1063 update_basedir(char *name, char *prop) 1064 { 1065 tgt_node_t *targ = NULL; 1066 char *msg = NULL; 1067 char *v; 1068 1069 if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) { 1070 xml_rtn_msg(&msg, ERR_INVALID_BASEDIR); 1071 return (msg); 1072 } 1073 1074 while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, 1075 targ)) != NULL) { 1076 /* 1077 * Traverse the list of configured targets, serching for any 1078 * target that is using the current base-directory. Fail the 1079 * update if found. 1080 * 1081 * The only targets that do not use the base-directory at this 1082 * time are those targets persisted in ZFS. 1083 */ 1084 if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &v) == True) { 1085 if (v != NULL) { 1086 if (strcmp(v, XML_VALUE_TRUE) == 0) { 1087 free(v); 1088 continue; 1089 } 1090 free(v); 1091 } 1092 } 1093 1094 /* 1095 * Found at least one target, so fail 1096 */ 1097 xml_rtn_msg(&msg, ERR_VALID_TARG_EXIST); 1098 return (msg); 1099 } 1100 1101 if (target_basedir) { 1102 free(target_basedir); 1103 } 1104 target_basedir = strdup(prop); 1105 if ((mkdir(target_basedir, 0700) != 0) && (errno != EEXIST)) { 1106 xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED); 1107 free(target_basedir); 1108 target_basedir = NULL; 1109 } 1110 return (msg); 1111 } 1112 1113 /* 1114 * []---- 1115 * | validate_radius -- validate that server[:port] are valid 1116 * []---- 1117 */ 1118 char * 1119 valid_radius_srv(char *name, char *prop) 1120 { 1121 struct addrinfo *res = NULL; 1122 char *msg = NULL; 1123 char *sp, *p; 1124 int port; 1125 1126 if ((sp = strdup(prop)) == NULL) { 1127 xml_rtn_msg(&msg, ERR_NO_MEM); 1128 return (msg); 1129 } else if ((p = strrchr(sp, ':')) != NULL) { 1130 *p++ = '\0'; 1131 port = atoi(p); 1132 if ((port < 1) || (port > 65535)) { 1133 xml_rtn_msg(&msg, ERR_INVALID_RADSRV); 1134 free(sp); 1135 return (msg); 1136 } 1137 } 1138 if ((getaddrinfo(sp, NULL, NULL, &res) != 0) || (res == NULL)) 1139 xml_rtn_msg(&msg, ERR_INVALID_RADSRV); 1140 else 1141 freeaddrinfo(res); 1142 free(sp); 1143 return (msg); 1144 } 1145 1146 /* 1147 * []---- 1148 * | validate_isns_server -- validate that server[:port] are valid 1149 * []---- 1150 */ 1151 char * 1152 valid_isns_srv(char *name, char *prop) 1153 { 1154 char *msg = NULL; 1155 char *sp, *p; 1156 int so; 1157 int port; 1158 1159 if (strlen(prop) > MAXHOSTNAMELEN) { 1160 xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); 1161 return (msg); 1162 } 1163 1164 if ((sp = strdup(prop)) == NULL) { 1165 xml_rtn_msg(&msg, ERR_NO_MEM); 1166 return (msg); 1167 } 1168 if ((p = strrchr(sp, ':')) != NULL) { 1169 *p++ = '\0'; 1170 port = atoi(p); 1171 if ((port < 1) || (port > 65535)) { 1172 xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); 1173 free(sp); 1174 return (msg); 1175 } 1176 } 1177 1178 so = isns_open(sp); 1179 if (so < 0) { 1180 if (isns_enabled() == True) { 1181 xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); 1182 } else { /* Just print a warning and accept the server */ 1183 syslog(LOG_ALERT, 1184 "Check if the server:%s is valid", sp); 1185 } 1186 } else { 1187 isns_close(so); 1188 } 1189 free(sp); 1190 return (msg); 1191 } 1192