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