Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9bb938de93248ca5cc71ecf424cefd6c > files > 26

kdebase-3.5.4-21.el5_5.1.src.rpm

--- kdebase-3.5.4/kdm/backend/client.c	2006/06/14 18:24:42	551490
+++ kdebase-3.5.4/kdm/backend/client.c	2008/01/31 21:50:25	769223
@@ -51,7 +51,6 @@
 #endif
 #ifdef HAVE_SETUSERCONTEXT
 # include <login_cap.h>
-# define USE_LOGIN_CAP 1
 #endif
 #ifdef USE_PAM
 # ifdef HAVE_PAM_PAM_APPL_H
@@ -66,9 +65,6 @@
 extern int loginfailed( const char *User, const char *Host, const char *Tty );
 extern int loginsuccess( const char *User, const char *Host, const char *Tty, char **Msg );
 #else /* USE_PAM || _AIX */
-# ifdef USESHADOW
-#  include <shadow.h>
-# endif
 # ifdef KERBEROS
 #  include <sys/param.h>
 #  include <krb.h>
@@ -82,6 +78,10 @@
 /* for expiration */
 # include <time.h>
 #endif /* USE_PAM || _AIX */
+#ifdef HAVE_SHADOW
+# include <shadow.h>
+#endif
+#include <signal.h>
 
 /*
  * Session data, mostly what struct verify_info was for
@@ -101,6 +101,13 @@
 char *newdmrc;
 
 static struct passwd *p;
+#ifdef HAVE_SETUSERCONTEXT
+# ifdef HAVE_LOGIN_GETCLASS
+login_cap_t *lc;
+# else
+struct login_cap *lc;
+# endif
+#endif
 #ifdef USE_PAM
 static pam_handle_t *pamh;
 #elif defined(_AIX)
@@ -310,6 +317,10 @@
 		if (pretc != PAM_SUCCESS)
 			goto pam_bail;
 	}
+# ifdef __sun__ /* Only Solaris <= 9, but checking it does not seem worth it. */
+	else if (pam_set_item( pamh, PAM_RHOST, 0 ) != PAM_SUCCESS)
+		goto pam_bail;
+# endif
 # ifdef PAM_FAIL_DELAY
 	pam_set_item( pamh, PAM_FAIL_DELAY, (void *)fail_delay );
 # endif
@@ -358,6 +369,9 @@
 AccNoPass( const char *un )
 {
 	struct passwd *pw = 0;
+# ifdef HAVE_SHADOW /* (sic!) - not USESHADOW */
+	struct spwd *spw;
+# endif
 #else
 AccNoPass( const char *un, struct passwd *pw )
 {
@@ -381,6 +395,13 @@
 #if defined(USE_PAM) || defined(_AIX)
 			if (!(pw = getpwnam( un )))
 				return 0;
+			if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
+				continue;
+# ifdef HAVE_SHADOW /* (sic!) - not USESHADOW */
+			if ((spw = getspnam( un )) &&
+			    (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*'))
+					continue;
+# endif
 #endif
 			if (pw->pw_uid)
 				return 1;
@@ -410,7 +431,7 @@
 	return 0;
 }
 
-#if !defined(USE_PAM) && !defined(_AIX) && defined(USE_LOGIN_CAP)
+#if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT)
 # define LC_RET0 do { login_close(lc); return 0; } while(0)
 #else
 # define LC_RET0 return 0
@@ -438,13 +459,6 @@
 # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
 	int tim, expir, warntime, quietlog;
 # endif
-# ifdef USE_LOGIN_CAP
-#  ifdef HAVE_LOGIN_GETCLASS
-	login_cap_t *lc;
-#  else
-	struct login_cap *lc;
-#  endif
-# endif
 #endif
 
 	Debug( "Verify ...\n" );
@@ -583,25 +597,31 @@
 
 	if (!(p = getpwnam( curuser ))) {
 		Debug( "getpwnam() failed.\n" );
+		gconv( GCONV_PASS, 0 );
 		V_RET_AUTH;
 	}
-# ifdef __linux__ /* only Linux? */
 	if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') {
 		Debug( "account is locked\n" );
+		gconv( GCONV_PASS, 0 );
 		V_RET_AUTH;
 	}
-# endif
 
 # ifdef USESHADOW
-	if ((sp = getspnam( curuser )))
+	if ((sp = getspnam( curuser ))) {
 		p->pw_passwd = sp->sp_pwdp;
-	else
+		if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') {
+			Debug( "account is locked\n" );
+			gconv( GCONV_PASS, 0 );
+			V_RET_AUTH;
+		}
+	} else
 		Debug( "getspnam() failed: %m. Are you root?\n" );
 # endif
 
 	if (!*p->pw_passwd) {
 		if (!td->allowNullPasswd) {
 			Debug( "denying user with empty password\n" );
+			gconv( GCONV_PASS, 0 );
 			V_RET_AUTH;
 		}
 		goto nplogin;
@@ -744,23 +764,11 @@
 	if (msg)
 		free( (void *)msg );
 
-#else /* USE_PAM || _AIX */
+#endif /* USE_PAM || _AIX */
 
-# ifdef HAVE_GETUSERSHELL
-	for (;;) {
-		if (!(s = getusershell())) {
-			Debug( "shell not in /etc/shells\n" );
-			endusershell();
-			V_RET_FAIL( "Your login shell is not listed in /etc/shells" );
-		}
-		if (!strcmp( s, p->pw_shell )) {
-			endusershell();
-			break;
-		}
-	}
-# endif
+#ifndef _AIX
 
-# ifdef USE_LOGIN_CAP
+# ifdef HAVE_SETUSERCONTEXT
 #  ifdef HAVE_LOGIN_GETCLASS
 	lc = login_getclass( p->pw_class );
 #  else
@@ -768,106 +776,45 @@
 #  endif
 	if (!lc)
 		V_RET_FAIL( 0 );
-# endif
-
 
-/* restrict_nologin */
-# ifndef _PATH_NOLOGIN
-#  define _PATH_NOLOGIN "/etc/nologin"
+	p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell );
 # endif
 
-	if ((
-# ifdef USE_LOGIN_CAP
-	     /* Do we ignore a nologin file? */
-	     !login_getcapbool( lc, "ignorenologin", 0 )) &&
-	    (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) ||
-# endif
-		 !stat( (nolg = _PATH_NOLOGIN), &st )))
-	{
-		PrepErrorGreet();
-		GSendInt( V_MSG_ERR );
-		if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) {
-			if ((buf = Malloc( st.st_size + 1 ))) {
-				if (read( fd, buf, st.st_size ) == st.st_size) {
-					buf[st.st_size] = 0;
-					GSendStr( buf );
-					free( buf );
-					close( fd );
-					GSendInt( V_FAIL );
-					LC_RET0;
-				}
-				free( buf );
-			}
-			close( fd );
-		}
-		GSendStr( "Logins are not allowed at the moment.\nTry again later" );
-		GSendInt( V_FAIL );
-		LC_RET0;
-	}
-
-
-/* restrict_nohome */
-# ifdef USE_LOGIN_CAP
-	if (login_getcapbool( lc, "requirehome", 0 )) {
-		struct stat st;
-		if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) {
-			PrepErrorGreet();
-			GSendInt( V_MSG_ERR );
-			GSendStr( "Home folder not available" );
-			GSendInt( V_FAIL );
-			LC_RET0;
-		}
-	}
-# endif
+# ifndef USE_PAM
 
+/* restrict_expired */
+#  if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
 
-/* restrict_time */
-# ifdef USE_LOGIN_CAP
-#  ifdef HAVE_AUTH_TIMEOK
-	if (!auth_timeok( lc, time( NULL ) )) {
-		PrepErrorGreet();
-		GSendInt( V_MSG_ERR );
-		GSendStr( "You are not allowed to login at the moment" );
-		GSendInt( V_FAIL );
-		LC_RET0;
-	}
-#  endif
-# endif
-
-
-/* restrict_expired; this MUST be the last one */
-# if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
-
-#  if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(USE_LOGIN_CAP) && defined(USESHADOW))
+#   if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW))
 	if (sp)
-#  endif
+#   endif
 	{
 
-#  define DEFAULT_WARN	(2L * 7L)  /* Two weeks */
+#   define DEFAULT_WARN	(2L * 7L)  /* Two weeks */
 
 		tim = time( NULL ) / 86400L;
 
-#  ifdef USE_LOGIN_CAP
+#   ifdef HAVE_SETUSERCONTEXT
 		quietlog = login_getcapbool( lc, "hushlogin", 0 );
 		warntime = login_getcaptime( lc, "warnexpire",
 		                             DEFAULT_WARN * 86400L,
 		                             DEFAULT_WARN * 86400L ) / 86400L;
-#  else
+#   else
 		quietlog = 0;
-#	ifdef USESHADOW
+#    ifdef USESHADOW
 		warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN;
-#	else
+#    else
 		warntime = DEFAULT_WARN;
-#	endif
-#  endif
+#    endif
+#   endif
 
-#  ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
+#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 		if (p->pw_expire) {
 			expir = p->pw_expire / 86400L;
-#  else
+#   else
 		if (sp->sp_expire != -1) {
 			expir = sp->sp_expire;
-#  endif
+#   endif
 			if (tim > expir) {
 				PrepErrorGreet();
 				GSendInt( V_MSG_ERR );
@@ -888,10 +835,10 @@
 			}
 		}
 
-#  ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
+#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 		if (p->pw_change) {
 			expir = p->pw_change / 86400L;
-#  else
+#   else
 		if (!sp->sp_lstchg) {
 			PrepErrorGreet();
 			GSendInt( V_MSG_ERR );
@@ -910,7 +857,7 @@
 				GSendInt( V_FAIL );
 				LC_RET0;
 			}
-#  endif
+#   endif
 			if (tim > expir) {
 				PrepErrorGreet();
 				GSendInt( V_MSG_ERR );
@@ -934,13 +881,84 @@
 
 	}
 
-# endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */
+#  endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */
+
+/* restrict_nologin */
+#  ifndef _PATH_NOLOGIN
+#   define _PATH_NOLOGIN "/etc/nologin"
+#  endif
+
+	if ((
+#  ifdef HAVE_SETUSERCONTEXT
+	     /* Do we ignore a nologin file? */
+	     !login_getcapbool( lc, "ignorenologin", 0 )) &&
+	    (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) ||
+#  endif
+		 !stat( (nolg = _PATH_NOLOGIN), &st )))
+	{
+		PrepErrorGreet();
+		GSendInt( V_MSG_ERR );
+		if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) {
+			if ((buf = Malloc( st.st_size + 1 ))) {
+				if (read( fd, buf, st.st_size ) == st.st_size) {
+					buf[st.st_size] = 0;
+					GSendStr( buf );
+					free( buf );
+					close( fd );
+					GSendInt( V_FAIL );
+					LC_RET0;
+				}
+				free( buf );
+			}
+			close( fd );
+		}
+		GSendStr( "Logins are not allowed at the moment.\nTry again later" );
+		GSendInt( V_FAIL );
+		LC_RET0;
+	}
+
+/* restrict_time */
+#  if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK)
+	if (!auth_timeok( lc, time( NULL ) )) {
+		PrepErrorGreet();
+		GSendInt( V_MSG_ERR );
+		GSendStr( "You are not allowed to login at the moment" );
+		GSendInt( V_FAIL );
+		LC_RET0;
+	}
+#  endif
+
+#  ifdef HAVE_GETUSERSHELL
+	for (;;) {
+		if (!(s = getusershell())) {
+			Debug( "shell not in /etc/shells\n" );
+			endusershell();
+			V_RET_FAIL( "Your login shell is not listed in /etc/shells" );
+		}
+		if (!strcmp( s, p->pw_shell )) {
+			endusershell();
+			break;
+		}
+	}
+#  endif
+
+# endif /* !USE_PAM */
 
-# ifdef USE_LOGIN_CAP
-	login_close( lc );
+/* restrict_nohome */
+# ifdef HAVE_SETUSERCONTEXT
+	if (login_getcapbool( lc, "requirehome", 0 )) {
+		struct stat st;
+		if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) {
+			PrepErrorGreet();
+			GSendInt( V_MSG_ERR );
+			GSendStr( "Home folder not available" );
+			GSendInt( V_FAIL );
+			LC_RET0;
+		}
+	}
 # endif
 
-#endif /* USE_PAM || _AIX */
+#endif /* !_AIX */
 
 	return 1;
 
@@ -956,6 +974,54 @@
 };
 
 
+#if defined(USE_PAM) && defined(HAVE_INITGROUPS)
+static int num_saved_gids;
+static gid_t *saved_gids;
+
+static int
+saveGids( void )
+{
+	num_saved_gids = getgroups( 0, 0 );
+	if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids )))
+		return 0;
+	if (getgroups( num_saved_gids, saved_gids ) < 0) {
+		LogError( "saving groups failed: %m\n" );
+		return 0;
+	}
+	return 1;
+}
+
+static int
+restoreGids( void )
+{
+	if (setgroups( num_saved_gids, saved_gids ) < 0) {
+		LogError( "restoring groups failed: %m\n" );
+		return 0;
+	}
+	if (setgid( p->pw_gid ) < 0) {
+		LogError( "restoring gid failed: %m\n" );
+		return 0;
+	}
+	return 1;
+}
+#endif /* USE_PAM && HAVE_INITGROUPS */
+
+static int
+resetGids( void )
+{
+#ifdef HAVE_INITGROUPS
+	if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) {
+		LogError( "restoring groups failed: %m\n" );
+		return 0;
+	}
+#endif
+	if (setgid( 0 ) < 0) {
+		LogError( "restoring gid failed: %m\n" );
+		return 0;
+	}
+	return 1;
+}
+
 static int
 SetGid( const char *name, int gid )
 {
@@ -966,6 +1032,7 @@
 #ifdef HAVE_INITGROUPS
 	if (initgroups( name, gid ) < 0) {
 		LogError( "initgroups for %s failed: %m\n", name );
+		setgid( 0 );
 		return 0;
 	}
 #endif	 /* QNX4 doesn't support multi-groups, no initgroups() */
@@ -985,7 +1052,12 @@
 static int
 SetUser( const char *name, int uid, int gid )
 {
-	return SetGid( name, gid ) && SetUid( name, uid );
+	if (SetGid( name, gid )) {
+		if (SetUid( name, uid ))
+			return 1;
+		resetGids();
+	}
+	return 0;
 }
 
 #if defined(SECURE_RPC) || defined(K5AUTH)
@@ -1044,6 +1116,10 @@
 }
 
 static int removeAuth;
+#ifdef USE_PAM
+static int removeSession;
+static int removeCreds;
+#endif
 
 int
 StartClient()
@@ -1053,6 +1129,9 @@
 	char **argv, *fname, *str;
 #ifdef USE_PAM
 	char **pam_env;
+# ifdef _AIX
+	char **saved_env;
+# endif
 	struct pam_conv pconv;
 	int pretc;
 #else
@@ -1140,7 +1219,7 @@
 		env = setEnv( env, "KRBTKFILE", krbtkfile );
 #endif
 	userEnviron = inheritEnv( env, envvars );
-	env = systemEnv( curuser );
+	env = systemEnv( p->pw_name );
 	systemEnviron = setEnv( env, "HOME", p->pw_dir );
 	Debug( "user environment:\n%[|''>'\n's"
 	       "system environment:\n%[|''>'\n's"
@@ -1190,13 +1269,83 @@
 		mergeSessionArgs( TRUE );
 
 	Debug( "now starting the session\n" );
+
 #ifdef USE_PAM
+	/* the greeter is gone by now ... */
 	pconv.conv = PAM_conv_null;
 	pconv.appdata_ptr = 0;
-	pam_set_item( pamh, PAM_CONV, &pconv ); /* XXX this can fail */
-	pam_open_session( pamh, 0 ); /* XXX this can fail, too */
+	if ((pretc = pam_set_item( pamh, PAM_CONV, &pconv )) != PAM_SUCCESS) {
+		ReInitErrorLog();
+		LogError( "pam_set_item() for %s failed: %s\n",
+		          curuser, pam_strerror( pamh, pretc ) );
+		return 0;
+	}
 	ReInitErrorLog();
 #endif
+
+#ifdef USE_PAM
+
+# ifdef HAVE_SETUSERCONTEXT
+	if (setusercontext( lc, p, p->pw_uid, LOGIN_SETGROUP )) {
+		LogError( "setusercontext(groups) for %s failed: %m\n",
+		          curuser );
+		return 0;
+	}
+# else
+	if (!SetGid( curuser, curgid ))
+		return 0;
+# endif
+
+# ifdef _AIX
+	if (!(pam_env = initStrArr( 0 ))) {
+		resetGids();
+		return 0;
+	}
+	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();
+# ifdef _AIX
+	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())
+		return 0;
+# 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();
@@ -1208,6 +1357,7 @@
 	case 0:
 
 		sessreg( td, getpid(), curuser, curuid );
+
 		if (source( systemEnviron, td->startup, td_setup )) {
 			LogError( "Cannot execute startup script %\"s\n", td->startup );
 			exit( 1 );
@@ -1217,32 +1367,16 @@
 			exit( 1 );
 		GSet( &mstrtalk );
 
-		/* Do system-dependent login setup here */
 		setsid();
+		Signal( SIGINT, SIG_DFL );
 
 	/* Memory leaks are ok here as we exec() soon. */
 
 #if defined(USE_PAM) || !defined(_AIX)
 
-# ifndef HAVE_SETUSERCONTEXT
-		if (!SetGid( curuser, curgid ))
-			exit( 1 );
-# endif
 # ifdef USE_PAM
-#  ifdef _AIX
-		if (!(environ = initStrArr( 0 )))
-			exit( 1 );
-#  endif
-		if ((pretc = pam_setcred( pamh, 0 )) != PAM_SUCCESS) {
-			ReInitErrorLog();
-			LogError( "pam_setcred() for %s failed: %s\n",
-			          curuser, pam_strerror( pamh, pretc ) );
-			exit( 1 );
-		}
 		/* pass in environment variables set by libpam and modules it called */
-#  ifdef _AIX
-		pam_env = environ;
-#  else
+#  ifndef _AIX
 		pam_env = pam_getenvlist( pamh );
 		ReInitErrorLog();
 #  endif
@@ -1250,19 +1384,36 @@
 			for (; *pam_env; pam_env++)
 				userEnviron = putEnv( *pam_env, userEnviron );
 # endif
-# ifndef HAVE_SETUSERCONTEXT
-#  ifdef HAVE_SETLOGIN
+
+# ifdef HAVE_SETLOGIN
 		if (setlogin( curuser ) < 0) {
 			LogError( "setlogin for %s failed: %m\n", curuser );
 			exit( 1 );
 		}
-#  endif
+#  define D_LOGIN_SETLOGIN LOGIN_SETLOGIN
+# else
+#  define D_LOGIN_SETLOGIN 0
+# endif
+
+# if defined(USE_PAM) && defined(HAVE_INITGROUPS)
+		if (!restoreGids())
+			exit( 1 );
+# endif
+
+# ifndef HAVE_SETUSERCONTEXT
+
+#  ifdef USE_PAM
 		if (!SetUid( curuser, curuid ))
 			exit( 1 );
-# else /* HAVE_SETUSERCONTEXT */
+#  else
+		if (!SetUser( curuser, curuid, curgid ))
+			exit( 1 );
+#  endif
+
+# else /* !HAVE_SETUSERCONTEXT */
 
 		/*
-		 * Destroy environment unless user has requested its preservation.
+		 * Destroy environment.
 		 * We need to do this before setusercontext() because that may
 		 * set or reset some environment variables.
 		 */
@@ -1273,7 +1424,9 @@
 		 * Set the user's credentials: uid, gid, groups,
 		 * environment variables, resource limits, and umask.
 		 */
-		if (setusercontext( NULL, p, p->pw_uid, LOGIN_SETALL ) < 0) {
+		if (setusercontext( lc, p, p->pw_uid,
+		        LOGIN_SETALL & ~(D_LOGIN_SETGROUP|D_LOGIN_SETLOGIN) ) < 0)
+		{
 			LogError( "setusercontext for %s failed: %m\n", curuser );
 			exit( 1 );
 		}
@@ -1281,8 +1434,9 @@
 		for (i = 0; environ[i]; i++)
 			userEnviron = putEnv( environ[i], userEnviron );
 
-# endif /* HAVE_SETUSERCONTEXT */
-#else /* _AIX */
+# endif /* !HAVE_SETUSERCONTEXT */
+
+#else /* PAM || !_AIX */
 		/*
 		 * Set the user's credentials: uid, gid, groups,
 		 * audit classes, user limits, and umask.
@@ -1466,51 +1620,79 @@
 void
 SessionExit( int status )
 {
-	/* make sure the server gets reset after the session is over */
-	if (td->serverPid >= 2) {
-		if (!td->terminateServer && td->resetSignal)
-			TerminateProcess( td->serverPid, td->resetSignal );
-	} else
-		ResetServer( td );
-	if (removeAuth) {
+	int pid;
 #ifdef USE_PAM
-		int pretc;
-		if ((pretc = pam_setcred( pamh, PAM_DELETE_CRED )) != PAM_SUCCESS)
-			LogError( "pam_setcred(DELETE_CRED) for %s failed: %s\n",
-			          curuser, pam_strerror( pamh, pretc ) );
-		pam_close_session( pamh, 0 );
-		pam_end( pamh, PAM_SUCCESS );
-		ReInitErrorLog();
+	int pretc;
 #endif
 
+	Signal( SIGTERM, SIG_IGN );
+
+	if (removeAuth) {
 		if (source( systemEnviron, td->reset, td_setup ))
 			LogError( "Cannot execute reset script %\"s\n", td->reset );
 		sessreg( td, 0, 0, 0 );
 
-		SetUser( curuser, curuid, curgid );
-		RemoveUserAuthorization( td );
+		switch ((pid = Fork())) {
+		case 0:
+#if defined(USE_PAM) && defined(HAVE_INITGROUPS)
+			if (restoreGids() && SetUid( curuser, curuid ))
+#else
+			if (SetUser( curuser, curuid, curgid ))
+#endif
+
+			{
+				RemoveUserAuthorization( td );
 #ifdef K5AUTH
-		Krb5Destroy( td->name );
+				Krb5Destroy( td->name );
 #endif /* K5AUTH */
 #if !defined(USE_PAM) && !defined(_AIX)
 # ifdef KERBEROS
-		if (krbtkfile[0]) {
-			(void)dest_tkt();
+				if (krbtkfile[0]) {
+					(void)dest_tkt();
 #  ifndef NO_AFS
-			if (k_hasafs())
-				(void)k_unlog();
+					if (k_hasafs())
+						(void)k_unlog();
 #  endif
-		}
+				}
 # endif
 #endif /* !USE_PAM && !_AIX*/
-#ifdef USE_PAM
-	} else {
-		if (pamh) {
-			pam_end( pamh, PAM_SUCCESS );
-			ReInitErrorLog();
+			}
+			exit( 0 );
+		case -1:
+			LogError( "Cannot clean up session: fork() failed: %m" );
+			break;
+		default:
+			Wait4( pid );
+			break;
 		}
-#endif
 	}
+
+#ifdef USE_PAM
+	if (removeCreds) {
+# ifdef HAVE_INITGROUPS
+		restoreGids();
+# endif
+		if (removeSession)
+			if ((pretc = pam_close_session( pamh, 0 )) != PAM_SUCCESS)
+				LogError( "pam_close_session() failed: %s\n",
+				          pam_strerror( pamh, pretc ) );
+		if ((pretc = pam_setcred( pamh, PAM_DELETE_CRED )) != PAM_SUCCESS)
+			LogError( "pam_setcred(DELETE_CRED) failed: %s\n",
+			          pam_strerror( pamh, pretc ) );
+		resetGids();
+	}
+	if (pamh) {
+		pam_end( pamh, PAM_SUCCESS );
+		ReInitErrorLog();
+	}
+#endif
+
+	/* make sure the server gets reset after the session is over */
+	if (td->serverPid >= 2) {
+		if (!td->terminateServer && td->resetSignal)
+			TerminateProcess( td->serverPid, td->resetSignal );
+	} else
+		ResetServer( td );
 	Debug( "display %s exiting with status %d\n", td->name, status );
 	exit( status );
 }