greet.c revision dfe7682d
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/*
29c9f4ce72Smrg * Copyright (c) 2006, Oracle and/or its affiliates. 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/*
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;
10239826d68Smrgvoid    (*__xdm_Debug)(const 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;
10839826d68Smrgvoid    (*__xdm_LogError)(const 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;
113dfe7682dSmrgchar    **(*__xdm_setEnv)(char **e, const char *name, const char *value) = NULL;
114145b7b3cSmrgchar    **(*__xdm_putEnv)(const char *string, char **env) = NULL;
115dfe7682dSmrgchar    **(*__xdm_parseArgs)(char **argv, const char *string) = NULL;
116145b7b3cSmrgvoid    (*__xdm_printEnv)(char **e) = NULL;
117145b7b3cSmrgchar    **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL;
11839826d68Smrgvoid    (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL;
119145b7b3cSmrgvoid    (*__xdm_setgrent)(void) = NULL;
120145b7b3cSmrgstruct group    *(*__xdm_getgrent)(void) = NULL;
121145b7b3cSmrgvoid    (*__xdm_endgrent)(void) = NULL;
122c9f4ce72Smrg# ifdef HAVE_GETSPNAM
123145b7b3cSmrgstruct spwd   *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL;
12439826d68Smrg#  ifndef QNX4
125145b7b3cSmrgvoid   (*__xdm_endspent)(void) = NULL;
12639826d68Smrg#  endif /* QNX4 doesn't use endspent */
12739826d68Smrg# endif
128145b7b3cSmrgstruct passwd   *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
12939826d68Smrg# if defined(linux) || defined(__GLIBC__)
130145b7b3cSmrgvoid   (*__xdm_endpwent)(void) = NULL;
13139826d68Smrg# endif
132145b7b3cSmrgchar     *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
13339826d68Smrg# ifdef USE_PAM
134145b7b3cSmrgpam_handle_t **(*__xdm_thepamhp)(void) = NULL;
13539826d68Smrg# endif
136145b7b3cSmrg
137145b7b3cSmrg#ifdef SECURE_RPC
13839826d68Smrg# include <rpc/rpc.h>
13939826d68Smrg# include <rpc/key_prot.h>
140145b7b3cSmrg#endif
141145b7b3cSmrg
142145b7b3cSmrg#ifdef K5AUTH
14339826d68Smrg# include <krb5/krb5.h>
144145b7b3cSmrg#endif
145145b7b3cSmrg
146145b7b3cSmrgstatic int	done, code;
147145b7b3cSmrg#ifndef USE_PAM
148145b7b3cSmrgstatic char	name[NAME_LEN], password[PASSWORD_LEN];
149145b7b3cSmrg#endif
150145b7b3cSmrgstatic Widget		toplevel;
151145b7b3cSmrgstatic Widget		login;
152145b7b3cSmrgstatic XtAppContext	context;
153145b7b3cSmrgstatic XtIntervalId	pingTimeout;
154145b7b3cSmrg
155145b7b3cSmrg#ifdef USE_PAM
156145b7b3cSmrgstatic int pamconv(int num_msg,
15739826d68Smrg# ifndef sun
158145b7b3cSmrg		   const
15939826d68Smrg# endif
160145b7b3cSmrg		   struct pam_message **msg,
161145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr);
162145b7b3cSmrg
163145b7b3cSmrg# define PAM_ERROR_PRINT(pamfunc, pamh)	\
164145b7b3cSmrg	LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error))
165145b7b3cSmrg
166145b7b3cSmrg
167145b7b3cSmrgstruct myconv_data {
168145b7b3cSmrg    struct display *d;
169145b7b3cSmrg    struct greet_info *greet;
170145b7b3cSmrg    char *username_display;
171145b7b3cSmrg};
172145b7b3cSmrg#endif
173145b7b3cSmrg
174145b7b3cSmrg
175145b7b3cSmrg/*ARGSUSED*/
176145b7b3cSmrgstatic void
177145b7b3cSmrgGreetPingServer (
178145b7b3cSmrg    XtPointer	    closure,
179145b7b3cSmrg    XtIntervalId    *intervalId)
180145b7b3cSmrg{
181145b7b3cSmrg    struct display *d;
182145b7b3cSmrg
183145b7b3cSmrg    d = (struct display *) closure;
184145b7b3cSmrg    if (!PingServer (d, XtDisplay (toplevel)))
185145b7b3cSmrg	SessionPingFailed (d);
186145b7b3cSmrg    pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
187145b7b3cSmrg				   GreetPingServer, (closure));
188145b7b3cSmrg}
189145b7b3cSmrg
190145b7b3cSmrg/*ARGSUSED*/
191145b7b3cSmrgstatic void
192145b7b3cSmrgGreetDone (
193145b7b3cSmrg    Widget	w,
194145b7b3cSmrg    LoginData	*data,
195145b7b3cSmrg    int		status)
196145b7b3cSmrg{
197e13a667bSwiz    Debug ("GreetDone: %s, (password is %zu long)\n",
198145b7b3cSmrg	    data->name, strlen (data->passwd));
199145b7b3cSmrg    switch (status) {
200145b7b3cSmrg    case NOTIFY_OK:
201145b7b3cSmrg#ifndef USE_PAM
202145b7b3cSmrg	strncpy (name, data->name, sizeof(name));
203145b7b3cSmrg	name[sizeof(name)-1] = '\0';
204145b7b3cSmrg	strncpy (password, data->passwd, sizeof(password));
205145b7b3cSmrg	password[sizeof(password)-1] = '\0';
206145b7b3cSmrg#endif
207145b7b3cSmrg	code = 0;
208145b7b3cSmrg	done = 1;
209145b7b3cSmrg	break;
210145b7b3cSmrg    case NOTIFY_ABORT:
211145b7b3cSmrg	Debug ("RESERVER_DISPLAY\n");
212145b7b3cSmrg	code = RESERVER_DISPLAY;
213145b7b3cSmrg	done = 1;
214145b7b3cSmrg	break;
215145b7b3cSmrg    case NOTIFY_RESTART:
216145b7b3cSmrg	Debug ("REMANAGE_DISPLAY\n");
217145b7b3cSmrg	code = REMANAGE_DISPLAY;
218145b7b3cSmrg	done = 1;
219145b7b3cSmrg	break;
220145b7b3cSmrg    case NOTIFY_ABORT_DISPLAY:
221145b7b3cSmrg	Debug ("UNMANAGE_DISPLAY\n");
222145b7b3cSmrg	code = UNMANAGE_DISPLAY;
223145b7b3cSmrg	done = 1;
224145b7b3cSmrg	break;
225145b7b3cSmrg    }
226145b7b3cSmrg#ifndef USE_PAM
227145b7b3cSmrg    if (done) {
228145b7b3cSmrg	bzero (data->name, NAME_LEN);
229145b7b3cSmrg	bzero (data->passwd, PASSWORD_LEN);
230145b7b3cSmrg    }
231145b7b3cSmrg#endif
232145b7b3cSmrg}
233145b7b3cSmrg
234145b7b3cSmrgstatic Display *
235145b7b3cSmrgInitGreet (struct display *d)
236145b7b3cSmrg{
237145b7b3cSmrg    Arg		arglist[10];
238145b7b3cSmrg    int		i;
239145b7b3cSmrg    static int	argc;
240145b7b3cSmrg    Screen		*scrn;
241145b7b3cSmrg    static char	*argv[] = { "xlogin", NULL };
242145b7b3cSmrg    Display		*dpy;
243145b7b3cSmrg#ifdef USE_XINERAMA
244145b7b3cSmrg    XineramaScreenInfo *screens;
245145b7b3cSmrg    int                 s_num;
246145b7b3cSmrg#endif
247145b7b3cSmrg
248145b7b3cSmrg    Debug ("greet %s\n", d->name);
249145b7b3cSmrg    argc = 1;
250145b7b3cSmrg    XtToolkitInitialize ();
251145b7b3cSmrg    context = XtCreateApplicationContext();
252145b7b3cSmrg    dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0,
253145b7b3cSmrg			 &argc, argv);
254145b7b3cSmrg
255145b7b3cSmrg    if (!dpy)
256145b7b3cSmrg	return NULL;
257145b7b3cSmrg
258145b7b3cSmrg#ifdef XKB
259145b7b3cSmrg    {
260145b7b3cSmrg    int opcode, evbase, errbase, majret, minret;
261145b7b3cSmrg    unsigned int value = XkbPCF_GrabsUseXKBStateMask;
262145b7b3cSmrg    if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) {
263145b7b3cSmrg	if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value))
264145b7b3cSmrg	    LogError ("%s\n", "SetPerClientControls failed");
265145b7b3cSmrg    }
266145b7b3cSmrg    }
267145b7b3cSmrg#endif
268145b7b3cSmrg    RegisterCloseOnFork (ConnectionNumber (dpy));
269145b7b3cSmrg
270145b7b3cSmrg    SecureDisplay (d, dpy);
271145b7b3cSmrg
272145b7b3cSmrg    i = 0;
273145b7b3cSmrg    scrn = XDefaultScreenOfDisplay(dpy);
274145b7b3cSmrg    XtSetArg(arglist[i], XtNscreen, scrn);	i++;
275145b7b3cSmrg    XtSetArg(arglist[i], XtNargc, argc);	i++;
276145b7b3cSmrg    XtSetArg(arglist[i], XtNargv, argv);	i++;
277145b7b3cSmrg
278145b7b3cSmrg    toplevel = XtAppCreateShell ((String) NULL, "Xlogin",
279145b7b3cSmrg		    applicationShellWidgetClass, dpy, arglist, i);
280145b7b3cSmrg
281145b7b3cSmrg    i = 0;
282145b7b3cSmrg    XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++;
283145b7b3cSmrg    if (!d->authorize || d->authorizations || !d->authComplain)
284145b7b3cSmrg    {
285145b7b3cSmrg	XtSetArg (arglist[i], XtNsecureSession, True); i++;
286145b7b3cSmrg    }
287145b7b3cSmrg    login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel,
288145b7b3cSmrg				    arglist, i);
289145b7b3cSmrg    XtRealizeWidget (toplevel);
290145b7b3cSmrg
291145b7b3cSmrg#ifdef USE_XINERAMA
292145b7b3cSmrg    if (
293145b7b3cSmrg	XineramaIsActive(dpy) &&
294145b7b3cSmrg	(screens = XineramaQueryScreens(dpy, &s_num)) != NULL
295145b7b3cSmrg       )
296145b7b3cSmrg    {
297145b7b3cSmrg	XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
298145b7b3cSmrg			0, 0, 0, 0,
299145b7b3cSmrg			screens[0].x_org + screens[0].width / 2,
300145b7b3cSmrg			screens[0].y_org + screens[0].height / 2);
301145b7b3cSmrg
302145b7b3cSmrg	XFree(screens);
303145b7b3cSmrg    }
304145b7b3cSmrg    else
305145b7b3cSmrg#endif
306145b7b3cSmrg    XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
307145b7b3cSmrg		    0, 0, 0, 0,
308145b7b3cSmrg		    XWidthOfScreen(scrn) / 2,
309145b7b3cSmrg		    XHeightOfScreen(scrn) / 2);
310145b7b3cSmrg
311145b7b3cSmrg    if (d->pingInterval)
312145b7b3cSmrg    {
313c9f4ce72Smrg	pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
314145b7b3cSmrg				       GreetPingServer, (XtPointer) d);
315145b7b3cSmrg    }
316145b7b3cSmrg    return dpy;
317145b7b3cSmrg}
318145b7b3cSmrg
319145b7b3cSmrgstatic void
320145b7b3cSmrgCloseGreet (struct display *d)
321145b7b3cSmrg{
322145b7b3cSmrg    Boolean	    allow;
323145b7b3cSmrg    Arg	    arglist[1];
324145b7b3cSmrg    Display *dpy = XtDisplay(toplevel);
325145b7b3cSmrg
326145b7b3cSmrg    if (pingTimeout)
327145b7b3cSmrg    {
328145b7b3cSmrg	XtRemoveTimeOut (pingTimeout);
329145b7b3cSmrg	pingTimeout = 0;
330145b7b3cSmrg    }
331145b7b3cSmrg    UnsecureDisplay (d, dpy);
332145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
333145b7b3cSmrg    XtGetValues (login, arglist, 1);
334145b7b3cSmrg    if (allow)
335145b7b3cSmrg    {
336145b7b3cSmrg	Debug ("Disabling access control\n");
337145b7b3cSmrg	XSetAccessControl (dpy, DisableAccess);
338145b7b3cSmrg    }
339145b7b3cSmrg    XtDestroyWidget (toplevel);
34043b4c634Smrg    toplevel = NULL;
34143b4c634Smrg    login = NULL; /* child of toplevel, which we just destroyed */
342145b7b3cSmrg    ClearCloseOnFork (XConnectionNumber (dpy));
343145b7b3cSmrg    XCloseDisplay (dpy);
344145b7b3cSmrg    Debug ("Greet connection closed\n");
345145b7b3cSmrg}
346145b7b3cSmrg
347145b7b3cSmrg#define WHITESPACE 0
348145b7b3cSmrg#define ARGUMENT 1
349145b7b3cSmrg
350145b7b3cSmrgstatic int
351145b7b3cSmrgGreet (struct display *d, struct greet_info *greet)
352145b7b3cSmrg{
353145b7b3cSmrg    XEvent		event;
354c9f4ce72Smrg    Arg		arglist[1];
355145b7b3cSmrg
356145b7b3cSmrg    XtSetArg (arglist[0], XtNallowAccess, False);
357145b7b3cSmrg    XtSetValues (login, arglist, 1);
358145b7b3cSmrg
359145b7b3cSmrg    Debug ("dispatching %s\n", d->name);
360145b7b3cSmrg    done = 0;
361145b7b3cSmrg    while (!done) {
362145b7b3cSmrg	XtAppNextEvent (context, &event);
363145b7b3cSmrg	switch (event.type) {
364145b7b3cSmrg	case MappingNotify:
365145b7b3cSmrg	    XRefreshKeyboardMapping(&event.xmapping);
366145b7b3cSmrg	    break;
367145b7b3cSmrg	default:
368145b7b3cSmrg	    XtDispatchEvent (&event);
369145b7b3cSmrg	    break;
370145b7b3cSmrg	}
371145b7b3cSmrg    }
372145b7b3cSmrg    XFlush (XtDisplay (toplevel));
373145b7b3cSmrg    Debug ("Done dispatch %s\n", d->name);
374145b7b3cSmrg    if (code == 0)
375145b7b3cSmrg    {
376145b7b3cSmrg#ifndef USE_PAM
377145b7b3cSmrg	char *ptr;
378145b7b3cSmrg	unsigned int c,state = WHITESPACE;
37939826d68Smrg
380145b7b3cSmrg	/*
381145b7b3cSmrg	 * Process the name string to get rid of white spaces.
382145b7b3cSmrg	 */
383145b7b3cSmrg	for (ptr = name; state == WHITESPACE; ptr++)
384145b7b3cSmrg	{
385145b7b3cSmrg	    c = (unsigned int)(*ptr);
386145b7b3cSmrg	    if (c == ' ')
387145b7b3cSmrg		continue;
388145b7b3cSmrg
389145b7b3cSmrg	    state = ARGUMENT;
390145b7b3cSmrg	    break;
391145b7b3cSmrg	}
392145b7b3cSmrg
393145b7b3cSmrg	greet->name = ptr;
394145b7b3cSmrg	greet->password = password;
395145b7b3cSmrg#endif  /* USE_PAM */
396145b7b3cSmrg	XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string));
397c9f4ce72Smrg	XtGetValues (login, arglist, 1);
398145b7b3cSmrg	Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>");
399145b7b3cSmrg    }
400145b7b3cSmrg    return code;
401145b7b3cSmrg}
402145b7b3cSmrg
403145b7b3cSmrg
404145b7b3cSmrgstatic void
405c9f4ce72SmrgFailedLogin (struct display *d, const char *username)
406145b7b3cSmrg{
40739826d68Smrg#ifdef USE_SYSLOG
40843b4c634Smrg    if (username == NULL)
40943b4c634Smrg	username = "username unavailable";
41043b4c634Smrg
411145b7b3cSmrg    syslog(LOG_AUTHPRIV|LOG_NOTICE,
412145b7b3cSmrg	   "LOGIN FAILURE ON %s, %s",
41343b4c634Smrg	   d->name, username);
414145b7b3cSmrg#endif
415145b7b3cSmrg    DrawFail (login);
416145b7b3cSmrg}
417145b7b3cSmrg
418145b7b3cSmrg_X_EXPORT
419145b7b3cSmrggreet_user_rtn GreetUser(
420145b7b3cSmrg    struct display          *d,
421145b7b3cSmrg    Display                 ** dpy,
422145b7b3cSmrg    struct verify_info      *verify,
423145b7b3cSmrg    struct greet_info       *greet,
424145b7b3cSmrg    struct dlfuncs        *dlfuncs)
425145b7b3cSmrg{
426145b7b3cSmrg    int i;
427c9f4ce72Smrg    Arg		arglist[2];
428145b7b3cSmrg
429145b7b3cSmrg/*
430145b7b3cSmrg * These must be set before they are used.
431145b7b3cSmrg */
432145b7b3cSmrg    __xdm_PingServer = dlfuncs->_PingServer;
433145b7b3cSmrg    __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed;
434145b7b3cSmrg    __xdm_Debug = dlfuncs->_Debug;
435145b7b3cSmrg    __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork;
436145b7b3cSmrg    __xdm_SecureDisplay = dlfuncs->_SecureDisplay;
437145b7b3cSmrg    __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay;
438145b7b3cSmrg    __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork;
439145b7b3cSmrg    __xdm_SetupDisplay = dlfuncs->_SetupDisplay;
440145b7b3cSmrg    __xdm_LogError = dlfuncs->_LogError;
441145b7b3cSmrg    __xdm_SessionExit = dlfuncs->_SessionExit;
442145b7b3cSmrg    __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources;
443145b7b3cSmrg    __xdm_source = dlfuncs->_source;
444145b7b3cSmrg    __xdm_defaultEnv = dlfuncs->_defaultEnv;
445145b7b3cSmrg    __xdm_setEnv = dlfuncs->_setEnv;
446145b7b3cSmrg    __xdm_putEnv = dlfuncs->_putEnv;
447145b7b3cSmrg    __xdm_parseArgs = dlfuncs->_parseArgs;
448145b7b3cSmrg    __xdm_printEnv = dlfuncs->_printEnv;
449145b7b3cSmrg    __xdm_systemEnv = dlfuncs->_systemEnv;
450145b7b3cSmrg    __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem;
451145b7b3cSmrg    __xdm_setgrent = dlfuncs->_setgrent;
452145b7b3cSmrg    __xdm_getgrent = dlfuncs->_getgrent;
453145b7b3cSmrg    __xdm_endgrent = dlfuncs->_endgrent;
454c9f4ce72Smrg# ifdef HAVE_GETSPNAM
455145b7b3cSmrg    __xdm_getspnam = dlfuncs->_getspnam;
45639826d68Smrg#  ifndef QNX4
457145b7b3cSmrg    __xdm_endspent = dlfuncs->_endspent;
45839826d68Smrg#  endif /* QNX4 doesn't use endspent */
45939826d68Smrg# endif
460145b7b3cSmrg    __xdm_getpwnam = dlfuncs->_getpwnam;
46139826d68Smrg# if defined(linux) || defined(__GLIBC__)
462145b7b3cSmrg    __xdm_endpwent = dlfuncs->_endpwent;
46339826d68Smrg# endif
464145b7b3cSmrg    __xdm_crypt = dlfuncs->_crypt;
46539826d68Smrg# ifdef USE_PAM
466145b7b3cSmrg    __xdm_thepamhp = dlfuncs->_thepamhp;
46739826d68Smrg# endif
468145b7b3cSmrg
469145b7b3cSmrg    *dpy = InitGreet (d);
470145b7b3cSmrg    /*
471145b7b3cSmrg     * Run the setup script - note this usually will not work when
472145b7b3cSmrg     * the server is grabbed, so we don't even bother trying.
473145b7b3cSmrg     */
474145b7b3cSmrg    if (!d->grabServer)
475145b7b3cSmrg	SetupDisplay (d);
476145b7b3cSmrg    if (!*dpy) {
477145b7b3cSmrg	LogError ("Cannot reopen display %s for greet window\n", d->name);
478145b7b3cSmrg	exit (RESERVER_DISPLAY);
479145b7b3cSmrg    }
480145b7b3cSmrg
481c9f4ce72Smrg    XtSetArg (arglist[0], XtNallowNullPasswd,
482c9f4ce72Smrg	      (char *) &(greet->allow_null_passwd));
483c9f4ce72Smrg    XtSetArg (arglist[1], XtNallowRootLogin,
484c9f4ce72Smrg	      (char *) &(greet->allow_root_login));
485c9f4ce72Smrg    XtGetValues (login, arglist, 2);
486c9f4ce72Smrg
487145b7b3cSmrg    for (;;) {
488145b7b3cSmrg#ifdef USE_PAM
489145b7b3cSmrg
490145b7b3cSmrg	/* Run PAM conversation */
491145b7b3cSmrg	pam_handle_t 	**pamhp		= thepamhp();
492145b7b3cSmrg	int		  pam_error;
493145b7b3cSmrg	unsigned int	  pam_flags 	= 0;
494145b7b3cSmrg	struct myconv_data pcd		= { d, greet, NULL };
495145b7b3cSmrg	struct pam_conv   pc 		= { pamconv, &pcd };
496145b7b3cSmrg	const char *	  pam_fname;
497145b7b3cSmrg	const char *	  login_prompt;
498145b7b3cSmrg
499145b7b3cSmrg
50043b4c634Smrg	SetPrompt(login, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
501145b7b3cSmrg	login_prompt  = GetPrompt(login, LOGIN_PROMPT_USERNAME);
50243b4c634Smrg	SetPrompt(login, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_NOT_SHOWN, False);
50339826d68Smrg
50439826d68Smrg# define RUN_AND_CHECK_PAM_ERROR(function, args)			\
505145b7b3cSmrg	    do { 						\
506145b7b3cSmrg		pam_error = function args;			\
507145b7b3cSmrg		if (pam_error != PAM_SUCCESS) {			\
508145b7b3cSmrg		    PAM_ERROR_PRINT(#function, *pamhp);		\
509145b7b3cSmrg		    goto pam_done;				\
510145b7b3cSmrg		} 						\
51139826d68Smrg	    } while (0)
51239826d68Smrg
513145b7b3cSmrg
514145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_start,
515145b7b3cSmrg				("xdm", NULL, &pc, pamhp));
516145b7b3cSmrg
517145b7b3cSmrg	/* Set default login prompt to xdm's default from Xresources */
518145b7b3cSmrg	if (login_prompt != NULL) {
519145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item,
520145b7b3cSmrg				    (*pamhp, PAM_USER_PROMPT, login_prompt));
521145b7b3cSmrg	}
522145b7b3cSmrg
523145b7b3cSmrg	if (d->name[0] != ':') {	/* Displaying to remote host */
524145b7b3cSmrg	    char *hostname = strdup(d->name);
525145b7b3cSmrg
526145b7b3cSmrg	    if (hostname == NULL) {
527145b7b3cSmrg		LogOutOfMem("GreetUser");
528145b7b3cSmrg	    } else {
529145b7b3cSmrg		char *colon = strrchr(hostname, ':');
53039826d68Smrg
531145b7b3cSmrg		if (colon != NULL)
532145b7b3cSmrg		    *colon = '\0';
53339826d68Smrg
534145b7b3cSmrg		RUN_AND_CHECK_PAM_ERROR(pam_set_item,
535145b7b3cSmrg					(*pamhp, PAM_RHOST, hostname));
536145b7b3cSmrg		free(hostname);
537145b7b3cSmrg	    }
538c9f4ce72Smrg	} else {			/* Displaying on local host */
539c9f4ce72Smrg	    const char *ttyname = NULL;
540c9f4ce72Smrg
541c9f4ce72Smrg#ifdef __sun
542c9f4ce72Smrg	    /* Solaris PAM & auditing insist this is a device file that can
543c9f4ce72Smrg	       be found under /dev, so we can't use the display name */
544c9f4ce72Smrg	    char vtpath[16];
545c9f4ce72Smrg
546c9f4ce72Smrg	    if ((d->windowPath) && !(strchr(d->windowPath, ':'))) {
547c9f4ce72Smrg		/* if path is simply a VT, with no intermediaries, use it */
548c9f4ce72Smrg		snprintf(vtpath, sizeof(vtpath), "/dev/vt/%s", d->windowPath);
549c9f4ce72Smrg		ttyname = vtpath;
550c9f4ce72Smrg	    }
551c9f4ce72Smrg#else
552c9f4ce72Smrg	    /* On all other OS'es we just pass the display name for PAM_TTY */
553c9f4ce72Smrg	    ttyname = d->name;
554c9f4ce72Smrg#endif
555c9f4ce72Smrg	    RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, ttyname));
556c9f4ce72Smrg	}
55739826d68Smrg
558145b7b3cSmrg	if (!greet->allow_null_passwd) {
559145b7b3cSmrg	    pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
560145b7b3cSmrg	}
561145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_authenticate,
562145b7b3cSmrg				(*pamhp, pam_flags));
56339826d68Smrg
564145b7b3cSmrg	/* handle expired passwords */
565145b7b3cSmrg	pam_error = pam_acct_mgmt(*pamhp, pam_flags);
566145b7b3cSmrg	pam_fname = "pam_acct_mgmt";
567145b7b3cSmrg	if (pam_error == PAM_NEW_AUTHTOK_REQD) {
568145b7b3cSmrg	    ShowChangePasswdMessage(login);
569145b7b3cSmrg	    do {
570145b7b3cSmrg		pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK);
571145b7b3cSmrg	    } while ((pam_error == PAM_AUTHTOK_ERR) ||
572145b7b3cSmrg		     (pam_error == PAM_TRY_AGAIN));
573145b7b3cSmrg	    pam_fname = "pam_chauthtok";
574145b7b3cSmrg	}
575145b7b3cSmrg	if (pam_error != PAM_SUCCESS) {
576145b7b3cSmrg	    PAM_ERROR_PRINT(pam_fname, *pamhp);
577145b7b3cSmrg	    goto pam_done;
578145b7b3cSmrg	}
57939826d68Smrg
580145b7b3cSmrg	RUN_AND_CHECK_PAM_ERROR(pam_setcred,
581145b7b3cSmrg				(*pamhp, 0));
582c9f4ce72Smrg	{
583c9f4ce72Smrg	    char *username	= NULL;
584c9f4ce72Smrg
585c9f4ce72Smrg	    RUN_AND_CHECK_PAM_ERROR(pam_get_item,
586c9f4ce72Smrg				    (*pamhp, PAM_USER, (void *) &username));
587c9f4ce72Smrg	    if (username != NULL) {
588c9f4ce72Smrg		Debug("PAM_USER: %s\n", username);
589c9f4ce72Smrg		greet->name = username;
590c9f4ce72Smrg		greet->password = NULL;
591c9f4ce72Smrg	    }
592145b7b3cSmrg	}
59339826d68Smrg
594145b7b3cSmrg      pam_done:
595145b7b3cSmrg	if (code != 0)
596145b7b3cSmrg	{
597145b7b3cSmrg	    CloseGreet (d);
598145b7b3cSmrg	    SessionExit (d, code, FALSE);
599145b7b3cSmrg	}
600145b7b3cSmrg	if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) {
601145b7b3cSmrg	    SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False);
602145b7b3cSmrg	    SetValue (login, 1, NULL);
603145b7b3cSmrg	    break;
604145b7b3cSmrg	} else {
60539826d68Smrg	    /* Try to fill in username for failed login error log */
606c9f4ce72Smrg	    char *username = greet->name;
607c9f4ce72Smrg
608c9f4ce72Smrg	    if (username == NULL) {
609c9f4ce72Smrg		RUN_AND_CHECK_PAM_ERROR(pam_get_item,
610c9f4ce72Smrg					(*pamhp, PAM_USER,
611c9f4ce72Smrg					 (void *) &username));
61239826d68Smrg	    }
613c9f4ce72Smrg	    FailedLogin (d, username);
614145b7b3cSmrg	    RUN_AND_CHECK_PAM_ERROR(pam_end,
615145b7b3cSmrg				    (*pamhp, pam_error));
616145b7b3cSmrg	}
617145b7b3cSmrg#else /* not PAM */
618145b7b3cSmrg	/*
619145b7b3cSmrg	 * Greet user, requesting name/password
620145b7b3cSmrg	 */
621145b7b3cSmrg	code = Greet (d, greet);
622145b7b3cSmrg	if (code != 0)
623145b7b3cSmrg	{
624145b7b3cSmrg	    CloseGreet (d);
625145b7b3cSmrg	    SessionExit (d, code, FALSE);
626145b7b3cSmrg	}
627145b7b3cSmrg	/*
628145b7b3cSmrg	 * Verify user
629145b7b3cSmrg	 */
630145b7b3cSmrg	if (Verify (d, greet, verify))
631145b7b3cSmrg	    break;
632145b7b3cSmrg	else
633c9f4ce72Smrg	{
634c9f4ce72Smrg	    FailedLogin (d, greet->name);
635c9f4ce72Smrg	    bzero (greet->name, strlen(greet->name));
636c9f4ce72Smrg	    bzero (greet->password, strlen(greet->password));
637c9f4ce72Smrg	}
638145b7b3cSmrg#endif
639145b7b3cSmrg    }
640145b7b3cSmrg    DeleteXloginResources (d, *dpy);
641145b7b3cSmrg    CloseGreet (d);
642145b7b3cSmrg    Debug ("Greet loop finished\n");
643145b7b3cSmrg    /*
644145b7b3cSmrg     * Run system-wide initialization file
645145b7b3cSmrg     */
646145b7b3cSmrg    if (source (verify->systemEnviron, d->startup) != 0)
647145b7b3cSmrg    {
648145b7b3cSmrg	Debug ("Startup program %s exited with non-zero status\n",
649145b7b3cSmrg		d->startup);
650145b7b3cSmrg	SessionExit (d, OBEYSESS_DISPLAY, FALSE);
651145b7b3cSmrg    }
652145b7b3cSmrg    /*
653145b7b3cSmrg     * for user-based authorization schemes,
654145b7b3cSmrg     * add the user to the server's allowed "hosts" list.
655145b7b3cSmrg     */
656145b7b3cSmrg    for (i = 0; i < d->authNum; i++)
657145b7b3cSmrg    {
658145b7b3cSmrg#ifdef SECURE_RPC
659145b7b3cSmrg	if (d->authorizations[i]->name_length == 9 &&
660145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
661145b7b3cSmrg	{
662145b7b3cSmrg	    XHostAddress	addr;
663145b7b3cSmrg	    char		netname[MAXNETNAMELEN+1];
664145b7b3cSmrg	    char		domainname[MAXNETNAMELEN+1];
66539826d68Smrg
666145b7b3cSmrg	    getdomainname(domainname, sizeof domainname);
667145b7b3cSmrg	    user2netname (netname, verify->uid, domainname);
668145b7b3cSmrg	    addr.family = FamilyNetname;
669145b7b3cSmrg	    addr.length = strlen (netname);
670145b7b3cSmrg	    addr.address = netname;
671145b7b3cSmrg	    XAddHost (*dpy, &addr);
672145b7b3cSmrg	}
673145b7b3cSmrg#endif
674145b7b3cSmrg#ifdef K5AUTH
675145b7b3cSmrg	if (d->authorizations[i]->name_length == 14 &&
676145b7b3cSmrg	    memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
677145b7b3cSmrg	{
678145b7b3cSmrg	    /* Update server's auth file with user-specific info.
679145b7b3cSmrg	     * Don't need to AddHost because X server will do that
680145b7b3cSmrg	     * automatically when it reads the cache we are about
681145b7b3cSmrg	     * to point it at.
682145b7b3cSmrg	     */
683145b7b3cSmrg	    extern Xauth *Krb5GetAuthFor();
684145b7b3cSmrg
685145b7b3cSmrg	    XauDisposeAuth (d->authorizations[i]);
686145b7b3cSmrg	    d->authorizations[i] =
687145b7b3cSmrg		Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
688145b7b3cSmrg	    SaveServerAuthorizations (d, d->authorizations, d->authNum);
68939826d68Smrg	}
690145b7b3cSmrg#endif
691145b7b3cSmrg    }
692145b7b3cSmrg
693145b7b3cSmrg    return Greet_Success;
694145b7b3cSmrg}
695145b7b3cSmrg
696145b7b3cSmrg
697145b7b3cSmrg#ifdef USE_PAM
698145b7b3cSmrgstatic int pamconv(int num_msg,
69939826d68Smrg# ifndef sun
700145b7b3cSmrg		   const
70139826d68Smrg# endif
702145b7b3cSmrg		   struct pam_message **msg,
703145b7b3cSmrg		   struct pam_response **response, void *appdata_ptr)
704145b7b3cSmrg{
705145b7b3cSmrg    int i;
706145b7b3cSmrg    int greetCode;
707145b7b3cSmrg    int status = PAM_SUCCESS;
708145b7b3cSmrg    const char *pam_msg_styles[5]
709145b7b3cSmrg	= { "<invalid pam msg style>",
710145b7b3cSmrg	    "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
711145b7b3cSmrg	    "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
71239826d68Smrg
713145b7b3cSmrg    struct pam_message      *m;
714145b7b3cSmrg    struct pam_response     *r;
715145b7b3cSmrg
716145b7b3cSmrg    struct myconv_data	    *d = (struct myconv_data *) appdata_ptr;
717145b7b3cSmrg
718145b7b3cSmrg    pam_handle_t	    **pamhp = thepamhp();
71939826d68Smrg
720145b7b3cSmrg    *response = calloc(num_msg, sizeof (struct pam_response));
721145b7b3cSmrg    if (*response == NULL)
722145b7b3cSmrg	return (PAM_BUF_ERR);
723145b7b3cSmrg
72439826d68Smrg    m = (struct pam_message *)*msg;
725145b7b3cSmrg    r = *response;
726145b7b3cSmrg
72743b4c634Smrg    if (login == NULL) {
72843b4c634Smrg	status = PAM_CONV_ERR;
72943b4c634Smrg	goto pam_error;
73043b4c634Smrg    }
73143b4c634Smrg
732145b7b3cSmrg    for (i = 0; i < num_msg; i++ , m++ , r++) {
733145b7b3cSmrg	char *username;
734145b7b3cSmrg	int promptId = 0;
735145b7b3cSmrg	loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
736145b7b3cSmrg
737145b7b3cSmrg	if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS)
738145b7b3cSmrg	    && (username != NULL) && (*username != '\0')) {
739145b7b3cSmrg	    SetPrompt(login, LOGIN_PROMPT_USERNAME,
740145b7b3cSmrg		      NULL, LOGIN_TEXT_INFO, False);
741145b7b3cSmrg	    SetValue(login, LOGIN_PROMPT_USERNAME, username);
742145b7b3cSmrg	    promptId = 1;
74339826d68Smrg	}
74439826d68Smrg
745145b7b3cSmrg	Debug("pam_msg: %s (%d): '%s'\n",
746145b7b3cSmrg	      ((m->msg_style > 0) && (m->msg_style <= 4)) ?
747145b7b3cSmrg	       pam_msg_styles[m->msg_style] : pam_msg_styles[0],
748145b7b3cSmrg	       m->msg_style, m->msg);
749145b7b3cSmrg
750145b7b3cSmrg	switch (m->msg_style) {
751145b7b3cSmrg	  case PAM_ERROR_MSG:
752145b7b3cSmrg	      ErrorMessage(login, m->msg, True);
753145b7b3cSmrg	      break;
754145b7b3cSmrg
755145b7b3cSmrg	  case PAM_TEXT_INFO:
756145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
757145b7b3cSmrg	      SetValue (login, promptId, NULL);
758145b7b3cSmrg	      break;
75939826d68Smrg
760145b7b3cSmrg          case PAM_PROMPT_ECHO_ON:
761145b7b3cSmrg	      pStyle = LOGIN_PROMPT_ECHO_ON;
762145b7b3cSmrg	      /* FALLTHROUGH */
763145b7b3cSmrg          case PAM_PROMPT_ECHO_OFF:
764145b7b3cSmrg	      SetPrompt (login, promptId, m->msg, pStyle, False);
765145b7b3cSmrg	      SetValue (login, promptId, NULL);
766145b7b3cSmrg	      greetCode = Greet (d->d, d->greet);
767145b7b3cSmrg	      if (greetCode != 0) {
768145b7b3cSmrg		  status = PAM_CONV_ERR;
769145b7b3cSmrg		  goto pam_error;
770145b7b3cSmrg	      } else {
771145b7b3cSmrg		  r->resp = strdup(GetValue(login, promptId));
772145b7b3cSmrg		  SetValue(login, promptId, NULL);
773145b7b3cSmrg		  if (r->resp == NULL) {
774145b7b3cSmrg		      status = PAM_BUF_ERR;
775145b7b3cSmrg		      goto pam_error;
776145b7b3cSmrg		  }
777145b7b3cSmrg		  /* Debug("pam_resp: '%s'\n", r->resp); */
778145b7b3cSmrg	      }
779145b7b3cSmrg	      break;
780145b7b3cSmrg
781145b7b3cSmrg	  default:
782145b7b3cSmrg	      LogError("Unknown PAM msg_style: %d\n", m->msg_style);
783145b7b3cSmrg	}
784145b7b3cSmrg    }
78539826d68Smrg  pam_error:
786145b7b3cSmrg    if (status != PAM_SUCCESS) {
787145b7b3cSmrg	/* free responses */
788145b7b3cSmrg	r = *response;
789145b7b3cSmrg	for (i = 0; i < num_msg; i++, r++) {
790145b7b3cSmrg	    if (r->resp) {
791145b7b3cSmrg		bzero(r->resp, strlen(r->resp));
792145b7b3cSmrg		free(r->resp);
793145b7b3cSmrg	    }
794145b7b3cSmrg	}
795145b7b3cSmrg	free(*response);
796145b7b3cSmrg	*response = NULL;
797145b7b3cSmrg    }
798145b7b3cSmrg    return status;
799145b7b3cSmrg}
800145b7b3cSmrg#endif
801