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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <time.h> 32 #include <unistd.h> 33 #include <pthread.h> 34 #include <sys/conf.h> 35 #include <sys/socket.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <assert.h> 39 #include <errno.h> 40 #include <signal.h> 41 #include <siginfo.h> 42 #include <libscf.h> 43 #include <syslog.h> 44 #include <synch.h> 45 #include <libxml/xmlreader.h> 46 #include <sys/resource.h> 47 #include <sys/select.h> 48 #include <iscsitgt_impl.h> 49 #include <umem.h> 50 #include <priv.h> 51 #include <libgen.h> 52 #include <ctype.h> 53 #include <pthread.h> 54 #include <pwd.h> 55 #include <auth_attr.h> 56 #include <sasl/saslutil.h> 57 #include <sys/wait.h> 58 59 #include "mgmt_scf.h" 60 #include "port.h" 61 #include "iscsi_conn.h" 62 #include "target.h" 63 #include "utility.h" 64 #include "iscsi_ffp.h" 65 #include "errcode.h" 66 #include "t10.h" 67 68 static Boolean_t create_pg(targ_scf_t *h, char *pgname, char *prop); 69 static void new_property(targ_scf_t *h, tgt_node_t *n); 70 static void new_value_list(targ_scf_t *h, tgt_node_t *p); 71 static int isnumber(char *s); 72 static void backup(char *file, char *ext); 73 static pthread_mutex_t scf_conf_mutex; 74 static pthread_mutex_t scf_param_mutex; 75 76 static void pgname_encode(char *instr, char *outstr, int max_len); 77 static void pgname_decode(char *instr); 78 79 Boolean_t 80 mgmt_scf_init() 81 { 82 (void) pthread_mutex_init(&scf_conf_mutex, NULL); 83 (void) pthread_mutex_init(&scf_param_mutex, NULL); 84 return (True); 85 } 86 87 void 88 mgmt_scf_fini() 89 { 90 (void) pthread_mutex_destroy(&scf_conf_mutex); 91 (void) pthread_mutex_destroy(&scf_param_mutex); 92 } 93 94 void 95 mgmt_handle_fini(targ_scf_t *h) 96 { 97 if (h != NULL) { 98 int unbind = 0; 99 if (h->t_scope != NULL) { 100 unbind = 1; 101 scf_scope_destroy(h->t_scope); 102 h->t_scope = NULL; 103 } 104 if (h->t_instance != NULL) { 105 scf_instance_destroy(h->t_instance); 106 h->t_instance = NULL; 107 } 108 if (h->t_service != NULL) { 109 scf_service_destroy(h->t_service); 110 h->t_service = NULL; 111 } 112 if (h->t_pg != NULL) { 113 scf_pg_destroy(h->t_pg); 114 h->t_pg = NULL; 115 } 116 if (h->t_handle != NULL) { 117 if (unbind) 118 (void) scf_handle_unbind(h->t_handle); 119 scf_handle_destroy(h->t_handle); 120 h->t_handle = NULL; 121 } 122 free(h); 123 h = NULL; 124 } 125 } 126 127 targ_scf_t * 128 mgmt_handle_init(void) 129 { 130 targ_scf_t *h; 131 132 h = calloc(1, sizeof (targ_scf_t)); 133 if (h == NULL) 134 return (NULL); 135 136 h->t_handle = scf_handle_create(SCF_VERSION); 137 if (h->t_handle != NULL) { 138 if (scf_handle_bind(h->t_handle) == 0) { 139 h->t_scope = scf_scope_create(h->t_handle); 140 h->t_service = scf_service_create(h->t_handle); 141 h->t_pg = scf_pg_create(h->t_handle); 142 h->t_instance = scf_instance_create(h->t_handle); 143 if (scf_handle_get_scope(h->t_handle, SCF_SCOPE_LOCAL, 144 h->t_scope) == 0) { 145 if (scf_scope_get_service(h->t_scope, 146 SA_TARGET_SVC_NAME, h->t_service) != 0) 147 goto error; 148 149 } else { 150 syslog(LOG_ERR, 151 "Got local scope which is wrong\n"); 152 goto error; 153 } 154 } else 155 goto error; 156 } else { 157 free(h); 158 h = NULL; 159 syslog(LOG_ERR, 160 "iscsitgt could not access SMF repository: %s\n", 161 scf_strerror(scf_error())); 162 } 163 164 return (h); 165 error: 166 mgmt_handle_fini(h); 167 free(h); 168 syslog(LOG_ERR, "iscsitgt SMF initialization problem: %s\n", 169 scf_strerror(scf_error())); 170 return (NULL); 171 } 172 173 /* 174 * This function starts a transaction with name of a property group 175 * and name of its property. If the property group does not exist 176 * this function will create an empty property group. 177 */ 178 Boolean_t 179 mgmt_transaction_start(targ_scf_t *h, char *pg, char *prop) 180 { 181 Boolean_t ret = True; 182 183 h->t_trans = scf_transaction_create(h->t_handle); 184 if (h->t_trans != NULL) { 185 if ((create_pg(h, pg, prop) == False) || 186 (scf_transaction_start(h->t_trans, h->t_pg) != 0)) { 187 scf_transaction_destroy(h->t_trans); 188 h->t_trans = NULL; 189 ret = False; 190 syslog(LOG_ERR, "transaction_start start: %s\n", 191 scf_strerror(scf_error())); 192 } 193 } else { 194 syslog(LOG_ERR, "transaction_start create: %s\n", 195 scf_strerror(scf_error())); 196 ret = False; 197 } 198 return (ret); 199 } 200 201 Boolean_t 202 mgmt_transaction_end(targ_scf_t *h) 203 { 204 Boolean_t ret = True; 205 206 if (scf_transaction_commit(h->t_trans) < 0) 207 ret = False; 208 (void) scf_pg_update(h->t_pg); 209 (void) scf_transaction_destroy_children(h->t_trans); 210 (void) scf_transaction_destroy(h->t_trans); 211 h->t_trans = NULL; 212 return (ret); 213 } 214 215 void 216 mgmt_transaction_abort(targ_scf_t *h) 217 { 218 if (h->t_trans != NULL) { 219 scf_transaction_reset_all(h->t_trans); 220 scf_transaction_destroy_children(h->t_trans); 221 scf_transaction_destroy(h->t_trans); 222 h->t_trans = NULL; 223 } 224 } 225 226 /* 227 * process property group name first 228 * a reasonable buf to receive encoded pgname is double size of pgname 229 */ 230 #define PG_FACTOR 2 231 static Boolean_t 232 create_pg(targ_scf_t *h, char *pgname, char *prop) 233 { 234 int len; 235 char *buf = NULL; 236 237 len = strlen(pgname); 238 buf = (char *)calloc(1, len * PG_FACTOR); 239 if (buf == NULL) 240 return (False); 241 242 pgname_encode(pgname, buf, len * PG_FACTOR); 243 244 if (scf_service_get_pg(h->t_service, buf, h->t_pg) != 0) { 245 if (scf_service_add_pg(h->t_service, buf, 246 prop, 0, h->t_pg) != 0) { 247 free(buf); 248 return (False); 249 } 250 } 251 free(buf); 252 return (True); 253 } 254 255 /* 256 * Manage allocating dynamic memory for a string that is stored in 257 * the SCF database. 258 * 259 * scf_limit(3SCF) is called in order to compute the maximum length of 260 * the type of string specified by the 'limit' argument. malloc() 261 * is then called to allocate the memory. 262 * 263 * If the function returns True, then the by-reference arguments will 264 * be updated to hold the length and address of the memory chunk. 265 */ 266 static Boolean_t 267 alloc_scf_element(uint32_t limit, ssize_t *max_len, void **buf) 268 { 269 ssize_t max_name_len; 270 void *name_buf; 271 Boolean_t status = False; 272 273 /* 274 * Dynamically compute the maximum length of the specified type 275 * of string so that our algorithms do not use an arbitrary, 276 * statically-defined value. 277 */ 278 if ((max_name_len = scf_limit(limit)) >= 0) { 279 /* 280 * scf_limit's return value knows nothing about a C-string's 281 * trailing NULL byte; increment the count to allow for it. 282 */ 283 max_name_len++; 284 285 if ((name_buf = malloc(max_name_len)) != NULL) { 286 *max_len = max_name_len; 287 *buf = name_buf; 288 status = True; 289 } 290 } 291 292 return (status); 293 } 294 295 /* 296 * Allocate dynamic memory for a string containing a NAME that is stored in 297 * the SCF database. 298 */ 299 static Boolean_t 300 alloc_scf_name(ssize_t *max_len, void **buf) 301 { 302 return (alloc_scf_element(SCF_LIMIT_MAX_NAME_LENGTH, max_len, buf)); 303 } 304 305 /* 306 * Allocate dynamic memory for a string containing a VALUE that is stored in 307 * the SCF database. 308 */ 309 static Boolean_t 310 alloc_scf_value(ssize_t *max_len, void **buf) 311 { 312 return (alloc_scf_element(SCF_LIMIT_MAX_VALUE_LENGTH, max_len, buf)); 313 } 314 315 /* 316 * mgmt_get_main_config() loads main configuration 317 * from scf into a node tree. 318 * Main configuration includes: admin/target/tpgt/initiator info. 319 * admin info is stored in "iscsitgt" property group 320 * target info is stored in "target_<name>" property group 321 * initiator info is stored in "initiator_<name>" property group 322 * tpgt info is stored in "tpgt_<number>" property group 323 */ 324 Boolean_t 325 mgmt_get_main_config(tgt_node_t **node) 326 { 327 targ_scf_t *h = NULL; 328 scf_property_t *prop = NULL; 329 scf_value_t *value = NULL; 330 scf_iter_t *iter = NULL; 331 scf_iter_t *iter_v = NULL; 332 scf_iter_t *iter_pv = NULL; 333 char *pname = NULL; 334 char *valuebuf = NULL; 335 ssize_t max_name_len; 336 ssize_t max_value_len; 337 char passcode[32]; 338 unsigned int outlen; 339 tgt_node_t *n; 340 tgt_node_t *pn; 341 tgt_node_t *vn; 342 Boolean_t status = False; 343 344 h = mgmt_handle_init(); 345 346 if (h == NULL) 347 return (status); 348 349 prop = scf_property_create(h->t_handle); 350 value = scf_value_create(h->t_handle); 351 iter = scf_iter_create(h->t_handle); 352 353 if ((alloc_scf_name(&max_name_len, (void *)&pname) == False) || 354 (alloc_scf_value(&max_value_len, (void *)&valuebuf) == False)) { 355 goto error; 356 } 357 358 (void) pthread_mutex_lock(&scf_conf_mutex); 359 360 /* Basic Information is stored in iscsitgt pg */ 361 if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == -1) { 362 goto error; 363 } 364 365 *node = NULL; 366 *node = tgt_node_alloc("main_config", String, NULL); 367 if (*node == NULL) 368 goto error; 369 370 if (scf_iter_pg_properties(iter, h->t_pg) == -1) { 371 goto error; 372 } 373 374 while (scf_iter_next_property(iter, prop) > 0) { 375 (void) scf_property_get_value(prop, value); 376 (void) scf_value_get_as_string(value, valuebuf, max_value_len); 377 (void) scf_property_get_name(prop, pname, max_name_len); 378 379 /* avoid load auth to incore data */ 380 if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || 381 strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || 382 strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) 383 continue; 384 385 n = tgt_node_alloc(pname, String, valuebuf); 386 if (n == NULL) 387 goto error; 388 389 /* put version info into root node's attr */ 390 if (strcmp(pname, XML_ELEMENT_VERS) == 0) { 391 tgt_node_add_attr(*node, n); 392 } else { 393 /* add other basic info into root node */ 394 tgt_node_add(*node, n); 395 } 396 } 397 398 /* 399 * targets/initiators/tpgt information is 400 * stored as type "configuration" in scf 401 * each target's param is stored as type "parameter" 402 */ 403 if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") 404 == -1) { 405 goto error; 406 } 407 408 while (scf_iter_next_pg(iter, h->t_pg) > 0) { 409 char *iname; 410 411 (void) scf_pg_get_name(h->t_pg, pname, max_name_len); 412 pgname_decode(pname); 413 iname = strchr(pname, '_'); 414 if (iname == NULL) { 415 /* the pg found here is not a tgt/initiator/tpgt */ 416 continue; 417 } 418 *iname = '\0'; 419 iname++; 420 /* 421 * now pname is "target" or "initiator" or "tpgt" 422 * meanwhile iname is the actual name of the item 423 */ 424 425 n = tgt_node_alloc(pname, String, iname); 426 if (n == NULL) 427 goto error; 428 429 iter_v = scf_iter_create(h->t_handle); 430 if (scf_iter_pg_properties(iter_v, h->t_pg) == -1) { 431 goto error; 432 } 433 while (scf_iter_next_property(iter_v, prop) > 0) { 434 /* there may be many values in one property */ 435 char *vname; 436 437 (void) scf_property_get_name(prop, pname, 438 max_name_len); 439 /* avoid load auth to incore data */ 440 if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || 441 strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || 442 strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) 443 continue; 444 445 vname = strstr(pname, "-list"); 446 if (vname == NULL) { 447 (void) scf_property_get_value(prop, value); 448 (void) scf_value_get_as_string(value, valuebuf, 449 max_value_len); 450 451 pn = tgt_node_alloc(pname, String, valuebuf); 452 if (pn == NULL) 453 goto error; 454 tgt_node_add(n, pn); 455 } else { 456 pn = tgt_node_alloc(pname, String, NULL); 457 if (pn == NULL) 458 goto error; 459 tgt_node_add(n, pn); 460 *vname = '\0'; 461 462 iter_pv = scf_iter_create(h->t_handle); 463 (void) scf_iter_property_values(iter_pv, prop); 464 while (scf_iter_next_value(iter_pv, value) 465 > 0) { 466 (void) scf_value_get_as_string( 467 value, valuebuf, max_value_len); 468 /* 469 * map 'acl' to 'initiator' since that 470 * is what used inside the acl-list. 471 */ 472 if (strcmp(pname, XML_ELEMENT_ACL) 473 == 0) { 474 vn = tgt_node_alloc( 475 XML_ELEMENT_INIT, 476 String, valuebuf); 477 } else { 478 vn = tgt_node_alloc( 479 pname, String, valuebuf); 480 } 481 if (vn == NULL) 482 goto error; 483 tgt_node_add(pn, vn); 484 } 485 scf_iter_destroy(iter_pv); 486 iter_pv = NULL; 487 } 488 } 489 tgt_node_add(*node, n); 490 scf_iter_destroy(iter_v); 491 iter_v = NULL; 492 } 493 494 /* chap-secrets are stored in "passwords" pgroup as "application" */ 495 if (scf_service_get_pg(h->t_service, "passwords", h->t_pg) == 0) { 496 if (scf_iter_pg_properties(iter, h->t_pg) == -1) { 497 goto error; 498 } 499 500 while (scf_iter_next_property(iter, prop) > 0) { 501 (void) scf_property_get_value(prop, value); 502 (void) scf_value_get_as_string(value, valuebuf, 503 max_value_len); 504 (void) scf_property_get_name(prop, pname, 505 max_name_len); 506 507 /* avoid load auth to incore data */ 508 if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || 509 strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || 510 strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) 511 continue; 512 513 /* max length of decoded passwd is 16B */ 514 (void) sasl_decode64(valuebuf, strlen(valuebuf), 515 passcode, sizeof (passcode), &outlen); 516 517 if (strcmp(pname, "radius") == 0) { 518 pn = tgt_node_alloc(XML_ELEMENT_RAD_SECRET, 519 String, passcode); 520 tgt_node_add(*node, pn); 521 } else if (strcmp(pname, "main") == 0) { 522 pn = tgt_node_alloc(XML_ELEMENT_CHAPSECRET, 523 String, passcode); 524 tgt_node_add(*node, pn); 525 } else { 526 /* find corresponding initiator */ 527 n = NULL; 528 while (n = tgt_node_next_child(*node, 529 XML_ELEMENT_INIT, n)) { 530 if (strcmp(pname + 2, n->x_value) != 0) 531 continue; 532 pn = tgt_node_alloc( 533 XML_ELEMENT_CHAPSECRET, 534 String, passcode); 535 tgt_node_add(n, pn); 536 } 537 } 538 } 539 } 540 541 status = True; 542 error: 543 if ((status != True) && (*node != NULL)) 544 tgt_node_free(*node); 545 (void) pthread_mutex_unlock(&scf_conf_mutex); 546 if (iter_pv != NULL) 547 scf_iter_destroy(iter_pv); 548 if (iter_v != NULL) 549 scf_iter_destroy(iter_v); 550 551 free(valuebuf); 552 free(pname); 553 554 scf_iter_destroy(iter); 555 scf_value_destroy(value); 556 scf_property_destroy(prop); 557 mgmt_handle_fini(h); 558 return (status); 559 } 560 561 static int 562 isnumber(char *s) 563 { 564 register int c; 565 566 if (!s || !(*s)) 567 return (0); 568 while ((c = *(s++)) != '\0') { 569 if (!isdigit(c)) 570 return (0); 571 } 572 return (1); 573 } 574 575 static void 576 new_property(targ_scf_t *h, 577 tgt_node_t *n) 578 { 579 scf_transaction_entry_t *e = NULL; 580 scf_value_t *v = NULL; 581 scf_type_t type; 582 583 assert(n != NULL); 584 585 e = scf_entry_create(h->t_handle); 586 v = scf_value_create(h->t_handle); 587 588 if (strcmp(n->x_value, "true") == 0 || 589 strcmp(n->x_value, "false") == 0) { 590 type = SCF_TYPE_BOOLEAN; 591 } else if (strcmp(n->x_name, "main") == 0 || 592 strcmp(n->x_name, "radius") == 0) { 593 type = SCF_TYPE_ASTRING; 594 } else if (strncmp(n->x_name, "I_", 2) == 0) { 595 type = SCF_TYPE_ASTRING; 596 } else if (strcmp(n->x_name, XML_ELEMENT_VERS) == 0) { 597 type = SCF_TYPE_ASTRING; 598 } else if (isnumber(n->x_value)) { 599 type = SCF_TYPE_COUNT; 600 } else { 601 type = SCF_TYPE_ASTRING; 602 } 603 if ((scf_transaction_property_new(h->t_trans, e, n->x_name, type) 604 == 0)) { 605 (void) scf_value_set_from_string(v, type, n->x_value); 606 (void) scf_entry_add_value(e, v); 607 } else { 608 scf_entry_destroy(e); 609 scf_value_destroy(v); 610 } 611 } 612 613 static void 614 new_value_list(targ_scf_t *h, 615 tgt_node_t *p) 616 { 617 scf_transaction_entry_t *e = NULL; 618 scf_value_t *v = NULL; 619 tgt_node_t *c; 620 char *name; 621 622 assert(p != NULL); 623 624 name = p->x_name; 625 e = scf_entry_create(h->t_handle); 626 (void) scf_transaction_property_new(h->t_trans, e, name, 627 SCF_TYPE_ASTRING); 628 629 for (c = p->x_child; c; c = c->x_sibling) { 630 v = scf_value_create(h->t_handle); 631 (void) scf_value_set_astring(v, c->x_value); 632 (void) scf_entry_add_value(e, v); 633 } 634 } 635 636 /* 637 * mgmt_config_save2scf() saves main configuration to scf 638 * See also : mgmt_get_main_config() 639 */ 640 Boolean_t 641 mgmt_config_save2scf() 642 { 643 targ_scf_t *h = NULL; 644 scf_property_t *prop = NULL; 645 scf_value_t *value = NULL; 646 scf_iter_t *iter = NULL; 647 char *pgname = NULL; 648 ssize_t max_name_len; 649 char passcode[32]; 650 char *incore = NULL; 651 unsigned int outlen; 652 tgt_node_t *n = NULL; 653 tgt_node_t *pn = NULL; 654 tgt_node_t *tn = NULL; 655 scf_transaction_t *tx = NULL; 656 secret_list_t *sl_head; 657 secret_list_t *sl_tail; 658 Boolean_t status = False; 659 660 h = mgmt_handle_init(); 661 662 if (h == NULL) 663 return (status); 664 665 prop = scf_property_create(h->t_handle); 666 value = scf_value_create(h->t_handle); 667 iter = scf_iter_create(h->t_handle); 668 669 if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) { 670 goto error; 671 } 672 673 (void) pthread_mutex_lock(&scf_conf_mutex); 674 675 if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { 676 (void) scf_pg_delete(h->t_pg); 677 (void) mgmt_transaction_end(h); 678 } 679 680 if (mgmt_transaction_start(h, "passwords", "application") == True) { 681 (void) scf_pg_delete(h->t_pg); 682 (void) mgmt_transaction_end(h); 683 } 684 685 if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") 686 == -1) { 687 goto error; 688 } 689 690 tx = scf_transaction_create(h->t_handle); 691 while (scf_iter_next_pg(iter, h->t_pg) > 0) { 692 (void) scf_transaction_start(tx, h->t_pg); 693 (void) scf_pg_delete(h->t_pg); 694 (void) scf_transaction_commit(tx); 695 } 696 scf_transaction_reset(tx); 697 scf_transaction_destroy(tx); 698 699 sl_head = (secret_list_t *)calloc(1, sizeof (secret_list_t)); 700 sl_tail = sl_head; 701 702 if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { 703 for (n = main_config->x_child; n; n = n->x_sibling) { 704 if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore)) 705 == True) { 706 if (strcmp(incore, "true") == 0) { 707 /* 708 * Ignore in core only elements. 709 * zvol target is the only one with 710 * incore attr as of now. 711 */ 712 free(incore); 713 continue; 714 } 715 /* if incore is false continue on */ 716 free(incore); 717 } 718 if (strcmp(n->x_name, 719 XML_ELEMENT_CHAPSECRET) == 0) { 720 sl_tail->next = (secret_list_t *) 721 calloc(1, sizeof (secret_list_t)); 722 sl_tail = sl_tail->next; 723 sl_tail->name = strdup("main"); 724 sl_tail->secret = strdup(n->x_value); 725 continue; 726 } 727 /* so does the radius server secret */ 728 if (strcmp(n->x_name, 729 XML_ELEMENT_RAD_SECRET) == 0) { 730 sl_tail->next = (secret_list_t *) 731 calloc(1, sizeof (secret_list_t)); 732 sl_tail = sl_tail->next; 733 sl_tail->name = strdup("radius"); 734 sl_tail->secret = strdup(n->x_value); 735 continue; 736 } 737 if (n->x_child == NULL) { 738 new_property(h, n); 739 } 740 } 741 new_property(h, main_config->x_attr); 742 n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, 743 ISCSI_AUTH_MODIFY); 744 new_property(h, n); 745 tgt_node_free(n); 746 n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, 747 ISCSI_AUTH_VALUE); 748 new_property(h, n); 749 tgt_node_free(n); 750 (void) mgmt_transaction_end(h); 751 } 752 753 /* now update target/initiator/tpgt information */ 754 for (n = main_config->x_child; n; n = n->x_sibling) { 755 if (n->x_child == NULL) 756 continue; 757 758 if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore)) 759 == True) { 760 if (strcmp(incore, "true") == 0) { 761 /* 762 * Ignore in core only elements. 763 * zvol target is the only one with 764 * incore attr as of now. 765 */ 766 free(incore); 767 continue; 768 } 769 /* if incore is false continue on */ 770 free(incore); 771 } 772 773 (void) snprintf(pgname, max_name_len, "%s_%s", n->x_name, 774 n->x_value); 775 776 if (mgmt_transaction_start(h, pgname, "configuration") 777 == True) { 778 for (pn = n->x_child; pn; pn = pn->x_sibling) { 779 if (strcmp(pn->x_name, 780 XML_ELEMENT_CHAPSECRET) == 0) { 781 sl_tail->next = (secret_list_t *) 782 calloc(1, sizeof (secret_list_t)); 783 sl_tail = sl_tail->next; 784 sl_tail->name = (char *) 785 calloc(1, strlen(n->x_value) + 3); 786 (void) snprintf(sl_tail->name, 787 strlen(n->x_value) + 3, 788 "I_%s", n->x_value); 789 sl_tail->secret = strdup(pn->x_value); 790 continue; 791 } 792 if (pn->x_child == NULL) { 793 /* normal property */ 794 new_property(h, pn); 795 } else { 796 /* pn -> xxx-list */ 797 new_value_list(h, pn); 798 } 799 tn = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, 800 String, ISCSI_AUTH_MODIFY); 801 new_property(h, tn); 802 tgt_node_free(tn); 803 tn = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, 804 String, ISCSI_AUTH_VALUE); 805 new_property(h, tn); 806 tgt_node_free(tn); 807 } 808 (void) mgmt_transaction_end(h); 809 } else 810 goto error; 811 } 812 813 if (mgmt_transaction_start(h, "passwords", "application") == True) { 814 while (sl_head != NULL) { 815 /* Here we use sl_tail as a temporari var */ 816 sl_tail = sl_head->next; 817 if (sl_head->name) { 818 /* max length of encoded passwd is 24B */ 819 (void) sasl_encode64(sl_head->secret, 820 strlen(sl_head->secret), passcode, 821 sizeof (passcode), &outlen); 822 823 n = tgt_node_alloc(sl_head->name, String, 824 passcode); 825 new_property(h, n); 826 tgt_node_free(n); 827 } 828 if (sl_head->name) 829 free(sl_head->name); 830 if (sl_head->secret) 831 free(sl_head->secret); 832 free(sl_head); 833 sl_head = sl_tail; 834 } 835 n = tgt_node_alloc(ISCSI_READ_AUTHNAME, String, 836 ISCSI_AUTH_READ); 837 new_property(h, n); 838 tgt_node_free(n); 839 n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, 840 ISCSI_AUTH_VALUE); 841 new_property(h, n); 842 tgt_node_free(n); 843 n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, 844 ISCSI_AUTH_MODIFY); 845 new_property(h, n); 846 tgt_node_free(n); 847 (void) mgmt_transaction_end(h); 848 } 849 850 if (smf_refresh_instance(SA_TARGET_SVC_INSTANCE_FMRI) != 0) 851 goto error; 852 853 status = True; 854 error: 855 (void) pthread_mutex_unlock(&scf_conf_mutex); 856 free(pgname); 857 scf_iter_destroy(iter); 858 scf_value_destroy(value); 859 scf_property_destroy(prop); 860 mgmt_handle_fini(h); 861 return (status); 862 } 863 864 Boolean_t 865 mgmt_param_save2scf(tgt_node_t *node, char *target_name, int lun) 866 { 867 targ_scf_t *h = NULL; 868 char *pgname = NULL; 869 ssize_t max_name_len; 870 tgt_node_t *n = NULL; 871 Boolean_t status = False; 872 873 h = mgmt_handle_init(); 874 875 if (h == NULL) 876 return (status); 877 878 if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) { 879 goto error; 880 } 881 882 (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, 883 lun); 884 885 (void) pthread_mutex_lock(&scf_param_mutex); 886 887 if (mgmt_transaction_start(h, pgname, "parameter") == True) { 888 (void) scf_pg_delete(h->t_pg); 889 (void) mgmt_transaction_end(h); 890 } 891 892 if (mgmt_transaction_start(h, pgname, "parameter") == True) { 893 for (n = node->x_child; n; n = n->x_sibling) { 894 if (n->x_child == NULL) { 895 /* now n is node of basic property */ 896 new_property(h, n); 897 } 898 } 899 new_property(h, node->x_attr); 900 n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, 901 ISCSI_AUTH_VALUE); 902 new_property(h, n); 903 tgt_node_free(n); 904 n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, 905 ISCSI_AUTH_MODIFY); 906 new_property(h, n); 907 tgt_node_free(n); 908 (void) mgmt_transaction_end(h); 909 } 910 911 status = True; 912 error: 913 (void) pthread_mutex_unlock(&scf_param_mutex); 914 free(pgname); 915 mgmt_handle_fini(h); 916 return (status); 917 } 918 919 /* 920 * mgmt_get_param() get parameter of a specific LUN from scf 921 * Args: 922 * node - the node which parameters will be stored in mem 923 * target_name - the local target name 924 * lun - the LUN number 925 * See also : mgmt_param_save2scf() 926 */ 927 Boolean_t 928 mgmt_get_param(tgt_node_t **node, char *target_name, int lun) 929 { 930 targ_scf_t *h = NULL; 931 scf_property_t *prop = NULL; 932 scf_value_t *value = NULL; 933 scf_iter_t *iter = NULL; 934 char *pname = NULL; 935 char *expgname = NULL; 936 char *pgname = NULL; 937 char *valuebuf = NULL; 938 ssize_t max_name_len; 939 ssize_t expg_max_name_len; 940 ssize_t max_value_len; 941 tgt_node_t *n; 942 Boolean_t status = False; 943 944 /* Set NULL as default output value */ 945 *node = NULL; 946 h = mgmt_handle_init(); 947 948 if (h == NULL) 949 return (status); 950 951 prop = scf_property_create(h->t_handle); 952 value = scf_value_create(h->t_handle); 953 iter = scf_iter_create(h->t_handle); 954 955 if ((alloc_scf_name(&max_name_len, (void *)&pname) == NULL) || 956 (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) || 957 (alloc_scf_value(&max_value_len, (void *)&valuebuf) == NULL)) { 958 goto error; 959 } 960 961 /* 962 * Allocate memory for an "expanded" (or "decoded") Property Group 963 * name. 964 */ 965 expg_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) * PG_FACTOR 966 + 1; 967 if ((expgname = malloc(expg_max_name_len)) == NULL) { 968 goto error; 969 } 970 971 (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, 972 lun); 973 pgname_encode(pgname, expgname, max_name_len); 974 975 (void) pthread_mutex_lock(&scf_param_mutex); 976 977 if (scf_service_get_pg(h->t_service, expgname, h->t_pg) == -1) { 978 goto error; 979 } 980 981 *node = tgt_node_alloc(XML_ELEMENT_PARAMS, String, NULL); 982 if (*node == NULL) 983 goto error; 984 985 if (scf_iter_pg_properties(iter, h->t_pg) == -1) { 986 goto error; 987 } 988 989 while (scf_iter_next_property(iter, prop) > 0) { 990 (void) scf_property_get_value(prop, value); 991 (void) scf_value_get_as_string(value, valuebuf, max_value_len); 992 (void) scf_property_get_name(prop, pname, max_name_len); 993 994 /* avoid load auth to incore data */ 995 if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || 996 strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || 997 strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) 998 continue; 999 1000 n = tgt_node_alloc(pname, String, valuebuf); 1001 if (n == NULL) 1002 goto error; 1003 1004 /* put version info into root node's attr */ 1005 if (strcmp(pname, XML_ELEMENT_VERS) == 0) { 1006 tgt_node_add_attr(*node, n); 1007 } else { 1008 /* add other basic info into root node */ 1009 tgt_node_add(*node, n); 1010 } 1011 } 1012 1013 status = True; 1014 error: 1015 (void) pthread_mutex_unlock(&scf_param_mutex); 1016 1017 free(valuebuf); 1018 free(expgname); 1019 free(pgname); 1020 free(pname); 1021 1022 scf_iter_destroy(iter); 1023 scf_value_destroy(value); 1024 scf_property_destroy(prop); 1025 mgmt_handle_fini(h); 1026 return (status); 1027 } 1028 1029 Boolean_t 1030 mgmt_param_remove(char *target_name, int lun) 1031 { 1032 targ_scf_t *h = NULL; 1033 char *pgname = NULL; 1034 ssize_t max_name_len; 1035 Boolean_t status = False; 1036 1037 h = mgmt_handle_init(); 1038 if (h == NULL) 1039 return (status); 1040 1041 if (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) { 1042 goto error; 1043 } 1044 1045 (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, 1046 lun); 1047 1048 if (mgmt_transaction_start(h, pgname, "parameter") == True) { 1049 (void) scf_pg_delete(h->t_pg); 1050 (void) mgmt_transaction_end(h); 1051 status = True; 1052 } 1053 error: 1054 free(pgname); 1055 mgmt_handle_fini(h); 1056 return (status); 1057 } 1058 1059 /* 1060 * mgmt_convert_param() converts legacy params file of each LUN 1061 * to scf data. It will convert LUNs under one target each time. 1062 * Args: 1063 * dir - string of directory where param file is stored 1064 * tnode - node tree which contains to a target 1065 */ 1066 Boolean_t 1067 mgmt_convert_param(char *dir, tgt_node_t *tnode) 1068 { 1069 Boolean_t ret = False; 1070 char path[MAXPATHLEN]; 1071 int xml_fd = -1; 1072 int n; 1073 int lun_num; 1074 tgt_node_t *lun = NULL; 1075 tgt_node_t *params = NULL; 1076 xmlTextReaderPtr r; 1077 1078 while ((lun = tgt_node_next(tnode, XML_ELEMENT_LUN, lun)) != NULL) { 1079 if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) == 1080 False) 1081 continue; 1082 (void) snprintf(path, sizeof (path), "%s/%s%d", 1083 dir, PARAMBASE, lun_num); 1084 if ((xml_fd = open(path, O_RDONLY)) < 0) 1085 continue; 1086 if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, 1087 NULL, NULL, 0)) == NULL) 1088 continue; 1089 1090 n = xmlTextReaderRead(r); 1091 while (n == 1) { 1092 if (tgt_node_process(r, ¶ms) == False) { 1093 break; 1094 } 1095 n = xmlTextReaderRead(r); 1096 } 1097 if (n < 0) { 1098 ret = False; 1099 break; 1100 } 1101 1102 if (mgmt_param_save2scf(params, tnode->x_value, lun_num) 1103 != True) { 1104 ret = False; 1105 break; 1106 } else { 1107 backup(path, tnode->x_value); 1108 ret = True; 1109 } 1110 params = NULL; 1111 (void) close(xml_fd); 1112 (void) xmlTextReaderClose(r); 1113 xmlFreeTextReader(r); 1114 } 1115 1116 if (ret == False) 1117 syslog(LOG_ERR, "Converting target %s params failed", dir); 1118 return (ret); 1119 } 1120 1121 /* 1122 * Convert legacy (XML) configuration files into an equivalent SCF 1123 * representation. 1124 * 1125 * Read the XML from disk, translate the XML into a tree of nodes of 1126 * type tgt_node_t, and write the in-memory tree to SCF's persistent 1127 * data-store using mgmt_config_save2scf(). 1128 * 1129 * Return Values: 1130 * CONVERT_OK: successfully converted 1131 * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry 1132 * CONVERT_FAIL: some conversion error occurred; no SCF entry created. 1133 * In this case, user has to manually check files and try 1134 * conversion again. 1135 */ 1136 convert_ret_t 1137 mgmt_convert_conf() 1138 { 1139 targ_scf_t *h = NULL; 1140 xmlTextReaderPtr r; 1141 convert_ret_t ret = CONVERT_FAIL; 1142 int xml_fd = -1; 1143 int n; 1144 tgt_node_t *node = NULL; 1145 tgt_node_t *next = NULL; 1146 char path[MAXPATHLEN]; 1147 char *target = NULL; 1148 1149 h = mgmt_handle_init(); 1150 if (h == NULL) 1151 return (CONVERT_FAIL); 1152 1153 /* 1154 * Check if the "iscsitgt" PropertyGroup has already been added 1155 * to the "iscsitgt" SMF Service. If so, then we have already 1156 * converted the legacy configuration files (and there is no work 1157 * to do). 1158 */ 1159 if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) { 1160 ret = CONVERT_OK; 1161 goto done; 1162 } 1163 1164 if (access(config_file, R_OK) != 0) { 1165 /* 1166 * then the Main Config file is not present; initialize 1167 * SCF Properties to default values. 1168 */ 1169 if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { 1170 ret = CONVERT_INIT_NEW; 1171 1172 node = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); 1173 new_property(h, node); 1174 tgt_node_free(node); 1175 /* "daemonize" is set to true by default */ 1176 node = tgt_node_alloc(XML_ELEMENT_DBGDAEMON, String, 1177 "true"); 1178 new_property(h, node); 1179 tgt_node_free(node); 1180 node = NULL; 1181 node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, 1182 ISCSI_AUTH_MODIFY); 1183 new_property(h, node); 1184 tgt_node_free(node); 1185 node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, 1186 ISCSI_AUTH_VALUE); 1187 new_property(h, node); 1188 tgt_node_free(node); 1189 (void) mgmt_transaction_end(h); 1190 } else { 1191 syslog(LOG_ERR, "Creating empty entry failed"); 1192 ret = CONVERT_FAIL; 1193 goto done; 1194 } 1195 if (mgmt_transaction_start(h, "passwords", "application") == 1196 True) { 1197 node = tgt_node_alloc(ISCSI_READ_AUTHNAME, String, 1198 ISCSI_AUTH_READ); 1199 new_property(h, node); 1200 tgt_node_free(node); 1201 node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, 1202 ISCSI_AUTH_MODIFY); 1203 new_property(h, node); 1204 tgt_node_free(node); 1205 node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, 1206 ISCSI_AUTH_VALUE); 1207 new_property(h, node); 1208 tgt_node_free(node); 1209 (void) mgmt_transaction_end(h); 1210 } else { 1211 syslog(LOG_ERR, "Creating empty entry failed"); 1212 ret = CONVERT_FAIL; 1213 } 1214 goto done; 1215 } 1216 1217 if ((xml_fd = open(config_file, O_RDONLY)) >= 0) 1218 r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0); 1219 1220 if (r != NULL) { 1221 int is_target_config; 1222 1223 n = xmlTextReaderRead(r); 1224 while (n == 1) { 1225 if (tgt_node_process(r, &node) == False) { 1226 break; 1227 } 1228 n = xmlTextReaderRead(r); 1229 } 1230 if (n < 0) { 1231 syslog(LOG_ERR, "Parsing main config failed"); 1232 ret = CONVERT_FAIL; 1233 goto done; 1234 } 1235 1236 main_config = node; 1237 1238 /* 1239 * Initialize the Base Directory (global) variable by 1240 * using the value specified in the XML_ELEMENT_BASEDIR 1241 * XML tag. If a tag is not specified, use a default. 1242 */ 1243 (void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR, 1244 &target_basedir); 1245 1246 if (target_basedir == NULL) 1247 target_basedir = strdup(DEFAULT_TARGET_BASEDIR); 1248 1249 if (xml_fd != -1) { 1250 (void) close(xml_fd); 1251 xml_fd = -1; 1252 } 1253 (void) xmlTextReaderClose(r); 1254 xmlFreeTextReader(r); 1255 xmlCleanupParser(); 1256 1257 /* 1258 * If a Target Config file is present, read and translate 1259 * its XML representation into a tree of tgt_node_t. 1260 * Merge that tree with the tree of tgt_node_t rooted at 1261 * 'main_config'. The merged tree will then be archived 1262 * using an SCF representation. 1263 */ 1264 (void) snprintf(path, MAXPATHLEN, "%s/%s", 1265 target_basedir, "config.xml"); 1266 1267 if ((xml_fd = open(path, O_RDONLY)) >= 0) { 1268 is_target_config = 1; 1269 r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, 1270 NULL, NULL, 0); 1271 } else { 1272 is_target_config = 0; 1273 r = NULL; 1274 } 1275 1276 if (r != NULL) { 1277 /* then the Target Config file is available. */ 1278 1279 node = NULL; 1280 1281 /* 1282 * Create a tree of tgt_node_t rooted at 'node' by 1283 * processing each XML Tag in the file. 1284 */ 1285 n = xmlTextReaderRead(r); 1286 while (n == 1) { 1287 if (tgt_node_process(r, &node) == False) { 1288 break; 1289 } 1290 n = xmlTextReaderRead(r); 1291 } 1292 if (n < 0) { 1293 syslog(LOG_ERR, "Parsing target conf failed"); 1294 ret = CONVERT_FAIL; 1295 goto done; 1296 } 1297 1298 /* 1299 * Merge the tree at 'node' into the tree rooted at 1300 * 'main_config'. 1301 */ 1302 if (node != NULL) { 1303 next = NULL; 1304 while ((next = tgt_node_next(node, 1305 XML_ELEMENT_TARG, next)) != NULL) { 1306 tgt_node_add(main_config, 1307 tgt_node_dup(next)); 1308 } 1309 tgt_node_free(node); 1310 } 1311 } 1312 1313 /* 1314 * Iterate over the in-memory tree rooted at 'main_config' 1315 * and write a representation of the appropriate nodes to 1316 * SCF's persistent data-store. 1317 */ 1318 if (mgmt_config_save2scf() != True) { 1319 syslog(LOG_ERR, "Converting config failed"); 1320 if (xml_fd != -1) { 1321 (void) close(xml_fd); 1322 xml_fd = -1; 1323 } 1324 (void) xmlTextReaderClose(r); 1325 xmlFreeTextReader(r); 1326 xmlCleanupParser(); 1327 ret = CONVERT_FAIL; 1328 goto done; 1329 } 1330 1331 /* 1332 * Move the configuration files into a well-known backup 1333 * directory. This allows a user to restore their 1334 * configuration, if they choose. 1335 */ 1336 (void) snprintf(path, sizeof (path), "%s/backup", 1337 target_basedir); 1338 if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) { 1339 syslog(LOG_ERR, "Creating backup dir failed"); 1340 ret = CONVERT_FAIL; 1341 goto done; 1342 } 1343 /* Save the Main Config file. */ 1344 backup(config_file, NULL); 1345 1346 /* Save the Target Config file, if it was present. */ 1347 if (is_target_config != 0) { 1348 (void) snprintf(path, MAXPATHLEN, "%s/%s", 1349 target_basedir, "config.xml"); 1350 backup(path, NULL); 1351 } 1352 1353 /* 1354 * For each tgt_node_t node in 'main_config' whose value is 1355 * an iSCSI Name as defined in the RFC (3720) standard (eg, 1356 * "iqn.1986..."), read its XML-encoded attributes from a 1357 * flat-file and write an equivalent representation to SCF's 1358 * data-store. 1359 */ 1360 while ((next = tgt_node_next(main_config, 1361 XML_ELEMENT_TARG, next)) != NULL) { 1362 if (tgt_find_value_str(next, XML_ELEMENT_INAME, 1363 &target) == False) { 1364 continue; 1365 } 1366 (void) snprintf(path, MAXPATHLEN, "%s/%s", 1367 target_basedir, target); 1368 if (mgmt_convert_param(path, next) 1369 != True) { 1370 ret = CONVERT_FAIL; 1371 goto done; 1372 } 1373 free(target); 1374 } 1375 1376 ret = CONVERT_OK; 1377 syslog(LOG_NOTICE, "Conversion succeeded"); 1378 1379 (void) xmlTextReaderClose(r); 1380 xmlFreeTextReader(r); 1381 xmlCleanupParser(); 1382 } else { 1383 syslog(LOG_ERR, "Reading main config failed"); 1384 ret = CONVERT_FAIL; 1385 goto done; 1386 } 1387 1388 done: 1389 if (xml_fd != -1) 1390 (void) close(xml_fd); 1391 mgmt_handle_fini(h); 1392 return (ret); 1393 } 1394 1395 /* 1396 * backup() moves configuration xml files into backup directory 1397 * under base-directory. It is called once when converting legacy 1398 * xml data into scf data. 1399 * Param files will be renamed as params.<lun#>.<initiatorname> 1400 */ 1401 static void 1402 backup(char *file, char *ext) 1403 { 1404 char dest[MAXPATHLEN]; 1405 char *bname; 1406 1407 bname = basename(file); 1408 if (ext) { 1409 (void) snprintf(dest, sizeof (dest), "%s/backup/%s.%s", 1410 target_basedir, bname, ext); 1411 } else { 1412 (void) snprintf(dest, sizeof (dest), "%s/backup/%s", 1413 target_basedir, bname); 1414 } 1415 1416 if (fork() == 0) { 1417 (void) execl("/bin/mv", "mv", file, dest, (char *)0); 1418 exit(0); 1419 } 1420 } 1421 1422 /* 1423 * check_auth() checks if a given cred has 1424 * the authorization to create/remove targets/initiators/tpgt 1425 * cred is from the door call. 1426 */ 1427 Boolean_t 1428 check_auth_addremove(ucred_t *cred) 1429 { 1430 targ_scf_t *h = NULL; 1431 Boolean_t ret = False; 1432 int exit_code = 1; 1433 uid_t uid; 1434 gid_t gid; 1435 pid_t pid; 1436 const priv_set_t *eset; 1437 1438 pid = fork(); 1439 1440 switch (pid) { 1441 case 0: 1442 /* Child process to check authorization */ 1443 uid = ucred_geteuid(cred); 1444 if (seteuid(uid) != 0) { 1445 syslog(LOG_ERR, "not priviliged\n"); 1446 exit(-1); 1447 } 1448 1449 gid = ucred_getegid(cred); 1450 if (setegid(gid) != 0) { 1451 syslog(LOG_ERR, "not priviliged\n"); 1452 exit(-1); 1453 } 1454 1455 eset = ucred_getprivset(cred, PRIV_EFFECTIVE); 1456 (void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset); 1457 1458 h = mgmt_handle_init(); 1459 1460 if (h == NULL) { 1461 exit(1); 1462 } 1463 if (mgmt_transaction_start(h, "dummy", "dummy") == True) { 1464 (void) scf_pg_delete(h->t_pg); 1465 (void) mgmt_transaction_end(h); 1466 exit_code = 0; 1467 } else { 1468 exit_code = 1; 1469 } 1470 mgmt_handle_fini(h); 1471 exit(exit_code); 1472 break; 1473 case -1: 1474 /* Fail to fork */ 1475 exit(SMF_EXIT_ERR_CONFIG); 1476 default: 1477 (void) wait(&exit_code); 1478 exit_code = exit_code >> 8; 1479 if (exit_code == 0) 1480 ret = True; 1481 else 1482 ret = False; 1483 break; 1484 } 1485 1486 return (ret); 1487 } 1488 /* 1489 * check_auth_modify() checks if a given cred has 1490 * the authorization to add/change/remove configuration values. 1491 * cred is from the door call. 1492 */ 1493 Boolean_t 1494 check_auth_modify(ucred_t *cred) 1495 { 1496 targ_scf_t *h = NULL; 1497 Boolean_t ret = False; 1498 int exit_code = -1; 1499 uid_t uid; 1500 gid_t gid; 1501 pid_t pid; 1502 tgt_node_t *n = NULL; 1503 scf_transaction_entry_t *ent = NULL; 1504 const priv_set_t *eset; 1505 1506 pid = fork(); 1507 1508 switch (pid) { 1509 case 0: 1510 /* Child process to check authorization */ 1511 uid = ucred_geteuid(cred); 1512 if (seteuid(uid) != 0) { 1513 syslog(LOG_ERR, "not priviliged\n"); 1514 exit(-1); 1515 } 1516 1517 gid = ucred_getegid(cred); 1518 if (setegid(gid) != 0) { 1519 syslog(LOG_ERR, "not priviliged\n"); 1520 exit(-1); 1521 } 1522 1523 eset = ucred_getprivset(cred, PRIV_EFFECTIVE); 1524 (void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset); 1525 1526 h = mgmt_handle_init(); 1527 1528 if (h == NULL) { 1529 exit(-1); 1530 } 1531 if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { 1532 n = tgt_node_alloc("dummy", String, "dummy"); 1533 new_property(h, n); 1534 tgt_node_free(n); 1535 if (mgmt_transaction_end(h) == True) { 1536 exit_code = 0; 1537 } else { 1538 exit_code = -1; 1539 } 1540 } else { 1541 exit_code = -1; 1542 } 1543 if (exit_code != 0) { 1544 mgmt_handle_fini(h); 1545 exit(exit_code); 1546 } 1547 if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { 1548 ent = scf_entry_create(h->t_handle); 1549 if (ent) { 1550 (void) scf_transaction_property_delete( 1551 h->t_trans, ent, "dummy"); 1552 } 1553 } 1554 (void) mgmt_transaction_end(h); 1555 1556 mgmt_handle_fini(h); 1557 exit(exit_code); 1558 break; 1559 case -1: 1560 /* Fail to fork */ 1561 exit(SMF_EXIT_ERR_CONFIG); 1562 default: 1563 (void) wait(&exit_code); 1564 exit_code = exit_code >> 8; 1565 if (exit_code == 0) 1566 ret = True; 1567 else 1568 ret = False; 1569 break; 1570 } 1571 1572 return (ret); 1573 } 1574 1575 /* 1576 * Following two functions replace ':' and '.' in target/initiator 1577 * names into '__2' and '__1' when write to SMF, and do a reverse 1578 * replacement when read from SMF. 1579 * pgname_encode's buffers are allocated by caller. 1580 * see CR 6626684 1581 */ 1582 #define SMF_COLON "__2" 1583 #define SMF_DOT "__1" 1584 1585 static void 1586 pgname_encode(char *instr, char *outstr, int max_len) 1587 { 1588 int i = 0; 1589 1590 assert(instr != NULL && outstr != NULL); 1591 for (; *instr != '\0'; instr++) { 1592 switch (*instr) { 1593 case ':': 1594 strcpy(outstr + i, SMF_COLON); 1595 i += 3; 1596 break; 1597 case '.': 1598 strcpy(outstr + i, SMF_DOT); 1599 i += 3; 1600 break; 1601 default: 1602 *(outstr + i) = *instr; 1603 i ++; 1604 break; 1605 } 1606 /* in case of next possible ':' or '.', we cease on len-3 */ 1607 if (i >= max_len - 3) 1608 break; 1609 } 1610 outstr[i] = '\0'; 1611 } 1612 1613 /* 1614 * pgname_decode use original buffer, since it reduces string length 1615 */ 1616 static void 1617 pgname_decode(char *instr) 1618 { 1619 char *buf; 1620 char *rec; 1621 1622 assert(instr != NULL); 1623 buf = strdup(instr); 1624 1625 if (buf == NULL) 1626 return; 1627 1628 rec = buf; 1629 for (; *buf != '\0'; buf++) { 1630 if (*buf == '_') { 1631 if (memcmp(buf, SMF_COLON, strlen(SMF_COLON)) == 0) { 1632 *instr = ':'; 1633 buf += 2; 1634 } else if (memcmp(buf, SMF_DOT, strlen(SMF_DOT)) == 0) { 1635 *instr = '.'; 1636 buf += 2; 1637 } else { 1638 *instr = *buf; 1639 } 1640 } else { 1641 *instr = *buf; 1642 } 1643 instr ++; 1644 } 1645 *instr = '\0'; 1646 free(rec); 1647 } 1648