|
|
|
/*
|
|
|
|
|
|
|
|
Copyright 1988, 1998 The Open Group
|
|
|
|
Copyright 2000-2004 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
the above copyright notice appear in all copies and that both that
|
|
|
|
copyright notice and this permission notice appear in supporting
|
|
|
|
documentation.
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
Except as contained in this notice, the name of a copyright holder shall
|
|
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
|
|
other dealings in this Software without prior written authorization
|
|
|
|
from the copyright holder.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* xdm - display manager daemon
|
|
|
|
* Author: Keith Packard, MIT X Consortium
|
|
|
|
*
|
|
|
|
* subdaemon event loop, etc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dm.h"
|
|
|
|
#include "dm_error.h"
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#ifdef WITH_CONSOLE_KIT
|
|
|
|
#include "consolekit.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct display *td;
|
|
|
|
const char *td_setup = "auto";
|
|
|
|
|
|
|
|
static void DeleteXloginResources( void );
|
|
|
|
static void LoadXloginResources( void );
|
|
|
|
static void SetupDisplay( const char *arg );
|
|
|
|
|
|
|
|
|
|
|
|
static Jmp_buf pingTime;
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
static void
|
|
|
|
catchAlrm( int n ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
Longjmp( pingTime, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
static Jmp_buf tenaciousClient;
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
static void
|
|
|
|
waitAbort( int n ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
Longjmp( tenaciousClient, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AbortClient( int pid )
|
|
|
|
{
|
|
|
|
int sig = SIGTERM;
|
|
|
|
volatile int i;
|
|
|
|
int retId;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
if (kill( -pid, sig ) == -1) {
|
|
|
|
switch (errno) {
|
|
|
|
case EPERM:
|
|
|
|
LogError( "Can't kill client\n" );
|
|
|
|
case EINVAL:
|
|
|
|
case ESRCH:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!Setjmp( tenaciousClient )) {
|
|
|
|
(void)Signal( SIGALRM, waitAbort );
|
|
|
|
(void)alarm( (unsigned)10 );
|
|
|
|
retId = wait( (waitType *)0 );
|
|
|
|
(void)alarm( (unsigned)0 );
|
|
|
|
(void)Signal( SIGALRM, SIG_DFL );
|
|
|
|
if (retId == pid)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
(void)Signal( SIGALRM, SIG_DFL );
|
|
|
|
sig = SIGKILL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
conv_auto( int what, const char *prompt ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
switch (what) {
|
|
|
|
case GCONV_USER:
|
|
|
|
return curuser;
|
|
|
|
case GCONV_PASS:
|
|
|
|
case GCONV_PASS_ND:
|
|
|
|
return curpass;
|
|
|
|
default:
|
|
|
|
LogError( "Unknown authentication data type requested for autologin.\n" );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DoAutoLogon( void )
|
|
|
|
{
|
|
|
|
ReStr( &curuser, td->autoUser );
|
|
|
|
ReStr( &curpass, td->autoPass );
|
|
|
|
ReStr( &curtype, "classic" );
|
|
|
|
cursource = PWSRC_AUTOLOGIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
AutoLogon( Time_t tdiff )
|
|
|
|
{
|
|
|
|
Debug( "autoLogon, tdiff = %d, rLogin = %d, goodexit = %d, nuser = %s\n",
|
|
|
|
tdiff, td->hstent->rLogin, td->hstent->goodExit, td->hstent->nuser );
|
|
|
|
if (td->hstent->rLogin == 2 ||
|
|
|
|
(td->hstent->rLogin == 1 &&
|
|
|
|
tdiff <= 0 && !td->hstent->goodExit && !td->hstent->lock))
|
|
|
|
{
|
|
|
|
curuser = td->hstent->nuser;
|
|
|
|
td->hstent->nuser = 0;
|
|
|
|
curpass = td->hstent->npass;
|
|
|
|
td->hstent->npass = 0;
|
|
|
|
newdmrc = td->hstent->nargs;
|
|
|
|
td->hstent->nargs = 0;
|
|
|
|
ReStr( &curtype, "classic" );
|
|
|
|
cursource = (td->hstent->rLogin == 1) ? PWSRC_RELOGIN : PWSRC_MANUAL;
|
|
|
|
return 1;
|
|
|
|
} else if (*td->autoUser && !td->autoDelay &&
|
|
|
|
((tdiff > 0 && ((td->displayType & d_lifetime) == dTransient ||
|
|
|
|
!td->hstent->lastExit)) ||
|
|
|
|
td->autoAgain))
|
|
|
|
{
|
|
|
|
unsigned int lmask;
|
|
|
|
Window dummy1, dummy2;
|
|
|
|
int dummy3, dummy4, dummy5, dummy6;
|
|
|
|
XQueryPointer( dpy, DefaultRootWindow( dpy ),
|
|
|
|
&dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6,
|
|
|
|
&lmask );
|
|
|
|
if (lmask & ShiftMask)
|
|
|
|
return 0;
|
|
|
|
DoAutoLogon();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
int vcode, echo, ndelay;
|
|
|
|
} grqs[] = {
|
|
|
|
{ V_GET_TEXT, TRUE, FALSE },
|
|
|
|
{ V_GET_TEXT, FALSE, FALSE },
|
|
|
|
{ V_GET_TEXT, TRUE, FALSE },
|
|
|
|
{ V_GET_TEXT, FALSE, FALSE },
|
|
|
|
{ V_GET_TEXT, FALSE, TRUE },
|
|
|
|
{ V_GET_BINARY, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
char *
|
|
|
|
conv_interact( int what, const char *prompt )
|
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
int tag;
|
|
|
|
|
|
|
|
GSendInt( grqs[what].vcode );
|
|
|
|
if (what == GCONV_BINARY) {
|
|
|
|
unsigned const char *up = (unsigned const char *)prompt;
|
|
|
|
int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24);
|
|
|
|
GSendArr( len, prompt );
|
|
|
|
GSendInt( FALSE ); /* ndelay */
|
|
|
|
return GRecvArr( &len );
|
|
|
|
} else {
|
|
|
|
GSendStr( prompt );
|
|
|
|
GSendInt( grqs[what].echo );
|
|
|
|
GSendInt( grqs[what].ndelay );
|
|
|
|
ret = GRecvStr();
|
|
|
|
if (ret) {
|
|
|
|
tag = GRecvInt();
|
|
|
|
switch (what) {
|
|
|
|
case GCONV_USER:
|
|
|
|
/* assert(tag & V_IS_USER); */
|
|
|
|
if (curuser)
|
|
|
|
free( curuser );
|
|
|
|
curuser = ret;
|
|
|
|
break;
|
|
|
|
case GCONV_PASS:
|
|
|
|
case GCONV_PASS_ND:
|
|
|
|
/* assert(tag & V_IS_PASSWORD); */
|
|
|
|
if (curpass)
|
|
|
|
free( curpass );
|
|
|
|
curpass = ret;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (tag & V_IS_USER)
|
|
|
|
ReStr( &curuser, ret );
|
|
|
|
else if (tag & V_IS_PASSWORD)
|
|
|
|
ReStr( &curpass, ret );
|
|
|
|
else if (tag & V_IS_NEWPASSWORD)
|
|
|
|
ReStr( &newpass, ret );
|
|
|
|
else if (tag & V_IS_OLDPASSWORD)
|
|
|
|
ReStr( &ret, curpass );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int greeter;
|
|
|
|
GProc grtproc;
|
|
|
|
GTalk grttalk;
|
|
|
|
|
|
|
|
GTalk mstrtalk; /* make static; see dm.c */
|
|
|
|
|
|
|
|
int
|
|
|
|
CtrlGreeterWait( int wreply )
|
|
|
|
{
|
|
|
|
int i, cmd, type, rootok;
|
|
|
|
char *name, *pass, **avptr;
|
|
|
|
#ifdef XDMCP
|
|
|
|
ARRAY8Ptr aptr;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (Setjmp( mstrtalk.errjmp )) {
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
SessionExit( EX_UNMANAGE_DPY );
|
|
|
|
}
|
|
|
|
|
|
|
|
while (GRecvCmd( &cmd )) {
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case G_Ready:
|
|
|
|
Debug( "G_Ready\n" );
|
|
|
|
return 0;
|
|
|
|
case G_GetCfg:
|
|
|
|
/*Debug ("G_GetCfg\n");*/
|
|
|
|
type = GRecvInt();
|
|
|
|
/*Debug (" index %#x\n", type);*/
|
|
|
|
if (type == C_isLocal)
|
|
|
|
i = (td->displayType & d_location) == dLocal;
|
|
|
|
else if (type == C_hasConsole)
|
|
|
|
#ifdef HAVE_VTS
|
|
|
|
i = *consoleTTYs != 0;
|
|
|
|
#else
|
|
|
|
i = td->console != 0;
|
|
|
|
#endif
|
|
|
|
else if (type == C_isAuthorized)
|
|
|
|
i = td->authorizations != 0;
|
|
|
|
else
|
|
|
|
goto normal;
|
|
|
|
GSendInt( GE_Ok );
|
|
|
|
/*Debug (" -> bool %d\n", i);*/
|
|
|
|
GSendInt( i );
|
|
|
|
break;
|
|
|
|
normal:
|
|
|
|
if (!(avptr = FindCfgEnt( td, type ))) {
|
|
|
|
/*Debug (" -> not found\n");*/
|
|
|
|
GSendInt( GE_NoEnt );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (type & C_TYPE_MASK) {
|
|
|
|
default:
|
|
|
|
/*Debug (" -> unknown type\n");*/
|
|
|
|
GSendInt( GE_BadType );
|
|
|
|
break;
|
|
|
|
case C_TYPE_INT:
|
|
|
|
case C_TYPE_STR:
|
|
|
|
case C_TYPE_ARGV:
|
|
|
|
#ifdef XDMCP
|
|
|
|
case C_TYPE_ARR:
|
|
|
|
#endif
|
|
|
|
GSendInt( GE_Ok );
|
|
|
|
switch (type & C_TYPE_MASK) {
|
|
|
|
case C_TYPE_INT:
|
|
|
|
/*Debug (" -> int %#x (%d)\n", *(int *)avptr, *(int *)avptr);*/
|
|
|
|
GSendInt( *(long *)avptr );
|
|
|
|
break;
|
|
|
|
case C_TYPE_STR:
|
|
|
|
/*Debug (" -> string %\"s\n", *avptr);*/
|
|
|
|
GSendStr( *avptr );
|
|
|
|
break;
|
|
|
|
case C_TYPE_ARGV:
|
|
|
|
/*Debug (" -> sending argv %\"[{s\n", *(char ***)avptr);*/
|
|
|
|
GSendArgv( *(char ***)avptr );
|
|
|
|
break;
|
|
|
|
#ifdef XDMCP
|
|
|
|
case C_TYPE_ARR:
|
|
|
|
aptr = *(ARRAY8Ptr *)avptr;
|
|
|
|
/*Debug (" -> sending array %02[*:hhx\n",
|
|
|
|
aptr->length, aptr->data);*/
|
|
|
|
GSendArr( aptr->length, (char *)aptr->data );
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case G_ReadDmrc:
|
|
|
|
Debug( "G_ReadDmrc\n" );
|
|
|
|
name = GRecvStr();
|
|
|
|
Debug( " user %\"s\n", name );
|
|
|
|
if (StrCmp( dmrcuser, name )) {
|
|
|
|
if (curdmrc) { free( curdmrc ); curdmrc = 0; }
|
|
|
|
if (dmrcuser)
|
|
|
|
free( dmrcuser );
|
|
|
|
dmrcuser = name;
|
|
|
|
i = ReadDmrc();
|
|
|
|
Debug( " -> status %d\n", i );
|
|
|
|
GSendInt( i );
|
|
|
|
Debug( " => %\"s\n", curdmrc );
|
|
|
|
} else {
|
|
|
|
if (name)
|
|
|
|
free( name );
|
|
|
|
Debug( " -> status " stringify( GE_Ok ) "\n" );
|
|
|
|
GSendInt( GE_Ok );
|
|
|
|
Debug( " => keeping old\n" );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case G_GetDmrc:
|
|
|
|
Debug( "G_GetDmrc\n" );
|
|
|
|
name = GRecvStr();
|
|
|
|
Debug( " key %\"s\n", name );
|
|
|
|
pass = iniEntry( curdmrc, "Desktop", name, 0 );
|
|
|
|
Debug( " -> %\"s\n", pass );
|
|
|
|
GSendStr( pass );
|
|
|
|
if (pass)
|
|
|
|
free( pass );
|
|
|
|
free( name );
|
|
|
|
break;
|
|
|
|
/* case G_ResetDmrc:
|
|
|
|
Debug ("G_ResetDmrc\n");
|
|
|
|
if (newdmrc) { free (newdmrc); newdmrc = 0; }
|
|
|
|
break; */
|
|
|
|
case G_PutDmrc:
|
|
|
|
Debug( "G_PutDmrc\n" );
|
|
|
|
name = GRecvStr();
|
|
|
|
Debug( " key %\"s\n", name );
|
|
|
|
pass = GRecvStr();
|
|
|
|
Debug( " value %\"s\n", pass );
|
|
|
|
newdmrc = iniEntry( newdmrc, "Desktop", name, pass );
|
|
|
|
free( pass );
|
|
|
|
free( name );
|
|
|
|
break;
|
|
|
|
case G_VerifyRootOK:
|
|
|
|
Debug( "G_VerifyRootOK\n" );
|
|
|
|
rootok = TRUE;
|
|
|
|
goto doverify;
|
|
|
|
case G_Verify:
|
|
|
|
Debug( "G_Verify\n" );
|
|
|
|
rootok = FALSE;
|
|
|
|
doverify:
|
|
|
|
if (curuser) { free( curuser ); curuser = 0; }
|
|
|
|
if (curpass) { free( curpass ); curpass = 0; }
|
|
|
|
if (curtype) free( curtype );
|
|
|
|
curtype = GRecvStr();
|
|
|
|
Debug( " type %\"s\n", curtype );
|
|
|
|
cursource = PWSRC_MANUAL;
|
|
|
|
if (Verify( conv_interact, rootok )) {
|
|
|
|
Debug( " -> return success\n" );
|
|
|
|
GSendInt( V_OK );
|
|
|
|
} else
|
|
|
|
Debug( " -> failure returned\n" );
|
|
|
|
break;
|
|
|
|
case G_AutoLogin:
|
|
|
|
Debug( "G_AutoLogin\n" );
|
|
|
|
DoAutoLogon();
|
|
|
|
if (Verify( conv_auto, FALSE )) {
|
|
|
|
Debug( " -> return success\n" );
|
|
|
|
GSendInt( V_OK );
|
|
|
|
} else
|
|
|
|
Debug( " -> failure returned\n" );
|
|
|
|
break;
|
|
|
|
case G_SetupDpy:
|
|
|
|
Debug( "G_SetupDpy\n" );
|
|
|
|
SetupDisplay( 0 );
|
|
|
|
td_setup = 0;
|
|
|
|
GSendInt( 0 );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
if (!wreply)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Debug( "lost connection to greeter\n" );
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OpenGreeter()
|
|
|
|
{
|
|
|
|
char *name, **env;
|
|
|
|
static Time_t lastStart;
|
|
|
|
int cmd;
|
|
|
|
Cursor xcursor;
|
|
|
|
|
|
|
|
GSet( &grttalk );
|
|
|
|
if (greeter)
|
|
|
|
return;
|
|
|
|
if (time( 0 ) < lastStart + 10) /* XXX should use some readiness indicator instead */
|
|
|
|
SessionExit( EX_UNMANAGE_DPY );
|
|
|
|
greeter = 1;
|
|
|
|
ASPrintf( &name, "greeter for display %s", td->name );
|
|
|
|
Debug( "starting %s\n", name );
|
|
|
|
|
|
|
|
/* Hourglass cursor */
|
|
|
|
if ((xcursor = XCreateFontCursor( dpy, XC_watch ))) {
|
|
|
|
XDefineCursor( dpy, DefaultRootWindow( dpy ), xcursor );
|
|
|
|
XFreeCursor( dpy, xcursor );
|
|
|
|
}
|
|
|
|
XFlush( dpy );
|
|
|
|
|
|
|
|
/* Load system default Resources (if any) */
|
|
|
|
LoadXloginResources();
|
|
|
|
|
|
|
|
grttalk.pipe = &grtproc.pipe;
|
|
|
|
env = systemEnv( (char *)0 );
|
|
|
|
if (GOpen( &grtproc, (char **)0, "_greet", env, name, &td->gpipe ))
|
|
|
|
SessionExit( EX_UNMANAGE_DPY );
|
|
|
|
freeStrArr( env );
|
|
|
|
if ((cmd = CtrlGreeterWait( TRUE ))) {
|
|
|
|
if (cmd != -2)
|
|
|
|
LogError( "Received unknown or unexpected command %d from greeter\n", cmd );
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
SessionExit( EX_UNMANAGE_DPY );
|
|
|
|
}
|
|
|
|
Debug( "%s ready\n", name );
|
|
|
|
time( &lastStart );
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CloseGreeter( int force )
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!greeter)
|
|
|
|
return EX_NORMAL;
|
|
|
|
greeter = 0;
|
|
|
|
ret = GClose (&grtproc, 0, force);
|
|
|
|
Debug( "greeter for %s stopped\n", td->name );
|
|
|
|
if (WaitCode( ret ) > EX_NORMAL && WaitCode( ret ) <= EX_MAX) {
|
|
|
|
Debug( "greeter-initiated session exit, code %d\n", WaitCode( ret ) );
|
|
|
|
SessionExit( WaitCode( ret ) );
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PrepErrorGreet()
|
|
|
|
{
|
|
|
|
if (!greeter) {
|
|
|
|
OpenGreeter();
|
|
|
|
GSendInt( G_ErrorGreet );
|
|
|
|
GSendStr( curuser );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Jmp_buf idleTOJmp;
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
static void
|
|
|
|
IdleTOJmp( int n ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
Longjmp( idleTOJmp, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Jmp_buf abortSession;
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
static void
|
|
|
|
catchTerm( int n ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
Signal( SIGTERM, SIG_IGN );
|
|
|
|
Longjmp( abortSession, EX_AL_RESERVER_DPY );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need our own error handlers because we can't be sure what exit code Xlib
|
|
|
|
* will use, and our Xlib does exit(1) which matches EX_REMANAGE_DPY, which
|
|
|
|
* can cause a race condition leaving the display wedged. We need to use
|
|
|
|
* EX_RESERVER_DPY for IO errors, to ensure that the manager waits for the
|
|
|
|
* server to terminate. For other X errors, we should give up.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
static int
|
|
|
|
IOErrorHandler( Display *dspl ATTR_UNUSED )
|
|
|
|
{
|
|
|
|
LogError( "Fatal X server IO error: %m\n" );
|
|
|
|
/* The only X interaction during the session are pings, and those
|
|
|
|
have an own IOErrorHandler -> not EX_AL_RESERVER_DPY */
|
|
|
|
Longjmp( abortSession, EX_RESERVER_DPY );
|
|
|
|
/*NOTREACHED*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
static int
|
|
|
|
ErrorHandler( Display *dspl ATTR_UNUSED, XErrorEvent *event )
|
|
|
|
{
|
|
|
|
LogError( "X error\n" );
|
|
|
|
if (event->error_code == BadImplementation)
|
|
|
|
Longjmp( abortSession, EX_UNMANAGE_DPY );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ManageSession( struct display *d )
|
|
|
|
{
|
|
|
|
int ex, cmd;
|
|
|
|
volatile int clientPid = 0;
|
|
|
|
volatile Time_t tdiff = 0;
|
|
|
|
#ifdef WITH_CONSOLE_KIT
|
|
|
|
char *ck_session_cookie;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
td = d;
|
|
|
|
Debug( "ManageSession %s\n", d->name );
|
|
|
|
if ((ex = Setjmp( abortSession ))) {
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
if (clientPid)
|
|
|
|
AbortClient( clientPid );
|
|
|
|
SessionExit( ex );
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
(void)XSetIOErrorHandler( IOErrorHandler );
|
|
|
|
(void)XSetErrorHandler( ErrorHandler );
|
|
|
|
(void)Signal( SIGTERM, catchTerm );
|
|
|
|
|
|
|
|
(void)Signal( SIGHUP, SIG_IGN );
|
|
|
|
|
|
|
|
if (Setjmp( grttalk.errjmp ))
|
|
|
|
Longjmp( abortSession, EX_RESERVER_DPY ); /* EX_RETRY_ONCE */
|
|
|
|
|
|
|
|
#ifdef XDMCP
|
|
|
|
if (d->useChooser)
|
|
|
|
DoChoose();
|
|
|
|
/* NOTREACHED */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (d->hstent->sdRec.how) {
|
|
|
|
OpenGreeter();
|
|
|
|
GSendInt( G_ConfShutdown );
|
|
|
|
GSendInt( d->hstent->sdRec.how );
|
|
|
|
GSendInt( d->hstent->sdRec.uid );
|
|
|
|
GSendStr( d->hstent->sdRec.osname );
|
|
|
|
if ((cmd = CtrlGreeterWait( TRUE )) != G_Ready) {
|
|
|
|
LogError( "Received unknown command %d from greeter\n", cmd );
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
}
|
|
|
|
goto regreet;
|
|
|
|
}
|
|
|
|
|
|
|
|
tdiff = time( 0 ) - td->hstent->lastExit - td->openDelay;
|
|
|
|
if (AutoLogon( tdiff )) {
|
|
|
|
if (!Verify( conv_auto, FALSE ))
|
|
|
|
goto gcont;
|
|
|
|
if (greeter)
|
|
|
|
GSendInt( V_OK );
|
|
|
|
} else {
|
|
|
|
regreet:
|
|
|
|
OpenGreeter();
|
|
|
|
if (Setjmp( idleTOJmp )) {
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
SessionExit( EX_NORMAL );
|
|
|
|
}
|
|
|
|
Signal( SIGALRM, IdleTOJmp );
|
|
|
|
alarm( td->idleTimeout );
|
|
|
|
#ifdef XDMCP
|
|
|
|
if (((d->displayType & d_location) == dLocal) &&
|
|
|
|
d->loginMode >= LOGIN_DEFAULT_REMOTE)
|
|
|
|
goto choose;
|
|
|
|
#endif
|
|
|
|
for (;;) {
|
|
|
|
Debug( "ManageSession, greeting, tdiff = %d\n", tdiff );
|
|
|
|
GSendInt( (*td->autoUser && td->autoDelay &&
|
|
|
|
(tdiff > 0 || td->autoAgain)) ?
|
|
|
|
G_GreetTimed : G_Greet );
|
|
|
|
gcont:
|
|
|
|
cmd = CtrlGreeterWait( TRUE );
|
|
|
|
#ifdef XDMCP
|
|
|
|
recmd:
|
|
|
|
if (cmd == G_DChoose) {
|
|
|
|
choose:
|
|
|
|
cmd = DoChoose();
|
|
|
|
goto recmd;
|
|
|
|
}
|
|
|
|
if (cmd == G_DGreet)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
alarm( 0 );
|
|
|
|
if (cmd == G_Ready)
|
|
|
|
break;
|
|
|
|
if (cmd == -2)
|
|
|
|
CloseGreeter( FALSE );
|
|
|
|
else {
|
|
|
|
LogError( "Received unknown command %d from greeter\n", cmd );
|
|
|
|
CloseGreeter( TRUE );
|
|
|
|
}
|
|
|
|
goto regreet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CloseGreeter( FALSE ) != EX_NORMAL)
|
|
|
|
goto regreet;
|
|
|
|
|
|
|
|
DeleteXloginResources();
|
|
|
|
|
|
|
|
if (td_setup)
|
|
|
|
SetupDisplay( td_setup );
|
|
|
|
|
|
|
|
#ifdef WITH_CONSOLE_KIT
|
|
|
|
ck_session_cookie = open_ck_session (getpwnam(curuser), d);
|
|
|
|
if (!(clientPid = StartClient(ck_session_cookie))) {
|
|
|
|
#else
|
|
|
|
if (!(clientPid = StartClient())) {
|
|
|
|
#endif
|
|
|
|
LogError( "Client start failed\n" );
|
|
|
|
SessionExit( EX_NORMAL ); /* XXX maybe EX_REMANAGE_DPY? -- enable in dm.c! */
|
|
|
|
}
|
|
|
|
Debug( "client Started\n" );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for session to end,
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
if (!Setjmp( pingTime )) {
|
|
|
|
(void)Signal( SIGALRM, catchAlrm );
|
|
|
|
(void)alarm( d->pingInterval * 60 ); /* may be 0 */
|
|
|
|
(void)Wait4( clientPid );
|
|
|
|
(void)alarm( 0 );
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
(void)alarm( 0 );
|
|
|
|
if (!PingServer( d ))
|
|
|
|
catchTerm( SIGTERM );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_CONSOLE_KIT
|
|
|
|
if (ck_session_cookie != NULL) {
|
|
|
|
close_ck_session (ck_session_cookie);
|
|
|
|
free (ck_session_cookie);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sometimes the Xsession somehow manages to exit before
|
|
|
|
* a server crash is noticed - so we sleep a bit and wait
|
|
|
|
* for being killed.
|
|
|
|
*/
|
|
|
|
if (!PingServer( d )) {
|
|
|
|
Debug( "X server dead upon session exit.\n" );
|
|
|
|
if ((d->displayType & d_location) == dLocal)
|
|
|
|
sleep( 10 );
|
|
|
|
SessionExit( EX_AL_RESERVER_DPY );
|
|
|
|
}
|
|
|
|
SessionExit( EX_NORMAL ); /* XXX maybe EX_REMANAGE_DPY? -- enable in dm.c! */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xResLoaded;
|
|
|
|
|
|
|
|
void
|
|
|
|
LoadXloginResources()
|
|
|
|
{
|
|
|
|
char **args;
|
|
|
|
char **env;
|
|
|
|
|
|
|
|
if (!xResLoaded && td->resources[0] && access( td->resources, 4 ) == 0) {
|
|
|
|
env = systemEnv( (char *)0 );
|
|
|
|
if ((args = parseArgs( (char **)0, td->xrdb )) &&
|
|
|
|
(args = addStrArr( args, td->resources, -1 )))
|
|
|
|
{
|
|
|
|
Debug( "loading resource file: %s\n", td->resources );
|
|
|
|
(void)runAndWait( args, env );
|
|
|
|
freeStrArr( args );
|
|
|
|
}
|
|
|
|
freeStrArr( env );
|
|
|
|
xResLoaded = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SetupDisplay( const char *arg )
|
|
|
|
{
|
|
|
|
char **env;
|
|
|
|
|
|
|
|
env = systemEnv( (char *)0 );
|
|
|
|
(void)source( env, td->setup, arg );
|
|
|
|
freeStrArr( env );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DeleteXloginResources()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Atom prop;
|
|
|
|
|
|
|
|
if (!xResLoaded)
|
|
|
|
return;
|
|
|
|
xResLoaded = FALSE;
|
|
|
|
prop = XInternAtom( dpy, "SCREEN_RESOURCES", True );
|
|
|
|
XDeleteProperty( dpy, RootWindow( dpy, 0 ), XA_RESOURCE_MANAGER );
|
|
|
|
if (prop)
|
|
|
|
for (i = ScreenCount(dpy); --i >= 0; )
|
|
|
|
XDeleteProperty( dpy, RootWindow( dpy, i ), prop );
|
|
|
|
XSync( dpy, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
source( char **env, const char *file, const char *arg )
|
|
|
|
{
|
|
|
|
char **args;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (file && file[0]) {
|
|
|
|
Debug( "source %s\n", file );
|
|
|
|
if (!(args = parseArgs( (char **)0, file )))
|
|
|
|
return waitCompose( 0,0,3 );
|
|
|
|
if (arg && !(args = addStrArr( args, arg, -1 )))
|
|
|
|
return waitCompose( 0,0,3 );
|
|
|
|
ret = runAndWait( args, env );
|
|
|
|
freeStrArr( args );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char **
|
|
|
|
inheritEnv( char **env, const char **what )
|
|
|
|
{
|
|
|
|
char *value;
|
|
|
|
|
|
|
|
for (; *what; ++what)
|
|
|
|
if ((value = getenv( *what )))
|
|
|
|
env = setEnv( env, *what, value );
|
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
|
|
|
char **
|
|
|
|
baseEnv( const char *user )
|
|
|
|
{
|
|
|
|
char **env;
|
|
|
|
|
|
|
|
env = 0;
|
|
|
|
|
|
|
|
#ifdef _AIX
|
|
|
|
/* we need the tags SYSENVIRON: and USRENVIRON: in the call to setpenv() */
|
|
|
|
env = setEnv( env, "SYSENVIRON:", 0 );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
env = setEnv( env, "USER", user );
|
|
|
|
#ifdef _AIX
|
|
|
|
env = setEnv( env, "LOGIN", user );
|
|
|
|
#endif
|
|
|
|
env = setEnv( env, "LOGNAME", user );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _AIX
|
|
|
|
env = setEnv( env, "USRENVIRON:", 0 );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
env = inheritEnv( env, (const char **)exportList );
|
|
|
|
|
|
|
|
env = setEnv( env, "DISPLAY",
|
|
|
|
memcmp( td->name, "localhost:", 10 ) ?
|
|
|
|
td->name : td->name + 9 );
|
|
|
|
|
|
|
|
if (td->ctrl.path)
|
|
|
|
env = setEnv( env, "DM_CONTROL", fifoDir );
|
|
|
|
|
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
|
|
|
char **
|
|
|
|
systemEnv( const char *user )
|
|
|
|
{
|
|
|
|
char **env;
|
|
|
|
|
|
|
|
env = baseEnv( user );
|
|
|
|
if (td->authFile)
|
|
|
|
env = setEnv( env, "XAUTHORITY", td->authFile );
|
|
|
|
char *lang = getenv("LANG");
|
|
|
|
if (lang != NULL) {
|
|
|
|
env = setEnv( env, "LANG", lang );
|
|
|
|
}
|
|
|
|
env = setEnv( env, "PATH", td->systemPath );
|
|
|
|
env = setEnv( env, "SHELL", td->systemShell );
|
|
|
|
return env;
|
|
|
|
}
|