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 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 27 */ 28 29 /* 30 * SMB specific functions 31 */ 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <zone.h> 38 #include <errno.h> 39 #include <locale.h> 40 #include <signal.h> 41 #include <fcntl.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <syslog.h> 45 #include "libshare.h" 46 #include "libshare_impl.h" 47 #include <pwd.h> 48 #include <limits.h> 49 #include <libscf.h> 50 #include <strings.h> 51 #include "libshare_smbfs.h" 52 #include <rpcsvc/daemon_utils.h> 53 #include <arpa/inet.h> 54 #include <uuid/uuid.h> 55 #include <netsmb/smb_lib.h> 56 57 #define SMBFS_PROTOCOL_NAME "smbfs" 58 59 /* internal functions */ 60 static uint64_t smbfs_features(); 61 static int smbfs_init(); 62 static void smbfs_fini(); 63 static int smbfs_set_proto_prop(sa_property_t); 64 static sa_protocol_properties_t smbfs_get_proto_set(); 65 static char *smbfs_get_status(); 66 static int smbfs_delete_section(char *); 67 static int smbfs_delete_property_group(char *); 68 69 static int range_check_validator(int, char *, char *); 70 static int string_length_check_validator(int, char *, char *); 71 static int yes_no_validator(int, char *, char *); 72 static int ip_address_validator(int, char *, char *); 73 static int minauth_validator(int, char *, char *); 74 static int password_validator(int, char *, char *); 75 static int protocol_validator(int, char *, char *); 76 static int signing_validator(int, char *, char *); 77 78 int propset_changed = 0; 79 80 /* 81 * ops vector that provides the protocol specific info and operations 82 * for share management. 83 */ 84 85 struct sa_plugin_ops sa_plugin_ops = { 86 SA_PLUGIN_VERSION, 87 SMBFS_PROTOCOL_NAME, 88 smbfs_init, 89 smbfs_fini, 90 NULL, /* share */ 91 NULL, /* unshare */ 92 NULL, /* valid_prop */ 93 NULL, /* valid_space */ 94 NULL, /* security_prop */ 95 NULL, /* legacy_opts */ 96 NULL, /* legacy_format */ 97 smbfs_set_proto_prop, 98 smbfs_get_proto_set, 99 smbfs_get_status, 100 NULL, /* space_alias */ 101 NULL, /* update_legacy */ 102 NULL, /* delete_legacy */ 103 NULL, /* change_notify */ 104 NULL, /* enable_resource */ 105 NULL, /* disable_resource */ 106 smbfs_features, 107 NULL, /* get_transient_shares */ 108 NULL, /* notify_resource */ 109 NULL, /* rename_resource */ 110 NULL, /* run_command */ 111 NULL, /* command_help */ 112 smbfs_delete_section, 113 }; 114 115 /* 116 * is_a_number(number) 117 * 118 * is the string a number in one of the forms we want to use? 119 */ 120 121 static int 122 is_a_number(char *number) 123 { 124 int ret = 1; 125 int hex = 0; 126 127 if (strncmp(number, "0x", 2) == 0) { 128 number += 2; 129 hex = 1; 130 } else if (*number == '-') { 131 number++; /* skip the minus */ 132 } 133 134 while (ret == 1 && *number != '\0') { 135 if (hex) { 136 ret = isxdigit(*number++); 137 } else { 138 ret = isdigit(*number++); 139 } 140 } 141 return (ret); 142 } 143 144 /* 145 * Protocol management functions 146 * 147 * properties defined in the default files are defined in 148 * proto_option_defs for parsing and validation. 149 */ 150 151 struct smbclnt_proto_option_defs smbclnt_proto_options[] = { 152 { "section", NULL, PROTO_OPT_SECTION, 153 0, 0, MAX_VALUE_BUFLEN, 154 string_length_check_validator}, 155 { "addr", NULL, PROTO_OPT_ADDR, 156 0, 0, MAX_VALUE_BUFLEN, 157 ip_address_validator}, 158 { "minauth", NULL, PROTO_OPT_MINAUTH, 159 0, 0, MAX_VALUE_BUFLEN, 160 minauth_validator}, 161 { "nbns_broadcast", NULL, PROTO_OPT_NBNS_BROADCAST, 162 0, 0, 0, 163 yes_no_validator}, 164 { "nbns_enable", NULL, PROTO_OPT_NBNS_ENABLE, 165 0, 0, 0, 166 yes_no_validator}, 167 { "nbns", NULL, PROTO_OPT_NBNSADDR, 168 0, 0, MAX_VALUE_BUFLEN, 169 ip_address_validator}, 170 { "password", NULL, PROTO_OPT_PASSWORD, 171 0, 0, MAX_VALUE_BUFLEN, 172 password_validator}, 173 { "timeout", NULL, PROTO_OPT_TIMEOUT, 174 0, 0, 60, 175 range_check_validator}, 176 { "user", NULL, PROTO_OPT_USER, 177 0, 0, MAX_VALUE_BUFLEN, 178 string_length_check_validator}, 179 { "domain", NULL, PROTO_OPT_DOMAIN, 180 0, 0, MAX_VALUE_BUFLEN, 181 string_length_check_validator}, 182 { "workgroup", NULL, PROTO_OPT_WORKGROUP, 183 0, 0, MAX_VALUE_BUFLEN, 184 string_length_check_validator}, 185 { "signing", NULL, PROTO_OPT_SIGNING, 186 0, 0, MAX_VALUE_BUFLEN, 187 signing_validator}, 188 { "min_protocol", NULL, PROTO_OPT_MIN_PROTOCOL, 189 0, 0, MAX_VALUE_BUFLEN, 190 protocol_validator}, 191 { "max_protocol", NULL, PROTO_OPT_MAX_PROTOCOL, 192 0, 0, MAX_VALUE_BUFLEN, 193 protocol_validator}, 194 {NULL} 195 }; 196 197 /* 198 * Check the range of value as int range. 199 */ 200 /*ARGSUSED*/ 201 static int 202 range_check_validator(int index, char *section, char *value) 203 { 204 int ret = SA_OK; 205 206 if (value == NULL) 207 return (SA_BAD_VALUE); 208 if (strlen(value) == 0) 209 return (SA_OK); 210 if (!is_a_number(value)) { 211 ret = SA_BAD_VALUE; 212 } else { 213 int val; 214 val = strtoul(value, NULL, 0); 215 if (val < smbclnt_proto_options[index].minval || 216 val > smbclnt_proto_options[index].maxval) 217 ret = SA_BAD_VALUE; 218 } 219 return (ret); 220 } 221 222 /* 223 * Check the length of the string 224 */ 225 /*ARGSUSED*/ 226 static int 227 string_length_check_validator(int index, char *section, char *value) 228 { 229 int ret = SA_OK; 230 231 if (value == NULL) 232 return (SA_BAD_VALUE); 233 if (strlen(value) == 0) 234 return (SA_OK); 235 if (strlen(value) > smbclnt_proto_options[index].maxval) 236 ret = SA_BAD_VALUE; 237 return (ret); 238 } 239 240 /* 241 * Check yes/no 242 */ 243 /*ARGSUSED*/ 244 static int 245 yes_no_validator(int index, char *section, char *value) 246 { 247 if (value == NULL) 248 return (SA_BAD_VALUE); 249 if (strlen(value) == 0) 250 return (SA_OK); 251 if ((strcasecmp(value, "yes") == 0) || 252 (strcasecmp(value, "no") == 0) || 253 (strcasecmp(value, "true") == 0) || 254 (strcasecmp(value, "false") == 0)) 255 return (SA_OK); 256 return (SA_BAD_VALUE); 257 } 258 259 /* 260 * Check IP address. 261 */ 262 /*ARGSUSED*/ 263 static int 264 ip_address_validator(int index, char *section, char *value) 265 { 266 int len; 267 268 if (value == NULL) 269 return (SA_BAD_VALUE); 270 len = strlen(value); 271 if (len == 0) 272 return (SA_OK); 273 if (len > MAX_VALUE_BUFLEN) 274 return (SA_BAD_VALUE); 275 return (SA_OK); 276 } 277 278 /*ARGSUSED*/ 279 static int 280 minauth_validator(int index, char *section, char *value) 281 { 282 int ival; 283 284 if (value == NULL) 285 return (SA_BAD_VALUE); 286 ival = smb_cf_minauth_from_str(value); 287 if (ival == -1) 288 return (SA_BAD_VALUE); 289 290 return (SA_OK); 291 } 292 293 /*ARGSUSED*/ 294 static int 295 protocol_validator(int index, char *section, char *value) 296 { 297 int ival; 298 299 if (value == NULL) 300 return (SA_BAD_VALUE); 301 ival = smb_cf_version_from_str(value); 302 if (ival == -1) 303 return (SA_BAD_VALUE); 304 305 return (SA_OK); 306 } 307 308 /*ARGSUSED*/ 309 static int 310 signing_validator(int index, char *section, char *value) 311 { 312 if (value == NULL) 313 return (SA_BAD_VALUE); 314 if (strlen(value) == 0) 315 return (SA_OK); 316 if (strcmp(value, "disabled") == 0 || 317 strcmp(value, "enabled") == 0 || 318 strcmp(value, "required") == 0) 319 return (SA_OK); 320 else 321 return (SA_BAD_VALUE); 322 } 323 324 /*ARGSUSED*/ 325 static int 326 password_validator(int index, char *section, char *value) 327 { 328 char buffer[100]; 329 330 /* mangled passwords will start with this pattern */ 331 if (strlen(value) == 0) 332 return (SA_OK); 333 if (strncmp(value, "$$1", 3) != 0) 334 return (SA_PASSWORD_ENC); 335 if (smb_simpledecrypt(buffer, value) != 0) 336 return (SA_BAD_VALUE); 337 return (SA_OK); 338 } 339 340 341 /* 342 * the protoset holds the defined options so we don't have to read 343 * them multiple times 344 */ 345 sa_protocol_properties_t protoset; 346 347 static int 348 findprotoopt(char *name) 349 { 350 int i; 351 for (i = 0; smbclnt_proto_options[i].name != NULL; i++) { 352 if (strcasecmp(smbclnt_proto_options[i].name, name) == 0) 353 return (i); 354 } 355 return (-1); 356 } 357 358 /* 359 * Load the persistent settings from SMF. Each section is an SMF 360 * property group with an "S-" prefix and a UUID, and the section 361 * is itself a property which can have a more flexible name than 362 * a property group name can have. The section name need not be 363 * the first property, so we have to be a little flexible, but 364 * the change of name of the property groups is a reliable way 365 * to know that we're seeing a different section. 366 */ 367 int 368 smbclnt_config_load() 369 { 370 scf_simple_app_props_t *props = NULL; 371 scf_simple_prop_t *prop = NULL, *lastprop = NULL; 372 char *lastpgname = NULL, *pgname = NULL; 373 char *name = NULL, *value = NULL; 374 sa_property_t sect, node; 375 376 props = scf_simple_app_props_get(NULL, SMBC_DEFAULT_INSTANCE_FMRI); 377 if (props == NULL) 378 return (-1); 379 380 for (;;) { 381 lastprop = prop; 382 prop = (scf_simple_prop_t *) 383 scf_simple_app_props_next(props, lastprop); 384 if (prop == NULL) 385 break; 386 387 /* Ignore properties that don't have our prefix */ 388 pgname = scf_simple_prop_pgname(prop); 389 if (strncmp("S-", pgname, 2) != 0) 390 continue; 391 392 /* 393 * Note property group name changes, which mark sections 394 * 395 * The memory allocated by sa_create_section is 396 * linked into the list of children under protoset, 397 * and will eventually be freed via that list. 398 */ 399 if (lastpgname == NULL || strcmp(lastpgname, pgname) != 0) { 400 sect = sa_create_section(NULL, pgname+2); 401 (void) xmlSetProp(sect, (xmlChar *)"type", 402 (xmlChar *)SMBFS_PROTOCOL_NAME); 403 (void) sa_add_protocol_property(protoset, sect); 404 if (lastpgname) 405 free(lastpgname); 406 lastpgname = strdup(pgname); 407 } 408 name = scf_simple_prop_name(prop); 409 value = scf_simple_prop_next_astring(prop); 410 411 /* If we get a section name, apply it and consume it */ 412 if (strncmp("section", name, 7) == 0 && value != NULL) { 413 (void) xmlSetProp(sect, (xmlChar *)"name", 414 (xmlChar *)value); 415 continue; 416 } 417 418 /* 419 * We have an ordinary property. Add to the section. 420 * 421 * The memory allocated by sa_create_property is 422 * linked into the list of children under "sect", 423 * and will eventually be freed via that list. 424 */ 425 node = sa_create_property(name, value); 426 (void) sa_add_protocol_property(sect, node); 427 } 428 scf_simple_app_props_free(props); 429 430 if (lastpgname) 431 free(lastpgname); 432 return (0); 433 } 434 435 /* 436 * Save the set of properties for a particular section, which is 437 * stored as a single property group. Properties will have been 438 * changed earlier by one or more calls to smbfs_save_property(), 439 * which only set the value in our array and marked them as 440 * SMBC_MODIFIED. 441 */ 442 int 443 smbfs_save_propset() 444 { 445 smb_scfhandle_t *handle = NULL; 446 char propgroup[256]; 447 char *section = smbclnt_proto_options[PROTO_OPT_SECTION].value; 448 char *uu = NULL; 449 uuid_t uuid; 450 int i, ret = 0; 451 sa_property_t propset; 452 int new = 0, nonnull = 0; 453 454 propset = sa_get_protocol_section(protoset, section); 455 (void) strlcpy(propgroup, SMBC_PG_PREFIX, sizeof (propgroup)); 456 propgroup[SMBC_PG_PREFIX_LEN] = '\0'; 457 uu = sa_get_property_attr(propset, "extra"); 458 if (uu != NULL) { 459 (void) strlcat(propgroup, uu, sizeof (propgroup)); 460 free(uu); 461 } else { 462 new = 1; 463 smbclnt_proto_options[PROTO_OPT_SECTION].flags |= SMBC_MODIFIED; 464 uuid_generate(uuid); 465 uuid_unparse(uuid, &propgroup[SMBC_PG_PREFIX_LEN]); 466 } 467 468 handle = smb_smf_scf_init(SMBC_FMRI_PREFIX); 469 if (handle == NULL) { 470 return (1); 471 } 472 473 if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX, 474 SMBC_PG_INSTANCE)) != SMBC_SMF_OK) { 475 goto out; 476 } 477 478 if ((ret = smb_smf_create_instance_pgroup(handle, propgroup)) 479 != SMBC_SMF_OK) { 480 goto out; 481 } 482 483 if ((ret = smb_smf_start_transaction(handle)) != SMBC_SMF_OK) { 484 goto out; 485 } 486 487 for (i = PROTO_OPT_SECTION+1; i <= SMBC_OPT_MAX; i++) { 488 if ((smbclnt_proto_options[i].flags & SMBC_MODIFIED) == 0) 489 continue; 490 if (strcmp(smbclnt_proto_options[i].value, "") == 0) 491 ret = smb_smf_delete_property(handle, 492 smbclnt_proto_options[i].name); 493 else { 494 ret = smb_smf_set_string_property(handle, 495 smbclnt_proto_options[i].name, 496 smbclnt_proto_options[i].value); 497 nonnull = 1; 498 } 499 free(smbclnt_proto_options[i].value); 500 smbclnt_proto_options[i].value = NULL; 501 smbclnt_proto_options[i].flags &= ~SMBC_MODIFIED; 502 if (ret != SMBC_SMF_OK) 503 goto outtrans; 504 } 505 /* 506 * Suppress new, null entries by not saving the section name. 507 */ 508 if (!new || nonnull) { 509 ret = smb_smf_set_string_property(handle, 510 smbclnt_proto_options[PROTO_OPT_SECTION].name, 511 smbclnt_proto_options[PROTO_OPT_SECTION].value); 512 free(smbclnt_proto_options[PROTO_OPT_SECTION].value); 513 smbclnt_proto_options[PROTO_OPT_SECTION].value = NULL; 514 smbclnt_proto_options[PROTO_OPT_SECTION].flags &= 515 ~SMBC_MODIFIED; 516 } 517 propset_changed = 0; 518 519 outtrans: 520 ret = smb_smf_end_transaction(handle); 521 out: 522 smb_smf_scf_fini(handle); 523 return (ret); 524 } 525 526 /* 527 * initprotofromdefault() 528 * 529 * read the default file(s) and add the defined values to the 530 * protoset. Note that default values are known from the built in 531 * table in case the file doesn't have a definition. 532 */ 533 534 static int 535 initprotofromdefault() 536 { 537 protoset = sa_create_protocol_properties(SMBFS_PROTOCOL_NAME); 538 if (protoset == NULL) 539 return (SA_NO_MEMORY); 540 if (smbclnt_config_load() != 0) 541 return (SA_OK); 542 543 return (SA_OK); 544 } 545 546 /* 547 * 548 * smbfs_features() 549 * 550 * Report the plugin's features 551 */ 552 static uint64_t 553 smbfs_features() 554 { 555 return (SA_FEATURE_HAS_SECTIONS | SA_FEATURE_ADD_PROPERTIES); 556 } 557 558 /* 559 * smbfs_init() 560 * 561 * Initialize the smb plugin. 562 */ 563 564 static int 565 smbfs_init() 566 { 567 int ret = SA_OK; 568 569 if (sa_plugin_ops.sa_init != smbfs_init) { 570 return (SA_SYSTEM_ERR); 571 } 572 573 if (initprotofromdefault() != SA_OK) { 574 return (SA_SYSTEM_ERR); 575 } 576 577 return (ret); 578 } 579 580 /* 581 * smbfs_fini() 582 * 583 * uninitialize the smb plugin. Want to avoid memory leaks. 584 */ 585 586 static void 587 smbfs_fini() 588 { 589 if (propset_changed) 590 (void) smbfs_save_propset(); 591 xmlFreeNode(protoset); 592 protoset = NULL; 593 } 594 595 /* 596 * smbfs_get_proto_set() 597 * 598 * Return an optionset with all the protocol specific properties in 599 * it. 600 */ 601 602 static sa_protocol_properties_t 603 smbfs_get_proto_set() 604 { 605 return (protoset); 606 } 607 608 /* 609 * smbfs_validate_proto_prop(index, name, value) 610 * 611 * Verify that the property specifed by name can take the new 612 * value. This is a sanity check to prevent bad values getting into 613 * the default files. 614 */ 615 static int 616 smbfs_validate_proto_prop(int index, char *section, char *name, char *value) 617 { 618 if ((section == NULL) || (name == NULL) || (index < 0)) 619 return (SA_BAD_VALUE); 620 621 if (smbclnt_proto_options[index].validator == NULL) 622 return (SA_OK); 623 624 return (smbclnt_proto_options[index].validator(index, section, value)); 625 } 626 627 /* 628 * Save a property to our array; it will be stored to SMF later by 629 * smbfs_save_propset(). 630 */ 631 int 632 smbfs_save_property(int index, char *section, char *value) 633 { 634 char *s; 635 636 if (index == PROTO_OPT_WORKGROUP) { 637 index = PROTO_OPT_DOMAIN; 638 } 639 propset_changed = 1; 640 s = strdup(section); 641 if (s == NULL) 642 return (-1); 643 smbclnt_proto_options[PROTO_OPT_SECTION].value = s; 644 s = strdup(value); 645 if (s == NULL) 646 return (-1); 647 smbclnt_proto_options[index].value = s; 648 smbclnt_proto_options[index].flags |= SMBC_MODIFIED; 649 return (0); 650 } 651 652 /* 653 * smbfs_set_proto_prop(prop) 654 * 655 * check that prop is valid. 656 */ 657 /*ARGSUSED*/ 658 static int 659 smbfs_set_proto_prop(sa_property_t prop) 660 { 661 int ret = SA_OK; 662 char *name; 663 char *value; 664 char *section; 665 int i = -1; 666 667 section = sa_get_property_attr(prop, "section"); 668 if (section == NULL) 669 return (SA_NO_SECTION); 670 name = sa_get_property_attr(prop, "type"); 671 value = sa_get_property_attr(prop, "value"); 672 if (name != NULL && value != NULL) { 673 i = findprotoopt(name); 674 if (i >= 0) { 675 ret = smbfs_validate_proto_prop(i, section, 676 name, value); 677 if (ret == SA_OK) { 678 if (smbfs_save_property(i, section, 679 value) != 0) { 680 ret = SA_SYSTEM_ERR; 681 errno = EIO; 682 } 683 } 684 } else 685 ret = SA_INVALID_NAME; 686 } 687 if (name != NULL) 688 sa_free_attr_string(name); 689 if (value != NULL) 690 sa_free_attr_string(value); 691 if (section != NULL) 692 sa_free_attr_string(section); 693 694 return (ret); 695 } 696 697 /* 698 * smbfs_get_status() 699 * 700 * What is the current status of the smbd? We use the SMF state here. 701 * Caller must free the returned value. 702 */ 703 704 static char * 705 smbfs_get_status() 706 { 707 return (smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI)); 708 } 709 710 /* 711 * Delete a section by its name, which we will have read into an 712 * XML optionset above. We need to find it and find its UUID to 713 * be able to generate the property group name in order to call 714 * smbfs_delete_property_group(). 715 */ 716 static int 717 smbfs_delete_section(char *section) 718 { 719 char propgroup[256]; 720 char *uu = NULL; 721 sa_property_t propset; 722 int ret = SA_SYSTEM_ERR; 723 724 propset = sa_get_protocol_section(protoset, section); 725 (void) strlcpy(propgroup, SMBC_PG_PREFIX, sizeof (propgroup)); 726 propgroup[SMBC_PG_PREFIX_LEN] = '\0'; 727 uu = sa_get_property_attr(propset, "extra"); 728 if (uu == NULL) 729 goto out; 730 (void) strlcat(propgroup, uu, sizeof (propgroup)); 731 free(uu); 732 if ((ret = smbfs_delete_property_group(propgroup)) != SMBC_SMF_OK) 733 goto out; 734 ret = SA_OK; 735 out: 736 return (ret); 737 } 738 739 /* 740 * Delete a property group by its name. Called to do a 'delsect' 741 * or called when smbclnt_config_load() notices an empty section 742 * at the end of the properties. 743 */ 744 static int 745 smbfs_delete_property_group(char *propgroup) 746 { 747 smb_scfhandle_t *handle = NULL; 748 int ret = SA_SYSTEM_ERR; 749 750 handle = smb_smf_scf_init(SMBC_FMRI_PREFIX); 751 if (handle == NULL) 752 goto out; 753 754 if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX, 755 SMBC_PG_INSTANCE)) != SMBC_SMF_OK) 756 goto out; 757 758 if ((ret = smb_smf_delete_instance_pgroup(handle, propgroup)) 759 != SMBC_SMF_OK) 760 goto out; 761 ret = SA_OK; 762 out: 763 smb_smf_scf_fini(handle); 764 return (ret); 765 } 766