Home | History | Annotate | Download | only in iscsitgtd
      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