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