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 /* 28 * This file deals with XML data for removing various configuration data. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <errno.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <priv.h> 37 #include <syslog.h> 38 #include <libzfs.h> 39 40 #include <iscsitgt_impl.h> 41 #include "utility.h" 42 #include "queue.h" 43 #include "target.h" 44 #include "iscsi_cmd.h" 45 #include "errcode.h" 46 #include "isns_client.h" 47 #include "mgmt_scf.h" 48 49 static char *remove_target(tgt_node_t *x, ucred_t *cred); 50 static char *remove_initiator(tgt_node_t *x); 51 static char *remove_tpgt(tgt_node_t *x); 52 static char *remove_zfs(tgt_node_t *x, ucred_t *cred); 53 54 55 /*ARGSUSED*/ 56 void 57 remove_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, 58 ucred_t *cred) 59 { 60 tgt_node_t *x; 61 char msgbuf[80]; 62 char *reply_msg = NULL; 63 64 x = p->x_child; 65 66 /* 67 * remove_zfs() does not affect SMF data 68 * therefore it is not covered by auth check 69 */ 70 if (x == NULL) { 71 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 72 } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { 73 reply_msg = remove_zfs(x, cred); 74 } else if (check_auth_addremove(cred) != True) { 75 xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); 76 } else { 77 if (x->x_name == NULL) { 78 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 79 } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { 80 reply_msg = remove_target(x, cred); 81 } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { 82 reply_msg = remove_initiator(x); 83 } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { 84 reply_msg = remove_tpgt(x); 85 } else { 86 (void) snprintf(msgbuf, sizeof (msgbuf), 87 "Unknown object '%s' for delete element", 88 x->x_name); 89 xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); 90 } 91 } 92 queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); 93 } 94 95 /* 96 * remove_zfs -- remove a ZFS property, or the entire ZVOL 97 */ 98 static char * 99 remove_zfs(tgt_node_t *x, ucred_t *cred) 100 { 101 char *msg = NULL; 102 char *dataset = NULL; 103 char *prop = NULL; 104 tgt_node_t *n = NULL; 105 tgt_node_t *t = NULL; 106 tgt_node_t *list = NULL; 107 tgt_node_t *c; 108 Boolean_t change_made = False; 109 uint64_t size; 110 int status; 111 112 (void) pthread_rwlock_wrlock(&targ_config_mutex); 113 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { 114 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 115 goto error; 116 } 117 118 /* 119 * Check for existance of ZFS shareiscsi properties 120 */ 121 status = get_zfs_shareiscsi(dataset, &n, &size, cred); 122 123 if ((status != ERR_SUCCESS) && (status != ERR_ZFS_ISCSISHARE_OFF) && 124 (status != ERR_NULL_XML_MESSAGE)) { 125 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 126 goto error; 127 } 128 129 while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) 130 != NULL) { 131 if (strcmp(t->x_value, dataset) == 0) 132 break; 133 } 134 135 if (t == NULL) { 136 if (status == ERR_ZFS_ISCSISHARE_OFF) { 137 /* 138 * This is iscsishare=off request from zfs on a target 139 * which is already unshared. In that case, zfs expects 140 * "success" result. 141 */ 142 xml_rtn_msg(&msg, ERR_SUCCESS); 143 } else { 144 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 145 } 146 goto error; 147 } 148 149 if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { 150 if (prop == NULL) { 151 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); 152 goto error; 153 } 154 if (status == ERR_ZFS_ISCSISHARE_OFF) { 155 xml_rtn_msg(&msg, status); 156 goto error; 157 } 158 159 /* 160 * Due to the fact that the targets_config differs from the 161 * ZVOL properties stored in zfs_shareiscsi, two lists need to 162 * be updated 163 */ 164 c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); 165 if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) != 166 NULL) { 167 tgt_node_remove(list, c, MatchBoth); 168 if (list->x_child == NULL) 169 (void) tgt_node_remove(t, list, MatchName); 170 } 171 if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL)) != 172 NULL) { 173 tgt_node_remove(list, c, MatchBoth); 174 if (list->x_child == NULL) 175 (void) tgt_node_remove(n, list, MatchName); 176 } 177 tgt_node_free(c); 178 179 /* update isns */ 180 if (isns_enabled()) { 181 if (isns_dev_update(t->x_value, ISNS_MOD_TPGT) != 0) 182 syslog(LOG_ALERT, "ISNS register failed\n"); 183 } 184 free(prop); 185 prop = NULL; 186 change_made = True; 187 } 188 189 if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { 190 if (prop == NULL) { 191 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); 192 goto error; 193 } 194 if (status == ERR_ZFS_ISCSISHARE_OFF) { 195 xml_rtn_msg(&msg, status); 196 goto error; 197 } 198 /* 199 * Due to the fact that the targets_config differs from the 200 * ZVOL properties stored in zfs_shareiscsi, two lists need to 201 * be updated 202 */ 203 c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); 204 if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) != 205 NULL) { 206 tgt_node_remove(list, c, MatchBoth); 207 if (list->x_child == NULL) 208 (void) tgt_node_remove(t, list, MatchName); 209 } 210 if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL)) != 211 NULL) { 212 tgt_node_remove(list, c, MatchBoth); 213 if (list->x_child == NULL) 214 (void) tgt_node_remove(n, list, MatchName); 215 } 216 tgt_node_free(c); 217 free(prop); 218 prop = NULL; 219 change_made = True; 220 } 221 222 if (change_made == False) { 223 if (tgt_find_value_str(t, XML_ELEMENT_INAME, &prop) == False) { 224 xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); 225 goto error; 226 } 227 228 /* deregister zovl target from iSNS server. */ 229 if (isns_enabled() == True) { 230 if (isns_dereg(prop) != 0) 231 syslog(LOG_INFO, "ISNS dereg failed\n"); 232 } 233 234 tgt_node_remove(targets_config, t, MatchBoth); 235 236 /* 237 * Wait until here to issue a logout to any initiators that 238 * might be logged into the target. Certain initiators are 239 * sneaky in that if asked to logout they will, but turn right 240 * around and log back into the target. By waiting here to issue 241 * the logout we'll have removed reference to the target such 242 * that this can't happen. 243 */ 244 logout_targ(prop); 245 thick_provo_stop(prop, 0); 246 247 xml_rtn_msg(&msg, ERR_SUCCESS); 248 } else { 249 status = put_zfs_shareiscsi(dataset, n); 250 if (status != ERR_SUCCESS) { 251 xml_rtn_msg(&msg, status); 252 goto error; 253 } else { 254 xml_rtn_msg(&msg, ERR_SUCCESS); 255 } 256 } 257 258 error: 259 if (prop) 260 free(prop); 261 if (n) 262 tgt_node_free(n); 263 if (dataset) 264 free(dataset); 265 (void) pthread_rwlock_unlock(&targ_config_mutex); 266 return (msg); 267 } 268 269 static char * 270 remove_target(tgt_node_t *x, ucred_t *cred) 271 { 272 char *msg = NULL; 273 char *prop = NULL; 274 tgt_node_t *targ = NULL; 275 tgt_node_t *list; 276 tgt_node_t *c = NULL; 277 Boolean_t change_made = False; 278 int lun_num; 279 280 (void) pthread_rwlock_wrlock(&targ_config_mutex); 281 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { 282 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 283 goto error; 284 } 285 286 while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, 287 targ)) != NULL) { 288 if (strcmp(targ->x_value, prop) == 0) 289 break; 290 } 291 free(prop); 292 prop = NULL; 293 if (targ == NULL) { 294 xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); 295 goto error; 296 } 297 298 if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &prop) == True) { 299 if (strcmp(prop, "true") == 0) { 300 free(prop); 301 (void) pthread_rwlock_unlock(&targ_config_mutex); 302 return (remove_zfs(x, cred)); 303 } 304 free(prop); 305 } 306 307 if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { 308 if (prop == NULL) { 309 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); 310 goto error; 311 } 312 if ((list = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == 313 NULL) { 314 xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); 315 goto error; 316 } 317 c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); 318 if (tgt_node_remove(list, c, MatchBoth) == False) { 319 xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); 320 goto error; 321 } 322 tgt_node_free(c); 323 if (list->x_child == NULL) 324 (void) tgt_node_remove(targ, list, MatchName); 325 free(prop); 326 change_made = True; 327 } 328 if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { 329 if (prop == NULL) { 330 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); 331 goto error; 332 } 333 if ((list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) == 334 NULL) { 335 xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); 336 goto error; 337 } 338 c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); 339 if (tgt_node_remove(list, c, MatchBoth) == False) { 340 xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); 341 goto error; 342 } 343 tgt_node_free(c); 344 if (list->x_child == NULL) 345 (void) tgt_node_remove(targ, list, MatchName); 346 347 /* update isns */ 348 if (isns_enabled()) { 349 if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0) 350 syslog(LOG_ALERT, "ISNS register failed\n"); 351 } 352 353 free(prop); 354 prop = NULL; 355 change_made = True; 356 } 357 if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) { 358 359 if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun_num) == 360 False) { 361 xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); 362 goto error; 363 } 364 365 /* 366 * Save the iscsi-name which we'll need to remove LUNs. 367 */ 368 if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == 369 False) { 370 xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); 371 goto error; 372 } 373 374 logout_targ(prop); 375 thick_provo_stop(prop, lun_num); 376 377 remove_target_common(targ->x_value, lun_num, &msg); 378 if (msg != NULL) 379 goto error; 380 381 /* ISNS de-register target if it's the last lun */ 382 if (lun_num == 0 && isns_enabled() == True) { 383 if (isns_dereg(prop) != 0) 384 syslog(LOG_INFO, "ISNS dereg failed\n"); 385 } 386 387 iscsi_inventory_change(prop); 388 free(prop); 389 change_made = True; 390 } 391 392 if (change_made == True) { 393 if (mgmt_config_save2scf() == True) { 394 xml_rtn_msg(&msg, ERR_SUCCESS); 395 } else { 396 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 397 } 398 } else { 399 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 400 } 401 402 (void) pthread_rwlock_unlock(&targ_config_mutex); 403 return (msg); 404 405 error: 406 if (c != NULL) 407 tgt_node_free(c); 408 if (prop != NULL) 409 free(prop); 410 (void) pthread_rwlock_unlock(&targ_config_mutex); 411 return (msg); 412 } 413 414 static char * 415 remove_initiator(tgt_node_t *x) 416 { 417 char *msg = NULL; 418 char *name; 419 tgt_node_t *node = NULL; 420 421 (void) pthread_rwlock_wrlock(&targ_config_mutex); 422 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 423 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 424 (void) pthread_rwlock_unlock(&targ_config_mutex); 425 return (msg); 426 } 427 while ((node = tgt_node_next_child(main_config, XML_ELEMENT_INIT, node)) 428 != NULL) { 429 if (strcmp(node->x_value, name) == 0) 430 break; 431 } 432 free(name); 433 if (node == NULL) { 434 xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); 435 (void) pthread_rwlock_unlock(&targ_config_mutex); 436 return (msg); 437 } 438 if (tgt_find_value_str(x, XML_ELEMENT_ALL, &name) == False) { 439 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_ALL); 440 (void) pthread_rwlock_unlock(&targ_config_mutex); 441 return (msg); 442 } 443 (void) tgt_node_remove(main_config, node, MatchBoth); 444 445 if (mgmt_config_save2scf() == True) { 446 xml_rtn_msg(&msg, ERR_SUCCESS); 447 } else { 448 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 449 } 450 451 free(name); 452 (void) pthread_rwlock_unlock(&targ_config_mutex); 453 return (msg); 454 } 455 456 static char * 457 remove_tpgt(tgt_node_t *x) 458 { 459 char *msg = NULL; 460 char *prop = NULL; 461 tgt_node_t *targ = NULL; 462 tgt_node_t *lnode = NULL; 463 tgt_node_t *lnp = NULL; 464 tgt_node_t *node = NULL; 465 tgt_node_t *c = NULL; 466 tgt_node_t *list = NULL; 467 Boolean_t change_made = False; 468 469 (void) pthread_rwlock_wrlock(&targ_config_mutex); 470 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { 471 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 472 (void) pthread_rwlock_unlock(&targ_config_mutex); 473 return (msg); 474 } 475 while ((node = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, node)) 476 != NULL) { 477 if (strcmp(node->x_value, prop) == 0) 478 break; 479 } 480 if (node == NULL) { 481 xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); 482 free(prop); 483 (void) pthread_rwlock_unlock(&targ_config_mutex); 484 return (msg); 485 } 486 while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, 487 targ)) != NULL) { 488 if ((lnode = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, 489 NULL)) != NULL) { 490 lnp = NULL; 491 while ((lnp = tgt_node_next_child(lnode, XML_ELEMENT_TPGT, 492 lnp)) != NULL) 493 if (strcmp(lnp->x_value, prop) == 0) { 494 xml_rtn_msg(&msg, ERR_TPGT_IN_USE); 495 free(prop); 496 (void) pthread_rwlock_unlock( 497 &targ_config_mutex); 498 return (msg); 499 } 500 } 501 } 502 free(prop); 503 if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &prop) == True) { 504 if (prop == NULL) { 505 xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_IPADDR); 506 (void) pthread_rwlock_unlock(&targ_config_mutex); 507 return (msg); 508 } 509 if ((list = tgt_node_next(node, XML_ELEMENT_IPADDRLIST, NULL)) 510 == NULL) { 511 xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); 512 goto error; 513 } 514 c = tgt_node_alloc(XML_ELEMENT_IPADDR, String, prop); 515 if (tgt_node_remove(list, c, MatchBoth) == False) { 516 xml_rtn_msg(&msg, ERR_INVALID_IP); 517 goto error; 518 } 519 tgt_node_free(c); 520 free(prop); 521 if (list->x_child == NULL) 522 (void) tgt_node_remove(node, list, MatchName); 523 change_made = True; 524 } 525 if ((change_made != True) && 526 (tgt_find_value_str(x, XML_ELEMENT_ALL, &prop) == True)) { 527 tgt_node_remove(main_config, node, MatchBoth); 528 change_made = True; 529 free(prop); 530 } 531 532 if (change_made == True) { 533 /* Isns re-register all target */ 534 if (isns_enabled() == True) 535 (void) isns_reg_all(); 536 if (mgmt_config_save2scf() == True) { 537 xml_rtn_msg(&msg, ERR_SUCCESS); 538 } else { 539 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 540 } 541 } else { 542 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); 543 } 544 545 (void) pthread_rwlock_unlock(&targ_config_mutex); 546 return (msg); 547 548 error: 549 if (c != NULL) 550 tgt_node_free(c); 551 if (prop != NULL) 552 free(prop); 553 (void) pthread_rwlock_unlock(&targ_config_mutex); 554 return (msg); 555 } 556