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