greet.c revision 145b7b3c
1145b7b3cSmrg/* $Xorg: greet.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
2145b7b3cSmrg/* $XdotOrg: app/xdm/greeter/greet.c,v 1.5 2006/06/03 01:13:44 alanc Exp $ */
3145b7b3cSmrg/*
4145b7b3cSmrg
5145b7b3cSmrgCopyright 1988, 1998  The Open Group
6145b7b3cSmrg
7145b7b3cSmrgPermission to use, copy, modify, distribute, and sell this software and its
8145b7b3cSmrgdocumentation for any purpose is hereby granted without fee, provided that
9145b7b3cSmrgthe above copyright notice appear in all copies and that both that
10145b7b3cSmrgcopyright notice and this permission notice appear in supporting
11145b7b3cSmrgdocumentation.
12145b7b3cSmrg
13145b7b3cSmrgThe above copyright notice and this permission notice shall be included
14145b7b3cSmrgin all copies or substantial portions of the Software.
15145b7b3cSmrg
16145b7b3cSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17145b7b3cSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18145b7b3cSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19145b7b3cSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
20145b7b3cSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21145b7b3cSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22145b7b3cSmrgOTHER DEALINGS IN THE SOFTWARE.
23145b7b3cSmrg
24145b7b3cSmrgExcept as contained in this notice, the name of The Open Group shall
25145b7b3cSmrgnot be used in advertising or otherwise to promote the sale, use or
26145b7b3cSmrgother dealings in this Software without prior written authorization
27145b7b3cSmrgfrom The Open Group.
28145b7b3cSmrg
29145b7b3cSmrg*/
30145b7b3cSmrg/* Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
31145b7b3cSmrg *
32145b7b3cSmrg * Permission is hereby granted, free of charge, to any person obtaining a
33145b7b3cSmrg * copy of this software and associated documentation files (the
34145b7b3cSmrg * "Software"), to deal in the Software without restriction, including
35145b7b3cSmrg * without limitation the rights to use, copy, modify, merge, publish,
36145b7b3cSmrg * distribute, and/or sell copies of the Software, and to permit persons
37145b7b3cSmrg * to whom the Software is furnished to do so, provided that the above
38145b7b3cSmrg * copyright notice(s) and this permission notice appear in all copies of
39145b7b3cSmrg * the Software and that both the above copyright notice(s) and this
40145b7b3cSmrg * permission notice appear in supporting documentation.
41145b7b3cSmrg *
42145b7b3cSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
43145b7b3cSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44145b7b3cSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
45145b7b3cSmrg * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
46145b7b3cSmrg * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
47145b7b3cSmrg * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
48145b7b3cSmrg * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
49145b7b3cSmrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50145b7b3cSmrg * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51145b7b3cSmrg *
52145b7b3cSmrg * Except as contained in this notice, the name of a copyright holder
53145b7b3cSmrg * shall not be used in advertising or otherwise to promote the sale, use
54145b7b3cSmrg * or other dealings in this Software without prior written authorization
55145b7b3cSmrg * of the copyright holder.
56145b7b3cSmrg */
57145b7b3cSmrg
58145b7b3cSmrg/* $XFree86: xc/programs/xdm/greeter/greet.c,v 3.16tsi Exp $ */
59145b7b3cSmrg
60145b7b3cSmrg/*
61145b7b3cSmrg * xdm - display manager daemon
62145b7b3cSmrg * Author:  Keith Packard, X Consortium
63145b7b3cSmrg *
64145b7b3cSmrg * widget to get username/password
65145b7b3cSmrg *
66145b7b3cSmrg */
67145b7b3cSmrg
68145b7b3cSmrg#ifdef HAVE_CONFIG_H
69145b7b3cSmrg# include "config.h"
70145b7b3cSmrg#endif
71145b7b3cSmrg
72145b7b3cSmrg#include <X11/Intrinsic.h>
73145b7b3cSmrg#include <X11/StringDefs.h>
74145b7b3cSmrg#include <X11/Shell.h>
75145b7b3cSmrg#include <X11/XKBlib.h>
76145b7b3cSmrg
77145b7b3cSmrg#ifdef USE_XINERAMA
78145b7b3cSmrg#include <X11/extensions/Xinerama.h>
79145b7b3cSmrg#endif
80145b7b3cSmrg
81145b7b3cSmrg#include "dm.h"
82145b7b3cSmrg#include "dm_error.h"
83145b7b3cSmrg#include "greet.h"
84145b7b3cSmrg#include "Login.h"
85145b7b3cSmrg
86145b7b3cSmrg#ifdef __OpenBSD__
87145b7b3cSmrg#include <syslog.h>
88145b7b3cSmrg#endif
89145b7b3cSmrg
90145b7b3cSmrg#if defined(SECURE_RPC) && defined(sun)
91145b7b3cSmrg/* Go figure, there's no getdomainname() prototype available */
92145b7b3cSmrgextern int getdomainname(char *name, size_t len);
93145b7b3cSmrg#endif
94145b7b3cSmrg
95145b7b3cSmrg#ifdef GREET_LIB
96145b7b3cSmrg/*
97145b7b3cSmrg * Function pointers filled in by the initial call ito the library
98145b7b3cSmrg */
99145b7b3cSmrg
100145b7b3cSmrgint     (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL;
101145b7b3cSmrgvoid    (*__xdm_SessionPingFailed)(struct display *d) = NULL;
102145b7b3cSmrgvoid    (*__xdm_Debug)(char * fmt, ...) = NULL;
103145b7b3cSmrgvoid    (*__xdm_RegisterCloseOnFork)(int fd) = NULL;
104145b7b3cSmrgvoid    (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL;
105145b7b3cSmrgvoid    (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL;
106145b7b3cSmrgvoid    (*__xdm_ClearCloseOnFork)(int fd) = NULL;
107145b7b3cSmrgvoid    (*__xdm_SetupDisplay)(struct display *d) = NULL;
108145b7b3cSmrgvoid    (*__xdm_LogError)(char * fmt, ...) = NULL;
109145b7b3cSmrgvoid    (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL;
110145b7b3cSmrgvoid    (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL;
111145b7b3cSmrgint     (*__xdm_source)(char **environ, char *file) = NULL;
112145b7b3cSmrgchar    **(*__xdm_defaultEnv)(void) = NULL;
113145b7b3cSmrgchar    **(*__xdm_setEnv)(char **e, char *name, char *value) = NULL;
114145b7b3cSmrgchar    **(*__xdm_putEnv)(const char *string, char **env) = NULL;
115145b7b3cSmrgchar    **(*__xdm_parseArgs)(char **argv, char *string) = NULL;
116145b7b3cSmrgvoid    (*__xdm_printEnv)(char **e) = NULL;
117145b7b3cSmrgchar    **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL;
118145b7b3cSmrgvoid    (*__xdm_LogOutOfMem)(char * fmt, ...) = NULL;
119145b7b3cSmrgvoid    (*__xdm_setgrent)(void) = NULL;
120145b7b3cSmrgstruct group    *(*__xdm_getgrent)(void) = NULL;
121145b7b3cSmrgvoid    (*__xdm_endgrent)(void) = NULL;
122145b7b3cSmrg#ifdef USESHADOW
123145b7b3cSmrgstruct spwd   *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL;
124145b7b3cSmrg# ifndef QNX4
125145b7b3cSmrgvoid   (*__xdm_endspent)(void) = NULL;
126145b7b3cSmrg# endif /* QNX4 doesn't use endspent */
127145b7b3cSmrg#endif
128145b7b3cSmrgstruct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
129145b7b3cSmrg#if defined(linux) || defined(__GLIBC__)
130145b7b3cSmrgvoid   (*__xdm_endpwent)(void) = NULL;
131145b7b3cSmrg#endif
132145b7b3cSmrgchar     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
133145b7b3cSmrg#ifdef USE_PAM
134145b7b3cSmrgpam_handle_t **(*__xdm_thepamhp)(void) = NULL;
135145b7b3cSmrg#endif
136145b7b3cSmrg
137145b7b3cSmrg#endif
138145b7b3cSmrg
139145b7b3cSmrg#ifdef SECURE_RPC
140145b7b3cSmrg#include <rpc/rpc.h>
141145b7b3cSmrg#include <rpc/key_prot.h>
142145b7b3cSmrg#endif
143145b7b3cSmrg
144145b7b3cSmrg#ifdef K5AUTH
145145b7b3cSmrg#include <krb5/krb5.h>
146145b7b3cSmrg#endif
147145b7b3cSmrg
148145b7b3cSmrgextern Display	*dpy;
149145b7b3cSmrg
150145b7b3cSmrgstatic int	done, code;
151145b7b3cSmrg#ifndef USE_PAM
152145b7b3cSmrgstatic char	name[NAME_LEN], password[PASSWORD_LEN];
153145b7b3cSmrg#endif
154145b7b3cSmrgstatic Widget		toplevel;
155145b7b3cSmrgstatic Widget		login;
156145b7b3cSmrgstatic XtAppContext	context;
157145b7b3cSmrgstatic XtIntervalId	pingTimeout;
158145b7b3cSmrg
159145b7b3cSmrg#ifdef USE_PAM
160145b7b3cSmrgstatic int pamconv(int num_msg,
161145b7b3cSmrg#ifndef sun
162145b7b3cSmrg		   const
163145b7b3cSmrg#endif
164145b7b3cSmrg		   struct pam_message **msg,
165145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr);
166145b7b3cSmrg
167145b7b3cSmrg# define PAM_ERROR_PRINT(pamfunc, pamh)	\
168145b7b3cSmrg	LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error))
169145b7b3cSmrg
170145b7b3cSmrg
171145b7b3cSmrgstruct myconv_data {
172145b7b3cSmrg    struct display *d;
173145b7b3cSmrg    struct greet_info *greet;
174145b7b3cSmrg    char *username_display;
175145b7b3cSmrg};
176145b7b3cSmrg#endif
177145b7b3cSmrg
178145b7b3cSmrg
179145b7b3cSmrg/*ARGSUSED*/
180145b7b3cSmrgstatic void
181145b7b3cSmrgGreetPingServer (
182145b7b3cSmrg    XtPointer	    closure,
183145b7b3cSmrg    XtIntervalId    *intervalId)
184145b7b3cSmrg{
185145b7b3cSmrg    struct display *d;
186145b7b3cSmrg
187145b7b3cSmrg    d = (struct display *) closure;
188145b7b3cSmrg    if (!PingServer (d, XtDisplay (toplevel)))
189145b7b3cSmrg	SessionPingFailed (d);
190145b7b3cSmrg    pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
191145b7b3cSmrg				   GreetPingServer, (closure));
192145b7b3cSmrg}
193145b7b3cSmrg
194145b7b3cSmrg/*ARGSUSED*/
195145b7b3cSmrgstatic void
196145b7b3cSmrgGreetDone (
197145b7b3cSmrg    Widget	w,
198145b7b3cSmrg    LoginData	*data,
199145b7b3cSmrg    int		status)
200145b7b3cSmrg{
201145b7b3cSmrg    Debug ("GreetDone: %s, (password is %d long)\n",
202145b7b3cSmrg	    data->name, strlen (data->passwd));
203145b7b3cSmrg    switch (status) {
204145b7b3cSmrg    case NOTIFY_OK:
205145b7b3cSmrg#ifndef USE_PAM
206145b7b3cSmrg	strncpy (name, data->name, sizeof(name));
207145b7b3cSmrg	name[sizeof(name)-1] = '\0';
208145b7b3cSmrg	strncpy (password, data->passwd, sizeof(password));
209145b7b3cSmrg	password[sizeof(password)-1] = '\0';
210145b7b3cSmrg#endif
211145b7b3cSmrg	code = 0;
212145b7b3cSmrg	done = 1;
213145b7b3cSmrg	break;
214145b7b3cSmrg    case NOTIFY_ABORT:
215145b7b3cSmrg	Debug ("RESERVER_DISPLAY\n");
216145b7b3cSmrg	code = RESERVER_DISPLAY;
217145b7b3cSmrg	done = 1;
218145b7b3cSmrg	break;
219145b7b3cSmrg    case NOTIFY_RESTART:
220145b7b3cSmrg	Debug ("REMANAGE_DISPLAY\n");
221145b7b3cSmrg	code = REMANAGE_DISPLAY;
222145b7b3cSmrg	done = 1;
223145b7b3cSmrg	break;
224145b7b3cSmrg    case NOTIFY_ABORT_DISPLAY:
225145b7b3cSmrg	Debug ("UNMANAGE_DISPLAY\n");
226145b7b3cSmrg	code = UNMANAGE_DISPLAY;
227145b7b3cSmrg	done = 1;
228145b7b3cSmrg	break;
229145b7b3cSmrg    }
230145b7b3cSmrg#ifndef USE_PAM
231145b7b3cSmrg    if (done) {
232145b7b3cSmrg	bzero (data->name, NAME_LEN);
233145b7b3cSmrg	bzero (data->passwd, PASSWORD_LEN);
234145b7b3cSmrg    }
235145b7b3cSmrg#endif
236145b7b3cSmrg}
237145b7b3cSmrg
238145b7b3cSmrgstatic Display *
239145b7b3cSmrgInitGreet (struct display *d)
240145b7b3cSmrg{
241145b7b3cSmrg    Arg		arglist[10];
242145b7b3cSmrg    int		i;
243145b7b3cSmrg    static int	argc;
244145b7b3cSmrg    Screen		*scrn;
245145b7b3cSmrg    static char	*argv[] = { "xlogin", NULL };
246145b7b3cSmrg    Display		*dpy;
247145b7b3cSmrg#ifdef USE_XINERAMA
248145b7b3cSmrg    XineramaScreenInfo *screens;
249145b7b3cSmrg    int                 s_num;
250145b7b3cSmrg#endif
251145b7b3cSmrg
252145b7b3cSmrg    Debug ("greet %s\n", d->name);
253145b7b3cSmrg    argc = 1;
254145b7b3cSmrg    XtToolkitInitialize ();
255145b7b3cSmrg    context = XtCreateApplicationContext();
256145b7b3cSmrg    dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0,
257145b7b3cSmrg			 &argc, argv);
258145b7b3cSmrg
259145b7b3cSmrg    if (!dpy)
260145b7b3cSmrg	return NULL;
261145b7b3cSmrg
262145b7b3cSmrg#ifdef XKB
263145b7b3cSmrg    {
264145b7b3cSmrg    int opcode, evbase, errbase, majret, minret;
265145b7b3cSmrg    unsigned int value = XkbPCF_GrabsUseXKBStateMask;
266145b7b3cSmrg    if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) {
267145b7b3cSmrg	if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value))
268145b7b3cSmrg	    LogError ("%s\n", "SetPerClientControls failed");
269145b7b3cSmrg    }
270145b7b3cSmrg    }
271145b7b3cSmrg#endif
272145b7b3cSmrg    RegisterCloseOnFork (ConnectionNumber (dpy));
273145b7b3cSmrg
274145b7b3cSmrg    SecureDisplay (d, dpy);
275145b7b3cSmrg
276145b7b3cSmrg    i = 0;
277145b7b3cSmrg    scrn = XDefaultScreenOfDisplay(dpy);
278145b7b3cSmrg    XtSetArg(arglist[i], XtNscreen, scrn);	i++;
279145b7b3cSmrg    XtSetArg(arglist[i], XtNargc, argc);	i++;
280145b7b3cSmrg    XtSetArg(arglist[i], XtNargv, argv);	i++;
281145b7b3cSmrg
282145b7b3cSmrg    toplevel = XtAppCreateShell ((String) NULL, "Xlogin",
283145b7b3cSmrg		    applicationShellWidgetClass, dpy, arglist, i);
284145b7b3cSmrg
285145b7b3cSmrg    i = 0;
286145b7b3cSmrg    XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++;
287145b7b3cSmrg    if (!d->authorize || d->authorizations || !d->authComplain)
288145b7b3cSmrg    {
289145b7b3cSmrg	XtSetArg (arglist[i], XtNsecureSession, True); i++;
290145b7b3cSmrg    }
291145b7b3cSmrg    login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel,
292145b7b3cSmrg				    arglist, i);
293145b7b3cSmrg    XtRealizeWidget (toplevel);
294145b7b3cSmrg
295145b7b3cSmrg#ifdef USE_XINERAMA
296145b7b3cSmrg    if (
297145b7b3cSmrg	XineramaIsActive(dpy) &&
298145b7b3cSmrg	(screens = XineramaQueryScreens(dpy, &s_num)) != NULL
299145b7b3cSmrg       )
300145b7b3cSmrg    {
301145b7b3cSmrg	XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
302145b7b3cSmrg			0, 0, 0, 0,
303145b7b3cSmrg			screens[0].x_org + screens[0].width / 2,
304145b7b3cSmrg			screens[0].y_org + screens[0].height / 2);
305145b7b3cSmrg
306145b7b3cSmrg	XFree(screens);
307145b7b3cSmrg    }
308145b7b3cSmrg    else
309145b7b3cSmrg#endif
310145b7b3cSmrg    XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
311145b7b3cSmrg		    0, 0, 0, 0,
312145b7b3cSmrg		    XWidthOfScreen(scrn) / 2,
313145b7b3cSmrg		    XHeightOfScreen(scrn) / 2);
314145b7b3cSmrg
315145b7b3cSmrg    if (d->pingInterval)
316145b7b3cSmrg    {
317145b7b3cSmrg    	pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
318145b7b3cSmrg				       GreetPingServer, (XtPointer) d);
319145b7b3cSmrg    }
320145b7b3cSmrg    return dpy;
321145b7b3cSmrg}
322145b7b3cSmrg
323145b7b3cSmrgstatic void
324145b7b3cSmrgCloseGreet (struct display *d)
325145b7b3cSmrg{
326145b7b3cSmrg    Boolean	    allow;
327145b7b3cSmrg    Arg	    arglist[1];
328145b7b3cSmrg    Display *dpy = XtDisplay(toplevel);
329145b7b3cSmrg
330145b7b3cSmrg    if (pingTimeout)
331145b7b3cSmrg    {
332145b7b3cSmrg	XtRemoveTimeOut (pingTimeout);
333145b7b3cSmrg	pingTimeout = 0;
334145b7b3cSmrg    }
335145b7b3cSmrg    UnsecureDisplay (d, dpy);
336145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
337145b7b3cSmrg    XtGetValues (login, arglist, 1);
338145b7b3cSmrg    if (allow)
339145b7b3cSmrg    {
340145b7b3cSmrg	Debug ("Disabling access control\n");
341145b7b3cSmrg	XSetAccessControl (dpy, DisableAccess);
342145b7b3cSmrg    }
343145b7b3cSmrg    XtDestroyWidget (toplevel);
344145b7b3cSmrg    ClearCloseOnFork (XConnectionNumber (dpy));
345145b7b3cSmrg    XCloseDisplay (dpy);
346145b7b3cSmrg    Debug ("Greet connection closed\n");
347145b7b3cSmrg}
348145b7b3cSmrg
349145b7b3cSmrg#define WHITESPACE 0
350145b7b3cSmrg#define ARGUMENT 1
351145b7b3cSmrg
352145b7b3cSmrgstatic int
353145b7b3cSmrgGreet (struct display *d, struct greet_info *greet)
354145b7b3cSmrg{
355145b7b3cSmrg    XEvent		event;
356145b7b3cSmrg    Arg		arglist[3];
357145b7b3cSmrg
358145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, False);
359145b7b3cSmrg    XtSetValues (login, arglist, 1);
360145b7b3cSmrg
361145b7b3cSmrg    Debug ("dispatching %s\n", d->name);
362145b7b3cSmrg    done = 0;
363145b7b3cSmrg    while (!done) {
364145b7b3cSmrg	XtAppNextEvent (context, &event);
365145b7b3cSmrg	switch (event.type) {
366145b7b3cSmrg	case MappingNotify:
367145b7b3cSmrg	    XRefreshKeyboardMapping(&event.xmapping);
368145b7b3cSmrg	    break;
369145b7b3cSmrg	default:
370145b7b3cSmrg	    XtDispatchEvent (&event);
371145b7b3cSmrg	    break;
372145b7b3cSmrg	}
373145b7b3cSmrg    }
374145b7b3cSmrg    XFlush (XtDisplay (toplevel));
375145b7b3cSmrg    Debug ("Done dispatch %s\n", d->name);
376145b7b3cSmrg    if (code == 0)
377145b7b3cSmrg    {
378145b7b3cSmrg#ifndef USE_PAM
379145b7b3cSmrg	char *ptr;
380145b7b3cSmrg	unsigned int c,state = WHITESPACE;
381145b7b3cSmrg
382145b7b3cSmrg	/*
383145b7b3cSmrg	 * Process the name string to get rid of white spaces.
384145b7b3cSmrg	 */
385145b7b3cSmrg	for (ptr = name; state == WHITESPACE; ptr++)
386145b7b3cSmrg	{
387145b7b3cSmrg	    c = (unsigned int)(*ptr);
388145b7b3cSmrg	    if (c == ' ')
389145b7b3cSmrg		continue;
390145b7b3cSmrg
391145b7b3cSmrg	    state = ARGUMENT;
392145b7b3cSmrg	    break;
393145b7b3cSmrg	}
394145b7b3cSmrg
395145b7b3cSmrg	greet->name = ptr;
396145b7b3cSmrg	greet->password = password;
397145b7b3cSmrg#endif  /* USE_PAM */
398145b7b3cSmrg	XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string));
399145b7b3cSmrg	XtSetArg (arglist[1], XtNallowNullPasswd, (char *) &(greet->allow_null_passwd));
400145b7b3cSmrg	XtSetArg (arglist[2], XtNallowRootLogin, (char *) &(greet->allow_root_login));
401145b7b3cSmrg	XtGetValues (login, arglist, 3);
402145b7b3cSmrg	Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>");
403145b7b3cSmrg    }
404145b7b3cSmrg    return code;
405145b7b3cSmrg}
406145b7b3cSmrg
407145b7b3cSmrg
408145b7b3cSmrgstatic void
409145b7b3cSmrgFailedLogin (struct display *d, struct greet_info *greet)
410145b7b3cSmrg{
411145b7b3cSmrg#ifdef __OpenBSD__
412145b7b3cSmrg    syslog(LOG_NOTICE, "LOGIN FAILURE ON %s",
413145b7b3cSmrg	   d->name);
414145b7b3cSmrg    syslog(LOG_AUTHPRIV|LOG_NOTICE,
415145b7b3cSmrg	   "LOGIN FAILURE ON %s, %s",
416145b7b3cSmrg	   d->name, greet->name);
417145b7b3cSmrg#endif
418145b7b3cSmrg    DrawFail (login);
419145b7b3cSmrg#ifndef USE_PAM
420145b7b3cSmrg    bzero (greet->name, strlen(greet->name));
421145b7b3cSmrg    bzero (greet->password, strlen(greet->password));
422145b7b3cSmrg#endif
423145b7b3cSmrg}
424145b7b3cSmrg
425145b7b3cSmrg_X_EXPORT
426145b7b3cSmrggreet_user_rtn GreetUser(
427145b7b3cSmrg    struct display          *d,
428145b7b3cSmrg    Display                 ** dpy,
429145b7b3cSmrg    struct verify_info      *verify,
430145b7b3cSmrg    struct greet_info       *greet,
431145b7b3cSmrg    struct dlfuncs        *dlfuncs)
432145b7b3cSmrg{
433145b7b3cSmrg    int i;
434145b7b3cSmrg
435145b7b3cSmrg#ifdef GREET_LIB
436145b7b3cSmrg/*
437145b7b3cSmrg * These must be set before they are used.
438145b7b3cSmrg */
439145b7b3cSmrg    __xdm_PingServer = dlfuncs->_PingServer;
440145b7b3cSmrg    __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed;
441145b7b3cSmrg    __xdm_Debug = dlfuncs->_Debug;
442145b7b3cSmrg    __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork;
443145b7b3cSmrg    __xdm_SecureDisplay = dlfuncs->_SecureDisplay;
444145b7b3cSmrg    __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay;
445145b7b3cSmrg    __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork;
446145b7b3cSmrg    __xdm_SetupDisplay = dlfuncs->_SetupDisplay;
447145b7b3cSmrg    __xdm_LogError = dlfuncs->_LogError;
448145b7b3cSmrg    __xdm_SessionExit = dlfuncs->_SessionExit;
449145b7b3cSmrg    __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources;
450145b7b3cSmrg    __xdm_source = dlfuncs->_source;
451145b7b3cSmrg    __xdm_defaultEnv = dlfuncs->_defaultEnv;
452145b7b3cSmrg    __xdm_setEnv = dlfuncs->_setEnv;
453145b7b3cSmrg    __xdm_putEnv = dlfuncs->_putEnv;
454145b7b3cSmrg    __xdm_parseArgs = dlfuncs->_parseArgs;
455145b7b3cSmrg    __xdm_printEnv = dlfuncs->_printEnv;
456145b7b3cSmrg    __xdm_systemEnv = dlfuncs->_systemEnv;
457145b7b3cSmrg    __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem;
458145b7b3cSmrg    __xdm_setgrent = dlfuncs->_setgrent;
459145b7b3cSmrg    __xdm_getgrent = dlfuncs->_getgrent;
460145b7b3cSmrg    __xdm_endgrent = dlfuncs->_endgrent;
461145b7b3cSmrg#ifdef USESHADOW
462145b7b3cSmrg    __xdm_getspnam = dlfuncs->_getspnam;
463145b7b3cSmrg# ifndef QNX4
464145b7b3cSmrg    __xdm_endspent = dlfuncs->_endspent;
465145b7b3cSmrg# endif /* QNX4 doesn't use endspent */
466145b7b3cSmrg#endif
467145b7b3cSmrg    __xdm_getpwnam = dlfuncs->_getpwnam;
468145b7b3cSmrg#if defined(linux) || defined(__GLIBC__)
469145b7b3cSmrg    __xdm_endpwent = dlfuncs->_endpwent;
470145b7b3cSmrg#endif
471145b7b3cSmrg    __xdm_crypt = dlfuncs->_crypt;
472145b7b3cSmrg#ifdef USE_PAM
473145b7b3cSmrg    __xdm_thepamhp = dlfuncs->_thepamhp;
474145b7b3cSmrg#endif
475145b7b3cSmrg#endif
476145b7b3cSmrg
477145b7b3cSmrg    *dpy = InitGreet (d);
478145b7b3cSmrg    /*
479145b7b3cSmrg     * Run the setup script - note this usually will not work when
480145b7b3cSmrg     * the server is grabbed, so we don't even bother trying.
481145b7b3cSmrg     */
482145b7b3cSmrg    if (!d->grabServer)
483145b7b3cSmrg	SetupDisplay (d);
484145b7b3cSmrg    if (!*dpy) {
485145b7b3cSmrg	LogError ("Cannot reopen display %s for greet window\n", d->name);
486145b7b3cSmrg	exit (RESERVER_DISPLAY);
487145b7b3cSmrg    }
488145b7b3cSmrg#ifdef __OpenBSD__
489145b7b3cSmrg    openlog("xdm", LOG_ODELAY, LOG_AUTH);
490145b7b3cSmrg#endif
491145b7b3cSmrg
492145b7b3cSmrg    for (;;) {
493145b7b3cSmrg#ifdef USE_PAM
494145b7b3cSmrg
495145b7b3cSmrg	/* Run PAM conversation */
496145b7b3cSmrg	pam_handle_t 	**pamhp		= thepamhp();
497145b7b3cSmrg	int		  pam_error;
498145b7b3cSmrg	unsigned int	  pam_flags 	= 0;
499145b7b3cSmrg	struct myconv_data pcd		= { d, greet, NULL };
500145b7b3cSmrg	struct pam_conv   pc 		= { pamconv, &pcd };
501145b7b3cSmrg	const char *	  pam_fname;
502145b7b3cSmrg	char *		  username;
503145b7b3cSmrg	const char *	  login_prompt;
504145b7b3cSmrg
505145b7b3cSmrg
506145b7b3cSmrg	SetPrompt(login, 0, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
507145b7b3cSmrg	login_prompt  = GetPrompt(login, LOGIN_PROMPT_USERNAME);
508145b7b3cSmrg	SetPrompt(login, 1, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
509145b7b3cSmrg
510145b7b3cSmrg#define RUN_AND_CHECK_PAM_ERROR(function, args)			\
511145b7b3cSmrg	    do { 						\
512145b7b3cSmrg		pam_error = function args;			\
513145b7b3cSmrg		if (pam_error != PAM_SUCCESS) {			\
514145b7b3cSmrg		    PAM_ERROR_PRINT(#function, *pamhp);		\
515145b7b3cSmrg		    goto pam_done;				\
516145b7b3cSmrg		} 						\
517145b7b3cSmrg	    } while (0)
518145b7b3cSmrg
519145b7b3cSmrg
520145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_start,
521145b7b3cSmrg				("xdm", NULL, &pc, pamhp));
522145b7b3cSmrg
523145b7b3cSmrg	/* Set default login prompt to xdm's default from Xresources */
524145b7b3cSmrg	if (login_prompt != NULL) {
525145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item,
526145b7b3cSmrg				    (*pamhp, PAM_USER_PROMPT, login_prompt));
527145b7b3cSmrg	}
528145b7b3cSmrg
529145b7b3cSmrg	if (d->name[0] != ':') {	/* Displaying to remote host */
530145b7b3cSmrg	    char *hostname = strdup(d->name);
531145b7b3cSmrg
532145b7b3cSmrg	    if (hostname == NULL) {
533145b7b3cSmrg		LogOutOfMem("GreetUser");
534145b7b3cSmrg	    } else {
535145b7b3cSmrg		char *colon = strrchr(hostname, ':');
536145b7b3cSmrg
537145b7b3cSmrg		if (colon != NULL)
538145b7b3cSmrg		    *colon = '\0';
539145b7b3cSmrg
540145b7b3cSmrg		RUN_AND_CHECK_PAM_ERROR(pam_set_item,
541145b7b3cSmrg					(*pamhp, PAM_RHOST, hostname));
542145b7b3cSmrg		free(hostname);
543145b7b3cSmrg	    }
544145b7b3cSmrg	} else
545145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, d->name));
546145b7b3cSmrg
547145b7b3cSmrg	if (!greet->allow_null_passwd) {
548145b7b3cSmrg	    pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
549145b7b3cSmrg	}
550145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_authenticate,
551145b7b3cSmrg				(*pamhp, pam_flags));
552145b7b3cSmrg
553145b7b3cSmrg	/* handle expired passwords */
554145b7b3cSmrg	pam_error = pam_acct_mgmt(*pamhp, pam_flags);
555145b7b3cSmrg	pam_fname = "pam_acct_mgmt";
556145b7b3cSmrg	if (pam_error == PAM_NEW_AUTHTOK_REQD) {
557145b7b3cSmrg	    ShowChangePasswdMessage(login);
558145b7b3cSmrg	    do {
559145b7b3cSmrg		pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK);
560145b7b3cSmrg	    } while ((pam_error == PAM_AUTHTOK_ERR) ||
561145b7b3cSmrg		     (pam_error == PAM_TRY_AGAIN));
562145b7b3cSmrg	    pam_fname = "pam_chauthtok";
563145b7b3cSmrg	}
564145b7b3cSmrg	if (pam_error != PAM_SUCCESS) {
565145b7b3cSmrg	    PAM_ERROR_PRINT(pam_fname, *pamhp);
566145b7b3cSmrg	    goto pam_done;
567145b7b3cSmrg	}
568145b7b3cSmrg
569145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_setcred,
570145b7b3cSmrg				(*pamhp, 0));
571145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_get_item,
572145b7b3cSmrg				(*pamhp, PAM_USER, (void *) &username));
573145b7b3cSmrg	if (username != NULL) {
574145b7b3cSmrg	    Debug("PAM_USER: %s\n", username);
575145b7b3cSmrg	    greet->name = username;
576145b7b3cSmrg	    greet->password = NULL;
577145b7b3cSmrg	}
578145b7b3cSmrg
579145b7b3cSmrg      pam_done:
580145b7b3cSmrg	if (code != 0)
581145b7b3cSmrg	{
582145b7b3cSmrg	    CloseGreet (d);
583145b7b3cSmrg	    SessionExit (d, code, FALSE);
584145b7b3cSmrg	}
585145b7b3cSmrg	if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) {
586145b7b3cSmrg	    SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False);
587145b7b3cSmrg	    SetValue (login, 1, NULL);
588145b7b3cSmrg	    break;
589145b7b3cSmrg	} else {
590145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_end,
591145b7b3cSmrg				    (*pamhp, pam_error));
592145b7b3cSmrg	    FailedLogin (d, greet);
593145b7b3cSmrg	}
594145b7b3cSmrg#else /* not PAM */
595145b7b3cSmrg	/*
596145b7b3cSmrg	 * Greet user, requesting name/password
597145b7b3cSmrg	 */
598145b7b3cSmrg	code = Greet (d, greet);
599145b7b3cSmrg	if (code != 0)
600145b7b3cSmrg	{
601145b7b3cSmrg	    CloseGreet (d);
602145b7b3cSmrg	    SessionExit (d, code, FALSE);
603145b7b3cSmrg	}
604145b7b3cSmrg	/*
605145b7b3cSmrg	 * Verify user
606145b7b3cSmrg	 */
607145b7b3cSmrg	if (Verify (d, greet, verify))
608145b7b3cSmrg	    break;
609145b7b3cSmrg	else
610145b7b3cSmrg	    FailedLogin (d, greet);
611145b7b3cSmrg#endif
612145b7b3cSmrg    }
613145b7b3cSmrg    DeleteXloginResources (d, *dpy);
614145b7b3cSmrg    CloseGreet (d);
615145b7b3cSmrg    Debug ("Greet loop finished\n");
616145b7b3cSmrg    /*
617145b7b3cSmrg     * Run system-wide initialization file
618145b7b3cSmrg     */
619145b7b3cSmrg    if (source (verify->systemEnviron, d->startup) != 0)
620145b7b3cSmrg    {
621145b7b3cSmrg	Debug ("Startup program %s exited with non-zero status\n",
622145b7b3cSmrg		d->startup);
623145b7b3cSmrg	SessionExit (d, OBEYSESS_DISPLAY, FALSE);
624145b7b3cSmrg    }
625145b7b3cSmrg    /*
626145b7b3cSmrg     * for user-based authorization schemes,
627145b7b3cSmrg     * add the user to the server's allowed "hosts" list.
628145b7b3cSmrg     */
629145b7b3cSmrg    for (i = 0; i < d->authNum; i++)
630145b7b3cSmrg    {
631145b7b3cSmrg#ifdef SECURE_RPC
632145b7b3cSmrg	if (d->authorizations[i]->name_length == 9 &&
633145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
634145b7b3cSmrg	{
635145b7b3cSmrg	    XHostAddress	addr;
636145b7b3cSmrg	    char		netname[MAXNETNAMELEN+1];
637145b7b3cSmrg	    char		domainname[MAXNETNAMELEN+1];
638145b7b3cSmrg
639145b7b3cSmrg	    getdomainname(domainname, sizeof domainname);
640145b7b3cSmrg	    user2netname (netname, verify->uid, domainname);
641145b7b3cSmrg	    addr.family = FamilyNetname;
642145b7b3cSmrg	    addr.length = strlen (netname);
643145b7b3cSmrg	    addr.address = netname;
644145b7b3cSmrg	    XAddHost (*dpy, &addr);
645145b7b3cSmrg	}
646145b7b3cSmrg#endif
647145b7b3cSmrg#ifdef K5AUTH
648145b7b3cSmrg	if (d->authorizations[i]->name_length == 14 &&
649145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
650145b7b3cSmrg	{
651145b7b3cSmrg	    /* Update server's auth file with user-specific info.
652145b7b3cSmrg	     * Don't need to AddHost because X server will do that
653145b7b3cSmrg	     * automatically when it reads the cache we are about
654145b7b3cSmrg	     * to point it at.
655145b7b3cSmrg	     */
656145b7b3cSmrg	    extern Xauth *Krb5GetAuthFor();
657145b7b3cSmrg
658145b7b3cSmrg	    XauDisposeAuth (d->authorizations[i]);
659145b7b3cSmrg	    d->authorizations[i] =
660145b7b3cSmrg		Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
661145b7b3cSmrg	    SaveServerAuthorizations (d, d->authorizations, d->authNum);
662145b7b3cSmrg	}
663145b7b3cSmrg#endif
664145b7b3cSmrg    }
665145b7b3cSmrg
666145b7b3cSmrg    return Greet_Success;
667145b7b3cSmrg}
668145b7b3cSmrg
669145b7b3cSmrg
670145b7b3cSmrg#ifdef USE_PAM
671145b7b3cSmrgstatic int pamconv(int num_msg,
672145b7b3cSmrg#ifndef sun
673145b7b3cSmrg		   const
674145b7b3cSmrg#endif
675145b7b3cSmrg		   struct pam_message **msg,
676145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr)
677145b7b3cSmrg{
678145b7b3cSmrg    int i;
679145b7b3cSmrg    int greetCode;
680145b7b3cSmrg    int status = PAM_SUCCESS;
681145b7b3cSmrg    const char *pam_msg_styles[5]
682145b7b3cSmrg	= { "<invalid pam msg style>",
683145b7b3cSmrg	    "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
684145b7b3cSmrg	    "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
685145b7b3cSmrg
686145b7b3cSmrg    struct pam_message      *m;
687145b7b3cSmrg    struct pam_response     *r;
688145b7b3cSmrg
689145b7b3cSmrg    struct myconv_data	    *d = (struct myconv_data *) appdata_ptr;
690145b7b3cSmrg
691145b7b3cSmrg    pam_handle_t	    **pamhp = thepamhp();
692145b7b3cSmrg
693145b7b3cSmrg    *response = calloc(num_msg, sizeof (struct pam_response));
694145b7b3cSmrg    if (*response == NULL)
695145b7b3cSmrg	return (PAM_BUF_ERR);
696145b7b3cSmrg
697145b7b3cSmrg    m = *msg;
698145b7b3cSmrg    r = *response;
699145b7b3cSmrg
700145b7b3cSmrg    for (i = 0; i < num_msg; i++ , m++ , r++) {
701145b7b3cSmrg	char *username;
702145b7b3cSmrg	int promptId = 0;
703145b7b3cSmrg	loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
704145b7b3cSmrg
705145b7b3cSmrg	if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS)
706145b7b3cSmrg	    && (username != NULL) && (*username != '\0')) {
707145b7b3cSmrg	    SetPrompt(login, LOGIN_PROMPT_USERNAME,
708145b7b3cSmrg		      NULL, LOGIN_TEXT_INFO, False);
709145b7b3cSmrg	    SetValue(login, LOGIN_PROMPT_USERNAME, username);
710145b7b3cSmrg	    promptId = 1;
711145b7b3cSmrg	}
712145b7b3cSmrg
713145b7b3cSmrg	Debug("pam_msg: %s (%d): '%s'\n",
714145b7b3cSmrg	      ((m->msg_style > 0) && (m->msg_style <= 4)) ?
715145b7b3cSmrg	       pam_msg_styles[m->msg_style] : pam_msg_styles[0],
716145b7b3cSmrg	       m->msg_style, m->msg);
717145b7b3cSmrg
718145b7b3cSmrg	switch (m->msg_style) {
719145b7b3cSmrg	  case PAM_ERROR_MSG:
720145b7b3cSmrg	      ErrorMessage(login, m->msg, True);
721145b7b3cSmrg	      break;
722145b7b3cSmrg
723145b7b3cSmrg	  case PAM_TEXT_INFO:
724145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
725145b7b3cSmrg	      SetValue (login, promptId, NULL);
726145b7b3cSmrg	      break;
727145b7b3cSmrg
728145b7b3cSmrg          case PAM_PROMPT_ECHO_ON:
729145b7b3cSmrg	      pStyle = LOGIN_PROMPT_ECHO_ON;
730145b7b3cSmrg	      /* FALLTHROUGH */
731145b7b3cSmrg          case PAM_PROMPT_ECHO_OFF:
732145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, pStyle, False);
733145b7b3cSmrg	      SetValue (login, promptId, NULL);
734145b7b3cSmrg	      greetCode = Greet (d->d, d->greet);
735145b7b3cSmrg	      if (greetCode != 0) {
736145b7b3cSmrg		  status = PAM_CONV_ERR;
737145b7b3cSmrg		  goto pam_error;
738145b7b3cSmrg	      } else {
739145b7b3cSmrg		  r->resp = strdup(GetValue(login, promptId));
740145b7b3cSmrg		  SetValue(login, promptId, NULL);
741145b7b3cSmrg		  if (r->resp == NULL) {
742145b7b3cSmrg		      status = PAM_BUF_ERR;
743145b7b3cSmrg		      goto pam_error;
744145b7b3cSmrg		  }
745145b7b3cSmrg		  /* Debug("pam_resp: '%s'\n", r->resp); */
746145b7b3cSmrg	      }
747145b7b3cSmrg	      break;
748145b7b3cSmrg
749145b7b3cSmrg	  default:
750145b7b3cSmrg	      LogError("Unknown PAM msg_style: %d\n", m->msg_style);
751145b7b3cSmrg	}
752145b7b3cSmrg    }
753145b7b3cSmrg  pam_error:
754145b7b3cSmrg    if (status != PAM_SUCCESS) {
755145b7b3cSmrg	/* free responses */
756145b7b3cSmrg	r = *response;
757145b7b3cSmrg	for (i = 0; i < num_msg; i++, r++) {
758145b7b3cSmrg	    if (r->resp) {
759145b7b3cSmrg		bzero(r->resp, strlen(r->resp));
760145b7b3cSmrg		free(r->resp);
761145b7b3cSmrg	    }
762145b7b3cSmrg	}
763145b7b3cSmrg	free(*response);
764145b7b3cSmrg	*response = NULL;
765145b7b3cSmrg    }
766145b7b3cSmrg    return status;
767145b7b3cSmrg}
768145b7b3cSmrg#endif
769