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