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