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