int main( int argc, char **argv ) { int oldpid, oldumask, fd, noDaemonMode; char *pt, *errorLogFile, **opts; /* make sure at least world write access is disabled */ if (((oldumask = umask( 022 )) & 002) == 002) (void)umask( oldumask ); /* give /dev/null as stdin */ if ((fd = open( "/dev/null", O_RDONLY )) > 0) { dup2( fd, 0 ); close( fd ); } if (fcntl( 1, F_GETFD ) < 0) dup2( 0, 1 ); if (fcntl( 2, F_GETFD ) < 0) dup2( 0, 2 ); if (argv[0][0] == '/') { if (!StrDup( &progpath, argv[0] )) Panic( "Out of memory" ); } else #ifdef __linux__ { /* note that this will resolve symlinks ... */ int len; char fullpath[PATH_MAX]; if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0) Panic( "Invoke with full path specification or mount /proc" ); if (!StrNDup( &progpath, fullpath, len )) Panic( "Out of memory" ); } #else # if 0 Panic( "Must be invoked with full path specification" ); # else { char directory[PATH_MAX+1]; if (!getcwd( directory, sizeof(directory) )) Panic( "Can't find myself (getcwd failed)" ); if (strchr( argv[0], '/' )) StrApp( &progpath, directory, "/", argv[0], (char *)0 ); else { int len; char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1]; if (!(path = getenv( "PATH" ))) Panic( "Can't find myself (no PATH)" ); len = strlen( argv[0] ); name = nambuf + PATH_MAX - len; memcpy( name, argv[0], len + 1 ); *--name = '/'; do { if (!(pathe = strchr( path, ':' ))) pathe = path + strlen( path ); len = pathe - path; if (!len || (len == 1 && *path == '.')) { len = strlen( directory ); path = directory; } thenam = name - len; if (thenam >= nambuf) { memcpy( thenam, path, len ); if (!access( thenam, X_OK )) goto found; } path = pathe; } while (*path++ != '\0'); Panic( "Can't find myself (not in PATH)" ); found: if (!StrDup( &progpath, thenam )) Panic( "Out of memory" ); } } # endif #endif prog = strrchr( progpath, '/' ) + 1; #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE) Title = argv[0]; TitleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - Title; #endif /* * Parse command line options */ noDaemonMode = getppid(); errorLogFile = 0; if (!(opts = Malloc( 2 * sizeof(char *) ))) return 1; opts[0] = (char *)""; opts[1] = 0; while (*++argv) { if (**argv != '-') break; pt = *argv + 1; if (*pt == '-') pt++; if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) { printf( "Usage: %s [options] [tty]\n" " -daemon\t - Daemonize even when started by init\n" " -nodaemon\t - Don't daemonize even when started from command line\n" " -config <file> - Use alternative master configuration file\n" " -xrm <res>\t - Override frontend-specific resource\n" " -error <file>\t - Use alternative log file\n" " -debug <num>\t - Debug option bitfield:\n" "\t\t\t0x1 - core log\n" "\t\t\t0x2 - config reader log\n" "\t\t\t0x4 - greeter log\n" "\t\t\t0x8 - IPC log\n" "\t\t\t0x10 - session sub-daemon post-fork delay\n" "\t\t\t0x20 - config reader post-start delay\n" "\t\t\t0x40 - greeter post-start delay\n" "\t\t\t0x80 - don't use syslog\n" "\t\t\t0x100 - core Xauth log\n" "\t\t\t0x400 - valgrind config reader and greeter\n" "\t\t\t0x800 - strace config reader and greeter\n" , prog ); exit( 0 ); } else if (!strcmp( pt, "daemon" )) noDaemonMode = 0; else if (!strcmp( pt, "nodaemon" )) noDaemonMode = 1; else if (argv[1] && !strcmp( pt, "config" )) StrDup( opts, *++argv ); else if (argv[1] && !strcmp( pt, "xrm" )) opts = addStrArr( opts, *++argv, -1 ); else if (argv[1] && !strcmp( pt, "debug" )) sscanf( *++argv, "%i", &debugLevel ); else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" ))) errorLogFile = *++argv; else { fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv ); exit( 1 ); } } /* * Only allow root to run in non-debug mode to avoid problems */ if (!debugLevel && getuid()) { fprintf( stderr, "Only root wants to run %s\n", prog ); exit( 1 ); } InitErrorLog( errorLogFile ); if (noDaemonMode != 1) BecomeDaemon(); /* * Step 1 - load configuration parameters */ if (!InitResources( opts ) || ScanConfigs( FALSE ) < 0) LogPanic( "Config reader failed. Aborting ...\n" ); /* SUPPRESS 560 */ if ((oldpid = StorePid())) { if (oldpid == -1) LogError( "Can't create/lock pid file %s\n", pidFile ); else LogError( "Can't lock pid file %s, another xdm is running (pid %d)\n", pidFile, oldpid ); exit( 1 ); } #ifdef NEED_ENTROPY AddOtherEntropy(); #endif /* * We used to clean up old authorization files here. As authDir is * supposed to be /var/run/xauth or /tmp, we needn't to care for it. */ #ifdef XDMCP init_session_id(); #else Debug( "not compiled for XDMCP\n" ); #endif if (pipe( signalFds )) LogPanic( "Unable to create signal notification pipe.\n" ); RegisterInput( signalFds[0] ); RegisterCloseOnFork( signalFds[0] ); RegisterCloseOnFork( signalFds[1] ); (void)Signal( SIGTERM, SigHandler ); (void)Signal( SIGINT, SigHandler ); (void)Signal( SIGHUP, SigHandler ); (void)Signal( SIGCHLD, SigHandler ); (void)Signal( SIGUSR1, SigHandler ); /* * Step 2 - run a sub-daemon for each entry */ #ifdef XDMCP UpdateListenSockets(); #endif openCtrl( 0 ); MainLoop(); closeCtrl( 0 ); if (sdRec.how) { commitBootOption(); if (Fork() <= 0) { char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot; execute( parseArgs( (char **)0, cmd ), (char **)0 ); LogError( "Failed to execute shutdown command %\"s\n", cmd ); exit( 1 ); } else { sigset_t mask; sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); sigaddset( &mask, SIGHUP ); sigsuspend( &mask ); } } Debug( "nothing left to do, exiting\n" ); return 0; }
static void checkUtmp(void) { static time_t modtim; time_t nck; time_t ends; struct utmps *utp; #ifndef HAVE_VTS struct utmps **utpp; #endif struct stat st; #ifdef BSD_UTMP int fd; struct utmp ut[1]; #else STRUCTUTMP *ut; #endif if (!utmpList) return; if (stat(UTMP_FILE, &st)) { logError(UTMP_FILE " not found - cannot use console mode\n"); wakeDisplays(); return; } if (modtim != st.st_mtime) { debug("rescanning " UTMP_FILE "\n"); #ifdef HAVE_VTS utp = utmpList; #else for (utp = utmpList; utp; utp = utp->next) #endif utp->state = UtDead; #ifdef BSD_UTMP if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) { logError("Cannot open " UTMP_FILE " - cannot use console mode\n"); wakeDisplays(); return; } while (reader(fd, ut, sizeof(ut[0])) == sizeof(ut[0])) #else SETUTENT(); while ((ut = GETUTENT())) #endif { /* first, match the tty to a utemps */ #ifdef HAVE_VTS char **line; for (line = consoleTTYs; *line; line++) if (!strncmp(*line, ut->ut_line, sizeof(ut->ut_line))) #else for (utp = utmpList; utp; utp = utp->next) if (!strncmp(utp->d->console, ut->ut_line, sizeof(ut->ut_line))) #endif goto hitlin; continue; hitlin: /* then, update the utemps accordingly */ #ifdef BSD_UTMP if (!*ut->ut_user) { #else if (ut->ut_type != USER_PROCESS) { #endif #ifdef HAVE_VTS /* don't allow "downgrading" the singular utemps */ if (utp->state == UtActive) continue; #endif utp->state = UtWait; } else { utp->hadSess = True; utp->state = UtActive; } nck = ut->ut_time - nowWallDelta; if (nck > now) nck = 0; /* Clock jumped. Time out immediately. */ #ifdef HAVE_VTS /* tty with latest activity wins */ if (utp->time < nck) #endif utp->time = nck; } #ifdef BSD_UTMP close(fd); #else ENDUTENT(); #endif modtim = st.st_mtime; } #ifdef HAVE_VTS utp = utmpList; #else for (utpp = &utmpList; (utp = *utpp);) { #endif if (utp->state != UtActive) { if (utp->state == UtDead) /* shouldn't happen ... */ utp->time = 0; ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG); if (ends <= now) { #ifdef HAVE_VTS wakeDisplays(); debug("console login timed out\n"); return; #else utp->d->status = notRunning; debug("console login for %s at %s timed out\n", utp->d->name, utp->d->console); *utpp = utp->next; free(utp); continue; #endif } else nck = ends; } else nck = TIME_RELOG + now; if (nck < utmpTimeout) utmpTimeout = nck; #ifndef HAVE_VTS utpp = &(*utpp)->next; } #endif } static void #ifdef HAVE_VTS switchToTTY(void) #else switchToTTY(struct display *d) #endif { struct utmps *utp; #ifdef HAVE_VTS int vt; #endif if (!(utp = Malloc(sizeof(*utp)))) { #ifdef HAVE_VTS wakeDisplays(); #else d->status = notRunning; #endif return; } #ifndef HAVE_VTS d->status = textMode; utp->d = d; utp->next = utmpList; #endif utp->time = now; utp->hadSess = False; utmpList = utp; checkUtmp(); #ifdef HAVE_VTS if ((vt = TTYtoVT(*consoleTTYs))) activateVT(vt); #endif } #ifdef HAVE_VTS static void stopToTTY(struct display *d) { if ((d->displayType & d_location) == dLocal) switch (d->status) { default: rStopDisplay(d, DS_TEXTMODE | DS_SCHEDULE); case reserve: case textMode: break; } } static void checkTTYMode(void) { struct display *d; for (d = displays; d; d = d->next) if (d->status == zombie) return; switchToTTY(); } #else void switchToX(struct display *d) { struct utmps *utp, **utpp; for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next) if (utp->d == d) { *utpp = utp->next; free(utp); d->status = notRunning; return; } } #endif #ifdef XDMCP static void startRemoteLogin(struct display *d) { char **argv; debug("startRemoteLogin for %s\n", d->name); /* HACK: omitting loadDisplayResources(d) here! */ switch (Fork(&d->serverPid)) { case 0: argv = prepareServerArgv(d, d->serverArgsRemote); if (!(argv = addStrArr(argv, "-once", 5)) || !(argv = addStrArr(argv, "-query", 6)) || !(argv = addStrArr(argv, d->remoteHost, -1))) exit(1); debug("exec %\"[s\n", argv); (void)execv(argv[0], argv); logError("X server %\"s cannot be executed\n", argv[0]); exit(1); case -1: logError("Forking X server for remote login failed: %m"); d->status = notRunning; return; default: break; } debug("X server forked, pid %d\n", d->serverPid); d->status = remoteLogin; }
static void CheckUtmp( void ) { static time_t modtim; time_t nck; time_t ends; struct utmps *utp, **utpp; struct stat st; #ifdef BSD_UTMP int fd; struct utmp ut[1]; #else STRUCTUTMP *ut; #endif if (!utmpList) return; if (stat( UTMP_FILE, &st )) { LogError( UTMP_FILE " not found - cannot use console mode\n" ); bombUtmp(); return; } if (modtim != st.st_mtime) { Debug( "rescanning " UTMP_FILE "\n" ); for (utp = utmpList; utp; utp = utp->next) utp->state = UtDead; #ifdef BSD_UTMP if ((fd = open( UTMP_FILE, O_RDONLY )) < 0) { LogError( "Cannot open " UTMP_FILE " - cannot use console mode\n" ); bombUtmp(); return; } while (Reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0])) #else SETUTENT(); while ((ut = GETUTENT())) #endif { for (utp = utmpList; utp; utp = utp->next) { #ifdef HAVE_VTS char **line; for (line = consoleTTYs; *line; line++) if (!strncmp( *line, ut->ut_line, sizeof(ut->ut_line) )) goto hitlin; continue; hitlin: #else if (strncmp( utp->d->console, ut->ut_line, sizeof(ut->ut_line) )) continue; #endif #ifdef BSD_UTMP if (!*ut->ut_user) { #else if (ut->ut_type != USER_PROCESS) { #endif #ifdef HAVE_VTS if (utp->state == UtActive) break; #endif utp->state = UtWait; } else { utp->hadSess = 1; utp->state = UtActive; } if (utp->time < ut->ut_time) /* theoretically superfluous */ utp->time = ut->ut_time; break; } } #ifdef BSD_UTMP close( fd ); #else ENDUTENT(); #endif modtim = st.st_mtime; } for (utpp = &utmpList; (utp = *utpp); ) { if (utp->state != UtActive) { if (utp->state == UtDead) /* shouldn't happen ... */ utp->time = 0; ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG); if (ends <= now) { #ifdef HAVE_VTS ForEachDisplay( WakeDisplay ); Debug( "console login timed out\n" ); #else utp->d->status = notRunning; Debug( "console login for %s at %s timed out\n", utp->d->name, utp->d->console ); #endif *utpp = utp->next; free( utp ); continue; } else nck = ends; } else nck = TIME_RELOG + now; if (nck < utmpTimeout) utmpTimeout = nck; utpp = &(*utpp)->next; } } static void #ifdef HAVE_VTS SwitchToTty( void ) #else SwitchToTty( struct display *d ) #endif { struct utmps *utp; #ifdef HAVE_VTS int vt; #endif if (!(utp = Malloc( sizeof(*utp) ))) { #ifdef HAVE_VTS ForEachDisplay( WakeDisplay ); #else d->status = notRunning; #endif return; } #ifndef HAVE_VTS d->status = textMode; utp->d = d; #endif utp->time = now; utp->hadSess = 0; utp->next = utmpList; utmpList = utp; CheckUtmp(); #ifdef HAVE_VTS if ((vt = TTYtoVT( *consoleTTYs ))) activateVT( vt ); #endif /* XXX output something useful here */ } #ifdef HAVE_VTS static void StopToTTY( struct display *d ) { if ((d->displayType & d_location) == dLocal) switch (d->status) { default: rStopDisplay( d, DS_TEXTMODE | 0x100 ); case reserve: case textMode: break; } } static void CheckTTYMode( void ) { struct display *d; for (d = displays; d; d = d->next) if (d->status == zombie) return; SwitchToTty(); } #else void SwitchToX( struct display *d ) { struct utmps *utp, **utpp; for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next) if (utp->d == d) { *utpp = utp->next; free( utp ); d->status = notRunning; return; } } #endif #ifdef XDMCP static void StartRemoteLogin( struct display *d ) { char **argv; int pid; Debug( "StartRemoteLogin for %s\n", d->name ); /* HACK: omitting LoadDisplayResources( d ) here! */ switch (pid = Fork()) { case 0: argv = PrepServerArgv( d, d->serverArgsRemote ); if (!(argv = addStrArr( argv, "-once", 5 )) || !(argv = addStrArr( argv, "-query", 6 )) || !(argv = addStrArr( argv, d->remoteHost, -1 ))) exit( 1 ); Debug( "exec %\"[s\n", argv ); (void)execv( argv[0], argv ); LogError( "X server %\"s cannot be executed\n", argv[0] ); exit( 1 ); case -1: LogError( "Forking X server for remote login failed: %m" ); d->status = notRunning; return; default: break; } Debug( "X server forked, pid %d\n", pid ); d->serverPid = pid; d->status = remoteLogin; }
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; }