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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Lan Manager (SMB/CIFS) share interface implementation. This interface 28 * returns Win32 error codes, usually network error values (lmerr.h). 29 */ 30 31 #include <errno.h> 32 #include <synch.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <strings.h> 36 #include <syslog.h> 37 #include <thread.h> 38 #include <fcntl.h> 39 #include <unistd.h> 40 #include <netdb.h> 41 #include <synch.h> 42 #include <pthread.h> 43 #include <ctype.h> 44 #include <assert.h> 45 #include <sys/mnttab.h> 46 #include <sys/stat.h> 47 #include <sys/types.h> 48 49 #include <smbsrv/libsmb.h> 50 #include <smbsrv/libsmbns.h> 51 #include <smbsrv/libmlsvc.h> 52 53 #include <libshare.h> 54 55 #include <smbsrv/lm.h> 56 #include <smbsrv/smb_share.h> 57 #include <smbsrv/cifs.h> 58 59 #include <smbsrv/ctype.h> 60 #include <smbsrv/smb_vops.h> 61 #include <smbsrv/nterror.h> 62 63 /* 64 * Cache functions and vars 65 */ 66 #define SMB_SHARE_HTAB_SZ 1024 67 68 static HT_HANDLE *smb_shr_handle = NULL; 69 static rwlock_t smb_shr_lock; 70 static pthread_t smb_shr_populate_thr; 71 72 static uint32_t smb_shr_cache_create(void); 73 static void smb_shr_cache_destroy(void); 74 static void *smb_shr_cache_populate(void *); 75 static uint32_t smb_shr_cache_addent(smb_share_t *); 76 static void smb_shr_cache_delent(char *); 77 static uint32_t smb_shr_cache_chgent(smb_share_t *); 78 static void smb_shr_cache_freent(HT_ITEM *); 79 static uint32_t smb_shr_cache_loadent(sa_share_t, sa_resource_t); 80 static void smb_shr_cache_loadgrp(sa_group_t); 81 82 static void smb_shr_set_ahcnt(char *, int); 83 static void smb_shr_set_oemname(smb_share_t *); 84 static uint32_t smb_shr_create_autohome(smb_share_t *); 85 static uint32_t smb_shr_create_ipc(void); 86 87 /* 88 * sharemgr functions 89 */ 90 static uint32_t smb_shr_sa_delent(smb_share_t *); 91 static uint32_t smb_shr_sa_addent(smb_share_t *); 92 static uint32_t smb_shr_sa_getent(sa_share_t, sa_resource_t, smb_share_t *); 93 static sa_group_t smb_shr_sa_getdefgrp(sa_handle_t); 94 95 /* 96 * share publishing 97 */ 98 #define SMB_SHR_PUBLISH 0 99 #define SMB_SHR_UNPUBLISH 1 100 101 typedef struct smb_shr_pitem { 102 list_node_t spi_lnd; 103 char spi_name[MAXNAMELEN]; 104 char spi_container[MAXPATHLEN]; 105 char spi_op; 106 } smb_shr_pitem_t; 107 108 /* 109 * publish queue states 110 */ 111 #define SMB_SHR_PQS_NOQUEUE 0 112 #define SMB_SHR_PQS_READY 1 /* the queue is ready */ 113 #define SMB_SHR_PQS_PUBLISHING 2 /* publisher thread is running */ 114 #define SMB_SHR_PQS_STOPPING 3 115 116 /* 117 * share publishing queue 118 */ 119 typedef struct smb_shr_pqueue { 120 int spq_cnt; 121 list_t spq_list; 122 mutex_t spq_mtx; 123 cond_t spq_cv; 124 uint32_t spq_state; 125 } smb_shr_pqueue_t; 126 127 static smb_shr_pqueue_t ad_queue; 128 static pthread_t smb_shr_publish_thr; 129 130 static int smb_shr_publisher_start(void); 131 static void smb_shr_publisher_stop(void); 132 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *); 133 static void *smb_shr_publisher(void *); 134 static void smb_shr_publish(const char *, const char *, char); 135 136 137 /* 138 * smb_shr_start 139 * 140 * Starts the publisher thread and another thread which 141 * populates the share cache by share information stored 142 * by sharemgr 143 */ 144 int 145 smb_shr_start(void) 146 { 147 pthread_attr_t tattr; 148 int rc; 149 150 if ((rc = smb_shr_publisher_start()) != 0) 151 return (rc); 152 153 (void) pthread_attr_init(&tattr); 154 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 155 rc = pthread_create(&smb_shr_populate_thr, &tattr, 156 smb_shr_cache_populate, 0); 157 (void) pthread_attr_destroy(&tattr); 158 159 return (rc); 160 } 161 162 void 163 smb_shr_stop(void) 164 { 165 smb_shr_cache_destroy(); 166 smb_shr_publisher_stop(); 167 } 168 169 /* 170 * smb_shr_count 171 * 172 * Return the total number of shares 173 */ 174 int 175 smb_shr_count(void) 176 { 177 int n_shares; 178 179 (void) rw_rdlock(&smb_shr_lock); 180 n_shares = ht_get_total_items(smb_shr_handle); 181 (void) rw_unlock(&smb_shr_lock); 182 183 return (n_shares); 184 } 185 186 /* 187 * smb_shr_iterinit 188 * 189 * Initialize given iterator for traversing hash table. 190 */ 191 void 192 smb_shr_iterinit(smb_shriter_t *shi) 193 { 194 bzero(shi, sizeof (smb_shriter_t)); 195 shi->si_first = B_TRUE; 196 } 197 198 /* 199 * smb_shr_iterate 200 * 201 * Iterate on the shares in the hash table. The iterator must be initialized 202 * before the first iteration. On subsequent calls, the iterator must be 203 * passed unchanged. 204 * 205 * Returns NULL on failure or when all shares are visited, otherwise 206 * returns information of visited share. 207 */ 208 smb_share_t * 209 smb_shr_iterate(smb_shriter_t *shi) 210 { 211 HT_ITEM *item; 212 smb_share_t *share = NULL; 213 214 if (smb_shr_handle == NULL || shi == NULL) 215 return (NULL); 216 217 (void) rw_rdlock(&smb_shr_lock); 218 if (shi->si_first) { 219 item = ht_findfirst(smb_shr_handle, &shi->si_hashiter); 220 shi->si_first = B_FALSE; 221 } else { 222 item = ht_findnext(&shi->si_hashiter); 223 } 224 225 if (item && item->hi_data) { 226 share = &shi->si_share; 227 bcopy(item->hi_data, share, sizeof (smb_share_t)); 228 } 229 (void) rw_unlock(&smb_shr_lock); 230 231 return (share); 232 } 233 234 /* 235 * smb_shr_create 236 * 237 * Adds the given to cache and if 'store' is B_TRUE it's also 238 * added to sharemgr 239 */ 240 uint32_t 241 smb_shr_create(smb_share_t *si, boolean_t store) 242 { 243 uint32_t status = NERR_Success; 244 int rc; 245 246 assert(si != NULL); 247 248 if (!smb_shr_chkname(si->shr_name)) 249 return (ERROR_INVALID_NAME); 250 251 if (si->shr_flags & SMB_SHRF_AUTOHOME) 252 return (smb_shr_create_autohome(si)); 253 254 if (smb_shr_exists(si->shr_name)) 255 return (NERR_DuplicateShare); 256 257 if ((status = smb_shr_cache_addent(si)) != NERR_Success) 258 return (status); 259 260 if (store && (si->shr_flags & SMB_SHRF_PERM)) { 261 if ((status = smb_shr_sa_addent(si)) != NERR_Success) { 262 (void) smb_shr_cache_delent(si->shr_name); 263 return (status); 264 } 265 } 266 267 rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name); 268 269 if (rc == 0) { 270 smb_shr_publish(si->shr_name, si->shr_container, 271 SMB_SHR_PUBLISH); 272 return (status); 273 } 274 275 smb_shr_cache_delent(si->shr_name); 276 if (store && (si->shr_flags & SMB_SHRF_PERM)) 277 (void) smb_shr_sa_delent(si); 278 279 /* 280 * rc == ENOENT means the shared directory doesn't exist 281 */ 282 return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError); 283 } 284 285 /* 286 * smb_shr_delete 287 * 288 * Removes the specified share. 289 */ 290 uint32_t 291 smb_shr_delete(char *sharename, boolean_t store) 292 { 293 smb_share_t si; 294 uint32_t status = NERR_Success; 295 296 assert(sharename != NULL); 297 298 if ((status = smb_shr_get(sharename, &si)) != NERR_Success) 299 return (status); 300 301 if (si.shr_type & STYPE_IPC) 302 return (ERROR_ACCESS_DENIED); 303 304 if (si.shr_flags & SMB_SHRF_AUTOHOME) { 305 si.shr_refcnt--; 306 if (si.shr_refcnt > 0) { 307 smb_shr_set_ahcnt(si.shr_name, si.shr_refcnt); 308 return (status); 309 } 310 } 311 312 if (store && (si.shr_flags & SMB_SHRF_PERM)) { 313 if (smb_shr_sa_delent(&si) != NERR_Success) 314 return (NERR_InternalError); 315 } 316 317 smb_shr_cache_delent(si.shr_name); 318 smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_UNPUBLISH); 319 (void) mlsvc_set_share(SMB_SHROP_DELETE, si.shr_path, si.shr_name); 320 321 return (NERR_Success); 322 } 323 324 /* 325 * smb_shr_rename 326 * 327 * Rename a share. Check that the current name exists and the new name 328 * doesn't exist. The rename is performed by deleting the current share 329 * definition and creating a new share with the new name. 330 */ 331 uint32_t 332 smb_shr_rename(char *from_name, char *to_name) 333 { 334 smb_share_t si; 335 uint32_t status; 336 337 assert((from_name != NULL) && (to_name != NULL)); 338 339 if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name)) 340 return (ERROR_INVALID_NAME); 341 342 if (!smb_shr_exists(from_name)) 343 return (NERR_NetNameNotFound); 344 345 if (smb_shr_exists(to_name)) 346 return (NERR_DuplicateShare); 347 348 if ((status = smb_shr_get(from_name, &si)) != NERR_Success) 349 return (status); 350 351 if (si.shr_type & STYPE_IPC) 352 return (ERROR_ACCESS_DENIED); 353 354 (void) strlcpy(si.shr_name, to_name, sizeof (si.shr_name)); 355 if ((status = smb_shr_cache_addent(&si)) != NERR_Success) 356 return (status); 357 358 smb_shr_cache_delent(from_name); 359 smb_shr_publish(from_name, si.shr_container, SMB_SHR_UNPUBLISH); 360 smb_shr_publish(to_name, si.shr_container, SMB_SHR_PUBLISH); 361 362 return (NERR_Success); 363 } 364 365 /* 366 * smb_shr_get 367 * 368 * Load the information for the specified share into the supplied share 369 * info structure. 370 */ 371 uint32_t 372 smb_shr_get(char *sharename, smb_share_t *si) 373 { 374 HT_ITEM *item; 375 376 (void) utf8_strlwr(sharename); 377 378 (void) rw_rdlock(&smb_shr_lock); 379 item = ht_find_item(smb_shr_handle, sharename); 380 if (item == NULL || item->hi_data == NULL) { 381 (void) rw_unlock(&smb_shr_lock); 382 return (NERR_NetNameNotFound); 383 } 384 385 bcopy(item->hi_data, si, sizeof (smb_share_t)); 386 (void) rw_unlock(&smb_shr_lock); 387 388 return (NERR_Success); 389 } 390 391 /* 392 * smb_shr_modify 393 * 394 * Modifies an existing share. Properties that can be modified are: 395 * 396 * o comment 397 * o AD container 398 */ 399 uint32_t 400 smb_shr_modify(char *sharename, const char *cmnt, 401 const char *ad_container, boolean_t store) 402 { 403 smb_share_t si; 404 uint32_t status; 405 boolean_t cmnt_changed = B_FALSE; 406 boolean_t adc_changed = B_FALSE; 407 char shr_container[MAXPATHLEN]; 408 409 assert(sharename != NULL); 410 411 if ((cmnt == NULL) && (ad_container == NULL)) 412 /* no changes */ 413 return (NERR_Success); 414 415 if ((status = smb_shr_get(sharename, &si)) != NERR_Success) 416 return (status); 417 418 if (si.shr_type & STYPE_IPC) 419 return (ERROR_ACCESS_DENIED); 420 421 if (cmnt) { 422 cmnt_changed = (strcmp(cmnt, si.shr_cmnt) != 0); 423 if (cmnt_changed) 424 (void) strlcpy(si.shr_cmnt, cmnt, sizeof (si.shr_cmnt)); 425 } 426 427 if (ad_container) { 428 adc_changed = (strcmp(ad_container, si.shr_container) != 0); 429 if (adc_changed) { 430 /* save current container needed for unpublishing */ 431 (void) strlcpy(shr_container, si.shr_container, 432 sizeof (shr_container)); 433 (void) strlcpy(si.shr_container, ad_container, 434 sizeof (si.shr_container)); 435 } 436 } 437 438 if (!cmnt_changed && !adc_changed) 439 /* no changes */ 440 return (NERR_Success); 441 442 if (store && (si.shr_flags & SMB_SHRF_PERM)) { 443 if (smb_shr_sa_addent(&si) != NERR_Success) 444 return (NERR_InternalError); 445 } 446 447 (void) smb_shr_cache_chgent(&si); 448 449 if (adc_changed) { 450 smb_shr_publish(si.shr_name, shr_container, 451 SMB_SHR_UNPUBLISH); 452 smb_shr_publish(si.shr_name, si.shr_container, 453 SMB_SHR_PUBLISH); 454 } 455 456 return (NERR_Success); 457 } 458 459 void 460 smb_shr_list(int offset, smb_shrlist_t *list) 461 { 462 smb_shriter_t iterator; 463 smb_share_t *si; 464 int n = 0; 465 466 bzero(list, sizeof (smb_shrlist_t)); 467 smb_shr_iterinit(&iterator); 468 469 while ((si = smb_shr_iterate(&iterator)) != NULL) { 470 if (--offset > 0) 471 continue; 472 473 if ((si->shr_flags & SMB_SHRF_TRANS) && 474 ((si->shr_type & STYPE_IPC) == 0)) { 475 bcopy(si, &list->sl_shares[n], sizeof (smb_share_t)); 476 if (++n == LMSHARES_PER_REQUEST) 477 break; 478 } 479 } 480 481 list->sl_cnt = n; 482 } 483 484 485 /* 486 * smb_shr_exists 487 * 488 * Returns B_TRUE if the share exists. Otherwise returns B_FALSE 489 */ 490 boolean_t 491 smb_shr_exists(char *sharename) 492 { 493 boolean_t exists; 494 495 if (sharename == NULL || *sharename == '\0') 496 return (B_FALSE); 497 498 (void) utf8_strlwr(sharename); 499 500 (void) rw_rdlock(&smb_shr_lock); 501 exists = (ht_find_item(smb_shr_handle, sharename) != NULL); 502 (void) rw_unlock(&smb_shr_lock); 503 504 return (exists); 505 } 506 507 /* 508 * smb_shr_is_special 509 * 510 * Special share reserved for interprocess communication (IPC$) or 511 * remote administration of the server (ADMIN$). Can also refer to 512 * administrative shares such as C$, D$, E$, and so forth. 513 */ 514 int 515 smb_shr_is_special(char *sharename) 516 { 517 int len; 518 519 if (sharename == NULL) 520 return (0); 521 522 if ((len = strlen(sharename)) == 0) 523 return (0); 524 525 if (sharename[len - 1] == '$') 526 return (STYPE_SPECIAL); 527 528 return (0); 529 } 530 531 /* 532 * smb_shr_is_restricted 533 * 534 * Check whether or not there is a restriction on a share. Restricted 535 * shares are generally STYPE_SPECIAL, for example, IPC$. All the 536 * administration share names are restricted: C$, D$ etc. Returns B_TRUE 537 * if the share is restricted. Otherwise B_FALSE is returned to indicate 538 * that there are no restrictions. 539 */ 540 boolean_t 541 smb_shr_is_restricted(char *sharename) 542 { 543 static char *restricted[] = { 544 "IPC$" 545 }; 546 547 int i; 548 549 if (sharename == NULL) 550 return (B_FALSE); 551 552 for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) { 553 if (utf8_strcasecmp(restricted[i], sharename) == 0) 554 return (B_TRUE); 555 } 556 557 return (smb_shr_is_admin(sharename)); 558 } 559 560 /* 561 * smb_shr_is_admin 562 * 563 * Check whether or not access to the share should be restricted to 564 * administrators. This is a bit of a hack because what we're doing 565 * is checking for the default admin shares: C$, D$ etc.. There are 566 * other shares that have restrictions: see smb_shr_is_restricted(). 567 * 568 * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE 569 * is returned to indicate that there are no restrictions. 570 */ 571 boolean_t 572 smb_shr_is_admin(char *sharename) 573 { 574 if (sharename == NULL) 575 return (B_FALSE); 576 577 if (strlen(sharename) == 2 && 578 mts_isalpha(sharename[0]) && sharename[1] == '$') { 579 return (B_TRUE); 580 } 581 582 return (B_FALSE); 583 } 584 585 /* 586 * smb_shr_chkname 587 * 588 * Check if any invalid char is present in share name. According to 589 * MSDN article #236388: "Err Msg: The Share Name Contains Invalid 590 * Characters", the list of invalid character is: 591 * 592 * " / \ [ ] : | < > + ; , ? * = 593 * 594 * Also rejects if control characters are embedded. 595 */ 596 boolean_t 597 smb_shr_chkname(char *sharename) 598 { 599 char *invalid = "\"/\\[]:|<>+;,?*="; 600 char *cp; 601 602 if (sharename == NULL) 603 return (B_FALSE); 604 605 if (strpbrk(sharename, invalid)) 606 return (B_FALSE); 607 608 for (cp = sharename; *cp != '\0'; cp++) { 609 if (iscntrl(*cp)) 610 return (B_FALSE); 611 } 612 613 return (B_TRUE); 614 } 615 616 /* 617 * smb_shr_get_realpath 618 * 619 * Derive the real path of a share from the path provided by a 620 * Windows client application during the share addition. 621 * 622 * For instance, the real path of C:\ is /cvol and the 623 * real path of F:\home is /vol1/home. 624 * 625 * clipath - path provided by the Windows client is in the 626 * format of <drive letter>:\<dir> 627 * realpath - path that will be stored as the directory field of 628 * the smb_share_t structure of the share. 629 * maxlen - maximum length fo the realpath buffer 630 * 631 * Return LAN Manager network error code. 632 */ 633 /*ARGSUSED*/ 634 uint32_t 635 smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen) 636 { 637 /* XXX do this translation */ 638 return (NERR_Success); 639 } 640 641 /* 642 * ============================================ 643 * Cache management functions 644 * ============================================ 645 */ 646 647 /* 648 * smb_shr_cache_create 649 * 650 * Create the share hash table. 651 */ 652 static uint32_t 653 smb_shr_cache_create(void) 654 { 655 if (smb_shr_handle == NULL) { 656 (void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0); 657 (void) rw_wrlock(&smb_shr_lock); 658 659 smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ, 660 MAXNAMELEN, 0); 661 if (smb_shr_handle == NULL) { 662 (void) rw_unlock(&smb_shr_lock); 663 return (NERR_InternalError); 664 } 665 666 (void) ht_register_callback(smb_shr_handle, 667 smb_shr_cache_freent); 668 (void) rw_unlock(&smb_shr_lock); 669 } 670 671 return (NERR_Success); 672 } 673 674 /* 675 * smb_shr_cache_destroy 676 * 677 * Destroys the share hash table. 678 */ 679 static void 680 smb_shr_cache_destroy(void) 681 { 682 if (smb_shr_handle) { 683 (void) rw_wrlock(&smb_shr_lock); 684 ht_destroy_table(smb_shr_handle); 685 (void) rw_unlock(&smb_shr_lock); 686 (void) rwlock_destroy(&smb_shr_lock); 687 smb_shr_handle = NULL; 688 } 689 } 690 691 /* 692 * smb_shr_cache_populate 693 * 694 * Load shares from sharemgr 695 */ 696 /*ARGSUSED*/ 697 static void * 698 smb_shr_cache_populate(void *args) 699 { 700 sa_handle_t handle; 701 sa_group_t group, subgroup; 702 char *gstate; 703 boolean_t gdisabled; 704 705 if (smb_shr_cache_create() != NERR_Success) { 706 syslog(LOG_ERR, "share: failed creating the cache"); 707 return (NULL); 708 } 709 710 if (smb_shr_create_ipc() != NERR_Success) { 711 syslog(LOG_ERR, "share: failed creating IPC$"); 712 return (NULL); 713 } 714 715 if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) { 716 syslog(LOG_ERR, "share: failed connecting to backend"); 717 return (NULL); 718 } 719 720 for (group = sa_get_group(handle, NULL); 721 group != NULL; group = sa_get_next_group(group)) { 722 gstate = sa_get_group_attr(group, "state"); 723 if (gstate == NULL) 724 continue; 725 726 gdisabled = (strcasecmp(gstate, "disabled") == 0); 727 sa_free_attr_string(gstate); 728 if (gdisabled) 729 continue; 730 731 smb_shr_cache_loadgrp(group); 732 for (subgroup = sa_get_sub_group(group); 733 subgroup != NULL; 734 subgroup = sa_get_next_group(subgroup)) { 735 smb_shr_cache_loadgrp(subgroup); 736 } 737 738 } 739 740 sa_fini(handle); 741 return (NULL); 742 } 743 744 static uint32_t 745 smb_shr_cache_addent(smb_share_t *si) 746 { 747 smb_share_t *cache_ent; 748 uint32_t status = NERR_Success; 749 750 /* 751 * allocate memory for the entry that needs to be cached. 752 */ 753 if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL) 754 return (ERROR_NOT_ENOUGH_MEMORY); 755 756 bcopy(si, cache_ent, sizeof (smb_share_t)); 757 758 (void) utf8_strlwr(cache_ent->shr_name); 759 smb_shr_set_oemname(cache_ent); 760 if ((si->shr_type & STYPE_IPC) == 0) 761 cache_ent->shr_type = STYPE_DISKTREE; 762 cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name); 763 764 (void) rw_wrlock(&smb_shr_lock); 765 if (ht_add_item(smb_shr_handle, cache_ent->shr_name, cache_ent) 766 == NULL) { 767 syslog(LOG_DEBUG, "share: failed adding %s to cache", 768 cache_ent->shr_name); 769 free(cache_ent); 770 status = NERR_InternalError; 771 } 772 (void) rw_unlock(&smb_shr_lock); 773 774 return (status); 775 } 776 777 static void 778 smb_shr_cache_delent(char *sharename) 779 { 780 (void) utf8_strlwr(sharename); 781 (void) rw_wrlock(&smb_shr_lock); 782 (void) ht_remove_item(smb_shr_handle, sharename); 783 (void) rw_unlock(&smb_shr_lock); 784 } 785 786 static uint32_t 787 smb_shr_cache_chgent(smb_share_t *si) 788 { 789 smb_share_t *cache_ent; 790 uint32_t status = NERR_Success; 791 792 /* 793 * allocate memory for the entry that needs to be cached. 794 */ 795 if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL) 796 return (ERROR_NOT_ENOUGH_MEMORY); 797 798 bcopy(si, cache_ent, sizeof (smb_share_t)); 799 (void) utf8_strlwr(cache_ent->shr_name); 800 801 (void) rw_wrlock(&smb_shr_lock); 802 if (ht_replace_item(smb_shr_handle, cache_ent->shr_name, cache_ent) 803 == NULL) { 804 syslog(LOG_DEBUG, "share: failed modifying %s", 805 cache_ent->shr_name); 806 free(cache_ent); 807 status = NERR_InternalError; 808 } 809 (void) rw_unlock(&smb_shr_lock); 810 811 return (status); 812 } 813 814 static uint32_t 815 smb_shr_create_autohome(smb_share_t *si) 816 { 817 uint32_t status = NERR_Success; 818 int rc; 819 820 if (si->shr_refcnt == 0) { 821 if ((status = smb_shr_cache_addent(si)) != NERR_Success) 822 return (status); 823 824 rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name); 825 826 if (rc != 0) { 827 smb_shr_cache_delent(si->shr_name); 828 return ((rc == ENOENT) 829 ? NERR_UnknownDevDir : NERR_InternalError); 830 } 831 832 smb_shr_publish(si->shr_name, si->shr_container, 833 SMB_SHR_PUBLISH); 834 } 835 836 si->shr_refcnt++; 837 smb_shr_set_ahcnt(si->shr_name, si->shr_refcnt); 838 return (status); 839 } 840 841 static uint32_t 842 smb_shr_create_ipc(void) 843 { 844 smb_share_t ipc; 845 846 bzero(&ipc, sizeof (smb_share_t)); 847 (void) strcpy(ipc.shr_name, "IPC$"); 848 (void) strcpy(ipc.shr_cmnt, "Remote IPC"); 849 ipc.shr_flags = SMB_SHRF_TRANS; 850 ipc.shr_type = STYPE_IPC; 851 return (smb_shr_cache_addent(&ipc)); 852 } 853 854 /* 855 * loads the given resource 856 */ 857 static uint32_t 858 smb_shr_cache_loadent(sa_share_t share, sa_resource_t resource) 859 { 860 smb_share_t si; 861 uint32_t status; 862 863 if ((status = smb_shr_sa_getent(share, resource, &si)) != NERR_Success) 864 return (status); 865 866 if ((status = smb_shr_cache_addent(&si)) == NERR_Success) 867 smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_PUBLISH); 868 869 if (status != NERR_Success) { 870 syslog(LOG_ERR, "share: failed loading %s (%d)", si.shr_name, 871 status); 872 } 873 874 return (status); 875 } 876 877 /* 878 * smb_shr_cache_loadgrp 879 * 880 * Helper function for smb_shr_cache_populate. 881 * It attempts to load the shares contained in the given group. 882 * It will check to see if "smb" protocol is enabled or 883 * not on the given group. This is needed in the ZFS case where 884 * the top level ZFS group won't have "smb" protocol 885 * enabled but the sub-groups will. 886 */ 887 static void 888 smb_shr_cache_loadgrp(sa_group_t group) 889 { 890 sa_share_t share; 891 sa_resource_t resource; 892 893 /* Don't bother if "smb" isn't set on the group */ 894 if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL) 895 return; 896 897 for (share = sa_get_share(group, NULL); 898 share != NULL; share = sa_get_next_share(share)) { 899 for (resource = sa_get_share_resource(share, NULL); 900 resource != NULL; 901 resource = sa_get_next_resource(resource)) { 902 (void) smb_shr_cache_loadent(share, resource); 903 } 904 } 905 } 906 907 /* 908 * smb_shr_cache_freent 909 * 910 * Call back to free given cache entry 911 */ 912 static void 913 smb_shr_cache_freent(HT_ITEM *item) 914 { 915 if (item && item->hi_data) 916 free(item->hi_data); 917 } 918 919 /* 920 * smb_shr_set_ahcnt 921 * 922 * sets the autohome reference count for the given share 923 */ 924 static void 925 smb_shr_set_ahcnt(char *sharename, int refcnt) 926 { 927 smb_share_t *si; 928 HT_ITEM *item; 929 930 (void) rw_wrlock(&smb_shr_lock); 931 item = ht_find_item(smb_shr_handle, sharename); 932 if (item == NULL || item->hi_data == NULL) { 933 (void) rw_unlock(&smb_shr_lock); 934 return; 935 } 936 937 si = (smb_share_t *)item->hi_data; 938 si->shr_refcnt = refcnt; 939 (void) rw_unlock(&smb_shr_lock); 940 } 941 942 /* 943 * smb_shr_set_oemname 944 * 945 * Generates the OEM name of the given share. If it's 946 * shorter than 13 chars it'll be saved in si->shr_oemname. 947 * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME 948 * will be set in si->shr_flags. 949 */ 950 static void 951 smb_shr_set_oemname(smb_share_t *si) 952 { 953 unsigned int cpid = oem_get_smb_cpid(); 954 mts_wchar_t *unibuf; 955 char *oem_name; 956 int length; 957 958 length = strlen(si->shr_name) + 1; 959 960 oem_name = malloc(length); 961 unibuf = malloc(length * sizeof (mts_wchar_t)); 962 if ((oem_name == NULL) || (unibuf == NULL)) { 963 free(oem_name); 964 free(unibuf); 965 return; 966 } 967 968 (void) mts_mbstowcs(unibuf, si->shr_name, length); 969 970 if (unicodestooems(oem_name, unibuf, length, cpid) == 0) 971 (void) strcpy(oem_name, si->shr_name); 972 973 free(unibuf); 974 975 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) { 976 si->shr_flags |= SMB_SHRF_LONGNAME; 977 *si->shr_oemname = '\0'; 978 } else { 979 si->shr_flags &= ~SMB_SHRF_LONGNAME; 980 (void) strlcpy(si->shr_oemname, oem_name, 981 SMB_SHARE_OEMNAME_MAX); 982 } 983 984 free(oem_name); 985 } 986 987 /* 988 * ============================================ 989 * Interfaces to sharemgr 990 * ============================================ 991 */ 992 993 /* 994 * Stores the given share in sharemgr 995 */ 996 static uint32_t 997 smb_shr_sa_addent(smb_share_t *si) 998 { 999 sa_handle_t handle; 1000 sa_share_t share; 1001 sa_group_t group; 1002 sa_resource_t resource; 1003 boolean_t share_created = B_FALSE; 1004 int err; 1005 1006 if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) 1007 return (NERR_InternalError); 1008 1009 share = sa_find_share(handle, si->shr_path); 1010 if (share == NULL) { 1011 group = smb_shr_sa_getdefgrp(handle); 1012 if (group == NULL) { 1013 sa_fini(handle); 1014 return (NERR_InternalError); 1015 } 1016 1017 share = sa_add_share(group, si->shr_path, SA_SHARE_PERMANENT, 1018 &err); 1019 if (share == NULL) { 1020 sa_fini(handle); 1021 return (NERR_InternalError); 1022 } 1023 share_created = B_TRUE; 1024 } 1025 1026 resource = sa_get_share_resource(share, si->shr_name); 1027 if (resource == NULL) { 1028 resource = sa_add_resource(share, si->shr_name, 1029 SA_SHARE_PERMANENT, &err); 1030 if (resource == NULL) 1031 goto failure; 1032 } 1033 1034 if (sa_set_resource_attr(resource, "description", si->shr_cmnt) 1035 != SA_OK) { 1036 goto failure; 1037 } 1038 1039 if (sa_set_resource_attr(resource, SMB_SHROPT_AD_CONTAINER, 1040 si->shr_container) != SA_OK) { 1041 goto failure; 1042 } 1043 1044 sa_fini(handle); 1045 return (NERR_Success); 1046 1047 failure: 1048 if (share_created && (share != NULL)) 1049 (void) sa_remove_share(share); 1050 1051 if (resource != NULL) 1052 (void) sa_remove_resource(resource); 1053 1054 sa_fini(handle); 1055 return (NERR_InternalError); 1056 } 1057 1058 static uint32_t 1059 smb_shr_sa_getent(sa_share_t share, sa_resource_t resource, smb_share_t *si) 1060 { 1061 sa_property_t prop; 1062 sa_optionset_t opts; 1063 char *val = NULL; 1064 char *path; 1065 char *rname; 1066 1067 if ((path = sa_get_share_attr(share, "path")) == NULL) 1068 return (NERR_InternalError); 1069 1070 if ((rname = sa_get_resource_attr(resource, "name")) == NULL) { 1071 sa_free_attr_string(path); 1072 return (NERR_InternalError); 1073 } 1074 1075 bzero(si, sizeof (smb_share_t)); 1076 /* Share is read from SMF so it should be permanent */ 1077 si->shr_flags = SMB_SHRF_PERM; 1078 1079 (void) strlcpy(si->shr_path, path, sizeof (si->shr_path)); 1080 (void) strlcpy(si->shr_name, rname, sizeof (si->shr_name)); 1081 1082 sa_free_attr_string(path); 1083 sa_free_attr_string(rname); 1084 1085 val = sa_get_resource_description(resource); 1086 if (val == NULL) 1087 val = sa_get_share_description(share); 1088 1089 if (val != NULL) { 1090 (void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt)); 1091 sa_free_share_description(val); 1092 } 1093 1094 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 1095 if (opts == NULL) 1096 return (NERR_Success); 1097 1098 prop = (sa_property_t)sa_get_property(opts, SMB_SHROPT_AD_CONTAINER); 1099 if (prop != NULL) { 1100 if ((val = sa_get_property_attr(prop, "value")) != NULL) { 1101 (void) strlcpy(si->shr_container, val, 1102 sizeof (si->shr_container)); 1103 free(val); 1104 } 1105 } 1106 sa_free_derived_optionset(opts); 1107 1108 return (NERR_Success); 1109 } 1110 1111 /* 1112 * Removes the share from sharemgr 1113 */ 1114 static uint32_t 1115 smb_shr_sa_delent(smb_share_t *si) 1116 { 1117 sa_handle_t handle; 1118 sa_share_t share; 1119 sa_resource_t resource; 1120 1121 if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) 1122 return (NERR_InternalError); 1123 1124 if ((share = sa_find_share(handle, si->shr_path)) == NULL) { 1125 sa_fini(handle); 1126 return (NERR_InternalError); 1127 } 1128 1129 if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) { 1130 sa_fini(handle); 1131 return (NERR_InternalError); 1132 } 1133 1134 if (sa_remove_resource(resource) != SA_OK) { 1135 sa_fini(handle); 1136 return (NERR_InternalError); 1137 } 1138 1139 sa_fini(handle); 1140 return (NERR_Success); 1141 } 1142 1143 /* 1144 * smb_shr_sa_getdefgrp 1145 * 1146 * If default group for CIFS shares (i.e. "smb") exists 1147 * then it will return the group handle, otherwise it will 1148 * create the group and return the handle. 1149 * 1150 * All the shares created by CIFS clients (this is only possible 1151 * via RPC) will be added to "smb" groups. 1152 */ 1153 static sa_group_t 1154 smb_shr_sa_getdefgrp(sa_handle_t handle) 1155 { 1156 sa_group_t group = NULL; 1157 int err; 1158 1159 group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP); 1160 if (group != NULL) 1161 return (group); 1162 1163 group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err); 1164 if (group == NULL) 1165 return (NULL); 1166 1167 if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) { 1168 (void) sa_remove_group(group); 1169 group = NULL; 1170 } 1171 1172 return (group); 1173 } 1174 1175 /* 1176 * ============================================ 1177 * Share publishing functions 1178 * ============================================ 1179 */ 1180 1181 /* 1182 * Put the share on publish queue. 1183 */ 1184 static void 1185 smb_shr_publish(const char *sharename, const char *container, char op) 1186 { 1187 smb_shr_pitem_t *item = NULL; 1188 1189 if (container == NULL || *container == '\0') 1190 return; 1191 1192 (void) mutex_lock(&ad_queue.spq_mtx); 1193 switch (ad_queue.spq_state) { 1194 case SMB_SHR_PQS_READY: 1195 case SMB_SHR_PQS_PUBLISHING: 1196 break; 1197 default: 1198 (void) mutex_unlock(&ad_queue.spq_mtx); 1199 return; 1200 } 1201 (void) mutex_unlock(&ad_queue.spq_mtx); 1202 1203 if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL) { 1204 syslog(LOG_DEBUG, "failed allocating share publish item"); 1205 return; 1206 } 1207 1208 item->spi_op = op; 1209 (void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name)); 1210 (void) strlcpy(item->spi_container, container, 1211 sizeof (item->spi_container)); 1212 1213 (void) mutex_lock(&ad_queue.spq_mtx); 1214 list_insert_tail(&ad_queue.spq_list, item); 1215 ad_queue.spq_cnt++; 1216 (void) cond_signal(&ad_queue.spq_cv); 1217 (void) mutex_unlock(&ad_queue.spq_mtx); 1218 } 1219 1220 static int 1221 smb_shr_publisher_start(void) 1222 { 1223 pthread_attr_t tattr; 1224 int rc; 1225 1226 (void) mutex_lock(&ad_queue.spq_mtx); 1227 if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) { 1228 (void) mutex_unlock(&ad_queue.spq_mtx); 1229 errno = EINVAL; 1230 return (-1); 1231 } 1232 1233 list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t), 1234 offsetof(smb_shr_pitem_t, spi_lnd)); 1235 ad_queue.spq_state = SMB_SHR_PQS_READY; 1236 (void) mutex_unlock(&ad_queue.spq_mtx); 1237 1238 (void) pthread_attr_init(&tattr); 1239 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 1240 rc = pthread_create(&smb_shr_publish_thr, &tattr, 1241 smb_shr_publisher, 0); 1242 (void) pthread_attr_destroy(&tattr); 1243 1244 return (rc); 1245 } 1246 1247 static void 1248 smb_shr_publisher_stop(void) 1249 { 1250 (void) mutex_lock(&ad_queue.spq_mtx); 1251 switch (ad_queue.spq_state) { 1252 case SMB_SHR_PQS_READY: 1253 case SMB_SHR_PQS_PUBLISHING: 1254 ad_queue.spq_state = SMB_SHR_PQS_STOPPING; 1255 (void) cond_signal(&ad_queue.spq_cv); 1256 break; 1257 default: 1258 break; 1259 } 1260 (void) mutex_unlock(&ad_queue.spq_mtx); 1261 } 1262 1263 /* 1264 * This functions waits to be signaled and once running 1265 * will publish/unpublish any items in the ad_queue 1266 */ 1267 /*ARGSUSED*/ 1268 static void * 1269 smb_shr_publisher(void *arg) 1270 { 1271 smb_ads_handle_t *ah; 1272 smb_shr_pitem_t *shr; 1273 list_t publist; 1274 char hostname[MAXHOSTNAMELEN]; 1275 1276 (void) mutex_lock(&ad_queue.spq_mtx); 1277 if (ad_queue.spq_state == SMB_SHR_PQS_READY) { 1278 ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING; 1279 } else { 1280 (void) mutex_unlock(&ad_queue.spq_mtx); 1281 return (NULL); 1282 } 1283 (void) mutex_unlock(&ad_queue.spq_mtx); 1284 1285 (void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0); 1286 list_create(&publist, sizeof (smb_shr_pitem_t), 1287 offsetof(smb_shr_pitem_t, spi_lnd)); 1288 1289 for (;;) { 1290 (void) mutex_lock(&ad_queue.spq_mtx); 1291 while ((ad_queue.spq_cnt == 0) && 1292 (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) 1293 (void) cond_wait(&ad_queue.spq_cv, &ad_queue.spq_mtx); 1294 1295 if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) { 1296 (void) mutex_unlock(&ad_queue.spq_mtx); 1297 break; 1298 } 1299 1300 if ((ah = smb_ads_open()) == NULL) { 1301 (void) mutex_unlock(&ad_queue.spq_mtx); 1302 continue; 1303 } 1304 1305 /* 1306 * Transfer queued items to the local list so the mutex 1307 * can be quickly released 1308 */ 1309 while ((shr = list_head(&ad_queue.spq_list)) != NULL) { 1310 list_remove(&ad_queue.spq_list, shr); 1311 ad_queue.spq_cnt--; 1312 list_insert_tail(&publist, shr); 1313 } 1314 (void) mutex_unlock(&ad_queue.spq_mtx); 1315 1316 smb_shr_publisher_send(ah, &publist, hostname); 1317 smb_ads_close(ah); 1318 } 1319 1320 /* Remove any leftover items from publishing queue */ 1321 (void) mutex_lock(&ad_queue.spq_mtx); 1322 while ((shr = list_head(&ad_queue.spq_list)) != NULL) { 1323 list_remove(&ad_queue.spq_list, shr); 1324 free(shr); 1325 } 1326 ad_queue.spq_cnt = 0; 1327 list_destroy(&ad_queue.spq_list); 1328 ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE; 1329 (void) mutex_unlock(&ad_queue.spq_mtx); 1330 1331 list_destroy(&publist); 1332 return (NULL); 1333 } 1334 1335 /* 1336 * Takes item from the given list and [un]publish them one by one. 1337 * In each iteration it checks the status of the publisher thread 1338 * and if it's been stopped then it continues to just empty the list 1339 */ 1340 static void 1341 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host) 1342 { 1343 smb_shr_pitem_t *shr; 1344 boolean_t publish = B_TRUE; 1345 1346 while ((shr = list_head(publist)) != NULL) { 1347 list_remove(publist, shr); 1348 if (publish) { 1349 (void) mutex_unlock(&ad_queue.spq_mtx); 1350 if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) 1351 publish = B_FALSE; 1352 (void) mutex_unlock(&ad_queue.spq_mtx); 1353 1354 if (shr->spi_op == SMB_SHR_PUBLISH) 1355 (void) smb_ads_publish_share(ah, shr->spi_name, 1356 NULL, shr->spi_container, host); 1357 else 1358 (void) smb_ads_remove_share(ah, shr->spi_name, 1359 NULL, shr->spi_container, host); 1360 } 1361 free(shr); 1362 } 1363 } 1364