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