Example #1
0
File: server.c Project: nguay/SSSD
void become_daemon(bool Fork)
{
        int ret;

	if (Fork) {
		if (fork()) {
			_exit(0);
		}
	}

    /* detach from the terminal */
	setsid();

        /* chdir to / to be sure we're not on a remote filesystem */
        errno = 0;
        if(chdir("/") == -1) {
            ret = errno;
            DEBUG(0, ("Cannot change directory (%d [%s])\n",
                    ret, strerror(ret)));
            return;
        }

	/* Close fd's 0,1,2. Needed if started by rsh */
	close_low_fds();
}
Example #2
0
_PUBLIC_ void become_daemon(bool do_fork, bool no_process_group, bool log_stdout)
{
	if (do_fork) {
		if (sys_fork()) {
			_exit(0);
		}
	}

	/* detach from the terminal */
#ifdef HAVE_SETSID
	if (!no_process_group) setsid();
#elif defined(TIOCNOTTY)
	if (!no_process_group) {
		int i = sys_open("/dev/tty", O_RDWR, 0);
		if (i != -1) {
			ioctl(i, (int) TIOCNOTTY, (char *)0);
			close(i);
		}
	}
#endif /* HAVE_SETSID */

	if (!log_stdout) {
		/* Close fd's 0,1,2. Needed if started by rsh */
		close_low_fds(false);  /* Don't close stderr, let the debug system
					  attach it to the logfile */
	}
}
Example #3
0
_PUBLIC_ void become_daemon(bool do_fork, bool no_process_group, bool log_stdout)
{
	pid_t newpid;
	if (do_fork) {
		newpid = fork();
		if (newpid) {
#if HAVE_SYSTEMD
			sd_notifyf(0, "READY=0\nSTATUS=Starting process...\nMAINPID=%lu", (unsigned long) newpid);
#endif /* HAVE_SYSTEMD */
			_exit(0);
		}
	}

	/* detach from the terminal */
#ifdef HAVE_SETSID
	if (!no_process_group) setsid();
#elif defined(TIOCNOTTY)
	if (!no_process_group) {
		int i = open("/dev/tty", O_RDWR, 0);
		if (i != -1) {
			ioctl(i, (int) TIOCNOTTY, (char *)0);
			close(i);
		}
	}
#endif /* HAVE_SETSID */

	/* Close fd's 0,1,2 as appropriate. Needed if started by rsh. */
	/* stdin must be open if we do not fork, for monitoring for
	 * close.  stdout must be open if we are logging there, and we
	 * never close stderr (but debug might dup it onto a log file) */
	close_low_fds(do_fork, !log_stdout, false);
}
Example #4
0
BOOL reopen_logs( void )
{
    pstring fname;
    mode_t oldumask;
    XFILE *new_dbf = NULL;
    XFILE *old_dbf = NULL;
    BOOL ret = True;

    if (stdout_logging)
        return True;

    oldumask = umask( 022 );

    pstrcpy(fname, debugf );

    if (lp_loaded()) {
        char *logfname;

        logfname = lp_logfile();
        if (*logfname)
            pstrcpy(fname, logfname);
    }

    pstrcpy( debugf, fname );
    new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);

    if (!new_dbf) {
        log_overflow = True;
        DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
        log_overflow = False;
        if (dbf)
            x_fflush(dbf);
        ret = False;
    } else {
        x_setbuf(new_dbf, NULL);
        old_dbf = dbf;
        dbf = new_dbf;
        if (old_dbf)
            (void) x_fclose(old_dbf);
    }

    /* Fix from [email protected]
     * to fix problem where smbd's that generate less
     * than 100 messages keep growing the log.
     */
    force_check_log_size();
    (void)umask(oldumask);

    /* Take over stderr to catch ouput into logs */
    if (dbf && sys_dup2(x_fileno(dbf), 2) == -1) {
        close_low_fds(True); /* Close stderr too, if dup2 can't point it
					at the logfile */
    }

    return ret;
}
Example #5
0
static BOOL open_sockets_inetd(void)
{
	/* Started from inetd. fd 0 is the socket. */
	/* We will abort gracefully when the client or remote system 
	   goes away */
	smbd_set_server_fd(dup(0));
	
	/* close our standard file descriptors */
	close_low_fds(False); /* Don't close stderr */
	
	set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
	set_socket_options(smbd_server_fd(), user_socket_options);

	return True;
}
Example #6
0
void start_epmd(struct tevent_context *ev_ctx,
		struct messaging_context *msg_ctx)
{
	struct rpc_srv_callbacks epmapper_cb;
	NTSTATUS status;
	pid_t pid;
	bool ok;
	int rc;

	epmapper_cb.init = NULL;
	epmapper_cb.shutdown = epmapper_shutdown_cb;
	epmapper_cb.private_data = NULL;

	DEBUG(1, ("Forking Endpoint Mapper Daemon\n"));

	pid = sys_fork();

	if (pid == -1) {
		DEBUG(0, ("Failed to fork Endpoint Mapper [%s], aborting ...\n",
			  strerror(errno)));
		exit(1);
	}

	if (pid) {
		/* parent */
		return;
	}

	/* child */
	close_low_fds(false);

	status = reinit_after_fork(msg_ctx,
				   ev_ctx,
				   procid_self(),
				   true);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("reinit_after_fork() failed\n"));
		smb_panic("reinit_after_fork() failed");
	}

	epmd_reopen_logs();

	epmd_setup_sig_term_handler(ev_ctx);
	epmd_setup_sig_hup_handler(ev_ctx, msg_ctx);

	ok = serverid_register(procid_self(),
			       FLAG_MSG_GENERAL|FLAG_MSG_SMBD
			       |FLAG_MSG_PRINT_GENERAL);
	if (!ok) {
		DEBUG(0, ("Failed to register serverid in epmd!\n"));
		exit(1);
	}

	messaging_register(msg_ctx,
			   ev_ctx,
			   MSG_SMB_CONF_UPDATED,
			   epmd_smb_conf_updated);

	status = rpc_epmapper_init(&epmapper_cb);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to register epmd rpc inteface! (%s)\n",
			  nt_errstr(status)));
		exit(1);
	}

	ok = setup_dcerpc_ncalrpc_socket(ev_ctx,
					 msg_ctx,
					 ndr_table_epmapper.syntax_id,
					 "EPMAPPER",
					 srv_epmapper_delete_endpoints);
	if (!ok) {
		DEBUG(0, ("Failed to open epmd ncalrpc pipe!\n"));
		exit(1);
	}

	ok = epmd_open_sockets(ev_ctx, msg_ctx);
	if (!ok) {
		DEBUG(0, ("Failed to open epmd tcpip sockets!\n"));
		exit(1);
	}

	ok = setup_named_pipe_socket("epmapper", ev_ctx);
	if (!ok) {
		DEBUG(0, ("Failed to open epmd named pipe!\n"));
		exit(1);
	}

	DEBUG(1, ("Endpoint Mapper Daemon Started (%d)\n", getpid()));

	/* loop forever */
	rc = tevent_loop_wait(ev_ctx);

	/* should not be reached */
	DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
		 rc, (rc == 0) ? "out of events" : strerror(errno)));

	exit(1);
}
Example #7
0
 int main(int argc,const char *argv[])
{
	/* shall I run as a daemon */
	bool is_daemon = false;
	bool interactive = false;
	bool Fork = true;
	bool no_process_group = false;
	bool log_stdout = false;
	char *ports = NULL;
	char *profile_level = NULL;
	int opt;
	poptContext pc;
	bool print_build_options = False;
        enum {
		OPT_DAEMON = 1000,
		OPT_INTERACTIVE,
		OPT_FORK,
		OPT_NO_PROCESS_GROUP,
		OPT_LOG_STDOUT
	};
	struct poptOption long_options[] = {
	POPT_AUTOHELP
	{"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" },
	{"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)"},
	{"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools, etc.)" },
	{"no-process-group", '\0', POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
	{"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
	{"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" },
	{"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"},
	{"profiling-level", 'P', POPT_ARG_STRING, &profile_level, 0, "Set profiling level","PROFILE_LEVEL"},
	POPT_COMMON_SAMBA
	POPT_COMMON_DYNCONFIG
	POPT_TABLEEND
	};
	struct smbd_parent_context *parent = NULL;
	TALLOC_CTX *frame;
	NTSTATUS status;
	uint64_t unique_id;
	struct tevent_context *ev_ctx;
	struct messaging_context *msg_ctx;

	/*
	 * Do this before any other talloc operation
	 */
	talloc_enable_null_tracking();
	frame = talloc_stackframe();

	setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);

	load_case_tables();

	smbd_init_globals();

	TimeInit();

#ifdef HAVE_SET_AUTH_PARAMETERS
	set_auth_parameters(argc,argv);
#endif

	pc = poptGetContext("smbd", argc, argv, long_options, 0);
	while((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt)  {
		case OPT_DAEMON:
			is_daemon = true;
			break;
		case OPT_INTERACTIVE:
			interactive = true;
			break;
		case OPT_FORK:
			Fork = false;
			break;
		case OPT_NO_PROCESS_GROUP:
			no_process_group = true;
			break;
		case OPT_LOG_STDOUT:
			log_stdout = true;
			break;
		case 'b':
			print_build_options = True;
			break;
		default:
			d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
				  poptBadOption(pc, 0), poptStrerror(opt));
			poptPrintUsage(pc, stderr, 0);
			exit(1);
		}
	}
	poptFreeContext(pc);

	if (interactive) {
		Fork = False;
		log_stdout = True;
	}

	if (log_stdout) {
		setup_logging(argv[0], DEBUG_STDOUT);
	} else {
		setup_logging(argv[0], DEBUG_FILE);
	}

	if (print_build_options) {
		build_options(True); /* Display output to screen as well as debug */
		exit(0);
	}

#ifdef HAVE_SETLUID
	/* needed for SecureWare on SCO */
	setluid(0);
#endif

	set_remote_machine_name("smbd", False);

	if (interactive && (DEBUGLEVEL >= 9)) {
		talloc_enable_leak_report();
	}

	if (log_stdout && Fork) {
		DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
		exit(1);
	}

	/* we want to re-seed early to prevent time delays causing
           client problems at a later date. (tridge) */
	generate_random_buffer(NULL, 0);

	/* get initial effective uid and gid */
	sec_init();

	/* make absolutely sure we run as root - to handle cases where people
	   are crazy enough to have it setuid */
	gain_root_privilege();
	gain_root_group_privilege();

	fault_setup();
	dump_core_setup("smbd", lp_logfile());

	/* we are never interested in SIGPIPE */
	BlockSignals(True,SIGPIPE);

#if defined(SIGFPE)
	/* we are never interested in SIGFPE */
	BlockSignals(True,SIGFPE);
#endif

#if defined(SIGUSR2)
	/* We are no longer interested in USR2 */
	BlockSignals(True,SIGUSR2);
#endif

	/* POSIX demands that signals are inherited. If the invoking process has
	 * these signals masked, we will have problems, as we won't recieve them. */
	BlockSignals(False, SIGHUP);
	BlockSignals(False, SIGUSR1);
	BlockSignals(False, SIGTERM);

	/* Ensure we leave no zombies until we
	 * correctly set up child handling below. */

	CatchChild();

	/* we want total control over the permissions on created files,
	   so set our umask to 0 */
	umask(0);

	reopen_logs();

	DEBUG(0,("smbd version %s started.\n", samba_version_string()));
	DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));

	DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
		 (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));

	/* Output the build options to the debug log */ 
	build_options(False);

	if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
		DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
		exit(1);
	}

	if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
		DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE()));
		exit(1);
	}

	/* Init the security context and global current_user */
	init_sec_ctx();

	/*
	 * Initialize the event context. The event context needs to be
	 * initialized before the messaging context, cause the messaging
	 * context holds an event context.
	 * FIXME: This should be s3_tevent_context_init()
	 */
	ev_ctx = server_event_context();
	if (ev_ctx == NULL) {
		exit(1);
	}

	/*
	 * Init the messaging context
	 * FIXME: This should only call messaging_init()
	 */
	msg_ctx = server_messaging_context();
	if (msg_ctx == NULL) {
		exit(1);
	}

	/*
	 * Reloading of the printers will not work here as we don't have a
	 * server info and rpc services set up. It will be called later.
	 */
	if (!reload_services(NULL, -1, False)) {
		exit(1);
	}

	/* ...NOTE... Log files are working from this point! */

	DEBUG(3,("loaded services\n"));

	init_structs();

#ifdef WITH_PROFILE
	if (!profile_setup(msg_ctx, False)) {
		DEBUG(0,("ERROR: failed to setup profiling\n"));
		return -1;
	}
	if (profile_level != NULL) {
		int pl = atoi(profile_level);
		struct server_id src;

		DEBUG(1, ("setting profiling level: %s\n",profile_level));
		src.pid = getpid();
		set_profile_level(pl, src);
	}
#endif

	if (!is_daemon && !is_a_socket(0)) {
		if (!interactive)
			DEBUG(0,("standard input is not a socket, assuming -D option\n"));

		/*
		 * Setting is_daemon here prevents us from eventually calling
		 * the open_sockets_inetd()
		 */

		is_daemon = True;
	}

	if (is_daemon && !interactive) {
		DEBUG( 3, ( "Becoming a daemon.\n" ) );
		become_daemon(Fork, no_process_group, log_stdout);
	}

        generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));
        set_my_unique_id(unique_id);

#if HAVE_SETPGID
	/*
	 * If we're interactive we want to set our own process group for
	 * signal management.
	 */
	if (interactive && !no_process_group)
		setpgid( (pid_t)0, (pid_t)0);
#endif

	if (!directory_exist(lp_lockdir()))
		mkdir(lp_lockdir(), 0755);

	if (is_daemon)
		pidfile_create("smbd");

	status = reinit_after_fork(msg_ctx,
				   ev_ctx,
				   procid_self(), false);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("reinit_after_fork() failed\n"));
		exit(1);
	}

	smbd_server_conn->msg_ctx = msg_ctx;

	smbd_setup_sig_term_handler();
	smbd_setup_sig_hup_handler(ev_ctx,
				   msg_ctx);

	/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */

	if (smbd_memcache() == NULL) {
		exit(1);
	}

	memcache_set_global(smbd_memcache());

	/* Initialise the password backed before the global_sam_sid
	   to ensure that we fetch from ldap before we make a domain sid up */

	if(!initialize_password_db(false, ev_ctx))
		exit(1);

	if (!secrets_init()) {
		DEBUG(0, ("ERROR: smbd can not open secrets.tdb\n"));
		exit(1);
	}

	if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
		struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_context());
		if (!open_schannel_session_store(NULL, lp_ctx)) {
			DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n"));
			exit(1);
		}
		TALLOC_FREE(lp_ctx);
	}

	if(!get_global_sam_sid()) {
		DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
		exit(1);
	}

	if (!sessionid_init()) {
		exit(1);
	}

	if (!connections_init(True))
		exit(1);

	if (!locking_init())
		exit(1);

	if (!messaging_tdb_parent_init(ev_ctx)) {
		exit(1);
	}

	if (!notify_internal_parent_init(ev_ctx)) {
		exit(1);
	}

	if (!serverid_parent_init(ev_ctx)) {
		exit(1);
	}

	if (!W_ERROR_IS_OK(registry_init_full()))
		exit(1);

	/* Open the share_info.tdb here, so we don't have to open
	   after the fork on every single connection.  This is a small
	   performance improvment and reduces the total number of system
	   fds used. */
	if (!share_info_db_init()) {
		DEBUG(0,("ERROR: failed to load share info db.\n"));
		exit(1);
	}

	status = init_system_info();
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("ERROR: failed to setup system user info: %s.\n",
			  nt_errstr(status)));
		return -1;
	}

	if (!init_guest_info()) {
		DEBUG(0,("ERROR: failed to setup guest info.\n"));
		return -1;
	}

	if (!file_init(smbd_server_conn)) {
		DEBUG(0, ("ERROR: file_init failed\n"));
		return -1;
	}

	/* This MUST be done before start_epmd() because otherwise
	 * start_epmd() forks and races against dcesrv_ep_setup() to
	 * call directory_create_or_exist() */
	if (!directory_create_or_exist(lp_ncalrpc_dir(), geteuid(), 0755)) {
		DEBUG(0, ("Failed to create pipe directory %s - %s\n",
			  lp_ncalrpc_dir(), strerror(errno)));
		return -1;
	}

	if (is_daemon && !interactive) {
		if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
			start_epmd(ev_ctx, msg_ctx);
		}
	}

	if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) {
		exit(1);
	}

	/* only start other daemons if we are running as a daemon
	 * -- bad things will happen if smbd is launched via inetd
	 *  and we fork a copy of ourselves here */
	if (is_daemon && !interactive) {

		if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) {
			start_lsasd(ev_ctx, msg_ctx);
		}

		if (!_lp_disable_spoolss() &&
		    (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
			bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);

			if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) {
				exit(1);
			}
		}
	} else if (!_lp_disable_spoolss() &&
		   (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
		if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
			exit(1);
		}
	}

	if (!is_daemon) {
		/* inetd mode */
		TALLOC_FREE(frame);

		/* Started from inetd. fd 0 is the socket. */
		/* We will abort gracefully when the client or remote system
		   goes away */
		smbd_server_conn->sock = dup(0);

		/* close our standard file descriptors */
		if (!debug_get_output_is_stdout()) {
			close_low_fds(False); /* Don't close stderr */
		}

#ifdef HAVE_ATEXIT
		atexit(killkids);
#endif

	        /* Stop zombies */
		smbd_setup_sig_chld_handler(ev_ctx);

		smbd_process(ev_ctx, smbd_server_conn);

		exit_server_cleanly(NULL);
		return(0);
	}

	parent = talloc_zero(ev_ctx, struct smbd_parent_context);
	if (!parent) {
		exit_server("talloc(struct smbd_parent_context) failed");
	}
	parent->interactive = interactive;

	if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports))
		exit_server("open_sockets_smbd() failed");

	/* do a printer update now that all messaging has been set up,
	 * before we allow clients to start connecting */
	printing_subsystem_update(ev_ctx, msg_ctx, false);

	TALLOC_FREE(frame);
	/* make sure we always have a valid stackframe */
	frame = talloc_stackframe();

	smbd_parent_loop(ev_ctx, parent);

	exit_server_cleanly(NULL);
	TALLOC_FREE(frame);
	return(0);
}
Example #8
0
static void smbd_accept_connection(struct tevent_context *ev,
				   struct tevent_fd *fde,
				   uint16_t flags,
				   void *private_data)
{
	struct smbd_open_socket *s = talloc_get_type_abort(private_data,
				     struct smbd_open_socket);
	struct messaging_context *msg_ctx = s->msg_ctx;
	struct smbd_server_connection *sconn = msg_ctx_to_sconn(msg_ctx);
	struct sockaddr_storage addr;
	socklen_t in_addrlen = sizeof(addr);
	int fd;
	pid_t pid = 0;
	uint64_t unique_id;

	fd = accept(s->fd, (struct sockaddr *)(void *)&addr,&in_addrlen);
	sconn->sock = fd;
	if (fd == -1 && errno == EINTR)
		return;

	if (fd == -1) {
		DEBUG(0,("open_sockets_smbd: accept: %s\n",
			 strerror(errno)));
		return;
	}

	if (s->parent->interactive) {
		smbd_process(ev, sconn);
		exit_server_cleanly("end of interactive mode");
		return;
	}

	if (!allowable_number_of_smbd_processes()) {
		close(fd);
		sconn->sock = -1;
		return;
	}

	/*
	 * Generate a unique id in the parent process so that we use
	 * the global random state in the parent.
	 */
	generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));

	pid = sys_fork();
	if (pid == 0) {
		NTSTATUS status = NT_STATUS_OK;

		/* Child code ... */
		am_parent = 0;

		set_my_unique_id(unique_id);

		/* Stop zombies, the parent explicitly handles
		 * them, counting worker smbds. */
		CatchChild();

		/* close our standard file
		   descriptors */
		if (!debug_get_output_is_stdout()) {
			close_low_fds(False); /* Don't close stderr */
		}

		/*
		 * Can't use TALLOC_FREE here. Nulling out the argument to it
		 * would overwrite memory we've just freed.
		 */
		talloc_free(s->parent);
		s = NULL;

		status = reinit_after_fork(msg_ctx,
					   ev,
					   procid_self(),
					   true);
		if (!NT_STATUS_IS_OK(status)) {
			if (NT_STATUS_EQUAL(status,
					    NT_STATUS_TOO_MANY_OPENED_FILES)) {
				DEBUG(0,("child process cannot initialize "
					 "because too many files are open\n"));
				goto exit;
			}
			if (lp_clustering() &&
			    NT_STATUS_EQUAL(status,
			    NT_STATUS_INTERNAL_DB_ERROR)) {
				DEBUG(1,("child process cannot initialize "
					 "because connection to CTDB "
					 "has failed\n"));
				goto exit;
			}

			DEBUG(0,("reinit_after_fork() failed\n"));
			smb_panic("reinit_after_fork() failed");
		}

		smbd_setup_sig_term_handler();
		smbd_setup_sig_hup_handler(ev,
					   msg_ctx);

		if (!serverid_register(procid_self(),
				       FLAG_MSG_GENERAL|FLAG_MSG_SMBD
				       |FLAG_MSG_DBWRAP
				       |FLAG_MSG_PRINT_GENERAL)) {
			exit_server_cleanly("Could not register myself in "
					    "serverid.tdb");
		}

		smbd_process(ev, sconn);
	 exit:
		exit_server_cleanly("end of child");
		return;
	}

	if (pid < 0) {
		DEBUG(0,("smbd_accept_connection: sys_fork() failed: %s\n",
			 strerror(errno)));
	}

	/* The parent doesn't need this socket */
	close(fd);

	/* Sun May 6 18:56:14 2001 [email protected]:
		Clear the closed fd info out of server_fd --
		and more importantly, out of client_fd in
		util_sock.c, to avoid a possible
		getpeername failure if we reopen the logs
		and use %I in the filename.
	*/
	sconn->sock = -1;

	if (pid != 0) {
		add_child_pid(pid);
	}

	/* Force parent to check log size after
	 * spawning child.  Fix from
	 * [email protected].  The
	 * parent smbd will log to logserver.smb.  It
	 * writes only two messages for each child
	 * started/finished. But each child writes,
	 * say, 50 messages also in logserver.smb,
	 * begining with the debug_count of the
	 * parent, before the child opens its own log
	 * file logserver.client. In a worst case
	 * scenario the size of logserver.smb would be
	 * checked after about 50*50=2500 messages
	 * (ca. 100kb).
	 * */
	force_check_log_size();
}
Example #9
0
void become_daemon(bool Fork)
{
    pid_t pid, cpid;
    int status;
    int ret, error;

    if (Fork) {
        pid = fork();
        if (pid != 0) {
            /* Terminate parent process on demand so we can hold systemd
             * or initd from starting next service until sssd in initialized.
             * We use signals directly here because we don't have a tevent
             * context yet. */
            CatchSignal(SIGTERM, deamon_parent_sigterm);

            /* or exit when sssd monitor is terminated */
            do {
                errno = 0;
                cpid = waitpid(pid, &status, 0);
                if (cpid == 1) {
                    /* An error occurred while waiting */
                    error = errno;
                    if (error != EINTR) {
                        DEBUG(SSSDBG_CRIT_FAILURE,
                              "Error [%d][%s] while waiting for child\n",
                               error, strerror(error));
                        /* Forcibly kill this child */
                        kill(pid, SIGKILL);
                        ret = 1;
                    }
                }

                error = 0;
                /* return error if we didn't exited normally */
                ret = 1;

                if (WIFEXITED(status)) {
                    /* but return our exit code otherwise */
                    ret = WEXITSTATUS(status);
                }
            } while (error == EINTR);

            _exit(ret);
        }
    }

    /* detach from the terminal */
    setsid();

    /* chdir to / to be sure we're not on a remote filesystem */
    errno = 0;
    if(chdir("/") == -1) {
        ret = errno;
        DEBUG(SSSDBG_FATAL_FAILURE, "Cannot change directory (%d [%s])\n",
                                     ret, strerror(ret));
        return;
    }

    /* Close fd's 0,1,2. Needed if started by rsh */
    close_low_fds();
}
Example #10
0
void start_spoolssd(struct tevent_context *ev_ctx,
		    struct messaging_context *msg_ctx)
{
	struct rpc_srv_callbacks spoolss_cb;
	pid_t pid;
	NTSTATUS status;
	int ret;

	DEBUG(1, ("Forking SPOOLSS Daemon\n"));

	pid = sys_fork();

	if (pid == -1) {
		DEBUG(0, ("Failed to fork SPOOLSS [%s], aborting ...\n",
			   strerror(errno)));
		exit(1);
	}

	if (pid) {
		/* parent */
		return;
	}

	/* child */
	close_low_fds(false);

	status = reinit_after_fork(msg_ctx,
				   ev_ctx,
				   procid_self(), true);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("reinit_after_fork() failed\n"));
		smb_panic("reinit_after_fork() failed");
	}

	spoolss_reopen_logs();

	spoolss_setup_sig_term_handler(ev_ctx);
	spoolss_setup_sig_hup_handler(ev_ctx, msg_ctx);

	if (!serverid_register(procid_self(),
				FLAG_MSG_GENERAL|FLAG_MSG_SMBD
				|FLAG_MSG_PRINT_GENERAL)) {
		exit(1);
	}

	if (!locking_init()) {
		exit(1);
	}

	messaging_register(msg_ctx, NULL,
			   MSG_PRINTER_UPDATE, print_queue_receive);
	messaging_register(msg_ctx, ev_ctx,
			   MSG_SMB_CONF_UPDATED, smb_conf_updated);

	/*
	 * Initialize spoolss with an init function to convert printers first.
	 * static_init_rpc will try to initialize the spoolss server too but you
	 * can't register it twice.
	 */
	spoolss_cb.init = spoolss_init_cb;
	spoolss_cb.shutdown = spoolss_shutdown_cb;
	spoolss_cb.private_data = msg_ctx;

	status = rpc_winreg_init(NULL);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to register winreg rpc inteface! (%s)\n",
			  nt_errstr(status)));
		exit(1);
	}

	status = rpc_spoolss_init(&spoolss_cb);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to register spoolss rpc inteface! (%s)\n",
			  nt_errstr(status)));
		exit(1);
	}

	if (!setup_named_pipe_socket(SPOOLSS_PIPE_NAME, ev_ctx)) {
		exit(1);
	}

	status = rpc_ep_setup_register(ev_ctx, msg_ctx, &ndr_table_spoolss, NULL, 0);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to register spoolss endpoint! (%s)\n",
			  nt_errstr(status)));
		exit(1);
	}

	DEBUG(1, ("SPOOLSS Daemon Started (%d)\n", getpid()));

	/* loop forever */
	ret = tevent_loop_wait(ev_ctx);

	/* should not be reached */
	DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
		 ret, (ret == 0) ? "out of events" : strerror(errno)));
	exit(1);
}
Example #11
0
static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports)
{
	int num_interfaces = iface_count();
	int num_sockets = 0;
	int fd_listenset[FD_SETSIZE];
	fd_set listen_set;
	int s;
	int maxfd = 0;
	int i;
	char *ports;

	if (!is_daemon) {
		return open_sockets_inetd();
	}

		
#ifdef HAVE_ATEXIT
	{
		static int atexit_set;
		if(atexit_set == 0) {
			atexit_set=1;
			atexit(killkids);
		}
	}
#endif

#ifndef _XBOX
	/* Stop zombies */
	CatchChild();
#endif

	FD_ZERO(&listen_set);

	/* use a reasonable default set of ports - listing on 445 and 139 */
	if (!smb_ports) {
		ports = lp_smb_ports();
		if (!ports || !*ports) {
			ports = smb_xstrdup(SMB_PORTS);
		} else {
			ports = smb_xstrdup(ports);
		}
	} else {
		ports = smb_xstrdup(smb_ports);
	}

	if (lp_interfaces() && lp_bind_interfaces_only()) {
		/* We have been given an interfaces line, and been 
		   told to only bind to those interfaces. Create a
		   socket per interface and bind to only these.
		*/
		
		/* Now open a listen socket for each of the
		   interfaces. */
		for(i = 0; i < num_interfaces; i++) {
			struct in_addr *ifip = iface_n_ip(i);
			fstring tok;
			const char *ptr;

			if(ifip == NULL) {
				DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
				continue;
			}

			for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
				unsigned port = atoi(tok);
				if (port == 0) {
					continue;
				}
				s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
				if(s == -1)
					return False;

				/* ready to listen */
				set_socket_options(s,"SO_KEEPALIVE"); 
				set_socket_options(s,user_socket_options);
     
				/* Set server socket to non-blocking for the accept. */
				set_blocking(s,False); 
 
				if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
					DEBUG(0,("listen: %s\n",strerror(errno)));
					close(s);
					return False;
				}
				FD_SET(s,&listen_set);
				maxfd = MAX( maxfd, s);

				num_sockets++;
				if (num_sockets >= FD_SETSIZE) {
					DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
					return False;
				}
			}
		}
	} else {
		/* Just bind to 0.0.0.0 - accept connections
		   from anywhere. */

		fstring tok;
		const char *ptr;

		num_interfaces = 1;
		
		for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
			unsigned port = atoi(tok);
			if (port == 0) continue;
			/* open an incoming socket */
			s = open_socket_in(SOCK_STREAM, port, 0,
					   interpret_addr(lp_socket_address()),True);
			if (s == -1)
				return(False);
		
			/* ready to listen */
#ifndef _XBOX
			set_socket_options(s,"SO_KEEPALIVE"); 
#endif
			set_socket_options(s,user_socket_options);
			
			/* Set server socket to non-blocking for the accept. */
			set_blocking(s,False); 
 
			if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
				DEBUG(0,("open_sockets_smbd: listen: %s\n",
					 strerror(errno)));
				close(s);
				return False;
			}

			fd_listenset[num_sockets] = s;
			FD_SET(s,&listen_set);
			maxfd = MAX( maxfd, s);

			num_sockets++;

			if (num_sockets >= FD_SETSIZE) {
				DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
				return False;
			}
		}
	} 

	SAFE_FREE(ports);

        /* Listen to messages */

        message_register(MSG_SMB_SAM_SYNC, msg_sam_sync);
        message_register(MSG_SMB_SAM_REPL, msg_sam_repl);
        message_register(MSG_SHUTDOWN, msg_exit_server);
        message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed);
	message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); 

#ifdef DEVELOPER
	message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault); 
#endif

	/* now accept incoming connections - forking a new process
	   for each incoming connection */
	DEBUG(2,("waiting for a connection\n"));
	while (1) {
		fd_set lfds;
		int num;
		
		/* Free up temporary memory from the main smbd. */
		lp_TALLOC_FREE();

		/* Ensure we respond to PING and DEBUG messages from the main smbd. */
		message_dispatch();

		memcpy((char *)&lfds, (char *)&listen_set, 
		       sizeof(listen_set));
		
		num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL);
		
		if (num == -1 && errno == EINTR) {
			if (got_sig_term) {
				exit_server_cleanly(NULL);
			}

			/* check for sighup processing */
			if (reload_after_sighup) {
				change_to_root_user();
				DEBUG(1,("Reloading services after SIGHUP\n"));
				reload_services(False);
				reload_after_sighup = 0;
			}

			continue;
		}
		
		/* check if we need to reload services */
		check_reload(time(NULL));

		/* Find the sockets that are read-ready -
		   accept on these. */
		for( ; num > 0; num--) {
			struct sockaddr addr;
			socklen_t in_addrlen = sizeof(addr);

			s = -1;
			for(i = 0; i < num_sockets; i++) {
				if(FD_ISSET(fd_listenset[i],&lfds)) {
					s = fd_listenset[i];
					/* Clear this so we don't look
					   at it again. */
					FD_CLR(fd_listenset[i],&lfds);
					break;
				}
			}

			smbd_set_server_fd(accept(s,&addr,&in_addrlen));
			
			if (smbd_server_fd() == -1 && errno == EINTR)
				continue;
			
			if (smbd_server_fd() == -1) {
				DEBUG(0,("open_sockets_smbd: accept: %s\n",
					 strerror(errno)));
				continue;
			}

			/* Ensure child is set to blocking mode */
			set_blocking(smbd_server_fd(),True);

			if (smbd_server_fd() != -1 && interactive) {
#ifdef _XBOX
				xb_IncClientCount();
#endif
				return True;
			}
			
			if (allowable_number_of_smbd_processes() && smbd_server_fd() != -1 && sys_fork()==0) {


				/* Child code ... */			

				/* close the listening socket(s) */
				for(i = 0; i < num_sockets; i++)
					close(fd_listenset[i]);
				
				/* close our standard file
				   descriptors */
				close_low_fds(False);
				am_parent = 0;
				
				set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
				set_socket_options(smbd_server_fd(),user_socket_options);
				
				/* this is needed so that we get decent entries
				   in smbstatus for port 445 connects */
				set_remote_machine_name(get_peer_addr(smbd_server_fd()), False);
				
				/* Reset the state of the random
				 * number generation system, so
				 * children do not get the same random
				 * numbers as each other */

				set_need_random_reseed();
				/* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */
				if (tdb_reopen_all(1) == -1) {
					DEBUG(0,("tdb_reopen_all failed.\n"));
					smb_panic("tdb_reopen_all failed.");
				}

				return True; 
			}
			/* The parent doesn't need this socket */
			close(smbd_server_fd()); 

			/* Sun May 6 18:56:14 2001 [email protected]:
				Clear the closed fd info out of server_fd --
				and more importantly, out of client_fd in
				util_sock.c, to avoid a possible
				getpeername failure if we reopen the logs
				and use %I in the filename.
			*/

			smbd_set_server_fd(-1);

			/* Force parent to check log size after
			 * spawning child.  Fix from
			 * [email protected].  The
			 * parent smbd will log to logserver.smb.  It
			 * writes only two messages for each child
			 * started/finished. But each child writes,
			 * say, 50 messages also in logserver.smb,
			 * begining with the debug_count of the
			 * parent, before the child opens its own log
			 * file logserver.client. In a worst case
			 * scenario the size of logserver.smb would be
			 * checked after about 50*50=2500 messages
			 * (ca. 100kb).
			 * */
			force_check_log_size();
 
		} /* end for num */
	} /* end while 1 */

/* NOTREACHED	return True; */
}