Пример #1
0
main()
{
        if (getuid() != 0) {
#if (defined(AIX) && defined(USE_SETREUID))
		/* setreuid is badly broken on AIX 4.1, we avoid it completely */
                fprintf(stderr,"avoiding possibly broken setreuid\n");
		exit(1);
#endif

		/* if not running as root then at least check to see if we get ENOSYS - this 
		   handles Linux 2.0.x with glibc 2.1 */
                fprintf(stderr,"not running as root: checking for ENOSYS\n");
		exit(have_syscall());
	}

	gain_root_privilege();
	gain_root_group_privilege();
	set_effective_gid(1);
	set_effective_uid(1);
	save_re_uid();
	restore_re_uid();
	gain_root_privilege();
	gain_root_group_privilege();
	become_user_permanently(1, 1);
	setuid(0);
	if (getuid() == 0) {
		fprintf(stderr,"uid not set permanently\n");
		exit(1);
	}

	printf("OK\n");

	exit(0);
}
Пример #2
0
/****************************************************************************
 Become the specified uid and gid - permanently !
 there should be no way back if possible
****************************************************************************/
void become_user_permanently(uid_t uid, gid_t gid)
{
	/*
	 * First - gain root privilege. We do this to ensure
	 * we can lose it again.
	 */

	gain_root_privilege();
	gain_root_group_privilege();

#if USE_SETRESUID
	setresgid(gid,gid,gid);
	setgid(gid);
	setresuid(uid,uid,uid);
	setuid(uid);
#endif

#if USE_SETREUID
	setregid(gid,gid);
	setgid(gid);
	setreuid(uid,uid);
	setuid(uid);
#endif

#if USE_SETEUID
	setegid(gid);
	setgid(gid);
	setuid(uid);
	seteuid(uid);
	setuid(uid);
#endif

#if USE_SETUIDX
	setgidx(ID_REAL, gid);
	setgidx(ID_EFFECTIVE, gid);
	setgid(gid);
	setuidx(ID_REAL, uid);
	setuidx(ID_EFFECTIVE, uid);
	setuid(uid);
#endif
	
	assert_uid(uid, uid);
	assert_gid(gid, gid);
}
Пример #3
0
/****************************************************************************
This is a utility function of smbrun(). It must be called only from
the child as it may leave the caller in a privileged state.
****************************************************************************/
static BOOL setup_stdout_file(char *outfile,BOOL shared)
{  
  int fd;
  SMB_STRUCT_STAT st;
  mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH;
  int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL;

  close(1);

  if (shared) {
	/* become root - unprivileged users can't delete these files */
	gain_root_privilege();
	gain_root_group_privilege();
  }

  if(sys_stat(outfile, &st) == 0) {
    /* Check we're not deleting a device file. */ 
    if(st.st_mode & S_IFREG)
      unlink(outfile);
    else
      flags = O_RDWR;
  }
  /* now create the file */
  fd = sys_open(outfile,flags,mode);

  if (fd == -1) return False;

  if (fd != 1) {
    if (dup2(fd,1) != 0) {
      DEBUG(2,("Failed to create stdout file descriptor\n"));
      close(fd);
      return False;
    }
    close(fd);
  }
  return True;
}
Пример #4
0
static int dochild(int master,char *slavedev, char *name, char *passwordprogram, BOOL as_root)
{
  int slave;
  struct termios stermios;
  struct passwd *pass = Get_Pwnam(name,True);
  gid_t gid;
  uid_t uid;

  if (pass == NULL) {
    DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n",
              name));
    return False;
  }

  gid = pass->pw_gid;
  uid = pass->pw_uid;

  gain_root_privilege();

  /* Start new session - gets rid of controlling terminal. */
  if (setsid() < 0) {
    DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
    return(False);
  }

  /* Open slave pty and acquire as new controlling terminal. */
  if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) {
    DEBUG(3,("More weirdness, could not open %s\n", 
	     slavedev));
    return(False);
  }
#ifdef I_PUSH
  ioctl(slave, I_PUSH, "ptem");
  ioctl(slave, I_PUSH, "ldterm");
#elif defined(TIOCSCTTY)
  if (ioctl(slave,TIOCSCTTY,0) <0) {
     DEBUG(3,("Error in ioctl call for slave pty\n"));
     /* return(False); */
  }
#endif 

  /* Close master. */
  close(master);

  /* Make slave stdin/out/err of child. */

  if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
    DEBUG(3,("Could not re-direct stdin\n"));
    return(False);
  }
  if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
    DEBUG(3,("Could not re-direct stdout\n"));
    return(False);
  }
  if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
    DEBUG(3,("Could not re-direct stderr\n"));
    return(False);
  }
  if (slave > 2) close(slave);

  /* Set proper terminal attributes - no echo, canonical input processing,
     no map NL to CR/NL on output. */

  if (tcgetattr(0, &stermios) < 0) {
    DEBUG(3,("could not read default terminal attributes on pty\n"));
    return(False);
  }
  stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
  stermios.c_lflag |= ICANON;
  stermios.c_oflag &= ~(ONLCR);
  if (tcsetattr(0, TCSANOW, &stermios) < 0) {
    DEBUG(3,("could not set attributes of pty\n"));
    return(False);
  }

  /* make us completely into the right uid */
  if (!as_root) {
	  become_user_permanently(uid, gid);
  }

  DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram));

  /* execl() password-change application */
  if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) {
    DEBUG(3,("Bad status returned from %s\n",passwordprogram));
    return(False);
  }
  return(True);
}
Пример #5
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);
}
Пример #6
0
static void krb5_ticket_gain_handler(struct tevent_context *event_ctx,
				     struct tevent_timer *te,
				     struct timeval now,
				     void *private_data)
{
	struct WINBINDD_CCACHE_ENTRY *entry =
		talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY);
#ifdef HAVE_KRB5
	int ret;
	struct timeval t;
	struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr;
	struct winbindd_domain *domain = NULL;
#endif

	DEBUG(10,("krb5_ticket_gain_handler called\n"));
	DEBUGADD(10,("event called for: %s, %s\n",
		entry->ccname, entry->username));

	TALLOC_FREE(entry->event);

#ifdef HAVE_KRB5

	if (!cred_ptr || !cred_ptr->pass) {
		DEBUG(10,("krb5_ticket_gain_handler: no memory creds\n"));
		return;
	}

	if ((domain = find_domain_from_name(entry->realm)) == NULL) {
		DEBUG(0,("krb5_ticket_gain_handler: unknown domain\n"));
		return;
	}

	if (!domain->online) {
		goto retry_later;
	}

	set_effective_uid(entry->uid);

	ret = kerberos_kinit_password_ext(entry->principal_name,
					  cred_ptr->pass,
					  0, /* hm, can we do time correction here ? */
					  &entry->refresh_time,
					  &entry->renew_until,
					  entry->ccname,
					  False, /* no PAC required anymore */
					  True,
					  WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
					  NULL);
	gain_root_privilege();

	if (ret) {
		DEBUG(3,("krb5_ticket_gain_handler: "
			"could not kinit: %s\n",
			error_message(ret)));
		/* evil. If we cannot do it, destroy any the __maybe__ 
		 * __existing__ ticket */
		ads_kdestroy(entry->ccname);
		goto retry_later;
	}

	DEBUG(10,("krb5_ticket_gain_handler: "
		"successful kinit for: %s in ccache: %s\n",
		entry->principal_name, entry->ccname));

	goto got_ticket;

  retry_later:
 
#if defined(DEBUG_KRB5_TKT_RENEWAL)
 	t = timeval_set(time(NULL) + 30, 0);
#else
	t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0);
#endif

	add_krb5_ticket_gain_handler_event(entry, t);
	return;

  got_ticket:

#if defined(DEBUG_KRB5_TKT_RENEWAL)
	t = timeval_set(time(NULL) + 30, 0);
#else
	t = timeval_set(krb5_event_refresh_time(entry->refresh_time), 0);
#endif

	if (entry->refresh_time == 0) {
		entry->refresh_time = t.tv_sec;
	}
	entry->event = tevent_add_timer(winbind_event_context(),
				       entry,
				       t,
				       krb5_ticket_refresh_handler,
				       entry);

	return;
#endif
}
Пример #7
0
static void krb5_ticket_refresh_handler(struct tevent_context *event_ctx,
					struct tevent_timer *te,
					struct timeval now,
					void *private_data)
{
	struct WINBINDD_CCACHE_ENTRY *entry =
		talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY);
#ifdef HAVE_KRB5
	int ret;
	time_t new_start;
	time_t expire_time = 0;
	struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr;
#endif

	DEBUG(10,("krb5_ticket_refresh_handler called\n"));
	DEBUGADD(10,("event called for: %s, %s\n",
		entry->ccname, entry->username));

	TALLOC_FREE(entry->event);

#ifdef HAVE_KRB5

	/* Kinit again if we have the user password and we can't renew the old
	 * tgt anymore 
	 * NB
	 * This happens when machine are put to sleep for a very long time. */

	if (entry->renew_until < time(NULL)) {
rekinit:
		if (cred_ptr && cred_ptr->pass) {

			set_effective_uid(entry->uid);

			ret = kerberos_kinit_password_ext(entry->principal_name,
							  cred_ptr->pass,
							  0, /* hm, can we do time correction here ? */
							  &entry->refresh_time,
							  &entry->renew_until,
							  entry->ccname,
							  False, /* no PAC required anymore */
							  True,
							  WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
							  NULL);
			gain_root_privilege();

			if (ret) {
				DEBUG(3,("krb5_ticket_refresh_handler: "
					"could not re-kinit: %s\n",
					error_message(ret)));
				/* destroy the ticket because we cannot rekinit
				 * it, ignore error here */
				ads_kdestroy(entry->ccname);

				/* Don't break the ticket refresh chain: retry 
				 * refreshing ticket sometime later when KDC is 
				 * unreachable -- BoYang. More error code handling
				 * here? 
				 * */

				if ((ret == KRB5_KDC_UNREACH)
				    || (ret == KRB5_REALM_CANT_RESOLVE)) {
#if defined(DEBUG_KRB5_TKT_RENEWAL)
					new_start = time(NULL) + 30;
#else
					new_start = time(NULL) +
						    MAX(30, lp_winbind_cache_time());
#endif
					add_krb5_ticket_gain_handler_event(entry,
							timeval_set(new_start, 0));
					return;
				}
				TALLOC_FREE(entry->event);
				return;
			}

			DEBUG(10,("krb5_ticket_refresh_handler: successful re-kinit "
				"for: %s in ccache: %s\n",
				entry->principal_name, entry->ccname));

#if defined(DEBUG_KRB5_TKT_RENEWAL)
			new_start = time(NULL) + 30;
#else
			/* The tkt should be refreshed at one-half the period
			   from now to the expiration time */
			expire_time = entry->refresh_time;
			new_start = krb5_event_refresh_time(entry->refresh_time);
#endif
			goto done;
		} else {
				/* can this happen? 
				 * No cached credentials
				 * destroy ticket and refresh chain 
				 * */
				ads_kdestroy(entry->ccname);
				TALLOC_FREE(entry->event);
				return;
		}
	}

	set_effective_uid(entry->uid);

	ret = smb_krb5_renew_ticket(entry->ccname,
				    entry->principal_name,
				    entry->service,
				    &new_start);
#if defined(DEBUG_KRB5_TKT_RENEWAL)
	new_start = time(NULL) + 30;
#else
	expire_time = new_start;
	new_start = krb5_event_refresh_time(new_start);
#endif

	gain_root_privilege();

	if (ret) {
		DEBUG(3,("krb5_ticket_refresh_handler: "
			"could not renew tickets: %s\n",
			error_message(ret)));
		/* maybe we are beyond the renewing window */

		/* evil rises here, we refresh ticket failed,
		 * but the ticket might be expired. Therefore,
		 * When we refresh ticket failed, destory the 
		 * ticket */

		ads_kdestroy(entry->ccname);

		/* avoid breaking the renewal chain: retry in
		 * lp_winbind_cache_time() seconds when the KDC was not
		 * available right now. 
		 * the return code can be KRB5_REALM_CANT_RESOLVE. 
		 * More error code handling here? */

		if ((ret == KRB5_KDC_UNREACH) 
		    || (ret == KRB5_REALM_CANT_RESOLVE)) {
#if defined(DEBUG_KRB5_TKT_RENEWAL)
			new_start = time(NULL) + 30;
#else
			new_start = time(NULL) +
				    MAX(30, lp_winbind_cache_time());
#endif
			/* ticket is destroyed here, we have to regain it
			 * if it is possible */
			add_krb5_ticket_gain_handler_event(entry,
						timeval_set(new_start, 0));
			return;
		}

		/* This is evil, if the ticket was already expired.
		 * renew ticket function returns KRB5KRB_AP_ERR_TKT_EXPIRED.
		 * But there is still a chance that we can rekinit it. 
		 *
		 * This happens when user login in online mode, and then network
		 * down or something cause winbind goes offline for a very long time,
		 * and then goes online again. ticket expired, renew failed.
		 * This happens when machine are put to sleep for a long time,
		 * but shorter than entry->renew_util.
		 * NB
		 * Looks like the KDC is reachable, we want to rekinit as soon as
		 * possible instead of waiting some time later. */
		if ((ret == KRB5KRB_AP_ERR_TKT_EXPIRED)
		    || (ret == KRB5_FCC_NOFILE)) goto rekinit;

		return;
	}

done:
	/* in cases that ticket will be unrenewable soon, we don't try to renew ticket 
	 * but try to regain ticket if it is possible */
	if (entry->renew_until && expire_time
	     && (entry->renew_until <= expire_time)) {
		/* try to regain ticket 10 seconds before expiration */
		expire_time -= 10;
		add_krb5_ticket_gain_handler_event(entry,
					timeval_set(expire_time, 0));
		return;
	}

	if (entry->refresh_time == 0) {
		entry->refresh_time = new_start;
	}
	entry->event = tevent_add_timer(winbind_event_context(), entry,
				       timeval_set(new_start, 0),
				       krb5_ticket_refresh_handler,
				       entry);

#endif
}
Пример #8
0
static int dochild(int master, const char *slavedev, const struct passwd *pass,
		   const char *passwordprogram, bool as_root)
{
	int slave;
	struct termios stermios;
	gid_t gid;
	uid_t uid;
	char * const eptrs[1] = { NULL };

	if (pass == NULL)
	{
		DEBUG(0,
		      ("dochild: user doesn't exist in the UNIX password database.\n"));
		return False;
	}

	gid = pass->pw_gid;
	uid = pass->pw_uid;

	gain_root_privilege();

	/* Start new session - gets rid of controlling terminal. */
	if (setsid() < 0)
	{
		DEBUG(3,
		      ("Weirdness, couldn't let go of controlling terminal\n"));
		return (False);
	}

	/* Open slave pty and acquire as new controlling terminal. */
	if ((slave = open(slavedev, O_RDWR, 0)) < 0)
	{
		DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
		return (False);
	}
#if defined(TIOCSCTTY) && !defined(SUNOS5)
	/*
	 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
	 * see the discussion under
	 * https://bugzilla.samba.org/show_bug.cgi?id=5366.
	 */
	if (ioctl(slave, TIOCSCTTY, 0) < 0)
	{
		DEBUG(3, ("Error in ioctl call for slave pty\n"));
		/* return(False); */
	}
#elif defined(I_PUSH) && defined(I_FIND)
	if (ioctl(slave, I_FIND, "ptem") == 0) {
		ioctl(slave, I_PUSH, "ptem");
	}
	if (ioctl(slave, I_FIND, "ldterm") == 0) {
		ioctl(slave, I_PUSH, "ldterm");
	}
#endif

	/* Close master. */
	close(master);

	/* Make slave stdin/out/err of child. */

	if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
	{
		DEBUG(3, ("Could not re-direct stdin\n"));
		return (False);
	}
	if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
	{
		DEBUG(3, ("Could not re-direct stdout\n"));
		return (False);
	}
	if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
	{
		DEBUG(3, ("Could not re-direct stderr\n"));
		return (False);
	}
	if (slave > 2)
		close(slave);

	/* Set proper terminal attributes - no echo, canonical input processing,
	   no map NL to CR/NL on output. */

	if (tcgetattr(0, &stermios) < 0)
	{
		DEBUG(3,
		      ("could not read default terminal attributes on pty\n"));
		return (False);
	}
	stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
	stermios.c_lflag |= ICANON;
#ifdef ONLCR
	stermios.c_oflag &= ~(ONLCR);
#endif
	if (tcsetattr(0, TCSANOW, &stermios) < 0)
	{
		DEBUG(3, ("could not set attributes of pty\n"));
		return (False);
	}

	/* make us completely into the right uid */
	if (!as_root)
	{
		become_user_permanently(uid, gid);
	}

	DEBUG(10,
	      ("Invoking '%s' as password change program.\n",
	       passwordprogram));

	/* execl() password-change application */
	if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
	{
		DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
		return (False);
	}
	return (True);
}
Пример #9
0
 int main2(int argc,const char *argv[])
{
	/* shall I run as a daemon */
	static BOOL is_daemon = False;
	static BOOL interactive = False;
	static BOOL Fork = True;
	static BOOL no_process_group = False;
	static BOOL log_stdout = False;
	static char *ports = NULL;
	int opt;
#ifndef _XBOX
	poptContext pc;

	struct poptOption long_options[] = {
	POPT_AUTOHELP
	{"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" },
	{"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"},
	{"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools, etc.)" },
	{"no-process-group", '\0', POPT_ARG_VAL, &no_process_group, True, "Don't create a new process group" },
	{"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "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"},
	POPT_COMMON_SAMBA
	POPT_COMMON_DYNCONFIG
	POPT_TABLEEND
	};
#else
	interactive = True;
	log_stdout = True;
#endif

	load_case_tables();

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

#ifndef _XBOX
	pc = poptGetContext("smbd", argc, argv, long_options, 0);
	
	while((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt)  {
		case 'b':
			build_options(True); /* Display output to screen as well as debug */ 
			exit(0);
			break;
		}
	}

	poptFreeContext(pc);
#endif

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

	sec_init();

	set_remote_machine_name("smbd", False);

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

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

	setup_logging(argv[0],log_stdout);

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

	/* 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();

#ifndef _XBOX
	fault_setup((void (*)(void *))exit_server_fault);
	dump_core_setup("smbd");
#endif

	CatchSignal(SIGTERM , SIGNAL_CAST sig_term);
#ifndef _XBOX
	CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
	
	/* we are never interested in SIGPIPE */
	BlockSignals(True,SIGPIPE);
#endif

#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. */
#ifndef _XBOX
	BlockSignals(False, SIGHUP);
#endif
	BlockSignals(False, SIGUSR1);
	BlockSignals(False, SIGTERM);

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

	init_sec_ctx();

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

	/*
	 * Do this before reload_services.
	 */

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

	init_structs();

#ifdef WITH_PROFILE
	if (!profile_setup(False)) {
		DEBUG(0,("ERROR: failed to setup profiling\n"));
		return -1;
	}
#endif

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

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

#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(), NULL))
		mkdir(lp_lockdir(), 0755);

#ifndef _XBOX
	if (is_daemon)
		pidfile_create("smbd");
#endif

	/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
	if (!message_init())
		exit(1);

	/* Initialize our global sam sid first -- quite a lot of the other
	 * initialization routines further down depend on it.
	 */

	/* 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))
		exit(1);

	/* Fail gracefully if we can't open secrets.tdb */

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

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

	if (!session_init())
		exit(1);

	if (conn_tdb_ctx() == NULL)
		exit(1);

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

	namecache_enable();

	if (!init_registry())
		exit(1);

#if 0
	if (!init_svcctl_db())
                exit(1);
#endif

#ifndef _XBOX
	if (!print_backend_init())
		exit(1);
#endif

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

	/* Setup the main smbd so that we can get messages. */
	/* don't worry about general printing messages here */

	claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD);

	/* only start the background queue daemon 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 */
#ifndef _XBOX
	if ( is_daemon && !interactive )
		start_background_queue(); 
#endif
	/* Always attempt to initialize DMAPI. We will only use it later if
	 * lp_dmapi_support is set on the share, but we need a single global
	 * session to work with.
	 */
	dmapi_init_session();

	if (!open_sockets_smbd(is_daemon, interactive, ports))
		exit(1);

	/*
	 * everything after this point is run after the fork()
	 */ 

	static_init_rpc;

	init_modules();

	/* possibly reload the services file. */
	reload_services(True);

	if (!init_account_policy()) {
		DEBUG(0,("Could not open account policy tdb.\n"));
		exit(1);
	}

	if (*lp_rootdir()) {
		if (sys_chroot(lp_rootdir()) == 0)
			DEBUG(2,("Changed root to %s\n", lp_rootdir()));
	}

	/* Setup oplocks */
	if (!init_oplocks())
		exit(1);
	
	/* Setup change notify */
	if (!init_change_notify())
		exit(1);

	/* Setup aio signal handler. */
	initialize_async_io_handler();

	/* re-initialise the timezone */
	TimeInit();

	/* register our message handlers */
	message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis);

	smbd_process();

#ifdef _XBOX
	xb_DecClientCount();
#endif

	namecache_shutdown();

	exit_server_cleanly(NULL);
	return(0);
}