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.
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;
124void   (*__xdm_endspent)(void) = NULL;
125# endif
126struct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
127# if defined(linux) || defined(__GLIBC__)
128void   (*__xdm_endpwent)(void) = NULL;
129# endif
130char     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
131# ifdef USE_PAM
132pam_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
144static int	done, code;
145#ifndef USE_PAM
146static char	name[NAME_LEN], password[PASSWORD_LEN];
147#endif
148static Widget		toplevel;
149static Widget		login;
150static XtAppContext	context;
151static 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
163static 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
170struct myconv_data {
171    struct display *d;
172    struct greet_info *greet;
173    char *username_display;
174};
175#endif
176
177
178/*ARGSUSED*/
179static void
180GreetPingServer (
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*/
194static void
195GreetDone (
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
237static Display *
238InitGreet (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
322static void
323CloseGreet (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
353static int
354Greet (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
407static void
408FailedLogin (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
422greet_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
700static 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