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. 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 */
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 #  ifndef QNX4
125 void   (*__xdm_endspent)(void) = NULL;
126 #  endif /* QNX4 doesn't use endspent */
127 # endif
128 struct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
129 # if defined(linux) || defined(__GLIBC__)
130 void   (*__xdm_endpwent)(void) = NULL;
131 # endif
132 char     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
133 # ifdef USE_PAM
134 pam_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 
146 static int	done, code;
147 #ifndef USE_PAM
148 static char	name[NAME_LEN], password[PASSWORD_LEN];
149 #endif
150 static Widget		toplevel;
151 static Widget		login;
152 static XtAppContext	context;
153 static XtIntervalId	pingTimeout;
154 
155 #ifdef USE_PAM
156 static 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 
167 struct myconv_data {
168     struct display *d;
169     struct greet_info *greet;
170     char *username_display;
171 };
172 #endif
173 
174 
175 /*ARGSUSED*/
176 static void
GreetPingServer(XtPointer closure,XtIntervalId * intervalId)177 GreetPingServer (
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*/
191 static void
GreetDone(Widget w,LoginData * data,int status)192 GreetDone (
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 
234 static Display *
InitGreet(struct display * d)235 InitGreet (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 
319 static void
CloseGreet(struct display * d)320 CloseGreet (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 
350 static int
Greet(struct display * d,struct greet_info * greet)351 Greet (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 
404 static void
FailedLogin(struct display * d,const char * username)405 FailedLogin (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
GreetUser(struct display * d,Display ** dpy,struct verify_info * verify,struct greet_info * greet,struct dlfuncs * dlfuncs)419 greet_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     login = NULL;
643     Debug ("Greet loop finished\n");
644     /*
645      * Run system-wide initialization file
646      */
647     if (source (verify->systemEnviron, d->startup) != 0)
648     {
649 	Debug ("Startup program %s exited with non-zero status\n",
650 		d->startup);
651 	SessionExit (d, OBEYSESS_DISPLAY, FALSE);
652     }
653     /*
654      * for user-based authorization schemes,
655      * add the user to the server's allowed "hosts" list.
656      */
657     for (i = 0; i < d->authNum; i++)
658     {
659 #ifdef SECURE_RPC
660 	if (d->authorizations[i]->name_length == 9 &&
661 	    memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
662 	{
663 	    XHostAddress	addr;
664 	    char		netname[MAXNETNAMELEN+1];
665 	    char		domainname[MAXNETNAMELEN+1];
666 
667 	    getdomainname(domainname, sizeof domainname);
668 	    user2netname (netname, verify->uid, domainname);
669 	    addr.family = FamilyNetname;
670 	    addr.length = strlen (netname);
671 	    addr.address = netname;
672 	    XAddHost (*dpy, &addr);
673 	}
674 #endif
675 #ifdef K5AUTH
676 	if (d->authorizations[i]->name_length == 14 &&
677 	    memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
678 	{
679 	    /* Update server's auth file with user-specific info.
680 	     * Don't need to AddHost because X server will do that
681 	     * automatically when it reads the cache we are about
682 	     * to point it at.
683 	     */
684 	    extern Xauth *Krb5GetAuthFor();
685 
686 	    XauDisposeAuth (d->authorizations[i]);
687 	    d->authorizations[i] =
688 		Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
689 	    SaveServerAuthorizations (d, d->authorizations, d->authNum);
690 	}
691 #endif
692     }
693 
694     return Greet_Success;
695 }
696 
697 
698 #ifdef USE_PAM
pamconv(int num_msg,const struct pam_message ** msg,struct pam_response ** response,void * appdata_ptr)699 static int pamconv(int num_msg,
700 # ifndef sun
701 		   const
702 # endif
703 		   struct pam_message **msg,
704 		   struct pam_response **response, void *appdata_ptr)
705 {
706     int i;
707     int greetCode;
708     int status = PAM_SUCCESS;
709     const char *pam_msg_styles[5]
710 	= { "<invalid pam msg style>",
711 	    "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
712 	    "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
713 
714     struct pam_message      *m;
715     struct pam_response     *r;
716 
717     struct myconv_data	    *d = (struct myconv_data *) appdata_ptr;
718 
719     pam_handle_t	    **pamhp = thepamhp();
720 
721     *response = calloc(num_msg, sizeof (struct pam_response));
722     if (*response == NULL)
723 	return (PAM_BUF_ERR);
724 
725     m = (struct pam_message *)*msg;
726     r = *response;
727 
728     if (login == NULL) {
729 	status = PAM_CONV_ERR;
730 	goto pam_error;
731     }
732 
733     for (i = 0; i < num_msg; i++ , m++ , r++) {
734 	char *username;
735 	int promptId = 0;
736 	loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
737 
738 	if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS)
739 	    && (username != NULL) && (*username != '\0')) {
740 	    SetPrompt(login, LOGIN_PROMPT_USERNAME,
741 		      NULL, LOGIN_TEXT_INFO, False);
742 	    SetValue(login, LOGIN_PROMPT_USERNAME, username);
743 	    promptId = 1;
744 	}
745 
746 	Debug("pam_msg: %s (%d): '%s'\n",
747 	      ((m->msg_style > 0) && (m->msg_style <= 4)) ?
748 	       pam_msg_styles[m->msg_style] : pam_msg_styles[0],
749 	       m->msg_style, m->msg);
750 
751 	switch (m->msg_style) {
752 	  case PAM_ERROR_MSG:
753 	      ErrorMessage(login, m->msg, True);
754 	      break;
755 
756 	  case PAM_TEXT_INFO:
757 	      SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
758 	      SetValue (login, promptId, NULL);
759 	      break;
760 
761           case PAM_PROMPT_ECHO_ON:
762 	      pStyle = LOGIN_PROMPT_ECHO_ON;
763 	      /* FALLTHROUGH */
764           case PAM_PROMPT_ECHO_OFF:
765 	      SetPrompt (login, promptId, m->msg, pStyle, False);
766 	      SetValue (login, promptId, NULL);
767 	      greetCode = Greet (d->d, d->greet);
768 	      if (greetCode != 0) {
769 		  status = PAM_CONV_ERR;
770 		  goto pam_error;
771 	      } else {
772 		  r->resp = strdup(GetValue(login, promptId));
773 		  SetValue(login, promptId, NULL);
774 		  if (r->resp == NULL) {
775 		      status = PAM_BUF_ERR;
776 		      goto pam_error;
777 		  }
778 		  /* Debug("pam_resp: '%s'\n", r->resp); */
779 	      }
780 	      break;
781 
782 	  default:
783 	      LogError("Unknown PAM msg_style: %d\n", m->msg_style);
784 	}
785     }
786   pam_error:
787     if (status != PAM_SUCCESS) {
788 	/* free responses */
789 	r = *response;
790 	for (i = 0; i < num_msg; i++, r++) {
791 	    if (r->resp) {
792 		bzero(r->resp, strlen(r->resp));
793 		free(r->resp);
794 	    }
795 	}
796 	free(*response);
797 	*response = NULL;
798     }
799     return status;
800 }
801 #endif
802