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