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 "%Z%%M% %I% %E% 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 <sys/mnttab.h> 46 #include <sys/stat.h> 47 #include <sys/types.h> 48 #include <sys/queue.h> 49 #include <ctype.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/smb_fsd.h> 63 64 #define SMB_SHARE_HTAB_SZ 1024 65 66 #define SMB_SHARE_PUBLISH 0 67 #define SMB_SHARE_UNPUBLISH 1 68 69 static HT_HANDLE *smb_shr_handle = NULL; 70 static rwlock_t smb_shr_lock; 71 static pthread_t smb_shr_cache_populatethr; 72 73 static uint32_t smb_shr_cache_create(void); 74 static void *smb_shr_cache_populate(void *); 75 static int smb_shr_del_shmgr(smb_share_t *); 76 static int smb_shr_set_shmgr(smb_share_t *); 77 static uint32_t smb_shr_set_refcnt(char *, int); 78 static void smb_shr_set_oemname(smb_share_t *); 79 80 typedef struct smb_shr_adinfo { 81 TAILQ_ENTRY(smb_shr_adinfo) next; 82 char name[MAXNAMELEN]; 83 char container[MAXPATHLEN]; 84 char flag; 85 } smb_shr_adinfo_t; 86 87 typedef struct smb_shr_adqueue { 88 int nentries; 89 TAILQ_HEAD(adqueue, smb_shr_adinfo) adlist; 90 } smb_shr_adqueue_t; 91 92 static smb_shr_adqueue_t ad_queue; 93 static int publish_on = 0; 94 95 static pthread_t smb_shr_publish_thr; 96 static mutex_t smb_shr_publish_mtx = PTHREAD_MUTEX_INITIALIZER; 97 static cond_t smb_shr_publish_cv = DEFAULTCV; 98 99 static void *smb_shr_publisher(void *); 100 static void smb_shr_stop_publish(void); 101 static void smb_shr_publish(smb_share_t *, char, int); 102 103 /* 104 * Start loading lmshare information from sharemanager 105 * and create the cache. 106 */ 107 int 108 smb_shr_start(void) 109 { 110 int rc; 111 112 rc = pthread_create(&smb_shr_publish_thr, NULL, 113 smb_shr_publisher, 0); 114 if (rc != 0) { 115 syslog(LOG_ERR, "Failed to start publisher thread, " 116 "share publishing is disabled"); 117 } 118 119 rc = pthread_create(&smb_shr_cache_populatethr, NULL, 120 smb_shr_cache_populate, 0); 121 if (rc != 0) { 122 syslog(LOG_ERR, "Failed to start share loading, " 123 "existing shares will not be available"); 124 } 125 126 return (rc); 127 } 128 129 void 130 smb_shr_stop(void) 131 { 132 smb_shr_stop_publish(); 133 } 134 135 /* 136 * lmshare_load_shares 137 * 138 * Helper function for smb_shr_cache_populate. It attempts to load the shares 139 * contained in the group. 140 */ 141 142 static void 143 lmshare_load_shares(sa_group_t group) 144 { 145 sa_share_t share; 146 sa_resource_t resource; 147 smb_share_t si; 148 char *path, *rname; 149 150 /* Don't bother if "smb" isn't set on the group */ 151 if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL) 152 return; 153 154 for (share = sa_get_share(group, NULL); 155 share != NULL; share = sa_get_next_share(share)) { 156 path = sa_get_share_attr(share, "path"); 157 if (path == NULL) { 158 continue; 159 } 160 for (resource = sa_get_share_resource(share, NULL); 161 resource != NULL; 162 resource = sa_get_next_resource(resource)) { 163 rname = sa_get_resource_attr(resource, "name"); 164 if (rname == NULL) { 165 syslog(LOG_ERR, "Invalid share " 166 "resource for path: %s", path); 167 continue; 168 } 169 smb_build_lmshare_info(rname, path, resource, &si); 170 sa_free_attr_string(rname); 171 if (smb_shr_add(&si, 0) != NERR_Success) { 172 syslog(LOG_ERR, "Failed to load " 173 "share %s", si.shr_name); 174 } 175 } 176 /* We are done with all shares for same path */ 177 sa_free_attr_string(path); 178 } 179 } 180 181 /* 182 * smb_shr_cache_populate 183 * 184 * Load shares from sharemanager. The args argument is currently not 185 * used. The function walks through all the groups in libshare and 186 * calls lmshare_load_shares for each group found. It also looks for 187 * sub-groups and calls lmshare_load_shares for each sub-group found. 188 */ 189 190 /*ARGSUSED*/ 191 static void * 192 smb_shr_cache_populate(void *args) 193 { 194 sa_handle_t handle; 195 sa_group_t group, subgroup; 196 char *gstate; 197 198 if (smb_shr_cache_create() != NERR_Success) { 199 syslog(LOG_ERR, "Failed to create share hash table"); 200 return (NULL); 201 } 202 203 handle = sa_init(SA_INIT_SHARE_API); 204 if (handle == NULL) { 205 syslog(LOG_ERR, "Failed to load share " 206 "information: no libshare handle"); 207 return (NULL); 208 } 209 210 for (group = sa_get_group(handle, NULL); 211 group != NULL; group = sa_get_next_group(group)) { 212 gstate = sa_get_group_attr(group, "state"); 213 if (gstate == NULL) 214 continue; 215 if (strcasecmp(gstate, "disabled") == 0) { 216 /* Skip disabled or unknown state group */ 217 sa_free_attr_string(gstate); 218 continue; 219 } 220 sa_free_attr_string(gstate); 221 222 /* 223 * Attempt to load the shares. lmshare_load_shares 224 * will check to see if the protocol is enabled or 225 * not. We then want to check for any sub-groups on 226 * this group. This is needed in the ZFS case where 227 * the top level ZFS group won't have "smb" protocol 228 * enabled but the sub-groups will. 229 */ 230 lmshare_load_shares(group); 231 for (subgroup = sa_get_sub_group(group); 232 subgroup != NULL; 233 subgroup = sa_get_next_group(subgroup)) { 234 lmshare_load_shares(subgroup); 235 } 236 237 } 238 239 sa_fini(handle); 240 241 return (NULL); 242 } 243 244 /* 245 * lmshare_callback 246 * 247 * Call back to free share structures stored 248 * in shares' hash table. 249 */ 250 static void 251 lmshare_callback(HT_ITEM *item) 252 { 253 if (item && item->hi_data) 254 free(item->hi_data); 255 } 256 257 /* 258 * smb_shr_cache_create 259 * 260 * Create the share hash table. 261 */ 262 static uint32_t 263 smb_shr_cache_create(void) 264 { 265 if (smb_shr_handle == NULL) { 266 (void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0); 267 (void) rw_wrlock(&smb_shr_lock); 268 269 smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ, 270 MAXNAMELEN, 0); 271 if (smb_shr_handle == NULL) { 272 syslog(LOG_ERR, "smb_shr_cache_create:" 273 " unable to create share table"); 274 (void) rw_unlock(&smb_shr_lock); 275 return (NERR_InternalError); 276 } 277 (void) ht_register_callback(smb_shr_handle, lmshare_callback); 278 (void) rw_unlock(&smb_shr_lock); 279 } 280 281 return (NERR_Success); 282 } 283 284 /* 285 * smb_shr_add_adminshare 286 * 287 * add the admin share for the volume when the share database 288 * for that volume is going to be loaded. 289 */ 290 uint32_t 291 smb_shr_add_adminshare(char *volname, unsigned char drive) 292 { 293 smb_share_t si; 294 uint32_t rc; 295 296 if (drive == 0) 297 return (NERR_InvalidDevice); 298 299 bzero(&si, sizeof (smb_share_t)); 300 (void) strcpy(si.shr_path, volname); 301 si.shr_flags = SMB_SHRF_TRANS | SMB_SHRF_ADMIN; 302 (void) snprintf(si.shr_name, sizeof (si.shr_name), "%c$", drive); 303 rc = smb_shr_add(&si, 0); 304 305 return (rc); 306 } 307 308 /* 309 * smb_shr_count 310 * 311 * Return the total number of shares, which should be the same value 312 * that would be returned from a share enum request. 313 */ 314 int 315 smb_shr_count(void) 316 { 317 int n_shares; 318 319 n_shares = ht_get_total_items(smb_shr_handle); 320 321 /* If we don't store IPC$ in hash table we should do this */ 322 n_shares++; 323 324 return (n_shares); 325 } 326 327 /* 328 * smb_shr_iterinit 329 * 330 * Initialize an iterator for traversing hash table. 331 * 'mode' is used for filtering shares when iterating. 332 */ 333 void 334 smb_shr_iterinit(smb_shriter_t *shi, uint32_t mode) 335 { 336 bzero(shi, sizeof (smb_shriter_t)); 337 shi->si_mode = mode; 338 } 339 340 /* 341 * smb_shr_iterate 342 * 343 * Iterate on the shares in the hash table. The iterator must be initialized 344 * before the first iteration. On subsequent calls, the iterator must be 345 * passed unchanged. 346 * 347 * Returns NULL on failure or when all shares are visited, otherwise 348 * returns information of visited share. 349 * 350 * Note that there are some special shares, i.e. IPC$, that must also 351 * be processed. 352 */ 353 smb_share_t * 354 smb_shr_iterate(smb_shriter_t *shi) 355 { 356 HT_ITEM *item; 357 smb_share_t *si; 358 359 if (smb_shr_handle == NULL || shi == NULL) 360 return (NULL); 361 362 if (shi->si_counter == 0) { 363 /* 364 * IPC$ is always first. 365 */ 366 (void) strcpy(shi->si_share.shr_name, "IPC$"); 367 smb_shr_set_oemname(&shi->si_share); 368 shi->si_share.shr_flags = SMB_SHRF_TRANS; 369 shi->si_share.shr_type = (int)(STYPE_IPC | STYPE_SPECIAL); 370 shi->si_counter = 1; 371 return (&(shi->si_share)); 372 } 373 374 if (shi->si_counter == 1) { 375 if ((item = ht_findfirst( 376 smb_shr_handle, &shi->si_hashiter)) == NULL) { 377 return (NULL); 378 } 379 380 si = (smb_share_t *)(item->hi_data); 381 ++shi->si_counter; 382 383 if (si->shr_flags & shi->si_mode) { 384 bcopy(si, &(shi->si_share), sizeof (smb_share_t)); 385 return (&(shi->si_share)); 386 } 387 } 388 389 while ((item = ht_findnext(&shi->si_hashiter)) != NULL) { 390 si = (smb_share_t *)(item->hi_data); 391 ++shi->si_counter; 392 if (si->shr_flags & shi->si_mode) { 393 bcopy(si, &(shi->si_share), sizeof (smb_share_t)); 394 return (&(shi->si_share)); 395 } 396 } 397 398 return (NULL); 399 } 400 401 /* 402 * smb_shr_add 403 * 404 * Add a share. This is a wrapper round smb_shr_set that checks 405 * whether or not the share already exists. If the share exists, an 406 * error is returned. 407 * 408 * Don't check smb_shr_is_dir here: it causes rootfs to recurse. 409 */ 410 uint32_t 411 smb_shr_add(smb_share_t *si, int doshm) 412 { 413 uint32_t status = NERR_Success; 414 415 if (si == 0 || smb_shr_is_valid(si->shr_name) == 0) 416 return (NERR_InvalidDevice); 417 418 (void) utf8_strlwr(si->shr_name); 419 420 if (smb_shr_exists(si->shr_name)) { 421 /* 422 * Only autohome shares can be added multiple times 423 */ 424 if ((si->shr_flags & SMB_SHRF_AUTOHOME) == 0) 425 return (NERR_DuplicateShare); 426 } 427 428 if (si->shr_refcnt == 0) { 429 status = smb_shr_set(si, doshm); 430 smb_shr_publish(si, SMB_SHARE_PUBLISH, 1); 431 } 432 433 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && (status == NERR_Success)) { 434 si->shr_refcnt++; 435 status = smb_shr_set_refcnt(si->shr_name, si->shr_refcnt); 436 } 437 438 if (status) 439 return (status); 440 441 return (smb_dwncall_share(SMB_SHROP_ADD, si->shr_path, si->shr_name)); 442 } 443 444 /* 445 * smb_shr_del 446 * 447 * Remove a share. Ensure that all SMB trees associated with this share 448 * are disconnected. If the share does not exist, an error is returned. 449 */ 450 uint32_t 451 smb_shr_del(char *share_name, int doshm) 452 { 453 smb_share_t *si; 454 HT_ITEM *item; 455 uint32_t status; 456 char path[MAXPATHLEN]; 457 458 if (share_name) 459 (void) utf8_strlwr(share_name); 460 461 if (smb_shr_is_valid(share_name) == 0 || 462 smb_shr_exists(share_name) == 0) { 463 return (NERR_NetNameNotFound); 464 } 465 466 (void) rw_wrlock(&smb_shr_lock); 467 item = ht_find_item(smb_shr_handle, share_name); 468 469 if (item == NULL) { 470 (void) rw_unlock(&smb_shr_lock); 471 return (NERR_ItemNotFound); 472 } 473 474 si = (smb_share_t *)item->hi_data; 475 if (si == NULL) { 476 (void) rw_unlock(&smb_shr_lock); 477 return (NERR_InternalError); 478 } 479 480 if ((si->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) { 481 si->shr_refcnt--; 482 if (si->shr_refcnt > 0) { 483 status = smb_shr_set_refcnt(si->shr_name, 484 si->shr_refcnt); 485 (void) rw_unlock(&smb_shr_lock); 486 return (status); 487 } 488 } 489 490 if (doshm && (smb_shr_del_shmgr(si) != 0)) { 491 (void) rw_unlock(&smb_shr_lock); 492 return (NERR_InternalError); 493 } 494 495 smb_shr_publish(si, SMB_SHARE_UNPUBLISH, 1); 496 497 /* 498 * Copy the path before the entry is removed from the hash table 499 */ 500 501 (void) strlcpy(path, si->shr_path, MAXPATHLEN); 502 503 /* Delete from hash table */ 504 505 (void) ht_remove_item(smb_shr_handle, share_name); 506 (void) rw_unlock(&smb_shr_lock); 507 508 return (smb_dwncall_share(SMB_SHROP_DELETE, path, share_name)); 509 } 510 511 /* 512 * smb_shr_set_refcnt 513 * 514 * sets the autohome shr_refcnt for a share 515 */ 516 static uint32_t 517 smb_shr_set_refcnt(char *share_name, int refcnt) 518 { 519 smb_share_t *si; 520 HT_ITEM *item; 521 522 if (share_name) { 523 (void) utf8_strlwr(share_name); 524 } 525 (void) rw_wrlock(&smb_shr_lock); 526 item = ht_find_item(smb_shr_handle, share_name); 527 if (item == NULL) { 528 (void) rw_unlock(&smb_shr_lock); 529 return (NERR_ItemNotFound); 530 } 531 532 si = (smb_share_t *)item->hi_data; 533 if (si == NULL) { 534 (void) rw_unlock(&smb_shr_lock); 535 return (NERR_InternalError); 536 } 537 si->shr_refcnt = refcnt; 538 (void) rw_unlock(&smb_shr_lock); 539 return (NERR_Success); 540 } 541 542 /* 543 * smb_shr_ren 544 * 545 * Rename a share. Check that the current name exists and the new name 546 * doesn't exist. The rename is performed by deleting the current share 547 * definition and creating a new share with the new name. 548 */ 549 uint32_t 550 smb_shr_ren(char *from_name, char *to_name, int doshm) 551 { 552 smb_share_t si; 553 uint32_t nerr; 554 555 if (smb_shr_is_valid(from_name) == 0 || 556 smb_shr_is_valid(to_name) == 0) 557 return (NERR_InvalidDevice); 558 559 (void) utf8_strlwr(from_name); 560 (void) utf8_strlwr(to_name); 561 562 if (smb_shr_exists(from_name) == 0) 563 return (NERR_NetNameNotFound); 564 565 if (smb_shr_exists(to_name)) 566 return (NERR_DuplicateShare); 567 568 if ((nerr = smb_shr_get(from_name, &si)) != NERR_Success) 569 return (nerr); 570 571 if ((nerr = smb_shr_del(from_name, doshm)) != NERR_Success) 572 return (nerr); 573 574 (void) strlcpy(si.shr_name, to_name, MAXNAMELEN); 575 return (smb_shr_add(&si, 1)); 576 } 577 578 /* 579 * smb_shr_exists 580 * 581 * Returns 1 if the share exists. Otherwise returns 0. 582 */ 583 int 584 smb_shr_exists(char *share_name) 585 { 586 if (share_name == 0 || *share_name == 0) 587 return (0); 588 589 if (ht_find_item(smb_shr_handle, share_name) == NULL) 590 return (0); 591 else 592 return (1); 593 } 594 595 /* 596 * smb_shr_is_special 597 * 598 * Simple check to determine if share name represents a special share, 599 * i.e. the last character of the name is a '$'. Returns STYPE_SPECIAL 600 * if the name is special. Otherwise returns 0. 601 */ 602 int 603 smb_shr_is_special(char *share_name) 604 { 605 int len; 606 607 if (share_name == 0) 608 return (0); 609 610 if ((len = strlen(share_name)) == 0) 611 return (0); 612 613 if (share_name[len - 1] == '$') 614 return (STYPE_SPECIAL); 615 else 616 return (0); 617 } 618 619 620 /* 621 * smb_shr_is_restricted 622 * 623 * Check whether or not there is a restriction on a share. Restricted 624 * shares are generally STYPE_SPECIAL, for example, IPC$. All the 625 * administration share names are restricted: C$, D$ etc. Returns 1 626 * if the share is restricted. Otherwise 0 is returned to indicate 627 * that there are no restrictions. 628 */ 629 int 630 smb_shr_is_restricted(char *share_name) 631 { 632 static char *restricted[] = { 633 "IPC$" 634 }; 635 636 int i; 637 638 for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) { 639 if (strcasecmp(restricted[i], share_name) == 0) 640 return (1); 641 } 642 643 if (smb_shr_is_admin(share_name)) 644 return (1); 645 646 return (0); 647 } 648 649 650 /* 651 * smb_shr_is_admin 652 * 653 * Check whether or not access to the share should be restricted to 654 * administrators. This is a bit of a hack because what we're doing 655 * is checking for the default admin shares: C$, D$ etc.. There are 656 * other shares that have restrictions: see smb_shr_is_restricted(). 657 * 658 * Returns 1 if the shares is an admin share. Otherwise 0 is returned 659 * to indicate that there are no restrictions. 660 */ 661 int 662 smb_shr_is_admin(char *share_name) 663 { 664 if (share_name == 0) 665 return (0); 666 667 if (strlen(share_name) == 2 && 668 mts_isalpha(share_name[0]) && share_name[1] == '$') { 669 return (1); 670 } 671 672 return (0); 673 } 674 675 676 /* 677 * smb_shr_is_valid 678 * 679 * Check if any invalid char is present in share name. According to 680 * MSDN article #236388: "Err Msg: The Share Name Contains Invalid 681 * Characters", the list of invalid character is: 682 * 683 * " / \ [ ] : | < > + ; , ? * = 684 * 685 * Also rejects if control characters are embedded. 686 * 687 * If the sharename is valid, return (1). Otherwise return (0). 688 */ 689 int 690 smb_shr_is_valid(char *share_name) 691 { 692 char *invalid = "\"/\\[]:|<>+;,?*="; 693 char *cp; 694 695 if (share_name == 0) 696 return (0); 697 698 if (strpbrk(share_name, invalid)) 699 return (0); 700 701 for (cp = share_name; *cp != '\0'; cp++) 702 if (iscntrl(*cp)) 703 return (0); 704 705 return (1); 706 } 707 708 /* 709 * smb_shr_is_dir 710 * 711 * Check to determine if a share object represents a directory. 712 * 713 * Returns 1 if the path leads to a directory. Otherwise returns 0. 714 */ 715 int 716 smb_shr_is_dir(char *path) 717 { 718 struct stat stat_info; 719 720 if (stat(path, &stat_info) == 0) 721 if (S_ISDIR(stat_info.st_mode)) 722 return (1); 723 724 return (0); 725 726 } 727 728 /* 729 * smb_shr_get 730 * 731 * Load the information for the specified share into the supplied share 732 * info structure. If the shared directory does not begin with a /, one 733 * will be inserted as a prefix. 734 */ 735 uint32_t 736 smb_shr_get(char *share_name, smb_share_t *si) 737 { 738 int i, endidx; 739 int dirlen; 740 HT_ITEM *item; 741 742 (void) rw_rdlock(&smb_shr_lock); 743 744 (void) utf8_strlwr(share_name); 745 if ((item = ht_find_item(smb_shr_handle, share_name)) == NULL) { 746 bzero(si, sizeof (smb_share_t)); 747 (void) rw_unlock(&smb_shr_lock); 748 return (NERR_NetNameNotFound); 749 } 750 751 (void) memcpy(si, item->hi_data, sizeof (smb_share_t)); 752 (void) rw_unlock(&smb_shr_lock); 753 754 if (si->shr_path[0] == '\0') 755 return (NERR_NetNameNotFound); 756 757 if (si->shr_path[0] != '/') { 758 dirlen = strlen(si->shr_path) + 1; 759 endidx = (dirlen < MAXPATHLEN-1) ? 760 dirlen : MAXPATHLEN - 2; 761 for (i = endidx; i >= 0; i--) 762 si->shr_path[i+1] = si->shr_path[i]; 763 si->shr_path[MAXPATHLEN-1] = '\0'; 764 si->shr_path[0] = '/'; 765 } 766 767 return (NERR_Success); 768 } 769 770 /* 771 * Remove share from sharemanager repository. 772 */ 773 static int 774 smb_shr_del_shmgr(smb_share_t *si) 775 { 776 sa_handle_t handle; 777 sa_share_t share; 778 sa_resource_t resource; 779 780 handle = sa_init(SA_INIT_SHARE_API); 781 if (handle == NULL) { 782 syslog(LOG_ERR, "Failed to get handle to " 783 "share lib"); 784 return (1); 785 } 786 share = sa_find_share(handle, si->shr_path); 787 if (share == NULL) { 788 syslog(LOG_ERR, "Failed to get share to delete"); 789 sa_fini(handle); 790 return (1); 791 } 792 resource = sa_get_share_resource(share, si->shr_name); 793 if (resource == NULL) { 794 syslog(LOG_ERR, "Failed to get share resource to delete"); 795 sa_fini(handle); 796 return (1); 797 } 798 if (sa_remove_resource(resource) != SA_OK) { 799 syslog(LOG_ERR, "Failed to remove resource"); 800 sa_fini(handle); 801 return (1); 802 } 803 sa_fini(handle); 804 return (0); 805 } 806 807 static int 808 smb_shr_set_shmgr(smb_share_t *si) 809 { 810 sa_handle_t handle; 811 sa_share_t share; 812 sa_group_t group; 813 sa_resource_t resource; 814 int share_created = 0; 815 int err; 816 817 /* Add share to sharemanager */ 818 handle = sa_init(SA_INIT_SHARE_API); 819 if (handle == NULL) { 820 syslog(LOG_ERR, "Failed to get handle to share lib"); 821 return (1); 822 } 823 share = sa_find_share(handle, si->shr_path); 824 if (share == NULL) { 825 group = smb_get_smb_share_group(handle); 826 if (group == NULL) { 827 sa_fini(handle); 828 return (1); 829 } 830 share = sa_add_share(group, si->shr_path, 0, &err); 831 if (share == NULL) { 832 sa_fini(handle); 833 return (1); 834 } 835 share_created = 1; 836 } 837 resource = sa_get_share_resource(share, si->shr_name); 838 if (resource == NULL) { 839 resource = sa_add_resource(share, si->shr_name, 840 SA_SHARE_PERMANENT, &err); 841 if (resource == NULL) { 842 goto failure; 843 } 844 } 845 if (sa_set_resource_attr(resource, 846 "description", si->shr_cmnt) != SA_OK) { 847 syslog(LOG_ERR, "Falied to set resource " 848 "description in sharemgr"); 849 goto failure; 850 } 851 if (sa_set_resource_attr(resource, 852 SMB_SHROPT_AD_CONTAINER, si->shr_container) != SA_OK) { 853 syslog(LOG_ERR, "Falied to set ad-container in sharemgr"); 854 goto failure; 855 } 856 857 sa_fini(handle); 858 return (0); 859 failure: 860 if (share_created && (share != NULL)) { 861 if (sa_remove_share(share) != SA_OK) { 862 syslog(LOG_ERR, "Failed to cleanup share"); 863 } 864 } 865 if (resource != NULL) { 866 if (sa_remove_resource(resource) != SA_OK) { 867 syslog(LOG_ERR, "Failed to cleanup share resource"); 868 } 869 } 870 sa_fini(handle); 871 return (1); 872 } 873 874 /* 875 * smb_shr_cache_delshare 876 * 877 * Delete the given share only from hash table 878 */ 879 static uint32_t 880 smb_shr_cache_delshare(char *share_name) 881 { 882 if (share_name == 0) 883 return (NERR_NetNameNotFound); 884 885 (void) utf8_strlwr(share_name); 886 887 if (smb_shr_is_valid(share_name) == 0 || 888 smb_shr_exists(share_name) == 0) { 889 return (NERR_NetNameNotFound); 890 } 891 892 (void) rw_wrlock(&smb_shr_lock); 893 (void) ht_remove_item(smb_shr_handle, share_name); 894 (void) rw_unlock(&smb_shr_lock); 895 896 return (NERR_Success); 897 } 898 899 /* 900 * smb_shr_set 901 * 902 * Adds the specified share into the system hash table 903 * and also store its info in the corresponding disk 904 * structure if it is not a temporary (SMB_SHRF_TRANS) share. 905 * when the first share is going to be added, create shares 906 * hash table if it is not already created. 907 * If the share already exists, it will be replaced. If the 908 * new share directory name does not begin with a /, one will be 909 * inserted as a prefix. 910 */ 911 uint32_t 912 smb_shr_set(smb_share_t *si, int doshm) 913 { 914 int i, endidx; 915 int dirlen; 916 smb_share_t *add_si; 917 int res = NERR_Success; 918 smb_share_t old_si; 919 920 if (si->shr_path[0] != '/') { 921 dirlen = strlen(si->shr_path) + 1; 922 endidx = (dirlen < MAXPATHLEN - 1) ? 923 dirlen : MAXPATHLEN - 2; 924 for (i = endidx; i >= 0; i--) 925 si->shr_path[i+1] = si->shr_path[i]; 926 si->shr_path[MAXPATHLEN-1] = '\0'; 927 si->shr_path[0] = '/'; 928 } 929 930 /* XXX Do we need to translate the directory here? to real path */ 931 if (smb_shr_is_dir(si->shr_path) == 0) 932 return (NERR_UnknownDevDir); 933 934 /* 935 * We should allocate memory for new entry because we 936 * don't know anything about the passed pointer i.e. 937 * it maybe destroyed by caller of this function while 938 * we only store a pointer to the data in hash table. 939 * Hash table doesn't do any allocation for the data that 940 * is being added. 941 */ 942 add_si = malloc(sizeof (smb_share_t)); 943 if (add_si == NULL) { 944 syslog(LOG_ERR, "LmshareSetinfo: resource shortage"); 945 return (NERR_NoRoom); 946 } 947 948 (void) memcpy(add_si, si, sizeof (smb_share_t)); 949 950 /* 951 * If we can't find it, use the new one to get things in sync, 952 * but if there is an existing one, that is the one to 953 * unpublish. 954 */ 955 if (smb_shr_get(si->shr_name, &old_si) != NERR_Success) 956 (void) memcpy(&old_si, si, sizeof (smb_share_t)); 957 958 if (doshm) { 959 res = smb_shr_del(si->shr_name, doshm); 960 if (res != NERR_Success) { 961 free(add_si); 962 syslog(LOG_ERR, "LmshareSetinfo: delete failed", res); 963 return (res); 964 } 965 } else { 966 /* Unpublish old share from AD */ 967 if ((add_si->shr_flags & SMB_SHRF_PERM) == SMB_SHRF_PERM) 968 smb_shr_publish(&old_si, SMB_SHARE_UNPUBLISH, 1); 969 (void) smb_shr_cache_delshare(si->shr_name); 970 } 971 972 smb_shr_set_oemname(add_si); 973 974 /* if it's not transient it should be permanent */ 975 if ((add_si->shr_flags & SMB_SHRF_TRANS) == 0) 976 add_si->shr_flags |= SMB_SHRF_PERM; 977 978 979 add_si->shr_type = STYPE_DISKTREE; 980 add_si->shr_type |= smb_shr_is_special(add_si->shr_name); 981 982 (void) rw_wrlock(&smb_shr_lock); 983 if (ht_add_item(smb_shr_handle, add_si->shr_name, add_si) == NULL) { 984 syslog(LOG_ERR, "smb_shr_set[%s]: error in adding share", 985 add_si->shr_name); 986 (void) rw_unlock(&smb_shr_lock); 987 free(add_si); 988 return (NERR_InternalError); 989 } 990 (void) rw_unlock(&smb_shr_lock); 991 992 if ((add_si->shr_flags & SMB_SHRF_PERM) == SMB_SHRF_PERM) { 993 if (doshm && (smb_shr_set_shmgr(add_si) != 0)) { 994 syslog(LOG_ERR, "Update share %s in sharemgr failed", 995 add_si->shr_name); 996 return (NERR_InternalError); 997 } 998 smb_shr_publish(add_si, SMB_SHARE_PUBLISH, 1); 999 } 1000 1001 return (res); 1002 } 1003 1004 void 1005 smb_shr_list(int offset, smb_shrlist_t *list) 1006 { 1007 smb_shriter_t iterator; 1008 smb_share_t *si; 1009 int list_idx = 0; 1010 int i = 0; 1011 1012 bzero(list, sizeof (smb_shrlist_t)); 1013 smb_shr_iterinit(&iterator, SMB_SHRF_ALL); 1014 1015 (void) smb_shr_iterate(&iterator); /* To skip IPC$ */ 1016 1017 while ((si = smb_shr_iterate(&iterator)) != NULL) { 1018 if (smb_shr_is_special(si->shr_name)) { 1019 /* 1020 * Don't return restricted shares. 1021 */ 1022 if (smb_shr_is_restricted(si->shr_name)) 1023 continue; 1024 } 1025 1026 if (i++ < offset) 1027 continue; 1028 1029 (void) memcpy(&list->smbshr[list_idx], si, 1030 sizeof (smb_share_t)); 1031 if (++list_idx == LMSHARES_PER_REQUEST) 1032 break; 1033 } 1034 1035 list->no = list_idx; 1036 } 1037 1038 /* 1039 * Put the share on publish queue. 1040 */ 1041 static void 1042 smb_shr_publish(smb_share_t *si, char flag, int poke) 1043 { 1044 smb_shr_adinfo_t *item = NULL; 1045 1046 if (publish_on == 0) 1047 return; 1048 1049 if ((si == NULL) || (si->shr_container[0] == '\0')) 1050 return; 1051 1052 (void) mutex_lock(&smb_shr_publish_mtx); 1053 item = (smb_shr_adinfo_t *)malloc(sizeof (smb_shr_adinfo_t)); 1054 if (item == NULL) { 1055 syslog(LOG_ERR, "Failed to allocate share publish item"); 1056 (void) mutex_unlock(&smb_shr_publish_mtx); 1057 return; 1058 } 1059 item->flag = flag; 1060 (void) strlcpy(item->name, si->shr_name, sizeof (item->name)); 1061 (void) strlcpy(item->container, si->shr_container, 1062 sizeof (item->container)); 1063 /*LINTED - E_CONSTANT_CONDITION*/ 1064 TAILQ_INSERT_TAIL(&ad_queue.adlist, item, next); 1065 ad_queue.nentries++; 1066 if (poke) 1067 (void) cond_signal(&smb_shr_publish_cv); 1068 (void) mutex_unlock(&smb_shr_publish_mtx); 1069 } 1070 1071 void 1072 smb_shr_stop_publish() 1073 { 1074 (void) mutex_lock(&smb_shr_publish_mtx); 1075 publish_on = 0; 1076 (void) cond_signal(&smb_shr_publish_cv); 1077 (void) mutex_unlock(&smb_shr_publish_mtx); 1078 } 1079 1080 /* 1081 * This functions waits to be signaled and once running 1082 * will publish/unpublish any items on list. 1083 * smb_shr_stop_publish when called will exit this thread. 1084 */ 1085 /*ARGSUSED*/ 1086 static void * 1087 smb_shr_publisher(void *arg) 1088 { 1089 smb_ads_handle_t *ah; 1090 smb_shr_adinfo_t *item; 1091 char hostname[MAXHOSTNAMELEN]; 1092 char name[MAXNAMELEN]; 1093 char container[MAXPATHLEN]; 1094 char flag; 1095 1096 /*LINTED - E_CONSTANT_CONDITION*/ 1097 TAILQ_INIT(&ad_queue.adlist); 1098 ad_queue.nentries = 0; 1099 publish_on = 1; 1100 hostname[0] = '\0'; 1101 1102 for (;;) { 1103 (void) cond_wait(&smb_shr_publish_cv, 1104 &smb_shr_publish_mtx); 1105 1106 if (hostname[0] == '\0') { 1107 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) 1108 continue; 1109 } 1110 1111 if (publish_on == 0) { 1112 syslog(LOG_DEBUG, "lmshare: publisher exit"); 1113 if (ad_queue.nentries == 0) { 1114 (void) mutex_unlock(&smb_shr_publish_mtx); 1115 break; 1116 } 1117 for (item = TAILQ_FIRST(&ad_queue.adlist); item; 1118 item = TAILQ_FIRST(&ad_queue.adlist)) { 1119 /*LINTED - E_CONSTANT_CONDITION*/ 1120 TAILQ_REMOVE(&ad_queue.adlist, item, next); 1121 (void) free(item); 1122 } 1123 ad_queue.nentries = 0; 1124 (void) mutex_unlock(&smb_shr_publish_mtx); 1125 break; 1126 } 1127 if (ad_queue.nentries == 0) 1128 continue; 1129 ah = smb_ads_open(); 1130 if (ah == NULL) { 1131 /* We mostly have no AD config so just clear the list */ 1132 for (item = TAILQ_FIRST(&ad_queue.adlist); item; 1133 item = TAILQ_FIRST(&ad_queue.adlist)) { 1134 /*LINTED - E_CONSTANT_CONDITION*/ 1135 TAILQ_REMOVE(&ad_queue.adlist, item, next); 1136 (void) free(item); 1137 } 1138 ad_queue.nentries = 0; 1139 continue; 1140 } 1141 TAILQ_FOREACH(item, &ad_queue.adlist, next) { 1142 (void) strlcpy(name, item->name, sizeof (name)); 1143 (void) strlcpy(container, item->container, 1144 sizeof (container)); 1145 flag = item->flag; 1146 1147 if (flag == SMB_SHARE_UNPUBLISH) 1148 (void) smb_ads_remove_share(ah, name, NULL, 1149 container, hostname); 1150 else 1151 (void) smb_ads_publish_share(ah, name, NULL, 1152 container, hostname); 1153 } 1154 for (item = TAILQ_FIRST(&ad_queue.adlist); item; 1155 item = TAILQ_FIRST(&ad_queue.adlist)) { 1156 /*LINTED - E_CONSTANT_CONDITION*/ 1157 TAILQ_REMOVE(&ad_queue.adlist, item, next); 1158 (void) free(item); 1159 } 1160 ad_queue.nentries = 0; 1161 if (ah != NULL) { 1162 smb_ads_close(ah); 1163 ah = NULL; 1164 } 1165 } 1166 1167 syslog(LOG_DEBUG, "lmshare: Stopping publisher"); 1168 return (NULL); 1169 } 1170 1171 /* 1172 * smb_shr_get_realpath 1173 * 1174 * Derive the real path of a share from the path provided by a 1175 * Windows client application during the share addition. 1176 * 1177 * For instance, the real path of C:\ is /cvol and the 1178 * real path of F:\home is /vol1/home. 1179 * 1180 * clipath - path provided by the Windows client is in the 1181 * format of <drive letter>:\<dir> 1182 * realpath - path that will be stored as the directory field of 1183 * the smb_share_t structure of the share. 1184 * maxlen - maximum length fo the realpath buffer 1185 * 1186 * Return LAN Manager network error code. 1187 */ 1188 /*ARGSUSED*/ 1189 uint32_t 1190 smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen) 1191 { 1192 /* XXX do this translation */ 1193 return (NERR_Success); 1194 } 1195 1196 /* 1197 * smb_shr_set_oemname 1198 * 1199 * Generates the OEM name of the given share. If it's 1200 * shorter than 13 chars it'll be saved in si->shr_oemname. 1201 * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME 1202 * will be set in si->shr_flags. 1203 */ 1204 static void 1205 smb_shr_set_oemname(smb_share_t *si) 1206 { 1207 unsigned int cpid = oem_get_smb_cpid(); 1208 mts_wchar_t *unibuf; 1209 char *oem_name; 1210 int length; 1211 1212 length = strlen(si->shr_name) + 1; 1213 1214 oem_name = malloc(length); 1215 unibuf = malloc(length * sizeof (mts_wchar_t)); 1216 if ((oem_name == NULL) || (unibuf == NULL)) { 1217 free(oem_name); 1218 free(unibuf); 1219 return; 1220 } 1221 1222 (void) mts_mbstowcs(unibuf, si->shr_name, length); 1223 1224 if (unicodestooems(oem_name, unibuf, length, cpid) == 0) 1225 (void) strcpy(oem_name, si->shr_name); 1226 1227 free(unibuf); 1228 1229 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) { 1230 si->shr_flags |= SMB_SHRF_LONGNAME; 1231 *si->shr_oemname = '\0'; 1232 } else { 1233 si->shr_flags &= ~SMB_SHRF_LONGNAME; 1234 (void) strlcpy(si->shr_oemname, oem_name, 1235 SMB_SHARE_OEMNAME_MAX); 1236 } 1237 1238 free(oem_name); 1239 } 1240