1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 2289dc44ceSjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <sys/types.h> 27da6c28aaSamw #include <sys/stat.h> 28da6c28aaSamw #include <sys/ioccom.h> 2929bd2886SAlan Wright #include <sys/corectl.h> 30da6c28aaSamw #include <stdio.h> 31da6c28aaSamw #include <string.h> 32da6c28aaSamw #include <strings.h> 33da6c28aaSamw #include <stdlib.h> 34da6c28aaSamw #include <unistd.h> 35da6c28aaSamw #include <stdarg.h> 36da6c28aaSamw #include <fcntl.h> 37da6c28aaSamw #include <wait.h> 38da6c28aaSamw #include <signal.h> 398d7e4166Sjose borrego #include <atomic.h> 40da6c28aaSamw #include <libscf.h> 41da6c28aaSamw #include <limits.h> 42da6c28aaSamw #include <priv_utils.h> 43da6c28aaSamw #include <door.h> 44da6c28aaSamw #include <errno.h> 45da6c28aaSamw #include <pthread.h> 46da6c28aaSamw #include <time.h> 47da6c28aaSamw #include <libscf.h> 48da6c28aaSamw #include <zone.h> 49da6c28aaSamw #include <libgen.h> 50da6c28aaSamw #include <pwd.h> 51da6c28aaSamw #include <grp.h> 52da6c28aaSamw 53da6c28aaSamw #include <smbsrv/smb_door_svc.h> 54da6c28aaSamw #include <smbsrv/smb_ioctl.h> 55*bbf6f00cSJordan Brown #include <smbsrv/string.h> 56da6c28aaSamw #include <smbsrv/libsmb.h> 57da6c28aaSamw #include <smbsrv/libsmbns.h> 58da6c28aaSamw #include <smbsrv/libmlsvc.h> 59da6c28aaSamw #include "smbd.h" 60da6c28aaSamw 61da6c28aaSamw #define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" 62da6c28aaSamw #define SMB_DBDIR "/var/smb" 63da6c28aaSamw 6429bd2886SAlan Wright static void *smbd_nbt_listener(void *); 6529bd2886SAlan Wright static void *smbd_tcp_listener(void *); 6629bd2886SAlan Wright static void *smbd_nbt_receiver(void *); 6729bd2886SAlan Wright static void *smbd_tcp_receiver(void *); 68faa1795aSjb150015 69da6c28aaSamw static int smbd_daemonize_init(void); 70da6c28aaSamw static void smbd_daemonize_fini(int, int); 7129bd2886SAlan Wright static int smb_init_daemon_priv(int, uid_t, gid_t); 72da6c28aaSamw 736537f381Sas200622 static int smbd_kernel_bind(void); 74da6c28aaSamw static void smbd_kernel_unbind(void); 75da6c28aaSamw static int smbd_already_running(void); 76da6c28aaSamw 77da6c28aaSamw static int smbd_service_init(void); 78da6c28aaSamw static void smbd_service_fini(void); 79da6c28aaSamw 80da6c28aaSamw static int smbd_setup_options(int argc, char *argv[]); 81da6c28aaSamw static void smbd_usage(FILE *fp); 82da6c28aaSamw static void smbd_report(const char *fmt, ...); 83da6c28aaSamw 84da6c28aaSamw static void smbd_sig_handler(int sig); 85da6c28aaSamw 86c8ec8eeaSjose borrego static int32_t smbd_gmtoff(void); 87da6c28aaSamw static int smbd_localtime_init(void); 88da6c28aaSamw static void *smbd_localtime_monitor(void *arg); 89da6c28aaSamw 90da6c28aaSamw static pthread_t localtime_thr; 91da6c28aaSamw 92da6c28aaSamw static int smbd_refresh_init(void); 93da6c28aaSamw static void smbd_refresh_fini(void); 94da6c28aaSamw static void *smbd_refresh_monitor(void *); 957f667e74Sjose borrego static void smbd_refresh_dc(void); 967f667e74Sjose borrego 9729bd2886SAlan Wright static void *smbd_nbt_receiver(void *); 9829bd2886SAlan Wright static void *smbd_nbt_listener(void *); 9929bd2886SAlan Wright 10029bd2886SAlan Wright static void *smbd_tcp_receiver(void *); 10129bd2886SAlan Wright static void *smbd_tcp_listener(void *); 10229bd2886SAlan Wright 103a4b239dfSjose borrego static int smbd_start_listeners(void); 104a4b239dfSjose borrego static void smbd_stop_listeners(void); 10529bd2886SAlan Wright static int smbd_kernel_start(void); 10629bd2886SAlan Wright 10729bd2886SAlan Wright static void smbd_fatal_error(const char *); 108a4b239dfSjose borrego 109da6c28aaSamw static pthread_t refresh_thr; 110da6c28aaSamw static pthread_cond_t refresh_cond; 111da6c28aaSamw static pthread_mutex_t refresh_mutex; 112da6c28aaSamw 113faa1795aSjb150015 smbd_t smbd; 114da6c28aaSamw 115da6c28aaSamw /* 116da6c28aaSamw * smbd user land daemon 117da6c28aaSamw * 118da6c28aaSamw * Use SMF error codes only on return or exit. 119da6c28aaSamw */ 120da6c28aaSamw int 121da6c28aaSamw main(int argc, char *argv[]) 122da6c28aaSamw { 123da6c28aaSamw struct sigaction act; 124da6c28aaSamw sigset_t set; 125da6c28aaSamw uid_t uid; 126da6c28aaSamw int pfd = -1; 1278d7e4166Sjose borrego uint_t sigval; 128da6c28aaSamw 129da6c28aaSamw smbd.s_pname = basename(argv[0]); 130da6c28aaSamw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 131da6c28aaSamw 132da6c28aaSamw if (smbd_setup_options(argc, argv) != 0) 133da6c28aaSamw return (SMF_EXIT_ERR_FATAL); 134da6c28aaSamw 135da6c28aaSamw if ((uid = getuid()) != smbd.s_uid) { 136da6c28aaSamw smbd_report("user %d: %s", uid, strerror(EPERM)); 137da6c28aaSamw return (SMF_EXIT_ERR_FATAL); 138da6c28aaSamw } 139da6c28aaSamw 140da6c28aaSamw if (getzoneid() != GLOBAL_ZONEID) { 141da6c28aaSamw smbd_report("non-global zones are not supported"); 142da6c28aaSamw return (SMF_EXIT_ERR_FATAL); 143da6c28aaSamw } 144da6c28aaSamw 145da6c28aaSamw if (is_system_labeled()) { 146da6c28aaSamw smbd_report("Trusted Extensions not supported"); 147da6c28aaSamw return (SMF_EXIT_ERR_FATAL); 148da6c28aaSamw } 149da6c28aaSamw 150da6c28aaSamw if (smbd_already_running()) 151da6c28aaSamw return (SMF_EXIT_OK); 152da6c28aaSamw 153da6c28aaSamw (void) sigfillset(&set); 154da6c28aaSamw (void) sigdelset(&set, SIGABRT); 155da6c28aaSamw 156da6c28aaSamw (void) sigfillset(&act.sa_mask); 157da6c28aaSamw act.sa_handler = smbd_sig_handler; 158da6c28aaSamw act.sa_flags = 0; 159da6c28aaSamw 160da6c28aaSamw (void) sigaction(SIGTERM, &act, NULL); 161da6c28aaSamw (void) sigaction(SIGHUP, &act, NULL); 162da6c28aaSamw (void) sigaction(SIGINT, &act, NULL); 163da6c28aaSamw (void) sigaction(SIGPIPE, &act, NULL); 164da6c28aaSamw 165da6c28aaSamw (void) sigdelset(&set, SIGTERM); 166da6c28aaSamw (void) sigdelset(&set, SIGHUP); 167da6c28aaSamw (void) sigdelset(&set, SIGINT); 168da6c28aaSamw (void) sigdelset(&set, SIGPIPE); 169da6c28aaSamw 170da6c28aaSamw if (smbd.s_fg) { 171da6c28aaSamw (void) sigdelset(&set, SIGTSTP); 172da6c28aaSamw (void) sigdelset(&set, SIGTTIN); 173da6c28aaSamw (void) sigdelset(&set, SIGTTOU); 174da6c28aaSamw 175da6c28aaSamw if (smbd_service_init() != 0) { 176da6c28aaSamw smbd_report("service initialization failed"); 177da6c28aaSamw exit(SMF_EXIT_ERR_FATAL); 178da6c28aaSamw } 179da6c28aaSamw } else { 180da6c28aaSamw /* 181da6c28aaSamw * "pfd" is a pipe descriptor -- any fatal errors 182da6c28aaSamw * during subsequent initialization of the child 183da6c28aaSamw * process should be written to this pipe and the 184da6c28aaSamw * parent will report this error as the exit status. 185da6c28aaSamw */ 186da6c28aaSamw pfd = smbd_daemonize_init(); 187da6c28aaSamw 188da6c28aaSamw if (smbd_service_init() != 0) { 189da6c28aaSamw smbd_report("daemon initialization failed"); 190da6c28aaSamw exit(SMF_EXIT_ERR_FATAL); 191da6c28aaSamw } 192da6c28aaSamw 193da6c28aaSamw smbd_daemonize_fini(pfd, SMF_EXIT_OK); 194da6c28aaSamw } 195da6c28aaSamw 196da6c28aaSamw (void) atexit(smbd_service_fini); 197da6c28aaSamw 1988d7e4166Sjose borrego while (!smbd.s_shutting_down) { 1998d7e4166Sjose borrego if (smbd.s_sigval == 0 && smbd.s_refreshes == 0) 200da6c28aaSamw (void) sigsuspend(&set); 201da6c28aaSamw 2028d7e4166Sjose borrego sigval = atomic_swap_uint(&smbd.s_sigval, 0); 203da6c28aaSamw 2043db3f65cSamw switch (sigval) { 2053db3f65cSamw case 0: 206da6c28aaSamw case SIGPIPE: 207da6c28aaSamw break; 208da6c28aaSamw 209da6c28aaSamw case SIGHUP: 2108d7e4166Sjose borrego syslog(LOG_DEBUG, "refresh requested"); 211da6c28aaSamw (void) pthread_cond_signal(&refresh_cond); 212da6c28aaSamw break; 213da6c28aaSamw 214da6c28aaSamw default: 215da6c28aaSamw /* 216da6c28aaSamw * Typically SIGINT or SIGTERM. 217da6c28aaSamw */ 2188d7e4166Sjose borrego smbd.s_shutting_down = B_TRUE; 219da6c28aaSamw break; 220da6c28aaSamw } 221da6c28aaSamw } 222da6c28aaSamw 223da6c28aaSamw smbd_service_fini(); 224da6c28aaSamw closelog(); 22529bd2886SAlan Wright return ((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL : SMF_EXIT_OK); 226da6c28aaSamw } 227da6c28aaSamw 228da6c28aaSamw /* 229da6c28aaSamw * This function will fork off a child process, 230da6c28aaSamw * from which only the child will return. 231da6c28aaSamw * 232da6c28aaSamw * Use SMF error codes only on exit. 233da6c28aaSamw */ 234da6c28aaSamw static int 235da6c28aaSamw smbd_daemonize_init(void) 236da6c28aaSamw { 237da6c28aaSamw int status, pfds[2]; 238da6c28aaSamw sigset_t set, oset; 239da6c28aaSamw pid_t pid; 240da6c28aaSamw int rc; 241da6c28aaSamw 242da6c28aaSamw /* 243da6c28aaSamw * Reset privileges to the minimum set required. We continue 244da6c28aaSamw * to run as root to create and access files in /var. 245da6c28aaSamw */ 24629bd2886SAlan Wright rc = smb_init_daemon_priv(PU_RESETGROUPS, smbd.s_uid, smbd.s_gid); 247da6c28aaSamw 248da6c28aaSamw if (rc != 0) { 249da6c28aaSamw smbd_report("insufficient privileges"); 250da6c28aaSamw exit(SMF_EXIT_ERR_FATAL); 251da6c28aaSamw } 252da6c28aaSamw 253da6c28aaSamw /* 254da6c28aaSamw * Block all signals prior to the fork and leave them blocked in the 255da6c28aaSamw * parent so we don't get in a situation where the parent gets SIGINT 256da6c28aaSamw * and returns non-zero exit status and the child is actually running. 257da6c28aaSamw * In the child, restore the signal mask once we've done our setsid(). 258da6c28aaSamw */ 259da6c28aaSamw (void) sigfillset(&set); 260da6c28aaSamw (void) sigdelset(&set, SIGABRT); 261da6c28aaSamw (void) sigprocmask(SIG_BLOCK, &set, &oset); 262da6c28aaSamw 263da6c28aaSamw if (pipe(pfds) == -1) { 264da6c28aaSamw smbd_report("unable to create pipe"); 265da6c28aaSamw exit(SMF_EXIT_ERR_FATAL); 266da6c28aaSamw } 267da6c28aaSamw 268da6c28aaSamw closelog(); 269da6c28aaSamw 270da6c28aaSamw if ((pid = fork()) == -1) { 271da6c28aaSamw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 272da6c28aaSamw smbd_report("unable to fork"); 273da6c28aaSamw closelog(); 274da6c28aaSamw exit(SMF_EXIT_ERR_FATAL); 275da6c28aaSamw } 276da6c28aaSamw 277da6c28aaSamw /* 278da6c28aaSamw * If we're the parent process, wait for either the child to send us 279da6c28aaSamw * the appropriate exit status over the pipe or for the read to fail 280da6c28aaSamw * (presumably with 0 for EOF if our child terminated abnormally). 281da6c28aaSamw * If the read fails, exit with either the child's exit status if it 282da6c28aaSamw * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. 283da6c28aaSamw */ 284da6c28aaSamw if (pid != 0) { 285da6c28aaSamw (void) close(pfds[1]); 286da6c28aaSamw 287da6c28aaSamw if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 288da6c28aaSamw _exit(status); 289da6c28aaSamw 290da6c28aaSamw if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 291da6c28aaSamw _exit(WEXITSTATUS(status)); 292da6c28aaSamw 293da6c28aaSamw _exit(SMF_EXIT_ERR_FATAL); 294da6c28aaSamw } 295da6c28aaSamw 296da6c28aaSamw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 297da6c28aaSamw (void) setsid(); 298da6c28aaSamw (void) sigprocmask(SIG_SETMASK, &oset, NULL); 299da6c28aaSamw (void) chdir("/"); 300da6c28aaSamw (void) umask(022); 301da6c28aaSamw (void) close(pfds[0]); 302da6c28aaSamw 303da6c28aaSamw return (pfds[1]); 304da6c28aaSamw } 305da6c28aaSamw 30629bd2886SAlan Wright /* 30729bd2886SAlan Wright * This function is based on __init_daemon_priv() and replaces 30829bd2886SAlan Wright * __init_daemon_priv() since we want smbd to have all privileges so that it 30929bd2886SAlan Wright * can execute map/unmap commands with all privileges during share 31029bd2886SAlan Wright * connection/disconnection. Unused privileges are disabled until command 31129bd2886SAlan Wright * execution. The permitted and the limit set contains all privileges. The 31229bd2886SAlan Wright * inheritable set contains no privileges. 31329bd2886SAlan Wright */ 31429bd2886SAlan Wright 31529bd2886SAlan Wright static const char root_cp[] = "/core.%f.%t"; 31629bd2886SAlan Wright static const char daemon_cp[] = "/var/tmp/core.%f.%t"; 31729bd2886SAlan Wright 31829bd2886SAlan Wright static int 31929bd2886SAlan Wright smb_init_daemon_priv(int flags, uid_t uid, gid_t gid) 32029bd2886SAlan Wright { 32129bd2886SAlan Wright priv_set_t *perm = NULL; 32229bd2886SAlan Wright int ret = -1; 32329bd2886SAlan Wright char buf[1024]; 32429bd2886SAlan Wright 32529bd2886SAlan Wright /* 32629bd2886SAlan Wright * This is not a significant failure: it allows us to start programs 32729bd2886SAlan Wright * with sufficient privileges and with the proper uid. We don't 32829bd2886SAlan Wright * care enough about the extra groups in that case. 32929bd2886SAlan Wright */ 33029bd2886SAlan Wright if (flags & PU_RESETGROUPS) 33129bd2886SAlan Wright (void) setgroups(0, NULL); 33229bd2886SAlan Wright 33329bd2886SAlan Wright if (gid != (gid_t)-1 && setgid(gid) != 0) 33429bd2886SAlan Wright goto end; 33529bd2886SAlan Wright 33629bd2886SAlan Wright perm = priv_allocset(); 33729bd2886SAlan Wright if (perm == NULL) 33829bd2886SAlan Wright goto end; 33929bd2886SAlan Wright 34029bd2886SAlan Wright /* E = P */ 34129bd2886SAlan Wright (void) getppriv(PRIV_PERMITTED, perm); 34229bd2886SAlan Wright (void) setppriv(PRIV_SET, PRIV_EFFECTIVE, perm); 34329bd2886SAlan Wright 34429bd2886SAlan Wright /* Now reset suid and euid */ 34529bd2886SAlan Wright if (uid != (uid_t)-1 && setreuid(uid, uid) != 0) 34629bd2886SAlan Wright goto end; 34729bd2886SAlan Wright 34829bd2886SAlan Wright /* I = 0 */ 34929bd2886SAlan Wright priv_emptyset(perm); 35029bd2886SAlan Wright ret = setppriv(PRIV_SET, PRIV_INHERITABLE, perm); 35129bd2886SAlan Wright end: 35229bd2886SAlan Wright priv_freeset(perm); 35329bd2886SAlan Wright 35429bd2886SAlan Wright if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 && 35529bd2886SAlan Wright strcmp(buf, "core") == 0) { 35629bd2886SAlan Wright 35729bd2886SAlan Wright if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) { 35829bd2886SAlan Wright (void) core_set_process_path(root_cp, sizeof (root_cp), 35929bd2886SAlan Wright getpid()); 36029bd2886SAlan Wright } else { 36129bd2886SAlan Wright (void) core_set_process_path(daemon_cp, 36229bd2886SAlan Wright sizeof (daemon_cp), getpid()); 36329bd2886SAlan Wright } 36429bd2886SAlan Wright } 36529bd2886SAlan Wright (void) setpflags(__PROC_PROTECT, 0); 36629bd2886SAlan Wright 36729bd2886SAlan Wright return (ret); 36829bd2886SAlan Wright } 36929bd2886SAlan Wright 37029bd2886SAlan Wright /* 37129bd2886SAlan Wright * Most privileges, except the ones that are required for smbd, are turn off 37229bd2886SAlan Wright * in the effective set. They will be turn on when needed for command 37329bd2886SAlan Wright * execution during share connection/disconnection. 37429bd2886SAlan Wright */ 375da6c28aaSamw static void 376da6c28aaSamw smbd_daemonize_fini(int fd, int exit_status) 377da6c28aaSamw { 37829bd2886SAlan Wright priv_set_t *pset; 37929bd2886SAlan Wright 380da6c28aaSamw /* 381da6c28aaSamw * Now that we're running, if a pipe fd was specified, write an exit 382da6c28aaSamw * status to it to indicate that our parent process can safely detach. 383da6c28aaSamw * Then proceed to loading the remaining non-built-in modules. 384da6c28aaSamw */ 385da6c28aaSamw if (fd >= 0) 386da6c28aaSamw (void) write(fd, &exit_status, sizeof (exit_status)); 387da6c28aaSamw 388da6c28aaSamw (void) close(fd); 389da6c28aaSamw 39029bd2886SAlan Wright pset = priv_allocset(); 39129bd2886SAlan Wright if (pset == NULL) 39229bd2886SAlan Wright return; 39329bd2886SAlan Wright 39429bd2886SAlan Wright priv_emptyset(pset); 39529bd2886SAlan Wright 39629bd2886SAlan Wright /* list of privileges for smbd */ 39729bd2886SAlan Wright (void) priv_addset(pset, PRIV_NET_MAC_AWARE); 39829bd2886SAlan Wright (void) priv_addset(pset, PRIV_NET_PRIVADDR); 39929bd2886SAlan Wright (void) priv_addset(pset, PRIV_PROC_AUDIT); 40029bd2886SAlan Wright (void) priv_addset(pset, PRIV_SYS_DEVICES); 40129bd2886SAlan Wright (void) priv_addset(pset, PRIV_SYS_SMB); 40229bd2886SAlan Wright 40329bd2886SAlan Wright priv_inverse(pset); 40429bd2886SAlan Wright 40529bd2886SAlan Wright /* turn off unneeded privileges */ 40629bd2886SAlan Wright (void) setppriv(PRIV_OFF, PRIV_EFFECTIVE, pset); 40729bd2886SAlan Wright 40829bd2886SAlan Wright priv_freeset(pset); 40929bd2886SAlan Wright 41029bd2886SAlan Wright /* reenable core dumps */ 41129bd2886SAlan Wright __fini_daemon_priv(NULL); 412da6c28aaSamw } 413da6c28aaSamw 414faa1795aSjb150015 /* 415faa1795aSjb150015 * smbd_service_init 416faa1795aSjb150015 */ 417da6c28aaSamw static int 418da6c28aaSamw smbd_service_init(void) 419da6c28aaSamw { 420da6c28aaSamw int rc; 421da6c28aaSamw 42229bd2886SAlan Wright smbd.s_pid = getpid(); 423faa1795aSjb150015 if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) { 424faa1795aSjb150015 smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno)); 425da6c28aaSamw return (1); 426da6c28aaSamw } 427da6c28aaSamw 428faa1795aSjb150015 if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) { 429faa1795aSjb150015 if (rc == -1) 430faa1795aSjb150015 smbd_report("mkdir %s: %s", SMB_VARRUN_DIR, 431faa1795aSjb150015 strerror(errno)); 432faa1795aSjb150015 else 433da6c28aaSamw smbd_report("unable to set KRB5CCNAME"); 434da6c28aaSamw return (1); 435da6c28aaSamw } 436da6c28aaSamw 437*bbf6f00cSJordan Brown smb_codepage_init(); 438da6c28aaSamw 4396537f381Sas200622 if (!smb_wka_init()) { 440da6c28aaSamw smbd_report("out of memory"); 441da6c28aaSamw return (1); 442da6c28aaSamw } 443da6c28aaSamw 4446537f381Sas200622 if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0) 4456537f381Sas200622 smbd_report("NIC monitoring failed to start"); 4466537f381Sas200622 4478d7e4166Sjose borrego (void) dyndns_start(); 448a0aa776eSAlan Wright smb_ipc_init(); 449da6c28aaSamw 450dc20a302Sas200622 if (smb_netbios_start() != 0) 451dc20a302Sas200622 smbd_report("NetBIOS services failed to start"); 452dc20a302Sas200622 else 453dc20a302Sas200622 smbd_report("NetBIOS services started"); 454dc20a302Sas200622 455da6c28aaSamw /* Get the ID map client handle */ 456da6c28aaSamw if ((rc = smb_idmap_start()) != 0) { 457da6c28aaSamw smbd_report("no idmap handle"); 458da6c28aaSamw return (rc); 459da6c28aaSamw } 460da6c28aaSamw 4616537f381Sas200622 smbd.s_secmode = smb_config_get_secmode(); 462a0aa776eSAlan Wright if ((rc = smb_domain_init(smbd.s_secmode)) != 0) { 463dc20a302Sas200622 if (rc == SMB_DOMAIN_NOMACHINE_SID) { 464dc20a302Sas200622 smbd_report( 465dc20a302Sas200622 "no machine SID: check idmap configuration"); 466da6c28aaSamw return (rc); 467da6c28aaSamw } 468dc20a302Sas200622 } 469da6c28aaSamw 4703db3f65cSamw smb_ads_init(); 471da6c28aaSamw if ((rc = mlsvc_init()) != 0) { 472da6c28aaSamw smbd_report("msrpc initialization failed"); 473da6c28aaSamw return (rc); 474da6c28aaSamw } 475da6c28aaSamw 476c8ec8eeaSjose borrego if (smbd.s_secmode == SMB_SECMODE_DOMAIN) 4778d7e4166Sjose borrego if (smbd_locate_dc_start() != 0) 478c8ec8eeaSjose borrego smbd_report("dc discovery failed %s", strerror(errno)); 479faa1795aSjb150015 4806537f381Sas200622 smbd.s_door_srv = smb_door_srv_start(); 4816537f381Sas200622 if (smbd.s_door_srv < 0) 482da6c28aaSamw return (rc); 483da6c28aaSamw 484da6c28aaSamw if ((rc = smbd_refresh_init()) != 0) 485da6c28aaSamw return (rc); 486da6c28aaSamw 4878d7e4166Sjose borrego dyndns_update_zones(); 488da6c28aaSamw 489da6c28aaSamw (void) smbd_localtime_init(); 490da6c28aaSamw 4913db3f65cSamw smbd.s_door_opipe = smbd_opipe_dsrv_start(); 4923db3f65cSamw if (smbd.s_door_opipe < 0) { 4933db3f65cSamw smbd_report("opipe initialization failed %s", 49455bf511dSas200622 strerror(errno)); 49555bf511dSas200622 return (rc); 49655bf511dSas200622 } 49755bf511dSas200622 498dc20a302Sas200622 (void) smb_lgrp_start(); 4997b59d02dSjb150015 5003db3f65cSamw smb_pwd_init(B_TRUE); 5017b59d02dSjb150015 502b89a8333Snatalie li - Sun Microsystems - Irvine United States if ((rc = smb_shr_start()) != 0) { 503b89a8333Snatalie li - Sun Microsystems - Irvine United States smbd_report("share initialization failed: %s", strerror(errno)); 5046537f381Sas200622 return (rc); 5056537f381Sas200622 } 506da6c28aaSamw 507b89a8333Snatalie li - Sun Microsystems - Irvine United States smbd.s_door_lmshr = smb_share_dsrv_start(); 508b89a8333Snatalie li - Sun Microsystems - Irvine United States if (smbd.s_door_lmshr < 0) { 509b89a8333Snatalie li - Sun Microsystems - Irvine United States smbd_report("share initialization failed"); 510b89a8333Snatalie li - Sun Microsystems - Irvine United States } 511b89a8333Snatalie li - Sun Microsystems - Irvine United States 5128d7e4166Sjose borrego if ((rc = smbd_kernel_bind()) != 0) { 513b89a8333Snatalie li - Sun Microsystems - Irvine United States smbd_report("kernel bind error: %s", strerror(errno)); 514c8ec8eeaSjose borrego return (rc); 515c8ec8eeaSjose borrego } 516c8ec8eeaSjose borrego 5178d7e4166Sjose borrego if ((rc = smb_shr_load()) != 0) { 5188d7e4166Sjose borrego smbd_report("failed to start loading shares: %s", 5198d7e4166Sjose borrego strerror(errno)); 5208d7e4166Sjose borrego return (rc); 5218d7e4166Sjose borrego } 5228d7e4166Sjose borrego 523c8ec8eeaSjose borrego return (0); 52455bf511dSas200622 } 52555bf511dSas200622 526da6c28aaSamw /* 527da6c28aaSamw * Close the kernel service and shutdown smbd services. 528da6c28aaSamw * This function is registered with atexit(): ensure that anything 529da6c28aaSamw * called from here is safe to be called multiple times. 530da6c28aaSamw */ 531da6c28aaSamw static void 532da6c28aaSamw smbd_service_fini(void) 533da6c28aaSamw { 5343db3f65cSamw smbd_opipe_dsrv_stop(); 5356537f381Sas200622 smb_wka_fini(); 536da6c28aaSamw smbd_refresh_fini(); 537da6c28aaSamw smbd_kernel_unbind(); 538da6c28aaSamw smb_door_srv_stop(); 5393ad684d6Sjb150015 smb_share_dsrv_stop(); 5403db3f65cSamw smb_shr_stop(); 5418d7e4166Sjose borrego dyndns_stop(); 542da6c28aaSamw smb_nicmon_stop(); 543da6c28aaSamw smb_idmap_stop(); 544dc20a302Sas200622 smb_lgrp_stop(); 545faa1795aSjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 5467b59d02dSjb150015 smb_pwd_fini(); 547a0aa776eSAlan Wright smb_domain_fini(); 54829bd2886SAlan Wright mlsvc_fini(); 54929bd2886SAlan Wright smb_ads_fini(); 550a0aa776eSAlan Wright smb_netbios_stop(); 551da6c28aaSamw } 552da6c28aaSamw 553faa1795aSjb150015 554da6c28aaSamw /* 555da6c28aaSamw * smbd_refresh_init() 556da6c28aaSamw * 557da6c28aaSamw * SMB service refresh thread initialization. This thread waits for a 558da6c28aaSamw * refresh event and updates the daemon's view of the configuration 559da6c28aaSamw * before going back to sleep. 560da6c28aaSamw */ 561da6c28aaSamw static int 562da6c28aaSamw smbd_refresh_init() 563da6c28aaSamw { 564da6c28aaSamw pthread_attr_t tattr; 565da6c28aaSamw pthread_condattr_t cattr; 566da6c28aaSamw int rc; 567da6c28aaSamw 568da6c28aaSamw (void) pthread_condattr_init(&cattr); 569da6c28aaSamw (void) pthread_cond_init(&refresh_cond, &cattr); 570da6c28aaSamw (void) pthread_condattr_destroy(&cattr); 571da6c28aaSamw 572da6c28aaSamw (void) pthread_mutex_init(&refresh_mutex, NULL); 573da6c28aaSamw 574da6c28aaSamw (void) pthread_attr_init(&tattr); 575da6c28aaSamw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 576da6c28aaSamw rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0); 577da6c28aaSamw (void) pthread_attr_destroy(&tattr); 578da6c28aaSamw 5796537f381Sas200622 return (rc); 580da6c28aaSamw } 581da6c28aaSamw 582da6c28aaSamw /* 583da6c28aaSamw * smbd_refresh_fini() 584da6c28aaSamw * 585da6c28aaSamw * Stop the refresh thread. 586da6c28aaSamw */ 587da6c28aaSamw static void 588da6c28aaSamw smbd_refresh_fini() 589da6c28aaSamw { 590da6c28aaSamw (void) pthread_cancel(refresh_thr); 591da6c28aaSamw 592da6c28aaSamw (void) pthread_cond_destroy(&refresh_cond); 593da6c28aaSamw (void) pthread_mutex_destroy(&refresh_mutex); 594da6c28aaSamw } 595da6c28aaSamw 596da6c28aaSamw /* 597da6c28aaSamw * smbd_refresh_monitor() 598da6c28aaSamw * 599da6c28aaSamw * Wait for a refresh event. When this thread wakes up, update the 600da6c28aaSamw * smbd configuration from the SMF config information then go back to 601da6c28aaSamw * wait for the next refresh. 602da6c28aaSamw */ 603da6c28aaSamw /*ARGSUSED*/ 604da6c28aaSamw static void * 605da6c28aaSamw smbd_refresh_monitor(void *arg) 606da6c28aaSamw { 60729bd2886SAlan Wright smb_kmod_cfg_t cfg; 60829bd2886SAlan Wright int error; 6093ad684d6Sjb150015 6108d7e4166Sjose borrego while (!smbd.s_shutting_down) { 611da6c28aaSamw (void) pthread_mutex_lock(&refresh_mutex); 6128d7e4166Sjose borrego while ((atomic_swap_uint(&smbd.s_refreshes, 0) == 0) && 6138d7e4166Sjose borrego (!smbd.s_shutting_down)) 6148d7e4166Sjose borrego (void) pthread_cond_wait(&refresh_cond, &refresh_mutex); 6158d7e4166Sjose borrego (void) pthread_mutex_unlock(&refresh_mutex); 6168d7e4166Sjose borrego 6178d7e4166Sjose borrego if (smbd.s_shutting_down) { 6188d7e4166Sjose borrego syslog(LOG_DEBUG, "shutting down"); 61929bd2886SAlan Wright exit((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL : 62029bd2886SAlan Wright SMF_EXIT_OK); 6218d7e4166Sjose borrego } 6228d7e4166Sjose borrego 623da6c28aaSamw /* 624da6c28aaSamw * We've been woken up by a refresh event so go do 625da6c28aaSamw * what is necessary. 626da6c28aaSamw */ 6273db3f65cSamw smb_ads_refresh(); 628faa1795aSjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 6296537f381Sas200622 6308d7e4166Sjose borrego /* 6318d7e4166Sjose borrego * Start the dyndns thread, if required. 6328d7e4166Sjose borrego * Clear the DNS zones for the existing interfaces 6338d7e4166Sjose borrego * before updating the NIC interface list. 6348d7e4166Sjose borrego */ 6358d7e4166Sjose borrego (void) dyndns_start(); 6368d7e4166Sjose borrego dyndns_clear_zones(); 6376537f381Sas200622 6386537f381Sas200622 /* re-initialize NIC table */ 6396537f381Sas200622 if (smb_nic_init() != 0) 6406537f381Sas200622 smbd_report("failed to get NIC information"); 6416537f381Sas200622 smb_netbios_name_reconfig(); 6426537f381Sas200622 smb_browser_reconfig(); 6437f667e74Sjose borrego smbd_refresh_dc(); 6448d7e4166Sjose borrego dyndns_update_zones(); 6456537f381Sas200622 6468d7e4166Sjose borrego if (smbd_set_netlogon_cred()) { 6476537f381Sas200622 /* 6488d7e4166Sjose borrego * Restart required because the domain changed 6498d7e4166Sjose borrego * or the credential chain setup failed. 6506537f381Sas200622 */ 6518d7e4166Sjose borrego if (smb_smf_restart_service() != 0) { 6528d7e4166Sjose borrego syslog(LOG_ERR, 6538d7e4166Sjose borrego "unable to restart smb service. " 6548d7e4166Sjose borrego "Run 'svcs -xv smb/server' for more " 6558d7e4166Sjose borrego "information."); 6568d7e4166Sjose borrego smbd.s_shutting_down = B_TRUE; 6578d7e4166Sjose borrego exit(SMF_EXIT_OK); 6588d7e4166Sjose borrego } 6598d7e4166Sjose borrego 6608d7e4166Sjose borrego break; 6618d7e4166Sjose borrego } 6628d7e4166Sjose borrego 66329bd2886SAlan Wright if (!smbd.s_kbound) { 66429bd2886SAlan Wright error = smbd_kernel_bind(); 66529bd2886SAlan Wright if (error != 0) 6666537f381Sas200622 smbd_report("kernel bind error: %s", 66729bd2886SAlan Wright strerror(error)); 66829bd2886SAlan Wright else 6698d7e4166Sjose borrego (void) smb_shr_load(); 67029bd2886SAlan Wright 6716537f381Sas200622 continue; 6726537f381Sas200622 } 6736537f381Sas200622 6748d7e4166Sjose borrego (void) smb_shr_load(); 6758d7e4166Sjose borrego 67629bd2886SAlan Wright smb_load_kconfig(&cfg); 67729bd2886SAlan Wright error = smb_kmod_setcfg(&cfg); 67829bd2886SAlan Wright if (error < 0) 67929bd2886SAlan Wright smbd_report("configuration update failed: %s", 68029bd2886SAlan Wright strerror(error)); 681da6c28aaSamw } 6828d7e4166Sjose borrego 683da6c28aaSamw return (NULL); 684da6c28aaSamw } 685da6c28aaSamw 6867f667e74Sjose borrego /* 6877f667e74Sjose borrego * Update DC information on a refresh. 6887f667e74Sjose borrego */ 6897f667e74Sjose borrego static void 6907f667e74Sjose borrego smbd_refresh_dc(void) 6917f667e74Sjose borrego { 6927f667e74Sjose borrego char fqdomain[MAXHOSTNAMELEN]; 6937f667e74Sjose borrego if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 6947f667e74Sjose borrego return; 6957f667e74Sjose borrego 6967f667e74Sjose borrego if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN)) 6977f667e74Sjose borrego return; 6987f667e74Sjose borrego 6997f667e74Sjose borrego if (smb_locate_dc(fqdomain, "", NULL)) 7007f667e74Sjose borrego smbd_report("DC discovery failed"); 7017f667e74Sjose borrego } 7027f667e74Sjose borrego 7038d7e4166Sjose borrego void 7048d7e4166Sjose borrego smbd_set_secmode(int secmode) 7058d7e4166Sjose borrego { 7068d7e4166Sjose borrego switch (secmode) { 7078d7e4166Sjose borrego case SMB_SECMODE_WORKGRP: 7088d7e4166Sjose borrego case SMB_SECMODE_DOMAIN: 7098d7e4166Sjose borrego (void) smb_config_set_secmode(secmode); 7108d7e4166Sjose borrego smbd.s_secmode = secmode; 7118d7e4166Sjose borrego break; 7128d7e4166Sjose borrego 7138d7e4166Sjose borrego default: 7148d7e4166Sjose borrego syslog(LOG_ERR, "invalid security mode: %d", secmode); 7158d7e4166Sjose borrego syslog(LOG_ERR, "entering maintenance mode"); 7168d7e4166Sjose borrego (void) smb_smf_maintenance_mode(); 7178d7e4166Sjose borrego } 7188d7e4166Sjose borrego } 719da6c28aaSamw 720da6c28aaSamw /* 721da6c28aaSamw * If the door has already been opened by another process (non-zero pid 722da6c28aaSamw * in target), we assume that another smbd is already running. If there 723da6c28aaSamw * is a race here, it will be caught later when smbsrv is opened because 724da6c28aaSamw * only one process is allowed to open the device at a time. 725da6c28aaSamw */ 726da6c28aaSamw static int 727da6c28aaSamw smbd_already_running(void) 728da6c28aaSamw { 729da6c28aaSamw door_info_t info; 730da6c28aaSamw int door; 731da6c28aaSamw 732faa1795aSjb150015 if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) 733da6c28aaSamw return (0); 734da6c28aaSamw 735da6c28aaSamw if (door_info(door, &info) < 0) 736da6c28aaSamw return (0); 737da6c28aaSamw 738da6c28aaSamw if (info.di_target > 0) { 739da6c28aaSamw smbd_report("already running: pid %ld\n", info.di_target); 740da6c28aaSamw (void) close(door); 741da6c28aaSamw return (1); 742da6c28aaSamw } 743da6c28aaSamw 744da6c28aaSamw (void) close(door); 745da6c28aaSamw return (0); 746da6c28aaSamw } 747da6c28aaSamw 748faa1795aSjb150015 /* 749faa1795aSjb150015 * smbd_kernel_bind 7506537f381Sas200622 * 7516537f381Sas200622 * This function open the smbsrv device and start the kernel service. 752faa1795aSjb150015 */ 753da6c28aaSamw static int 7546537f381Sas200622 smbd_kernel_bind(void) 755da6c28aaSamw { 756faa1795aSjb150015 int rc; 757faa1795aSjb150015 7588d7e4166Sjose borrego smbd_kernel_unbind(); 759da6c28aaSamw 76029bd2886SAlan Wright rc = smb_kmod_bind(); 76129bd2886SAlan Wright if (rc == 0) { 76229bd2886SAlan Wright rc = smbd_kernel_start(); 76329bd2886SAlan Wright if (rc != 0) 76429bd2886SAlan Wright smb_kmod_unbind(); 76529bd2886SAlan Wright else 76629bd2886SAlan Wright smbd.s_kbound = B_TRUE; 76729bd2886SAlan Wright } 76829bd2886SAlan Wright return (rc); 769da6c28aaSamw } 77094fff790SAlan Wright 77129bd2886SAlan Wright static int 77229bd2886SAlan Wright smbd_kernel_start(void) 77329bd2886SAlan Wright { 77429bd2886SAlan Wright smb_kmod_cfg_t cfg; 77529bd2886SAlan Wright int rc; 7768d7e4166Sjose borrego 77729bd2886SAlan Wright smb_load_kconfig(&cfg); 77829bd2886SAlan Wright rc = smb_kmod_setcfg(&cfg); 77929bd2886SAlan Wright if (rc != 0) 78029bd2886SAlan Wright return (rc); 78129bd2886SAlan Wright 78229bd2886SAlan Wright rc = smb_kmod_setgmtoff(smbd_gmtoff()); 78329bd2886SAlan Wright if (rc != 0) 78429bd2886SAlan Wright return (rc); 78529bd2886SAlan Wright 78629bd2886SAlan Wright rc = smb_kmod_start(smbd.s_door_opipe, smbd.s_door_lmshr, 78729bd2886SAlan Wright smbd.s_door_srv); 78829bd2886SAlan Wright if (rc != 0) 78929bd2886SAlan Wright return (rc); 790da6c28aaSamw 791a4b239dfSjose borrego rc = smbd_start_listeners(); 79229bd2886SAlan Wright if (rc != 0) 793faa1795aSjb150015 return (rc); 79429bd2886SAlan Wright 79529bd2886SAlan Wright return (0); 796faa1795aSjb150015 } 797faa1795aSjb150015 798faa1795aSjb150015 /* 799faa1795aSjb150015 * smbd_kernel_unbind 800faa1795aSjb150015 */ 801faa1795aSjb150015 static void 802faa1795aSjb150015 smbd_kernel_unbind(void) 803faa1795aSjb150015 { 804a4b239dfSjose borrego smbd_stop_listeners(); 80529bd2886SAlan Wright smb_kmod_unbind(); 8066537f381Sas200622 smbd.s_kbound = B_FALSE; 807faa1795aSjb150015 } 80894fff790SAlan Wright 809da6c28aaSamw /* 810da6c28aaSamw * Initialization of the localtime thread. 811da6c28aaSamw * Returns 0 on success, an error number if thread creation fails. 812da6c28aaSamw */ 813da6c28aaSamw 814da6c28aaSamw int 815da6c28aaSamw smbd_localtime_init(void) 816da6c28aaSamw { 817da6c28aaSamw pthread_attr_t tattr; 818da6c28aaSamw int rc; 819da6c28aaSamw 820da6c28aaSamw (void) pthread_attr_init(&tattr); 821da6c28aaSamw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 822da6c28aaSamw rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0); 823da6c28aaSamw (void) pthread_attr_destroy(&tattr); 824da6c28aaSamw return (rc); 825da6c28aaSamw } 826da6c28aaSamw 827da6c28aaSamw /* 828da6c28aaSamw * Local time thread to kernel land. 829da6c28aaSamw * Send local gmtoff to kernel module one time at startup 830da6c28aaSamw * and each time it changes (up to twice a year). 831da6c28aaSamw * Local gmtoff is checked once every 15 minutes and 832da6c28aaSamw * since some timezones are aligned on half and qtr hour boundaries, 833da6c28aaSamw * once an hour would likely suffice. 834da6c28aaSamw */ 835da6c28aaSamw 836da6c28aaSamw /*ARGSUSED*/ 837da6c28aaSamw static void * 838da6c28aaSamw smbd_localtime_monitor(void *arg) 839da6c28aaSamw { 840da6c28aaSamw struct tm local_tm; 841c8ec8eeaSjose borrego time_t secs; 842c8ec8eeaSjose borrego int32_t gmtoff, last_gmtoff = -1; 843da6c28aaSamw int timeout; 84429bd2886SAlan Wright int error; 84594fff790SAlan Wright 846da6c28aaSamw for (;;) { 847c8ec8eeaSjose borrego gmtoff = smbd_gmtoff(); 848da6c28aaSamw 84929bd2886SAlan Wright if ((last_gmtoff != gmtoff) && smbd.s_kbound) { 85029bd2886SAlan Wright error = smb_kmod_setgmtoff(gmtoff); 85129bd2886SAlan Wright if (error != 0) 85229bd2886SAlan Wright smbd_report("localtime set failed: %s", 85329bd2886SAlan Wright strerror(error)); 854da6c28aaSamw } 855da6c28aaSamw 856da6c28aaSamw /* 857da6c28aaSamw * Align the next iteration on a fifteen minute boundary. 858da6c28aaSamw */ 859da6c28aaSamw secs = time(0); 860da6c28aaSamw (void) localtime_r(&secs, &local_tm); 861da6c28aaSamw timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN); 862da6c28aaSamw (void) sleep(timeout); 863da6c28aaSamw 864da6c28aaSamw last_gmtoff = gmtoff; 865da6c28aaSamw } 866da6c28aaSamw 867da6c28aaSamw /*NOTREACHED*/ 868da6c28aaSamw return (NULL); 869da6c28aaSamw } 870da6c28aaSamw 871c8ec8eeaSjose borrego /* 872c8ec8eeaSjose borrego * smbd_gmtoff 873c8ec8eeaSjose borrego * 874c8ec8eeaSjose borrego * Determine offset from GMT. If daylight saving time use altzone, 875c8ec8eeaSjose borrego * otherwise use timezone. 876c8ec8eeaSjose borrego */ 877c8ec8eeaSjose borrego static int32_t 878c8ec8eeaSjose borrego smbd_gmtoff(void) 879c8ec8eeaSjose borrego { 880c8ec8eeaSjose borrego time_t clock_val; 881c8ec8eeaSjose borrego struct tm *atm; 882c8ec8eeaSjose borrego int32_t gmtoff; 883c8ec8eeaSjose borrego 884c8ec8eeaSjose borrego (void) time(&clock_val); 885c8ec8eeaSjose borrego atm = localtime(&clock_val); 886c8ec8eeaSjose borrego 887c8ec8eeaSjose borrego gmtoff = (atm->tm_isdst) ? altzone : timezone; 888c8ec8eeaSjose borrego 889c8ec8eeaSjose borrego return (gmtoff); 890c8ec8eeaSjose borrego } 891c8ec8eeaSjose borrego 892da6c28aaSamw static void 893da6c28aaSamw smbd_sig_handler(int sigval) 894da6c28aaSamw { 895da6c28aaSamw if (smbd.s_sigval == 0) 8968d7e4166Sjose borrego (void) atomic_swap_uint(&smbd.s_sigval, sigval); 8978d7e4166Sjose borrego 8988d7e4166Sjose borrego if (sigval == SIGHUP) { 8998d7e4166Sjose borrego atomic_inc_uint(&smbd.s_refreshes); 9008d7e4166Sjose borrego (void) pthread_cond_signal(&refresh_cond); 9018d7e4166Sjose borrego } 9028d7e4166Sjose borrego 9038d7e4166Sjose borrego if (sigval == SIGINT || sigval == SIGTERM) { 9048d7e4166Sjose borrego smbd.s_shutting_down = B_TRUE; 9058d7e4166Sjose borrego (void) pthread_cond_signal(&refresh_cond); 9068d7e4166Sjose borrego } 907da6c28aaSamw } 908da6c28aaSamw 909da6c28aaSamw /* 910da6c28aaSamw * Set up configuration options and parse the command line. 911da6c28aaSamw * This function will determine if we will run as a daemon 912da6c28aaSamw * or in the foreground. 913da6c28aaSamw * 914da6c28aaSamw * Failure to find a uid or gid results in using the default (0). 915da6c28aaSamw */ 916da6c28aaSamw static int 917da6c28aaSamw smbd_setup_options(int argc, char *argv[]) 918da6c28aaSamw { 919da6c28aaSamw struct passwd *pwd; 920da6c28aaSamw struct group *grp; 921da6c28aaSamw int c; 922da6c28aaSamw 923da6c28aaSamw if ((pwd = getpwnam("root")) != NULL) 924da6c28aaSamw smbd.s_uid = pwd->pw_uid; 925da6c28aaSamw 926da6c28aaSamw if ((grp = getgrnam("sys")) != NULL) 927da6c28aaSamw smbd.s_gid = grp->gr_gid; 928da6c28aaSamw 929dc20a302Sas200622 smbd.s_fg = smb_config_get_fg_flag(); 930da6c28aaSamw 931da6c28aaSamw while ((c = getopt(argc, argv, ":f")) != -1) { 932da6c28aaSamw switch (c) { 933da6c28aaSamw case 'f': 934da6c28aaSamw smbd.s_fg = 1; 935da6c28aaSamw break; 936da6c28aaSamw 937da6c28aaSamw case ':': 938da6c28aaSamw case '?': 939da6c28aaSamw default: 940da6c28aaSamw smbd_usage(stderr); 941da6c28aaSamw return (-1); 942da6c28aaSamw } 943da6c28aaSamw } 944da6c28aaSamw 945da6c28aaSamw return (0); 946da6c28aaSamw } 947da6c28aaSamw 948da6c28aaSamw static void 949da6c28aaSamw smbd_usage(FILE *fp) 950da6c28aaSamw { 951da6c28aaSamw static char *help[] = { 952da6c28aaSamw "-f run program in foreground" 953da6c28aaSamw }; 954da6c28aaSamw 955da6c28aaSamw int i; 956da6c28aaSamw 957da6c28aaSamw (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname); 958da6c28aaSamw 959da6c28aaSamw for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i) 960da6c28aaSamw (void) fprintf(fp, " %s\n", help[i]); 961da6c28aaSamw } 962da6c28aaSamw 963da6c28aaSamw static void 964da6c28aaSamw smbd_report(const char *fmt, ...) 965da6c28aaSamw { 966da6c28aaSamw char buf[128]; 967da6c28aaSamw va_list ap; 968da6c28aaSamw 969da6c28aaSamw if (fmt == NULL) 970da6c28aaSamw return; 971da6c28aaSamw 972da6c28aaSamw va_start(ap, fmt); 973da6c28aaSamw (void) vsnprintf(buf, 128, fmt, ap); 974da6c28aaSamw va_end(ap); 975da6c28aaSamw 976da6c28aaSamw (void) fprintf(stderr, "smbd: %s\n", buf); 977da6c28aaSamw } 978da6c28aaSamw 979a4b239dfSjose borrego static int 980a4b239dfSjose borrego smbd_start_listeners(void) 981a4b239dfSjose borrego { 982a4b239dfSjose borrego int rc1; 983a4b239dfSjose borrego int rc2; 984a4b239dfSjose borrego pthread_attr_t tattr; 985a4b239dfSjose borrego 986a4b239dfSjose borrego (void) pthread_attr_init(&tattr); 987a4b239dfSjose borrego 988a4b239dfSjose borrego if (!smbd.s_nbt_listener_running) { 989a4b239dfSjose borrego rc1 = pthread_create(&smbd.s_nbt_listener_id, &tattr, 990a4b239dfSjose borrego smbd_nbt_listener, NULL); 991a4b239dfSjose borrego if (rc1 != 0) 992a4b239dfSjose borrego smbd_report("unable to start NBT service"); 993a4b239dfSjose borrego else 994a4b239dfSjose borrego smbd.s_nbt_listener_running = B_TRUE; 995a4b239dfSjose borrego } 996a4b239dfSjose borrego 997a4b239dfSjose borrego if (!smbd.s_tcp_listener_running) { 998a4b239dfSjose borrego rc2 = pthread_create(&smbd.s_tcp_listener_id, &tattr, 999a4b239dfSjose borrego smbd_tcp_listener, NULL); 1000a4b239dfSjose borrego if (rc2 != 0) 1001a4b239dfSjose borrego smbd_report("unable to start TCP service"); 1002a4b239dfSjose borrego else 1003a4b239dfSjose borrego smbd.s_tcp_listener_running = B_TRUE; 1004a4b239dfSjose borrego } 1005a4b239dfSjose borrego 1006a4b239dfSjose borrego (void) pthread_attr_destroy(&tattr); 1007a4b239dfSjose borrego 1008a4b239dfSjose borrego if (rc1 != 0) 1009a4b239dfSjose borrego return (rc1); 1010a4b239dfSjose borrego return (rc2); 1011a4b239dfSjose borrego } 1012a4b239dfSjose borrego 1013a4b239dfSjose borrego static void 1014a4b239dfSjose borrego smbd_stop_listeners(void) 1015a4b239dfSjose borrego { 1016a4b239dfSjose borrego void *status; 1017a4b239dfSjose borrego 1018a4b239dfSjose borrego if (smbd.s_nbt_listener_running) { 1019a4b239dfSjose borrego (void) pthread_kill(smbd.s_nbt_listener_id, SIGTERM); 1020a4b239dfSjose borrego (void) pthread_join(smbd.s_nbt_listener_id, &status); 1021a4b239dfSjose borrego smbd.s_nbt_listener_running = B_FALSE; 1022a4b239dfSjose borrego } 1023a4b239dfSjose borrego 1024a4b239dfSjose borrego if (smbd.s_tcp_listener_running) { 1025a4b239dfSjose borrego (void) pthread_kill(smbd.s_tcp_listener_id, SIGTERM); 1026a4b239dfSjose borrego (void) pthread_join(smbd.s_tcp_listener_id, &status); 1027a4b239dfSjose borrego smbd.s_tcp_listener_running = B_FALSE; 1028a4b239dfSjose borrego } 1029a4b239dfSjose borrego } 1030a4b239dfSjose borrego 1031da6c28aaSamw /* 103229bd2886SAlan Wright * Perform fatal error exit. 103329bd2886SAlan Wright */ 103429bd2886SAlan Wright static void 103529bd2886SAlan Wright smbd_fatal_error(const char *msg) 103629bd2886SAlan Wright { 103729bd2886SAlan Wright if (msg == NULL) 103829bd2886SAlan Wright msg = "Fatal error"; 103929bd2886SAlan Wright 104029bd2886SAlan Wright smbd_report("%s", msg); 104129bd2886SAlan Wright smbd.s_fatal_error = B_TRUE; 104229bd2886SAlan Wright (void) kill(smbd.s_pid, SIGTERM); 104329bd2886SAlan Wright } 104429bd2886SAlan Wright 104529bd2886SAlan Wright /*ARGSUSED*/ 104629bd2886SAlan Wright static void * 104729bd2886SAlan Wright smbd_nbt_receiver(void *arg) 104829bd2886SAlan Wright { 104929bd2886SAlan Wright (void) smb_kmod_nbtreceive(); 105029bd2886SAlan Wright return (NULL); 105129bd2886SAlan Wright } 105229bd2886SAlan Wright 105329bd2886SAlan Wright /*ARGSUSED*/ 105429bd2886SAlan Wright static void * 105529bd2886SAlan Wright smbd_nbt_listener(void *arg) 105629bd2886SAlan Wright { 105729bd2886SAlan Wright pthread_attr_t tattr; 105829bd2886SAlan Wright sigset_t set; 105929bd2886SAlan Wright sigset_t oset; 106029bd2886SAlan Wright pthread_t tid; 106129bd2886SAlan Wright int error = 0; 106229bd2886SAlan Wright 106329bd2886SAlan Wright (void) sigfillset(&set); 106429bd2886SAlan Wright (void) sigdelset(&set, SIGTERM); 106529bd2886SAlan Wright (void) sigdelset(&set, SIGINT); 106629bd2886SAlan Wright (void) pthread_sigmask(SIG_SETMASK, &set, &oset); 106729bd2886SAlan Wright (void) pthread_attr_init(&tattr); 106829bd2886SAlan Wright (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 106929bd2886SAlan Wright 107029bd2886SAlan Wright while (smb_kmod_nbtlisten(error) == 0) 107129bd2886SAlan Wright error = pthread_create(&tid, &tattr, smbd_nbt_receiver, NULL); 107229bd2886SAlan Wright 107329bd2886SAlan Wright (void) pthread_attr_destroy(&tattr); 107429bd2886SAlan Wright 107529bd2886SAlan Wright if (!smbd.s_shutting_down) 107629bd2886SAlan Wright smbd_fatal_error("NBT listener thread terminated unexpectedly"); 107729bd2886SAlan Wright 107829bd2886SAlan Wright return (NULL); 107929bd2886SAlan Wright } 108029bd2886SAlan Wright 108129bd2886SAlan Wright /*ARGSUSED*/ 108229bd2886SAlan Wright static void * 108329bd2886SAlan Wright smbd_tcp_receiver(void *arg) 108429bd2886SAlan Wright { 108529bd2886SAlan Wright (void) smb_kmod_tcpreceive(); 108629bd2886SAlan Wright return (NULL); 108729bd2886SAlan Wright } 108829bd2886SAlan Wright 108929bd2886SAlan Wright /*ARGSUSED*/ 109029bd2886SAlan Wright static void * 109129bd2886SAlan Wright smbd_tcp_listener(void *arg) 109229bd2886SAlan Wright { 109329bd2886SAlan Wright pthread_attr_t tattr; 109429bd2886SAlan Wright sigset_t set; 109529bd2886SAlan Wright sigset_t oset; 109629bd2886SAlan Wright pthread_t tid; 109729bd2886SAlan Wright int error = 0; 109829bd2886SAlan Wright 109929bd2886SAlan Wright (void) sigfillset(&set); 110029bd2886SAlan Wright (void) sigdelset(&set, SIGTERM); 110129bd2886SAlan Wright (void) sigdelset(&set, SIGINT); 110229bd2886SAlan Wright (void) pthread_sigmask(SIG_SETMASK, &set, &oset); 110329bd2886SAlan Wright (void) pthread_attr_init(&tattr); 110429bd2886SAlan Wright (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 110529bd2886SAlan Wright 110629bd2886SAlan Wright while (smb_kmod_tcplisten(error) == 0) 110729bd2886SAlan Wright error = pthread_create(&tid, &tattr, smbd_tcp_receiver, NULL); 110829bd2886SAlan Wright 110929bd2886SAlan Wright (void) pthread_attr_destroy(&tattr); 111029bd2886SAlan Wright 111129bd2886SAlan Wright if (!smbd.s_shutting_down) 111229bd2886SAlan Wright smbd_fatal_error("TCP listener thread terminated unexpectedly"); 111329bd2886SAlan Wright 111429bd2886SAlan Wright return (NULL); 111529bd2886SAlan Wright } 111629bd2886SAlan Wright 111729bd2886SAlan Wright /* 1118da6c28aaSamw * Enable libumem debugging by default on DEBUG builds. 1119da6c28aaSamw */ 1120da6c28aaSamw #ifdef DEBUG 1121da6c28aaSamw const char * 1122da6c28aaSamw _umem_debug_init(void) 1123da6c28aaSamw { 1124da6c28aaSamw return ("default,verbose"); /* $UMEM_DEBUG setting */ 1125da6c28aaSamw } 1126da6c28aaSamw 1127da6c28aaSamw const char * 1128da6c28aaSamw _umem_logging_init(void) 1129da6c28aaSamw { 1130da6c28aaSamw return ("fail,contents"); /* $UMEM_LOGGING setting */ 1131da6c28aaSamw } 1132da6c28aaSamw #endif 1133