示例#1
0
ATF_TC_BODY(setlogin_err, tc)
{
	char buf[MAXLOGNAME + 1];
	char *name;
	pid_t pid;
	int sta;

	pid = fork();
	ATF_REQUIRE(pid >= 0);

	(void)memset(buf, 'x', sizeof(buf));

	if (pid == 0) {

		(void)setsid();

		errno = 0;

		if (setlogin(buf) != -1)
			_exit(EINVAL);

		if (errno != EINVAL)
			_exit(EINVAL);

		errno = 0;

		if (setlogin((void *)-1) != -1)
			_exit(EFAULT);

		if (errno != EFAULT)
			_exit(EFAULT);

		name = getlogin();

		if (name == NULL)
			_exit(EXIT_FAILURE);

		if (strcmp(name, "foobar") == 0)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	(void)wait(&sta);

	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {

		if (WEXITSTATUS(sta) == EFAULT)
			atf_tc_fail("expected EFAULT, but the call succeeded");

		if (WEXITSTATUS(sta) == EINVAL)
			atf_tc_fail("expected EINVAL, but the call succeeded");

		atf_tc_fail("setlogin(2) failed, but login name was set");
	}
}
示例#2
0
void
priv_proc_setlogin_cleanup(int asroot, int injail, struct test *test)
{

	if (initialized)
		(void)setlogin(loginname);
}
示例#3
0
ATF_TC_BODY(setlogin_basic, tc)
{
	char *name;
	pid_t pid;
	int sta;

	pid = fork();
	ATF_REQUIRE(pid >= 0);

	if (pid == 0) {

		(void)setsid();

		if (setlogin("foobar") != 0)
			_exit(EXIT_FAILURE);

		name = getlogin();

		if (name == NULL)
			_exit(EXIT_FAILURE);

		if (strcmp(name, "foobar") != 0)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	(void)wait(&sta);

	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
		atf_tc_fail("setlogin(2) failed to set login name");
}
示例#4
0
void
priv_proc_setlogin(int asroot, int injail, struct test *test)
{
	int error;

	error = setlogin(loginname);
	if (asroot && injail)
		expect("priv_proc_setlogin(asroot, injail)", error, 0, 0);
	if (asroot && !injail)
		expect("priv_proc_setlogin(asroot, !injail)", error, 0, 0);
	if (!asroot && injail)
		expect("priv_proc_setlogin(!sroot, injail)", error, -1,
		    EPERM);
	if (!asroot && !injail)
		expect("priv_proc_setlogin(!asroot, !injail)", error, -1,
		    EPERM);
}
示例#5
0
文件: newaid.C 项目: bougyman/sfs
static void
sfs_setlogin (uid_t nuid)
{
#if defined (HAVE_SETLOGIN) || defined (HAVE_SETUSERCONTEXT)
  struct passwd *pw;
  char *p;
  if (!(p = getenv ("USER")) || !(pw = getpwnam (p)) || pw->pw_uid != nuid)
    pw = getpwuid (nuid);
  if (!pw)
    fatal ("No pwent for UID %d\n", nuid);

#if defined (HAVE_SETUSERCONTEXT)
  if (setusercontext (NULL, pw, pw->pw_uid,
		      LOGIN_SETALL & ~(LOGIN_SETUSER|LOGIN_SETGROUP)) < 0)
    fatal ("setusercontext failed\n");
#elif defined (HAVE_SETLOGIN)
  if (setlogin (pw->pw_name) < 0)
    fatal ("setlogin %s: %m\n", pw->pw_name);
#endif /* HAVE_SETLOGIN */
#endif /* HAVE_SETLOGIN || HAVE_SETUSERCONTEXT */
}
示例#6
0
ATF_TC_BODY(setlogin_perm, tc)
{
	char *name;
	pid_t pid;
	int sta;

	pid = fork();
	ATF_REQUIRE(pid >= 0);

	if (pid == 0) {

		(void)setsid();

		errno = 0;

		if (setlogin("foobar") != -1)
			_exit(EXIT_FAILURE);

		if (errno != EPERM)
			_exit(EXIT_FAILURE);

		name = getlogin();

		if (name == NULL)
			_exit(EXIT_FAILURE);

		if (strcmp(name, "foobar") == 0)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	(void)wait(&sta);

	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
		atf_tc_fail("login name was set as an unprivileged user");
}
示例#7
0
int
main( int argc, char** argv )
    {
    char* cp;
    struct passwd* pwd;
    uid_t uid;
    gid_t gid;
    char cwd[MAXPATHLEN];
    FILE* logfp;
    int num_ready;
    int cnum, ridx;
    connecttab* c;
    httpd_conn* hc;
    httpd_sockaddr sa4;
    httpd_sockaddr sa6;
    int gotv4, gotv6;
    struct timeval tv;

    argv0 = argv[0];

    cp = strrchr( argv0, '/' );
    if ( cp != (char*) 0 )
	++cp;
    else
	cp = argv0;
    openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY );

    /* Handle command-line arguments. */
    parse_args( argc, argv );

    /* Check port number. */
    if ( port <= 0 )
	{
	syslog( LOG_CRIT, "illegal port number" );
	(void) fprintf( stderr, "%s: illegal port number\n", argv0 );
	exit( 1 );
	}

    /* Read zone info now, in case we chroot(). */
    tzset();

    /* Look up hostname now, in case we chroot(). */
    lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 );
    if ( ! ( gotv4 || gotv6 ) )
	{
	syslog( LOG_ERR, "can't find any valid address" );
	(void) fprintf( stderr, "%s: can't find any valid address\n", argv0 );
	exit( 1 );
	}

    /* Throttle file. */
    numthrottles = 0;
    maxthrottles = 0;
    throttles = (throttletab*) 0;
    if ( throttlefile != (char*) 0 )
	read_throttlefile( throttlefile );

    /* Log file. */
    if ( logfile != (char*) 0 )
	{
	if ( strcmp( logfile, "/dev/null" ) == 0 )
	    {
	    no_log = 1;
	    logfp = (FILE*) 0;
	    }
	else
	    {
	    logfp = fopen( logfile, "a" );
	    if ( logfp == (FILE*) 0 )
		{
		syslog( LOG_CRIT, "%.80s - %m", logfile );
		perror( logfile );
		exit( 1 );
		}
	    (void) fcntl( fileno( logfp ), F_SETFD, 1 );
	    }
	}
    else
	logfp = (FILE*) 0;

    /* Figure out uid/gid from user. */
    pwd = getpwnam( user );
    if ( pwd == (struct passwd*) 0 )
	{
	syslog( LOG_CRIT, "unknown user - '%.80s'", user );
	(void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user );
	exit( 1 );
	}
    uid = pwd->pw_uid;
    gid = pwd->pw_gid;

    /* Switch directories if requested. */
    if ( dir != (char*) 0 )
	{
	if ( chdir( dir ) < 0 )
	    {
	    syslog( LOG_CRIT, "chdir - %m" );
	    perror( "chdir" );
	    exit( 1 );
	    }
	}
#ifdef USE_USER_DIR
    else if ( getuid() == 0 )
	{
	/* No explicit directory was specified, we're root, and the
	** USE_USER_DIR option is set - switch to the specified user's
	** home dir.
	*/
	if ( chdir( pwd->pw_dir ) < 0 )
	    {
	    syslog( LOG_CRIT, "chdir - %m" );
	    perror( "chdir" );
	    exit( 1 );
	    }
	}
#endif /* USE_USER_DIR */

    /* Get current directory. */
    (void) getcwd( cwd, sizeof(cwd) - 1 );
    if ( cwd[strlen( cwd ) - 1] != '/' )
	(void) strcat( cwd, "/" );

    if ( ! debug )
	{
	/* We're not going to use stdin stdout or stderr from here on, so close
	** them to save file descriptors.
	*/
	(void) fclose( stdin );
	(void) fclose( stdout );
	(void) fclose( stderr );

	/* Daemonize - make ourselves a subprocess. */
#ifdef HAVE_DAEMON
	if ( daemon( 1, 1 ) < 0 )
	    {
	    syslog( LOG_CRIT, "daemon - %m" );
	    exit( 1 );
	    }
#else /* HAVE_DAEMON */
	switch ( fork() )
	    {
	    case 0:
	    break;
	    case -1:
	    syslog( LOG_CRIT, "fork - %m" );
	    exit( 1 );
	    default:
	    exit( 0 );
	    }
#ifdef HAVE_SETSID
        (void) setsid();
#endif /* HAVE_SETSID */
#endif /* HAVE_DAEMON */
	}
    else
	{
	/* Even if we don't daemonize, we still want to disown our parent
	** process.
	*/
#ifdef HAVE_SETSID
        (void) setsid();
#endif /* HAVE_SETSID */
	}

    if ( pidfile != (char*) 0 )
	{
	/* Write the PID file. */
	FILE* pidfp = fopen( pidfile, "w" );
	if ( pidfp == (FILE*) 0 )
	    {
	    syslog( LOG_CRIT, "%.80s - %m", pidfile );
	    exit( 1 );
	    }
	(void) fprintf( pidfp, "%d\n", (int) getpid() );
	(void) fclose( pidfp );
	}

    /* Chroot if requested. */
    if ( do_chroot )
	{
	if ( chroot( cwd ) < 0 )
	    {
	    syslog( LOG_CRIT, "chroot - %m" );
	    perror( "chroot" );
	    exit( 1 );
	    }
	(void) strcpy( cwd, "/" );
	/* Always chdir to / after a chroot. */
	if ( chdir( cwd ) < 0 )
	    {
	    syslog( LOG_CRIT, "chroot chdir - %m" );
	    perror( "chroot chdir" );
	    exit( 1 );
	    }
	}

    /* Set up to catch signals. */
    (void) signal( SIGTERM, handle_term );
    (void) signal( SIGINT, handle_term );
    (void) signal( SIGPIPE, SIG_IGN );          /* get EPIPE instead */
    (void) signal( SIGHUP, handle_hup );
    got_usr1 = 0;
    (void) signal( SIGUSR1, handle_usr1 );
    (void) signal( SIGUSR2, handle_usr2 );

    /* Initialize the timer package. */
    tmr_init();

    /* Initialize the HTTP layer.  Got to do this before giving up root,
    ** so that we can bind to a privileged port.
    */
    hs = httpd_initialize(
	hostname,
	gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0,
	port, cgi_pattern, charset, cwd, no_log, logfp, no_symlink, do_vhost,
	do_global_passwd, url_pattern, local_pattern, no_empty_referers );
    if ( hs == (httpd_server*) 0 )
	exit( 1 );

    /* Set up the occasional timer. */
    if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 )
	{
	syslog( LOG_CRIT, "tmr_create(occasional) failed" );
	exit( 1 );
	}
    if ( numthrottles > 0 )
	{
	/* Set up the throttles timer. */
	if ( tmr_create( (struct timeval*) 0, update_throttles, JunkClientData, THROTTLE_TIME * 1000L, 1 ) == (Timer*) 0 )
	    {
	    syslog( LOG_CRIT, "tmr_create(update_throttles) failed" );
	    exit( 1 );
	    }
	}
#ifdef STATS_TIME
    /* Set up the stats timer. */
    if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )
	{
	syslog( LOG_CRIT, "tmr_create(show_stats) failed" );
	exit( 1 );
	}
#endif /* STATS_TIME */
    start_time = stats_time = time( (time_t*) 0 );
    stats_connections = stats_bytes = 0L;
    stats_simultaneous = 0;

    /* If we're root, try to become someone else. */
    if ( getuid() == 0 )
	{
	/* Set aux groups to null. */
	if ( setgroups( 0, (const gid_t*) 0 ) < 0 )
	    {
	    syslog( LOG_CRIT, "setgroups - %m" );
	    exit( 1 );
	    }
	/* Set primary group. */
	if ( setgid( gid ) < 0 )
	    {
	    syslog( LOG_CRIT, "setgid - %m" );
	    exit( 1 );
	    }
	/* Try setting aux groups correctly - not critical if this fails. */
	if ( initgroups( user, gid ) < 0 )
	    syslog( LOG_WARNING, "initgroups - %m" );
#ifdef HAVE_SETLOGIN
	/* Set login name. */
        (void) setlogin( user );
#endif /* HAVE_SETLOGIN */
	/* Set uid. */
	if ( setuid( uid ) < 0 )
	    {
	    syslog( LOG_CRIT, "setuid - %m" );
	    exit( 1 );
	    }
	/* Check for unnecessary security exposure. */
	if ( ! do_chroot )
	    syslog(
		LOG_CRIT,
		"started as root without requesting chroot(), warning only" );
	}

    /* Initialize our connections table. */
    maxconnects = fdwatch_get_nfiles();
    if ( maxconnects < 0 )
	{
	syslog( LOG_CRIT, "fdwatch initialization failure" );
	exit( 1 );
	}
    maxconnects -= SPARE_FDS;
    connects = NEW( connecttab, maxconnects );
    if ( connects == (connecttab*) 0 )
	{
	syslog( LOG_CRIT, "out of memory allocating a connecttab" );
	exit( 1 );
	}
    for ( cnum = 0; cnum < maxconnects; ++cnum )
	{
	connects[cnum].conn_state = CNST_FREE;
	connects[cnum].hc = (httpd_conn*) 0;
	}
    numconnects = 0;
    httpd_conn_count = 0;

    if ( hs != (httpd_server*) 0 )
	{
	if ( hs->listen4_fd != -1 )
	    fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ );
	if ( hs->listen6_fd != -1 )
	    fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ );
	}

    /* Main loop. */
    (void) gettimeofday( &tv, (struct timezone*) 0 );
    while ( ( ! terminate ) || numconnects > 0 )
	{
	/* Do the fd watch. */
	num_ready = fdwatch( tmr_mstimeout( &tv ) );
	if ( num_ready < 0 )
	    {
	    if ( errno == EINTR )
		continue;       /* try again */
	    syslog( LOG_ERR, "fdwatch - %m" );
	    exit( 1 );
	    }
	(void) gettimeofday( &tv, (struct timezone*) 0 );
	if ( num_ready == 0 )
	    {
	    /* No fd's are ready - run the timers. */
	    tmr_run( &tv );
	    continue;
	    }

	/* Is it a new connection? */
	if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && 
	     fdwatch_check_fd( hs->listen6_fd ) )
	    {
	    if ( handle_newconnect( &tv, hs->listen6_fd ) )
		/* Go around the loop and do another fdwatch, rather than
		** dropping through and processing existing connections.
		** New connections always get priority.
		*/
		continue;
	    }
	if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && 
	     fdwatch_check_fd( hs->listen4_fd ) )
	    {
	    if ( handle_newconnect( &tv, hs->listen4_fd ) )
		/* Go around the loop and do another fdwatch, rather than
		** dropping through and processing existing connections.
		** New connections always get priority.
		*/
		continue;
	    }

	/* Find the connections that need servicing. */
	for ( ridx = 0; ridx < num_ready; ++ridx )
	    {
	    c = (connecttab*) fdwatch_get_client_data( ridx );
	    if ( c == (connecttab*) 0 )
		continue;
	    hc = c->hc;
	    if ( c->conn_state == CNST_READING &&
		 fdwatch_check_fd( hc->conn_fd ) )
		handle_read( c, &tv );
	    else if ( c->conn_state == CNST_SENDING &&
		 fdwatch_check_fd( hc->conn_fd ) )
		handle_send( c, &tv );
	    else if ( c->conn_state == CNST_LINGERING &&
		 fdwatch_check_fd( hc->conn_fd ) )
		handle_linger( c, &tv );
	    }
	tmr_run( &tv );

	if ( got_usr1 && ! terminate )
	    {
	    terminate = 1;
	    if ( hs != (httpd_server*) 0 )
		{
		httpd_terminate( hs );
		hs = (httpd_server*) 0;
		}
	    }
	}

    /* The main loop terminated. */
    shut_down();
    syslog( LOG_NOTICE, "exiting" );
    closelog();
    exit( 0 );
    }
示例#8
0
文件: session.c 项目: cz172638/wdm
static Bool
StartClient (
    struct verify_info	*verify,
    struct display	*d,
    int			*pidp,
    char		*name,
    char		*passwd)
{
    char	**f, *home;
    char	*failsafeArgv[2];
    int	pid;
#ifdef HAS_SETUSERCONTEXT
    struct passwd* pwd;
#endif
#ifdef USE_PAM 
    pam_handle_t *pamh = thepamh();
#endif

    if (verify->argv) {
	Debug ("StartSession %s: ", verify->argv[0]);
	for (f = verify->argv; *f; f++)
		Debug ("%s ", *f);
	Debug ("; ");
    }
    if (verify->userEnviron) {
	for (f = verify->userEnviron; *f; f++)
		Debug ("%s ", *f);
	Debug ("\n");
    }
#ifdef USE_PAM
    if (pamh) pam_open_session(pamh, 0);
#endif    
    switch (pid = fork ()) {
    case 0:
	CleanUpChild ();
#ifdef XDMCP
	/* The chooser socket is not closed by CleanUpChild() */
	DestroyWellKnownSockets();
#endif

	/* Do system-dependent login setup here */

#ifdef USE_PAM
	/* pass in environment variables set by libpam and modules it called */
	if (pamh) {
	    long i;
	    char **pam_env = pam_getenvlist(pamh);
	    for(i = 0; pam_env && pam_env[i]; i++) {
		verify->userEnviron = putEnv(pam_env[i], verify->userEnviron);
	    }
	}
#endif


#ifndef AIXV3
#ifndef HAS_SETUSERCONTEXT
	if (setgid(verify->gid) < 0)
	{
	    LogError("setgid %d (user \"%s\") failed, errno=%d\n",
		     verify->gid, name, errno);
	    return (0);
	}
#if defined(BSD) && (BSD >= 199103)
	if (setlogin(name) < 0)
	{
	    LogError("setlogin for \"%s\" failed, errno=%d", name, errno);
	    return(0);
	}
#endif
#ifndef QNX4
	if (initgroups(name, verify->gid) < 0)
	{
	    LogError("initgroups for \"%s\" failed, errno=%d\n", name, errno);
	    return (0);
	}
#endif   /* QNX4 doesn't support multi-groups, no initgroups() */
#ifdef USE_PAM
	if (thepamh()) {
	    pam_setcred(thepamh(), PAM_ESTABLISH_CRED);
	}
#endif
	if (setuid(verify->uid) < 0)
	{
	    LogError("setuid %d (user \"%s\") failed, errno=%d\n",
		     verify->uid, name, errno);
	    return (0);
	}
#else /* HAS_SETUSERCONTEXT */
	/*
	 * Set the user's credentials: uid, gid, groups,
	 * environment variables, resource limits, and umask.
	 */
	pwd = getpwnam(name);
	if (pwd)
	{
	    if (setusercontext(NULL, pwd, pwd->pw_uid, LOGIN_SETALL) < 0)
	    {
		LogError("setusercontext for \"%s\" failed, errno=%d\n", name,
		    errno);
		return (0);
	    }
	    endpwent();
	}
	else
	{
	    LogError("getpwnam for \"%s\" failed, errno=%d\n", name, errno);
	    return (0);
	}
#endif /* HAS_SETUSERCONTEXT */
#else /* AIXV3 */
	/*
	 * Set the user's credentials: uid, gid, groups,
	 * audit classes, user limits, and umask.
	 */
	if (setpcred(name, NULL) == -1)
	{
	    LogError("setpcred for \"%s\" failed, errno=%d\n", name, errno);
	    return (0);
	}
#endif /* AIXV3 */

	/*
	 * for user-based authorization schemes,
	 * use the password to get the user's credentials.
	 */
#ifdef SECURE_RPC
	/* do like "keylogin" program */
	{
	    char    netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
	    int	    nameret, keyret;
	    int	    len;
	    int     key_set_ok = 0;

	    nameret = getnetname (netname);
	    Debug ("User netname: %s\n", netname);
	    len = strlen (passwd);
	    if (len > 8)
		bzero (passwd + 8, len - 8);
	    keyret = getsecretkey(netname,secretkey,passwd);
	    Debug ("getsecretkey returns %d, key length %d\n",
		    keyret, strlen (secretkey));
	    /* is there a key, and do we have the right password? */
	    if (keyret == 1)
	    {
		if (*secretkey)
		{
		    keyret = key_setsecret(secretkey);
		    Debug ("key_setsecret returns %d\n", keyret);
		    if (keyret == -1)
			LogError ("failed to set NIS secret key\n");
		    else
			key_set_ok = 1;
		}
		else
		{
		    /* found a key, but couldn't interpret it */
		    LogError ("password incorrect for NIS principal \"%s\"\n",
			      nameret ? netname : name);
		}
	    }
	    if (!key_set_ok)
	    {
		/* remove SUN-DES-1 from authorizations list */
		int i, j;
		for (i = 0; i < d->authNum; i++)
		{
		    if (d->authorizations[i]->name_length == 9 &&
			memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
		    {
			for (j = i+1; j < d->authNum; j++)
			    d->authorizations[j-1] = d->authorizations[j];
			d->authNum--;
			break;
		    }
		}
	    }
	    bzero(secretkey, strlen(secretkey));
	}
#endif
#ifdef K5AUTH
	/* do like "kinit" program */
	{
	    int i, j;
	    int result;
	    extern char *Krb5CCacheName();

	    result = Krb5Init(name, passwd, d);
	    if (result == 0) {
		/* point session clients at the Kerberos credentials cache */
		verify->userEnviron =
		    setEnv(verify->userEnviron,
			   "KRB5CCNAME", Krb5CCacheName(d->name));
	    } else {
		for (i = 0; i < d->authNum; i++)
		{
		    if (d->authorizations[i]->name_length == 14 &&
			memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
		    {
			/* remove Kerberos from authorizations list */
			for (j = i+1; j < d->authNum; j++)
			    d->authorizations[j-1] = d->authorizations[j];
			d->authNum--;
			break;
		    }
		}
	    }
	}
#endif /* K5AUTH */
	bzero(passwd, strlen(passwd));
	SetUserAuthorization (d, verify);
	home = getEnv (verify->userEnviron, "HOME");
	if (home)
	    if (chdir (home) == -1) {
		LogError ("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n",
			  getEnv (verify->userEnviron, "USER"), home, errno);
		chdir ("/");
		verify->userEnviron = setEnv(verify->userEnviron, "HOME", "/");
	    }
	if (verify->argv) {
		Debug ("executing session %s\n", verify->argv[0]);
		execute (verify->argv, verify->userEnviron);
		LogError ("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno);
	} else {
		LogError ("Session has no command/arguments\n");
	}
	failsafeArgv[0] = d->failsafeClient;
	failsafeArgv[1] = 0;
	execute (failsafeArgv, verify->userEnviron);
	exit (1);
    case -1:
	bzero(passwd, strlen(passwd));
	Debug ("StartSession, fork failed\n");
	LogError ("can't start session on \"%s\", fork failed, errno=%d\n",
		  d->name, errno);
	return 0;
    default:
	bzero(passwd, strlen(passwd));
	Debug ("StartSession, fork succeeded %d\n", pid);
	*pidp = pid;
	return 1;
    }
}
示例#9
0
文件: login.c 项目: ryo/netbsd-src
int
main(int argc, char *argv[])
{
	struct group *gr;
	struct stat st;
	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
	uid_t uid, saved_uid;
	gid_t saved_gid, saved_gids[NGROUPS_MAX];
	int nsaved_gids;
#ifdef notdef
	char *domain;
#endif
	char *p, *ttyn;
	const char *pwprompt;
	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
	char localhost[MAXHOSTNAMELEN + 1];
	int need_chpass, require_chpass;
	int login_retries = DEFAULT_RETRIES, 
	    login_backoff = DEFAULT_BACKOFF;
	time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
	char *loginname = NULL;
#ifdef KERBEROS5
	int Fflag;
	krb5_error_code kerror;
#endif
#if defined(KERBEROS5)
	int got_tickets = 0;
#endif
#ifdef LOGIN_CAP
	char *shell = NULL;
	login_cap_t *lc = NULL;
#endif

	tbuf[0] = '\0';
	rval = 0;
	pwprompt = NULL;
	nested = NULL;
	need_chpass = require_chpass = 0;

	(void)signal(SIGALRM, timedout);
	(void)alarm(timeout);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)setpriority(PRIO_PROCESS, 0, 0);

	openlog("login", 0, LOG_AUTH);

	/*
	 * -p is used by getty to tell login not to destroy the environment
	 * -f is used to skip a second login authentication
	 * -h is used by other servers to pass the name of the remote host to
	 *    login so that it may be placed in utmp/utmpx and wtmp/wtmpx
	 * -a in addition to -h, a server may supply -a to pass the actual
	 *    server address.
	 * -s is used to force use of S/Key or equivalent.
	 */
	if (gethostname(localhost, sizeof(localhost)) < 0) {
		syslog(LOG_ERR, "couldn't get local hostname: %m");
		strcpy(hostname, "amnesiac");
	}
#ifdef notdef
	domain = strchr(localhost, '.');
#endif
	localhost[sizeof(localhost) - 1] = '\0';

	fflag = hflag = pflag = sflag = 0;
	have_ss = 0;
#ifdef KERBEROS5
	Fflag = 0;
	have_forward = 0;
#endif
	uid = getuid();
	while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1)
		switch (ch) {
		case 'a':
			if (uid)
				errx(EXIT_FAILURE, "-a option: %s", strerror(EPERM));
			decode_ss(optarg);
#ifdef notdef
			(void)sockaddr_snprintf(optarg,
			    sizeof(struct sockaddr_storage), "%a", (void *)&ss);
#endif
			break;
		case 'F':
#ifdef KERBEROS5
			Fflag = 1;
#endif
			/* FALLTHROUGH */
		case 'f':
			fflag = 1;
			break;
		case 'h':
			if (uid)
				errx(EXIT_FAILURE, "-h option: %s", strerror(EPERM));
			hflag = 1;
#ifdef notdef
			if (domain && (p = strchr(optarg, '.')) != NULL &&
			    strcasecmp(p, domain) == 0)
				*p = '\0';
#endif
			hostname = optarg;
			break;
		case 'p':
			pflag = 1;
			break;
		case 's':
			sflag = 1;
			break;
		default:
		case '?':
			usage();
			break;
		}

	setproctitle(NULL);
	argc -= optind;
	argv += optind;

	if (*argv) {
		username = loginname = *argv;
		ask = 0;
	} else
		ask = 1;

#ifdef F_CLOSEM
	(void)fcntl(3, F_CLOSEM, 0);
#else
	for (cnt = getdtablesize(); cnt > 2; cnt--)
		(void)close(cnt);
#endif

	ttyn = ttyname(STDIN_FILENO);
	if (ttyn == NULL || *ttyn == '\0') {
		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
		ttyn = tname;
	}
	if ((tty = strstr(ttyn, "/pts/")) != NULL)
		++tty;
	else if ((tty = strrchr(ttyn, '/')) != NULL)
		++tty;
	else
		tty = ttyn;

	if (issetugid()) {
		nested = strdup(user_from_uid(getuid(), 0));
		if (nested == NULL) {
			syslog(LOG_ERR, "strdup: %m");
			sleepexit(EXIT_FAILURE);
		}
	}

#ifdef LOGIN_CAP
	/* Get "login-retries" and "login-backoff" from default class */
	if ((lc = login_getclass(NULL)) != NULL) {
		login_retries = (int)login_getcapnum(lc, "login-retries",
		    DEFAULT_RETRIES, DEFAULT_RETRIES);
		login_backoff = (int)login_getcapnum(lc, "login-backoff", 
		    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
		login_close(lc);
		lc = NULL;
	}
#endif

#ifdef KERBEROS5
	kerror = krb5_init_context(&kcontext);
	if (kerror) {
		/*
		 * If Kerberos is not configured, that is, we are
		 * not using Kerberos, do not log the error message.
		 * However, if Kerberos is configured,  and the
		 * context init fails for some other reason, we need
		 * to issue a no tickets warning to the user when the
		 * login succeeds.
		 */
		if (kerror != ENXIO) {	/* XXX NetBSD-local Heimdal hack */
			syslog(LOG_NOTICE,
			    "%s when initializing Kerberos context",
			    error_message(kerror));
			krb5_configured = 1;
		}
		login_krb5_get_tickets = 0;
	}
#endif /* KERBEROS5 */

	for (cnt = 0;; ask = 1) {
#if defined(KERBEROS5)
		if (login_krb5_get_tickets)
			k5destroy();
#endif
		if (ask) {
			fflag = 0;
			loginname = getloginname();
		}
		rootlogin = 0;
#ifdef KERBEROS5
		if ((instance = strchr(loginname, '/')) != NULL)
			*instance++ = '\0';
		else
			instance = __UNCONST("");
#endif
		username = trimloginname(loginname);
		/*
		 * Note if trying multiple user names; log failures for
		 * previous user name, but don't bother logging one failure
		 * for nonexistent name (mistyped username).
		 */
		if (failures && strcmp(tbuf, username)) {
			if (failures > (pwd ? 0 : 1))
				badlogin(tbuf);
			failures = 0;
		}
		(void)strlcpy(tbuf, username, sizeof(tbuf));

		pwd = getpwnam(username);

#ifdef LOGIN_CAP
		/*
		 * Establish the class now, before we might goto
		 * within the next block. pwd can be NULL since it
		 * falls back to the "default" class if it is.
		 */
		lc = login_getclass(pwd ? pwd->pw_class : NULL);
#endif
		/*
		 * if we have a valid account name, and it doesn't have a
		 * password, or the -f option was specified and the caller
		 * is root or the caller isn't changing their uid, don't
		 * authenticate.
		 */
		if (pwd) {
			if (pwd->pw_uid == 0)
				rootlogin = 1;

			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
				/* already authenticated */
#ifdef KERBEROS5
				if (login_krb5_get_tickets && Fflag)
					k5_read_creds(username);
#endif
				break;
			} else if (pwd->pw_passwd[0] == '\0') {
				/* pretend password okay */
				rval = 0;
				goto ttycheck;
			}
		}

		fflag = 0;

		(void)setpriority(PRIO_PROCESS, 0, -4);

#ifdef SKEY
		if (skey_haskey(username) == 0) {
			static char skprompt[80];
			const char *skinfo = skey_keyinfo(username);
				
			(void)snprintf(skprompt, sizeof(skprompt),
			    "Password [ %s ]:",
			    skinfo ? skinfo : "error getting challenge");
			pwprompt = skprompt;
		} else
#endif
			pwprompt = "Password:"******"Login incorrect or refused on this "
			    "terminal.\n");
			if (hostname)
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED FROM %s ON TTY %s",
				    pwd->pw_name, hostname, tty);
			else
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED ON TTY %s",
				     pwd->pw_name, tty);
			continue;
		}

		if (pwd && !rval)
			break;

		(void)printf("Login incorrect or refused on this "
		    "terminal.\n");
		failures++;
		cnt++;
		/*
		 * We allow login_retries tries, but after login_backoff
		 * we start backing off.  These default to 10 and 3
		 * respectively.
		 */
		if (cnt > login_backoff) {
			if (cnt >= login_retries) {
				badlogin(username);
				sleepexit(EXIT_FAILURE);
			}
			sleep((u_int)((cnt - login_backoff) * 5));
		}
	}

	/* committed to login -- turn off timeout */
	(void)alarm((u_int)0);

	endpwent();

	/* if user not super-user, check for disabled logins */
#ifdef LOGIN_CAP
	if (!login_getcapbool(lc, "ignorenologin", rootlogin))
		checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
#else
	if (!rootlogin)
		checknologin(NULL);
#endif

#ifdef LOGIN_CAP
	quietlog = login_getcapbool(lc, "hushlogin", 0);
#else
	quietlog = 0;
#endif
	/* Temporarily give up special privileges so we can change */
	/* into NFS-mounted homes that are exported for non-root */
	/* access and have mode 7x0 */
	saved_uid = geteuid();
	saved_gid = getegid();
	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
	
	(void)setegid(pwd->pw_gid);
	initgroups(username, pwd->pw_gid);
	(void)seteuid(pwd->pw_uid);
	
	if (chdir(pwd->pw_dir) < 0) {
#ifdef LOGIN_CAP
		if (login_getcapbool(lc, "requirehome", 0)) {
			(void)printf("Home directory %s required\n",
			    pwd->pw_dir);
			sleepexit(EXIT_FAILURE);
		}
#endif	
		(void)printf("No home directory %s!\n", pwd->pw_dir);
		if (chdir("/") == -1)
			exit(EXIT_FAILURE);
		pwd->pw_dir = __UNCONST("/");
		(void)printf("Logging in with home = \"/\".\n");
	}

	if (!quietlog)
		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;

	/* regain special privileges */
	(void)seteuid(saved_uid);
	setgroups(nsaved_gids, saved_gids);
	(void)setegid(saved_gid);

#ifdef LOGIN_CAP
	pw_warntime = login_getcaptime(lc, "password-warn",
		_PASSWORD_WARNDAYS * SECSPERDAY,
		_PASSWORD_WARNDAYS * SECSPERDAY);
#endif

	(void)gettimeofday(&now, NULL);
	if (pwd->pw_expire) {
		if (now.tv_sec >= pwd->pw_expire) {
			(void)printf("Sorry -- your account has expired.\n");
			sleepexit(EXIT_FAILURE);
		} else if (pwd->pw_expire - now.tv_sec < pw_warntime && 
		    !quietlog)
			(void)printf("Warning: your account expires on %s",
			    ctime(&pwd->pw_expire));
	}
	if (pwd->pw_change) {
		if (pwd->pw_change == _PASSWORD_CHGNOW)
			need_chpass = 1;
		else if (now.tv_sec >= pwd->pw_change) {
			(void)printf("Sorry -- your password has expired.\n");
			sleepexit(EXIT_FAILURE);
		} else if (pwd->pw_change - now.tv_sec < pw_warntime && 
		    !quietlog)
			(void)printf("Warning: your password expires on %s",
			    ctime(&pwd->pw_change));

	}
	/* Nothing else left to fail -- really log in. */
	update_db(quietlog, rootlogin, fflag);

	(void)chown(ttyn, pwd->pw_uid,
	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);

	if (ttyaction(ttyn, "login", pwd->pw_name))
		(void)printf("Warning: ttyaction failed.\n");

#if defined(KERBEROS5)
	/* Fork so that we can call kdestroy */
	if (! login_krb5_retain_ccache && has_ccache)
		dofork();
#endif

	/* Destroy environment unless user has requested its preservation. */
	if (!pflag)
		environ = envinit;

#ifdef LOGIN_CAP
	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
	    LOGIN_SETLOGIN) != 0) {
		syslog(LOG_ERR, "setusercontext failed");
		exit(EXIT_FAILURE);
	}
	if (setusercontext(lc, pwd, pwd->pw_uid,
	    (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
		syslog(LOG_ERR, "setusercontext failed");
		exit(EXIT_FAILURE);
	}
#else
	(void)setgid(pwd->pw_gid);

	initgroups(username, pwd->pw_gid);
	
	if (nested == NULL && setlogin(pwd->pw_name) < 0)
		syslog(LOG_ERR, "setlogin() failure: %m");

	/* Discard permissions last so can't get killed and drop core. */
	if (rootlogin)
		(void)setuid(0);
	else
		(void)setuid(pwd->pw_uid);
#endif

	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = __UNCONST(_PATH_BSHELL);
#ifdef LOGIN_CAP
	if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
		if ((shell = strdup(shell)) == NULL) {
			syslog(LOG_ERR, "Cannot alloc mem");
			sleepexit(EXIT_FAILURE);
		}
		pwd->pw_shell = shell;
	}
#endif
	
	(void)setenv("HOME", pwd->pw_dir, 1);
	(void)setenv("SHELL", pwd->pw_shell, 1);
	if (term[0] == '\0') {
		const char *tt = stypeof(tty);
#ifdef LOGIN_CAP
		if (tt == NULL)
			tt = login_getcapstr(lc, "term", NULL, NULL);
#endif
		/* unknown term -> "su" */
		(void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
	}
	(void)setenv("TERM", term, 0);
	(void)setenv("LOGNAME", pwd->pw_name, 1);
	(void)setenv("USER", pwd->pw_name, 1);

#ifdef LOGIN_CAP
	setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
#else
	(void)setenv("PATH", _PATH_DEFPATH, 0);
#endif

#ifdef KERBEROS5
	if (krb5tkfile_env)
		(void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
#endif

	/* If fflag is on, assume caller/authenticator has logged root login. */
	if (rootlogin && fflag == 0) {
		if (hostname)
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
			    username, tty, hostname);
		else
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
			    username, tty);
	}

#if defined(KERBEROS5)
	if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
		(void)printf("Warning: no Kerberos tickets issued.\n");
#endif

	if (!quietlog) {
		const char *fname;
#ifdef LOGIN_CAP
		fname = login_getcapstr(lc, "copyright", NULL, NULL);
		if (fname != NULL && access(fname, F_OK) == 0)
			motd(fname);
		else
#endif
			(void)printf("%s", copyrightstr);

#ifdef LOGIN_CAP
		fname = login_getcapstr(lc, "welcome", NULL, NULL);
		if (fname == NULL || access(fname, F_OK) != 0)
#endif
			fname = _PATH_MOTDFILE;
		motd(fname);

		(void)snprintf(tbuf,
		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
		if (stat(tbuf, &st) == 0 && st.st_size != 0)
			(void)printf("You have %smail.\n",
			    (st.st_mtime > st.st_atime) ? "new " : "");
	}

#ifdef LOGIN_CAP
	login_close(lc);
#endif

	(void)signal(SIGALRM, SIG_DFL);
	(void)signal(SIGQUIT, SIG_DFL);
	(void)signal(SIGINT, SIG_DFL);
	(void)signal(SIGTSTP, SIG_IGN);

	tbuf[0] = '-';
	(void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);

	/* Wait to change password until we're unprivileged */
	if (need_chpass) {
		if (!require_chpass)
			(void)printf(
"Warning: your password has expired. Please change it as soon as possible.\n");
		else {
			int	status;

			(void)printf(
		    "Your password has expired. Please choose a new one.\n");
			switch (fork()) {
			case -1:
				warn("fork");
				sleepexit(EXIT_FAILURE);
			case 0:
				execl(_PATH_BINPASSWD, "passwd", NULL);
				_exit(EXIT_FAILURE);
			default:
				if (wait(&status) == -1 ||
				    WEXITSTATUS(status))
					sleepexit(EXIT_FAILURE);
			}
		}
	}

#ifdef KERBEROS5
	if (login_krb5_get_tickets)
		k5_write_creds();
#endif
	execlp(pwd->pw_shell, tbuf, NULL);
	err(EXIT_FAILURE, "%s", pwd->pw_shell);
}
示例#10
0
void
doit(struct sockaddr *fromp)
{
	extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
	struct passwd *pwd;
	u_short port;
	fd_set ready, readfrom;
	int cc, fd, nfd, pv[2], pid, s;
	int one = 1;
	const char *cp, *errorstr;
	char sig, buf[BUFSIZ];
	char *cmdbuf, luser[16], ruser[16];
	char rhost[2 * MAXHOSTNAMELEN + 1];
	char numericname[INET6_ADDRSTRLEN];
	int af, srcport;
	int maxcmdlen;
	login_cap_t *lc;

	maxcmdlen = (int)sysconf(_SC_ARG_MAX);
	if (maxcmdlen <= 0 || (cmdbuf = malloc(maxcmdlen)) == NULL)
		exit(1);

	(void) signal(SIGINT, SIG_DFL);
	(void) signal(SIGQUIT, SIG_DFL);
	(void) signal(SIGTERM, SIG_DFL);
	af = fromp->sa_family;
	srcport = ntohs(*((in_port_t *)&fromp->sa_data));
	if (af == AF_INET) {
		inet_ntop(af, &((struct sockaddr_in *)fromp)->sin_addr,
		    numericname, sizeof numericname);
	} else if (af == AF_INET6) {
		inet_ntop(af, &((struct sockaddr_in6 *)fromp)->sin6_addr,
		    numericname, sizeof numericname);
	} else {
		syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
		exit(1);
	}
#ifdef IP_OPTIONS
	if (af == AF_INET) {
		u_char optbuf[BUFSIZ/3];
		socklen_t optsize = sizeof(optbuf), ipproto, i;
		struct protoent *ip;

		if ((ip = getprotobyname("ip")) != NULL)
			ipproto = ip->p_proto;
		else
			ipproto = IPPROTO_IP;
		if (!getsockopt(0, ipproto, IP_OPTIONS, optbuf, &optsize) &&
		    optsize != 0) {
			for (i = 0; i < optsize; ) {
				u_char c = optbuf[i];
				if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
					syslog(LOG_NOTICE,
					    "connection refused from %s with IP option %s",
					    numericname,
					    c == IPOPT_LSRR ? "LSRR" : "SSRR");
					exit(1);
				}
				if (c == IPOPT_EOL)
					break;
				i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
			}
		}
	}
#endif

	if (srcport >= IPPORT_RESERVED ||
	    srcport < IPPORT_RESERVED/2) {
		syslog(LOG_NOTICE|LOG_AUTH,
		    "connection from %s on illegal port %u",
		    numericname,
		    srcport);
		exit(1);
	}

	(void) alarm(60);
	port = 0;
	s = 0;		/* not set or used if port == 0 */
	for (;;) {
		char c;
		if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
			if (cc < 0)
				syslog(LOG_NOTICE, "read: %m");
			shutdown(0, SHUT_RDWR);
			exit(1);
		}
		if (c == 0)
			break;
		port = port * 10 + c - '0';
	}

	(void) alarm(0);
	if (port != 0) {
		int lport = IPPORT_RESERVED - 1;
		s = rresvport_af(&lport, af);
		if (s < 0) {
			syslog(LOG_ERR, "can't get stderr port: %m");
			exit(1);
		}
		if (port >= IPPORT_RESERVED ||
		    port < IPPORT_RESERVED/2) {
			syslog(LOG_NOTICE|LOG_AUTH,
			    "2nd socket from %s on unreserved port %u",
			    numericname,
			    port);
			exit(1);
		}
		*((in_port_t *)&fromp->sa_data) = htons(port);
		if (connect(s, fromp, fromp->sa_len) < 0) {
			syslog(LOG_INFO, "connect second port %d: %m", port);
			exit(1);
		}
	}

	errorstr = NULL;
	realhostname_sa(rhost, sizeof(rhost) - 1, fromp, fromp->sa_len);
	rhost[sizeof(rhost) - 1] = '\0';
	/* XXX truncation! */

	(void) alarm(60);
	getstr(ruser, sizeof(ruser), "ruser");
	getstr(luser, sizeof(luser), "luser");
	getstr(cmdbuf, maxcmdlen, "command");
	(void) alarm(0);

	pam_err = pam_start("rsh", luser, &pamc, &pamh);
	if (pam_err != PAM_SUCCESS) {
		syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
		    pam_strerror(pamh, pam_err));
		rshd_errx(1, "Login incorrect.");
	}

	if ((pam_err = pam_set_item(pamh, PAM_RUSER, ruser)) != PAM_SUCCESS ||
	    (pam_err = pam_set_item(pamh, PAM_RHOST, rhost)) != PAM_SUCCESS) {
		syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
		    pam_strerror(pamh, pam_err));
		rshd_errx(1, "Login incorrect.");
	}

	pam_err = pam_authenticate(pamh, 0);
	if (pam_err == PAM_SUCCESS) {
		if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
			strncpy(luser, cp, sizeof(luser));
			luser[sizeof(luser) - 1] = '\0';
			/* XXX truncation! */
		}
		pam_err = pam_acct_mgmt(pamh, 0);
	}
	if (pam_err != PAM_SUCCESS) {
		syslog(LOG_INFO|LOG_AUTH,
		    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
		    ruser, rhost, luser, pam_strerror(pamh, pam_err), cmdbuf);
		rshd_errx(1, "Login incorrect.");
	}

	setpwent();
	pwd = getpwnam(luser);
	if (pwd == NULL) {
		syslog(LOG_INFO|LOG_AUTH,
		    "%s@%s as %s: unknown login. cmd='%.80s'",
		    ruser, rhost, luser, cmdbuf);
		if (errorstr == NULL)
			errorstr = "Login incorrect.";
		rshd_errx(1, errorstr, rhost);
	}

	lc = login_getpwclass(pwd);
	if (pwd->pw_uid)
		auth_checknologin(lc);

	if (chdir(pwd->pw_dir) < 0) {
		if (chdir("/") < 0 ||
		    login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
			syslog(LOG_INFO|LOG_AUTH,
			"%s@%s as %s: no home directory. cmd='%.80s'",
			ruser, rhost, luser, cmdbuf);
			rshd_errx(0, "No remote home directory.");
		}
		pwd->pw_dir = slash;
	}

	if (lc != NULL && fromp->sa_family == AF_INET) {	/*XXX*/
		char	remote_ip[MAXHOSTNAMELEN];

		strncpy(remote_ip, numericname,
			sizeof(remote_ip) - 1);
		remote_ip[sizeof(remote_ip) - 1] = 0;
		/* XXX truncation! */
		if (!auth_hostok(lc, rhost, remote_ip)) {
			syslog(LOG_INFO|LOG_AUTH,
			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
			    ruser, rhost, luser, __rcmd_errstr,
			    cmdbuf);
			rshd_errx(1, "Login incorrect.");
		}
		if (!auth_timeok(lc, time(NULL)))
			rshd_errx(1, "Logins not available right now");
	}

	/*
	 * PAM modules might add supplementary groups in
	 * pam_setcred(), so initialize them first.
	 * But we need to open the session as root.
	 */
	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
		syslog(LOG_ERR, "setusercontext: %m");
		exit(1);
	}

	if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
		syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, pam_err));
	} else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
		syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
	}

	(void) write(STDERR_FILENO, "\0", 1);
	sent_null = 1;

	if (port) {
		if (pipe(pv) < 0)
			rshd_errx(1, "Can't make pipe.");
		pid = fork();
		if (pid == -1)
			rshd_errx(1, "Can't fork; try again.");
		if (pid) {
			(void) close(0);
			(void) close(1);
			(void) close(2);
			(void) close(pv[1]);

			FD_ZERO(&readfrom);
			FD_SET(s, &readfrom);
			FD_SET(pv[0], &readfrom);
			if (pv[0] > s)
				nfd = pv[0];
			else
				nfd = s;
				ioctl(pv[0], FIONBIO, (char *)&one);

			/* should set s nbio! */
			nfd++;
			do {
				ready = readfrom;
				if (select(nfd, &ready, (fd_set *)0,
				  (fd_set *)0, (struct timeval *)0) < 0)
					break;
				if (FD_ISSET(s, &ready)) {
					int	ret;
						ret = read(s, &sig, 1);
				if (ret <= 0)
					FD_CLR(s, &readfrom);
				else
					killpg(pid, sig);
				}
				if (FD_ISSET(pv[0], &ready)) {
					errno = 0;
					cc = read(pv[0], buf, sizeof(buf));
					if (cc <= 0) {
						shutdown(s, SHUT_RDWR);
						FD_CLR(pv[0], &readfrom);
					} else {
						(void)write(s, buf, cc);
					}
				}

			} while (FD_ISSET(s, &readfrom) ||
			    FD_ISSET(pv[0], &readfrom));
			PAM_END;
			exit(0);
		}
		(void) close(s);
		(void) close(pv[0]);
		dup2(pv[1], 2);
		close(pv[1]);
	}
	else {
		pid = fork();
		if (pid == -1)
			rshd_errx(1, "Can't fork; try again.");
		if (pid) {
			/* Parent. */
			while (wait(NULL) > 0 || errno == EINTR)
				/* nothing */ ;
			PAM_END;
			exit(0);
		}
	}

	for (fd = getdtablesize(); fd > 2; fd--)
		(void) close(fd);
	if (setsid() == -1)
		syslog(LOG_ERR, "setsid() failed: %m");
	if (setlogin(pwd->pw_name) < 0)
		syslog(LOG_ERR, "setlogin() failed: %m");

	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = bshell;
	(void) pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
	(void) pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
	(void) pam_setenv(pamh, "USER", pwd->pw_name, 1);
	(void) pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
	environ = pam_getenvlist(pamh);
	(void) pam_end(pamh, pam_err);
	cp = strrchr(pwd->pw_shell, '/');
	if (cp)
		cp++;
	else
		cp = pwd->pw_shell;

	if (setusercontext(lc, pwd, pwd->pw_uid,
		LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
		syslog(LOG_ERR, "setusercontext(): %m");
		exit(1);
	}
	login_close(lc);
	endpwent();
	if (log_success || pwd->pw_uid == 0) {
		    syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
			ruser, rhost, luser, cmdbuf);
	}
	execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL);
	err(1, "%s", pwd->pw_shell);
	exit(1);
}
示例#11
0
int
main(int argc, char **argv)
{
	struct group *gr;
	struct stat st;
	int retries, backoff;
	int ask, ch, cnt, quietlog, rootlogin, rval;
	uid_t uid, euid;
	gid_t egid;
	char *term;
	char *p, *ttyn;
	char tname[sizeof(_PATH_TTY) + 10];
	char *arg0;
	const char *tp;
	const char *shell = NULL;
	login_cap_t *lc = NULL;
	login_cap_t *lc_user = NULL;
	pid_t pid;
#ifdef USE_BSM_AUDIT
	char auditsuccess = 1;
#endif

	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	if (setjmp(timeout_buf)) {
		if (failures)
			badlogin(username);
		fprintf(stderr, "Login timed out after %d seconds\n",
		    timeout);
		bail(NO_SLEEP_EXIT, 0);
	}
	signal(SIGALRM, timedout);
	alarm(timeout);
	setpriority(PRIO_PROCESS, 0, 0);

	openlog("login", LOG_ODELAY, LOG_AUTH);

	uid = getuid();
	euid = geteuid();
	egid = getegid();

	while ((ch = getopt(argc, argv, "fh:p")) != -1)
		switch (ch) {
		case 'f':
			fflag = 1;
			break;
		case 'h':
			if (uid != 0)
				errx(1, "-h option: %s", strerror(EPERM));
			if (strlen(optarg) >= MAXHOSTNAMELEN)
				errx(1, "-h option: %s: exceeds maximum "
				    "hostname size", optarg);
			hflag = 1;
			hostname = optarg;
			break;
		case 'p':
			pflag = 1;
			break;
		case '?':
		default:
			if (uid == 0)
				syslog(LOG_ERR, "invalid flag %c", ch);
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc > 0) {
		username = strdup(*argv);
		if (username == NULL)
			err(1, "strdup()");
		ask = 0;
	} else {
		ask = 1;
	}

	setproctitle("-%s", getprogname());

	for (cnt = getdtablesize(); cnt > 2; cnt--)
		close(cnt);

	/*
	 * Get current TTY
	 */
	ttyn = ttyname(STDIN_FILENO);
	if (ttyn == NULL || *ttyn == '\0') {
		snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
		ttyn = tname;
	}
	if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV) -1) == 0)
		tty = ttyn + sizeof(_PATH_DEV) -1;
	else
		tty = ttyn;

	/*
	 * Get "login-retries" & "login-backoff" from default class
	 */
	lc = login_getclass(NULL);
	prompt = login_getcapstr(lc, "login_prompt",
	    default_prompt, default_prompt);
	passwd_prompt = login_getcapstr(lc, "passwd_prompt",
	    default_passwd_prompt, default_passwd_prompt);
	retries = login_getcapnum(lc, "login-retries",
	    DEFAULT_RETRIES, DEFAULT_RETRIES);
	backoff = login_getcapnum(lc, "login-backoff",
	    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
	login_close(lc);
	lc = NULL;

	/*
	 * Try to authenticate the user until we succeed or time out.
	 */
	for (cnt = 0;; ask = 1) {
		if (ask) {
			fflag = 0;
			if (olduser != NULL)
				free(olduser);
			olduser = username;
			username = getloginname();
		}
		rootlogin = 0;

		/*
		 * Note if trying multiple user names; log failures for
		 * previous user name, but don't bother logging one failure
		 * for nonexistent name (mistyped username).
		 */
		if (failures && strcmp(olduser, username) != 0) {
			if (failures > (pwd ? 0 : 1))
				badlogin(olduser);
		}

		/*
		 * Load the PAM policy and set some variables
		 */
		pam_err = pam_start("login", username, &pamc, &pamh);
		if (pam_err != PAM_SUCCESS) {
			pam_syslog("pam_start()");
#ifdef USE_BSM_AUDIT
			au_login_fail("PAM Error", 1);
#endif
			bail(NO_SLEEP_EXIT, 1);
		}
		pam_err = pam_set_item(pamh, PAM_TTY, tty);
		if (pam_err != PAM_SUCCESS) {
			pam_syslog("pam_set_item(PAM_TTY)");
#ifdef USE_BSM_AUDIT
			au_login_fail("PAM Error", 1);
#endif
			bail(NO_SLEEP_EXIT, 1);
		}
		pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
		if (pam_err != PAM_SUCCESS) {
			pam_syslog("pam_set_item(PAM_RHOST)");
#ifdef USE_BSM_AUDIT
			au_login_fail("PAM Error", 1);
#endif
			bail(NO_SLEEP_EXIT, 1);
		}

		pwd = getpwnam(username);
		if (pwd != NULL && pwd->pw_uid == 0)
			rootlogin = 1;

		/*
		 * If the -f option was specified and the caller is
		 * root or the caller isn't changing their uid, don't
		 * authenticate.
		 */
		if (pwd != NULL && fflag &&
		    (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
			/* already authenticated */
			rval = 0;
#ifdef USE_BSM_AUDIT
			auditsuccess = 0; /* opened a terminal window only */
#endif
		} else {
			fflag = 0;
			setpriority(PRIO_PROCESS, 0, -4);
			rval = auth_pam();
			setpriority(PRIO_PROCESS, 0, 0);
		}

		if (pwd && rval == 0)
			break;

		pam_cleanup();

		/*
		 * We are not exiting here, but this corresponds to a failed
		 * login event, so set exitstatus to 1.
		 */
#ifdef USE_BSM_AUDIT
		au_login_fail("Login incorrect", 1);
#endif

		printf("Login incorrect\n");
		failures++;

		pwd = NULL;

		/*
		 * Allow up to 'retry' (10) attempts, but start
		 * backing off after 'backoff' (3) attempts.
		 */
		if (++cnt > backoff) {
			if (cnt >= retries) {
				badlogin(username);
				bail(SLEEP_EXIT, 1);
			}
			sleep((u_int)((cnt - backoff) * 5));
		}
	}

	/* committed to login -- turn off timeout */
	alarm((u_int)0);
	signal(SIGHUP, SIG_DFL);

	endpwent();

#ifdef USE_BSM_AUDIT
	/* Audit successful login. */
	if (auditsuccess)
		au_login_success();
#endif

	/*
	 * Establish the login class.
	 */
	lc = login_getpwclass(pwd);
	lc_user = login_getuserclass(pwd);

	if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
		quietlog = login_getcapbool(lc, "hushlogin", 0);

	/*
	 * Switching needed for NFS with root access disabled.
	 *
	 * XXX: This change fails to modify the additional groups for the
	 * process, and as such, may restrict rights normally granted
	 * through those groups.
	 */
	setegid(pwd->pw_gid);
	seteuid(rootlogin ? 0 : pwd->pw_uid);
	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
		if (login_getcapbool(lc, "requirehome", 0))
			refused("Home directory not available", "HOMEDIR", 1);
		if (chdir("/") < 0)
			refused("Cannot find root directory", "ROOTDIR", 1);
		if (!quietlog || *pwd->pw_dir)
			printf("No home directory.\nLogging in with home = \"/\".\n");
		pwd->pw_dir = strdup("/");
		if (pwd->pw_dir == NULL) {
			syslog(LOG_NOTICE, "strdup(): %m");
			bail(SLEEP_EXIT, 1);
		}
	}
	seteuid(euid);
	setegid(egid);
	if (!quietlog) {
		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
		if (!quietlog)
			pam_silent = 0;
	}

	shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = strdup(_PATH_BSHELL);
	if (pwd->pw_shell == NULL) {
		syslog(LOG_NOTICE, "strdup(): %m");
		bail(SLEEP_EXIT, 1);
	}
	if (*shell == '\0')   /* Not overridden */
		shell = pwd->pw_shell;
	if ((shell = strdup(shell)) == NULL) {
		syslog(LOG_NOTICE, "strdup(): %m");
		bail(SLEEP_EXIT, 1);
	}

	/*
	 * Set device protections, depending on what terminal the
	 * user is logged in. This feature is used on Suns to give
	 * console users better privacy.
	 */
	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);

	/*
	 * Clear flags of the tty.  None should be set, and when the
	 * user sets them otherwise, this can cause the chown to fail.
	 * Since it isn't clear that flags are useful on character
	 * devices, we just clear them.
	 *
	 * We don't log in the case of EOPNOTSUPP because dev might be
	 * on NFS, which doesn't support chflags.
	 *
	 * We don't log in the EROFS because that means that /dev is on
	 * a read only file system and we assume that the permissions there
	 * are sane.
	 */
	if (ttyn != tname && chflags(ttyn, 0))
		if (errno != EOPNOTSUPP && errno != EROFS)
			syslog(LOG_ERR, "chflags(%s): %m", ttyn);
	if (ttyn != tname && chown(ttyn, pwd->pw_uid,
	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
		if (errno != EROFS)
			syslog(LOG_ERR, "chown(%s): %m", ttyn);

	/*
	 * Exclude cons/vt/ptys only, assume dialup otherwise
	 * TODO: Make dialup tty determination a library call
	 * for consistency (finger etc.)
	 */
	if (hflag && isdialuptty(tty))
		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);

#ifdef LOGALL
	/*
	 * Syslog each successful login, so we don't have to watch
	 * hundreds of wtmp or lastlogin files.
	 */
	if (hflag)
		syslog(LOG_INFO, "login from %s on %s as %s",
		       hostname, tty, pwd->pw_name);
	else
		syslog(LOG_INFO, "login on %s as %s",
		       tty, pwd->pw_name);
#endif

	/*
	 * If fflag is on, assume caller/authenticator has logged root
	 * login.
	 */
	if (rootlogin && fflag == 0) {
		if (hflag)
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
			    username, tty, hostname);
		else
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
			    username, tty);
	}

	/*
	 * Destroy environment unless user has requested its
	 * preservation - but preserve TERM in all cases
	 */
	term = getenv("TERM");
	if (!pflag)
		environ = envinit;
	if (term != NULL) {
		if (setenv("TERM", term, 0) == -1)
			err(1, "setenv: cannot set TERM=%s", term);
	}

	/*
	 * PAM modules might add supplementary groups during pam_setcred().
	 */
	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
		syslog(LOG_ERR, "setusercontext() failed - exiting");
		bail(NO_SLEEP_EXIT, 1);
	}

	pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
	if (pam_err != PAM_SUCCESS) {
		pam_syslog("pam_setcred()");
		bail(NO_SLEEP_EXIT, 1);
	}
	pam_cred_established = 1;

	pam_err = pam_open_session(pamh, pam_silent);
	if (pam_err != PAM_SUCCESS) {
		pam_syslog("pam_open_session()");
		bail(NO_SLEEP_EXIT, 1);
	}
	pam_session_established = 1;

	/*
	 * We must fork() before setuid() because we need to call
	 * pam_close_session() as root.
	 */
	pid = fork();
	if (pid < 0) {
		err(1, "fork");
	} else if (pid != 0) {
		/*
		 * Parent: wait for child to finish, then clean up
		 * session.
		 */
		int status;
		setproctitle("-%s [pam]", getprogname());
		waitpid(pid, &status, 0);
		bail(NO_SLEEP_EXIT, 0);
	}

	/*
	 * NOTICE: We are now in the child process!
	 */

	/*
	 * Add any environment variables the PAM modules may have set.
	 */
	export_pam_environment();

	/*
	 * We're done with PAM now; our parent will deal with the rest.
	 */
	pam_end(pamh, 0);
	pamh = NULL;

	/*
	 * We don't need to be root anymore, so set the login name and
	 * the UID.
	 */
	if (setlogin(username) != 0) {
		syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
		bail(NO_SLEEP_EXIT, 1);
	}
	if (setusercontext(lc, pwd, pwd->pw_uid,
	    LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
		syslog(LOG_ERR, "setusercontext() failed - exiting");
		exit(1);
	}

	if (setenv("SHELL", pwd->pw_shell, 1) == -1)
		err(1, "setenv: cannot set SHELL=%s", pwd->pw_shell);
	if (setenv("HOME", pwd->pw_dir, 1) == -1)
		err(1, "setenv: cannot set HOME=%s", pwd->pw_dir);
	/* Overwrite "term" from login.conf(5) for any known TERM */
	if (term == NULL && (tp = stypeof(tty)) != NULL) {
		if (setenv("TERM", tp, 1) == -1)
			err(1, "setenv: cannot set TERM=%s", tp);
	} else {
		if (setenv("TERM", TERM_UNKNOWN, 0) == -1)
			err(1, "setenv: cannot set TERM=%s", TERM_UNKNOWN);
	}

	if (setenv("LOGNAME", username, 1) == -1)
		err(1, "setenv: cannot set LOGNAME=%s", username);
	if (setenv("USER", username, 1) == -1)
		err(1, "setenv: cannot set USER=%s", username);
	if (setenv("PATH",
	    rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0) == -1) {
		err(1, "setenv: cannot set PATH=%s",
		    rootlogin ? _PATH_STDPATH : _PATH_DEFPATH);
	}

	if (!quietlog) {
		const char *cw;

		cw = login_getcapstr(lc, "copyright", NULL, NULL);
		if (cw == NULL || motd(cw) == -1)
			printf("%s", copyright);

		printf("\n");

		cw = login_getcapstr(lc, "welcome", NULL, NULL);
		if (cw != NULL && access(cw, F_OK) == 0)
			motd(cw);
		else
			motd(_PATH_MOTDFILE);

		if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
		    login_getcapbool(lc, "nocheckmail", 0) == 0) {
			char *cx;

			/* $MAIL may have been set by class. */
			cx = getenv("MAIL");
			if (cx == NULL) {
				asprintf(&cx, "%s/%s",
				    _PATH_MAILDIR, pwd->pw_name);
			}
			if (cx && stat(cx, &st) == 0 && st.st_size != 0)
				printf("You have %smail.\n",
				    (st.st_mtime > st.st_atime) ? "new " : "");
			if (getenv("MAIL") == NULL)
				free(cx);
		}
	}

	login_close(lc_user);
	login_close(lc);

	signal(SIGALRM, SIG_DFL);
	signal(SIGQUIT, SIG_DFL);
	signal(SIGINT, SIG_DFL);
	signal(SIGTSTP, SIG_IGN);

	/*
	 * Login shells have a leading '-' in front of argv[0]
	 */
	p = strrchr(pwd->pw_shell, '/');
	if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
		syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
		    username);
		errx(1, "shell exceeds maximum pathname size");
	} else if (arg0 == NULL) {
		err(1, "asprintf()");
	}

	execlp(shell, arg0, NULL);
	err(1, "%s", shell);

	/*
	 * That's it, folks!
	 */
}
示例#12
0
文件: session.c 项目: bbidulock/wdm
static Bool StartClient(struct verify_info *verify, struct display *d, int *pidp, char *name, char *passwd
#ifdef WITH_CONSOLE_KIT
						, char *ck_session_cookie
#endif
	)
{
	char **f;
	const char *home;
	char *failsafeArgv[2];
	int pid;
#ifdef HAS_SETUSERCONTEXT
	struct passwd *pwd;
#endif
#ifdef USE_PAM
	pam_handle_t *pamh = thepamh();
#endif

	if (verify->argv) {
		WDMDebug("StartSession %s: ", verify->argv[0]);
		for (f = verify->argv; *f; f++)
			WDMDebug("%s ", *f);
		WDMDebug("; ");
	}
	if (verify->userEnviron) {
		for (f = verify->userEnviron; *f; f++)
			WDMDebug("%s ", *f);
		WDMDebug("\n");
	}

	/* Do system-dependent login setup here */

	if (setgid(verify->gid) < 0) {
		WDMError("setgid %d (user \"%s\") failed, errno=%d\n", verify->gid, name, errno);
		return (0);
	}
#if defined(BSD) && (BSD >= 199103)
	if (setlogin(name) < 0) {
		WDMError("setlogin for \"%s\" failed, errno=%d", name, errno);
		return (0);
	}
#endif
	if (initgroups(name, verify->gid) < 0) {
		WDMError("initgroups for \"%s\" failed, errno=%d\n", name, errno);
		return (0);
	}
#ifdef USE_PAM
	if (pamh) {
		if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) {
			WDMError("pam_setcred failed, errno=%d\n", errno);
			log_to_audit_system(0);
			pam_end(pamh, PAM_SUCCESS);
			pamh = NULL;
			return 0;
		}

		pam_open_session(pamh, 0);
		log_to_audit_system(1);

		/* pass in environment variables set by libpam and modules it called */
		{
			long i;
			char **pam_env = pam_getenvlist(pamh);
			for (i = 0; pam_env && pam_env[i]; i++) {
				verify->userEnviron = WDMPutEnv(verify->userEnviron, pam_env[i]);
			}
		}
	}
#endif
	switch (pid = fork()) {
	case 0:
		CleanUpChild();
#ifdef XDMCP
		/* The chooser socket is not closed by CleanUpChild() */
		DestroyWellKnownSockets();
#endif

		if (setuid(verify->uid) < 0) {
			WDMError("setuid %d (user \"%s\") failed, errno=%d\n", verify->uid, name, errno);
			return (0);
		}

		/*
		 * for Security Enhanced Linux,
		 * set the default security context for this user.
		 */
#ifdef WITH_SELINUX
		if (is_selinux_enabled()) {
			security_context_t scontext;
			if (get_default_context(name, NULL, &scontext))
				WDMError("Failed to get default security context" " for %s.", name);
			WDMDebug("setting security context to %s", scontext);
			if (setexeccon(scontext)) {
				freecon(scontext);
				WDMError("Failed to set exec security context %s " "for %s.", scontext, name);
			}
			freecon(scontext);
		}
#endif
		/*
		 * for user-based authorization schemes,
		 * use the password to get the user's credentials.
		 */
		bzero(passwd, strlen(passwd));
#ifdef WITH_CONSOLE_KIT
		if (ck_session_cookie != NULL) {
			verify->userEnviron = WDMSetEnv(verify->userEnviron, "XDG_SESSION_COOKIE", ck_session_cookie);
		}
#endif
		SetUserAuthorization(d, verify);
		home = WDMGetEnv(verify->userEnviron, "HOME");
		if (home)
			if (chdir(home) == -1) {
				WDMError("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n",
						 WDMGetEnv(verify->userEnviron, "USER"), home, errno);
				chdir("/");
				verify->userEnviron = WDMSetEnv(verify->userEnviron, "HOME", "/");
			}
		if (verify->argv) {
			WDMDebug("executing session %s\n", verify->argv[0]);
			execute(verify->argv, verify->userEnviron);
			WDMError("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno);
		} else {
			WDMError("Session has no command/arguments\n");
		}
		failsafeArgv[0] = d->failsafeClient;
		failsafeArgv[1] = 0;
		execute(failsafeArgv, verify->userEnviron);
		exit(1);
	case -1:
		bzero(passwd, strlen(passwd));
		WDMDebug("StartSession, fork failed\n");
		WDMError("can't start session on \"%s\", fork failed, errno=%d\n", d->name, errno);
		return 0;
	default:
		bzero(passwd, strlen(passwd));
		WDMDebug("StartSession, fork succeeded %d\n", pid);
		*pidp = pid;
		return 1;
	}
}
示例#13
0
static void
run_file(const char *filename, uid_t uid, gid_t gid)
{
/* Run a file by spawning off a process which redirects I/O,
 * spawns a subshell, then waits for it to complete and sends
 * mail to the user.
 */
    pid_t pid;
    int fd_out, fd_in;
    int queue;
    char mailbuf[LOGNAMESIZE + 1], fmt[49];
    char *mailname = NULL;
    FILE *stream;
    int send_mail = 0;
    struct stat buf, lbuf;
    off_t size;
    struct passwd *pentry;
    int fflags;
    uid_t nuid;
    gid_t ngid;
#ifdef PAM
    pam_handle_t *pamh = NULL;
    int pam_err;
    struct pam_conv pamc = {
	.conv = openpam_nullconv,
	.appdata_ptr = NULL
    };
#endif

    PRIV_START

    if (chmod(filename, S_IRUSR) != 0)
    {
	perr("cannot change file permissions");
    }

    PRIV_END

    pid = fork();
    if (pid == -1)
	perr("cannot fork");
    
    else if (pid != 0)
	return;

    /* Let's see who we mail to.  Hopefully, we can read it from
     * the command file; if not, send it to the owner, or, failing that,
     * to root.
     */

    pentry = getpwuid(uid);
    if (pentry == NULL)
	perrx("Userid %lu not found - aborting job %s",
		(unsigned long) uid, filename);

#ifdef PAM
    PRIV_START

    pam_err = pam_start(atrun, pentry->pw_name, &pamc, &pamh);
    if (pam_err != PAM_SUCCESS)
	perrx("cannot start PAM: %s", pam_strerror(pamh, pam_err));

    pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
    /* Expired password shouldn't prevent the job from running. */
    if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
	perrx("Account %s (userid %lu) unavailable for job %s: %s",
	    pentry->pw_name, (unsigned long)uid,
	    filename, pam_strerror(pamh, pam_err));

    pam_end(pamh, pam_err);

    PRIV_END
#endif /* PAM */

    PRIV_START

    stream=fopen(filename, "r");

    PRIV_END

    if (stream == NULL)
	perr("cannot open input file");

    if ((fd_in = dup(fileno(stream))) <0)
	perr("error duplicating input file descriptor");

    if (fstat(fd_in, &buf) == -1)
	perr("error in fstat of input file descriptor");

    if (lstat(filename, &lbuf) == -1)
	perr("error in fstat of input file");

    if (S_ISLNK(lbuf.st_mode))
	perrx("Symbolic link encountered in job %s - aborting", filename);

    if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
        (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
        (lbuf.st_size!=buf.st_size))
	perrx("Somebody changed files from under us for job %s - aborting",
		filename);

    if (buf.st_nlink > 1)
	perrx("Somebody is trying to run a linked script for job %s", filename);

    if ((fflags = fcntl(fd_in, F_GETFD)) <0)
	perr("error in fcntl");

    fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);

    snprintf(fmt, sizeof(fmt),
	"#!/bin/sh\n# atrun uid=%%ld gid=%%ld\n# mail %%%ds %%d",
                          LOGNAMESIZE);

    if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4)
	perrx("File %s is in wrong format - aborting", filename);

    if (mailbuf[0] == '-')
	perrx("Illegal mail name %s in %s", mailbuf, filename);

    mailname = mailbuf;

    if (nuid != uid)
	perrx("Job %s - userid %u does not match file uid %u",
		filename, nuid, uid);

    if (ngid != gid)
	perrx("Job %s - groupid %u does not match file gid %u",
		filename, ngid, gid);

    fclose(stream);

    if (chdir(ATSPOOL_DIR) < 0)
	perr("cannot chdir to %s", ATSPOOL_DIR);
    
    /* Create a file to hold the output of the job we are about to run.
     * Write the mail header.
     */    
    if((fd_out=open(filename,
		O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0)
	perr("cannot create output file");

    write_string(fd_out, "Subject: Output from your job ");
    write_string(fd_out, filename);
    write_string(fd_out, "\n\n");
    fstat(fd_out, &buf);
    size = buf.st_size;

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
 
    pid = fork();
    if (pid < 0)
	perr("error in fork");

    else if (pid == 0)
    {
	char *nul = NULL;
	char **nenvp = &nul;

	/* Set up things for the child; we want standard input from the input file,
	 * and standard output and error sent to our output file.
	 */

	if (lseek(fd_in, (off_t) 0, SEEK_SET) < 0)
	    perr("error in lseek");

	if (dup(fd_in) != STDIN_FILENO)
	    perr("error in I/O redirection");

	if (dup(fd_out) != STDOUT_FILENO)
	    perr("error in I/O redirection");

	if (dup(fd_out) != STDERR_FILENO)
	    perr("error in I/O redirection");

	close(fd_in);
	close(fd_out);
	if (chdir(ATJOB_DIR) < 0)
	    perr("cannot chdir to %s", ATJOB_DIR);

	queue = *filename;

	PRIV_START

        nice(tolower(queue) - 'a');
	
#ifdef LOGIN_CAP
	/*
	 * For simplicity and safety, set all aspects of the user context
	 * except for a selected subset:  Don't set priority, which was
	 * set based on the queue file name according to the tradition.
	 * Don't bother to set environment, including path vars, either
	 * because it will be discarded anyway.  Although the job file
	 * should set umask, preset it here just in case.
	 */
	if (setusercontext(NULL, pentry, uid, LOGIN_SETALL &
		~(LOGIN_SETPRIORITY | LOGIN_SETPATH | LOGIN_SETENV)) != 0)
	    exit(EXIT_FAILURE);	/* setusercontext() logged the error */
#else /* LOGIN_CAP */
	if (initgroups(pentry->pw_name,pentry->pw_gid))
	    perr("cannot init group access list");

	if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
	    perr("cannot change group");

	if (setlogin(pentry->pw_name))
	    perr("cannot set login name");

	if (setuid(uid) < 0 || seteuid(uid) < 0)
	    perr("cannot set user id");
#endif /* LOGIN_CAP */

	if (chdir(pentry->pw_dir))
		chdir("/");

	if(execle("/bin/sh","sh",NULL, nenvp) != 0)
	    perr("exec failed for /bin/sh");

	PRIV_END
    }
示例#14
0
int
main(int argc, char **argv)
{
    int devfs=0,c,i;

    /* These are copied from real init(8) */
    if(getuid()!=0)
        errx(1,"%s",strerror(EPERM));
    openlog("init",LOG_CONS|LOG_ODELAY,LOG_AUTH);
    if(setsid()<0)
        warn("initial setsid() failed");
    if(setlogin("root")<0)
        warn("setlogin() failed");

    close(0);
    close(1);
    close(2);
    chdir("/");

    progname=rindex(argv[0],'/');
    if(progname==NULL) {
        progname=argv[0];
    } else progname++;

    transition=MULTI;

    /* We must recognize the same options as real init does */
    while((c=getopt(argc,argv,"dsf"))!=-1) {
        switch(c) {
        case 'd':
            devfs=1;
            break;
        case 's':
            transition=SINGLE;
            break;
        case 'f':
            break;
        default:
            printf("%s: unrecognized flag '-%c'\n",progname,c);
            break;
        }
    }
    if(devfs)
        mount("devfs",_PATH_DEV,MNT_NOEXEC|MNT_RDONLY,0);

    /* Fill in the sess structures. */
    /* XXX Really, should be filled based upon config file. */
    for(i=0; i<MAX_CONS; i++) {
        if(i==0) {
            sprintf(ttys[i].tty,_PATH_CONSOLE);
        } else {
            sprintf(ttys[i].tty,"%sv%c",_PATH_TTY,vty[i]);
        }
        ttys[i].pid=0;
        ttys[i].func=shell;
    }

    getcwd(cwd,BUFSIZE);

    signal(SIGINT,transition_handler);
    signal(SIGQUIT,transition_handler);
    signal(SIGTERM,transition_handler);
    signal(SIGHUP,transition_handler);
    signal(SIGALRM,kill_timer);

    setjmp(machine);
    transition_machine(transition);
    /* NOTREACHED */
    exit(100);
}
示例#15
0
static void
do_login(const struct passwd *pwd, char *tty, char *ttyn)
{
#ifdef HAVE_GETSPNAM
    struct spwd *sp;
#endif
    int rootlogin = (pwd->pw_uid == 0);
    gid_t tty_gid;
    struct group *gr;
    const char *home_dir;
    int i;

    if(!rootlogin)
	checknologin();

#ifdef HAVE_GETSPNAM
    sp = getspnam(pwd->pw_name);
#endif

    update_utmp(pwd->pw_name, remote_host ? remote_host : "",
		tty, ttyn);

    gr = getgrnam ("tty");
    if (gr != NULL)
	tty_gid = gr->gr_gid;
    else
	tty_gid = pwd->pw_gid;

    if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) {
	warn("chown %s", ttyn);
	if (rootlogin == 0)
	    exit (1);
    }

    if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) {
	warn("chmod %s", ttyn);
	if (rootlogin == 0)
	    exit (1);
    }

#ifdef HAVE_SETLOGIN
    if(setlogin(pwd->pw_name)){
	warn("setlogin(%s)", pwd->pw_name);
	if(rootlogin == 0)
	    exit(1);
    }
#endif
    if(rootlogin == 0) {
	const char *file = login_conf_get_string("limits");
	if(file == NULL)
	    file = _PATH_LIMITS_CONF;

	read_limits_conf(file, pwd);
    }
	
#ifdef HAVE_SETPCRED
    if (setpcred (pwd->pw_name, NULL) == -1)
	warn("setpcred(%s)", pwd->pw_name);
#endif /* HAVE_SETPCRED */
#ifdef HAVE_INITGROUPS
    if(initgroups(pwd->pw_name, pwd->pw_gid)){
	warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid);
	if(rootlogin == 0)
	    exit(1);
    }
#endif
    if(do_osfc2_magic(pwd->pw_uid))
	exit(1);
    if(setgid(pwd->pw_gid)){
	warn("setgid(%u)", (unsigned)pwd->pw_gid);
	if(rootlogin == 0)
	    exit(1);
    }
    if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) {
	warn("setuid(%u)", (unsigned)pwd->pw_uid);
	if(rootlogin == 0)
	    exit(1);
    }

    /* make sure signals are set to default actions, apparently some
       OS:es like to ignore SIGINT, which is not very convenient */

    for (i = 1; i < NSIG; ++i)
	signal(i, SIG_DFL);

    /* all kinds of different magic */

#ifdef HAVE_GETSPNAM
    check_shadow(pwd, sp);
#endif

#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM)
    {
	struct udb *udb;
	long t;
	const long maxcpu = 46116860184; /* some random constant */
	udb = getudbnam(pwd->pw_name);
	if(udb == UDB_NULL)
	    errx(1, "Failed to get UDB entry.");
	t = udb->ue_pcpulim[UDBRC_INTER];
	if(t == 0 || t > maxcpu)
	    t = CPUUNLIM;
	else
	    t *= 100 * CLOCKS_PER_SEC;

	if(limit(C_PROC, 0, L_CPU, t) < 0)
	    warn("limit C_PROC");

	t = udb->ue_jcpulim[UDBRC_INTER];
	if(t == 0 || t > maxcpu)
	    t = CPUUNLIM;
	else
	    t *= 100 * CLOCKS_PER_SEC;

	if(limit(C_JOBPROCS, 0, L_CPU, t) < 0)
	    warn("limit C_JOBPROCS");

	nice(udb->ue_nice[UDBRC_INTER]);
    }
#endif
#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC)
	/* XXX SGI capability hack IRIX 6.x (x >= 0?) has something
	   called capabilities, that allow you to give away
	   permissions (such as chown) to specific processes. From 6.5
	   this is default on, and the default capability set seems to
	   not always be the empty set. The problem is that the
	   runtime linker refuses to do just about anything if the
	   process has *any* capabilities set, so we have to remove
	   them here (unless otherwise instructed by /etc/capability).
	   In IRIX < 6.5, these functions was called sgi_cap_setproc,
	   etc, but we ignore this fact (it works anyway). */
	{
	    struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name);
	    cap_t cap;
	    if(ucap == NULL)
		cap = cap_from_text("all=");
	    else
		cap = cap_from_text(ucap->ca_default);
	    if(cap == NULL)
		err(1, "cap_from_text");
	    if(cap_set_proc(cap) < 0)
		err(1, "cap_set_proc");
	    cap_free(cap);
	    free(ucap);
	}
#endif
    home_dir = pwd->pw_dir;
    if (chdir(home_dir) < 0) {
	fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir);
	if (chdir("/"))
	    exit(0);
	home_dir = "/";
	fprintf(stderr, "Logging in with home = \"/\".\n");
    }
#ifdef KRB5
    if (auth == AUTH_KRB5) {
	krb5_start_session (pwd);
    }

    krb5_get_afs_tokens (pwd);

    krb5_finish ();
#endif /* KRB5 */

    add_env("PATH", _PATH_DEFPATH);

    {
	const char *str = login_conf_get_string("environment");
	char buf[MAXPATHLEN];

	if(str == NULL) {
	    login_read_env(_PATH_ETC_ENVIRONMENT);
	} else {
	    while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) {
		if(buf[0] == '\0')
		    continue;
		login_read_env(buf);
	    }
	}
    }
    {
	const char *str = login_conf_get_string("motd");
	char buf[MAXPATHLEN];

	if(str != NULL) {
	    while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) {
		if(buf[0] == '\0')
		    continue;
		show_file(buf);
	    }
	} else {
	    str = login_conf_get_string("welcome");
	    if(str != NULL)
		show_file(str);
	}
    }
    add_env("HOME", home_dir);
    add_env("USER", pwd->pw_name);
    add_env("LOGNAME", pwd->pw_name);
    add_env("SHELL", pwd->pw_shell);
    exec_shell(pwd->pw_shell, rootlogin);
}
示例#16
0
static void
child_process(entry *e) {
    int stdin_pipe[2], stdout_pipe[2];
    char * volatile input_data;
    char *homedir, *usernm, * volatile mailto;
    int children = 0;

    Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd));

    setproctitle("running job");

    /* discover some useful and important environment settings
     */
    usernm = e->pwd->pw_name;
    mailto = env_get("MAILTO", e->envp);

    /* our parent is watching for our death by catching SIGCHLD.  we
     * do not care to watch for our children's deaths this way -- we
     * use wait() explicitly.  so we have to reset the signal (which
     * was inherited from the parent).
     */
    (void) signal(SIGCHLD, SIG_DFL);

    /* create some pipes to talk to our future child
     */
    if (pipe(stdin_pipe) == -1) 	/* child's stdin */
        log_it("CRON", getpid(), "error", "create child stdin pipe");
    if (pipe(stdout_pipe) == -1)	/* child's stdout */
        log_it("CRON", getpid(), "error", "create child stdout pipe");

    /* since we are a forked process, we can diddle the command string
     * we were passed -- nobody else is going to use it again, right?
     *
     * if a % is present in the command, previous characters are the
     * command, and subsequent characters are the additional input to
     * the command.  An escaped % will have the escape character stripped
     * from it.  Subsequent %'s will be transformed into newlines,
     * but that happens later.
     */
    /*local*/{
        int escaped = FALSE;
        int ch;
        char *p;

        /* translation:
         *	\% -> %
         *	%  -> end of command, following is command input.
         *	\x -> \x	for all x != %
         */
        input_data = p = e->cmd;
        while ((ch = *input_data++) != '\0') {
            if (escaped) {
                if (ch != '%')
                    *p++ = '\\';
            } else {
                if (ch == '%') {
                    break;
                }
            }

            if (!(escaped = (ch == '\\'))) {
                *p++ = ch;
            }
        }
        if (ch == '\0') {
            /* move pointer back, so that code below
             * won't think we encountered % sequence */
            input_data--;
        }
        if (escaped)
            *p++ = '\\';

        *p = '\0';
    }

    /* fork again, this time so we can exec the user's command.
     */
    switch (vfork()) {
    case -1:
        log_it("CRON", getpid(), "error", "can't vfork");
        exit(ERROR_EXIT);
    /*NOTREACHED*/
    case 0:
        Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n",
                      (long)getpid()));

        /* write a log message.  we've waited this long to do it
         * because it was not until now that we knew the PID that
         * the actual user command shell was going to get and the
         * PID is part of the log message.
         */
        if ((e->flags & DONT_LOG) == 0) {
            char *x = mkprints(e->cmd, strlen(e->cmd));

            log_it(usernm, getpid(), "CMD START", x);
            free(x);
        }

        /* that's the last thing we'll log.  close the log files.
         */
        log_close();

        /* get new pgrp, void tty, etc.
         */
        if (setsid() == -1)
            syslog(LOG_ERR, "setsid() failure: %m");

        /* close the pipe ends that we won't use.  this doesn't affect
         * the parent, who has to read and write them; it keeps the
         * kernel from recording us as a potential client TWICE --
         * which would keep it from sending SIGPIPE in otherwise
         * appropriate circumstances.
         */
        (void)close(stdin_pipe[WRITE_PIPE]);
        (void)close(stdout_pipe[READ_PIPE]);

        /* grandchild process.  make std{in,out} be the ends of
         * pipes opened by our daddy; make stderr go to stdout.
         */
        if (stdin_pipe[READ_PIPE] != STDIN) {
            (void)dup2(stdin_pipe[READ_PIPE], STDIN);
            (void)close(stdin_pipe[READ_PIPE]);
        }
        if (stdout_pipe[WRITE_PIPE] != STDOUT) {
            (void)dup2(stdout_pipe[WRITE_PIPE], STDOUT);
            (void)close(stdout_pipe[WRITE_PIPE]);
        }
        (void)dup2(STDOUT, STDERR);

        /* set our directory, uid and gid.  Set gid first, since once
         * we set uid, we've lost root privledges.
         */
#ifdef LOGIN_CAP
        {
#ifdef BSD_AUTH
            auth_session_t *as;
#endif
            login_cap_t *lc;
            char *p;

            if ((lc = login_getclass(e->pwd->pw_class)) == NULL) {
                warnx("unable to get login class for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
            if (setusercontext(lc, e->pwd, e->pwd->pw_uid, LOGIN_SETALL) < 0) {
                warnx("setusercontext failed for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
#ifdef BSD_AUTH
            as = auth_open();
            if (as == NULL || auth_setpwd(as, e->pwd) != 0) {
                warn("can't malloc");
                _exit(ERROR_EXIT);
            }
            if (auth_approval(as, lc, usernm, "cron") <= 0) {
                warnx("approval failed for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
            auth_close(as);
#endif /* BSD_AUTH */
            login_close(lc);

            /* If no PATH specified in crontab file but
             * we just added one via login.conf, add it to
             * the crontab environment.
             */
            if (env_get("PATH", e->envp) == NULL) {
                if ((p = getenv("PATH")) != NULL)
                    e->envp = env_set(e->envp, p);
            }
        }
#else
        if (setgid(e->pwd->pw_gid) != 0) {
            syslog(LOG_ERR, "setgid(%d) failed for %s: %m",
                   e->pwd->pw_gid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
        if (initgroups(usernm, e->pwd->pw_gid) != 0) {
            syslog(LOG_ERR, "initgroups(%s, %d) failed for %s: %m",
                   usernm, e->pwd->pw_gid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
#if (defined(BSD)) && (BSD >= 199103)
        if (setlogin(usernm) < 0) {
            syslog(LOG_ERR, "setlogin(%s) failure for %s: %m",
                   usernm, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
#endif /* BSD */
        if (setuid(e->pwd->pw_uid) != 0) {
            syslog(LOG_ERR, "setuid(%d) failed for %s: %m",
                   e->pwd->pw_uid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
        /* we aren't root after this... */
#endif /* LOGIN_CAP */
        homedir = env_get("HOME", e->envp);
        if (chdir(homedir) != 0) {
            syslog(LOG_ERR, "chdir(%s) $HOME failed for %s: %m",
                   homedir, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }

#ifdef USE_SIGCHLD
        /* our grandparent is watching for our death by catching
         * SIGCHLD.  the parent is ignoring SIGCHLD's; we want
         * to restore default behaviour.
         */
        (void) signal(SIGCHLD, SIG_DFL);
#endif
        (void) signal(SIGHUP, SIG_DFL);

        /*
         * Exec the command.
         */
        {
            char	*shell = env_get("SHELL", e->envp);

# if DEBUGGING
            if (DebugFlags & DTEST) {
                (void)fprintf(stderr,
                              "debug DTEST is on, not exec'ing command.\n");
                (void)fprintf(stderr,
                              "\tcmd='%s' shell='%s'\n", e->cmd, shell);
                _exit(OK_EXIT);
            }
# endif /*DEBUGGING*/
            (void)execle(shell, shell, "-c", e->cmd, NULL, e->envp);
            warn("execl: couldn't exec `%s'", shell);
            _exit(ERROR_EXIT);
        }
        break;
    default:
        /* parent process */
        break;
    }

    children++;

    /* middle process, child of original cron, parent of process running
     * the user's command.
     */

    Debug(DPROC, ("[%ld] child continues, closing pipes\n",(long)getpid()));

    /* close the ends of the pipe that will only be referenced in the
     * grandchild process...
     */
    (void)close(stdin_pipe[READ_PIPE]);
    (void)close(stdout_pipe[WRITE_PIPE]);

    /*
     * write, to the pipe connected to child's stdin, any input specified
     * after a % in the crontab entry.  while we copy, convert any
     * additional %'s to newlines.  when done, if some characters were
     * written and the last one wasn't a newline, write a newline.
     *
     * Note that if the input data won't fit into one pipe buffer (2K
     * or 4K on most BSD systems), and the child doesn't read its stdin,
     * we would block here.  thus we must fork again.
     */

    if (*input_data && fork() == 0) {
        FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
        int need_newline = FALSE;
        int escaped = FALSE;
        int ch;

        Debug(DPROC, ("[%ld] child2 sending data to grandchild\n",
                      (long)getpid()));

        /* close the pipe we don't use, since we inherited it and
         * are part of its reference count now.
         */
        (void)close(stdout_pipe[READ_PIPE]);

        /* translation:
         *	\% -> %
         *	%  -> \n
         *	\x -> \x	for all x != %
         */
        while ((ch = *input_data++) != '\0') {
            if (escaped) {
                if (ch != '%')
                    (void)putc('\\', out);
            } else {
                if (ch == '%')
                    ch = '\n';
            }

            if (!(escaped = (ch == '\\'))) {
                (void)putc(ch, out);
                need_newline = (ch != '\n');
            }
        }
        if (escaped)
            (void)putc('\\', out);
        if (need_newline)
            (void)putc('\n', out);

        /* close the pipe, causing an EOF condition.  fclose causes
         * stdin_pipe[WRITE_PIPE] to be closed, too.
         */
        (void)fclose(out);

        Debug(DPROC, ("[%ld] child2 done sending to grandchild\n",
                      (long)getpid()));
        exit(0);
    }

    /* close the pipe to the grandkiddie's stdin, since its wicked uncle
     * ernie back there has it open and will close it when he's done.
     */
    (void)close(stdin_pipe[WRITE_PIPE]);

    children++;

    /*
     * read output from the grandchild.  it's stderr has been redirected to
     * it's stdout, which has been redirected to our pipe.  if there is any
     * output, we'll be mailing it to the user whose crontab this is...
     * when the grandchild exits, we'll get EOF.
     */

    Debug(DPROC, ("[%ld] child reading output from grandchild\n",
                  (long)getpid()));

    /*local*/{
        FILE	*in = fdopen(stdout_pipe[READ_PIPE], "r");
        int	ch = getc(in);

        if (ch != EOF) {
            FILE	*mail = NULL;
            int	bytes = 1;
            int	status = 0;

            Debug(DPROC|DEXT,
                  ("[%ld] got data (%x:%c) from grandchild\n",
                   (long)getpid(), ch, ch));

            /* get name of recipient.  this is MAILTO if set to a
             * valid local username; USER otherwise.
             */
            if (mailto) {
                /* MAILTO was present in the environment
                 */
                if (!*mailto) {
                    /* ... but it's empty. set to NULL
                     */
                    mailto = NULL;
                }
            } else {
                /* MAILTO not present, set to USER.
                 */
                mailto = usernm;
            }

            /* if we are supposed to be mailing, MAILTO will
             * be non-NULL.  only in this case should we set
             * up the mail command and subjects and stuff...
             */

            if (mailto && safe_p(usernm, mailto)) {
                char	**env;
                char	mailcmd[MAX_COMMAND];
                char	hostname[MAXHOSTNAMELEN + 1];

                (void)gethostname(hostname, MAXHOSTNAMELEN);
                if (strlens(MAILFMT, MAILARG, NULL) + 1
                        >= sizeof mailcmd) {
                    warnx("mailcmd too long");
                    (void) _exit(ERROR_EXIT);
                }
                (void)snprintf(mailcmd, sizeof(mailcmd),
                               MAILFMT, MAILARG);
                if (!(mail = cron_popen(mailcmd, "w", e->pwd))) {
                    warn("cannot run `%s'", mailcmd);
                    (void) _exit(ERROR_EXIT);
                }
                (void)fprintf(mail,
                              "From: root (Cron Daemon)\n");
                (void)fprintf(mail, "To: %s\n", mailto);
                (void)fprintf(mail,
                              "Subject: Cron <%s@%s> %s\n",
                              usernm, first_word(hostname, "."), e->cmd);
                (void)fprintf(mail,
                              "Auto-Submitted: auto-generated\n");
#ifdef MAIL_DATE
                (void)fprintf(mail, "Date: %s\n",
                              arpadate(&StartTime));
#endif /*MAIL_DATE*/
                for (env = e->envp;  *env;  env++)
                    (void)fprintf(mail,
                                  "X-Cron-Env: <%s>\n", *env);
                (void)fprintf(mail, "\n");

                /* this was the first char from the pipe
                 */
                (void)putc(ch, mail);
            }

            /* we have to read the input pipe no matter whether
             * we mail or not, but obviously we only write to
             * mail pipe if we ARE mailing.
             */

            while (EOF != (ch = getc(in))) {
                bytes++;
                if (mailto)
                    (void)putc(ch, mail);
            }

            /* only close pipe if we opened it -- i.e., we're
             * mailing...
             */

            if (mailto) {
                Debug(DPROC, ("[%ld] closing pipe to mail\n",
                              (long)getpid()));
                /* Note: the pclose will probably see
                 * the termination of the grandchild
                 * in addition to the mail process, since
                 * it (the grandchild) is likely to exit
                 * after closing its stdout.
                 */
                status = cron_pclose(mail);
            }

            /* if there was output and we could not mail it,
             * log the facts so the poor user can figure out
             * what's going on.
             */
            if (mailto && status) {
                char buf[MAX_TEMPSTR];

                (void)snprintf(buf, sizeof(buf),
                               "mailed %d byte%s of output but got status 0x%04x\n",
                               bytes, (bytes==1)?"":"s",
                               status);
                log_it(usernm, getpid(), "MAIL", buf);
            }

        } /*if data from grandchild*/

        Debug(DPROC, ("[%ld] got EOF from grandchild\n",
                      (long)getpid()));

        (void)fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
    }

    /* wait for children to die.
     */
    for (; children > 0; children--) {
        WAIT_T waiter;
        PID_T pid;

        Debug(DPROC, ("[%ld] waiting for grandchild #%d to finish\n",
                      (long)getpid(), children));
        while ((pid = wait(&waiter)) < OK && errno == EINTR)
            ;
        if (pid < OK) {
            Debug(DPROC,
                  ("[%ld] no more grandchildren--mail written?\n",
                   (long)getpid()));
            break;
        }
        Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x",
                      (long)getpid(), (long)pid, WEXITSTATUS(waiter)));
        if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
            Debug(DPROC, (", dumped core"));
        Debug(DPROC, ("\n"));
    }

    /* Log the time when we finished deadling with the job */
    /*local*/{
        char *x = mkprints(e->cmd, strlen(e->cmd));

        log_it(usernm, getpid(), "CMD FINISH", x);
        free(x);
    }
}
示例#17
0
文件: rshd.c 项目: 2asoft/freebsd
static void
doit (void)
{
    u_char buf[BUFSIZ];
    u_char *p;
    struct sockaddr_storage thisaddr_ss;
    struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
    struct sockaddr_storage thataddr_ss;
    struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
    struct sockaddr_storage erraddr_ss;
    struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
    socklen_t thisaddr_len, thataddr_len;
    int port;
    int errsock = -1;
    char *client_user = NULL, *server_user = NULL, *cmd = NULL;
    struct passwd *pwd;
    int s = STDIN_FILENO;
    char **env;
    int ret;
    char that_host[NI_MAXHOST];

    thisaddr_len = sizeof(thisaddr_ss);
    if (getsockname (s, thisaddr, &thisaddr_len) < 0)
	syslog_and_die("getsockname: %s", strerror(errno));
    thataddr_len = sizeof(thataddr_ss);
    if (getpeername (s, thataddr, &thataddr_len) < 0)
	syslog_and_die ("getpeername: %s", strerror(errno));

    /* check for V4MAPPED addresses? */

    if (do_kerberos == 0 && !is_reserved(socket_get_port(thataddr)))
	fatal(s, NULL, "Permission denied.");

    p = buf;
    port = 0;
    for(;;) {
	if (net_read (s, p, 1) != 1)
	    syslog_and_die ("reading port number: %s", strerror(errno));
	if (*p == '\0')
	    break;
	else if (isdigit(*p))
	    port = port * 10 + *p - '0';
	else
	    syslog_and_die ("non-digit in port number: %c", *p);
    }

    if (do_kerberos  == 0 && !is_reserved(htons(port)))
	fatal(s, NULL, "Permission denied.");

    if (port) {
	int priv_port = IPPORT_RESERVED - 1;

	/*
	 * There's no reason to require a ``privileged'' port number
	 * here, but for some reason the brain dead rsh clients
	 * do... :-(
	 */

	erraddr->sa_family = thataddr->sa_family;
	socket_set_address_and_port (erraddr,
				     socket_get_address (thataddr),
				     htons(port));

	/*
	 * we only do reserved port for IPv4
	 */

	if (erraddr->sa_family == AF_INET)
	    errsock = rresvport (&priv_port);
	else
	    errsock = socket (erraddr->sa_family, SOCK_STREAM, 0);
	if (errsock < 0)
	    syslog_and_die ("socket: %s", strerror(errno));
	if (connect (errsock,
		     erraddr,
		     socket_sockaddr_size (erraddr)) < 0) {
	    syslog (LOG_WARNING, "connect: %s", strerror(errno));
	    close (errsock);
	}
    }

    if(do_kerberos) {
	if (net_read (s, buf, 4) != 4)
	    syslog_and_die ("reading auth info: %s", strerror(errno));

#ifdef KRB5
	    if((do_kerberos & DO_KRB5) &&
	       recv_krb5_auth (s, buf, thisaddr, thataddr,
			       &client_user,
			       &server_user,
			       &cmd) == 0)
		auth_method = AUTH_KRB5;
	    else
#endif /* KRB5 */
		syslog_and_die ("unrecognized auth protocol: %x %x %x %x",
				buf[0], buf[1], buf[2], buf[3]);
    } else {
	if(recv_bsd_auth (s, buf,
			  (struct sockaddr_in *)thisaddr,
			  (struct sockaddr_in *)thataddr,
			  &client_user,
			  &server_user,
			  &cmd) == 0) {
	    auth_method = AUTH_BROKEN;
	    if(do_vacuous) {
		printf("Remote host requires Kerberos authentication\n");
		exit(0);
	    }
	} else
	    syslog_and_die("recv_bsd_auth failed");
    }

    if (client_user == NULL || server_user == NULL || cmd == NULL)
	syslog_and_die("mising client/server/cmd");

    pwd = getpwnam (server_user);
    if (pwd == NULL)
	fatal (s, NULL, "Login incorrect.");

    if (*pwd->pw_shell == '\0')
	pwd->pw_shell = _PATH_BSHELL;

    if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0)
	fatal (s, NULL, "Login disabled.");


    ret = getnameinfo_verified (thataddr, thataddr_len,
				that_host, sizeof(that_host),
				NULL, 0, 0);
    if (ret)
	fatal (s, NULL, "getnameinfo: %s", gai_strerror(ret));

    if (login_access(pwd, that_host) == 0) {
	syslog(LOG_NOTICE, "Kerberos rsh denied to %s from %s",
	       server_user, that_host);
	fatal(s, NULL, "Permission denied.");
    }

#ifdef HAVE_GETSPNAM
    {
	struct spwd *sp;
	long    today;

	sp = getspnam(server_user);
	if (sp != NULL) {
	    today = time(0)/(24L * 60 * 60);
	    if (sp->sp_expire > 0)
		if (today > sp->sp_expire)
		    fatal(s, NULL, "Account has expired.");
	}
    }
#endif


#ifdef HAVE_SETLOGIN
    if (setlogin(pwd->pw_name) < 0)
	syslog(LOG_ERR, "setlogin() failed: %s", strerror(errno));
#endif

#ifdef HAVE_SETPCRED
    if (setpcred (pwd->pw_name, NULL) == -1)
	syslog(LOG_ERR, "setpcred() failure: %s", strerror(errno));
#endif /* HAVE_SETPCRED */

    /* Apply limits if not root */
    if(pwd->pw_uid != 0) {
	 const char *file = _PATH_LIMITS_CONF;
	 read_limits_conf(file, pwd);
    }

    if (initgroups (pwd->pw_name, pwd->pw_gid) < 0)
	fatal (s, "initgroups", "Login incorrect.");

    if (setgid(pwd->pw_gid) < 0)
	fatal (s, "setgid", "Login incorrect.");

    if (setuid (pwd->pw_uid) < 0)
	fatal (s, "setuid", "Login incorrect.");

    if (chdir (pwd->pw_dir) < 0)
	fatal (s, "chdir", "Remote directory.");

    if (errsock >= 0) {
	if (dup2 (errsock, STDERR_FILENO) < 0)
	    fatal (s, "dup2", "Cannot dup stderr.");
	close (errsock);
    } else {
	if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0)
	    fatal (s, "dup2", "Cannot dup stderr.");
    }

#ifdef KRB5
    {
	int fd;

	if (!do_unique_tkfile)
	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%lu",
		     (unsigned long)pwd->pw_uid);
	else if (*tkfile=='\0') {
	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX");
	    fd = mkstemp(tkfile+5);
	    close(fd);
	    unlink(tkfile+5);
	}

	if (kerberos_status)
	    krb5_start_session();
    }
#endif

    setup_environment (&env, pwd);

    if (do_encrypt) {
	setup_copier (errsock >= 0);
    } else {
	if (net_write (s, "", 1) != 1)
	    fatal (s, "net_write", "write failed");
    }

#if defined(KRB5)
    if(k_hasafs()) {
	char cell[64];

	if(do_newpag)
	    k_setpag();

	/* XXX */
       if (kerberos_status) {
	   krb5_ccache ccache;
	   krb5_error_code status;

	   status = krb5_cc_resolve (context, tkfile, &ccache);
	   if (!status) {
	       if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0)
		   krb5_afslog_uid_home(context, ccache, cell, NULL,
					pwd->pw_uid, pwd->pw_dir);
	       krb5_afslog_uid_home(context, ccache, NULL, NULL,
				    pwd->pw_uid, pwd->pw_dir);
	       krb5_cc_close (context, ccache);
	   }
       }
    }
#endif /* KRB5 */
    execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env);
    err(1, "exec %s", pwd->pw_shell);
}
示例#18
0
/*
 * Threaded process initialization.
 *
 * This is only called under two conditions:
 *
 *   1) Some thread routines have detected that the library hasn't yet
 *      been initialized (_thr_initial == NULL && curthread == NULL), or
 *
 *   2) An explicit call to reinitialize after a fork (indicated
 *      by curthread != NULL)
 */
void
_libpthread_init(struct pthread *curthread)
{
	int fd;

	/* Check if this function has already been called: */
	if ((_thr_initial != NULL) && (curthread == NULL))
		/* Only initialize the threaded application once. */
		return;

	/*
	 * Make gcc quiescent about {,libgcc_}references not being
	 * referenced:
	 */
	if ((references[0] == NULL) || (libgcc_references[0] == NULL))
		PANIC("Failed loading mandatory references in _thread_init");

	/* Pull debug symbols in for static binary */
	_thread_state_running = PS_RUNNING;

	/*
	 * Check the size of the jump table to make sure it is preset
	 * with the correct number of entries.
	 */
	if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
		PANIC("Thread jump table not properly initialized");
	memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));

	/*
	 * Check for the special case of this process running as
	 * or in place of init as pid = 1:
	 */
	if ((_thr_pid = getpid()) == 1) {
		/*
		 * Setup a new session for this process which is
		 * assumed to be running as root.
		 */
		if (setsid() == -1)
			PANIC("Can't set session ID");
		if (revoke(_PATH_CONSOLE) != 0)
			PANIC("Can't revoke console");
		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
			PANIC("Can't open console");
		if (setlogin("root") == -1)
			PANIC("Can't set login to root");
		if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
			PANIC("Can't set controlling terminal");
	}

	/* Initialize pthread private data. */
	init_private();
	_kse_init();

	/* Initialize the initial kse and kseg. */
	_kse_initial = _kse_alloc(NULL, _thread_scope_system > 0);
	if (_kse_initial == NULL)
		PANIC("Can't allocate initial kse.");
	_kse_initial->k_kseg = _kseg_alloc(NULL);
	if (_kse_initial->k_kseg == NULL)
		PANIC("Can't allocate initial kseg.");
	_kse_initial->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
	_kse_initial->k_schedq = &_kse_initial->k_kseg->kg_schedq;

	TAILQ_INSERT_TAIL(&_kse_initial->k_kseg->kg_kseq, _kse_initial, k_kgqe);
	_kse_initial->k_kseg->kg_ksecount = 1;

	/* Set the initial thread. */
	if (curthread == NULL) {
		/* Create and initialize the initial thread. */
		curthread = _thr_alloc(NULL);
		if (curthread == NULL)
			PANIC("Can't allocate initial thread");
		_thr_initial = curthread;
		init_main_thread(curthread);
	} else {
		/*
		 * The initial thread is the current thread.  It is
		 * assumed that the current thread is already initialized
		 * because it is left over from a fork().
		 */
		_thr_initial = curthread;
	}
	_kse_initial->k_kseg->kg_threadcount = 0;
	_thr_initial->kse = _kse_initial;
	_thr_initial->kseg = _kse_initial->k_kseg;
	_thr_initial->active = 1;

	/*
	 * Add the thread to the thread list and to the KSEG's thread
         * queue.
	 */
	THR_LIST_ADD(_thr_initial);
	KSEG_THRQ_ADD(_kse_initial->k_kseg, _thr_initial);

	/* Setup the KSE/thread specific data for the current KSE/thread. */
	_thr_initial->kse->k_curthread = _thr_initial;
	_kcb_set(_thr_initial->kse->k_kcb);
	_tcb_set(_thr_initial->kse->k_kcb, _thr_initial->tcb);
	_thr_initial->kse->k_flags |= KF_INITIALIZED;

	_thr_signal_init();
	_kse_critical_leave(&_thr_initial->tcb->tcb_tmbx);
	/*
	 * activate threaded mode as soon as possible if we are
	 * being debugged
	 */
	if (_libkse_debug)
		_kse_setthreaded(1);
}
示例#19
0
int
startClient( volatile int *pid )
{
	const char *home, *sessargs, *desksess;
	char **env, *xma;
	char **argv, *fname, *str;
#ifdef USE_PAM
	char ** volatile pam_env;
# ifndef HAVE_PAM_GETENVLIST
	char **saved_env;
# endif
	int pretc;
#else
# ifdef _AIX
	char *msg;
	char **theenv;
	extern char **newenv; /* from libs.a, this is set up by setpenv */
# endif
#endif
#ifdef HAVE_SETUSERCONTEXT
	extern char **environ;
#endif
	char *failsafeArgv[2];
	char *buf, *buf2;
	int i;

	if (strCmp( dmrcuser, curuser )) {
		if (curdmrc) { free( curdmrc ); curdmrc = 0; }
		if (dmrcuser) { free( dmrcuser ); dmrcuser = 0; }
	}

#if defined(USE_PAM) || defined(_AIX)
	if (!(p = getpwnam( curuser ))) {
		logError( "getpwnam(%s) failed.\n", curuser );
	  pError:
		displayStr( V_MSG_ERR, 0 );
		return 0;
	}
#endif

#ifndef USE_PAM
# ifdef _AIX
	msg = NULL;
	loginsuccess( curuser, hostname, tty, &msg );
	if (msg) {
		debug( "loginsuccess() - %s\n", msg );
		free( (void *)msg );
	}
# else /* _AIX */
#  if defined(KERBEROS) && defined(AFS)
	if (krbtkfile[0] != '\0') {
		if (k_hasafs()) {
			int fail = 0;
			if (k_setpag() == -1) {
				logError( "setpag() for %s failed\n", curuser );
				fail = 1;
			}
			if ((ret = k_afsklog( NULL, NULL )) != KSUCCESS) {
				logError( "AFS Warning: %s\n", krb_get_err_text( ret ) );
				fail = 1;
			}
			if (fail)
				displayMsg( V_MSG_ERR,
				            "Warning: Problems during Kerberos4/AFS setup." );
		}
	}
#  endif /* KERBEROS && AFS */
# endif /* _AIX */
#endif	/* !PAM */

	curuid = p->pw_uid;
	curgid = p->pw_gid;

	env = baseEnv( curuser );
	xma = 0;
	strApp( &xma, "method=", curtype, (char *)0 );
	if (td_setup)
		strApp( &xma, ",auto", (char *)0 );
	if (xma) {
		env = setEnv( env, "XDM_MANAGED", xma );
		free( xma );
	}
	if (td->autoLock && cursource == PWSRC_AUTOLOGIN)
		env = setEnv( env, "DESKTOP_LOCKED", "true" );
	env = setEnv( env, "PATH", curuid ? td->userPath : td->systemPath );
	env = setEnv( env, "SHELL", p->pw_shell );
	env = setEnv( env, "HOME", p->pw_dir );
#if !defined(USE_PAM) && !defined(_AIX) && defined(KERBEROS)
	if (krbtkfile[0] != '\0')
		env = setEnv( env, "KRBTKFILE", krbtkfile );
#endif
	userEnviron = inheritEnv( env, envvars );
	env = systemEnv( curuser );
	systemEnviron = setEnv( env, "HOME", p->pw_dir );
	debug( "user environment:\n%[|''>'\n's"
	       "system environment:\n%[|''>'\n's"
	       "end of environments\n",
	       userEnviron,
	       systemEnviron );

	/*
	 * for user-based authorization schemes,
	 * add the user to the server's allowed "hosts" list.
	 */
	for (i = 0; i < td->authNum; i++) {
#ifdef SECURE_RPC
		if (td->authorizations[i]->name_length == 9 &&
		    !memcmp( td->authorizations[i]->name, "SUN-DES-1", 9 ))
		{
			XHostAddress addr;
			char netname[MAXNETNAMELEN+1];
			char domainname[MAXNETNAMELEN+1];

			getdomainname( domainname, sizeof(domainname) );
			user2netname( netname, curuid, domainname );
			addr.family = FamilyNetname;
			addr.length = strlen( netname );
			addr.address = netname;
			XAddHost( dpy, &addr );
		}
#endif
#ifdef K5AUTH
		if (td->authorizations[i]->name_length == 14 &&
		    !memcmp( td->authorizations[i]->name, "MIT-KERBEROS-5", 14 ))
		{
			/* Update server's auth file with user-specific info.
			 * Don't need to AddHost because X server will do that
			 * automatically when it reads the cache we are about
			 * to point it at.
			 */
			XauDisposeAuth( td->authorizations[i] );
			td->authorizations[i] =
				krb5GetAuthFor( 14, "MIT-KERBEROS-5", td->name );
			saveServerAuthorizations( td, td->authorizations, td->authNum );
		}
#endif
	}

	if (*dmrcDir)
		mergeSessionArgs( TRUE );

	debug( "now starting the session\n" );

#ifdef USE_PAM

# ifdef HAVE_SETUSERCONTEXT
	if (setusercontext( lc, p, p->pw_uid, LOGIN_SETGROUP )) {
		logError( "setusercontext(groups) for %s failed: %m\n",
		          curuser );
		goto pError;
	}
# else
	if (!setGid( curuser, curgid ))
		goto pError;
# endif

# ifndef HAVE_PAM_GETENVLIST
	if (!(pam_env = initStrArr( 0 ))) {
		resetGids();
		goto pError;
	}
	saved_env = environ;
	environ = pam_env;
# endif
	removeCreds = 1; /* set it first - i don't trust PAM's rollback */
	pretc = pam_setcred( pamh, 0 );
	reInitErrorLog();
# ifndef HAVE_PAM_GETENVLIST
	pam_env = environ;
	environ = saved_env;
# endif
# ifdef HAVE_INITGROUPS
	/* This seems to be a strange place for it, but do it:
	   - after the initial groups are set
	   - after pam_setcred might have set something, even in the error case
	   - before pam_setcred(DELETE_CRED) might need it
	 */
	if (!saveGids())
		goto pError;
# endif
	if (pretc != PAM_SUCCESS) {
		logError( "pam_setcred() for %s failed: %s\n",
		          curuser, pam_strerror( pamh, pretc ) );
		resetGids();
		return 0;
	}

	removeSession = 1; /* set it first - same as above */
	pretc = pam_open_session( pamh, 0 );
	reInitErrorLog();
	if (pretc != PAM_SUCCESS) {
		logError( "pam_open_session() for %s failed: %s\n",
		          curuser, pam_strerror( pamh, pretc ) );
		resetGids();
		return 0;
	}

	/* we don't want sessreg and the startup/reset scripts run with user
	   credentials. unfortunately, we can reset only the gids. */
	resetGids();

# define D_LOGIN_SETGROUP LOGIN_SETGROUP
#else /* USE_PAM */
# define D_LOGIN_SETGROUP 0
#endif /* USE_PAM */

	removeAuth = 1;
	chownCtrl( &td->ctrl, curuid );
	endpwent();
#if !defined(USE_PAM) && defined(USESHADOW) && !defined(_AIX)
	endspent();
#endif
	ctltalk.pipe = &ctlpipe;
	ASPrintf( &buf, "sub-daemon for display %s", td->name );
	ASPrintf( &buf2, "client for display %s", td->name );
	switch (gFork( &ctlpipe, buf, buf2, 0, 0, mstrtalk.pipe, pid )) {
	case 0:

		gCloseOnExec( ctltalk.pipe );
		if (Setjmp( ctltalk.errjmp ))
			exit( 1 );

		gCloseOnExec( mstrtalk.pipe );
		if (Setjmp( mstrtalk.errjmp ))
			goto cError;

#ifndef NOXDMTITLE
		setproctitle( "%s'", td->name );
#endif
		strApp( &prog, " '", (char *)0 );
		reInitErrorLog();

		setsid();

		sessreg( td, getpid(), curuser, curuid );

		/* We do this here, as we want to have the session as parent. */
		switch (source( systemEnviron, td->startup, td_setup )) {
		case 0:
			break;
		case wcCompose( 0, 0, 127 ):
			goto cError;
		default: /* Explicit failure => message already displayed. */
			logError( "Startup script returned non-zero exit code\n" );
			exit( 1 );
		}

	/* Memory leaks are ok here as we exec() soon. */

#if defined(USE_PAM) || !defined(_AIX)

# ifdef USE_PAM
		/* pass in environment variables set by libpam and modules it called */
#  ifdef HAVE_PAM_GETENVLIST
		pam_env = pam_getenvlist( pamh );
		reInitErrorLog();
#  endif
		if (pam_env)
			for (; *pam_env; pam_env++)
				userEnviron = putEnv( *pam_env, userEnviron );
# endif

# ifdef HAVE_SETLOGIN
		if (setlogin( curuser ) < 0) {
			logError( "setlogin for %s failed: %m\n", curuser );
			goto cError;
		}
#  define D_LOGIN_SETLOGIN LOGIN_SETLOGIN
# else
#  define D_LOGIN_SETLOGIN 0
# endif

# if defined(USE_PAM) && defined(HAVE_INITGROUPS)
		if (!restoreGids())
			goto cError;
# endif

# ifndef HAVE_SETUSERCONTEXT

#  ifdef USE_PAM
		if (!setUid( curuser, curuid ))
			goto cError;
#  else
		if (!setUser( curuser, curuid, curgid ))
			goto cError;
#  endif

# else /* !HAVE_SETUSERCONTEXT */

		/*
		 * Destroy environment.
		 * We need to do this before setusercontext() because that may
		 * set or reset some environment variables.
		 */
		if (!(environ = initStrArr( 0 )))
			goto cError;

		/*
		 * Set the user's credentials: uid, gid, groups,
		 * environment variables, resource limits, and umask.
		 */
		if (setusercontext( lc, p, p->pw_uid,
		        LOGIN_SETALL & ~(D_LOGIN_SETGROUP|D_LOGIN_SETLOGIN) ) < 0)
		{
			logError( "setusercontext for %s failed: %m\n", curuser );
			goto cError;
		}

		for (i = 0; environ[i]; i++)
			userEnviron = putEnv( environ[i], userEnviron );

# endif /* !HAVE_SETUSERCONTEXT */

#else /* PAM || !_AIX */
		/*
		 * Set the user's credentials: uid, gid, groups,
		 * audit classes, user limits, and umask.
		 */
		if (setpcred( curuser, NULL ) == -1) {
			logError( "setpcred for %s failed: %m\n", curuser );
			goto cError;
		}

		/*
		 * Set the users process environment. Store protected variables and
		 * obtain updated user environment list. This call will initialize
		 * global 'newenv'.
		 */
		if (setpenv( curuser, PENV_INIT | PENV_ARGV | PENV_NOEXEC,
		             userEnviron, NULL ) != 0)
		{
			logError( "Cannot set %s's process environment\n", curuser );
			goto cError;
		}
		userEnviron = newenv;

#endif /* _AIX */

		/*
		 * for user-based authorization schemes,
		 * use the password to get the user's credentials.
		 */
#ifdef SECURE_RPC
		/* do like "keylogin" program */
		if (!curpass[0])
			logInfo( "No password for NIS provided.\n" );
		else {
			char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
			int nameret, keyret;
			int len;
			int key_set_ok = 0;
			struct key_netstarg netst;

			nameret = getnetname( netname );
			debug( "user netname: %s\n", netname );
			len = strlen( curpass );
			if (len > 8)
				bzero( curpass + 8, len - 8 );
			keyret = getsecretkey( netname, secretkey, curpass );
			debug( "getsecretkey returns %d, key length %d\n",
			       keyret, strlen( secretkey ) );
			netst.st_netname = netname;
			memcpy( netst.st_priv_key, secretkey, HEXKEYBYTES );
			memset( netst.st_pub_key, 0, HEXKEYBYTES );
			if (key_setnet( &netst ) < 0)
				debug( "Could not set secret key.\n" );
			/* is there a key, and do we have the right password? */
			if (keyret == 1) {
				if (*secretkey) {
					keyret = key_setsecret( secretkey );
					debug( "key_setsecret returns %d\n", keyret );
					if (keyret == -1)
						logError( "Failed to set NIS secret key\n" );
					else
						key_set_ok = 1;
				} else {
					/* found a key, but couldn't interpret it */
					logError( "Password incorrect for NIS principal %s\n",
					          nameret ? netname : curuser );
				}
			}
			if (!key_set_ok)
				nukeAuth( 9, "SUN-DES-1" );
			bzero( secretkey, strlen( secretkey ) );
		}
#endif
#ifdef K5AUTH
		/* do like "kinit" program */
		if (!curpass[0])
			logInfo( "No password for Kerberos5 provided.\n" );
		else
			if ((str = krb5Init( curuser, curpass, td->name )))
				userEnviron = setEnv( userEnviron, "KRB5CCNAME", str );
			else
				nukeAuth( 14, "MIT-KERBEROS-5" );
#endif /* K5AUTH */
		if (td->autoReLogin) {
			gSet( &mstrtalk );
			gSendInt( D_ReLogin );
			gSendStr( curuser );
			gSendStr( curpass );
			gSendStr( newdmrc );
		}
		if (curpass)
			bzero( curpass, strlen( curpass ) );
		setUserAuthorization( td );
		home = getEnv( userEnviron, "HOME" );
		if (home && chdir( home ) < 0) {
			logError( "Cannot chdir to %s's home %s: %m\n", curuser, home );
			sendStr( V_MSG_ERR, "Cannot enter home directory. Using /.\n" );
			chdir( "/" );
			userEnviron = setEnv( userEnviron, "HOME", "/" );
			home = 0;
		}
		if (home || td->clientLogFile[0] == '/') {
			if (!createClientLog( td->clientLogFile )) {
				logWarn( "Session log file according to %s cannot be created: %m\n",
				         td->clientLogFile );
				goto tmperr;
			}
		} else {
		  tmperr:
			if (!createClientLog( td->clientLogFallback ))
				logError( "Fallback session log file according to %s cannot be created: %m\n",
				          td->clientLogFallback );
			/* Could inform the user, but I guess this is only confusing. */
		}
		if (!*dmrcDir)
			mergeSessionArgs( home != 0 );
		if (!(desksess = iniEntry( curdmrc, "Desktop", "Session", 0 )))
			desksess = "failsafe"; /* only due to OOM */
		gSet( &mstrtalk );
		gSendInt( D_User );
		gSendInt( curuid );
		gSendStr( curuser );
		gSendStr( desksess );
		close( mstrtalk.pipe->fd.w );
		userEnviron = setEnv( userEnviron, "DESKTOP_SESSION", desksess );
		for (i = 0; td->sessionsDirs[i]; i++) {
			fname = 0;
			if (strApp( &fname, td->sessionsDirs[i], "/", desksess, ".desktop", (char *)0 )) {
				if ((str = iniLoad( fname ))) {
					if (!strCmp( iniEntry( str, "Desktop Entry", "Hidden", 0 ), "true" ) ||
					    !(sessargs = iniEntry( str, "Desktop Entry", "Exec", 0 )))
						sessargs = "";
					free( str );
					free( fname );
					goto gotit;
				}
				free( fname );
			}
		}
		if (!strcmp( desksess, "failsafe" ) ||
		    !strcmp( desksess, "default" ) ||
		    !strcmp( desksess, "custom" ))
			sessargs = desksess;
		else
			sessargs = "";
	  gotit:
		if (!(argv = parseArgs( (char **)0, td->session )) ||
		    !(argv = addStrArr( argv, sessargs, -1 )))
			exit( 1 );
		if (argv[0] && *argv[0]) {
			debug( "executing session %\"[s\n", argv );
			execute( argv, userEnviron );
			logError( "Session %\"s execution failed: %m\n", argv[0] );
		} else
			logError( "Session has no command/arguments\n" );
		failsafeArgv[0] = td->failsafeClient;
		failsafeArgv[1] = 0;
		execute( failsafeArgv, userEnviron );
		logError( "Failsafe client %\"s execution failed: %m\n",
		          failsafeArgv[0] );
	  cError:
		sendStr( V_MSG_ERR, 0 );
		exit( 1 );
	case -1:
		free( buf );
		return 0;
	}
	debug( "StartSession, fork succeeded %d\n", *pid );
	free( buf );

	gSet( &ctltalk );
	if (!Setjmp( ctltalk.errjmp ))
		while (gRecvCmd( &i )) {
			buf = gRecvStr();
			displayStr( i, buf );
			free( buf );
			gSet( &ctltalk );
			gSendInt( 0 );
		}
	gClosen( ctltalk.pipe );
	finishGreet();

	return 1;
}
示例#20
0
/*
 * Threaded process initialization.
 *
 * This is only called under two conditions:
 *
 *   1) Some thread routines have detected that the library hasn't yet
 *      been initialized (_thr_initial == NULL && curthread == NULL), or
 *
 *   2) An explicit call to reinitialize after a fork (indicated
 *      by curthread != NULL)
 */
void
_libpthread_init(struct pthread *curthread)
{
	int fd, first = 0;

	/* Check if this function has already been called: */
	if ((_thr_initial != NULL) && (curthread == NULL))
		/* Only initialize the threaded application once. */
		return;

	/*
	 * Check the size of the jump table to make sure it is preset
	 * with the correct number of entries.
	 */
	if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
		PANIC("Thread jump table not properly initialized");
	memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));

	/*
	 * Check for the special case of this process running as
	 * or in place of init as pid = 1:
	 */
	if ((_thr_pid = getpid()) == 1) {
		/*
		 * Setup a new session for this process which is
		 * assumed to be running as root.
		 */
		if (setsid() == -1)
			PANIC("Can't set session ID");
		if (revoke(_PATH_CONSOLE) != 0)
			PANIC("Can't revoke console");
		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
			PANIC("Can't open console");
		if (setlogin("root") == -1)
			PANIC("Can't set login to root");
		if (_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
			PANIC("Can't set controlling terminal");
	}

	/* Initialize pthread private data. */
	init_private();

	/* Set the initial thread. */
	if (curthread == NULL) {
		first = 1;
		/* Create and initialize the initial thread. */
		curthread = _thr_alloc(NULL);
		if (curthread == NULL)
			PANIC("Can't allocate initial thread");
		init_main_thread(curthread);
	}
	/*
	 * Add the thread to the thread list queue.
	 */
	THR_LIST_ADD(curthread);
	_thread_active_threads = 1;

	/* Setup the thread specific data */
	_tcb_set(curthread->tcb);

	if (first) {
		_thr_initial = curthread;
		_thr_signal_init();
		if (_thread_event_mask & TD_CREATE)
			_thr_report_creation(curthread, curthread);
	}
}
示例#21
0
bool XProcess::startXSession(){
  //Returns true if the session can continue, or false if it needs to be closed down
  qDebug() << "Starting X Session:" << xuser << xcmd << xhome << xde << VT;
  //Check that the necessary info to start the session is available
  if( xuser.isEmpty() || xcmd.isEmpty() || xhome.isEmpty() || xde.isEmpty() ){
    emit InvalidLogin();  //Make sure the GUI knows that it was a failure
    return true;
  }
  //Backend::log("Starting up Desktop environment ("+xcmd+") as user ("+xuser+")");

  //Check for PAM username/password validity
  if( !pam_checkPW() ){ emit InvalidLogin(); pam_shutdown(); return true; }

  //Make sure the user is added to any required groups
  QStringList cgroups = Backend::runShellCommand("id -nG "+xuser).join("").split(" "); //current groups
  if(!cgroups.contains("video")){ Backend::runShellCommand("pw group mod video -m "+xuser); } //add user to video group (required for GPU access)

  //If this has a special device password, mount the personacrypt device
  if( !xanonlogin && !xdevpass.isEmpty() ){ //&& Backend::getAvailablePersonaCryptUsers().contains(xuser) ){
    Backend::log(" - PersonaCrypt Login Detected");
    if( !Backend::MountPersonaCryptUser(xuser, xdevpass) ){
      //Could not mount the personacrypt device (invalid password?)
      xdevpass.clear(); //clear the invalid password
      emit InvalidLogin(); pam_shutdown(); return true;
    }else{
      //overwrite the password in memory, but leave it flagged (not empty)
      if(DEBUG){ qDebug() << "Mounted PersonaCrypt Device"; }
      xdevpass.clear();
      xdevpass = "******";
    }
  }

  //Save the current user/desktop as the last login
  Backend::saveLoginInfo(xuser, xhome, xde);

  // Get the users uid/gid information
  struct passwd *pw;
  int uid;
  char *ok;

  if (!(pw = getpwnam(xuser.toLatin1()))) {
      uid = strtol(xuser.toLatin1(), &ok, 10);
      if (!(pw = getpwuid(uid))) {
          return false;
      }
  }

  //Emit the last couple logs before dropping privileges
  Backend::log("Starting session:");
  Backend::log(" - Session Log: ~/.pcdm-startup.log");
  QProcess::execute("killall compton");
  //For sanity's sake, ensure that the ZFS mountpoint are all available first
  if(QFile::exists("/sbin/zfs")){
    QProcess::execute("zfs mount -a"); //just to ensure the user's home dir is actually mounted
  }
  //Check/create the user's home-dir before dropping privs
  if(!QFile::exists(xhome)){
    qDebug() << "No Home dir found - populating...";
    QString hmcmd = "pw usermod "+xuser+" -m";
    QProcess::execute(hmcmd);
  }
  //If this is an anonymous login, create the blank home-dir on top
  if(xanonlogin){
    if(DEBUG){ qDebug() << " - Stealth Session selected"; }
    QProcess::execute("personacrypt tempinit "+xuser+" 10G"); //always use 10GB blank dir
  }

  // Get the environment before we drop priv
  this->setProcessEnvironment( QProcessEnvironment::systemEnvironment() ); //current environment

  //Now allow this user access to the Xserver
  QString xhostcmd = "xhost si:localuser:"******"/tmp/pcdm-session."+VT+".XXXXXX");
  if ( ! tFile->open() )
     return false;

  QTextStream tOut(tFile);

  // Configure the DE startup command
  if(QFile::exists("/usr/local/bin/dbus-launch") && !xcmd.contains("lumina-desktop") ){
    cmd.append("dbus-launch --exit-with-session "+xcmd);
  }else{
    cmd.append(xcmd);
  }

  QString tUid, tGid, logFile;
  tUid.setNum(pw->pw_uid);
  tGid.setNum(pw->pw_gid);
  logFile=xhome + "/.pcdm-startup.log";

  // Locate the auth file
  QString authfile = qgetenv("XAUTHORITY");
  if ( authfile.isEmpty() )
    authfile = xhome + "/.Xauthority";

  //Need to run a couple commands in sequence: so put them in a script file
  tOut << "#!/bin/sh\n\n";

  QString PICOCLIENT = qgetenv("PICO_CLIENT_LOGIN");
  QString PICOHOME = qgetenv("PICO_CLIENT_HOME");
  if ( ! PICOCLIENT.isEmpty() && ! PICOHOME.isEmpty() ) {
    // Change ownership on the Xauthority file for PICO usage
    tOut << "rm "+authfile+"\n";
    tOut << "ln -fs "+PICOHOME+"/.Xauthority "+authfile+"\n";
    QString PICOPULSE = qgetenv("PICO_PULSE_COOKIE");
    // Check if PULSE is enabled
    if ( ! PICOPULSE.isEmpty() ) {
      tOut << "mkdir -p "+xhome+"/.config/pulse 2>/dev/null\n";
      tOut << "cp "+PICOPULSE+" "+xhome+"/.config/pulse/cookie\n";
      tOut << "chown "+tUid+":"+tGid+" " +xhome+"/.config/pulse/cookie\n";
    }
    QProcess::execute("chown "+tUid+" "+PICOHOME+"/.Xauthority"); // Change ownership on the pico login
  } else {
    // Change ownership on the Xauthority file
    QProcess::execute("chown "+tUid+":"+tGid+" "+authfile);
  }

  tOut << Backend::resetKbdCmd() + "\n"; //do this before sourcing .xprofile - in case there is a user-override set there
  tOut << "if [ -e '"+xhome+"/.xprofile' ] ; then\n";
  tOut << "  chmod 755 "+xhome+"/.xprofile\n";
  tOut << "  . "+xhome+"/.xprofile\n";
  tOut << "fi\n";
  tOut << cmd + "\n"; //+ " >" + xhome+ "/.pcdm-startup.log" + " 2>" + xhome + "/.pcdm-startup.log\n";
  tOut << "exit $?"; //Make sure we return the DE return value

  cmd = "/usr/local/share/PCDM/pcdm-session"; //+xuser+" "+tUid+" "+tGid+" "+tFile->fileName()+" "+logFile;
  QStringList cmdArgs; cmdArgs << xuser << tUid << tGid << tFile->fileName() << logFile;
  connect( this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotCleanup()) );
  tFile->setPermissions(QFile::ReadOwner | QFile::WriteOwner |QFile::ReadGroup | QFile::ReadUser | QFile::ReadOther);
  tFile->close();

  if(DEBUG){ Backend::log("Starting session with:\n" + cmd ); }
  this->start(cmd, cmdArgs);
  return true;
}
示例#22
0
void
doit(struct sockaddr *fromp)
{
	extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
	struct passwd *pwd;
	u_short port;
	fd_set ready, readfrom;
	int cc, fd, nfd, pv[2], pid, s;
	int one = 1;
	const char *cp, *errorstr;
	char sig, buf[BUFSIZ];
	char *cmdbuf, luser[16], ruser[16];
	char rhost[2 * MAXHOSTNAMELEN + 1];
	char numericname[INET6_ADDRSTRLEN];
	int af, srcport;
	int maxcmdlen;
#ifndef __APPLE__
	login_cap_t *lc;
#else
	struct hostent *hp;
	char *hostname, *errorhost = NULL;
#endif

	maxcmdlen = (int)sysconf(_SC_ARG_MAX);
	if (maxcmdlen <= 0 || (cmdbuf = malloc(maxcmdlen)) == NULL)
		exit(1);

#if defined(KERBEROS)
	AUTH_DAT	*kdata = (AUTH_DAT *) NULL;
	KTEXT		ticket = (KTEXT) NULL;
	char		instance[INST_SZ], version[VERSION_SIZE];
	struct		sockaddr_in	fromaddr;
	int		rc;
	long		authopts;
	int		pv1[2], pv2[2];
	fd_set		wready, writeto;

	fromaddr = *fromp;
#endif /* KERBEROS */

	(void) signal(SIGINT, SIG_DFL);
	(void) signal(SIGQUIT, SIG_DFL);
	(void) signal(SIGTERM, SIG_DFL);
	af = fromp->sa_family;
	srcport = ntohs(*((in_port_t *)&fromp->sa_data));
	if (af == AF_INET) {
		inet_ntop(af, &((struct sockaddr_in *)fromp)->sin_addr,
		    numericname, sizeof numericname);
	} else if (af == AF_INET6) {
		inet_ntop(af, &((struct sockaddr_in6 *)fromp)->sin6_addr,
		    numericname, sizeof numericname);
	} else {
		syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
		exit(1);
	}
#ifdef IP_OPTIONS
	if (af == AF_INET) {
		u_char optbuf[BUFSIZ/3];
		socklen_t optsize = sizeof(optbuf), ipproto, i;
		struct protoent *ip;

		if ((ip = getprotobyname("ip")) != NULL)
			ipproto = ip->p_proto;
		else
			ipproto = IPPROTO_IP;
		if (!getsockopt(0, ipproto, IP_OPTIONS, optbuf, &optsize) &&
		    optsize != 0) {
			for (i = 0; i < optsize; ) {
				u_char c = optbuf[i];
				if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
					syslog(LOG_NOTICE,
					    "connection refused from %s with IP option %s",
					    numericname,
					    c == IPOPT_LSRR ? "LSRR" : "SSRR");
					exit(1);
				}
				if (c == IPOPT_EOL)
					break;
				i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
			}
		}
	}
#endif

#if defined(KERBEROS)
	if (!use_kerberos)
#endif
	if (srcport >= IPPORT_RESERVED ||
	    srcport < IPPORT_RESERVED/2) {
		syslog(LOG_NOTICE|LOG_AUTH,
		    "connection from %s on illegal port %u",
		    numericname,
		    srcport);
		exit(1);
	}

	(void) alarm(60);
	port = 0;
	s = 0;		/* not set or used if port == 0 */
	for (;;) {
		char c;
		if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
			if (cc < 0)
				syslog(LOG_NOTICE, "read: %m");
			shutdown(0, SHUT_RDWR);
			exit(1);
		}
		if (c == 0)
			break;
		port = port * 10 + c - '0';
	}

	(void) alarm(0);
	if (port != 0) {
		int lport = IPPORT_RESERVED - 1;
		s = rresvport_af(&lport, af);
		if (s < 0) {
			syslog(LOG_ERR, "can't get stderr port: %m");
			exit(1);
		}
#if defined(KERBEROS)
		if (!use_kerberos)
#endif
		if (port >= IPPORT_RESERVED ||
		    port < IPPORT_RESERVED/2) {
			syslog(LOG_NOTICE|LOG_AUTH,
			    "2nd socket from %s on unreserved port %u",
			    numericname,
			    port);
			exit(1);
		}
		*((in_port_t *)&fromp->sa_data) = htons(port);
		if (connect(s, fromp, fromp->sa_len) < 0) {
			syslog(LOG_INFO, "connect second port %d: %m", port);
			exit(1);
		}
	}

#if defined(KERBEROS)
	if (vacuous) {
		error("rshd: remote host requires Kerberos authentication\n");
		exit(1);
	}
#endif

	errorstr = NULL;
#ifndef __APPLE__
	realhostname_sa(rhost, sizeof(rhost) - 1, fromp, fromp->sa_len);
	rhost[sizeof(rhost) - 1] = '\0';
	/* XXX truncation! */
#else
	errorstr = NULL;
	hp = gethostbyaddr((char *)&((struct sockaddr_in *)fromp)->sin_addr, sizeof (struct in_addr),
		((struct sockaddr_in *)fromp)->sin_family);
	if (hp) {
		/*
		 * If name returned by gethostbyaddr is in our domain,
		 * attempt to verify that we haven't been fooled by someone
		 * in a remote net; look up the name and check that this
		 * address corresponds to the name.
		 */
		hostname = hp->h_name;
#if defined(KERBEROS)
		if (!use_kerberos)
#endif
		if (check_all || local_domain(hp->h_name)) {
			strncpy(rhost, hp->h_name, sizeof(rhost) - 1);
			rhost[sizeof(rhost) - 1] = 0;
			errorhost = rhost;
			hp = gethostbyname(rhost);
			if (hp == NULL) {
				syslog(LOG_INFO,
				    "Couldn't look up address for %s",
				    rhost);
				errorstr =
				"Couldn't look up address for your host (%s)\n";
				hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr);
			} else for (; ; hp->h_addr_list++) {
				if (hp->h_addr_list[0] == NULL) {
					syslog(LOG_NOTICE,
					  "Host addr %s not listed for host %s",
					    inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr),
					    hp->h_name);
					errorstr =
					    "Host address mismatch for %s\n";
					hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr);
					break;
				}
				if (!bcmp(hp->h_addr_list[0],
				    (caddr_t)&((struct sockaddr_in *)fromp)->sin_addr,
				    sizeof(((struct sockaddr_in *)fromp)->sin_addr))) {
					hostname = hp->h_name;
					break;
				}
			}
		}
	} else
		errorhost = hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr);

#if defined(KERBEROS)
	if (use_kerberos) {
		kdata = (AUTH_DAT *) authbuf;
		ticket = (KTEXT) tickbuf;
		authopts = 0L;
		strcpy(instance, "*");
		version[VERSION_SIZE - 1] = '\0';
#if defined(CRYPT)
		if (doencrypt) {
			struct sockaddr_in local_addr;
			rc = sizeof(local_addr);
			if (getsockname(0, (struct sockaddr *)&local_addr,
			    &rc) < 0) {
				syslog(LOG_ERR, "getsockname: %m");
				error("rshd: getsockname: %m");
				exit(1);
			}
			authopts = KOPT_DO_MUTUAL;
			rc = krb_recvauth(authopts, 0, ticket,
				"rcmd", instance, &fromaddr,
				&local_addr, kdata, "", schedule,
				version);
			des_set_key(kdata->session, schedule);
		} else
#endif /* CRYPT */
			rc = krb_recvauth(authopts, 0, ticket, "rcmd",
				instance, &fromaddr,
				(struct sockaddr_in *) 0,
				kdata, "", (bit_64 *) 0, version);
		if (rc != KSUCCESS) {
			error("Kerberos authentication failure: %s\n",
				  krb_err_txt[rc]);
			exit(1);
		}
	} else
#endif /* KERBEROS */
#endif

	(void) alarm(60);
	getstr(ruser, sizeof(ruser), "ruser");
	getstr(luser, sizeof(luser), "luser");
	getstr(cmdbuf, maxcmdlen, "command");
	(void) alarm(0);
#if !TARGET_OS_EMBEDDED
	pam_err = pam_start("rshd", luser, &pamc, &pamh);
	if (pam_err != PAM_SUCCESS) {
		syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
		    pam_strerror(pamh, pam_err));
		rshd_errx(1, "Login incorrect.");
	}

	if ((pam_err = pam_set_item(pamh, PAM_RUSER, ruser)) != PAM_SUCCESS ||
	    (pam_err = pam_set_item(pamh, PAM_RHOST, rhost) != PAM_SUCCESS)) {
		syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
		    pam_strerror(pamh, pam_err));
		rshd_errx(1, "Login incorrect.");
	}

	pam_err = pam_authenticate(pamh, 0);
	if (pam_err == PAM_SUCCESS) {
		if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
			strncpy(luser, cp, sizeof(luser));
			luser[sizeof(luser) - 1] = '\0';
			/* XXX truncation! */
		}
		pam_err = pam_acct_mgmt(pamh, 0);
	}
	if (pam_err != PAM_SUCCESS) {
		syslog(LOG_INFO|LOG_AUTH,
		    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
		    ruser, rhost, luser, pam_strerror(pamh, pam_err), cmdbuf);
		rshd_errx(1, "Login incorrect.");
	}
#endif
	setpwent();
	pwd = getpwnam(luser);
	if (pwd == NULL) {
		syslog(LOG_INFO|LOG_AUTH,
		    "%s@%s as %s: unknown login. cmd='%.80s'",
		    ruser, rhost, luser, cmdbuf);
		if (errorstr == NULL)
			errorstr = "Login incorrect.";
		rshd_errx(1, errorstr, rhost);
	}

#ifndef __APPLE__
	lc = login_getpwclass(pwd);
	if (pwd->pw_uid)
		auth_checknologin(lc);
#endif

	if (chdir(pwd->pw_dir) < 0) {
		if (chdir("/") < 0 ||
#ifndef __APPLE__
		    login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
#else
			0) {
#endif /* __APPLE__ */
#ifdef notdef
			syslog(LOG_INFO|LOG_AUTH,
			"%s@%s as %s: no home directory. cmd='%.80s'",
			ruser, rhost, luser, cmdbuf);
			rshd_errx(0, "No remote home directory.");
#endif
		}
		pwd->pw_dir = slash;
	}

#if defined(KERBEROS)
	if (use_kerberos) {
		if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
			if (kuserok(kdata, luser) != 0) {
				syslog(LOG_INFO|LOG_AUTH,
				    "Kerberos rsh denied to %s.%s@%s",
				    kdata->pname, kdata->pinst, kdata->prealm);
				error("Permission denied.\n");
				exit(1);
			}
		}
	} else
#endif

#ifdef __APPLE__
		if (errorstr ||
		    (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
		    iruserok(((struct sockaddr_in *)fromp)->sin_addr.s_addr,
#if TARGET_OS_EMBEDDED
	// rdar://problem/5381734
		    0,
#else
		    pwd->pw_uid == 0,
#endif
		    ruser, luser) < 0)) {
			if (__rcmd_errstr)
			syslog(LOG_INFO|LOG_AUTH,
			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
			    ruser, rhost, luser, __rcmd_errstr,
				    cmdbuf);
			else
				syslog(LOG_INFO|LOG_AUTH,
			    "%s@%s as %s: permission denied. cmd='%.80s'",
				    ruser, rhost, luser, cmdbuf);
			if (errorstr == NULL)
				errorstr = "Permission denied.";
			rshd_errx(1, errorstr, errorhost);
		}

	if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
		rshd_errx(1, "Logins currently disabled.");
	}
#else
	if (lc != NULL && fromp->sa_family == AF_INET) {	/*XXX*/
		char	remote_ip[MAXHOSTNAMELEN];

		strncpy(remote_ip, numericname,
			sizeof(remote_ip) - 1);
		remote_ip[sizeof(remote_ip) - 1] = 0;
		/* XXX truncation! */
		if (!auth_hostok(lc, rhost, remote_ip)) {
			syslog(LOG_INFO|LOG_AUTH,
			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
			    ruser, rhost, luser, __rcmd_errstr,
			    cmdbuf);
			rshd_errx(1, "Login incorrect.");
		}
		if (!auth_timeok(lc, time(NULL)))
			rshd_errx(1, "Logins not available right now");
	}

	/*
	 * PAM modules might add supplementary groups in
	 * pam_setcred(), so initialize them first.
	 * But we need to open the session as root.
	 */
	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
		syslog(LOG_ERR, "setusercontext: %m");
		exit(1);
	}
#endif /* !__APPLE__ */

#if !TARGET_OS_EMBEDDED
	if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
		syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, pam_err));
	} else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
		syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
	}
#endif
	(void) write(STDERR_FILENO, "\0", 1);
	sent_null = 1;

	if (port) {
		if (pipe(pv) < 0)
			rshd_errx(1, "Can't make pipe.");
#if defined(KERBEROS) && defined(CRYPT)
		if (doencrypt) {
			if (pipe(pv1) < 0)
				rshd_errx(1, "Can't make 2nd pipe.");
			if (pipe(pv2) < 0)
				rshd_errx(1, "Can't make 3rd pipe.");
		}
#endif /* KERBEROS && CRYPT */
		pid = fork();
		if (pid == -1)
			rshd_errx(1, "Can't fork; try again.");
		if (pid) {
#if defined(KERBEROS) && defined(CRYPT)
			if (doencrypt) {
				static char msg[] = SECURE_MESSAGE;
				(void) close(pv1[1]);
				(void) close(pv2[1]);
				des_write(s, msg, sizeof(msg) - 1);

			} else
#endif /* KERBEROS && CRYPT */
			(void) close(0);
			(void) close(1);
			(void) close(2);
			(void) close(pv[1]);

			FD_ZERO(&readfrom);
			FD_SET(s, &readfrom);
			FD_SET(pv[0], &readfrom);
			if (pv[0] > s)
				nfd = pv[0];
			else
				nfd = s;
#if defined(KERBEROS) && defined(CRYPT)
			if (doencrypt) {
				FD_ZERO(&writeto);
				FD_SET(pv2[0], &writeto);
				FD_SET(pv1[0], &readfrom);

				nfd = MAX(nfd, pv2[0]);
				nfd = MAX(nfd, pv1[0]);
			} else
#endif /* KERBEROS && CRYPT */
				ioctl(pv[0], FIONBIO, (char *)&one);

			/* should set s nbio! */
			nfd++;
			do {
				ready = readfrom;
#if defined(KERBEROS) && defined(CRYPT)
				if (doencrypt) {
					wready = writeto;
					if (select(nfd, &ready,
					    &wready, (fd_set *) 0,
					    (struct timeval *) 0) < 0)
						break;
				} else
#endif /* KERBEROS && CRYPT */
				if (select(nfd, &ready, (fd_set *)0,
				  (fd_set *)0, (struct timeval *)0) < 0)
					break;
				if (FD_ISSET(s, &ready)) {
					int	ret;
#if defined(KERBEROS) && defined(CRYPT)
					if (doencrypt)
						ret = des_read(s, &sig, 1);
					else
#endif /* KERBEROS && CRYPT */
						ret = read(s, &sig, 1);
				if (ret <= 0)
					FD_CLR(s, &readfrom);
				else
					killpg(pid, sig);
				}
				if (FD_ISSET(pv[0], &ready)) {
					errno = 0;
					cc = read(pv[0], buf, sizeof(buf));
					if (cc <= 0) {
						shutdown(s, SHUT_RDWR);
						FD_CLR(pv[0], &readfrom);
					} else {
#if defined(KERBEROS) && defined(CRYPT)
						if (doencrypt)
							(void)
							  des_write(s, buf, cc);
						else
#endif /* KERBEROS && CRYPT */
						(void)write(s, buf, cc);
					}
				}
#if defined(KERBEROS) && defined(CRYPT)
				if (doencrypt && FD_ISSET(pv1[0], &ready)) {
					errno = 0;
					cc = read(pv1[0], buf, sizeof(buf));
					if (cc <= 0) {
						shutdown(pv1[0], 1+1);
						FD_CLR(pv1[0], &readfrom);
					} else
						(void) des_write(STDOUT_FILENO,
						    buf, cc);
				}

				if (doencrypt && FD_ISSET(pv2[0], &wready)) {
					errno = 0;
					cc = des_read(STDIN_FILENO,
					    buf, sizeof(buf));
					if (cc <= 0) {
						shutdown(pv2[0], 1+1);
						FD_CLR(pv2[0], &writeto);
					} else
						(void) write(pv2[0], buf, cc);
				}
#endif /* KERBEROS && CRYPT */

			} while (FD_ISSET(s, &readfrom) ||
#if defined(KERBEROS) && defined(CRYPT)
			    (doencrypt && FD_ISSET(pv1[0], &readfrom)) ||
#endif /* KERBEROS && CRYPT */
			    FD_ISSET(pv[0], &readfrom));
#if !TARGET_OS_EMBEDDED
			PAM_END;
#endif
			exit(0);
		}
#ifdef __APPLE__
		// rdar://problem/4485794
		setpgid(0, getpid());
#endif
		(void) close(s);
		(void) close(pv[0]);
#if defined(KERBEROS) && defined(CRYPT)
		if (doencrypt) {
			close(pv1[0]); close(pv2[0]);
			dup2(pv1[1], 1);
			dup2(pv2[1], 0);
			close(pv1[1]);
			close(pv2[1]);
		}
#endif /* KERBEROS && CRYPT */
		dup2(pv[1], 2);
		close(pv[1]);
	}
#ifndef __APPLE__
	else {
		pid = fork();
		if (pid == -1)
			rshd_errx(1, "Can't fork; try again.");
		if (pid) {
			/* Parent. */
			while (wait(NULL) > 0 || errno == EINTR)
				/* nothing */ ;
			PAM_END;
			exit(0);
		}
	}
#endif

	for (fd = getdtablesize(); fd > 2; fd--) {
#ifdef __APPLE__
		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
#else
		(void) close(fd);
#endif
	}
	if (setsid() == -1)
		syslog(LOG_ERR, "setsid() failed: %m");
	if (setlogin(pwd->pw_name) < 0)
		syslog(LOG_ERR, "setlogin() failed: %m");

	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = bshell;
#ifdef __APPLE__
	(void) setgid((gid_t)pwd->pw_gid);
	initgroups(pwd->pw_name, pwd->pw_gid);
	(void) setuid((uid_t)pwd->pw_uid);

	environ = envinit;
	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
	strcat(path, _PATH_DEFPATH);
	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
	strncat(username, pwd->pw_name, sizeof(username)-6);
#endif
#if !TARGET_OS_EMBEDDED
	(void) pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
	(void) pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
	(void) pam_setenv(pamh, "USER", pwd->pw_name, 1);
	(void) pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
	environ = pam_getenvlist(pamh);
	(void) pam_end(pamh, pam_err);
#endif
	cp = strrchr(pwd->pw_shell, '/');
	if (cp)
		cp++;
	else
		cp = pwd->pw_shell;

#ifndef __APPLE__
	if (setusercontext(lc, pwd, pwd->pw_uid,
		LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
		syslog(LOG_ERR, "setusercontext(): %m");
		exit(1);
	}
	login_close(lc);
#endif
	endpwent();
	if (log_success || pwd->pw_uid == 0) {
#if defined(KERBEROS)
		if (use_kerberos)
		    syslog(LOG_INFO|LOG_AUTH,
			"Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
			kdata->pname, kdata->pinst, kdata->prealm,
			hostname, luser, cmdbuf);
		else
#endif /* KERBEROS */
		    syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
			ruser, rhost, luser, cmdbuf);
	}
	execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL);
	err(1, "%s", pwd->pw_shell);
	exit(1);
}
示例#23
0
/*
 * Threaded process initialization.
 *
 * This is only called under two conditions:
 *
 *   1) Some thread routines have detected that the library hasn't yet
 *      been initialized (_thr_initial == NULL && curthread == NULL), or
 *
 *   2) An explicit call to reinitialize after a fork (indicated
 *      by curthread != NULL)
 */
void
_libpthread_init(struct pthread *curthread)
{
	int fd, first = 0;
	sigset_t sigset, oldset;

	/* Check if this function has already been called: */
	if ((_thr_initial != NULL) && (curthread == NULL))
		/* Only initialize the threaded application once. */
		return;

	/*
	 * Check for the special case of this process running as
	 * or in place of init as pid = 1:
	 */
	if ((_thr_pid = getpid()) == 1) {
		/*
		 * Setup a new session for this process which is
		 * assumed to be running as root.
		 */
		if (setsid() == -1)
			PANIC("Can't set session ID");
		if (revoke(_PATH_CONSOLE) != 0)
			PANIC("Can't revoke console");
		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
			PANIC("Can't open console");
		if (setlogin("root") == -1)
			PANIC("Can't set login to root");
		if (__sys_ioctl(fd, TIOCSCTTY, NULL) == -1)
			PANIC("Can't set controlling terminal");
	}

	/* Initialize pthread private data. */
	init_private();

	/* Set the initial thread. */
	if (curthread == NULL) {
		first = 1;
		/* Create and initialize the initial thread. */
		curthread = _thr_alloc(NULL);
		if (curthread == NULL)
			PANIC("Can't allocate initial thread");
		init_main_thread(curthread);
	}
	/*
	 * Add the thread to the thread list queue.
	 */
	THR_LIST_ADD(curthread);
	_thread_active_threads = 1;

	/* Setup the thread specific data */
	tls_set_tcb(curthread->tcb);

	if (first) {
		SIGFILLSET(sigset);
		__sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
		_thr_signal_init();
		_thr_initial = curthread;
		SIGDELSET(oldset, SIGCANCEL);
		__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
		if (td_eventismember(&_thread_event_mask, TD_CREATE))
			_thr_report_creation(curthread, curthread);
	}
}
示例#24
0
int
setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
{
    quad_t	p;
    mode_t	mymask;
    login_cap_t *llc = NULL;
    struct sigaction sa, prevsa;
    struct rtprio rtp;
    int error;

    if (lc == NULL) {
	if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
	    llc = lc; /* free this when we're done */
    }

    if (flags & LOGIN_SETPATH)
	pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;

    /* we need a passwd entry to set these */
    if (pwd == NULL)
	flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN | LOGIN_SETMAC);

    /* Set the process priority */
    if (flags & LOGIN_SETPRIORITY) {
	p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);

	if (p > PRIO_MAX) {
	    rtp.type = RTP_PRIO_IDLE;
	    rtp.prio = p - PRIO_MAX - 1;
	    p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p;
	    if (rtprio(RTP_SET, 0, &rtp))
		syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	} else if (p < PRIO_MIN) {
	    rtp.type = RTP_PRIO_REALTIME;
	    rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX);
	    p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p;
	    if (rtprio(RTP_SET, 0, &rtp))
		syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	} else {
	    if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
		syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	}
    }

    /* Setup the user's group permissions */
    if (flags & LOGIN_SETGROUP) {
	if (setgid(pwd->pw_gid) != 0) {
	    syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid);
	    login_close(llc);
	    return (-1);
	}
	if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
	    syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name,
		   (u_long)pwd->pw_gid);
	    login_close(llc);
	    return (-1);
	}
    }

    /* Set up the user's MAC label. */
    if ((flags & LOGIN_SETMAC) && mac_is_present(NULL) == 1) {
	const char *label_string;
	mac_t label;

	label_string = login_getcapstr(lc, "label", NULL, NULL);
	if (label_string != NULL) {
	    if (mac_from_text(&label, label_string) == -1) {
		syslog(LOG_ERR, "mac_from_text('%s') for %s: %m",
		    pwd->pw_name, label_string);
		return (-1);
	    }
	    if (mac_set_proc(label) == -1)
		error = errno;
	    else
		error = 0;
	    mac_free(label);
	    if (error != 0) {
		syslog(LOG_ERR, "mac_set_proc('%s') for %s: %s",
		    label_string, pwd->pw_name, strerror(error));
		return (-1);
	    }
	}
    }

    /* Set the sessions login */
    if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
	syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name);
	login_close(llc);
	return (-1);
    }

    /* Inform the kernel about current login class */
    if (lc != NULL && lc->lc_class != NULL && (flags & LOGIN_SETLOGINCLASS)) {
	/*
	 * XXX: This is a workaround to fail gracefully in case the kernel
	 *      does not support setloginclass(2).
	 */
	bzero(&sa, sizeof(sa));
	sa.sa_handler = SIG_IGN;
	sigfillset(&sa.sa_mask);
	sigaction(SIGSYS, &sa, &prevsa);
	error = setloginclass(lc->lc_class);
	sigaction(SIGSYS, &prevsa, NULL);
	if (error != 0) {
	    syslog(LOG_ERR, "setloginclass(%s): %m", lc->lc_class);
#ifdef notyet
	    login_close(llc);
	    return (-1);
#endif
	}
    }

    mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
    mymask = setlogincontext(lc, pwd, mymask, flags);
    login_close(llc);

    /* This needs to be done after anything that needs root privs */
    if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
	syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid);
	return (-1);	/* Paranoia again */
    }

    /*
     * Now, we repeat some of the above for the user's private entries
     */
    if (getuid() == uid && (lc = login_getuserclass(pwd)) != NULL) {
	mymask = setlogincontext(lc, pwd, mymask, flags);
	login_close(lc);
    }

    /* Finally, set any umask we've found */
    if (flags & LOGIN_SETUMASK)
	umask(mymask);

    return (0);
}
示例#25
0
int
setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
{
    quad_t	p;
    mode_t	mymask;
    login_cap_t *llc = NULL;
    struct rtprio rtp;

    if (lc == NULL) {
	if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
	    llc = lc; /* free this when we're done */
    }

    if (flags & LOGIN_SETPATH)
	pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;

    /* we need a passwd entry to set these */
    if (pwd == NULL)
	flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN);

    /* Set the process priority */
    if (flags & LOGIN_SETPRIORITY) {
	p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);

	if (p > PRIO_MAX) {
	    rtp.type = RTP_PRIO_IDLE;
	    rtp.prio = p - PRIO_MAX - 1;
	    p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p;
	    if (rtprio(RTP_SET, 0, &rtp))
		syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	} else if (p < PRIO_MIN) {
	    rtp.type = RTP_PRIO_REALTIME;
	    rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX);
	    p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p;
	    if (rtprio(RTP_SET, 0, &rtp))
		syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	} else {
	    if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
		syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
		    pwd ? pwd->pw_name : "-",
		    lc ? lc->lc_class : LOGIN_DEFCLASS);
	}
    }

    /* Setup the user's group permissions */
    if (flags & LOGIN_SETGROUP) {
	if (setgid(pwd->pw_gid) != 0) {
	    syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid);
	    login_close(llc);
	    return (-1);
	}
	if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
	    syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name,
		   (u_long)pwd->pw_gid);
	    login_close(llc);
	    return (-1);
	}
    }

    /* Set the sessions login */
    if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
	syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name);
	login_close(llc);
	return (-1);
    }

    mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
    mymask = setlogincontext(lc, pwd, mymask, flags);
    login_close(llc);

    /* This needs to be done after anything that needs root privs */
    if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
	syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid);
	return (-1);	/* Paranoia again */
    }

    /*
     * Now, we repeat some of the above for the user's private entries
     */
    if (getuid() == uid && (lc = login_getuserclass(pwd)) != NULL) {
	mymask = setlogincontext(lc, pwd, mymask, flags);
	login_close(lc);
    }

    /* Finally, set any umask we've found */
    if (flags & LOGIN_SETUMASK)
	umask(mymask);

    return (0);
}
示例#26
0
文件: init.c 项目: ngkaho1234/freebsd
/*
 * The mother of all processes.
 */
int
main(int argc, char *argv[])
{
	state_t initial_transition = runcom;
	char kenv_value[PATH_MAX];
	int c;
	struct sigaction sa;
	sigset_t mask;

	/* Dispose of random users. */
	if (getuid() != 0)
		errx(1, "%s", strerror(EPERM));

	/* System V users like to reexec init. */
	if (getpid() != 1) {
#ifdef COMPAT_SYSV_INIT
		/* So give them what they want */
		if (argc > 1) {
			if (strlen(argv[1]) == 1) {
				char runlevel = *argv[1];
				int sig;

				switch (runlevel) {
				case '0': /* halt + poweroff */
					sig = SIGUSR2;
					break;
				case '1': /* single-user */
					sig = SIGTERM;
					break;
				case '6': /* reboot */
					sig = SIGINT;
					break;
				case 'c': /* block further logins */
					sig = SIGTSTP;
					break;
				case 'q': /* rescan /etc/ttys */
					sig = SIGHUP;
					break;
				default:
					goto invalid;
				}
				kill(1, sig);
				_exit(0);
			} else
invalid:
				errx(1, "invalid run-level ``%s''", argv[1]);
		} else
#endif
			errx(1, "already running");
	}
	/*
	 * Note that this does NOT open a file...
	 * Does 'init' deserve its own facility number?
	 */
	openlog("init", LOG_CONS, LOG_AUTH);

	/*
	 * Create an initial session.
	 */
	if (setsid() < 0)
		warning("initial setsid() failed: %m");

	/*
	 * Establish an initial user so that programs running
	 * single user do not freak out and die (like passwd).
	 */
	if (setlogin("root") < 0)
		warning("setlogin() failed: %m");

	/*
	 * This code assumes that we always get arguments through flags,
	 * never through bits set in some random machine register.
	 */
	while ((c = getopt(argc, argv, "dsf")) != -1)
		switch (c) {
		case 'd':
			devfs = 1;
			break;
		case 's':
			initial_transition = single_user;
			break;
		case 'f':
			runcom_mode = FASTBOOT;
			break;
		default:
			warning("unrecognized flag '-%c'", c);
			break;
		}

	if (optind != argc)
		warning("ignoring excess arguments");

	/*
	 * We catch or block signals rather than ignore them,
	 * so that they get reset on exec.
	 */
	handle(badsys, SIGSYS, 0);
	handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU,
	    SIGXFSZ, 0);
	handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGUSR1,
	    SIGUSR2, 0);
	handle(alrm_handler, SIGALRM, 0);
	sigfillset(&mask);
	delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
	    SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM,
	    SIGUSR1, SIGUSR2, 0);
	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sa.sa_handler = SIG_IGN;
	sigaction(SIGTTIN, &sa, (struct sigaction *)0);
	sigaction(SIGTTOU, &sa, (struct sigaction *)0);

	/*
	 * Paranoia.
	 */
	close(0);
	close(1);
	close(2);

	if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) {
		state_func_t next_transition;

		if ((next_transition = run_script(kenv_value)) != 0)
			initial_transition = (state_t) next_transition;
	}

	if (kenv(KENV_GET, "init_chroot", kenv_value, sizeof(kenv_value)) > 0) {
		if (chdir(kenv_value) != 0 || chroot(".") != 0)
			warning("Can't chroot to %s: %m", kenv_value);
	}

	/*
	 * Additional check if devfs needs to be mounted:
	 * If "/" and "/dev" have the same device number,
	 * then it hasn't been mounted yet.
	 */
	if (!devfs) {
		struct stat stst;
		dev_t root_devno;

		stat("/", &stst);
		root_devno = stst.st_dev;
		if (stat("/dev", &stst) != 0)
			warning("Can't stat /dev: %m");
		else if (stst.st_dev == root_devno)
			devfs++;
	}

	if (devfs) {
		struct iovec iov[4];
		char *s;
		int i;

		char _fstype[]	= "fstype";
		char _devfs[]	= "devfs";
		char _fspath[]	= "fspath";
		char _path_dev[]= _PATH_DEV;

		iov[0].iov_base = _fstype;
		iov[0].iov_len = sizeof(_fstype);
		iov[1].iov_base = _devfs;
		iov[1].iov_len = sizeof(_devfs);
		iov[2].iov_base = _fspath;
		iov[2].iov_len = sizeof(_fspath);
		/*
		 * Try to avoid the trailing slash in _PATH_DEV.
		 * Be *very* defensive.
		 */
		s = strdup(_PATH_DEV);
		if (s != NULL) {
			i = strlen(s);
			if (i > 0 && s[i - 1] == '/')
				s[i - 1] = '\0';
			iov[3].iov_base = s;
			iov[3].iov_len = strlen(s) + 1;
		} else {
			iov[3].iov_base = _path_dev;
			iov[3].iov_len = sizeof(_path_dev);
		}
		nmount(iov, 4, 0);
		if (s != NULL)
			free(s);
	}

	/*
	 * Start the state machine.
	 */
	transition(initial_transition);

	/*
	 * Should never reach here.
	 */
	return 1;
}
示例#27
0
bool XProcess::startXSession(){
  //Returns true if the session can continue, or false if it needs to be closed down

  //Check that the necessary info to start the session is available
  if( xuser.isEmpty() || xcmd.isEmpty() || xhome.isEmpty() || xde.isEmpty() ){
    emit InvalidLogin();  //Make sure the GUI knows that it was a failure
    return true;
  }
  //Backend::log("Starting up Desktop environment ("+xcmd+") as user ("+xuser+")");
  
  //Check for PAM username/password validity
  if( !pam_checkPW() ){ emit InvalidLogin(); pam_shutdown(); return true; }

  //If this has a special device password, mount the personacrypt device
  if( !xanonlogin && !xdevpass.isEmpty() && Backend::getAvailablePersonaCryptUsers().contains(xuser) ){
    if( !Backend::MountPersonaCryptUser(xuser, xdevpass) ){ 
      //Could not mount the personacrypt device (invalid password?)
      xdevpass.clear(); //clear the invalid password
      emit InvalidLogin(); pam_shutdown(); return true; 
    }else{
      //overwrite the password in memory, but leave it flagged (not empty)
      if(DEBUG){ qDebug() << "Mounted PersonaCrypt Device"; }
      xdevpass.clear();
      xdevpass = "******"; 
    }
  }

  //Save the current user/desktop as the last login
  Backend::saveLoginInfo(xuser,xde);

  // Get the users uid/gid information
  struct passwd *pw;
  int uid;
  char *ok;

  if (!(pw = getpwnam(xuser.toLatin1()))) {
      uid = strtol(xuser.toLatin1(), &ok, 10);
      if (!(pw = getpwuid(uid))) {
          return false;
      }
  }

  //Emit the last couple logs before dropping privileges
  Backend::log("Starting session:");
  Backend::log(" - Session Log: ~/.pcdm-startup.log");
  //For sanity's sake, ensure that the ZFS mountpoint are all available first
  if(QFile::exists("/sbin/zfs")){
    QProcess::execute("zfs mount -a"); //just to ensure the user's home dir is actually mounted
  }
  //Check/create the user's home-dir before dropping privs
  if(!QFile::exists(xhome)){
    qDebug() << "No Home dir found - populating...";
    QString hmcmd = "pw usermod "+xuser+" -m";
    QProcess::execute(hmcmd);
  }
  //If this is an anonymous login, create the blank home-dir on top
  if(xanonlogin){
    if(DEBUG){ qDebug() << " - Stealth Session selected"; }
    QProcess::execute("personacrypt tempinit "+xuser+" 10G"); //always use 10GB blank dir
  }
  
  // Get the environment before we drop priv
  this->setProcessEnvironment( QProcessEnvironment::systemEnvironment() ); //current environment

  //Now allow this user access to the Xserver
  QString xhostcmd = "xhost si:localuser:"******"/usr/local/bin/dbus-launch")){
    cmd.append("dbus-launch --exit-with-session "+xcmd);
  }
  //Need to run a couple commands in sequence: so put them in a script file
  tOut << "#!/bin/sh\n\n";
  tOut << "if [ -e '"+xhome+"/.xprofile' ] ; then\n";
  tOut << "  chmod 755 "+xhome+"/.xprofile\n";
  tOut << "  . "+xhome+"/.xprofile\n";
  tOut << "fi\n";
  tOut << cmd + "\n"; //+ " >" + xhome+ "/.pcdm-startup.log" + " 2>" + xhome + "/.pcdm-startup.log\n";
  tOut << "exit $?"; //Make sure we return the DE return value

  QString tUid, tGid, logFile;
  tUid.setNum(pw->pw_uid);
  tGid.setNum(pw->pw_gid);
  logFile=xhome + "/.pcdm-startup.log";
  cmd = "/usr/local/share/PCDM/pcdm-session "+xuser+" "+tUid+" "+tGid+" "+tFile->fileName()+" "+logFile;
  connect( this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotCleanup()) );
  tFile->setPermissions(QFile::ReadOwner | QFile::WriteOwner |QFile::ReadGroup | QFile::ReadUser | QFile::ReadOther);
  tFile->close();

  if(DEBUG){ Backend::log("Starting session with:\n" + cmd ); }
  this->start(cmd);
  return true;
}