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