15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*5772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <sys/types.h> 295331Samw #include <sys/stat.h> 305331Samw #include <sys/ioccom.h> 315331Samw #include <stdio.h> 325331Samw #include <string.h> 335331Samw #include <strings.h> 345331Samw #include <stdlib.h> 355331Samw #include <unistd.h> 365331Samw #include <stdarg.h> 375331Samw #include <fcntl.h> 385331Samw #include <wait.h> 395331Samw #include <signal.h> 405331Samw #include <libscf.h> 415331Samw #include <limits.h> 425331Samw #include <priv_utils.h> 435331Samw #include <door.h> 445331Samw #include <errno.h> 455331Samw #include <syslog.h> 465331Samw #include <pthread.h> 475331Samw #include <time.h> 485331Samw #include <libscf.h> 495331Samw #include <zone.h> 505331Samw #include <tzfile.h> 515331Samw #include <libgen.h> 525331Samw #include <pwd.h> 535331Samw #include <grp.h> 545331Samw 555331Samw #include <smbsrv/smb_door_svc.h> 565331Samw #include <smbsrv/smb_ioctl.h> 575331Samw #include <smbsrv/libsmb.h> 585331Samw #include <smbsrv/libsmbns.h> 595331Samw #include <smbsrv/libsmbrdr.h> 605331Samw #include <smbsrv/libmlsvc.h> 615331Samw 625331Samw #include "smbd.h" 635331Samw 645331Samw #define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" 655521Sas200622 #define SMB_VARRUN_DIR "/var/run/smb" 665521Sas200622 #define SMB_CCACHE SMB_VARRUN_DIR "/ccache" 675331Samw #define SMB_DBDIR "/var/smb" 685331Samw 695331Samw extern void smb_netbios_name_reconfig(); 705331Samw extern void smb_browser_config(); 715331Samw 725331Samw static int smbd_daemonize_init(void); 735331Samw static void smbd_daemonize_fini(int, int); 745331Samw 755331Samw static int smbd_kernel_bind(void); 765331Samw static void smbd_kernel_unbind(void); 775331Samw static int smbd_already_running(void); 785331Samw 795521Sas200622 static void smbd_remove_ccache(void); 805331Samw static int smbd_service_init(void); 815331Samw static void smbd_service_fini(void); 825331Samw 835331Samw static int smbd_setup_options(int argc, char *argv[]); 845331Samw static void smbd_usage(FILE *fp); 855331Samw static void smbd_report(const char *fmt, ...); 865331Samw 875331Samw static void smbd_sig_handler(int sig); 885331Samw 895331Samw static int smbd_localtime_init(void); 905331Samw static void *smbd_localtime_monitor(void *arg); 915331Samw 925331Samw extern time_t altzone; 935331Samw 945331Samw static pthread_t localtime_thr; 955331Samw 965331Samw static int smbd_refresh_init(void); 975331Samw static void smbd_refresh_fini(void); 985331Samw static void *smbd_refresh_monitor(void *); 995331Samw static pthread_t refresh_thr; 1005331Samw static pthread_cond_t refresh_cond; 1015331Samw static pthread_mutex_t refresh_mutex; 1025331Samw 1035331Samw static smbd_t smbd; 1045331Samw 1055331Samw /* 1065331Samw * smbd user land daemon 1075331Samw * 1085331Samw * Use SMF error codes only on return or exit. 1095331Samw */ 1105331Samw int 1115331Samw main(int argc, char *argv[]) 1125331Samw { 1135331Samw struct sigaction act; 1145331Samw sigset_t set; 1155331Samw uid_t uid; 1165331Samw int pfd = -1; 1175331Samw 1185331Samw smbd.s_pname = basename(argv[0]); 1195331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1205331Samw 1215331Samw if (smbd_setup_options(argc, argv) != 0) 1225331Samw return (SMF_EXIT_ERR_FATAL); 1235331Samw 1245331Samw if ((uid = getuid()) != smbd.s_uid) { 1255331Samw smbd_report("user %d: %s", uid, strerror(EPERM)); 1265331Samw return (SMF_EXIT_ERR_FATAL); 1275331Samw } 1285331Samw 1295331Samw if (getzoneid() != GLOBAL_ZONEID) { 1305331Samw smbd_report("non-global zones are not supported"); 1315331Samw return (SMF_EXIT_ERR_FATAL); 1325331Samw } 1335331Samw 1345331Samw if (is_system_labeled()) { 1355331Samw smbd_report("Trusted Extensions not supported"); 1365331Samw return (SMF_EXIT_ERR_FATAL); 1375331Samw } 1385331Samw 1395331Samw if (smbd_already_running()) 1405331Samw return (SMF_EXIT_OK); 1415331Samw 1425331Samw (void) sigfillset(&set); 1435331Samw (void) sigdelset(&set, SIGABRT); 1445331Samw 1455331Samw (void) sigfillset(&act.sa_mask); 1465331Samw act.sa_handler = smbd_sig_handler; 1475331Samw act.sa_flags = 0; 1485331Samw 1495331Samw (void) sigaction(SIGTERM, &act, NULL); 1505331Samw (void) sigaction(SIGHUP, &act, NULL); 1515331Samw (void) sigaction(SIGINT, &act, NULL); 1525331Samw (void) sigaction(SIGPIPE, &act, NULL); 1535331Samw 1545331Samw (void) sigdelset(&set, SIGTERM); 1555331Samw (void) sigdelset(&set, SIGHUP); 1565331Samw (void) sigdelset(&set, SIGINT); 1575331Samw (void) sigdelset(&set, SIGPIPE); 1585331Samw 1595331Samw if (smbd.s_fg) { 1605331Samw (void) sigdelset(&set, SIGTSTP); 1615331Samw (void) sigdelset(&set, SIGTTIN); 1625331Samw (void) sigdelset(&set, SIGTTOU); 1635331Samw 1645331Samw if (smbd_service_init() != 0) { 1655331Samw smbd_report("service initialization failed"); 1665331Samw exit(SMF_EXIT_ERR_FATAL); 1675331Samw } 1685331Samw } else { 1695331Samw /* 1705331Samw * "pfd" is a pipe descriptor -- any fatal errors 1715331Samw * during subsequent initialization of the child 1725331Samw * process should be written to this pipe and the 1735331Samw * parent will report this error as the exit status. 1745331Samw */ 1755331Samw pfd = smbd_daemonize_init(); 1765331Samw 1775331Samw if (smbd_service_init() != 0) { 1785331Samw smbd_report("daemon initialization failed"); 1795331Samw exit(SMF_EXIT_ERR_FATAL); 1805331Samw } 1815331Samw 1825331Samw smbd_daemonize_fini(pfd, SMF_EXIT_OK); 1835331Samw } 1845331Samw 1855331Samw (void) atexit(smbd_service_fini); 1865331Samw 1875331Samw while (!smbd.s_shutdown_flag) { 1885331Samw (void) sigsuspend(&set); 1895331Samw 1905331Samw switch (smbd.s_sigval) { 1915331Samw case 0: 1925331Samw break; 1935331Samw 1945331Samw case SIGPIPE: 1955331Samw break; 1965331Samw 1975331Samw case SIGHUP: 1985331Samw /* Refresh config was triggered */ 1995331Samw if (smbd.s_fg) 2005331Samw smbd_report("reconfiguration requested"); 2015331Samw (void) pthread_cond_signal(&refresh_cond); 2025331Samw break; 2035331Samw 2045331Samw default: 2055331Samw /* 2065331Samw * Typically SIGINT or SIGTERM. 2075331Samw */ 2085331Samw smbd.s_shutdown_flag = 1; 2095331Samw break; 2105331Samw } 2115331Samw 2125331Samw smbd.s_sigval = 0; 2135331Samw } 2145331Samw 2155331Samw smbd_service_fini(); 2165331Samw closelog(); 2175331Samw return (SMF_EXIT_OK); 2185331Samw } 2195331Samw 2205331Samw /* 2215331Samw * This function will fork off a child process, 2225331Samw * from which only the child will return. 2235331Samw * 2245331Samw * Use SMF error codes only on exit. 2255331Samw */ 2265331Samw static int 2275331Samw smbd_daemonize_init(void) 2285331Samw { 2295331Samw int status, pfds[2]; 2305331Samw sigset_t set, oset; 2315331Samw pid_t pid; 2325331Samw int rc; 2335331Samw 2345331Samw /* 2355331Samw * Reset privileges to the minimum set required. We continue 2365331Samw * to run as root to create and access files in /var. 2375331Samw */ 2385331Samw rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS, 2395331Samw smbd.s_uid, smbd.s_gid, 2405331Samw PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT, 2415331Samw PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL); 2425331Samw 2435331Samw if (rc != 0) { 2445331Samw smbd_report("insufficient privileges"); 2455331Samw exit(SMF_EXIT_ERR_FATAL); 2465331Samw } 2475331Samw 2485331Samw /* 2495331Samw * Block all signals prior to the fork and leave them blocked in the 2505331Samw * parent so we don't get in a situation where the parent gets SIGINT 2515331Samw * and returns non-zero exit status and the child is actually running. 2525331Samw * In the child, restore the signal mask once we've done our setsid(). 2535331Samw */ 2545331Samw (void) sigfillset(&set); 2555331Samw (void) sigdelset(&set, SIGABRT); 2565331Samw (void) sigprocmask(SIG_BLOCK, &set, &oset); 2575331Samw 2585331Samw if (pipe(pfds) == -1) { 2595331Samw smbd_report("unable to create pipe"); 2605331Samw exit(SMF_EXIT_ERR_FATAL); 2615331Samw } 2625331Samw 2635331Samw closelog(); 2645331Samw 2655331Samw if ((pid = fork()) == -1) { 2665331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2675331Samw smbd_report("unable to fork"); 2685331Samw closelog(); 2695331Samw exit(SMF_EXIT_ERR_FATAL); 2705331Samw } 2715331Samw 2725331Samw /* 2735331Samw * If we're the parent process, wait for either the child to send us 2745331Samw * the appropriate exit status over the pipe or for the read to fail 2755331Samw * (presumably with 0 for EOF if our child terminated abnormally). 2765331Samw * If the read fails, exit with either the child's exit status if it 2775331Samw * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. 2785331Samw */ 2795331Samw if (pid != 0) { 2805331Samw (void) close(pfds[1]); 2815331Samw 2825331Samw if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 2835331Samw _exit(status); 2845331Samw 2855331Samw if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 2865331Samw _exit(WEXITSTATUS(status)); 2875331Samw 2885331Samw _exit(SMF_EXIT_ERR_FATAL); 2895331Samw } 2905331Samw 2915331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2925331Samw smbd.s_pid = getpid(); 2935331Samw (void) setsid(); 2945331Samw (void) sigprocmask(SIG_SETMASK, &oset, NULL); 2955331Samw (void) chdir("/"); 2965331Samw (void) umask(022); 2975331Samw (void) close(pfds[0]); 2985331Samw 2995331Samw return (pfds[1]); 3005331Samw } 3015331Samw 3025331Samw static void 3035331Samw smbd_daemonize_fini(int fd, int exit_status) 3045331Samw { 3055331Samw /* 3065331Samw * Now that we're running, if a pipe fd was specified, write an exit 3075331Samw * status to it to indicate that our parent process can safely detach. 3085331Samw * Then proceed to loading the remaining non-built-in modules. 3095331Samw */ 3105331Samw if (fd >= 0) 3115331Samw (void) write(fd, &exit_status, sizeof (exit_status)); 3125331Samw 3135331Samw (void) close(fd); 3145331Samw 3155331Samw if ((fd = open("/dev/null", O_RDWR)) >= 0) { 3165331Samw (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 3175331Samw (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 3185331Samw (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 3195331Samw (void) close(fd); 3205331Samw } 3215331Samw 3225331Samw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 3235331Samw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL); 3245331Samw } 3255331Samw 3265331Samw static int 3275331Samw smbd_service_init(void) 3285331Samw { 3295331Samw static char *dir[] = { 3305331Samw SMB_DBDIR, /* smbpasswd */ 3315521Sas200622 SMB_VARRUN_DIR /* KRB credential cache */ 3325331Samw }; 3335331Samw 3345521Sas200622 int door_id; 3355331Samw int rc; 3365331Samw uint32_t mode; 3375331Samw char resource_domain[SMB_PI_MAX_DOMAIN]; 3385331Samw int i; 3395331Samw 3405331Samw smbd.s_drv_fd = -1; 3415331Samw 3425331Samw for (i = 0; i < (sizeof (dir)/sizeof (dir[0])); ++i) { 3435331Samw errno = 0; 3445331Samw 3455331Samw if ((mkdir(dir[i], 0700) < 0) && (errno != EEXIST)) { 3465331Samw smbd_report("mkdir %s: %s", dir[i], strerror(errno)); 3475331Samw return (1); 3485331Samw } 3495331Samw } 3505331Samw 3515331Samw /* 3525331Samw * Set KRB5CCNAME (for the SMB credential cache) in the environment. 3535331Samw */ 3545521Sas200622 if (putenv("KRB5CCNAME=" SMB_CCACHE) != 0) { 3555331Samw smbd_report("unable to set KRB5CCNAME"); 3565331Samw return (1); 3575331Samw } 3585331Samw 3595331Samw (void) oem_language_set("english"); 3605331Samw 3615331Samw if (!nt_builtin_init()) { 3625331Samw smbd_report("out of memory"); 3635331Samw return (1); 3645331Samw } 3655331Samw 366*5772Sas200622 (void) smb_nicmon_start(); 367*5772Sas200622 if (dns_msgid_init() != 0) { 368*5772Sas200622 smbd_report("DNS message id initialization failed"); 3695331Samw return (1); 3705331Samw } 3715331Samw 3725331Samw smbrdr_init(); 3735331Samw 374*5772Sas200622 if (smb_netbios_start() != 0) 375*5772Sas200622 smbd_report("NetBIOS services failed to start"); 376*5772Sas200622 else 377*5772Sas200622 smbd_report("NetBIOS services started"); 378*5772Sas200622 3795331Samw if (smb_netlogon_init() != 0) { 3805331Samw smbd_report("netlogon initialization failed"); 3815331Samw return (1); 3825331Samw } 3835331Samw 384*5772Sas200622 (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN); 3855331Samw (void) utf8_strupr(resource_domain); 3865331Samw 387*5772Sas200622 mode = smb_config_get_secmode(); 3885331Samw if (mode == SMB_SECMODE_DOMAIN) 3895331Samw (void) locate_resource_pdc(resource_domain); 3905331Samw 3915331Samw /* Get the ID map client handle */ 3925331Samw if ((rc = smb_idmap_start()) != 0) { 3935331Samw smbd_report("no idmap handle"); 3945331Samw return (rc); 3955331Samw } 3965331Samw 3975331Samw if ((rc = nt_domain_init(resource_domain, mode)) != 0) { 398*5772Sas200622 if (rc == SMB_DOMAIN_NOMACHINE_SID) { 399*5772Sas200622 smbd_report( 400*5772Sas200622 "no machine SID: check idmap configuration"); 401*5772Sas200622 return (rc); 402*5772Sas200622 } 4035331Samw } 4045331Samw 405*5772Sas200622 ads_init(); 4065331Samw if ((rc = mlsvc_init()) != 0) { 4075331Samw smbd_report("msrpc initialization failed"); 4085331Samw return (rc); 4095331Samw } 4105331Samw 4115331Samw if (smb_lmshrd_srv_start() != 0) { 4125331Samw smbd_report("share initialization failed"); 4135331Samw } 4145331Samw 4155331Samw /* XXX following will get removed */ 4165331Samw (void) smb_doorsrv_start(); 4175331Samw if ((rc = smb_door_srv_start()) != 0) 4185331Samw return (rc); 4195331Samw 4205331Samw if ((rc = smbd_refresh_init()) != 0) 4215331Samw return (rc); 4225331Samw 4235331Samw /* Call dyndns update - Just in case its configured to refresh DNS */ 424*5772Sas200622 if (smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 4255331Samw (void) dyndns_update(); 4265331Samw 4275331Samw if ((rc = smbd_kernel_bind()) != 0) 4285331Samw smbd_report("kernel bind error: %s", strerror(errno)); 4295331Samw 4305331Samw (void) smbd_localtime_init(); 4315331Samw 4325521Sas200622 if ((door_id = smb_winpipe_doorsvc_start()) == -1) { 4335521Sas200622 smbd_report("winpipe initialization failed %s", 4345521Sas200622 strerror(errno)); 4355521Sas200622 return (rc); 4365521Sas200622 } else { 4375521Sas200622 if (ioctl(smbd.s_drv_fd, SMB_IOC_WINPIPE, &door_id) < 0) 4385521Sas200622 smbd_report("winpipe ioctl: %s", strerror(errno)); 4395521Sas200622 } 4405521Sas200622 441*5772Sas200622 (void) smb_lgrp_start(); 4425331Samw return (lmshare_start()); 4435331Samw } 4445331Samw 4455521Sas200622 static void 4465521Sas200622 smbd_remove_ccache(void) 4475521Sas200622 { 4485521Sas200622 if ((remove(SMB_CCACHE) < 0) && (errno != ENOENT)) 4495521Sas200622 smbd_report("failed to remove SMB ccache"); 4505521Sas200622 } 4515521Sas200622 4525331Samw /* 4535331Samw * Close the kernel service and shutdown smbd services. 4545331Samw * This function is registered with atexit(): ensure that anything 4555331Samw * called from here is safe to be called multiple times. 4565331Samw */ 4575331Samw static void 4585331Samw smbd_service_fini(void) 4595331Samw { 4605521Sas200622 smb_winpipe_doorsvc_stop(); 4615331Samw nt_builtin_fini(); 4625331Samw smbd_refresh_fini(); 4635331Samw smbd_kernel_unbind(); 4645331Samw smb_door_srv_stop(); 4655331Samw smb_doorsrv_stop(); 4665331Samw smb_lmshrd_srv_stop(); 4675331Samw lmshare_stop(); 4685331Samw smb_nicmon_stop(); 4695331Samw smb_idmap_stop(); 470*5772Sas200622 smb_lgrp_stop(); 4715521Sas200622 smbd_remove_ccache(); 4725521Sas200622 4735331Samw } 4745331Samw 4755331Samw /* 4765331Samw * smbd_refresh_init() 4775331Samw * 4785331Samw * SMB service refresh thread initialization. This thread waits for a 4795331Samw * refresh event and updates the daemon's view of the configuration 4805331Samw * before going back to sleep. 4815331Samw */ 4825331Samw static int 4835331Samw smbd_refresh_init() 4845331Samw { 4855331Samw pthread_attr_t tattr; 4865331Samw pthread_condattr_t cattr; 4875331Samw int rc; 4885331Samw 4895331Samw (void) pthread_condattr_init(&cattr); 4905331Samw (void) pthread_cond_init(&refresh_cond, &cattr); 4915331Samw (void) pthread_condattr_destroy(&cattr); 4925331Samw 4935331Samw (void) pthread_mutex_init(&refresh_mutex, NULL); 4945331Samw 4955331Samw (void) pthread_attr_init(&tattr); 4965331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 4975331Samw rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0); 4985331Samw (void) pthread_attr_destroy(&tattr); 4995331Samw return (rc); 5005331Samw 5015331Samw } 5025331Samw 5035331Samw /* 5045331Samw * smbd_refresh_fini() 5055331Samw * 5065331Samw * Stop the refresh thread. 5075331Samw */ 5085331Samw static void 5095331Samw smbd_refresh_fini() 5105331Samw { 5115331Samw (void) pthread_cancel(refresh_thr); 5125331Samw 5135331Samw (void) pthread_cond_destroy(&refresh_cond); 5145331Samw (void) pthread_mutex_destroy(&refresh_mutex); 5155331Samw } 5165331Samw 5175331Samw /* 5185331Samw * smbd_refresh_monitor() 5195331Samw * 5205331Samw * Wait for a refresh event. When this thread wakes up, update the 5215331Samw * smbd configuration from the SMF config information then go back to 5225331Samw * wait for the next refresh. 5235331Samw */ 5245331Samw /*ARGSUSED*/ 5255331Samw static void * 5265331Samw smbd_refresh_monitor(void *arg) 5275331Samw { 5285331Samw int dummy = 0; 5295331Samw 5305331Samw (void) pthread_mutex_lock(&refresh_mutex); 5315331Samw while (pthread_cond_wait(&refresh_cond, &refresh_mutex) == 0) { 5325331Samw /* 5335331Samw * We've been woken up by a refresh event so go do 5345331Samw * what is necessary. 5355331Samw */ 536*5772Sas200622 ads_refresh(); 5375331Samw smb_nic_build_info(); 5385331Samw (void) smb_netbios_name_reconfig(); 5395331Samw (void) smb_browser_config(); 5405521Sas200622 smbd_remove_ccache(); 5415521Sas200622 if (ioctl(smbd.s_drv_fd, SMB_IOC_CONFIG, &dummy) < 0) { 5425331Samw smbd_report("configuration update ioctl: %s", 5435331Samw strerror(errno)); 5445331Samw } 5455331Samw } 5465331Samw return (NULL); 5475331Samw } 5485331Samw 5495331Samw 5505331Samw /* 5515331Samw * If the door has already been opened by another process (non-zero pid 5525331Samw * in target), we assume that another smbd is already running. If there 5535331Samw * is a race here, it will be caught later when smbsrv is opened because 5545331Samw * only one process is allowed to open the device at a time. 5555331Samw */ 5565331Samw static int 5575331Samw smbd_already_running(void) 5585331Samw { 5595331Samw door_info_t info; 5605331Samw int door; 5615331Samw 5625331Samw if ((door = open(SMBD_DOOR_NAME, O_RDONLY)) < 0) 5635331Samw return (0); 5645331Samw 5655331Samw if (door_info(door, &info) < 0) 5665331Samw return (0); 5675331Samw 5685331Samw if (info.di_target > 0) { 5695331Samw smbd_report("already running: pid %ld\n", info.di_target); 5705331Samw (void) close(door); 5715331Samw return (1); 5725331Samw } 5735331Samw 5745331Samw (void) close(door); 5755331Samw return (0); 5765331Samw } 5775331Samw 5785331Samw static int 5795331Samw smbd_kernel_bind(void) 5805331Samw { 5815331Samw if (smbd.s_drv_fd != -1) 5825331Samw (void) close(smbd.s_drv_fd); 5835331Samw 5845331Samw if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) { 5855331Samw smbd.s_drv_fd = -1; 5865331Samw return (1); 5875331Samw } 5885331Samw return (0); 5895331Samw } 5905331Samw 5915331Samw 5925331Samw /* 5935331Samw * Initialization of the localtime thread. 5945331Samw * Returns 0 on success, an error number if thread creation fails. 5955331Samw */ 5965331Samw 5975331Samw int 5985331Samw smbd_localtime_init(void) 5995331Samw { 6005331Samw pthread_attr_t tattr; 6015331Samw int rc; 6025331Samw 6035331Samw (void) pthread_attr_init(&tattr); 6045331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 6055331Samw rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0); 6065331Samw (void) pthread_attr_destroy(&tattr); 6075331Samw return (rc); 6085331Samw } 6095331Samw 6105331Samw /* 6115331Samw * Local time thread to kernel land. 6125331Samw * Send local gmtoff to kernel module one time at startup 6135331Samw * and each time it changes (up to twice a year). 6145331Samw * Local gmtoff is checked once every 15 minutes and 6155331Samw * since some timezones are aligned on half and qtr hour boundaries, 6165331Samw * once an hour would likely suffice. 6175331Samw */ 6185331Samw 6195331Samw /*ARGSUSED*/ 6205331Samw static void * 6215331Samw smbd_localtime_monitor(void *arg) 6225331Samw { 6235331Samw struct tm local_tm; 6245331Samw time_t secs, gmtoff; 6255331Samw time_t last_gmtoff = -1; 6265331Samw int timeout; 6275331Samw 6285331Samw for (;;) { 6295331Samw gmtoff = -altzone; 6305331Samw 6315331Samw if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) { 6325331Samw if (ioctl(smbd.s_drv_fd, SMB_IOC_GMTOFF, &gmtoff) < 0) { 6335331Samw smbd_report("localtime ioctl: %s", 6345331Samw strerror(errno)); 6355331Samw } 6365331Samw } 6375331Samw 6385331Samw /* 6395331Samw * Align the next iteration on a fifteen minute boundary. 6405331Samw */ 6415331Samw secs = time(0); 6425331Samw (void) localtime_r(&secs, &local_tm); 6435331Samw timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN); 6445331Samw (void) sleep(timeout); 6455331Samw 6465331Samw last_gmtoff = gmtoff; 6475331Samw } 6485331Samw 6495331Samw /*NOTREACHED*/ 6505331Samw return (NULL); 6515331Samw } 6525331Samw 6535331Samw 6545331Samw static void 6555331Samw smbd_kernel_unbind(void) 6565331Samw { 6575331Samw if (smbd.s_drv_fd != -1) { 6585331Samw (void) close(smbd.s_drv_fd); 6595331Samw smbd.s_drv_fd = -1; 6605331Samw } 6615331Samw } 6625331Samw 6635331Samw static void 6645331Samw smbd_sig_handler(int sigval) 6655331Samw { 6665331Samw if (smbd.s_sigval == 0) 6675331Samw smbd.s_sigval = sigval; 6685331Samw } 6695331Samw 6705331Samw /* 6715331Samw * Set up configuration options and parse the command line. 6725331Samw * This function will determine if we will run as a daemon 6735331Samw * or in the foreground. 6745331Samw * 6755331Samw * Failure to find a uid or gid results in using the default (0). 6765331Samw */ 6775331Samw static int 6785331Samw smbd_setup_options(int argc, char *argv[]) 6795331Samw { 6805331Samw struct passwd *pwd; 6815331Samw struct group *grp; 6825331Samw int c; 6835331Samw 6845331Samw if ((pwd = getpwnam("root")) != NULL) 6855331Samw smbd.s_uid = pwd->pw_uid; 6865331Samw 6875331Samw if ((grp = getgrnam("sys")) != NULL) 6885331Samw smbd.s_gid = grp->gr_gid; 6895331Samw 690*5772Sas200622 smbd.s_fg = smb_config_get_fg_flag(); 6915331Samw 6925331Samw while ((c = getopt(argc, argv, ":f")) != -1) { 6935331Samw switch (c) { 6945331Samw case 'f': 6955331Samw smbd.s_fg = 1; 6965331Samw break; 6975331Samw 6985331Samw case ':': 6995331Samw case '?': 7005331Samw default: 7015331Samw smbd_usage(stderr); 7025331Samw return (-1); 7035331Samw } 7045331Samw } 7055331Samw 7065331Samw return (0); 7075331Samw } 7085331Samw 7095331Samw static void 7105331Samw smbd_usage(FILE *fp) 7115331Samw { 7125331Samw static char *help[] = { 7135331Samw "-f run program in foreground" 7145331Samw }; 7155331Samw 7165331Samw int i; 7175331Samw 7185331Samw (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname); 7195331Samw 7205331Samw for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i) 7215331Samw (void) fprintf(fp, " %s\n", help[i]); 7225331Samw } 7235331Samw 7245331Samw static void 7255331Samw smbd_report(const char *fmt, ...) 7265331Samw { 7275331Samw char buf[128]; 7285331Samw va_list ap; 7295331Samw 7305331Samw if (fmt == NULL) 7315331Samw return; 7325331Samw 7335331Samw va_start(ap, fmt); 7345331Samw (void) vsnprintf(buf, 128, fmt, ap); 7355331Samw va_end(ap); 7365331Samw 7375331Samw (void) fprintf(stderr, "smbd: %s\n", buf); 7385331Samw } 7395331Samw 7405331Samw /* 7415331Samw * Enable libumem debugging by default on DEBUG builds. 7425331Samw */ 7435331Samw #ifdef DEBUG 7445331Samw const char * 7455331Samw _umem_debug_init(void) 7465331Samw { 7475331Samw return ("default,verbose"); /* $UMEM_DEBUG setting */ 7485331Samw } 7495331Samw 7505331Samw const char * 7515331Samw _umem_logging_init(void) 7525331Samw { 7535331Samw return ("fail,contents"); /* $UMEM_LOGGING setting */ 7545331Samw } 7555331Samw #endif 756