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 /* 228474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/types.h> 275331Samw #include <sys/stat.h> 285331Samw #include <sys/ioccom.h> 295331Samw #include <stdio.h> 305331Samw #include <string.h> 315331Samw #include <strings.h> 325331Samw #include <stdlib.h> 335331Samw #include <unistd.h> 345331Samw #include <stdarg.h> 355331Samw #include <fcntl.h> 365331Samw #include <wait.h> 375331Samw #include <signal.h> 388334SJose.Borrego@Sun.COM #include <atomic.h> 395331Samw #include <libscf.h> 405331Samw #include <limits.h> 415331Samw #include <priv_utils.h> 425331Samw #include <door.h> 435331Samw #include <errno.h> 445331Samw #include <pthread.h> 455331Samw #include <time.h> 465331Samw #include <libscf.h> 475331Samw #include <zone.h> 485331Samw #include <libgen.h> 495331Samw #include <pwd.h> 505331Samw #include <grp.h> 515331Samw 525331Samw #include <smbsrv/smb_door_svc.h> 535331Samw #include <smbsrv/smb_ioctl.h> 545331Samw #include <smbsrv/libsmb.h> 555331Samw #include <smbsrv/libsmbns.h> 565331Samw #include <smbsrv/libsmbrdr.h> 575331Samw #include <smbsrv/libmlsvc.h> 585331Samw #include "smbd.h" 595331Samw 605331Samw #define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" 615331Samw #define SMB_DBDIR "/var/smb" 625331Samw 636139Sjb150015 extern void *smbd_nbt_listener(void *); 646139Sjb150015 extern void *smbd_tcp_listener(void *); 656139Sjb150015 665331Samw static int smbd_daemonize_init(void); 675331Samw static void smbd_daemonize_fini(int, int); 685331Samw 696432Sas200622 static int smbd_kernel_bind(void); 705331Samw static void smbd_kernel_unbind(void); 715331Samw static int smbd_already_running(void); 725331Samw 735331Samw static int smbd_service_init(void); 745331Samw static void smbd_service_fini(void); 755331Samw 765331Samw static int smbd_setup_options(int argc, char *argv[]); 775331Samw static void smbd_usage(FILE *fp); 785331Samw static void smbd_report(const char *fmt, ...); 795331Samw 805331Samw static void smbd_sig_handler(int sig); 815331Samw 827348SJose.Borrego@Sun.COM static int32_t smbd_gmtoff(void); 835331Samw static int smbd_localtime_init(void); 845331Samw static void *smbd_localtime_monitor(void *arg); 855331Samw 865331Samw static pthread_t localtime_thr; 875331Samw 885331Samw static int smbd_refresh_init(void); 895331Samw static void smbd_refresh_fini(void); 905331Samw static void *smbd_refresh_monitor(void *); 918670SJose.Borrego@Sun.COM static void smbd_refresh_dc(void); 928670SJose.Borrego@Sun.COM 93*9046SJose.Borrego@Sun.COM static int smbd_start_listeners(void); 94*9046SJose.Borrego@Sun.COM static void smbd_stop_listeners(void); 95*9046SJose.Borrego@Sun.COM 965331Samw static pthread_t refresh_thr; 975331Samw static pthread_cond_t refresh_cond; 985331Samw static pthread_mutex_t refresh_mutex; 995331Samw 1006139Sjb150015 smbd_t smbd; 1015331Samw 1025331Samw /* 1035331Samw * smbd user land daemon 1045331Samw * 1055331Samw * Use SMF error codes only on return or exit. 1065331Samw */ 1075331Samw int 1085331Samw main(int argc, char *argv[]) 1095331Samw { 1106432Sas200622 struct sigaction act; 1116432Sas200622 sigset_t set; 1126432Sas200622 uid_t uid; 1136432Sas200622 int pfd = -1; 1148334SJose.Borrego@Sun.COM uint_t sigval; 1155331Samw 1165331Samw smbd.s_pname = basename(argv[0]); 1175331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1185331Samw 1195331Samw if (smbd_setup_options(argc, argv) != 0) 1205331Samw return (SMF_EXIT_ERR_FATAL); 1215331Samw 1225331Samw if ((uid = getuid()) != smbd.s_uid) { 1235331Samw smbd_report("user %d: %s", uid, strerror(EPERM)); 1245331Samw return (SMF_EXIT_ERR_FATAL); 1255331Samw } 1265331Samw 1275331Samw if (getzoneid() != GLOBAL_ZONEID) { 1285331Samw smbd_report("non-global zones are not supported"); 1295331Samw return (SMF_EXIT_ERR_FATAL); 1305331Samw } 1315331Samw 1325331Samw if (is_system_labeled()) { 1335331Samw smbd_report("Trusted Extensions not supported"); 1345331Samw return (SMF_EXIT_ERR_FATAL); 1355331Samw } 1365331Samw 1375331Samw if (smbd_already_running()) 1385331Samw return (SMF_EXIT_OK); 1395331Samw 1405331Samw (void) sigfillset(&set); 1415331Samw (void) sigdelset(&set, SIGABRT); 1425331Samw 1435331Samw (void) sigfillset(&act.sa_mask); 1445331Samw act.sa_handler = smbd_sig_handler; 1455331Samw act.sa_flags = 0; 1465331Samw 1475331Samw (void) sigaction(SIGTERM, &act, NULL); 1485331Samw (void) sigaction(SIGHUP, &act, NULL); 1495331Samw (void) sigaction(SIGINT, &act, NULL); 1505331Samw (void) sigaction(SIGPIPE, &act, NULL); 1515331Samw 1525331Samw (void) sigdelset(&set, SIGTERM); 1535331Samw (void) sigdelset(&set, SIGHUP); 1545331Samw (void) sigdelset(&set, SIGINT); 1555331Samw (void) sigdelset(&set, SIGPIPE); 1565331Samw 1575331Samw if (smbd.s_fg) { 1585331Samw (void) sigdelset(&set, SIGTSTP); 1595331Samw (void) sigdelset(&set, SIGTTIN); 1605331Samw (void) sigdelset(&set, SIGTTOU); 1615331Samw 1625331Samw if (smbd_service_init() != 0) { 1635331Samw smbd_report("service initialization failed"); 1645331Samw exit(SMF_EXIT_ERR_FATAL); 1655331Samw } 1665331Samw } else { 1675331Samw /* 1685331Samw * "pfd" is a pipe descriptor -- any fatal errors 1695331Samw * during subsequent initialization of the child 1705331Samw * process should be written to this pipe and the 1715331Samw * parent will report this error as the exit status. 1725331Samw */ 1735331Samw pfd = smbd_daemonize_init(); 1745331Samw 1755331Samw if (smbd_service_init() != 0) { 1765331Samw smbd_report("daemon initialization failed"); 1775331Samw exit(SMF_EXIT_ERR_FATAL); 1785331Samw } 1795331Samw 1805331Samw smbd_daemonize_fini(pfd, SMF_EXIT_OK); 1815331Samw } 1825331Samw 1835331Samw (void) atexit(smbd_service_fini); 1845331Samw 1858334SJose.Borrego@Sun.COM while (!smbd.s_shutting_down) { 1868334SJose.Borrego@Sun.COM if (smbd.s_sigval == 0 && smbd.s_refreshes == 0) 1877052Samw (void) sigsuspend(&set); 1885331Samw 1898334SJose.Borrego@Sun.COM sigval = atomic_swap_uint(&smbd.s_sigval, 0); 1907052Samw 1917052Samw switch (sigval) { 1925331Samw case 0: 1935331Samw case SIGPIPE: 1945331Samw break; 1955331Samw 1965331Samw case SIGHUP: 1978334SJose.Borrego@Sun.COM syslog(LOG_DEBUG, "refresh requested"); 1985331Samw (void) pthread_cond_signal(&refresh_cond); 1995331Samw break; 2005331Samw 2015331Samw default: 2025331Samw /* 2035331Samw * Typically SIGINT or SIGTERM. 2045331Samw */ 2058334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 2065331Samw break; 2075331Samw } 2085331Samw } 2095331Samw 2105331Samw smbd_service_fini(); 2115331Samw closelog(); 2125331Samw return (SMF_EXIT_OK); 2135331Samw } 2145331Samw 2155331Samw /* 2165331Samw * This function will fork off a child process, 2175331Samw * from which only the child will return. 2185331Samw * 2195331Samw * Use SMF error codes only on exit. 2205331Samw */ 2215331Samw static int 2225331Samw smbd_daemonize_init(void) 2235331Samw { 2245331Samw int status, pfds[2]; 2255331Samw sigset_t set, oset; 2265331Samw pid_t pid; 2275331Samw int rc; 2285331Samw 2295331Samw /* 2305331Samw * Reset privileges to the minimum set required. We continue 2315331Samw * to run as root to create and access files in /var. 2325331Samw */ 2335331Samw rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS, 2345331Samw smbd.s_uid, smbd.s_gid, 2355331Samw PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT, 2365331Samw PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL); 2375331Samw 2385331Samw if (rc != 0) { 2395331Samw smbd_report("insufficient privileges"); 2405331Samw exit(SMF_EXIT_ERR_FATAL); 2415331Samw } 2425331Samw 2435331Samw /* 2445331Samw * Block all signals prior to the fork and leave them blocked in the 2455331Samw * parent so we don't get in a situation where the parent gets SIGINT 2465331Samw * and returns non-zero exit status and the child is actually running. 2475331Samw * In the child, restore the signal mask once we've done our setsid(). 2485331Samw */ 2495331Samw (void) sigfillset(&set); 2505331Samw (void) sigdelset(&set, SIGABRT); 2515331Samw (void) sigprocmask(SIG_BLOCK, &set, &oset); 2525331Samw 2535331Samw if (pipe(pfds) == -1) { 2545331Samw smbd_report("unable to create pipe"); 2555331Samw exit(SMF_EXIT_ERR_FATAL); 2565331Samw } 2575331Samw 2585331Samw closelog(); 2595331Samw 2605331Samw if ((pid = fork()) == -1) { 2615331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2625331Samw smbd_report("unable to fork"); 2635331Samw closelog(); 2645331Samw exit(SMF_EXIT_ERR_FATAL); 2655331Samw } 2665331Samw 2675331Samw /* 2685331Samw * If we're the parent process, wait for either the child to send us 2695331Samw * the appropriate exit status over the pipe or for the read to fail 2705331Samw * (presumably with 0 for EOF if our child terminated abnormally). 2715331Samw * If the read fails, exit with either the child's exit status if it 2725331Samw * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. 2735331Samw */ 2745331Samw if (pid != 0) { 2755331Samw (void) close(pfds[1]); 2765331Samw 2775331Samw if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 2785331Samw _exit(status); 2795331Samw 2805331Samw if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 2815331Samw _exit(WEXITSTATUS(status)); 2825331Samw 2835331Samw _exit(SMF_EXIT_ERR_FATAL); 2845331Samw } 2855331Samw 2865331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2875331Samw smbd.s_pid = getpid(); 2885331Samw (void) setsid(); 2895331Samw (void) sigprocmask(SIG_SETMASK, &oset, NULL); 2905331Samw (void) chdir("/"); 2915331Samw (void) umask(022); 2925331Samw (void) close(pfds[0]); 2935331Samw 2945331Samw return (pfds[1]); 2955331Samw } 2965331Samw 2975331Samw static void 2985331Samw smbd_daemonize_fini(int fd, int exit_status) 2995331Samw { 3005331Samw /* 3015331Samw * Now that we're running, if a pipe fd was specified, write an exit 3025331Samw * status to it to indicate that our parent process can safely detach. 3035331Samw * Then proceed to loading the remaining non-built-in modules. 3045331Samw */ 3055331Samw if (fd >= 0) 3065331Samw (void) write(fd, &exit_status, sizeof (exit_status)); 3075331Samw 3085331Samw (void) close(fd); 3095331Samw 3105331Samw if ((fd = open("/dev/null", O_RDWR)) >= 0) { 3115331Samw (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 3125331Samw (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 3135331Samw (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 3145331Samw (void) close(fd); 3155331Samw } 3165331Samw 3175331Samw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 3185331Samw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL); 3195331Samw } 3205331Samw 3216139Sjb150015 /* 3226139Sjb150015 * smbd_service_init 3236139Sjb150015 */ 3245331Samw static int 3255331Samw smbd_service_init(void) 3265331Samw { 3276432Sas200622 int rc; 3288334SJose.Borrego@Sun.COM char nb_domain[NETBIOS_NAME_SZ]; 3296432Sas200622 3305331Samw smbd.s_drv_fd = -1; 3315331Samw 3326139Sjb150015 if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) { 3336139Sjb150015 smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno)); 3346139Sjb150015 return (1); 3355331Samw } 3365331Samw 3376139Sjb150015 if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) { 3386139Sjb150015 if (rc == -1) 3396139Sjb150015 smbd_report("mkdir %s: %s", SMB_VARRUN_DIR, 3406139Sjb150015 strerror(errno)); 3416139Sjb150015 else 3426139Sjb150015 smbd_report("unable to set KRB5CCNAME"); 3435331Samw return (1); 3445331Samw } 3455331Samw 3466139Sjb150015 3475331Samw (void) oem_language_set("english"); 3485331Samw 3496432Sas200622 if (!smb_wka_init()) { 3505331Samw smbd_report("out of memory"); 3515331Samw return (1); 3525331Samw } 3535331Samw 3546432Sas200622 if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0) 3556432Sas200622 smbd_report("NIC monitoring failed to start"); 3566432Sas200622 3578334SJose.Borrego@Sun.COM (void) dyndns_start(); 3585331Samw smbrdr_init(); 3595331Samw 3605772Sas200622 if (smb_netbios_start() != 0) 3615772Sas200622 smbd_report("NetBIOS services failed to start"); 3625772Sas200622 else 3635772Sas200622 smbd_report("NetBIOS services started"); 3645772Sas200622 3658334SJose.Borrego@Sun.COM (void) smb_getdomainname(nb_domain, NETBIOS_NAME_SZ); 3668334SJose.Borrego@Sun.COM (void) utf8_strupr(nb_domain); 3675331Samw 3685331Samw /* Get the ID map client handle */ 3695331Samw if ((rc = smb_idmap_start()) != 0) { 3705331Samw smbd_report("no idmap handle"); 3715331Samw return (rc); 3725331Samw } 3735331Samw 3746432Sas200622 smbd.s_secmode = smb_config_get_secmode(); 3758334SJose.Borrego@Sun.COM if ((rc = nt_domain_init(nb_domain, smbd.s_secmode)) != 0) { 3765772Sas200622 if (rc == SMB_DOMAIN_NOMACHINE_SID) { 3775772Sas200622 smbd_report( 3785772Sas200622 "no machine SID: check idmap configuration"); 3795772Sas200622 return (rc); 3805772Sas200622 } 3815331Samw } 3825331Samw 3837052Samw smb_ads_init(); 3845331Samw if ((rc = mlsvc_init()) != 0) { 3855331Samw smbd_report("msrpc initialization failed"); 3865331Samw return (rc); 3875331Samw } 3885331Samw 3897348SJose.Borrego@Sun.COM if (smbd.s_secmode == SMB_SECMODE_DOMAIN) 3908334SJose.Borrego@Sun.COM if (smbd_locate_dc_start() != 0) 3917348SJose.Borrego@Sun.COM smbd_report("dc discovery failed %s", strerror(errno)); 3926139Sjb150015 3936432Sas200622 smbd.s_door_srv = smb_door_srv_start(); 3946432Sas200622 if (smbd.s_door_srv < 0) 3955331Samw return (rc); 3965331Samw 3975331Samw if ((rc = smbd_refresh_init()) != 0) 3985331Samw return (rc); 3995331Samw 4008334SJose.Borrego@Sun.COM dyndns_update_zones(); 4015331Samw 4025331Samw (void) smbd_localtime_init(); 4035331Samw 4047052Samw smbd.s_door_opipe = smbd_opipe_dsrv_start(); 4057052Samw if (smbd.s_door_opipe < 0) { 4067052Samw smbd_report("opipe initialization failed %s", 4075521Sas200622 strerror(errno)); 4085521Sas200622 return (rc); 4095521Sas200622 } 4105521Sas200622 4115772Sas200622 (void) smb_lgrp_start(); 4126030Sjb150015 4137052Samw smb_pwd_init(B_TRUE); 4146030Sjb150015 4157961SNatalie.Li@Sun.COM if ((rc = smb_shr_start()) != 0) { 4167961SNatalie.Li@Sun.COM smbd_report("share initialization failed: %s", strerror(errno)); 4177961SNatalie.Li@Sun.COM return (rc); 4187961SNatalie.Li@Sun.COM } 4197961SNatalie.Li@Sun.COM 4207961SNatalie.Li@Sun.COM smbd.s_door_lmshr = smb_share_dsrv_start(); 4217961SNatalie.Li@Sun.COM if (smbd.s_door_lmshr < 0) { 4227961SNatalie.Li@Sun.COM smbd_report("share initialization failed"); 4237961SNatalie.Li@Sun.COM } 4247961SNatalie.Li@Sun.COM 4258334SJose.Borrego@Sun.COM if ((rc = smbd_kernel_bind()) != 0) { 4266139Sjb150015 smbd_report("kernel bind error: %s", strerror(errno)); 4276432Sas200622 return (rc); 4286432Sas200622 } 4295331Samw 4308334SJose.Borrego@Sun.COM if ((rc = smb_shr_load()) != 0) { 4318334SJose.Borrego@Sun.COM smbd_report("failed to start loading shares: %s", 4328334SJose.Borrego@Sun.COM strerror(errno)); 4338334SJose.Borrego@Sun.COM return (rc); 4348334SJose.Borrego@Sun.COM } 4358334SJose.Borrego@Sun.COM 4367348SJose.Borrego@Sun.COM return (0); 4375521Sas200622 } 4385521Sas200622 4395331Samw /* 4405331Samw * Close the kernel service and shutdown smbd services. 4415331Samw * This function is registered with atexit(): ensure that anything 4425331Samw * called from here is safe to be called multiple times. 4435331Samw */ 4445331Samw static void 4455331Samw smbd_service_fini(void) 4465331Samw { 4477052Samw smbd_opipe_dsrv_stop(); 4486432Sas200622 smb_wka_fini(); 4495331Samw smbd_refresh_fini(); 4505331Samw smbd_kernel_unbind(); 4515331Samw smb_door_srv_stop(); 4526771Sjb150015 smb_share_dsrv_stop(); 4537052Samw smb_shr_stop(); 4548334SJose.Borrego@Sun.COM dyndns_stop(); 4555331Samw smb_nicmon_stop(); 4565331Samw smb_idmap_stop(); 4575772Sas200622 smb_lgrp_stop(); 4586139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 4596030Sjb150015 smb_pwd_fini(); 4608474SJose.Borrego@Sun.COM nt_domain_unlink(); 4615331Samw } 4625331Samw 4636139Sjb150015 4645331Samw /* 4655331Samw * smbd_refresh_init() 4665331Samw * 4675331Samw * SMB service refresh thread initialization. This thread waits for a 4685331Samw * refresh event and updates the daemon's view of the configuration 4695331Samw * before going back to sleep. 4705331Samw */ 4715331Samw static int 4725331Samw smbd_refresh_init() 4735331Samw { 4746432Sas200622 pthread_attr_t tattr; 4756432Sas200622 pthread_condattr_t cattr; 4766432Sas200622 int rc; 4775331Samw 4785331Samw (void) pthread_condattr_init(&cattr); 4795331Samw (void) pthread_cond_init(&refresh_cond, &cattr); 4805331Samw (void) pthread_condattr_destroy(&cattr); 4815331Samw 4825331Samw (void) pthread_mutex_init(&refresh_mutex, NULL); 4835331Samw 4845331Samw (void) pthread_attr_init(&tattr); 4855331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 4865331Samw rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0); 4875331Samw (void) pthread_attr_destroy(&tattr); 4886432Sas200622 4895331Samw return (rc); 4905331Samw } 4915331Samw 4925331Samw /* 4935331Samw * smbd_refresh_fini() 4945331Samw * 4955331Samw * Stop the refresh thread. 4965331Samw */ 4975331Samw static void 4985331Samw smbd_refresh_fini() 4995331Samw { 5005331Samw (void) pthread_cancel(refresh_thr); 5015331Samw 5025331Samw (void) pthread_cond_destroy(&refresh_cond); 5035331Samw (void) pthread_mutex_destroy(&refresh_mutex); 5045331Samw } 5055331Samw 5065331Samw /* 5075331Samw * smbd_refresh_monitor() 5085331Samw * 5095331Samw * Wait for a refresh event. When this thread wakes up, update the 5105331Samw * smbd configuration from the SMF config information then go back to 5115331Samw * wait for the next refresh. 5125331Samw */ 5135331Samw /*ARGSUSED*/ 5145331Samw static void * 5155331Samw smbd_refresh_monitor(void *arg) 5165331Samw { 5176432Sas200622 smb_io_t smb_io; 5185331Samw 5196771Sjb150015 bzero(&smb_io, sizeof (smb_io)); 5206771Sjb150015 5218334SJose.Borrego@Sun.COM while (!smbd.s_shutting_down) { 5228334SJose.Borrego@Sun.COM (void) pthread_mutex_lock(&refresh_mutex); 5238334SJose.Borrego@Sun.COM while ((atomic_swap_uint(&smbd.s_refreshes, 0) == 0) && 5248334SJose.Borrego@Sun.COM (!smbd.s_shutting_down)) 5258334SJose.Borrego@Sun.COM (void) pthread_cond_wait(&refresh_cond, &refresh_mutex); 5268334SJose.Borrego@Sun.COM (void) pthread_mutex_unlock(&refresh_mutex); 5278334SJose.Borrego@Sun.COM 5288334SJose.Borrego@Sun.COM if (smbd.s_shutting_down) { 5298334SJose.Borrego@Sun.COM syslog(LOG_DEBUG, "shutting down"); 5308334SJose.Borrego@Sun.COM exit(SMF_EXIT_OK); 5318334SJose.Borrego@Sun.COM } 5328334SJose.Borrego@Sun.COM 5335331Samw /* 5345331Samw * We've been woken up by a refresh event so go do 5355331Samw * what is necessary. 5365331Samw */ 5377052Samw smb_ads_refresh(); 5386139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 5396432Sas200622 5408334SJose.Borrego@Sun.COM /* 5418334SJose.Borrego@Sun.COM * Start the dyndns thread, if required. 5428334SJose.Borrego@Sun.COM * Clear the DNS zones for the existing interfaces 5438334SJose.Borrego@Sun.COM * before updating the NIC interface list. 5448334SJose.Borrego@Sun.COM */ 5458334SJose.Borrego@Sun.COM (void) dyndns_start(); 5468334SJose.Borrego@Sun.COM dyndns_clear_zones(); 5476432Sas200622 5486432Sas200622 /* re-initialize NIC table */ 5496432Sas200622 if (smb_nic_init() != 0) 5506432Sas200622 smbd_report("failed to get NIC information"); 5516432Sas200622 smb_netbios_name_reconfig(); 5526432Sas200622 smb_browser_reconfig(); 5538670SJose.Borrego@Sun.COM smbd_refresh_dc(); 5548334SJose.Borrego@Sun.COM dyndns_update_zones(); 5556432Sas200622 5568334SJose.Borrego@Sun.COM if (smbd_set_netlogon_cred()) { 5576432Sas200622 /* 5588334SJose.Borrego@Sun.COM * Restart required because the domain changed 5598334SJose.Borrego@Sun.COM * or the credential chain setup failed. 5606432Sas200622 */ 5618334SJose.Borrego@Sun.COM if (smb_smf_restart_service() != 0) { 5628334SJose.Borrego@Sun.COM syslog(LOG_ERR, 5638334SJose.Borrego@Sun.COM "unable to restart smb service. " 5648334SJose.Borrego@Sun.COM "Run 'svcs -xv smb/server' for more " 5658334SJose.Borrego@Sun.COM "information."); 5668334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 5678334SJose.Borrego@Sun.COM exit(SMF_EXIT_OK); 5688334SJose.Borrego@Sun.COM } 5698334SJose.Borrego@Sun.COM 5708334SJose.Borrego@Sun.COM break; 5718334SJose.Borrego@Sun.COM } 5728334SJose.Borrego@Sun.COM 5738334SJose.Borrego@Sun.COM if (smbd.s_drv_fd == -1) { 5746432Sas200622 if (smbd_kernel_bind()) { 5756432Sas200622 smbd_report("kernel bind error: %s", 5766432Sas200622 strerror(errno)); 5778334SJose.Borrego@Sun.COM } else { 5788334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5796432Sas200622 } 5806432Sas200622 continue; 5816432Sas200622 } 5826432Sas200622 5838334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5848334SJose.Borrego@Sun.COM 5858334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 5868334SJose.Borrego@Sun.COM 5878167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 5885331Samw smbd_report("configuration update ioctl: %s", 5895331Samw strerror(errno)); 5905331Samw } 5915331Samw } 5928334SJose.Borrego@Sun.COM 5935331Samw return (NULL); 5945331Samw } 5955331Samw 5968670SJose.Borrego@Sun.COM /* 5978670SJose.Borrego@Sun.COM * Update DC information on a refresh. 5988670SJose.Borrego@Sun.COM */ 5998670SJose.Borrego@Sun.COM static void 6008670SJose.Borrego@Sun.COM smbd_refresh_dc(void) 6018670SJose.Borrego@Sun.COM { 6028670SJose.Borrego@Sun.COM char fqdomain[MAXHOSTNAMELEN]; 6038670SJose.Borrego@Sun.COM if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 6048670SJose.Borrego@Sun.COM return; 6058670SJose.Borrego@Sun.COM 6068670SJose.Borrego@Sun.COM if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN)) 6078670SJose.Borrego@Sun.COM return; 6088670SJose.Borrego@Sun.COM 6098670SJose.Borrego@Sun.COM if (smb_locate_dc(fqdomain, "", NULL)) 6108670SJose.Borrego@Sun.COM smbd_report("DC discovery failed"); 6118670SJose.Borrego@Sun.COM } 6128670SJose.Borrego@Sun.COM 6138334SJose.Borrego@Sun.COM void 6148334SJose.Borrego@Sun.COM smbd_set_secmode(int secmode) 6158334SJose.Borrego@Sun.COM { 6168334SJose.Borrego@Sun.COM switch (secmode) { 6178334SJose.Borrego@Sun.COM case SMB_SECMODE_WORKGRP: 6188334SJose.Borrego@Sun.COM case SMB_SECMODE_DOMAIN: 6198334SJose.Borrego@Sun.COM (void) smb_config_set_secmode(secmode); 6208334SJose.Borrego@Sun.COM smbd.s_secmode = secmode; 6218334SJose.Borrego@Sun.COM break; 6228334SJose.Borrego@Sun.COM 6238334SJose.Borrego@Sun.COM default: 6248334SJose.Borrego@Sun.COM syslog(LOG_ERR, "invalid security mode: %d", secmode); 6258334SJose.Borrego@Sun.COM syslog(LOG_ERR, "entering maintenance mode"); 6268334SJose.Borrego@Sun.COM (void) smb_smf_maintenance_mode(); 6278334SJose.Borrego@Sun.COM } 6288334SJose.Borrego@Sun.COM } 6295331Samw 6305331Samw /* 6315331Samw * If the door has already been opened by another process (non-zero pid 6325331Samw * in target), we assume that another smbd is already running. If there 6335331Samw * is a race here, it will be caught later when smbsrv is opened because 6345331Samw * only one process is allowed to open the device at a time. 6355331Samw */ 6365331Samw static int 6375331Samw smbd_already_running(void) 6385331Samw { 6395331Samw door_info_t info; 6405331Samw int door; 6415331Samw 6426139Sjb150015 if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) 6435331Samw return (0); 6445331Samw 6455331Samw if (door_info(door, &info) < 0) 6465331Samw return (0); 6475331Samw 6485331Samw if (info.di_target > 0) { 6495331Samw smbd_report("already running: pid %ld\n", info.di_target); 6505331Samw (void) close(door); 6515331Samw return (1); 6525331Samw } 6535331Samw 6545331Samw (void) close(door); 6555331Samw return (0); 6565331Samw } 6575331Samw 6586139Sjb150015 /* 6596139Sjb150015 * smbd_kernel_bind 6606432Sas200622 * 6616432Sas200622 * This function open the smbsrv device and start the kernel service. 6626139Sjb150015 */ 6635331Samw static int 6646432Sas200622 smbd_kernel_bind(void) 6655331Samw { 6666139Sjb150015 smb_io_t smb_io; 6676139Sjb150015 int rc; 6686139Sjb150015 6696139Sjb150015 bzero(&smb_io, sizeof (smb_io)); 6706139Sjb150015 6718334SJose.Borrego@Sun.COM smbd_kernel_unbind(); 6725331Samw 6735331Samw if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) { 6745331Samw smbd.s_drv_fd = -1; 6756139Sjb150015 return (errno); 6766139Sjb150015 } 6778167Samw@Sun.COM 6788334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 6798334SJose.Borrego@Sun.COM 6808167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 6816139Sjb150015 (void) close(smbd.s_drv_fd); 6826139Sjb150015 smbd.s_drv_fd = -1; 6836139Sjb150015 return (errno); 6846139Sjb150015 } 6857348SJose.Borrego@Sun.COM smb_io.sio_data.gmtoff = smbd_gmtoff(); 6868167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 6876139Sjb150015 (void) close(smbd.s_drv_fd); 6886139Sjb150015 smbd.s_drv_fd = -1; 6896139Sjb150015 return (errno); 6905331Samw } 6917052Samw smb_io.sio_data.start.opipe = smbd.s_door_opipe; 6926432Sas200622 smb_io.sio_data.start.lmshrd = smbd.s_door_lmshr; 6936432Sas200622 smb_io.sio_data.start.udoor = smbd.s_door_srv; 6948167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_START, &smb_io) < 0) { 6956139Sjb150015 (void) close(smbd.s_drv_fd); 6966139Sjb150015 smbd.s_drv_fd = -1; 6976139Sjb150015 return (errno); 6986139Sjb150015 } 6996139Sjb150015 700*9046SJose.Borrego@Sun.COM rc = smbd_start_listeners(); 7016139Sjb150015 if (rc == 0) { 7027826SJose.Borrego@Sun.COM smbd.s_kbound = B_TRUE; 7037826SJose.Borrego@Sun.COM return (0); 7046432Sas200622 } 705*9046SJose.Borrego@Sun.COM smbd_stop_listeners(); 7066139Sjb150015 (void) close(smbd.s_drv_fd); 7076139Sjb150015 smbd.s_drv_fd = -1; 7086139Sjb150015 return (rc); 7095331Samw } 7105331Samw 7116139Sjb150015 /* 7126139Sjb150015 * smbd_kernel_unbind 7136139Sjb150015 */ 7146139Sjb150015 static void 7156139Sjb150015 smbd_kernel_unbind(void) 7166139Sjb150015 { 7176139Sjb150015 if (smbd.s_drv_fd != -1) { 718*9046SJose.Borrego@Sun.COM smbd_stop_listeners(); 7196139Sjb150015 (void) close(smbd.s_drv_fd); 7206139Sjb150015 smbd.s_drv_fd = -1; 7216432Sas200622 smbd.s_kbound = B_FALSE; 7226139Sjb150015 } 7236139Sjb150015 } 7245331Samw 7258167Samw@Sun.COM int 7268167Samw@Sun.COM smbd_ioctl(int cmd, smb_io_t *smb_io) 7278167Samw@Sun.COM { 7288167Samw@Sun.COM smb_io->sio_version = SMB_IOC_VERSION; 7298167Samw@Sun.COM smb_io->sio_crc = 0; 7308167Samw@Sun.COM smb_io->sio_crc = smb_crc_gen((uint8_t *)smb_io, sizeof (smb_io_t)); 7318167Samw@Sun.COM 7328167Samw@Sun.COM return (ioctl(smbd.s_drv_fd, cmd, smb_io)); 7338167Samw@Sun.COM } 7348167Samw@Sun.COM 7355331Samw /* 7365331Samw * Initialization of the localtime thread. 7375331Samw * Returns 0 on success, an error number if thread creation fails. 7385331Samw */ 7395331Samw 7405331Samw int 7415331Samw smbd_localtime_init(void) 7425331Samw { 7435331Samw pthread_attr_t tattr; 7445331Samw int rc; 7455331Samw 7465331Samw (void) pthread_attr_init(&tattr); 7475331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 7485331Samw rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0); 7495331Samw (void) pthread_attr_destroy(&tattr); 7505331Samw return (rc); 7515331Samw } 7525331Samw 7535331Samw /* 7545331Samw * Local time thread to kernel land. 7555331Samw * Send local gmtoff to kernel module one time at startup 7565331Samw * and each time it changes (up to twice a year). 7575331Samw * Local gmtoff is checked once every 15 minutes and 7585331Samw * since some timezones are aligned on half and qtr hour boundaries, 7595331Samw * once an hour would likely suffice. 7605331Samw */ 7615331Samw 7625331Samw /*ARGSUSED*/ 7635331Samw static void * 7645331Samw smbd_localtime_monitor(void *arg) 7655331Samw { 7668167Samw@Sun.COM smb_io_t smb_io; 7675331Samw struct tm local_tm; 7687348SJose.Borrego@Sun.COM time_t secs; 7697348SJose.Borrego@Sun.COM int32_t gmtoff, last_gmtoff = -1; 7705331Samw int timeout; 7715331Samw 7728167Samw@Sun.COM bzero(&smb_io, sizeof (smb_io)); 7738167Samw@Sun.COM 7745331Samw for (;;) { 7757348SJose.Borrego@Sun.COM gmtoff = smbd_gmtoff(); 7765331Samw 7775331Samw if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) { 7788167Samw@Sun.COM smb_io.sio_data.gmtoff = gmtoff; 7798167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 7805331Samw smbd_report("localtime ioctl: %s", 7815331Samw strerror(errno)); 7825331Samw } 7835331Samw } 7845331Samw 7855331Samw /* 7865331Samw * Align the next iteration on a fifteen minute boundary. 7875331Samw */ 7885331Samw secs = time(0); 7895331Samw (void) localtime_r(&secs, &local_tm); 7905331Samw timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN); 7915331Samw (void) sleep(timeout); 7925331Samw 7935331Samw last_gmtoff = gmtoff; 7945331Samw } 7955331Samw 7965331Samw /*NOTREACHED*/ 7975331Samw return (NULL); 7985331Samw } 7995331Samw 8007348SJose.Borrego@Sun.COM /* 8017348SJose.Borrego@Sun.COM * smbd_gmtoff 8027348SJose.Borrego@Sun.COM * 8037348SJose.Borrego@Sun.COM * Determine offset from GMT. If daylight saving time use altzone, 8047348SJose.Borrego@Sun.COM * otherwise use timezone. 8057348SJose.Borrego@Sun.COM */ 8067348SJose.Borrego@Sun.COM static int32_t 8077348SJose.Borrego@Sun.COM smbd_gmtoff(void) 8087348SJose.Borrego@Sun.COM { 8097348SJose.Borrego@Sun.COM time_t clock_val; 8107348SJose.Borrego@Sun.COM struct tm *atm; 8117348SJose.Borrego@Sun.COM int32_t gmtoff; 8127348SJose.Borrego@Sun.COM 8137348SJose.Borrego@Sun.COM (void) time(&clock_val); 8147348SJose.Borrego@Sun.COM atm = localtime(&clock_val); 8157348SJose.Borrego@Sun.COM 8167348SJose.Borrego@Sun.COM gmtoff = (atm->tm_isdst) ? altzone : timezone; 8177348SJose.Borrego@Sun.COM 8187348SJose.Borrego@Sun.COM return (gmtoff); 8197348SJose.Borrego@Sun.COM } 8207348SJose.Borrego@Sun.COM 8215331Samw static void 8225331Samw smbd_sig_handler(int sigval) 8235331Samw { 8245331Samw if (smbd.s_sigval == 0) 8258334SJose.Borrego@Sun.COM (void) atomic_swap_uint(&smbd.s_sigval, sigval); 8268334SJose.Borrego@Sun.COM 8278334SJose.Borrego@Sun.COM if (sigval == SIGHUP) { 8288334SJose.Borrego@Sun.COM atomic_inc_uint(&smbd.s_refreshes); 8298334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8308334SJose.Borrego@Sun.COM } 8318334SJose.Borrego@Sun.COM 8328334SJose.Borrego@Sun.COM if (sigval == SIGINT || sigval == SIGTERM) { 8338334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 8348334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8358334SJose.Borrego@Sun.COM } 8365331Samw } 8375331Samw 8385331Samw /* 8395331Samw * Set up configuration options and parse the command line. 8405331Samw * This function will determine if we will run as a daemon 8415331Samw * or in the foreground. 8425331Samw * 8435331Samw * Failure to find a uid or gid results in using the default (0). 8445331Samw */ 8455331Samw static int 8465331Samw smbd_setup_options(int argc, char *argv[]) 8475331Samw { 8485331Samw struct passwd *pwd; 8495331Samw struct group *grp; 8505331Samw int c; 8515331Samw 8525331Samw if ((pwd = getpwnam("root")) != NULL) 8535331Samw smbd.s_uid = pwd->pw_uid; 8545331Samw 8555331Samw if ((grp = getgrnam("sys")) != NULL) 8565331Samw smbd.s_gid = grp->gr_gid; 8575331Samw 8585772Sas200622 smbd.s_fg = smb_config_get_fg_flag(); 8595331Samw 8605331Samw while ((c = getopt(argc, argv, ":f")) != -1) { 8615331Samw switch (c) { 8625331Samw case 'f': 8635331Samw smbd.s_fg = 1; 8645331Samw break; 8655331Samw 8665331Samw case ':': 8675331Samw case '?': 8685331Samw default: 8695331Samw smbd_usage(stderr); 8705331Samw return (-1); 8715331Samw } 8725331Samw } 8735331Samw 8745331Samw return (0); 8755331Samw } 8765331Samw 8775331Samw static void 8785331Samw smbd_usage(FILE *fp) 8795331Samw { 8805331Samw static char *help[] = { 8815331Samw "-f run program in foreground" 8825331Samw }; 8835331Samw 8845331Samw int i; 8855331Samw 8865331Samw (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname); 8875331Samw 8885331Samw for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i) 8895331Samw (void) fprintf(fp, " %s\n", help[i]); 8905331Samw } 8915331Samw 8925331Samw static void 8935331Samw smbd_report(const char *fmt, ...) 8945331Samw { 8955331Samw char buf[128]; 8965331Samw va_list ap; 8975331Samw 8985331Samw if (fmt == NULL) 8995331Samw return; 9005331Samw 9015331Samw va_start(ap, fmt); 9025331Samw (void) vsnprintf(buf, 128, fmt, ap); 9035331Samw va_end(ap); 9045331Samw 9055331Samw (void) fprintf(stderr, "smbd: %s\n", buf); 9065331Samw } 9075331Samw 908*9046SJose.Borrego@Sun.COM static int 909*9046SJose.Borrego@Sun.COM smbd_start_listeners(void) 910*9046SJose.Borrego@Sun.COM { 911*9046SJose.Borrego@Sun.COM int rc1; 912*9046SJose.Borrego@Sun.COM int rc2; 913*9046SJose.Borrego@Sun.COM pthread_attr_t tattr; 914*9046SJose.Borrego@Sun.COM 915*9046SJose.Borrego@Sun.COM (void) pthread_attr_init(&tattr); 916*9046SJose.Borrego@Sun.COM 917*9046SJose.Borrego@Sun.COM if (!smbd.s_nbt_listener_running) { 918*9046SJose.Borrego@Sun.COM rc1 = pthread_create(&smbd.s_nbt_listener_id, &tattr, 919*9046SJose.Borrego@Sun.COM smbd_nbt_listener, NULL); 920*9046SJose.Borrego@Sun.COM if (rc1 != 0) 921*9046SJose.Borrego@Sun.COM smbd_report("unable to start NBT service"); 922*9046SJose.Borrego@Sun.COM else 923*9046SJose.Borrego@Sun.COM smbd.s_nbt_listener_running = B_TRUE; 924*9046SJose.Borrego@Sun.COM } 925*9046SJose.Borrego@Sun.COM 926*9046SJose.Borrego@Sun.COM if (!smbd.s_tcp_listener_running) { 927*9046SJose.Borrego@Sun.COM rc2 = pthread_create(&smbd.s_tcp_listener_id, &tattr, 928*9046SJose.Borrego@Sun.COM smbd_tcp_listener, NULL); 929*9046SJose.Borrego@Sun.COM if (rc2 != 0) 930*9046SJose.Borrego@Sun.COM smbd_report("unable to start TCP service"); 931*9046SJose.Borrego@Sun.COM else 932*9046SJose.Borrego@Sun.COM smbd.s_tcp_listener_running = B_TRUE; 933*9046SJose.Borrego@Sun.COM } 934*9046SJose.Borrego@Sun.COM 935*9046SJose.Borrego@Sun.COM (void) pthread_attr_destroy(&tattr); 936*9046SJose.Borrego@Sun.COM 937*9046SJose.Borrego@Sun.COM if (rc1 != 0) 938*9046SJose.Borrego@Sun.COM return (rc1); 939*9046SJose.Borrego@Sun.COM return (rc2); 940*9046SJose.Borrego@Sun.COM } 941*9046SJose.Borrego@Sun.COM 942*9046SJose.Borrego@Sun.COM static void 943*9046SJose.Borrego@Sun.COM smbd_stop_listeners(void) 944*9046SJose.Borrego@Sun.COM { 945*9046SJose.Borrego@Sun.COM void *status; 946*9046SJose.Borrego@Sun.COM 947*9046SJose.Borrego@Sun.COM if (smbd.s_nbt_listener_running) { 948*9046SJose.Borrego@Sun.COM (void) pthread_kill(smbd.s_nbt_listener_id, SIGTERM); 949*9046SJose.Borrego@Sun.COM (void) pthread_join(smbd.s_nbt_listener_id, &status); 950*9046SJose.Borrego@Sun.COM smbd.s_nbt_listener_running = B_FALSE; 951*9046SJose.Borrego@Sun.COM } 952*9046SJose.Borrego@Sun.COM 953*9046SJose.Borrego@Sun.COM if (smbd.s_tcp_listener_running) { 954*9046SJose.Borrego@Sun.COM (void) pthread_kill(smbd.s_tcp_listener_id, SIGTERM); 955*9046SJose.Borrego@Sun.COM (void) pthread_join(smbd.s_tcp_listener_id, &status); 956*9046SJose.Borrego@Sun.COM smbd.s_tcp_listener_running = B_FALSE; 957*9046SJose.Borrego@Sun.COM } 958*9046SJose.Borrego@Sun.COM } 959*9046SJose.Borrego@Sun.COM 9605331Samw /* 9615331Samw * Enable libumem debugging by default on DEBUG builds. 9625331Samw */ 9635331Samw #ifdef DEBUG 9645331Samw const char * 9655331Samw _umem_debug_init(void) 9665331Samw { 9675331Samw return ("default,verbose"); /* $UMEM_DEBUG setting */ 9685331Samw } 9695331Samw 9705331Samw const char * 9715331Samw _umem_logging_init(void) 9725331Samw { 9735331Samw return ("fail,contents"); /* $UMEM_LOGGING setting */ 9745331Samw } 9755331Samw #endif 976