greet.c revision 43b4c634
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*/
2843b4c634Smrg/*
2943b4c634Smrg * Copyright © 2006 Sun Microsystems, Inc.  All rights reserved.
30145b7b3cSmrg *
31145b7b3cSmrg * Permission is hereby granted, free of charge, to any person obtaining a
3243b4c634Smrg * copy of this software and associated documentation files (the "Software"),
3343b4c634Smrg * to deal in the Software without restriction, including without limitation
3443b4c634Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3543b4c634Smrg * and/or sell copies of the Software, and to permit persons to whom the
3643b4c634Smrg * Software is furnished to do so, subject to the following conditions:
37145b7b3cSmrg *
3843b4c634Smrg * The above copyright notice and this permission notice (including the next
3943b4c634Smrg * paragraph) shall be included in all copies or substantial portions of the
4043b4c634Smrg * Software.
41145b7b3cSmrg *
4243b4c634Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4343b4c634Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4443b4c634Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
4543b4c634Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4643b4c634Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
4743b4c634Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
4843b4c634Smrg * DEALINGS IN THE SOFTWARE.
49145b7b3cSmrg */
50145b7b3cSmrg
51145b7b3cSmrg
52145b7b3cSmrg/*
53145b7b3cSmrg * xdm - display manager daemon
54145b7b3cSmrg * Author:  Keith Packard, X Consortium
55145b7b3cSmrg *
56145b7b3cSmrg * widget to get username/password
57145b7b3cSmrg *
58145b7b3cSmrg */
59145b7b3cSmrg
60145b7b3cSmrg#ifdef HAVE_CONFIG_H
61145b7b3cSmrg# include "config.h"
62145b7b3cSmrg#endif
63145b7b3cSmrg
64145b7b3cSmrg#include <X11/Intrinsic.h>
65145b7b3cSmrg#include <X11/StringDefs.h>
66145b7b3cSmrg#include <X11/Shell.h>
67145b7b3cSmrg#include <X11/XKBlib.h>
68145b7b3cSmrg
69145b7b3cSmrg#ifdef USE_XINERAMA
7039826d68Smrg# include <X11/extensions/Xinerama.h>
71145b7b3cSmrg#endif
72145b7b3cSmrg
73145b7b3cSmrg#include "dm.h"
74145b7b3cSmrg#include "dm_error.h"
75145b7b3cSmrg#include "greet.h"
7643b4c634Smrg#include "LoginP.h"
77145b7b3cSmrg
7839826d68Smrg#if defined(HAVE_OPENLOG) && defined(HAVE_SYSLOG_H)
7939826d68Smrg# define USE_SYSLOG
8039826d68Smrg# include <syslog.h>
8139826d68Smrg# ifndef LOG_AUTHPRIV
8239826d68Smrg#  define LOG_AUTHPRIV LOG_AUTH
8339826d68Smrg# endif
8439826d68Smrg# ifndef LOG_PID
8539826d68Smrg#  define LOG_PID 0
8639826d68Smrg# endif
87145b7b3cSmrg#endif
88145b7b3cSmrg
8939826d68Smrg#include <string.h>
9039826d68Smrg
91145b7b3cSmrg#if defined(SECURE_RPC) && defined(sun)
92145b7b3cSmrg/* Go figure, there's no getdomainname() prototype available */
93145b7b3cSmrgextern int getdomainname(char *name, size_t len);
94145b7b3cSmrg#endif
95145b7b3cSmrg
96145b7b3cSmrg#ifdef GREET_LIB
97145b7b3cSmrg/*
98145b7b3cSmrg * Function pointers filled in by the initial call ito the library
99145b7b3cSmrg */
100145b7b3cSmrg
101145b7b3cSmrgint     (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL;
102145b7b3cSmrgvoid    (*__xdm_SessionPingFailed)(struct display *d) = NULL;
10339826d68Smrgvoid    (*__xdm_Debug)(const char * fmt, ...) = NULL;
104145b7b3cSmrgvoid    (*__xdm_RegisterCloseOnFork)(int fd) = NULL;
105145b7b3cSmrgvoid    (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL;
106145b7b3cSmrgvoid    (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL;
107145b7b3cSmrgvoid    (*__xdm_ClearCloseOnFork)(int fd) = NULL;
108145b7b3cSmrgvoid    (*__xdm_SetupDisplay)(struct display *d) = NULL;
10939826d68Smrgvoid    (*__xdm_LogError)(const char * fmt, ...) = NULL;
110145b7b3cSmrgvoid    (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL;
111145b7b3cSmrgvoid    (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL;
112145b7b3cSmrgint     (*__xdm_source)(char **environ, char *file) = NULL;
113145b7b3cSmrgchar    **(*__xdm_defaultEnv)(void) = NULL;
114145b7b3cSmrgchar    **(*__xdm_setEnv)(char **e, char *name, char *value) = NULL;
115145b7b3cSmrgchar    **(*__xdm_putEnv)(const char *string, char **env) = NULL;
116145b7b3cSmrgchar    **(*__xdm_parseArgs)(char **argv, char *string) = NULL;
117145b7b3cSmrgvoid    (*__xdm_printEnv)(char **e) = NULL;
118145b7b3cSmrgchar    **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL;
11939826d68Smrgvoid    (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL;
120145b7b3cSmrgvoid    (*__xdm_setgrent)(void) = NULL;
121145b7b3cSmrgstruct group    *(*__xdm_getgrent)(void) = NULL;
122145b7b3cSmrgvoid    (*__xdm_endgrent)(void) = NULL;
12339826d68Smrg# ifdef USESHADOW
124145b7b3cSmrgstruct spwd   *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL;
12539826d68Smrg#  ifndef QNX4
126145b7b3cSmrgvoid   (*__xdm_endspent)(void) = NULL;
12739826d68Smrg#  endif /* QNX4 doesn't use endspent */
12839826d68Smrg# endif
129145b7b3cSmrgstruct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
13039826d68Smrg# if defined(linux) || defined(__GLIBC__)
131145b7b3cSmrgvoid   (*__xdm_endpwent)(void) = NULL;
13239826d68Smrg# endif
133145b7b3cSmrgchar     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
13439826d68Smrg# ifdef USE_PAM
135145b7b3cSmrgpam_handle_t **(*__xdm_thepamhp)(void) = NULL;
13639826d68Smrg# endif
137145b7b3cSmrg
138145b7b3cSmrg#endif
139145b7b3cSmrg
140145b7b3cSmrg#ifdef SECURE_RPC
14139826d68Smrg# include <rpc/rpc.h>
14239826d68Smrg# include <rpc/key_prot.h>
143145b7b3cSmrg#endif
144145b7b3cSmrg
145145b7b3cSmrg#ifdef K5AUTH
14639826d68Smrg# include <krb5/krb5.h>
147145b7b3cSmrg#endif
148145b7b3cSmrg
149145b7b3cSmrgextern Display	*dpy;
150145b7b3cSmrg
151145b7b3cSmrgstatic int	done, code;
152145b7b3cSmrg#ifndef USE_PAM
153145b7b3cSmrgstatic char	name[NAME_LEN], password[PASSWORD_LEN];
154145b7b3cSmrg#endif
155145b7b3cSmrgstatic Widget		toplevel;
156145b7b3cSmrgstatic Widget		login;
157145b7b3cSmrgstatic XtAppContext	context;
158145b7b3cSmrgstatic XtIntervalId	pingTimeout;
159145b7b3cSmrg
160145b7b3cSmrg#ifdef USE_PAM
161145b7b3cSmrgstatic int pamconv(int num_msg,
16239826d68Smrg# ifndef sun
163145b7b3cSmrg		   const
16439826d68Smrg# endif
165145b7b3cSmrg		   struct pam_message **msg,
166145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr);
167145b7b3cSmrg
168145b7b3cSmrg# define PAM_ERROR_PRINT(pamfunc, pamh)	\
169145b7b3cSmrg	LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error))
170145b7b3cSmrg
171145b7b3cSmrg
172145b7b3cSmrgstruct myconv_data {
173145b7b3cSmrg    struct display *d;
174145b7b3cSmrg    struct greet_info *greet;
175145b7b3cSmrg    char *username_display;
176145b7b3cSmrg};
177145b7b3cSmrg#endif
178145b7b3cSmrg
179145b7b3cSmrg
180145b7b3cSmrg/*ARGSUSED*/
181145b7b3cSmrgstatic void
182145b7b3cSmrgGreetPingServer (
183145b7b3cSmrg    XtPointer	    closure,
184145b7b3cSmrg    XtIntervalId    *intervalId)
185145b7b3cSmrg{
186145b7b3cSmrg    struct display *d;
187145b7b3cSmrg
188145b7b3cSmrg    d = (struct display *) closure;
189145b7b3cSmrg    if (!PingServer (d, XtDisplay (toplevel)))
190145b7b3cSmrg	SessionPingFailed (d);
191145b7b3cSmrg    pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
192145b7b3cSmrg				   GreetPingServer, (closure));
193145b7b3cSmrg}
194145b7b3cSmrg
195145b7b3cSmrg/*ARGSUSED*/
196145b7b3cSmrgstatic void
197145b7b3cSmrgGreetDone (
198145b7b3cSmrg    Widget	w,
199145b7b3cSmrg    LoginData	*data,
200145b7b3cSmrg    int		status)
201145b7b3cSmrg{
202145b7b3cSmrg    Debug ("GreetDone: %s, (password is %d long)\n",
203145b7b3cSmrg	    data->name, strlen (data->passwd));
204145b7b3cSmrg    switch (status) {
205145b7b3cSmrg    case NOTIFY_OK:
206145b7b3cSmrg#ifndef USE_PAM
207145b7b3cSmrg	strncpy (name, data->name, sizeof(name));
208145b7b3cSmrg	name[sizeof(name)-1] = '\0';
209145b7b3cSmrg	strncpy (password, data->passwd, sizeof(password));
210145b7b3cSmrg	password[sizeof(password)-1] = '\0';
211145b7b3cSmrg#endif
212145b7b3cSmrg	code = 0;
213145b7b3cSmrg	done = 1;
214145b7b3cSmrg	break;
215145b7b3cSmrg    case NOTIFY_ABORT:
216145b7b3cSmrg	Debug ("RESERVER_DISPLAY\n");
217145b7b3cSmrg	code = RESERVER_DISPLAY;
218145b7b3cSmrg	done = 1;
219145b7b3cSmrg	break;
220145b7b3cSmrg    case NOTIFY_RESTART:
221145b7b3cSmrg	Debug ("REMANAGE_DISPLAY\n");
222145b7b3cSmrg	code = REMANAGE_DISPLAY;
223145b7b3cSmrg	done = 1;
224145b7b3cSmrg	break;
225145b7b3cSmrg    case NOTIFY_ABORT_DISPLAY:
226145b7b3cSmrg	Debug ("UNMANAGE_DISPLAY\n");
227145b7b3cSmrg	code = UNMANAGE_DISPLAY;
228145b7b3cSmrg	done = 1;
229145b7b3cSmrg	break;
230145b7b3cSmrg    }
231145b7b3cSmrg#ifndef USE_PAM
232145b7b3cSmrg    if (done) {
233145b7b3cSmrg	bzero (data->name, NAME_LEN);
234145b7b3cSmrg	bzero (data->passwd, PASSWORD_LEN);
235145b7b3cSmrg    }
236145b7b3cSmrg#endif
237145b7b3cSmrg}
238145b7b3cSmrg
239145b7b3cSmrgstatic Display *
240145b7b3cSmrgInitGreet (struct display *d)
241145b7b3cSmrg{
242145b7b3cSmrg    Arg		arglist[10];
243145b7b3cSmrg    int		i;
244145b7b3cSmrg    static int	argc;
245145b7b3cSmrg    Screen		*scrn;
246145b7b3cSmrg    static char	*argv[] = { "xlogin", NULL };
247145b7b3cSmrg    Display		*dpy;
248145b7b3cSmrg#ifdef USE_XINERAMA
249145b7b3cSmrg    XineramaScreenInfo *screens;
250145b7b3cSmrg    int                 s_num;
251145b7b3cSmrg#endif
252145b7b3cSmrg
253145b7b3cSmrg    Debug ("greet %s\n", d->name);
254145b7b3cSmrg    argc = 1;
255145b7b3cSmrg    XtToolkitInitialize ();
256145b7b3cSmrg    context = XtCreateApplicationContext();
257145b7b3cSmrg    dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0,
258145b7b3cSmrg			 &argc, argv);
259145b7b3cSmrg
260145b7b3cSmrg    if (!dpy)
261145b7b3cSmrg	return NULL;
262145b7b3cSmrg
263145b7b3cSmrg#ifdef XKB
264145b7b3cSmrg    {
265145b7b3cSmrg    int opcode, evbase, errbase, majret, minret;
266145b7b3cSmrg    unsigned int value = XkbPCF_GrabsUseXKBStateMask;
267145b7b3cSmrg    if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) {
268145b7b3cSmrg	if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value))
269145b7b3cSmrg	    LogError ("%s\n", "SetPerClientControls failed");
270145b7b3cSmrg    }
271145b7b3cSmrg    }
272145b7b3cSmrg#endif
273145b7b3cSmrg    RegisterCloseOnFork (ConnectionNumber (dpy));
274145b7b3cSmrg
275145b7b3cSmrg    SecureDisplay (d, dpy);
276145b7b3cSmrg
277145b7b3cSmrg    i = 0;
278145b7b3cSmrg    scrn = XDefaultScreenOfDisplay(dpy);
279145b7b3cSmrg    XtSetArg(arglist[i], XtNscreen, scrn);	i++;
280145b7b3cSmrg    XtSetArg(arglist[i], XtNargc, argc);	i++;
281145b7b3cSmrg    XtSetArg(arglist[i], XtNargv, argv);	i++;
282145b7b3cSmrg
283145b7b3cSmrg    toplevel = XtAppCreateShell ((String) NULL, "Xlogin",
284145b7b3cSmrg		    applicationShellWidgetClass, dpy, arglist, i);
285145b7b3cSmrg
286145b7b3cSmrg    i = 0;
287145b7b3cSmrg    XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++;
288145b7b3cSmrg    if (!d->authorize || d->authorizations || !d->authComplain)
289145b7b3cSmrg    {
290145b7b3cSmrg	XtSetArg (arglist[i], XtNsecureSession, True); i++;
291145b7b3cSmrg    }
292145b7b3cSmrg    login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel,
293145b7b3cSmrg				    arglist, i);
294145b7b3cSmrg    XtRealizeWidget (toplevel);
295145b7b3cSmrg
296145b7b3cSmrg#ifdef USE_XINERAMA
297145b7b3cSmrg    if (
298145b7b3cSmrg	XineramaIsActive(dpy) &&
299145b7b3cSmrg	(screens = XineramaQueryScreens(dpy, &s_num)) != NULL
300145b7b3cSmrg       )
301145b7b3cSmrg    {
302145b7b3cSmrg	XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
303145b7b3cSmrg			0, 0, 0, 0,
304145b7b3cSmrg			screens[0].x_org + screens[0].width / 2,
305145b7b3cSmrg			screens[0].y_org + screens[0].height / 2);
306145b7b3cSmrg
307145b7b3cSmrg	XFree(screens);
308145b7b3cSmrg    }
309145b7b3cSmrg    else
310145b7b3cSmrg#endif
311145b7b3cSmrg    XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
312145b7b3cSmrg		    0, 0, 0, 0,
313145b7b3cSmrg		    XWidthOfScreen(scrn) / 2,
314145b7b3cSmrg		    XHeightOfScreen(scrn) / 2);
315145b7b3cSmrg
316145b7b3cSmrg    if (d->pingInterval)
317145b7b3cSmrg    {
318145b7b3cSmrg    	pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
319145b7b3cSmrg				       GreetPingServer, (XtPointer) d);
320145b7b3cSmrg    }
321145b7b3cSmrg    return dpy;
322145b7b3cSmrg}
323145b7b3cSmrg
324145b7b3cSmrgstatic void
325145b7b3cSmrgCloseGreet (struct display *d)
326145b7b3cSmrg{
327145b7b3cSmrg    Boolean	    allow;
328145b7b3cSmrg    Arg	    arglist[1];
329145b7b3cSmrg    Display *dpy = XtDisplay(toplevel);
330145b7b3cSmrg
331145b7b3cSmrg    if (pingTimeout)
332145b7b3cSmrg    {
333145b7b3cSmrg	XtRemoveTimeOut (pingTimeout);
334145b7b3cSmrg	pingTimeout = 0;
335145b7b3cSmrg    }
336145b7b3cSmrg    UnsecureDisplay (d, dpy);
337145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
338145b7b3cSmrg    XtGetValues (login, arglist, 1);
339145b7b3cSmrg    if (allow)
340145b7b3cSmrg    {
341145b7b3cSmrg	Debug ("Disabling access control\n");
342145b7b3cSmrg	XSetAccessControl (dpy, DisableAccess);
343145b7b3cSmrg    }
344145b7b3cSmrg    XtDestroyWidget (toplevel);
34543b4c634Smrg    toplevel = NULL;
34643b4c634Smrg    login = NULL; /* child of toplevel, which we just destroyed */
347145b7b3cSmrg    ClearCloseOnFork (XConnectionNumber (dpy));
348145b7b3cSmrg    XCloseDisplay (dpy);
349145b7b3cSmrg    Debug ("Greet connection closed\n");
350145b7b3cSmrg}
351145b7b3cSmrg
352145b7b3cSmrg#define WHITESPACE 0
353145b7b3cSmrg#define ARGUMENT 1
354145b7b3cSmrg
355145b7b3cSmrgstatic int
356145b7b3cSmrgGreet (struct display *d, struct greet_info *greet)
357145b7b3cSmrg{
358145b7b3cSmrg    XEvent		event;
359145b7b3cSmrg    Arg		arglist[3];
360145b7b3cSmrg
361145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, False);
362145b7b3cSmrg    XtSetValues (login, arglist, 1);
363145b7b3cSmrg
364145b7b3cSmrg    Debug ("dispatching %s\n", d->name);
365145b7b3cSmrg    done = 0;
366145b7b3cSmrg    while (!done) {
367145b7b3cSmrg	XtAppNextEvent (context, &event);
368145b7b3cSmrg	switch (event.type) {
369145b7b3cSmrg	case MappingNotify:
370145b7b3cSmrg	    XRefreshKeyboardMapping(&event.xmapping);
371145b7b3cSmrg	    break;
372145b7b3cSmrg	default:
373145b7b3cSmrg	    XtDispatchEvent (&event);
374145b7b3cSmrg	    break;
375145b7b3cSmrg	}
376145b7b3cSmrg    }
377145b7b3cSmrg    XFlush (XtDisplay (toplevel));
378145b7b3cSmrg    Debug ("Done dispatch %s\n", d->name);
379145b7b3cSmrg    if (code == 0)
380145b7b3cSmrg    {
381145b7b3cSmrg#ifndef USE_PAM
382145b7b3cSmrg	char *ptr;
383145b7b3cSmrg	unsigned int c,state = WHITESPACE;
38439826d68Smrg
385145b7b3cSmrg	/*
386145b7b3cSmrg	 * Process the name string to get rid of white spaces.
387145b7b3cSmrg	 */
388145b7b3cSmrg	for (ptr = name; state == WHITESPACE; ptr++)
389145b7b3cSmrg	{
390145b7b3cSmrg	    c = (unsigned int)(*ptr);
391145b7b3cSmrg	    if (c == ' ')
392145b7b3cSmrg		continue;
393145b7b3cSmrg
394145b7b3cSmrg	    state = ARGUMENT;
395145b7b3cSmrg	    break;
396145b7b3cSmrg	}
397145b7b3cSmrg
398145b7b3cSmrg	greet->name = ptr;
399145b7b3cSmrg	greet->password = password;
400145b7b3cSmrg#endif  /* USE_PAM */
401145b7b3cSmrg	XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string));
402145b7b3cSmrg	XtSetArg (arglist[1], XtNallowNullPasswd, (char *) &(greet->allow_null_passwd));
403145b7b3cSmrg	XtSetArg (arglist[2], XtNallowRootLogin, (char *) &(greet->allow_root_login));
404145b7b3cSmrg	XtGetValues (login, arglist, 3);
405145b7b3cSmrg	Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>");
406145b7b3cSmrg    }
407145b7b3cSmrg    return code;
408145b7b3cSmrg}
409145b7b3cSmrg
410145b7b3cSmrg
411145b7b3cSmrgstatic void
412145b7b3cSmrgFailedLogin (struct display *d, struct greet_info *greet)
413145b7b3cSmrg{
41439826d68Smrg#ifdef USE_SYSLOG
41543b4c634Smrg    const char *username = greet->name;
41643b4c634Smrg
41743b4c634Smrg    if (username == NULL)
41843b4c634Smrg	username = "username unavailable";
41943b4c634Smrg
420145b7b3cSmrg    syslog(LOG_AUTHPRIV|LOG_NOTICE,
421145b7b3cSmrg	   "LOGIN FAILURE ON %s, %s",
42243b4c634Smrg	   d->name, username);
423145b7b3cSmrg#endif
424145b7b3cSmrg    DrawFail (login);
425145b7b3cSmrg#ifndef USE_PAM
426145b7b3cSmrg    bzero (greet->name, strlen(greet->name));
427145b7b3cSmrg    bzero (greet->password, strlen(greet->password));
428145b7b3cSmrg#endif
429145b7b3cSmrg}
430145b7b3cSmrg
431145b7b3cSmrg_X_EXPORT
432145b7b3cSmrggreet_user_rtn GreetUser(
433145b7b3cSmrg    struct display          *d,
434145b7b3cSmrg    Display                 ** dpy,
435145b7b3cSmrg    struct verify_info      *verify,
436145b7b3cSmrg    struct greet_info       *greet,
437145b7b3cSmrg    struct dlfuncs        *dlfuncs)
438145b7b3cSmrg{
439145b7b3cSmrg    int i;
440145b7b3cSmrg
441145b7b3cSmrg#ifdef GREET_LIB
442145b7b3cSmrg/*
443145b7b3cSmrg * These must be set before they are used.
444145b7b3cSmrg */
445145b7b3cSmrg    __xdm_PingServer = dlfuncs->_PingServer;
446145b7b3cSmrg    __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed;
447145b7b3cSmrg    __xdm_Debug = dlfuncs->_Debug;
448145b7b3cSmrg    __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork;
449145b7b3cSmrg    __xdm_SecureDisplay = dlfuncs->_SecureDisplay;
450145b7b3cSmrg    __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay;
451145b7b3cSmrg    __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork;
452145b7b3cSmrg    __xdm_SetupDisplay = dlfuncs->_SetupDisplay;
453145b7b3cSmrg    __xdm_LogError = dlfuncs->_LogError;
454145b7b3cSmrg    __xdm_SessionExit = dlfuncs->_SessionExit;
455145b7b3cSmrg    __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources;
456145b7b3cSmrg    __xdm_source = dlfuncs->_source;
457145b7b3cSmrg    __xdm_defaultEnv = dlfuncs->_defaultEnv;
458145b7b3cSmrg    __xdm_setEnv = dlfuncs->_setEnv;
459145b7b3cSmrg    __xdm_putEnv = dlfuncs->_putEnv;
460145b7b3cSmrg    __xdm_parseArgs = dlfuncs->_parseArgs;
461145b7b3cSmrg    __xdm_printEnv = dlfuncs->_printEnv;
462145b7b3cSmrg    __xdm_systemEnv = dlfuncs->_systemEnv;
463145b7b3cSmrg    __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem;
464145b7b3cSmrg    __xdm_setgrent = dlfuncs->_setgrent;
465145b7b3cSmrg    __xdm_getgrent = dlfuncs->_getgrent;
466145b7b3cSmrg    __xdm_endgrent = dlfuncs->_endgrent;
46739826d68Smrg# ifdef USESHADOW
468145b7b3cSmrg    __xdm_getspnam = dlfuncs->_getspnam;
46939826d68Smrg#  ifndef QNX4
470145b7b3cSmrg    __xdm_endspent = dlfuncs->_endspent;
47139826d68Smrg#  endif /* QNX4 doesn't use endspent */
47239826d68Smrg# endif
473145b7b3cSmrg    __xdm_getpwnam = dlfuncs->_getpwnam;
47439826d68Smrg# if defined(linux) || defined(__GLIBC__)
475145b7b3cSmrg    __xdm_endpwent = dlfuncs->_endpwent;
47639826d68Smrg# endif
477145b7b3cSmrg    __xdm_crypt = dlfuncs->_crypt;
47839826d68Smrg# ifdef USE_PAM
479145b7b3cSmrg    __xdm_thepamhp = dlfuncs->_thepamhp;
48039826d68Smrg# endif
481145b7b3cSmrg#endif
482145b7b3cSmrg
483145b7b3cSmrg    *dpy = InitGreet (d);
484145b7b3cSmrg    /*
485145b7b3cSmrg     * Run the setup script - note this usually will not work when
486145b7b3cSmrg     * the server is grabbed, so we don't even bother trying.
487145b7b3cSmrg     */
488145b7b3cSmrg    if (!d->grabServer)
489145b7b3cSmrg	SetupDisplay (d);
490145b7b3cSmrg    if (!*dpy) {
491145b7b3cSmrg	LogError ("Cannot reopen display %s for greet window\n", d->name);
492145b7b3cSmrg	exit (RESERVER_DISPLAY);
493145b7b3cSmrg    }
494145b7b3cSmrg
495145b7b3cSmrg    for (;;) {
496145b7b3cSmrg#ifdef USE_PAM
497145b7b3cSmrg
498145b7b3cSmrg	/* Run PAM conversation */
499145b7b3cSmrg	pam_handle_t 	**pamhp		= thepamhp();
500145b7b3cSmrg	int		  pam_error;
501145b7b3cSmrg	unsigned int	  pam_flags 	= 0;
502145b7b3cSmrg	struct myconv_data pcd		= { d, greet, NULL };
503145b7b3cSmrg	struct pam_conv   pc 		= { pamconv, &pcd };
504145b7b3cSmrg	const char *	  pam_fname;
50543b4c634Smrg	char *		  username	= NULL;
506145b7b3cSmrg	const char *	  login_prompt;
507145b7b3cSmrg
508145b7b3cSmrg
50943b4c634Smrg	SetPrompt(login, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
510145b7b3cSmrg	login_prompt  = GetPrompt(login, LOGIN_PROMPT_USERNAME);
51143b4c634Smrg	SetPrompt(login, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
51239826d68Smrg
51339826d68Smrg# define RUN_AND_CHECK_PAM_ERROR(function, args)			\
514145b7b3cSmrg	    do { 						\
515145b7b3cSmrg		pam_error = function args;			\
516145b7b3cSmrg		if (pam_error != PAM_SUCCESS) {			\
517145b7b3cSmrg		    PAM_ERROR_PRINT(#function, *pamhp);		\
518145b7b3cSmrg		    goto pam_done;				\
519145b7b3cSmrg		} 						\
52039826d68Smrg	    } while (0)
52139826d68Smrg
522145b7b3cSmrg
523145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_start,
524145b7b3cSmrg				("xdm", NULL, &pc, pamhp));
525145b7b3cSmrg
526145b7b3cSmrg	/* Set default login prompt to xdm's default from Xresources */
527145b7b3cSmrg	if (login_prompt != NULL) {
528145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item,
529145b7b3cSmrg				    (*pamhp, PAM_USER_PROMPT, login_prompt));
530145b7b3cSmrg	}
531145b7b3cSmrg
532145b7b3cSmrg	if (d->name[0] != ':') {	/* Displaying to remote host */
533145b7b3cSmrg	    char *hostname = strdup(d->name);
534145b7b3cSmrg
535145b7b3cSmrg	    if (hostname == NULL) {
536145b7b3cSmrg		LogOutOfMem("GreetUser");
537145b7b3cSmrg	    } else {
538145b7b3cSmrg		char *colon = strrchr(hostname, ':');
53939826d68Smrg
540145b7b3cSmrg		if (colon != NULL)
541145b7b3cSmrg		    *colon = '\0';
54239826d68Smrg
543145b7b3cSmrg		RUN_AND_CHECK_PAM_ERROR(pam_set_item,
544145b7b3cSmrg					(*pamhp, PAM_RHOST, hostname));
545145b7b3cSmrg		free(hostname);
546145b7b3cSmrg	    }
547145b7b3cSmrg	} else
548145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, d->name));
54939826d68Smrg
550145b7b3cSmrg	if (!greet->allow_null_passwd) {
551145b7b3cSmrg	    pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
552145b7b3cSmrg	}
553145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_authenticate,
554145b7b3cSmrg				(*pamhp, pam_flags));
55539826d68Smrg
556145b7b3cSmrg	/* handle expired passwords */
557145b7b3cSmrg	pam_error = pam_acct_mgmt(*pamhp, pam_flags);
558145b7b3cSmrg	pam_fname = "pam_acct_mgmt";
559145b7b3cSmrg	if (pam_error == PAM_NEW_AUTHTOK_REQD) {
560145b7b3cSmrg	    ShowChangePasswdMessage(login);
561145b7b3cSmrg	    do {
562145b7b3cSmrg		pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK);
563145b7b3cSmrg	    } while ((pam_error == PAM_AUTHTOK_ERR) ||
564145b7b3cSmrg		     (pam_error == PAM_TRY_AGAIN));
565145b7b3cSmrg	    pam_fname = "pam_chauthtok";
566145b7b3cSmrg	}
567145b7b3cSmrg	if (pam_error != PAM_SUCCESS) {
568145b7b3cSmrg	    PAM_ERROR_PRINT(pam_fname, *pamhp);
569145b7b3cSmrg	    goto pam_done;
570145b7b3cSmrg	}
57139826d68Smrg
572145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_setcred,
573145b7b3cSmrg				(*pamhp, 0));
574145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_get_item,
575145b7b3cSmrg				(*pamhp, PAM_USER, (void *) &username));
576145b7b3cSmrg	if (username != NULL) {
577145b7b3cSmrg	    Debug("PAM_USER: %s\n", username);
578145b7b3cSmrg	    greet->name = username;
579145b7b3cSmrg	    greet->password = NULL;
580145b7b3cSmrg	}
58139826d68Smrg
582145b7b3cSmrg      pam_done:
583145b7b3cSmrg	if (code != 0)
584145b7b3cSmrg	{
585145b7b3cSmrg	    CloseGreet (d);
586145b7b3cSmrg	    SessionExit (d, code, FALSE);
587145b7b3cSmrg	}
588145b7b3cSmrg	if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) {
589145b7b3cSmrg	    SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False);
590145b7b3cSmrg	    SetValue (login, 1, NULL);
591145b7b3cSmrg	    break;
592145b7b3cSmrg	} else {
59339826d68Smrg	    /* Try to fill in username for failed login error log */
59439826d68Smrg	    if (greet->name == NULL) {
59539826d68Smrg		if (username == NULL) {
59639826d68Smrg		    RUN_AND_CHECK_PAM_ERROR(pam_get_item,
59739826d68Smrg					    (*pamhp, PAM_USER,
59839826d68Smrg					     (void *) &username));
59939826d68Smrg		}
60039826d68Smrg		greet->name = username;
60139826d68Smrg	    }
60239826d68Smrg	    FailedLogin (d, greet);
603145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_end,
604145b7b3cSmrg				    (*pamhp, pam_error));
605145b7b3cSmrg	}
606145b7b3cSmrg#else /* not PAM */
607145b7b3cSmrg	/*
608145b7b3cSmrg	 * Greet user, requesting name/password
609145b7b3cSmrg	 */
610145b7b3cSmrg	code = Greet (d, greet);
611145b7b3cSmrg	if (code != 0)
612145b7b3cSmrg	{
613145b7b3cSmrg	    CloseGreet (d);
614145b7b3cSmrg	    SessionExit (d, code, FALSE);
615145b7b3cSmrg	}
616145b7b3cSmrg	/*
617145b7b3cSmrg	 * Verify user
618145b7b3cSmrg	 */
619145b7b3cSmrg	if (Verify (d, greet, verify))
620145b7b3cSmrg	    break;
621145b7b3cSmrg	else
622145b7b3cSmrg	    FailedLogin (d, greet);
623145b7b3cSmrg#endif
624145b7b3cSmrg    }
625145b7b3cSmrg    DeleteXloginResources (d, *dpy);
626145b7b3cSmrg    CloseGreet (d);
627145b7b3cSmrg    Debug ("Greet loop finished\n");
628145b7b3cSmrg    /*
629145b7b3cSmrg     * Run system-wide initialization file
630145b7b3cSmrg     */
631145b7b3cSmrg    if (source (verify->systemEnviron, d->startup) != 0)
632145b7b3cSmrg    {
633145b7b3cSmrg	Debug ("Startup program %s exited with non-zero status\n",
634145b7b3cSmrg		d->startup);
635145b7b3cSmrg	SessionExit (d, OBEYSESS_DISPLAY, FALSE);
636145b7b3cSmrg    }
637145b7b3cSmrg    /*
638145b7b3cSmrg     * for user-based authorization schemes,
639145b7b3cSmrg     * add the user to the server's allowed "hosts" list.
640145b7b3cSmrg     */
641145b7b3cSmrg    for (i = 0; i < d->authNum; i++)
642145b7b3cSmrg    {
643145b7b3cSmrg#ifdef SECURE_RPC
644145b7b3cSmrg	if (d->authorizations[i]->name_length == 9 &&
645145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
646145b7b3cSmrg	{
647145b7b3cSmrg	    XHostAddress	addr;
648145b7b3cSmrg	    char		netname[MAXNETNAMELEN+1];
649145b7b3cSmrg	    char		domainname[MAXNETNAMELEN+1];
65039826d68Smrg
651145b7b3cSmrg	    getdomainname(domainname, sizeof domainname);
652145b7b3cSmrg	    user2netname (netname, verify->uid, domainname);
653145b7b3cSmrg	    addr.family = FamilyNetname;
654145b7b3cSmrg	    addr.length = strlen (netname);
655145b7b3cSmrg	    addr.address = netname;
656145b7b3cSmrg	    XAddHost (*dpy, &addr);
657145b7b3cSmrg	}
658145b7b3cSmrg#endif
659145b7b3cSmrg#ifdef K5AUTH
660145b7b3cSmrg	if (d->authorizations[i]->name_length == 14 &&
661145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
662145b7b3cSmrg	{
663145b7b3cSmrg	    /* Update server's auth file with user-specific info.
664145b7b3cSmrg	     * Don't need to AddHost because X server will do that
665145b7b3cSmrg	     * automatically when it reads the cache we are about
666145b7b3cSmrg	     * to point it at.
667145b7b3cSmrg	     */
668145b7b3cSmrg	    extern Xauth *Krb5GetAuthFor();
669145b7b3cSmrg
670145b7b3cSmrg	    XauDisposeAuth (d->authorizations[i]);
671145b7b3cSmrg	    d->authorizations[i] =
672145b7b3cSmrg		Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
673145b7b3cSmrg	    SaveServerAuthorizations (d, d->authorizations, d->authNum);
67439826d68Smrg	}
675145b7b3cSmrg#endif
676145b7b3cSmrg    }
677145b7b3cSmrg
678145b7b3cSmrg    return Greet_Success;
679145b7b3cSmrg}
680145b7b3cSmrg
681145b7b3cSmrg
682145b7b3cSmrg#ifdef USE_PAM
683145b7b3cSmrgstatic int pamconv(int num_msg,
68439826d68Smrg# ifndef sun
685145b7b3cSmrg		   const
68639826d68Smrg# endif
687145b7b3cSmrg		   struct pam_message **msg,
688145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr)
689145b7b3cSmrg{
690145b7b3cSmrg    int i;
691145b7b3cSmrg    int greetCode;
692145b7b3cSmrg    int status = PAM_SUCCESS;
693145b7b3cSmrg    const char *pam_msg_styles[5]
694145b7b3cSmrg	= { "<invalid pam msg style>",
695145b7b3cSmrg	    "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
696145b7b3cSmrg	    "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
69739826d68Smrg
698145b7b3cSmrg    struct pam_message      *m;
699145b7b3cSmrg    struct pam_response     *r;
700145b7b3cSmrg
701145b7b3cSmrg    struct myconv_data	    *d = (struct myconv_data *) appdata_ptr;
702145b7b3cSmrg
703145b7b3cSmrg    pam_handle_t	    **pamhp = thepamhp();
70439826d68Smrg
705145b7b3cSmrg    *response = calloc(num_msg, sizeof (struct pam_response));
706145b7b3cSmrg    if (*response == NULL)
707145b7b3cSmrg	return (PAM_BUF_ERR);
708145b7b3cSmrg
70939826d68Smrg    m = (struct pam_message *)*msg;
710145b7b3cSmrg    r = *response;
711145b7b3cSmrg
71243b4c634Smrg    if (login == NULL) {
71343b4c634Smrg	status = PAM_CONV_ERR;
71443b4c634Smrg	goto pam_error;
71543b4c634Smrg    }
71643b4c634Smrg
717145b7b3cSmrg    for (i = 0; i < num_msg; i++ , m++ , r++) {
718145b7b3cSmrg	char *username;
719145b7b3cSmrg	int promptId = 0;
720145b7b3cSmrg	loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
721145b7b3cSmrg
722145b7b3cSmrg	if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS)
723145b7b3cSmrg	    && (username != NULL) && (*username != '\0')) {
724145b7b3cSmrg	    SetPrompt(login, LOGIN_PROMPT_USERNAME,
725145b7b3cSmrg		      NULL, LOGIN_TEXT_INFO, False);
726145b7b3cSmrg	    SetValue(login, LOGIN_PROMPT_USERNAME, username);
727145b7b3cSmrg	    promptId = 1;
72839826d68Smrg	}
72939826d68Smrg
730145b7b3cSmrg	Debug("pam_msg: %s (%d): '%s'\n",
731145b7b3cSmrg	      ((m->msg_style > 0) && (m->msg_style <= 4)) ?
732145b7b3cSmrg	       pam_msg_styles[m->msg_style] : pam_msg_styles[0],
733145b7b3cSmrg	       m->msg_style, m->msg);
734145b7b3cSmrg
735145b7b3cSmrg	switch (m->msg_style) {
736145b7b3cSmrg	  case PAM_ERROR_MSG:
737145b7b3cSmrg	      ErrorMessage(login, m->msg, True);
738145b7b3cSmrg	      break;
739145b7b3cSmrg
740145b7b3cSmrg	  case PAM_TEXT_INFO:
741145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
742145b7b3cSmrg	      SetValue (login, promptId, NULL);
743145b7b3cSmrg	      break;
74439826d68Smrg
745145b7b3cSmrg          case PAM_PROMPT_ECHO_ON:
746145b7b3cSmrg	      pStyle = LOGIN_PROMPT_ECHO_ON;
747145b7b3cSmrg	      /* FALLTHROUGH */
748145b7b3cSmrg          case PAM_PROMPT_ECHO_OFF:
749145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, pStyle, False);
750145b7b3cSmrg	      SetValue (login, promptId, NULL);
751145b7b3cSmrg	      greetCode = Greet (d->d, d->greet);
752145b7b3cSmrg	      if (greetCode != 0) {
753145b7b3cSmrg		  status = PAM_CONV_ERR;
754145b7b3cSmrg		  goto pam_error;
755145b7b3cSmrg	      } else {
756145b7b3cSmrg		  r->resp = strdup(GetValue(login, promptId));
757145b7b3cSmrg		  SetValue(login, promptId, NULL);
758145b7b3cSmrg		  if (r->resp == NULL) {
759145b7b3cSmrg		      status = PAM_BUF_ERR;
760145b7b3cSmrg		      goto pam_error;
761145b7b3cSmrg		  }
762145b7b3cSmrg		  /* Debug("pam_resp: '%s'\n", r->resp); */
763145b7b3cSmrg	      }
764145b7b3cSmrg	      break;
765145b7b3cSmrg
766145b7b3cSmrg	  default:
767145b7b3cSmrg	      LogError("Unknown PAM msg_style: %d\n", m->msg_style);
768145b7b3cSmrg	}
769145b7b3cSmrg    }
77039826d68Smrg  pam_error:
771145b7b3cSmrg    if (status != PAM_SUCCESS) {
772145b7b3cSmrg	/* free responses */
773145b7b3cSmrg	r = *response;
774145b7b3cSmrg	for (i = 0; i < num_msg; i++, r++) {
775145b7b3cSmrg	    if (r->resp) {
776145b7b3cSmrg		bzero(r->resp, strlen(r->resp));
777145b7b3cSmrg		free(r->resp);
778145b7b3cSmrg	    }
779145b7b3cSmrg	}
780145b7b3cSmrg	free(*response);
781145b7b3cSmrg	*response = NULL;
782145b7b3cSmrg    }
783145b7b3cSmrg    return status;
784145b7b3cSmrg}
785145b7b3cSmrg#endif
786