Home | History | Annotate | Line # | Download | only in greeter
      1 /*
      2 
      3 Copyright 1988, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 */
     28 /*
     29  * Copyright (c) 2006, Oracle and/or its affiliates.
     30  *
     31  * Permission is hereby granted, free of charge, to any person obtaining a
     32  * copy of this software and associated documentation files (the "Software"),
     33  * to deal in the Software without restriction, including without limitation
     34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     35  * and/or sell copies of the Software, and to permit persons to whom the
     36  * Software is furnished to do so, subject to the following conditions:
     37  *
     38  * The above copyright notice and this permission notice (including the next
     39  * paragraph) shall be included in all copies or substantial portions of the
     40  * Software.
     41  *
     42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     45  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     48  * DEALINGS IN THE SOFTWARE.
     49  */
     50 
     51 
     52 /*
     53  * xdm - display manager daemon
     54  * Author:  Keith Packard, X Consortium
     55  *
     56  * widget to get username/password
     57  *
     58  */
     59 
     60 #ifdef HAVE_CONFIG_H
     61 # include "config.h"
     62 #endif
     63 
     64 #include <X11/Intrinsic.h>
     65 #include <X11/StringDefs.h>
     66 #include <X11/Shell.h>
     67 #include <X11/XKBlib.h>
     68 
     69 #ifdef USE_XINERAMA
     70 # include <X11/extensions/Xinerama.h>
     71 #endif
     72 
     73 #include "dm.h"
     74 #include "dm_error.h"
     75 #include "greet.h"
     76 #include "LoginP.h"
     77 
     78 #if defined(HAVE_OPENLOG) && defined(HAVE_SYSLOG_H)
     79 # define USE_SYSLOG
     80 # include <syslog.h>
     81 # ifndef LOG_AUTHPRIV
     82 #  define LOG_AUTHPRIV LOG_AUTH
     83 # endif
     84 # ifndef LOG_PID
     85 #  define LOG_PID 0
     86 # endif
     87 #endif
     88 
     89 #include <string.h>
     90 
     91 #if defined(SECURE_RPC) && defined(sun)
     92 /* Go figure, there's no getdomainname() prototype available */
     93 extern int getdomainname(char *name, size_t len);
     94 #endif
     95 
     96 /*
     97  * Function pointers filled in by the initial call ito the library
     98  */
     99 
    100 int     (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL;
    101 void    (*__xdm_SessionPingFailed)(struct display *d) = NULL;
    102 void    (*__xdm_Debug)(const char * fmt, ...) = NULL;
    103 void    (*__xdm_RegisterCloseOnFork)(int fd) = NULL;
    104 void    (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL;
    105 void    (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL;
    106 void    (*__xdm_ClearCloseOnFork)(int fd) = NULL;
    107 void    (*__xdm_SetupDisplay)(struct display *d) = NULL;
    108 void    (*__xdm_LogError)(const char * fmt, ...) = NULL;
    109 void    (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL;
    110 void    (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL;
    111 int     (*__xdm_source)(char **environ, char *file) = NULL;
    112 char    **(*__xdm_defaultEnv)(void) = NULL;
    113 char    **(*__xdm_setEnv)(char **e, const char *name, const char *value) = NULL;
    114 char    **(*__xdm_putEnv)(const char *string, char **env) = NULL;
    115 char    **(*__xdm_parseArgs)(char **argv, const char *string) = NULL;
    116 void    (*__xdm_printEnv)(char **e) = NULL;
    117 char    **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL;
    118 void    (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL;
    119 void    (*__xdm_setgrent)(void) = NULL;
    120 struct group    *(*__xdm_getgrent)(void) = NULL;
    121 void    (*__xdm_endgrent)(void) = NULL;
    122 # ifdef HAVE_GETSPNAM
    123 struct spwd   *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL;
    124 void   (*__xdm_endspent)(void) = NULL;
    125 # endif
    126 struct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
    127 # if defined(linux) || defined(__GLIBC__)
    128 void   (*__xdm_endpwent)(void) = NULL;
    129 # endif
    130 char     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
    131 # ifdef USE_PAM
    132 pam_handle_t **(*__xdm_thepamhp)(void) = NULL;
    133 # endif
    134 
    135 #ifdef SECURE_RPC
    136 # include <rpc/rpc.h>
    137 # include <rpc/key_prot.h>
    138 #endif
    139 
    140 #ifdef K5AUTH
    141 # include <krb5/krb5.h>
    142 #endif
    143 
    144 static int	done, code;
    145 #ifndef USE_PAM
    146 static char	name[NAME_LEN], password[PASSWORD_LEN];
    147 #endif
    148 static Widget		toplevel;
    149 static Widget		login;
    150 static XtAppContext	context;
    151 static XtIntervalId	pingTimeout;
    152 
    153 #ifdef USE_PAM
    154 
    155 #ifdef __sun
    156 /* Solaris does not const qualify arguments to pam_get_item() or the
    157    PAM conversation function that Linux-PAM and others do. */
    158 # define XDM_PAM_QUAL /**/
    159 #else
    160 # define XDM_PAM_QUAL const
    161 #endif
    162 
    163 static int pamconv(int num_msg, XDM_PAM_QUAL struct pam_message **msg,
    164 		   struct pam_response **response, void *appdata_ptr);
    165 
    166 # define PAM_ERROR_PRINT(pamfunc, pamh)	\
    167 	LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error))
    168 
    169 
    170 struct myconv_data {
    171     struct display *d;
    172     struct greet_info *greet;
    173     char *username_display;
    174 };
    175 #endif
    176 
    177 
    178 /*ARGSUSED*/
    179 static void
    180 GreetPingServer (
    181     XtPointer	    closure,
    182     XtIntervalId    *intervalId)
    183 {
    184     struct display *d;
    185 
    186     d = (struct display *) closure;
    187     if (!PingServer (d, XtDisplay (toplevel)))
    188 	SessionPingFailed (d);
    189     pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
    190 				   GreetPingServer, (closure));
    191 }
    192 
    193 /*ARGSUSED*/
    194 static void
    195 GreetDone (
    196     Widget	w,
    197     LoginData	*data,
    198     int		status)
    199 {
    200     Debug ("GreetDone: %s, (password is %zu long)\n",
    201 	    data->name, strlen (data->passwd));
    202     switch (status) {
    203     case NOTIFY_OK:
    204 #ifndef USE_PAM
    205 	strncpy (name, data->name, sizeof(name));
    206 	name[sizeof(name)-1] = '\0';
    207 	strncpy (password, data->passwd, sizeof(password));
    208 	password[sizeof(password)-1] = '\0';
    209 #endif
    210 	code = 0;
    211 	done = 1;
    212 	break;
    213     case NOTIFY_ABORT:
    214 	Debug ("RESERVER_DISPLAY\n");
    215 	code = RESERVER_DISPLAY;
    216 	done = 1;
    217 	break;
    218     case NOTIFY_RESTART:
    219 	Debug ("REMANAGE_DISPLAY\n");
    220 	code = REMANAGE_DISPLAY;
    221 	done = 1;
    222 	break;
    223     case NOTIFY_ABORT_DISPLAY:
    224 	Debug ("UNMANAGE_DISPLAY\n");
    225 	code = UNMANAGE_DISPLAY;
    226 	done = 1;
    227 	break;
    228     }
    229 #ifndef USE_PAM
    230     if (done) {
    231 	bzero (data->name, NAME_LEN);
    232 	bzero (data->passwd, PASSWORD_LEN);
    233     }
    234 #endif
    235 }
    236 
    237 static Display *
    238 InitGreet (struct display *d)
    239 {
    240     Arg		arglist[10];
    241     int		i;
    242     static int	argc;
    243     Screen		*scrn;
    244     static char	*argv[] = { "xlogin", NULL };
    245     Display		*dpy;
    246 #ifdef USE_XINERAMA
    247     XineramaScreenInfo *screens;
    248     int                 s_num;
    249 #endif
    250 
    251     Debug ("greet %s\n", d->name);
    252     argc = 1;
    253     XtToolkitInitialize ();
    254     context = XtCreateApplicationContext();
    255     dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0,
    256 			 &argc, argv);
    257 
    258     if (!dpy)
    259 	return NULL;
    260 
    261 #ifdef XKB
    262     {
    263     int opcode, evbase, errbase, majret, minret;
    264     unsigned int value = XkbPCF_GrabsUseXKBStateMask;
    265     if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) {
    266 	if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value))
    267 	    LogError ("%s\n", "SetPerClientControls failed");
    268     }
    269     }
    270 #endif
    271     RegisterCloseOnFork (ConnectionNumber (dpy));
    272 
    273     SecureDisplay (d, dpy);
    274 
    275     i = 0;
    276     scrn = XDefaultScreenOfDisplay(dpy);
    277     XtSetArg(arglist[i], XtNscreen, scrn);	i++;
    278     XtSetArg(arglist[i], XtNargc, argc);	i++;
    279     XtSetArg(arglist[i], XtNargv, argv);	i++;
    280 
    281     toplevel = XtAppCreateShell ((String) NULL, "Xlogin",
    282 		    applicationShellWidgetClass, dpy, arglist, i);
    283 
    284     i = 0;
    285     XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++;
    286     if (!d->authorize || d->authorizations || !d->authComplain)
    287     {
    288 	XtSetArg (arglist[i], XtNsecureSession, True); i++;
    289     }
    290     login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel,
    291 				    arglist, i);
    292     XtRealizeWidget (toplevel);
    293 
    294 #ifdef USE_XINERAMA
    295     if (
    296 	XineramaIsActive(dpy) &&
    297 	(screens = XineramaQueryScreens(dpy, &s_num)) != NULL
    298        )
    299     {
    300 	XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
    301 			0, 0, 0, 0,
    302 			screens[0].x_org + screens[0].width / 2,
    303 			screens[0].y_org + screens[0].height / 2);
    304 
    305 	XFree(screens);
    306     }
    307     else
    308 #endif
    309     XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
    310 		    0, 0, 0, 0,
    311 		    XWidthOfScreen(scrn) / 2,
    312 		    XHeightOfScreen(scrn) / 2);
    313 
    314     if (d->pingInterval)
    315     {
    316 	pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
    317 				       GreetPingServer, (XtPointer) d);
    318     }
    319     return dpy;
    320 }
    321 
    322 static void
    323 CloseGreet (struct display *d)
    324 {
    325     Boolean	    allow;
    326     Arg	    arglist[1];
    327     Display *dpy = XtDisplay(toplevel);
    328 
    329     if (pingTimeout)
    330     {
    331 	XtRemoveTimeOut (pingTimeout);
    332 	pingTimeout = 0;
    333     }
    334     UnsecureDisplay (d, dpy);
    335     XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
    336     XtGetValues (login, arglist, 1);
    337     if (allow)
    338     {
    339 	Debug ("Disabling access control\n");
    340 	XSetAccessControl (dpy, DisableAccess);
    341     }
    342     XtDestroyWidget (toplevel);
    343     toplevel = NULL;
    344     login = NULL; /* child of toplevel, which we just destroyed */
    345     ClearCloseOnFork (XConnectionNumber (dpy));
    346     XCloseDisplay (dpy);
    347     Debug ("Greet connection closed\n");
    348 }
    349 
    350 #define WHITESPACE 0
    351 #define ARGUMENT 1
    352 
    353 static int
    354 Greet (struct display *d, struct greet_info *greet)
    355 {
    356     XEvent		event;
    357     Arg		arglist[1];
    358 
    359     XtSetArg (arglist[0], XtNallowAccess, False);
    360     XtSetValues (login, arglist, 1);
    361 
    362     Debug ("dispatching %s\n", d->name);
    363     done = 0;
    364     while (!done) {
    365 	XtAppNextEvent (context, &event);
    366 	switch (event.type) {
    367 	case MappingNotify:
    368 	    XRefreshKeyboardMapping(&event.xmapping);
    369 	    break;
    370 	default:
    371 	    XtDispatchEvent (&event);
    372 	    break;
    373 	}
    374     }
    375     XFlush (XtDisplay (toplevel));
    376     Debug ("Done dispatch %s\n", d->name);
    377     if (code == 0)
    378     {
    379 #ifndef USE_PAM
    380 	char *ptr;
    381 	unsigned int c,state = WHITESPACE;
    382 
    383 	/*
    384 	 * Process the name string to get rid of white spaces.
    385 	 */
    386 	for (ptr = name; state == WHITESPACE; ptr++)
    387 	{
    388 	    c = (unsigned int)(*ptr);
    389 	    if (c == ' ')
    390 		continue;
    391 
    392 	    state = ARGUMENT;
    393 	    break;
    394 	}
    395 
    396 	greet->name = ptr;
    397 	greet->password = password;
    398 #endif  /* USE_PAM */
    399 	XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string));
    400 	XtGetValues (login, arglist, 1);
    401 	Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>");
    402     }
    403     return code;
    404 }
    405 
    406 
    407 static void
    408 FailedLogin (struct display *d, const char *username)
    409 {
    410 #ifdef USE_SYSLOG
    411     if (username == NULL)
    412 	username = "username unavailable";
    413 
    414     syslog(LOG_AUTHPRIV|LOG_NOTICE,
    415 	   "LOGIN FAILURE ON %s, %s",
    416 	   d->name, username);
    417 #endif
    418     DrawFail (login);
    419 }
    420 
    421 _X_EXPORT
    422 greet_user_rtn GreetUser(
    423     struct display          *d,
    424     Display                 ** dpy,
    425     struct verify_info      *verify,
    426     struct greet_info       *greet,
    427     struct dlfuncs        *dlfuncs)
    428 {
    429     int i;
    430     Arg		arglist[2];
    431 
    432 /*
    433  * These must be set before they are used.
    434  */
    435     __xdm_PingServer = dlfuncs->_PingServer;
    436     __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed;
    437     __xdm_Debug = dlfuncs->_Debug;
    438     __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork;
    439     __xdm_SecureDisplay = dlfuncs->_SecureDisplay;
    440     __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay;
    441     __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork;
    442     __xdm_SetupDisplay = dlfuncs->_SetupDisplay;
    443     __xdm_LogError = dlfuncs->_LogError;
    444     __xdm_SessionExit = dlfuncs->_SessionExit;
    445     __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources;
    446     __xdm_source = dlfuncs->_source;
    447     __xdm_defaultEnv = dlfuncs->_defaultEnv;
    448     __xdm_setEnv = dlfuncs->_setEnv;
    449     __xdm_putEnv = dlfuncs->_putEnv;
    450     __xdm_parseArgs = dlfuncs->_parseArgs;
    451     __xdm_printEnv = dlfuncs->_printEnv;
    452     __xdm_systemEnv = dlfuncs->_systemEnv;
    453     __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem;
    454     __xdm_setgrent = dlfuncs->_setgrent;
    455     __xdm_getgrent = dlfuncs->_getgrent;
    456     __xdm_endgrent = dlfuncs->_endgrent;
    457 # ifdef HAVE_GETSPNAM
    458     __xdm_getspnam = dlfuncs->_getspnam;
    459     __xdm_endspent = dlfuncs->_endspent;
    460 # endif
    461     __xdm_getpwnam = dlfuncs->_getpwnam;
    462 # if defined(linux) || defined(__GLIBC__)
    463     __xdm_endpwent = dlfuncs->_endpwent;
    464 # endif
    465     __xdm_crypt = dlfuncs->_crypt;
    466 # ifdef USE_PAM
    467     __xdm_thepamhp = dlfuncs->_thepamhp;
    468 # endif
    469 
    470     *dpy = InitGreet (d);
    471     /*
    472      * Run the setup script - note this usually will not work when
    473      * the server is grabbed, so we don't even bother trying.
    474      */
    475     if (!d->grabServer)
    476 	SetupDisplay (d);
    477     if (!*dpy) {
    478 	LogError ("Cannot reopen display %s for greet window\n", d->name);
    479 	exit (RESERVER_DISPLAY);
    480     }
    481 
    482     XtSetArg (arglist[0], XtNallowNullPasswd,
    483 	      (char *) &(greet->allow_null_passwd));
    484     XtSetArg (arglist[1], XtNallowRootLogin,
    485 	      (char *) &(greet->allow_root_login));
    486     XtGetValues (login, arglist, 2);
    487 
    488     for (;;) {
    489 #ifdef USE_PAM
    490 
    491 	/* Run PAM conversation */
    492 	pam_handle_t 	**pamhp		= thepamhp();
    493 	int		  pam_error;
    494 	unsigned int	  pam_flags 	= 0;
    495 	struct myconv_data pcd		= { d, greet, NULL };
    496 	struct pam_conv   pc 		= { pamconv, &pcd };
    497 	const char *	  pam_fname;
    498 	const char *	  login_prompt;
    499 
    500 
    501 	SetPrompt(login, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
    502 	login_prompt  = GetPrompt(login, LOGIN_PROMPT_USERNAME);
    503 	SetPrompt(login, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
    504 
    505 # define RUN_AND_CHECK_PAM_ERROR(function, args)			\
    506 	    do { 						\
    507 		pam_error = function args;			\
    508 		if (pam_error != PAM_SUCCESS) {			\
    509 		    PAM_ERROR_PRINT(#function, *pamhp);		\
    510 		    goto pam_done;				\
    511 		} 						\
    512 	    } while (0)
    513 
    514 
    515 	RUN_AND_CHECK_PAM_ERROR(pam_start,
    516 				("xdm", NULL, &pc, pamhp));
    517 
    518 	/* Set default login prompt to xdm's default from Xresources */
    519 	if (login_prompt != NULL) {
    520 	    RUN_AND_CHECK_PAM_ERROR(pam_set_item,
    521 				    (*pamhp, PAM_USER_PROMPT, login_prompt));
    522 	}
    523 
    524 	if (d->name[0] != ':') {	/* Displaying to remote host */
    525 	    char *hostname = strdup(d->name);
    526 
    527 	    if (hostname == NULL) {
    528 		LogOutOfMem("GreetUser");
    529 	    } else {
    530 		char *colon = strrchr(hostname, ':');
    531 
    532 		if (colon != NULL)
    533 		    *colon = '\0';
    534 
    535 		RUN_AND_CHECK_PAM_ERROR(pam_set_item,
    536 					(*pamhp, PAM_RHOST, hostname));
    537 		free(hostname);
    538 	    }
    539 	} else {			/* Displaying on local host */
    540 	    const char *ttyname = NULL;
    541 
    542 #ifdef __sun
    543 	    /* Solaris PAM & auditing insist this is a device file that can
    544 	       be found under /dev, so we can't use the display name */
    545 	    char vtpath[16];
    546 
    547 	    if ((d->windowPath) && !(strchr(d->windowPath, ':'))) {
    548 		/* if path is simply a VT, with no intermediaries, use it */
    549 		snprintf(vtpath, sizeof(vtpath), "/dev/vt/%s", d->windowPath);
    550 		ttyname = vtpath;
    551 	    }
    552 #else
    553 	    /* On all other OS'es we just pass the display name for PAM_TTY */
    554 	    ttyname = d->name;
    555 #endif
    556 	    RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, ttyname));
    557 	}
    558 
    559 	if (!greet->allow_null_passwd) {
    560 	    pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
    561 	}
    562 	RUN_AND_CHECK_PAM_ERROR(pam_authenticate,
    563 				(*pamhp, pam_flags));
    564 
    565 	/* handle expired passwords */
    566 	pam_error = pam_acct_mgmt(*pamhp, pam_flags);
    567 	pam_fname = "pam_acct_mgmt";
    568 	if (pam_error == PAM_NEW_AUTHTOK_REQD) {
    569 	    ShowChangePasswdMessage(login);
    570 	    do {
    571 		pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK);
    572 	    } while ((pam_error == PAM_AUTHTOK_ERR) ||
    573 		     (pam_error == PAM_TRY_AGAIN));
    574 	    pam_fname = "pam_chauthtok";
    575 	}
    576 	if (pam_error != PAM_SUCCESS) {
    577 	    PAM_ERROR_PRINT(pam_fname, *pamhp);
    578 	    goto pam_done;
    579 	}
    580 
    581 	RUN_AND_CHECK_PAM_ERROR(pam_setcred,
    582 				(*pamhp, 0));
    583 	{
    584 	    char *username	= NULL;
    585 
    586 	    RUN_AND_CHECK_PAM_ERROR(pam_get_item,
    587                                     (*pamhp, PAM_USER,
    588                                      (XDM_PAM_QUAL void **) &username));
    589 	    if (username != NULL) {
    590 		Debug("PAM_USER: %s\n", username);
    591 		greet->name = username;
    592 		greet->password = NULL;
    593 	    }
    594 	}
    595 
    596       pam_done:
    597 	if (code != 0)
    598 	{
    599 	    CloseGreet (d);
    600 	    SessionExit (d, code, FALSE);
    601 	}
    602 	if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) {
    603 	    SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False);
    604 	    SetValue (login, 1, NULL);
    605 	    break;
    606 	} else {
    607 	    /* Try to fill in username for failed login error log */
    608 	    XDM_PAM_QUAL char *username = greet->name;
    609 
    610 	    if (username == NULL) {
    611 		RUN_AND_CHECK_PAM_ERROR(pam_get_item,
    612 					(*pamhp, PAM_USER,
    613 					 (XDM_PAM_QUAL void **) &username));
    614 	    }
    615 	    FailedLogin (d, username);
    616 	    RUN_AND_CHECK_PAM_ERROR(pam_end,
    617 				    (*pamhp, pam_error));
    618 	}
    619 #else /* not PAM */
    620 	/*
    621 	 * Greet user, requesting name/password
    622 	 */
    623 	code = Greet (d, greet);
    624 	if (code != 0)
    625 	{
    626 	    CloseGreet (d);
    627 	    SessionExit (d, code, FALSE);
    628 	}
    629 	/*
    630 	 * Verify user
    631 	 */
    632 	if (Verify (d, greet, verify))
    633 	    break;
    634 	else
    635 	{
    636 	    FailedLogin (d, greet->name);
    637 	    bzero (greet->name, strlen(greet->name));
    638 	    bzero (greet->password, strlen(greet->password));
    639 	}
    640 #endif
    641     }
    642     DeleteXloginResources (d, *dpy);
    643     CloseGreet (d);
    644     Debug ("Greet loop finished\n");
    645     /*
    646      * Run system-wide initialization file
    647      */
    648     if (source (verify->systemEnviron, d->startup) != 0)
    649     {
    650 	Debug ("Startup program %s exited with non-zero status\n",
    651 		d->startup);
    652 	SessionExit (d, OBEYSESS_DISPLAY, FALSE);
    653     }
    654     /*
    655      * for user-based authorization schemes,
    656      * add the user to the server's allowed "hosts" list.
    657      */
    658     for (i = 0; i < d->authNum; i++)
    659     {
    660 #ifdef SECURE_RPC
    661 	if (d->authorizations[i]->name_length == 9 &&
    662 	    memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
    663 	{
    664 	    XHostAddress	addr;
    665 	    char		netname[MAXNETNAMELEN+1];
    666 	    char		domainname[MAXNETNAMELEN+1];
    667 
    668 	    getdomainname(domainname, sizeof domainname);
    669 	    user2netname (netname, verify->uid, domainname);
    670 	    addr.family = FamilyNetname;
    671 	    addr.length = strlen (netname);
    672 	    addr.address = netname;
    673 	    XAddHost (*dpy, &addr);
    674 	}
    675 #endif
    676 #ifdef K5AUTH
    677 	if (d->authorizations[i]->name_length == 14 &&
    678 	    memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
    679 	{
    680 	    /* Update server's auth file with user-specific info.
    681 	     * Don't need to AddHost because X server will do that
    682 	     * automatically when it reads the cache we are about
    683 	     * to point it at.
    684 	     */
    685 	    extern Xauth *Krb5GetAuthFor();
    686 
    687 	    XauDisposeAuth (d->authorizations[i]);
    688 	    d->authorizations[i] =
    689 		Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
    690 	    SaveServerAuthorizations (d, d->authorizations, d->authNum);
    691 	}
    692 #endif
    693     }
    694 
    695     return Greet_Success;
    696 }
    697 
    698 
    699 #ifdef USE_PAM
    700 static int pamconv(int num_msg, XDM_PAM_QUAL struct pam_message **msg,
    701 		   struct pam_response **response, void *appdata_ptr)
    702 {
    703     int i;
    704     int greetCode;
    705     int status = PAM_SUCCESS;
    706     const char *pam_msg_styles[5]
    707 	= { "<invalid pam msg style>",
    708 	    "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
    709 	    "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
    710 
    711     struct pam_message      *m;
    712     struct pam_response     *r;
    713 
    714     struct myconv_data	    *d = (struct myconv_data *) appdata_ptr;
    715 
    716     pam_handle_t	    **pamhp = thepamhp();
    717 
    718     *response = calloc(num_msg, sizeof (struct pam_response));
    719     if (*response == NULL)
    720 	return (PAM_BUF_ERR);
    721 
    722     m = (struct pam_message *)*msg;
    723     r = *response;
    724 
    725     if (login == NULL) {
    726 	status = PAM_CONV_ERR;
    727 	goto pam_error;
    728     }
    729 
    730     for (i = 0; i < num_msg; i++ , m++ , r++) {
    731 	XDM_PAM_QUAL char *username;
    732 	int promptId = 0;
    733 	loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
    734 
    735 	if ((pam_get_item(*pamhp, PAM_USER, (XDM_PAM_QUAL void **) &username)
    736              == PAM_SUCCESS) && (username != NULL) && (*username != '\0')) {
    737 	    SetPrompt(login, LOGIN_PROMPT_USERNAME,
    738 		      NULL, LOGIN_TEXT_INFO, False);
    739 	    SetValue(login, LOGIN_PROMPT_USERNAME, username);
    740 	    promptId = 1;
    741 	}
    742 
    743 	Debug("pam_msg: %s (%d): '%s'\n",
    744 	      ((m->msg_style > 0) && (m->msg_style <= 4)) ?
    745 	       pam_msg_styles[m->msg_style] : pam_msg_styles[0],
    746 	       m->msg_style, m->msg);
    747 
    748 	switch (m->msg_style) {
    749 	  case PAM_ERROR_MSG:
    750 	      ErrorMessage(login, m->msg, True);
    751 	      break;
    752 
    753 	  case PAM_TEXT_INFO:
    754 	      SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
    755 	      SetValue (login, promptId, NULL);
    756 	      break;
    757 
    758           case PAM_PROMPT_ECHO_ON:
    759 	      pStyle = LOGIN_PROMPT_ECHO_ON;
    760 	      /* FALLTHROUGH */
    761           case PAM_PROMPT_ECHO_OFF:
    762 	      SetPrompt (login, promptId, m->msg, pStyle, False);
    763 	      SetValue (login, promptId, NULL);
    764 	      greetCode = Greet (d->d, d->greet);
    765 	      if (greetCode != 0) {
    766 		  status = PAM_CONV_ERR;
    767 		  goto pam_error;
    768 	      } else {
    769 		  r->resp = strdup(GetValue(login, promptId));
    770 		  SetValue(login, promptId, NULL);
    771 		  if (r->resp == NULL) {
    772 		      status = PAM_BUF_ERR;
    773 		      goto pam_error;
    774 		  }
    775 		  /* Debug("pam_resp: '%s'\n", r->resp); */
    776 	      }
    777 	      break;
    778 
    779 	  default:
    780 	      LogError("Unknown PAM msg_style: %d\n", m->msg_style);
    781 	}
    782     }
    783   pam_error:
    784     if (status != PAM_SUCCESS) {
    785 	/* free responses */
    786 	r = *response;
    787 	for (i = 0; i < num_msg; i++, r++) {
    788 	    if (r->resp) {
    789 		bzero(r->resp, strlen(r->resp));
    790 		free(r->resp);
    791 	    }
    792 	}
    793 	free(*response);
    794 	*response = NULL;
    795     }
    796     return status;
    797 }
    798 #endif
    799