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*8474SJose.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> 487348SJose.Borrego@Sun.COM #include <time.h> 495331Samw #include <tzfile.h> 505331Samw #include <libgen.h> 515331Samw #include <pwd.h> 525331Samw #include <grp.h> 535331Samw 545331Samw #include <smbsrv/smb_door_svc.h> 555331Samw #include <smbsrv/smb_ioctl.h> 565331Samw #include <smbsrv/libsmb.h> 575331Samw #include <smbsrv/libsmbns.h> 585331Samw #include <smbsrv/libsmbrdr.h> 595331Samw #include <smbsrv/libmlsvc.h> 605331Samw #include "smbd.h" 615331Samw 625331Samw #define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" 635331Samw #define SMB_DBDIR "/var/smb" 645331Samw 656139Sjb150015 extern void *smbd_nbt_listener(void *); 666139Sjb150015 extern void *smbd_tcp_listener(void *); 676139Sjb150015 685331Samw static int smbd_daemonize_init(void); 695331Samw static void smbd_daemonize_fini(int, int); 705331Samw 716432Sas200622 static int smbd_kernel_bind(void); 725331Samw static void smbd_kernel_unbind(void); 735331Samw static int smbd_already_running(void); 745331Samw 755331Samw static int smbd_service_init(void); 765331Samw static void smbd_service_fini(void); 775331Samw 785331Samw static int smbd_setup_options(int argc, char *argv[]); 795331Samw static void smbd_usage(FILE *fp); 805331Samw static void smbd_report(const char *fmt, ...); 815331Samw 825331Samw static void smbd_sig_handler(int sig); 835331Samw 847348SJose.Borrego@Sun.COM static int32_t smbd_gmtoff(void); 855331Samw static int smbd_localtime_init(void); 865331Samw static void *smbd_localtime_monitor(void *arg); 875331Samw 885331Samw static pthread_t localtime_thr; 895331Samw 905331Samw static int smbd_refresh_init(void); 915331Samw static void smbd_refresh_fini(void); 925331Samw static void *smbd_refresh_monitor(void *); 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(); 459*8474SJose.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 5328334SJose.Borrego@Sun.COM syslog(LOG_DEBUG, "refresh"); 5338334SJose.Borrego@Sun.COM 5345331Samw /* 5355331Samw * We've been woken up by a refresh event so go do 5365331Samw * what is necessary. 5375331Samw */ 5387052Samw smb_ads_refresh(); 5396139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH); 5406432Sas200622 5418334SJose.Borrego@Sun.COM /* 5428334SJose.Borrego@Sun.COM * Start the dyndns thread, if required. 5438334SJose.Borrego@Sun.COM * Clear the DNS zones for the existing interfaces 5448334SJose.Borrego@Sun.COM * before updating the NIC interface list. 5458334SJose.Borrego@Sun.COM */ 5468334SJose.Borrego@Sun.COM (void) dyndns_start(); 5478334SJose.Borrego@Sun.COM dyndns_clear_zones(); 5486432Sas200622 5496432Sas200622 /* re-initialize NIC table */ 5506432Sas200622 if (smb_nic_init() != 0) 5516432Sas200622 smbd_report("failed to get NIC information"); 5526432Sas200622 5536432Sas200622 smb_netbios_name_reconfig(); 5546432Sas200622 smb_browser_reconfig(); 5558334SJose.Borrego@Sun.COM dyndns_update_zones(); 5566432Sas200622 5578334SJose.Borrego@Sun.COM if (smbd_set_netlogon_cred()) { 5586432Sas200622 /* 5598334SJose.Borrego@Sun.COM * Restart required because the domain changed 5608334SJose.Borrego@Sun.COM * or the credential chain setup failed. 5616432Sas200622 */ 5628334SJose.Borrego@Sun.COM if (smb_smf_restart_service() != 0) { 5638334SJose.Borrego@Sun.COM syslog(LOG_ERR, 5648334SJose.Borrego@Sun.COM "unable to restart smb service. " 5658334SJose.Borrego@Sun.COM "Run 'svcs -xv smb/server' for more " 5668334SJose.Borrego@Sun.COM "information."); 5678334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 5688334SJose.Borrego@Sun.COM exit(SMF_EXIT_OK); 5698334SJose.Borrego@Sun.COM } 5708334SJose.Borrego@Sun.COM 5718334SJose.Borrego@Sun.COM break; 5728334SJose.Borrego@Sun.COM } 5738334SJose.Borrego@Sun.COM 5748334SJose.Borrego@Sun.COM if (smbd.s_drv_fd == -1) { 5756432Sas200622 if (smbd_kernel_bind()) { 5766432Sas200622 smbd_report("kernel bind error: %s", 5776432Sas200622 strerror(errno)); 5788334SJose.Borrego@Sun.COM } else { 5798334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5806432Sas200622 } 5816432Sas200622 continue; 5826432Sas200622 } 5836432Sas200622 5848334SJose.Borrego@Sun.COM (void) smb_shr_load(); 5858334SJose.Borrego@Sun.COM 5868334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 5878334SJose.Borrego@Sun.COM 5888167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 5895331Samw smbd_report("configuration update ioctl: %s", 5905331Samw strerror(errno)); 5915331Samw } 5925331Samw } 5938334SJose.Borrego@Sun.COM 5945331Samw return (NULL); 5955331Samw } 5965331Samw 5978334SJose.Borrego@Sun.COM void 5988334SJose.Borrego@Sun.COM smbd_set_secmode(int secmode) 5998334SJose.Borrego@Sun.COM { 6008334SJose.Borrego@Sun.COM switch (secmode) { 6018334SJose.Borrego@Sun.COM case SMB_SECMODE_WORKGRP: 6028334SJose.Borrego@Sun.COM case SMB_SECMODE_DOMAIN: 6038334SJose.Borrego@Sun.COM (void) smb_config_set_secmode(secmode); 6048334SJose.Borrego@Sun.COM smbd.s_secmode = secmode; 6058334SJose.Borrego@Sun.COM break; 6068334SJose.Borrego@Sun.COM 6078334SJose.Borrego@Sun.COM default: 6088334SJose.Borrego@Sun.COM syslog(LOG_ERR, "invalid security mode: %d", secmode); 6098334SJose.Borrego@Sun.COM syslog(LOG_ERR, "entering maintenance mode"); 6108334SJose.Borrego@Sun.COM (void) smb_smf_maintenance_mode(); 6118334SJose.Borrego@Sun.COM } 6128334SJose.Borrego@Sun.COM } 6135331Samw 6145331Samw /* 6155331Samw * If the door has already been opened by another process (non-zero pid 6165331Samw * in target), we assume that another smbd is already running. If there 6175331Samw * is a race here, it will be caught later when smbsrv is opened because 6185331Samw * only one process is allowed to open the device at a time. 6195331Samw */ 6205331Samw static int 6215331Samw smbd_already_running(void) 6225331Samw { 6235331Samw door_info_t info; 6245331Samw int door; 6255331Samw 6266139Sjb150015 if ((door = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) 6275331Samw return (0); 6285331Samw 6295331Samw if (door_info(door, &info) < 0) 6305331Samw return (0); 6315331Samw 6325331Samw if (info.di_target > 0) { 6335331Samw smbd_report("already running: pid %ld\n", info.di_target); 6345331Samw (void) close(door); 6355331Samw return (1); 6365331Samw } 6375331Samw 6385331Samw (void) close(door); 6395331Samw return (0); 6405331Samw } 6415331Samw 6426139Sjb150015 /* 6436139Sjb150015 * smbd_kernel_bind 6446432Sas200622 * 6456432Sas200622 * This function open the smbsrv device and start the kernel service. 6466139Sjb150015 */ 6475331Samw static int 6486432Sas200622 smbd_kernel_bind(void) 6495331Samw { 6507826SJose.Borrego@Sun.COM pthread_attr_t tattr; 6516139Sjb150015 smb_io_t smb_io; 6527826SJose.Borrego@Sun.COM int rc1; 6537826SJose.Borrego@Sun.COM int rc2; 6546139Sjb150015 int rc; 6556139Sjb150015 6566139Sjb150015 bzero(&smb_io, sizeof (smb_io)); 6576139Sjb150015 6588334SJose.Borrego@Sun.COM smbd_kernel_unbind(); 6595331Samw 6605331Samw if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) { 6615331Samw smbd.s_drv_fd = -1; 6626139Sjb150015 return (errno); 6636139Sjb150015 } 6648167Samw@Sun.COM 6658334SJose.Borrego@Sun.COM smb_load_kconfig(&smb_io.sio_data.cfg); 6668334SJose.Borrego@Sun.COM 6678167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) { 6686139Sjb150015 (void) close(smbd.s_drv_fd); 6696139Sjb150015 smbd.s_drv_fd = -1; 6706139Sjb150015 return (errno); 6716139Sjb150015 } 6727348SJose.Borrego@Sun.COM smb_io.sio_data.gmtoff = smbd_gmtoff(); 6738167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 6746139Sjb150015 (void) close(smbd.s_drv_fd); 6756139Sjb150015 smbd.s_drv_fd = -1; 6766139Sjb150015 return (errno); 6775331Samw } 6787052Samw smb_io.sio_data.start.opipe = smbd.s_door_opipe; 6796432Sas200622 smb_io.sio_data.start.lmshrd = smbd.s_door_lmshr; 6806432Sas200622 smb_io.sio_data.start.udoor = smbd.s_door_srv; 6818167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_START, &smb_io) < 0) { 6826139Sjb150015 (void) close(smbd.s_drv_fd); 6836139Sjb150015 smbd.s_drv_fd = -1; 6846139Sjb150015 return (errno); 6856139Sjb150015 } 6866139Sjb150015 6877826SJose.Borrego@Sun.COM (void) pthread_attr_init(&tattr); 6887826SJose.Borrego@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 6897826SJose.Borrego@Sun.COM 6907826SJose.Borrego@Sun.COM rc1 = pthread_create(&nbt_listener, &tattr, smbd_nbt_listener, NULL); 6917826SJose.Borrego@Sun.COM if (rc1 != 0) 6927826SJose.Borrego@Sun.COM smbd_report("unable to start NBT service"); 6937826SJose.Borrego@Sun.COM 6947826SJose.Borrego@Sun.COM rc2 = pthread_create(&tcp_listener, &tattr, smbd_tcp_listener, NULL); 6957826SJose.Borrego@Sun.COM if (rc2 != 0) 6967826SJose.Borrego@Sun.COM smbd_report("unable to start TCP service"); 6977826SJose.Borrego@Sun.COM 6987826SJose.Borrego@Sun.COM (void) pthread_attr_destroy(&tattr); 6997826SJose.Borrego@Sun.COM 7007826SJose.Borrego@Sun.COM rc = rc1; 7017826SJose.Borrego@Sun.COM if (rc == 0) 7027826SJose.Borrego@Sun.COM rc = rc2; 7037826SJose.Borrego@Sun.COM 7046139Sjb150015 if (rc == 0) { 7057826SJose.Borrego@Sun.COM smbd.s_kbound = B_TRUE; 7067826SJose.Borrego@Sun.COM return (0); 7076432Sas200622 } 7086432Sas200622 7096139Sjb150015 (void) close(smbd.s_drv_fd); 7106139Sjb150015 smbd.s_drv_fd = -1; 7116139Sjb150015 return (rc); 7125331Samw } 7135331Samw 7146139Sjb150015 /* 7156139Sjb150015 * smbd_kernel_unbind 7166139Sjb150015 */ 7176139Sjb150015 static void 7186139Sjb150015 smbd_kernel_unbind(void) 7196139Sjb150015 { 7206139Sjb150015 if (smbd.s_drv_fd != -1) { 7216139Sjb150015 (void) close(smbd.s_drv_fd); 7226139Sjb150015 smbd.s_drv_fd = -1; 7236432Sas200622 smbd.s_kbound = B_FALSE; 7246139Sjb150015 } 7256139Sjb150015 } 7265331Samw 7278167Samw@Sun.COM int 7288167Samw@Sun.COM smbd_ioctl(int cmd, smb_io_t *smb_io) 7298167Samw@Sun.COM { 7308167Samw@Sun.COM smb_io->sio_version = SMB_IOC_VERSION; 7318167Samw@Sun.COM smb_io->sio_crc = 0; 7328167Samw@Sun.COM smb_io->sio_crc = smb_crc_gen((uint8_t *)smb_io, sizeof (smb_io_t)); 7338167Samw@Sun.COM 7348167Samw@Sun.COM return (ioctl(smbd.s_drv_fd, cmd, smb_io)); 7358167Samw@Sun.COM } 7368167Samw@Sun.COM 7375331Samw /* 7385331Samw * Initialization of the localtime thread. 7395331Samw * Returns 0 on success, an error number if thread creation fails. 7405331Samw */ 7415331Samw 7425331Samw int 7435331Samw smbd_localtime_init(void) 7445331Samw { 7455331Samw pthread_attr_t tattr; 7465331Samw int rc; 7475331Samw 7485331Samw (void) pthread_attr_init(&tattr); 7495331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 7505331Samw rc = pthread_create(&localtime_thr, &tattr, smbd_localtime_monitor, 0); 7515331Samw (void) pthread_attr_destroy(&tattr); 7525331Samw return (rc); 7535331Samw } 7545331Samw 7555331Samw /* 7565331Samw * Local time thread to kernel land. 7575331Samw * Send local gmtoff to kernel module one time at startup 7585331Samw * and each time it changes (up to twice a year). 7595331Samw * Local gmtoff is checked once every 15 minutes and 7605331Samw * since some timezones are aligned on half and qtr hour boundaries, 7615331Samw * once an hour would likely suffice. 7625331Samw */ 7635331Samw 7645331Samw /*ARGSUSED*/ 7655331Samw static void * 7665331Samw smbd_localtime_monitor(void *arg) 7675331Samw { 7688167Samw@Sun.COM smb_io_t smb_io; 7695331Samw struct tm local_tm; 7707348SJose.Borrego@Sun.COM time_t secs; 7717348SJose.Borrego@Sun.COM int32_t gmtoff, last_gmtoff = -1; 7725331Samw int timeout; 7735331Samw 7748167Samw@Sun.COM bzero(&smb_io, sizeof (smb_io)); 7758167Samw@Sun.COM 7765331Samw for (;;) { 7777348SJose.Borrego@Sun.COM gmtoff = smbd_gmtoff(); 7785331Samw 7795331Samw if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) { 7808167Samw@Sun.COM smb_io.sio_data.gmtoff = gmtoff; 7818167Samw@Sun.COM if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) { 7825331Samw smbd_report("localtime ioctl: %s", 7835331Samw strerror(errno)); 7845331Samw } 7855331Samw } 7865331Samw 7875331Samw /* 7885331Samw * Align the next iteration on a fifteen minute boundary. 7895331Samw */ 7905331Samw secs = time(0); 7915331Samw (void) localtime_r(&secs, &local_tm); 7925331Samw timeout = ((15 - (local_tm.tm_min % 15)) * SECSPERMIN); 7935331Samw (void) sleep(timeout); 7945331Samw 7955331Samw last_gmtoff = gmtoff; 7965331Samw } 7975331Samw 7985331Samw /*NOTREACHED*/ 7995331Samw return (NULL); 8005331Samw } 8015331Samw 8027348SJose.Borrego@Sun.COM /* 8037348SJose.Borrego@Sun.COM * smbd_gmtoff 8047348SJose.Borrego@Sun.COM * 8057348SJose.Borrego@Sun.COM * Determine offset from GMT. If daylight saving time use altzone, 8067348SJose.Borrego@Sun.COM * otherwise use timezone. 8077348SJose.Borrego@Sun.COM */ 8087348SJose.Borrego@Sun.COM static int32_t 8097348SJose.Borrego@Sun.COM smbd_gmtoff(void) 8107348SJose.Borrego@Sun.COM { 8117348SJose.Borrego@Sun.COM time_t clock_val; 8127348SJose.Borrego@Sun.COM struct tm *atm; 8137348SJose.Borrego@Sun.COM int32_t gmtoff; 8147348SJose.Borrego@Sun.COM 8157348SJose.Borrego@Sun.COM (void) time(&clock_val); 8167348SJose.Borrego@Sun.COM atm = localtime(&clock_val); 8177348SJose.Borrego@Sun.COM 8187348SJose.Borrego@Sun.COM gmtoff = (atm->tm_isdst) ? altzone : timezone; 8197348SJose.Borrego@Sun.COM 8207348SJose.Borrego@Sun.COM return (gmtoff); 8217348SJose.Borrego@Sun.COM } 8227348SJose.Borrego@Sun.COM 8235331Samw static void 8245331Samw smbd_sig_handler(int sigval) 8255331Samw { 8265331Samw if (smbd.s_sigval == 0) 8278334SJose.Borrego@Sun.COM (void) atomic_swap_uint(&smbd.s_sigval, sigval); 8288334SJose.Borrego@Sun.COM 8298334SJose.Borrego@Sun.COM if (sigval == SIGHUP) { 8308334SJose.Borrego@Sun.COM atomic_inc_uint(&smbd.s_refreshes); 8318334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8328334SJose.Borrego@Sun.COM } 8338334SJose.Borrego@Sun.COM 8348334SJose.Borrego@Sun.COM if (sigval == SIGINT || sigval == SIGTERM) { 8358334SJose.Borrego@Sun.COM smbd.s_shutting_down = B_TRUE; 8368334SJose.Borrego@Sun.COM (void) pthread_cond_signal(&refresh_cond); 8378334SJose.Borrego@Sun.COM } 8385331Samw } 8395331Samw 8405331Samw /* 8415331Samw * Set up configuration options and parse the command line. 8425331Samw * This function will determine if we will run as a daemon 8435331Samw * or in the foreground. 8445331Samw * 8455331Samw * Failure to find a uid or gid results in using the default (0). 8465331Samw */ 8475331Samw static int 8485331Samw smbd_setup_options(int argc, char *argv[]) 8495331Samw { 8505331Samw struct passwd *pwd; 8515331Samw struct group *grp; 8525331Samw int c; 8535331Samw 8545331Samw if ((pwd = getpwnam("root")) != NULL) 8555331Samw smbd.s_uid = pwd->pw_uid; 8565331Samw 8575331Samw if ((grp = getgrnam("sys")) != NULL) 8585331Samw smbd.s_gid = grp->gr_gid; 8595331Samw 8605772Sas200622 smbd.s_fg = smb_config_get_fg_flag(); 8615331Samw 8625331Samw while ((c = getopt(argc, argv, ":f")) != -1) { 8635331Samw switch (c) { 8645331Samw case 'f': 8655331Samw smbd.s_fg = 1; 8665331Samw break; 8675331Samw 8685331Samw case ':': 8695331Samw case '?': 8705331Samw default: 8715331Samw smbd_usage(stderr); 8725331Samw return (-1); 8735331Samw } 8745331Samw } 8755331Samw 8765331Samw return (0); 8775331Samw } 8785331Samw 8795331Samw static void 8805331Samw smbd_usage(FILE *fp) 8815331Samw { 8825331Samw static char *help[] = { 8835331Samw "-f run program in foreground" 8845331Samw }; 8855331Samw 8865331Samw int i; 8875331Samw 8885331Samw (void) fprintf(fp, "Usage: %s [-f]\n", smbd.s_pname); 8895331Samw 8905331Samw for (i = 0; i < sizeof (help)/sizeof (help[0]); ++i) 8915331Samw (void) fprintf(fp, " %s\n", help[i]); 8925331Samw } 8935331Samw 8945331Samw static void 8955331Samw smbd_report(const char *fmt, ...) 8965331Samw { 8975331Samw char buf[128]; 8985331Samw va_list ap; 8995331Samw 9005331Samw if (fmt == NULL) 9015331Samw return; 9025331Samw 9035331Samw va_start(ap, fmt); 9045331Samw (void) vsnprintf(buf, 128, fmt, ap); 9055331Samw va_end(ap); 9065331Samw 9075331Samw (void) fprintf(stderr, "smbd: %s\n", buf); 9085331Samw } 9095331Samw 9105331Samw /* 9115331Samw * Enable libumem debugging by default on DEBUG builds. 9125331Samw */ 9135331Samw #ifdef DEBUG 9145331Samw const char * 9155331Samw _umem_debug_init(void) 9165331Samw { 9175331Samw return ("default,verbose"); /* $UMEM_DEBUG setting */ 9185331Samw } 9195331Samw 9205331Samw const char * 9215331Samw _umem_logging_init(void) 9225331Samw { 9235331Samw return ("fail,contents"); /* $UMEM_LOGGING setting */ 9245331Samw } 9255331Samw #endif 926