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 *); 91*8670SJose.Borrego@Sun.COM static void smbd_refresh_dc(void); 92*8670SJose.Borrego@Sun.COM 936139Sjb150015 static pthread_t nbt_listener; 946139Sjb150015 static pthread_t tcp_listener; 955331Samw static pthread_t refresh_thr; 965331Samw static pthread_cond_t refresh_cond; 975331Samw static pthread_mutex_t refresh_mutex; 985331Samw 996139Sjb150015 smbd_t smbd; 1005331Samw 1015331Samw /* 1025331Samw * smbd user land daemon 1035331Samw * 1045331Samw * Use SMF error codes only on return or exit. 1055331Samw */ 1065331Samw int 1075331Samw main(int argc, char *argv[]) 1085331Samw { 1096432Sas200622 struct sigaction act; 1106432Sas200622 sigset_t set; 1116432Sas200622 uid_t uid; 1126432Sas200622 int pfd = -1; 1138334SJose.Borrego@Sun.COM uint_t sigval; 1145331Samw 1155331Samw smbd.s_pname = basename(argv[0]); 1165331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1175331Samw 1185331Samw if (smbd_setup_options(argc, argv) != 0) 1195331Samw return (SMF_EXIT_ERR_FATAL); 1205331Samw 1215331Samw if ((uid = getuid()) != smbd.s_uid) { 1225331Samw smbd_report("user %d: %s", uid, strerror(EPERM)); 1235331Samw return (SMF_EXIT_ERR_FATAL); 1245331Samw } 1255331Samw 1265331Samw if (getzoneid() != GLOBAL_ZONEID) { 1275331Samw smbd_report("non-global zones are not supported"); 1285331Samw return (SMF_EXIT_ERR_FATAL); 1295331Samw } 1305331Samw 1315331Samw if (is_system_labeled()) { 1325331Samw smbd_report("Trusted Extensions not supported"); 1335331Samw return (SMF_EXIT_ERR_FATAL); 1345331Samw } 1355331Samw 1365331Samw if (smbd_already_running()) 1375331Samw return (SMF_EXIT_OK); 1385331Samw 1395331Samw (void) sigfillset(&set); 1405331Samw (void) sigdelset(&set, SIGABRT); 1415331Samw 1425331Samw (void) sigfillset(&act.sa_mask); 1435331Samw act.sa_handler = smbd_sig_handler; 1445331Samw act.sa_flags = 0; 1455331Samw 1465331Samw (void) sigaction(SIGTERM, &act, NULL); 1475331Samw (void) sigaction(SIGHUP, &act, NULL); 1485331Samw (void) sigaction(SIGINT, &act, NULL); 1495331Samw (void) sigaction(SIGPIPE, &act, NULL); 1505331Samw 1515331Samw (void) sigdelset(&set, SIGTERM); 1525331Samw (void) sigdelset(&set, SIGHUP); 1535331Samw (void) sigdelset(&set, SIGINT); 1545331Samw (void) sigdelset(&set, SIGPIPE); 1555331Samw 1565331Samw if (smbd.s_fg) { 1575331Samw (void) sigdelset(&set, SIGTSTP); 1585331Samw (void) sigdelset(&set, SIGTTIN); 1595331Samw (void) sigdelset(&set, SIGTTOU); 1605331Samw 1615331Samw if (smbd_service_init() != 0) { 1625331Samw smbd_report("service initialization failed"); 1635331Samw exit(SMF_EXIT_ERR_FATAL); 1645331Samw } 1655331Samw } else { 1665331Samw /* 1675331Samw * "pfd" is a pipe descriptor -- any fatal errors 1685331Samw * during subsequent initialization of the child 1695331Samw * process should be written to this pipe and the 1705331Samw * parent will report this error as the exit status. 1715331Samw */ 1725331Samw pfd = smbd_daemonize_init(); 1735331Samw 1745331Samw if (smbd_service_init() != 0) { 1755331Samw smbd_report("daemon initialization failed"); 1765331Samw exit(SMF_EXIT_ERR_FATAL); 1775331Samw } 1785331Samw 1795331Samw smbd_daemonize_fini(pfd, SMF_EXIT_OK); 1805331Samw } 1815331Samw 1825331Samw (void) atexit(smbd_service_fini); 1835331Samw 1848334SJose.Borrego@Sun.COM while (!smbd.s_shutting_down) { 1858334SJose.Borrego@Sun.COM if (smbd.s_sigval == 0 && smbd.s_refreshes == 0) 1867052Samw (void) sigsuspend(&set); 1875331Samw 1888334SJose.Borrego@Sun.COM sigval = atomic_swap_uint(&smbd.s_sigval, 0); 1897052Samw 1907052Samw switch (sigval) { 1915331Samw case 0: 1925331Samw case SIGPIPE: 1935331Samw break; 1945331Samw 1955331Samw case SIGHUP: 1968334SJose.Borrego@Sun.COM syslog(LOG_DEBUG, "refresh requested"); 1975331Samw (void) pthread_cond_signal(&refresh_cond); 1985331Samw break; 1995331Samw 2005331Samw default: 2015331Samw /* 2025331Samw * Typically SIGINT or SIGTERM. 2035331Samw */ 2048334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 2055331Samw break; 2065331Samw } 2075331Samw } 2085331Samw 2095331Samw smbd_service_fini(); 2105331Samw closelog(); 2115331Samw return (SMF_EXIT_OK); 2125331Samw } 2135331Samw 2145331Samw /* 2155331Samw * This function will fork off a child process, 2165331Samw * from which only the child will return. 2175331Samw * 2185331Samw * Use SMF error codes only on exit. 2195331Samw */ 2205331Samw static int 2215331Samw smbd_daemonize_init(void) 2225331Samw { 2235331Samw int status, pfds[2]; 2245331Samw sigset_t set, oset; 2255331Samw pid_t pid; 2265331Samw int rc; 2275331Samw 2285331Samw /* 2295331Samw * Reset privileges to the minimum set required. We continue 2305331Samw * to run as root to create and access files in /var. 2315331Samw */ 2325331Samw rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS, 2335331Samw smbd.s_uid, smbd.s_gid, 2345331Samw PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT, 2355331Samw PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL); 2365331Samw 2375331Samw if (rc != 0) { 2385331Samw smbd_report("insufficient privileges"); 2395331Samw exit(SMF_EXIT_ERR_FATAL); 2405331Samw } 2415331Samw 2425331Samw /* 2435331Samw * Block all signals prior to the fork and leave them blocked in the 2445331Samw * parent so we don't get in a situation where the parent gets SIGINT 2455331Samw * and returns non-zero exit status and the child is actually running. 2465331Samw * In the child, restore the signal mask once we've done our setsid(). 2475331Samw */ 2485331Samw (void) sigfillset(&set); 2495331Samw (void) sigdelset(&set, SIGABRT); 2505331Samw (void) sigprocmask(SIG_BLOCK, &set, &oset); 2515331Samw 2525331Samw if (pipe(pfds) == -1) { 2535331Samw smbd_report("unable to create pipe"); 2545331Samw exit(SMF_EXIT_ERR_FATAL); 2555331Samw } 2565331Samw 2575331Samw closelog(); 2585331Samw 2595331Samw if ((pid = fork()) == -1) { 2605331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2615331Samw smbd_report("unable to fork"); 2625331Samw closelog(); 2635331Samw exit(SMF_EXIT_ERR_FATAL); 2645331Samw } 2655331Samw 2665331Samw /* 2675331Samw * If we're the parent process, wait for either the child to send us 2685331Samw * the appropriate exit status over the pipe or for the read to fail 2695331Samw * (presumably with 0 for EOF if our child terminated abnormally). 2705331Samw * If the read fails, exit with either the child's exit status if it 2715331Samw * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. 2725331Samw */ 2735331Samw if (pid != 0) { 2745331Samw (void) close(pfds[1]); 2755331Samw 2765331Samw if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 2775331Samw _exit(status); 2785331Samw 2795331Samw if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 2805331Samw _exit(WEXITSTATUS(status)); 2815331Samw 2825331Samw _exit(SMF_EXIT_ERR_FATAL); 2835331Samw } 2845331Samw 2855331Samw openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2865331Samw smbd.s_pid = getpid(); 2875331Samw (void) setsid(); 2885331Samw (void) sigprocmask(SIG_SETMASK, &oset, NULL); 2895331Samw (void) chdir("/"); 2905331Samw (void) umask(022); 2915331Samw (void) close(pfds[0]); 2925331Samw 2935331Samw return (pfds[1]); 2945331Samw } 2955331Samw 2965331Samw static void 2975331Samw smbd_daemonize_fini(int fd, int exit_status) 2985331Samw { 2995331Samw /* 3005331Samw * Now that we're running, if a pipe fd was specified, write an exit 3015331Samw * status to it to indicate that our parent process can safely detach. 3025331Samw * Then proceed to loading the remaining non-built-in modules. 3035331Samw */ 3045331Samw if (fd >= 0) 3055331Samw (void) write(fd, &exit_status, sizeof (exit_status)); 3065331Samw 3075331Samw (void) close(fd); 3085331Samw 3095331Samw if ((fd = open("/dev/null", O_RDWR)) >= 0) { 3105331Samw (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 3115331Samw (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 3125331Samw (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 3135331Samw (void) close(fd); 3145331Samw } 3155331Samw 3165331Samw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 3175331Samw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL); 3185331Samw } 3195331Samw 3206139Sjb150015 /* 3216139Sjb150015 * smbd_service_init 3226139Sjb150015 */ 3235331Samw static int 3245331Samw smbd_service_init(void) 3255331Samw { 3266432Sas200622 int rc; 3278334SJose.Borrego@Sun.COM char nb_domain[NETBIOS_NAME_SZ]; 3286432Sas200622 3295331Samw smbd.s_drv_fd = -1; 3305331Samw 3316139Sjb150015 if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) { 3326139Sjb150015 smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno)); 3336139Sjb150015 return (1); 3345331Samw } 3355331Samw 3366139Sjb150015 if ((rc = smb_ccache_init(SMB_VARRUN_DIR, SMB_CCACHE_FILE)) != 0) { 3376139Sjb150015 if (rc == -1) 3386139Sjb150015 smbd_report("mkdir %s: %s", SMB_VARRUN_DIR, 3396139Sjb150015 strerror(errno)); 3406139Sjb150015 else 3416139Sjb150015 smbd_report("unable to set KRB5CCNAME"); 3425331Samw return (1); 3435331Samw } 3445331Samw 3456139Sjb150015 3465331Samw (void) oem_language_set("english"); 3475331Samw 3486432Sas200622 if (!smb_wka_init()) { 3495331Samw smbd_report("out of memory"); 3505331Samw return (1); 3515331Samw } 3525331Samw 3536432Sas200622 if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0) 3546432Sas200622 smbd_report("NIC monitoring failed to start"); 3556432Sas200622 3568334SJose.Borrego@Sun.COM (void) dyndns_start(); 3575331Samw smbrdr_init(); 3585331Samw 3595772Sas200622 if (smb_netbios_start() != 0) 3605772Sas200622 smbd_report("NetBIOS services failed to start"); 3615772Sas200622 else 3625772Sas200622 smbd_report("NetBIOS services started"); 3635772Sas200622 3648334SJose.Borrego@Sun.COM (void) smb_getdomainname(nb_domain, NETBIOS_NAME_SZ); 3658334SJose.Borrego@Sun.COM (void) utf8_strupr(nb_domain); 3665331Samw 3675331Samw /* Get the ID map client handle */ 3685331Samw if ((rc = smb_idmap_start()) != 0) { 3695331Samw smbd_report("no idmap handle"); 3705331Samw return (rc); 3715331Samw } 3725331Samw 3736432Sas200622 smbd.s_secmode = smb_config_get_secmode(); 3748334SJose.Borrego@Sun.COM if ((rc = nt_domain_init(nb_domain, smbd.s_secmode)) != 0) { 3755772Sas200622 if (rc == SMB_DOMAIN_NOMACHINE_SID) { 3765772Sas200622 smbd_report( 3775772Sas200622 "no machine SID: check idmap configuration"); 3785772Sas200622 return (rc); 3795772Sas200622 } 3805331Samw } 3815331Samw 3827052Samw smb_ads_init(); 3835331Samw if ((rc = mlsvc_init()) != 0) { 3845331Samw smbd_report("msrpc initialization failed"); 3855331Samw return (rc); 3865331Samw } 3875331Samw 3887348SJose.Borrego@Sun.COM if (smbd.s_secmode == SMB_SECMODE_DOMAIN) 3898334SJose.Borrego@Sun.COM if (smbd_locate_dc_start() != 0) 3907348SJose.Borrego@Sun.COM smbd_report("dc discovery failed %s", strerror(errno)); 3916139Sjb150015 3926432Sas200622 smbd.s_door_srv = smb_door_srv_start(); 3936432Sas200622 if (smbd.s_door_srv < 0) 3945331Samw return (rc); 3955331Samw 3965331Samw if ((rc = smbd_refresh_init()) != 0) 3975331Samw return (rc); 3985331Samw 3998334SJose.Borrego@Sun.COM dyndns_update_zones(); 4005331Samw 4015331Samw (void) smbd_localtime_init(); 4025331Samw 4037052Samw smbd.s_door_opipe = smbd_opipe_dsrv_start(); 4047052Samw if (smbd.s_door_opipe < 0) { 4057052Samw smbd_report("opipe initialization failed %s", 4065521Sas200622 strerror(errno)); 4075521Sas200622 return (rc); 4085521Sas200622 } 4095521Sas200622 4105772Sas200622 (void) smb_lgrp_start(); 4116030Sjb150015 4127052Samw smb_pwd_init(B_TRUE); 4136030Sjb150015 4147961SNatalie.Li@Sun.COM if ((rc = smb_shr_start()) != 0) { 4157961SNatalie.Li@Sun.COM smbd_report("share initialization failed: %s", strerror(errno)); 4167961SNatalie.Li@Sun.COM return (rc); 4177961SNatalie.Li@Sun.COM } 4187961SNatalie.Li@Sun.COM 4197961SNatalie.Li@Sun.COM smbd.s_door_lmshr = smb_share_dsrv_start(); 4207961SNatalie.Li@Sun.COM if (smbd.s_door_lmshr < 0) { 4217961SNatalie.Li@Sun.COM smbd_report("share initialization failed"); 4227961SNatalie.Li@Sun.COM } 4237961SNatalie.Li@Sun.COM 4248334SJose.Borrego@Sun.COM if ((rc = smbd_kernel_bind()) != 0) { 4256139Sjb150015 smbd_report("kernel bind error: %s", strerror(errno)); 4266432Sas200622 return (rc); 4276432Sas200622 } 4285331Samw 4298334SJose.Borrego@Sun.COM if ((rc = smb_shr_load()) != 0) { 4308334SJose.Borrego@Sun.COM smbd_report("failed to start loading shares: %s", 4318334SJose.Borrego@Sun.COM strerror(errno)); 4328334SJose.Borrego@Sun.COM return (rc); 4338334SJose.Borrego@Sun.COM } 4348334SJose.Borrego@Sun.COM 4357348SJose.Borrego@Sun.COM return (0); 4365521Sas200622 } 4375521Sas200622 4385331Samw /* 4395331Samw * Close the kernel service and shutdown smbd services. 4405331Samw * This function is registered with atexit(): ensure that anything 4415331Samw * called from here is safe to be called multiple times. 4425331Samw */ 4435331Samw static void 4445331Samw smbd_service_fini(void) 4455331Samw { 4467052Samw smbd_opipe_dsrv_stop(); 4476432Sas200622 smb_wka_fini(); 4485331Samw smbd_refresh_fini(); 4495331Samw smbd_kernel_unbind(); 4505331Samw smb_door_srv_stop(); 4516771Sjb150015 smb_share_dsrv_stop(); 4527052Samw smb_shr_stop(); 4538334SJose.Borrego@Sun.COM dyndns_stop(); 4545331Samw smb_nicmon_stop(); 4555331Samw smb_idmap_stop(); 4565772Sas200622 smb_lgrp_stop(); 4576139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 4586030Sjb150015 smb_pwd_fini(); 4598474SJose.Borrego@Sun.COM nt_domain_unlink(); 4605331Samw } 4615331Samw 4626139Sjb150015 4635331Samw /* 4645331Samw * smbd_refresh_init() 4655331Samw * 4665331Samw * SMB service refresh thread initialization. This thread waits for a 4675331Samw * refresh event and updates the daemon's view of the configuration 4685331Samw * before going back to sleep. 4695331Samw */ 4705331Samw static int 4715331Samw smbd_refresh_init() 4725331Samw { 4736432Sas200622 pthread_attr_t tattr; 4746432Sas200622 pthread_condattr_t cattr; 4756432Sas200622 int rc; 4765331Samw 4775331Samw (void) pthread_condattr_init(&cattr); 4785331Samw (void) pthread_cond_init(&refresh_cond, &cattr); 4795331Samw (void) pthread_condattr_destroy(&cattr); 4805331Samw 4815331Samw (void) pthread_mutex_init(&refresh_mutex, NULL); 4825331Samw 4835331Samw (void) pthread_attr_init(&tattr); 4845331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 4855331Samw rc = pthread_create(&refresh_thr, &tattr, smbd_refresh_monitor, 0); 4865331Samw (void) pthread_attr_destroy(&tattr); 4876432Sas200622 4885331Samw return (rc); 4895331Samw } 4905331Samw 4915331Samw /* 4925331Samw * smbd_refresh_fini() 4935331Samw * 4945331Samw * Stop the refresh thread. 4955331Samw */ 4965331Samw static void 4975331Samw smbd_refresh_fini() 4985331Samw { 4995331Samw (void) pthread_cancel(refresh_thr); 5005331Samw 5015331Samw (void) pthread_cond_destroy(&refresh_cond); 5025331Samw (void) pthread_mutex_destroy(&refresh_mutex); 5035331Samw } 5045331Samw 5055331Samw /* 5065331Samw * smbd_refresh_monitor() 5075331Samw * 5085331Samw * Wait for a refresh event. When this thread wakes up, update the 5095331Samw * smbd configuration from the SMF config information then go back to 5105331Samw * wait for the next refresh. 5115331Samw */ 5125331Samw /*ARGSUSED*/ 5135331Samw static void * 5145331Samw smbd_refresh_monitor(void *arg) 5155331Samw { 5166432Sas200622 smb_io_t smb_io; 5175331Samw 5186771Sjb150015 bzero(&smb_io, sizeof (smb_io)); 5196771Sjb150015 5208334SJose.Borrego@Sun.COM while (!smbd.s_shutting_down) { 5218334SJose.Borrego@Sun.COM (void) pthread_mutex_lock(&refresh_mutex); 5228334SJose.Borrego@Sun.COM while ((atomic_swap_uint(&smbd.s_refreshes, 0) == 0) && 5238334SJose.Borrego@Sun.COM (!smbd.s_shutting_down)) 5248334SJose.Borrego@Sun.COM (void) pthread_cond_wait(&refresh_cond, &refresh_mutex); 5258334SJose.Borrego@Sun.COM (void) pthread_mutex_unlock(&refresh_mutex); 5268334SJose.Borrego@Sun.COM 5278334SJose.Borrego@Sun.COM if (smbd.s_shutting_down) { 5288334SJose.Borrego@Sun.COM syslog(LOG_DEBUG, "shutting down"); 5298334SJose.Borrego@Sun.COM exit(SMF_EXIT_OK); 5308334SJose.Borrego@Sun.COM } 5318334SJose.Borrego@Sun.COM 5325331Samw /* 5335331Samw * We've been woken up by a refresh event so go do 5345331Samw * what is necessary. 5355331Samw */ 5367052Samw smb_ads_refresh(); 5376139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 5386432Sas200622 5398334SJose.Borrego@Sun.COM /* 5408334SJose.Borrego@Sun.COM * Start the dyndns thread, if required. 5418334SJose.Borrego@Sun.COM * Clear the DNS zones for the existing interfaces 5428334SJose.Borrego@Sun.COM * before updating the NIC interface list. 5438334SJose.Borrego@Sun.COM */ 5448334SJose.Borrego@Sun.COM (void) dyndns_start(); 5458334SJose.Borrego@Sun.COM dyndns_clear_zones(); 5466432Sas200622 5476432Sas200622 /* re-initialize NIC table */ 5486432Sas200622 if (smb_nic_init() != 0) 5496432Sas200622 smbd_report("failed to get NIC information"); 5506432Sas200622 smb_netbios_name_reconfig(); 5516432Sas200622 smb_browser_reconfig(); 552*8670SJose.Borrego@Sun.COM smbd_refresh_dc(); 5538334SJose.Borrego@Sun.COM dyndns_update_zones(); 5546432Sas200622 5558334SJose.Borrego@Sun.COM if (smbd_set_netlogon_cred()) { 5566432Sas200622 /* 5578334SJose.Borrego@Sun.COM * Restart required because the domain changed 5588334SJose.Borrego@Sun.COM * or the credential chain setup failed. 5596432Sas200622 */ 5608334SJose.Borrego@Sun.COM if (smb_smf_restart_service() != 0) { 5618334SJose.Borrego@Sun.COM syslog(LOG_ERR, 5628334SJose.Borrego@Sun.COM "unable to restart smb service. " 5638334SJose.Borrego@Sun.COM "Run 'svcs -xv smb/server' for more " 5648334SJose.Borrego@Sun.COM "information."); 5658334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 5668334SJose.Borrego@Sun.COM exit(SMF_EXIT_OK); 5678334SJose.Borrego@Sun.COM } 5688334SJose.Borrego@Sun.COM 5698334SJose.Borrego@Sun.COM break; 5708334SJose.Borrego@Sun.COM } 5718334SJose.Borrego@Sun.COM 5728334SJose.Borrego@Sun.COM if (smbd.s_drv_fd == -1) { 5736432Sas200622 if (smbd_kernel_bind()) { 5746432Sas200622 smbd_report("kernel bind error: %s", 5756432Sas200622 strerror(errno)); 5768334SJose.Borrego@Sun.COM } else { 5778334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5786432Sas200622 } 5796432Sas200622 continue; 5806432Sas200622 } 5816432Sas200622 5828334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5838334SJose.Borrego@Sun.COM 5848334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 5858334SJose.Borrego@Sun.COM 5868167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 5875331Samw smbd_report("configuration update ioctl: %s", 5885331Samw strerror(errno)); 5895331Samw } 5905331Samw } 5918334SJose.Borrego@Sun.COM 5925331Samw return (NULL); 5935331Samw } 5945331Samw 595*8670SJose.Borrego@Sun.COM /* 596*8670SJose.Borrego@Sun.COM * Update DC information on a refresh. 597*8670SJose.Borrego@Sun.COM */ 598*8670SJose.Borrego@Sun.COM static void 599*8670SJose.Borrego@Sun.COM smbd_refresh_dc(void) 600*8670SJose.Borrego@Sun.COM { 601*8670SJose.Borrego@Sun.COM char fqdomain[MAXHOSTNAMELEN]; 602*8670SJose.Borrego@Sun.COM if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 603*8670SJose.Borrego@Sun.COM return; 604*8670SJose.Borrego@Sun.COM 605*8670SJose.Borrego@Sun.COM if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN)) 606*8670SJose.Borrego@Sun.COM return; 607*8670SJose.Borrego@Sun.COM 608*8670SJose.Borrego@Sun.COM if (smb_locate_dc(fqdomain, "", NULL)) 609*8670SJose.Borrego@Sun.COM smbd_report("DC discovery failed"); 610*8670SJose.Borrego@Sun.COM } 611*8670SJose.Borrego@Sun.COM 6128334SJose.Borrego@Sun.COM void 6138334SJose.Borrego@Sun.COM smbd_set_secmode(int secmode) 6148334SJose.Borrego@Sun.COM { 6158334SJose.Borrego@Sun.COM switch (secmode) { 6168334SJose.Borrego@Sun.COM case SMB_SECMODE_WORKGRP: 6178334SJose.Borrego@Sun.COM case SMB_SECMODE_DOMAIN: 6188334SJose.Borrego@Sun.COM (void) smb_config_set_secmode(secmode); 6198334SJose.Borrego@Sun.COM smbd.s_secmode = secmode; 6208334SJose.Borrego@Sun.COM break; 6218334SJose.Borrego@Sun.COM 6228334SJose.Borrego@Sun.COM default: 6238334SJose.Borrego@Sun.COM syslog(LOG_ERR, "invalid security mode: %d", secmode); 6248334SJose.Borrego@Sun.COM syslog(LOG_ERR, "entering maintenance mode"); 6258334SJose.Borrego@Sun.COM (void) smb_smf_maintenance_mode(); 6268334SJose.Borrego@Sun.COM } 6278334SJose.Borrego@Sun.COM } 6285331Samw 6295331Samw /* 6305331Samw * If the door has already been opened by another process (non-zero pid 6315331Samw * in target), we assume that another smbd is already running. If there 6325331Samw * is a race here, it will be caught later when smbsrv is opened because 6335331Samw * only one process is allowed to open the device at a time. 6345331Samw */ 6355331Samw static int 6365331Samw smbd_already_running(void) 6375331Samw { 6385331Samw door_info_t info; 6395331Samw int door; 6405331Samw 6416139Sjb150015 if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) 6425331Samw return (0); 6435331Samw 6445331Samw if (door_info(door, &info) < 0) 6455331Samw return (0); 6465331Samw 6475331Samw if (info.di_target > 0) { 6485331Samw smbd_report("already running: pid %ld\n", info.di_target); 6495331Samw (void) close(door); 6505331Samw return (1); 6515331Samw } 6525331Samw 6535331Samw (void) close(door); 6545331Samw return (0); 6555331Samw } 6565331Samw 6576139Sjb150015 /* 6586139Sjb150015 * smbd_kernel_bind 6596432Sas200622 * 6606432Sas200622 * This function open the smbsrv device and start the kernel service. 6616139Sjb150015 */ 6625331Samw static int 6636432Sas200622 smbd_kernel_bind(void) 6645331Samw { 6657826SJose.Borrego@Sun.COM pthread_attr_t tattr; 6666139Sjb150015 smb_io_t smb_io; 6677826SJose.Borrego@Sun.COM int rc1; 6687826SJose.Borrego@Sun.COM int rc2; 6696139Sjb150015 int rc; 6706139Sjb150015 6716139Sjb150015 bzero(&smb_io, sizeof (smb_io)); 6726139Sjb150015 6738334SJose.Borrego@Sun.COM smbd_kernel_unbind(); 6745331Samw 6755331Samw if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) { 6765331Samw smbd.s_drv_fd = -1; 6776139Sjb150015 return (errno); 6786139Sjb150015 } 6798167Samw@Sun.COM 6808334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 6818334SJose.Borrego@Sun.COM 6828167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 6836139Sjb150015 (void) close(smbd.s_drv_fd); 6846139Sjb150015 smbd.s_drv_fd = -1; 6856139Sjb150015 return (errno); 6866139Sjb150015 } 6877348SJose.Borrego@Sun.COM smb_io.sio_data.gmtoff = smbd_gmtoff(); 6888167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 6896139Sjb150015 (void) close(smbd.s_drv_fd); 6906139Sjb150015 smbd.s_drv_fd = -1; 6916139Sjb150015 return (errno); 6925331Samw } 6937052Samw smb_io.sio_data.start.opipe = smbd.s_door_opipe; 6946432Sas200622 smb_io.sio_data.start.lmshrd = smbd.s_door_lmshr; 6956432Sas200622 smb_io.sio_data.start.udoor = smbd.s_door_srv; 6968167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_START, &smb_io) < 0) { 6976139Sjb150015 (void) close(smbd.s_drv_fd); 6986139Sjb150015 smbd.s_drv_fd = -1; 6996139Sjb150015 return (errno); 7006139Sjb150015 } 7016139Sjb150015 7027826SJose.Borrego@Sun.COM (void) pthread_attr_init(&tattr); 7037826SJose.Borrego@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 7047826SJose.Borrego@Sun.COM 7057826SJose.Borrego@Sun.COM rc1 = pthread_create(&nbt_listener, &tattr, smbd_nbt_listener, NULL); 7067826SJose.Borrego@Sun.COM if (rc1 != 0) 7077826SJose.Borrego@Sun.COM smbd_report("unable to start NBT service"); 7087826SJose.Borrego@Sun.COM 7097826SJose.Borrego@Sun.COM rc2 = pthread_create(&tcp_listener, &tattr, smbd_tcp_listener, NULL); 7107826SJose.Borrego@Sun.COM if (rc2 != 0) 7117826SJose.Borrego@Sun.COM smbd_report("unable to start TCP service"); 7127826SJose.Borrego@Sun.COM 7137826SJose.Borrego@Sun.COM (void) pthread_attr_destroy(&tattr); 7147826SJose.Borrego@Sun.COM 7157826SJose.Borrego@Sun.COM rc = rc1; 7167826SJose.Borrego@Sun.COM if (rc == 0) 7177826SJose.Borrego@Sun.COM rc = rc2; 7187826SJose.Borrego@Sun.COM 7196139Sjb150015 if (rc == 0) { 7207826SJose.Borrego@Sun.COM smbd.s_kbound = B_TRUE; 7217826SJose.Borrego@Sun.COM return (0); 7226432Sas200622 } 7236432Sas200622 7246139Sjb150015 (void) close(smbd.s_drv_fd); 7256139Sjb150015 smbd.s_drv_fd = -1; 7266139Sjb150015 return (rc); 7275331Samw } 7285331Samw 7296139Sjb150015 /* 7306139Sjb150015 * smbd_kernel_unbind 7316139Sjb150015 */ 7326139Sjb150015 static void 7336139Sjb150015 smbd_kernel_unbind(void) 7346139Sjb150015 { 7356139Sjb150015 if (smbd.s_drv_fd != -1) { 7366139Sjb150015 (void) close(smbd.s_drv_fd); 7376139Sjb150015 smbd.s_drv_fd = -1; 7386432Sas200622 smbd.s_kbound = B_FALSE; 7396139Sjb150015 } 7406139Sjb150015 } 7415331Samw 7428167Samw@Sun.COM int 7438167Samw@Sun.COM smbd_ioctl(int cmd, smb_io_t *smb_io) 7448167Samw@Sun.COM { 7458167Samw@Sun.COM smb_io->sio_version = SMB_IOC_VERSION; 7468167Samw@Sun.COM smb_io->sio_crc = 0; 7478167Samw@Sun.COM smb_io->sio_crc = smb_crc_gen((uint8_t *)smb_io, sizeof (smb_io_t)); 7488167Samw@Sun.COM 7498167Samw@Sun.COM return (ioctl(smbd.s_drv_fd, cmd, smb_io)); 7508167Samw@Sun.COM } 7518167Samw@Sun.COM 7525331Samw /* 7535331Samw * Initialization of the localtime thread. 7545331Samw * Returns 0 on success, an error number if thread creation fails. 7555331Samw */ 7565331Samw 7575331Samw int 7585331Samw smbd_localtime_init(void) 7595331Samw { 7605331Samw pthread_attr_t tattr; 7615331Samw int rc; 7625331Samw 7635331Samw (void) pthread_attr_init(&tattr); 7645331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 7655331Samw rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0); 7665331Samw (void) pthread_attr_destroy(&tattr); 7675331Samw return (rc); 7685331Samw } 7695331Samw 7705331Samw /* 7715331Samw * Local time thread to kernel land. 7725331Samw * Send local gmtoff to kernel module one time at startup 7735331Samw * and each time it changes (up to twice a year). 7745331Samw * Local gmtoff is checked once every 15 minutes and 7755331Samw * since some timezones are aligned on half and qtr hour boundaries, 7765331Samw * once an hour would likely suffice. 7775331Samw */ 7785331Samw 7795331Samw /*ARGSUSED*/ 7805331Samw static void * 7815331Samw smbd_localtime_monitor(void *arg) 7825331Samw { 7838167Samw@Sun.COM smb_io_t smb_io; 7845331Samw struct tm local_tm; 7857348SJose.Borrego@Sun.COM time_t secs; 7867348SJose.Borrego@Sun.COM int32_t gmtoff, last_gmtoff = -1; 7875331Samw int timeout; 7885331Samw 7898167Samw@Sun.COM bzero(&smb_io, sizeof (smb_io)); 7908167Samw@Sun.COM 7915331Samw for (;;) { 7927348SJose.Borrego@Sun.COM gmtoff = smbd_gmtoff(); 7935331Samw 7945331Samw if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) { 7958167Samw@Sun.COM smb_io.sio_data.gmtoff = gmtoff; 7968167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 7975331Samw smbd_report("localtime ioctl: %s", 7985331Samw strerror(errno)); 7995331Samw } 8005331Samw } 8015331Samw 8025331Samw /* 8035331Samw * Align the next iteration on a fifteen minute boundary. 8045331Samw */ 8055331Samw secs = time(0); 8065331Samw (void) localtime_r(&secs, &local_tm); 8075331Samw timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN); 8085331Samw (void) sleep(timeout); 8095331Samw 8105331Samw last_gmtoff = gmtoff; 8115331Samw } 8125331Samw 8135331Samw /*NOTREACHED*/ 8145331Samw return (NULL); 8155331Samw } 8165331Samw 8177348SJose.Borrego@Sun.COM /* 8187348SJose.Borrego@Sun.COM * smbd_gmtoff 8197348SJose.Borrego@Sun.COM * 8207348SJose.Borrego@Sun.COM * Determine offset from GMT. If daylight saving time use altzone, 8217348SJose.Borrego@Sun.COM * otherwise use timezone. 8227348SJose.Borrego@Sun.COM */ 8237348SJose.Borrego@Sun.COM static int32_t 8247348SJose.Borrego@Sun.COM smbd_gmtoff(void) 8257348SJose.Borrego@Sun.COM { 8267348SJose.Borrego@Sun.COM time_t clock_val; 8277348SJose.Borrego@Sun.COM struct tm *atm; 8287348SJose.Borrego@Sun.COM int32_t gmtoff; 8297348SJose.Borrego@Sun.COM 8307348SJose.Borrego@Sun.COM (void) time(&clock_val); 8317348SJose.Borrego@Sun.COM atm = localtime(&clock_val); 8327348SJose.Borrego@Sun.COM 8337348SJose.Borrego@Sun.COM gmtoff = (atm->tm_isdst) ? altzone : timezone; 8347348SJose.Borrego@Sun.COM 8357348SJose.Borrego@Sun.COM return (gmtoff); 8367348SJose.Borrego@Sun.COM } 8377348SJose.Borrego@Sun.COM 8385331Samw static void 8395331Samw smbd_sig_handler(int sigval) 8405331Samw { 8415331Samw if (smbd.s_sigval == 0) 8428334SJose.Borrego@Sun.COM (void) atomic_swap_uint(&smbd.s_sigval, sigval); 8438334SJose.Borrego@Sun.COM 8448334SJose.Borrego@Sun.COM if (sigval == SIGHUP) { 8458334SJose.Borrego@Sun.COM atomic_inc_uint(&smbd.s_refreshes); 8468334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8478334SJose.Borrego@Sun.COM } 8488334SJose.Borrego@Sun.COM 8498334SJose.Borrego@Sun.COM if (sigval == SIGINT || sigval == SIGTERM) { 8508334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 8518334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8528334SJose.Borrego@Sun.COM } 8535331Samw } 8545331Samw 8555331Samw /* 8565331Samw * Set up configuration options and parse the command line. 8575331Samw * This function will determine if we will run as a daemon 8585331Samw * or in the foreground. 8595331Samw * 8605331Samw * Failure to find a uid or gid results in using the default (0). 8615331Samw */ 8625331Samw static int 8635331Samw smbd_setup_options(int argc, char *argv[]) 8645331Samw { 8655331Samw struct passwd *pwd; 8665331Samw struct group *grp; 8675331Samw int c; 8685331Samw 8695331Samw if ((pwd = getpwnam("root")) != NULL) 8705331Samw smbd.s_uid = pwd->pw_uid; 8715331Samw 8725331Samw if ((grp = getgrnam("sys")) != NULL) 8735331Samw smbd.s_gid = grp->gr_gid; 8745331Samw 8755772Sas200622 smbd.s_fg = smb_config_get_fg_flag(); 8765331Samw 8775331Samw while ((c = getopt(argc, argv, ":f")) != -1) { 8785331Samw switch (c) { 8795331Samw case 'f': 8805331Samw smbd.s_fg = 1; 8815331Samw break; 8825331Samw 8835331Samw case ':': 8845331Samw case '?': 8855331Samw default: 8865331Samw smbd_usage(stderr); 8875331Samw return (-1); 8885331Samw } 8895331Samw } 8905331Samw 8915331Samw return (0); 8925331Samw } 8935331Samw 8945331Samw static void 8955331Samw smbd_usage(FILE *fp) 8965331Samw { 8975331Samw static char *help[] = { 8985331Samw "-f run program in foreground" 8995331Samw }; 9005331Samw 9015331Samw int i; 9025331Samw 9035331Samw (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname); 9045331Samw 9055331Samw for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i) 9065331Samw (void) fprintf(fp, " %s\n", help[i]); 9075331Samw } 9085331Samw 9095331Samw static void 9105331Samw smbd_report(const char *fmt, ...) 9115331Samw { 9125331Samw char buf[128]; 9135331Samw va_list ap; 9145331Samw 9155331Samw if (fmt == NULL) 9165331Samw return; 9175331Samw 9185331Samw va_start(ap, fmt); 9195331Samw (void) vsnprintf(buf, 128, fmt, ap); 9205331Samw va_end(ap); 9215331Samw 9225331Samw (void) fprintf(stderr, "smbd: %s\n", buf); 9235331Samw } 9245331Samw 9255331Samw /* 9265331Samw * Enable libumem debugging by default on DEBUG builds. 9275331Samw */ 9285331Samw #ifdef DEBUG 9295331Samw const char * 9305331Samw _umem_debug_init(void) 9315331Samw { 9325331Samw return ("default,verbose"); /* $UMEM_DEBUG setting */ 9335331Samw } 9345331Samw 9355331Samw const char * 9365331Samw _umem_logging_init(void) 9375331Samw { 9385331Samw return ("fail,contents"); /* $UMEM_LOGGING setting */ 9395331Samw } 9405331Samw #endif 941