Ejemplo n.º 1
0
 int main(int argc, const char *argv[])
{
	bool is_daemon = false;
	bool opt_interactive = false;
	bool Fork = true;
	bool no_process_group = false;
	bool log_stdout = false;
	poptContext pc;
	char *p_lmhosts = NULL;
	int opt;
	struct messaging_context *msg;
	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" },
	{"hosts", 'H', POPT_ARG_STRING, &p_lmhosts, 0, "Load a netbios hosts file"},
	{"port", 'p', POPT_ARG_INT, &global_nmb_port, 0, "Listen on the specified port" },
	POPT_COMMON_SAMBA
	POPT_COMMON_DYNCONFIG
	POPT_TABLEEND
	};
	TALLOC_CTX *frame;
	NTSTATUS status;
	bool ok;

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

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

	setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);

	load_case_tables();

	global_nmb_port = NMB_PORT;

	pc = poptGetContext("nmbd", argc, argv, long_options, 0);
	while ((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt) {
		case OPT_DAEMON:
			is_daemon = true;
			break;
		case OPT_INTERACTIVE:
			opt_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;
		default:
			d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
				  poptBadOption(pc, 0), poptStrerror(opt));
			poptPrintUsage(pc, stderr, 0);
			exit(1);
		}
	};
	poptFreeContext(pc);

	global_in_nmbd = true;

	StartupTime = time(NULL);

	sys_srandom(time(NULL) ^ getpid());

	if (!override_logfile) {
		char *lfile = NULL;
		if (asprintf(&lfile, "%s/log.nmbd", get_dyn_LOGFILEBASE()) < 0) {
			exit(1);
		}
		lp_set_logfile(lfile);
		SAFE_FREE(lfile);
	}

	fault_setup();
	dump_core_setup("nmbd", lp_logfile(talloc_tos()));

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

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

	/* We no longer use USR2... */
#if defined(SIGUSR2)
	BlockSignals(True, SIGUSR2);
#endif

	/* Ignore children - no zombies. */
	CatchChild();

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

	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);
	}

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

	reopen_logs();

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

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

	reopen_logs();

	if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
	    && !lp_parm_bool(-1, "server role check", "inhibit", false)) {
		/* TODO: when we have a merged set of defaults for
		 * loadparm, we could possibly check if the internal
		 * nbt server is in the list, and allow a startup if disabled */
		DEBUG(0, ("server role = 'active directory domain controller' not compatible with running nmbd standalone. \n"));
		DEBUGADD(0, ("You should start 'samba' instead, and it will control starting the internal nbt server\n"));
		exit(1);
	}

	msg = messaging_init(NULL, server_event_context());
	if (msg == NULL) {
		return 1;
	}

	if ( !reload_nmbd_services(False) )
		return(-1);

	if(!init_names())
		return -1;

	reload_nmbd_services( True );

	if (strequal(lp_workgroup(),"*")) {
		DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
		exit(1);
	}

	set_samba_nb_type();

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

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

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

#ifndef SYNC_DNS
	/* Setup the async dns. We do it here so it doesn't have all the other
		stuff initialised and thus chewing memory and sockets */
	if(lp_we_are_a_wins_server() && lp_wins_dns_proxy()) {
		start_async_dns(msg);
	}
#endif

	ok = directory_create_or_exist(lp_lockdir(), geteuid(), 0755);
	if (!ok) {
		exit_daemon("Failed to create directory for lock files, check 'lock directory'", errno);
	}

	ok = directory_create_or_exist(lp_piddir(), geteuid(), 0755);
	if (!ok) {
		exit_daemon("Failed to create directory for pid files, check 'pid directory'", errno);
	}

	pidfile_create(lp_piddir(), "nmbd");

	status = reinit_after_fork(msg, nmbd_event_context(),
				   false);

	if (!NT_STATUS_IS_OK(status)) {
		exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
	}

	/*
	 * Do not initialize the parent-child-pipe before becoming
	 * a daemon: this is used to detect a died parent in the child
	 * process.
	 */
	status = init_before_fork();
	if (!NT_STATUS_IS_OK(status)) {
		exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
	}

	if (!nmbd_setup_sig_term_handler(msg))
		exit_daemon("NMBD failed to setup signal handler", EINVAL);
	if (!nmbd_setup_stdin_handler(msg, !Fork))
		exit_daemon("NMBD failed to setup stdin handler", EINVAL);
	if (!nmbd_setup_sig_hup_handler(msg))
		exit_daemon("NMBD failed to setup SIGHUP handler", EINVAL);

	/* get broadcast messages */

	if (!serverid_register(messaging_server_id(msg),
				FLAG_MSG_GENERAL |
				FLAG_MSG_NMBD |
				FLAG_MSG_DBWRAP)) {
		exit_daemon("Could not register NMBD process in serverid.tdb", EACCES);
	}

	messaging_register(msg, NULL, MSG_FORCE_ELECTION,
			   nmbd_message_election);
#if 0
	/* Until winsrepl is done. */
	messaging_register(msg, NULL, MSG_WINS_NEW_ENTRY,
			   nmbd_wins_new_entry);
#endif
	messaging_register(msg, NULL, MSG_SHUTDOWN,
			   nmbd_terminate);
	messaging_register(msg, NULL, MSG_SMB_CONF_UPDATED,
			   msg_reload_nmbd_services);
	messaging_register(msg, NULL, MSG_SEND_PACKET,
			   msg_nmbd_send_packet);

	TimeInit();

	DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );

	if ( !open_sockets( is_daemon, global_nmb_port ) ) {
		kill_async_dns_child();
		return 1;
	}

	/* Determine all the IP addresses we have. */
	load_interfaces();

	/* Create an nmbd subnet record for each of the above. */
	if( False == create_subnets() ) {
		kill_async_dns_child();
		exit_daemon("NMBD failed when creating subnet lists", EACCES);
	}

	/* Load in any static local names. */ 
	if (p_lmhosts) {
		set_dyn_LMHOSTSFILE(p_lmhosts);
	}
	load_lmhosts_file(get_dyn_LMHOSTSFILE());
	DEBUG(3,("Loaded hosts file %s\n", get_dyn_LMHOSTSFILE()));

	/* If we are acting as a WINS server, initialise data structures. */
	if( !initialise_wins() ) {
		kill_async_dns_child();
		exit_daemon( "NMBD failed when initialising WINS server.", EACCES);
	}

	/* 
	 * Register nmbd primary workgroup and nmbd names on all
	 * the broadcast subnets, and on the WINS server (if specified).
	 * Also initiate the startup of our primary workgroup (start
	 * elections if we are setup as being able to be a local
	 * master browser.
	 */

	if( False == register_my_workgroup_and_names() ) {
		kill_async_dns_child();
		exit_daemon( "NMBD failed when creating my workgroup.", EACCES);
	}

	if (!initialize_nmbd_proxy_logon()) {
		kill_async_dns_child();
		exit_daemon( "NMBD failed to setup nmbd_proxy_logon.", EACCES);
	}

	if (!nmbd_init_packet_server()) {
		kill_async_dns_child();
		exit_daemon( "NMBD failed to setup packet server.", EACCES);
	}

	if (is_daemon && !opt_interactive) {
		daemon_ready("nmbd");
	}

	TALLOC_FREE(frame);
	process(msg);

	kill_async_dns_child();
	return(0);
}
Ejemplo n.º 2
0
/*
  query a name
*/
static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
				  struct nbt_name_socket *nbtsock, 
				  struct nbt_name_packet *packet, 
				  struct socket_address *src)
{
	NTSTATUS status;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	struct nbt_name *name = &packet->questions[0].name;
	struct winsdb_record *rec;
	struct winsdb_record *rec_1b = NULL;
	const char **addresses;
	const char **addresses_1b = NULL;
	uint16_t nb_flags = 0;

	if (name->type == NBT_NAME_MASTER) {
		goto notfound;
	}

	/*
	 * w2k3 returns the first address of the 0x1B record as first address
	 * to a 0x1C query
	 *
	 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
	 *
	 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
	 * Typ: Daten REG_DWORD
	 * Value: 0 = deactivated, 1 = activated
	 */
	if (name->type == NBT_NAME_LOGON && 
	    lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
		struct nbt_name name_1b;

		name_1b = *name;
		name_1b.type = NBT_NAME_PDC;

		status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
		if (NT_STATUS_IS_OK(status)) {
			addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
		}
	}

	status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
	if (!NT_STATUS_IS_OK(status)) {
		if (!lp_wins_dns_proxy(lp_ctx)) {
			goto notfound;
		}

		if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
			goto notfound;
		}

		nbtd_wins_dns_proxy_query(nbtsock, packet, src);
		return;
	}

	/*
	 * for group's we always reply with
	 * 255.255.255.255 as address, even if
	 * the record is released or tombstoned
	 */
	if (rec->type == WREPL_TYPE_GROUP) {
		addresses = str_list_add(NULL, "255.255.255.255");
		talloc_steal(packet, addresses);
		if (!addresses) {
			goto notfound;
		}
		nb_flags |= NBT_NM_GROUP;
		goto found;
	}

	if (rec->state != WREPL_STATE_ACTIVE) {
		goto notfound;
	}

	addresses = winsdb_addr_string_list(packet, rec->addresses);
	if (!addresses) {
		goto notfound;
	}

	/* 
	 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
	 * first 0x1B address as first address
	 */
	if (addresses_1b && addresses_1b[0]) {
		const char **addresses_1c = addresses;
		uint32_t i;
		uint32_t num_addrs;

		addresses = str_list_add(NULL, addresses_1b[0]);
		if (!addresses) {
			goto notfound;
		}
		talloc_steal(packet, addresses);
		num_addrs = 1;

		for (i=0; addresses_1c[i]; i++) {
			if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;

			/*
			 * stop when we already have 25 addresses
			 */
			if (num_addrs >= 25) break;

			num_addrs++;			
			addresses = str_list_add(addresses, addresses_1c[i]);
			if (!addresses) {
				goto notfound;
			}
		}
	}

	if (rec->type == WREPL_TYPE_SGROUP) {
		nb_flags |= NBT_NM_GROUP;
	} else {
		nb_flags |= (rec->node <<13);
	}

	/*
	 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
	 *
	 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
	 * Typ: Daten REG_DWORD
	 * Value: 0 = deactivated, 1 = activated
	 */
	if (name->type == NBT_NAME_LOGON && 
	    lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
		nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
	}

found:
	nbtd_name_query_reply(nbtsock, packet, src, name, 
			      0, nb_flags, addresses);
	return;

notfound:
	nbtd_negative_name_query_reply(nbtsock, packet, src);
}