greet.c revision 43b4c634
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/* 2943b4c634Smrg * Copyright © 2006 Sun Microsystems, Inc. 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#ifdef GREET_LIB 97145b7b3cSmrg/* 98145b7b3cSmrg * Function pointers filled in by the initial call ito the library 99145b7b3cSmrg */ 100145b7b3cSmrg 101145b7b3cSmrgint (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL; 102145b7b3cSmrgvoid (*__xdm_SessionPingFailed)(struct display *d) = NULL; 10339826d68Smrgvoid (*__xdm_Debug)(const char * fmt, ...) = NULL; 104145b7b3cSmrgvoid (*__xdm_RegisterCloseOnFork)(int fd) = NULL; 105145b7b3cSmrgvoid (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL; 106145b7b3cSmrgvoid (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL; 107145b7b3cSmrgvoid (*__xdm_ClearCloseOnFork)(int fd) = NULL; 108145b7b3cSmrgvoid (*__xdm_SetupDisplay)(struct display *d) = NULL; 10939826d68Smrgvoid (*__xdm_LogError)(const char * fmt, ...) = NULL; 110145b7b3cSmrgvoid (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL; 111145b7b3cSmrgvoid (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL; 112145b7b3cSmrgint (*__xdm_source)(char **environ, char *file) = NULL; 113145b7b3cSmrgchar **(*__xdm_defaultEnv)(void) = NULL; 114145b7b3cSmrgchar **(*__xdm_setEnv)(char **e, char *name, char *value) = NULL; 115145b7b3cSmrgchar **(*__xdm_putEnv)(const char *string, char **env) = NULL; 116145b7b3cSmrgchar **(*__xdm_parseArgs)(char **argv, char *string) = NULL; 117145b7b3cSmrgvoid (*__xdm_printEnv)(char **e) = NULL; 118145b7b3cSmrgchar **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL; 11939826d68Smrgvoid (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL; 120145b7b3cSmrgvoid (*__xdm_setgrent)(void) = NULL; 121145b7b3cSmrgstruct group *(*__xdm_getgrent)(void) = NULL; 122145b7b3cSmrgvoid (*__xdm_endgrent)(void) = NULL; 12339826d68Smrg# ifdef USESHADOW 124145b7b3cSmrgstruct spwd *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL; 12539826d68Smrg# ifndef QNX4 126145b7b3cSmrgvoid (*__xdm_endspent)(void) = NULL; 12739826d68Smrg# endif /* QNX4 doesn't use endspent */ 12839826d68Smrg# endif 129145b7b3cSmrgstruct passwd *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL; 13039826d68Smrg# if defined(linux) || defined(__GLIBC__) 131145b7b3cSmrgvoid (*__xdm_endpwent)(void) = NULL; 13239826d68Smrg# endif 133145b7b3cSmrgchar *(*__xdm_crypt)(CRYPT_ARGS) = NULL; 13439826d68Smrg# ifdef USE_PAM 135145b7b3cSmrgpam_handle_t **(*__xdm_thepamhp)(void) = NULL; 13639826d68Smrg# endif 137145b7b3cSmrg 138145b7b3cSmrg#endif 139145b7b3cSmrg 140145b7b3cSmrg#ifdef SECURE_RPC 14139826d68Smrg# include <rpc/rpc.h> 14239826d68Smrg# include <rpc/key_prot.h> 143145b7b3cSmrg#endif 144145b7b3cSmrg 145145b7b3cSmrg#ifdef K5AUTH 14639826d68Smrg# include <krb5/krb5.h> 147145b7b3cSmrg#endif 148145b7b3cSmrg 149145b7b3cSmrgextern Display *dpy; 150145b7b3cSmrg 151145b7b3cSmrgstatic int done, code; 152145b7b3cSmrg#ifndef USE_PAM 153145b7b3cSmrgstatic char name[NAME_LEN], password[PASSWORD_LEN]; 154145b7b3cSmrg#endif 155145b7b3cSmrgstatic Widget toplevel; 156145b7b3cSmrgstatic Widget login; 157145b7b3cSmrgstatic XtAppContext context; 158145b7b3cSmrgstatic XtIntervalId pingTimeout; 159145b7b3cSmrg 160145b7b3cSmrg#ifdef USE_PAM 161145b7b3cSmrgstatic int pamconv(int num_msg, 16239826d68Smrg# ifndef sun 163145b7b3cSmrg const 16439826d68Smrg# endif 165145b7b3cSmrg struct pam_message **msg, 166145b7b3cSmrg struct pam_response **response, void *appdata_ptr); 167145b7b3cSmrg 168145b7b3cSmrg# define PAM_ERROR_PRINT(pamfunc, pamh) \ 169145b7b3cSmrg LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error)) 170145b7b3cSmrg 171145b7b3cSmrg 172145b7b3cSmrgstruct myconv_data { 173145b7b3cSmrg struct display *d; 174145b7b3cSmrg struct greet_info *greet; 175145b7b3cSmrg char *username_display; 176145b7b3cSmrg}; 177145b7b3cSmrg#endif 178145b7b3cSmrg 179145b7b3cSmrg 180145b7b3cSmrg/*ARGSUSED*/ 181145b7b3cSmrgstatic void 182145b7b3cSmrgGreetPingServer ( 183145b7b3cSmrg XtPointer closure, 184145b7b3cSmrg XtIntervalId *intervalId) 185145b7b3cSmrg{ 186145b7b3cSmrg struct display *d; 187145b7b3cSmrg 188145b7b3cSmrg d = (struct display *) closure; 189145b7b3cSmrg if (!PingServer (d, XtDisplay (toplevel))) 190145b7b3cSmrg SessionPingFailed (d); 191145b7b3cSmrg pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, 192145b7b3cSmrg GreetPingServer, (closure)); 193145b7b3cSmrg} 194145b7b3cSmrg 195145b7b3cSmrg/*ARGSUSED*/ 196145b7b3cSmrgstatic void 197145b7b3cSmrgGreetDone ( 198145b7b3cSmrg Widget w, 199145b7b3cSmrg LoginData *data, 200145b7b3cSmrg int status) 201145b7b3cSmrg{ 202145b7b3cSmrg Debug ("GreetDone: %s, (password is %d long)\n", 203145b7b3cSmrg data->name, strlen (data->passwd)); 204145b7b3cSmrg switch (status) { 205145b7b3cSmrg case NOTIFY_OK: 206145b7b3cSmrg#ifndef USE_PAM 207145b7b3cSmrg strncpy (name, data->name, sizeof(name)); 208145b7b3cSmrg name[sizeof(name)-1] = '\0'; 209145b7b3cSmrg strncpy (password, data->passwd, sizeof(password)); 210145b7b3cSmrg password[sizeof(password)-1] = '\0'; 211145b7b3cSmrg#endif 212145b7b3cSmrg code = 0; 213145b7b3cSmrg done = 1; 214145b7b3cSmrg break; 215145b7b3cSmrg case NOTIFY_ABORT: 216145b7b3cSmrg Debug ("RESERVER_DISPLAY\n"); 217145b7b3cSmrg code = RESERVER_DISPLAY; 218145b7b3cSmrg done = 1; 219145b7b3cSmrg break; 220145b7b3cSmrg case NOTIFY_RESTART: 221145b7b3cSmrg Debug ("REMANAGE_DISPLAY\n"); 222145b7b3cSmrg code = REMANAGE_DISPLAY; 223145b7b3cSmrg done = 1; 224145b7b3cSmrg break; 225145b7b3cSmrg case NOTIFY_ABORT_DISPLAY: 226145b7b3cSmrg Debug ("UNMANAGE_DISPLAY\n"); 227145b7b3cSmrg code = UNMANAGE_DISPLAY; 228145b7b3cSmrg done = 1; 229145b7b3cSmrg break; 230145b7b3cSmrg } 231145b7b3cSmrg#ifndef USE_PAM 232145b7b3cSmrg if (done) { 233145b7b3cSmrg bzero (data->name, NAME_LEN); 234145b7b3cSmrg bzero (data->passwd, PASSWORD_LEN); 235145b7b3cSmrg } 236145b7b3cSmrg#endif 237145b7b3cSmrg} 238145b7b3cSmrg 239145b7b3cSmrgstatic Display * 240145b7b3cSmrgInitGreet (struct display *d) 241145b7b3cSmrg{ 242145b7b3cSmrg Arg arglist[10]; 243145b7b3cSmrg int i; 244145b7b3cSmrg static int argc; 245145b7b3cSmrg Screen *scrn; 246145b7b3cSmrg static char *argv[] = { "xlogin", NULL }; 247145b7b3cSmrg Display *dpy; 248145b7b3cSmrg#ifdef USE_XINERAMA 249145b7b3cSmrg XineramaScreenInfo *screens; 250145b7b3cSmrg int s_num; 251145b7b3cSmrg#endif 252145b7b3cSmrg 253145b7b3cSmrg Debug ("greet %s\n", d->name); 254145b7b3cSmrg argc = 1; 255145b7b3cSmrg XtToolkitInitialize (); 256145b7b3cSmrg context = XtCreateApplicationContext(); 257145b7b3cSmrg dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0, 258145b7b3cSmrg &argc, argv); 259145b7b3cSmrg 260145b7b3cSmrg if (!dpy) 261145b7b3cSmrg return NULL; 262145b7b3cSmrg 263145b7b3cSmrg#ifdef XKB 264145b7b3cSmrg { 265145b7b3cSmrg int opcode, evbase, errbase, majret, minret; 266145b7b3cSmrg unsigned int value = XkbPCF_GrabsUseXKBStateMask; 267145b7b3cSmrg if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) { 268145b7b3cSmrg if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value)) 269145b7b3cSmrg LogError ("%s\n", "SetPerClientControls failed"); 270145b7b3cSmrg } 271145b7b3cSmrg } 272145b7b3cSmrg#endif 273145b7b3cSmrg RegisterCloseOnFork (ConnectionNumber (dpy)); 274145b7b3cSmrg 275145b7b3cSmrg SecureDisplay (d, dpy); 276145b7b3cSmrg 277145b7b3cSmrg i = 0; 278145b7b3cSmrg scrn = XDefaultScreenOfDisplay(dpy); 279145b7b3cSmrg XtSetArg(arglist[i], XtNscreen, scrn); i++; 280145b7b3cSmrg XtSetArg(arglist[i], XtNargc, argc); i++; 281145b7b3cSmrg XtSetArg(arglist[i], XtNargv, argv); i++; 282145b7b3cSmrg 283145b7b3cSmrg toplevel = XtAppCreateShell ((String) NULL, "Xlogin", 284145b7b3cSmrg applicationShellWidgetClass, dpy, arglist, i); 285145b7b3cSmrg 286145b7b3cSmrg i = 0; 287145b7b3cSmrg XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++; 288145b7b3cSmrg if (!d->authorize || d->authorizations || !d->authComplain) 289145b7b3cSmrg { 290145b7b3cSmrg XtSetArg (arglist[i], XtNsecureSession, True); i++; 291145b7b3cSmrg } 292145b7b3cSmrg login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel, 293145b7b3cSmrg arglist, i); 294145b7b3cSmrg XtRealizeWidget (toplevel); 295145b7b3cSmrg 296145b7b3cSmrg#ifdef USE_XINERAMA 297145b7b3cSmrg if ( 298145b7b3cSmrg XineramaIsActive(dpy) && 299145b7b3cSmrg (screens = XineramaQueryScreens(dpy, &s_num)) != NULL 300145b7b3cSmrg ) 301145b7b3cSmrg { 302145b7b3cSmrg XWarpPointer(dpy, None, XRootWindowOfScreen (scrn), 303145b7b3cSmrg 0, 0, 0, 0, 304145b7b3cSmrg screens[0].x_org + screens[0].width / 2, 305145b7b3cSmrg screens[0].y_org + screens[0].height / 2); 306145b7b3cSmrg 307145b7b3cSmrg XFree(screens); 308145b7b3cSmrg } 309145b7b3cSmrg else 310145b7b3cSmrg#endif 311145b7b3cSmrg XWarpPointer(dpy, None, XRootWindowOfScreen (scrn), 312145b7b3cSmrg 0, 0, 0, 0, 313145b7b3cSmrg XWidthOfScreen(scrn) / 2, 314145b7b3cSmrg XHeightOfScreen(scrn) / 2); 315145b7b3cSmrg 316145b7b3cSmrg if (d->pingInterval) 317145b7b3cSmrg { 318145b7b3cSmrg pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, 319145b7b3cSmrg GreetPingServer, (XtPointer) d); 320145b7b3cSmrg } 321145b7b3cSmrg return dpy; 322145b7b3cSmrg} 323145b7b3cSmrg 324145b7b3cSmrgstatic void 325145b7b3cSmrgCloseGreet (struct display *d) 326145b7b3cSmrg{ 327145b7b3cSmrg Boolean allow; 328145b7b3cSmrg Arg arglist[1]; 329145b7b3cSmrg Display *dpy = XtDisplay(toplevel); 330145b7b3cSmrg 331145b7b3cSmrg if (pingTimeout) 332145b7b3cSmrg { 333145b7b3cSmrg XtRemoveTimeOut (pingTimeout); 334145b7b3cSmrg pingTimeout = 0; 335145b7b3cSmrg } 336145b7b3cSmrg UnsecureDisplay (d, dpy); 337145b7b3cSmrg XtSetArg (arglist[0], XtNallowAccess, (char *) &allow); 338145b7b3cSmrg XtGetValues (login, arglist, 1); 339145b7b3cSmrg if (allow) 340145b7b3cSmrg { 341145b7b3cSmrg Debug ("Disabling access control\n"); 342145b7b3cSmrg XSetAccessControl (dpy, DisableAccess); 343145b7b3cSmrg } 344145b7b3cSmrg XtDestroyWidget (toplevel); 34543b4c634Smrg toplevel = NULL; 34643b4c634Smrg login = NULL; /* child of toplevel, which we just destroyed */ 347145b7b3cSmrg ClearCloseOnFork (XConnectionNumber (dpy)); 348145b7b3cSmrg XCloseDisplay (dpy); 349145b7b3cSmrg Debug ("Greet connection closed\n"); 350145b7b3cSmrg} 351145b7b3cSmrg 352145b7b3cSmrg#define WHITESPACE 0 353145b7b3cSmrg#define ARGUMENT 1 354145b7b3cSmrg 355145b7b3cSmrgstatic int 356145b7b3cSmrgGreet (struct display *d, struct greet_info *greet) 357145b7b3cSmrg{ 358145b7b3cSmrg XEvent event; 359145b7b3cSmrg Arg arglist[3]; 360145b7b3cSmrg 361145b7b3cSmrg XtSetArg (arglist[0], XtNallowAccess, False); 362145b7b3cSmrg XtSetValues (login, arglist, 1); 363145b7b3cSmrg 364145b7b3cSmrg Debug ("dispatching %s\n", d->name); 365145b7b3cSmrg done = 0; 366145b7b3cSmrg while (!done) { 367145b7b3cSmrg XtAppNextEvent (context, &event); 368145b7b3cSmrg switch (event.type) { 369145b7b3cSmrg case MappingNotify: 370145b7b3cSmrg XRefreshKeyboardMapping(&event.xmapping); 371145b7b3cSmrg break; 372145b7b3cSmrg default: 373145b7b3cSmrg XtDispatchEvent (&event); 374145b7b3cSmrg break; 375145b7b3cSmrg } 376145b7b3cSmrg } 377145b7b3cSmrg XFlush (XtDisplay (toplevel)); 378145b7b3cSmrg Debug ("Done dispatch %s\n", d->name); 379145b7b3cSmrg if (code == 0) 380145b7b3cSmrg { 381145b7b3cSmrg#ifndef USE_PAM 382145b7b3cSmrg char *ptr; 383145b7b3cSmrg unsigned int c,state = WHITESPACE; 38439826d68Smrg 385145b7b3cSmrg /* 386145b7b3cSmrg * Process the name string to get rid of white spaces. 387145b7b3cSmrg */ 388145b7b3cSmrg for (ptr = name; state == WHITESPACE; ptr++) 389145b7b3cSmrg { 390145b7b3cSmrg c = (unsigned int)(*ptr); 391145b7b3cSmrg if (c == ' ') 392145b7b3cSmrg continue; 393145b7b3cSmrg 394145b7b3cSmrg state = ARGUMENT; 395145b7b3cSmrg break; 396145b7b3cSmrg } 397145b7b3cSmrg 398145b7b3cSmrg greet->name = ptr; 399145b7b3cSmrg greet->password = password; 400145b7b3cSmrg#endif /* USE_PAM */ 401145b7b3cSmrg XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string)); 402145b7b3cSmrg XtSetArg (arglist[1], XtNallowNullPasswd, (char *) &(greet->allow_null_passwd)); 403145b7b3cSmrg XtSetArg (arglist[2], XtNallowRootLogin, (char *) &(greet->allow_root_login)); 404145b7b3cSmrg XtGetValues (login, arglist, 3); 405145b7b3cSmrg Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>"); 406145b7b3cSmrg } 407145b7b3cSmrg return code; 408145b7b3cSmrg} 409145b7b3cSmrg 410145b7b3cSmrg 411145b7b3cSmrgstatic void 412145b7b3cSmrgFailedLogin (struct display *d, struct greet_info *greet) 413145b7b3cSmrg{ 41439826d68Smrg#ifdef USE_SYSLOG 41543b4c634Smrg const char *username = greet->name; 41643b4c634Smrg 41743b4c634Smrg if (username == NULL) 41843b4c634Smrg username = "username unavailable"; 41943b4c634Smrg 420145b7b3cSmrg syslog(LOG_AUTHPRIV|LOG_NOTICE, 421145b7b3cSmrg "LOGIN FAILURE ON %s, %s", 42243b4c634Smrg d->name, username); 423145b7b3cSmrg#endif 424145b7b3cSmrg DrawFail (login); 425145b7b3cSmrg#ifndef USE_PAM 426145b7b3cSmrg bzero (greet->name, strlen(greet->name)); 427145b7b3cSmrg bzero (greet->password, strlen(greet->password)); 428145b7b3cSmrg#endif 429145b7b3cSmrg} 430145b7b3cSmrg 431145b7b3cSmrg_X_EXPORT 432145b7b3cSmrggreet_user_rtn GreetUser( 433145b7b3cSmrg struct display *d, 434145b7b3cSmrg Display ** dpy, 435145b7b3cSmrg struct verify_info *verify, 436145b7b3cSmrg struct greet_info *greet, 437145b7b3cSmrg struct dlfuncs *dlfuncs) 438145b7b3cSmrg{ 439145b7b3cSmrg int i; 440145b7b3cSmrg 441145b7b3cSmrg#ifdef GREET_LIB 442145b7b3cSmrg/* 443145b7b3cSmrg * These must be set before they are used. 444145b7b3cSmrg */ 445145b7b3cSmrg __xdm_PingServer = dlfuncs->_PingServer; 446145b7b3cSmrg __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed; 447145b7b3cSmrg __xdm_Debug = dlfuncs->_Debug; 448145b7b3cSmrg __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork; 449145b7b3cSmrg __xdm_SecureDisplay = dlfuncs->_SecureDisplay; 450145b7b3cSmrg __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay; 451145b7b3cSmrg __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork; 452145b7b3cSmrg __xdm_SetupDisplay = dlfuncs->_SetupDisplay; 453145b7b3cSmrg __xdm_LogError = dlfuncs->_LogError; 454145b7b3cSmrg __xdm_SessionExit = dlfuncs->_SessionExit; 455145b7b3cSmrg __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources; 456145b7b3cSmrg __xdm_source = dlfuncs->_source; 457145b7b3cSmrg __xdm_defaultEnv = dlfuncs->_defaultEnv; 458145b7b3cSmrg __xdm_setEnv = dlfuncs->_setEnv; 459145b7b3cSmrg __xdm_putEnv = dlfuncs->_putEnv; 460145b7b3cSmrg __xdm_parseArgs = dlfuncs->_parseArgs; 461145b7b3cSmrg __xdm_printEnv = dlfuncs->_printEnv; 462145b7b3cSmrg __xdm_systemEnv = dlfuncs->_systemEnv; 463145b7b3cSmrg __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem; 464145b7b3cSmrg __xdm_setgrent = dlfuncs->_setgrent; 465145b7b3cSmrg __xdm_getgrent = dlfuncs->_getgrent; 466145b7b3cSmrg __xdm_endgrent = dlfuncs->_endgrent; 46739826d68Smrg# ifdef USESHADOW 468145b7b3cSmrg __xdm_getspnam = dlfuncs->_getspnam; 46939826d68Smrg# ifndef QNX4 470145b7b3cSmrg __xdm_endspent = dlfuncs->_endspent; 47139826d68Smrg# endif /* QNX4 doesn't use endspent */ 47239826d68Smrg# endif 473145b7b3cSmrg __xdm_getpwnam = dlfuncs->_getpwnam; 47439826d68Smrg# if defined(linux) || defined(__GLIBC__) 475145b7b3cSmrg __xdm_endpwent = dlfuncs->_endpwent; 47639826d68Smrg# endif 477145b7b3cSmrg __xdm_crypt = dlfuncs->_crypt; 47839826d68Smrg# ifdef USE_PAM 479145b7b3cSmrg __xdm_thepamhp = dlfuncs->_thepamhp; 48039826d68Smrg# endif 481145b7b3cSmrg#endif 482145b7b3cSmrg 483145b7b3cSmrg *dpy = InitGreet (d); 484145b7b3cSmrg /* 485145b7b3cSmrg * Run the setup script - note this usually will not work when 486145b7b3cSmrg * the server is grabbed, so we don't even bother trying. 487145b7b3cSmrg */ 488145b7b3cSmrg if (!d->grabServer) 489145b7b3cSmrg SetupDisplay (d); 490145b7b3cSmrg if (!*dpy) { 491145b7b3cSmrg LogError ("Cannot reopen display %s for greet window\n", d->name); 492145b7b3cSmrg exit (RESERVER_DISPLAY); 493145b7b3cSmrg } 494145b7b3cSmrg 495145b7b3cSmrg for (;;) { 496145b7b3cSmrg#ifdef USE_PAM 497145b7b3cSmrg 498145b7b3cSmrg /* Run PAM conversation */ 499145b7b3cSmrg pam_handle_t **pamhp = thepamhp(); 500145b7b3cSmrg int pam_error; 501145b7b3cSmrg unsigned int pam_flags = 0; 502145b7b3cSmrg struct myconv_data pcd = { d, greet, NULL }; 503145b7b3cSmrg struct pam_conv pc = { pamconv, &pcd }; 504145b7b3cSmrg const char * pam_fname; 50543b4c634Smrg char * username = NULL; 506145b7b3cSmrg const char * login_prompt; 507145b7b3cSmrg 508145b7b3cSmrg 50943b4c634Smrg SetPrompt(login, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_NOT_SHOWN, False); 510145b7b3cSmrg login_prompt = GetPrompt(login, LOGIN_PROMPT_USERNAME); 51143b4c634Smrg SetPrompt(login, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_NOT_SHOWN, False); 51239826d68Smrg 51339826d68Smrg# define RUN_AND_CHECK_PAM_ERROR(function, args) \ 514145b7b3cSmrg do { \ 515145b7b3cSmrg pam_error = function args; \ 516145b7b3cSmrg if (pam_error != PAM_SUCCESS) { \ 517145b7b3cSmrg PAM_ERROR_PRINT(#function, *pamhp); \ 518145b7b3cSmrg goto pam_done; \ 519145b7b3cSmrg } \ 52039826d68Smrg } while (0) 52139826d68Smrg 522145b7b3cSmrg 523145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_start, 524145b7b3cSmrg ("xdm", NULL, &pc, pamhp)); 525145b7b3cSmrg 526145b7b3cSmrg /* Set default login prompt to xdm's default from Xresources */ 527145b7b3cSmrg if (login_prompt != NULL) { 528145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_set_item, 529145b7b3cSmrg (*pamhp, PAM_USER_PROMPT, login_prompt)); 530145b7b3cSmrg } 531145b7b3cSmrg 532145b7b3cSmrg if (d->name[0] != ':') { /* Displaying to remote host */ 533145b7b3cSmrg char *hostname = strdup(d->name); 534145b7b3cSmrg 535145b7b3cSmrg if (hostname == NULL) { 536145b7b3cSmrg LogOutOfMem("GreetUser"); 537145b7b3cSmrg } else { 538145b7b3cSmrg char *colon = strrchr(hostname, ':'); 53939826d68Smrg 540145b7b3cSmrg if (colon != NULL) 541145b7b3cSmrg *colon = '\0'; 54239826d68Smrg 543145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_set_item, 544145b7b3cSmrg (*pamhp, PAM_RHOST, hostname)); 545145b7b3cSmrg free(hostname); 546145b7b3cSmrg } 547145b7b3cSmrg } else 548145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, d->name)); 54939826d68Smrg 550145b7b3cSmrg if (!greet->allow_null_passwd) { 551145b7b3cSmrg pam_flags |= PAM_DISALLOW_NULL_AUTHTOK; 552145b7b3cSmrg } 553145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_authenticate, 554145b7b3cSmrg (*pamhp, pam_flags)); 55539826d68Smrg 556145b7b3cSmrg /* handle expired passwords */ 557145b7b3cSmrg pam_error = pam_acct_mgmt(*pamhp, pam_flags); 558145b7b3cSmrg pam_fname = "pam_acct_mgmt"; 559145b7b3cSmrg if (pam_error == PAM_NEW_AUTHTOK_REQD) { 560145b7b3cSmrg ShowChangePasswdMessage(login); 561145b7b3cSmrg do { 562145b7b3cSmrg pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK); 563145b7b3cSmrg } while ((pam_error == PAM_AUTHTOK_ERR) || 564145b7b3cSmrg (pam_error == PAM_TRY_AGAIN)); 565145b7b3cSmrg pam_fname = "pam_chauthtok"; 566145b7b3cSmrg } 567145b7b3cSmrg if (pam_error != PAM_SUCCESS) { 568145b7b3cSmrg PAM_ERROR_PRINT(pam_fname, *pamhp); 569145b7b3cSmrg goto pam_done; 570145b7b3cSmrg } 57139826d68Smrg 572145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_setcred, 573145b7b3cSmrg (*pamhp, 0)); 574145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_get_item, 575145b7b3cSmrg (*pamhp, PAM_USER, (void *) &username)); 576145b7b3cSmrg if (username != NULL) { 577145b7b3cSmrg Debug("PAM_USER: %s\n", username); 578145b7b3cSmrg greet->name = username; 579145b7b3cSmrg greet->password = NULL; 580145b7b3cSmrg } 58139826d68Smrg 582145b7b3cSmrg pam_done: 583145b7b3cSmrg if (code != 0) 584145b7b3cSmrg { 585145b7b3cSmrg CloseGreet (d); 586145b7b3cSmrg SessionExit (d, code, FALSE); 587145b7b3cSmrg } 588145b7b3cSmrg if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) { 589145b7b3cSmrg SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False); 590145b7b3cSmrg SetValue (login, 1, NULL); 591145b7b3cSmrg break; 592145b7b3cSmrg } else { 59339826d68Smrg /* Try to fill in username for failed login error log */ 59439826d68Smrg if (greet->name == NULL) { 59539826d68Smrg if (username == NULL) { 59639826d68Smrg RUN_AND_CHECK_PAM_ERROR(pam_get_item, 59739826d68Smrg (*pamhp, PAM_USER, 59839826d68Smrg (void *) &username)); 59939826d68Smrg } 60039826d68Smrg greet->name = username; 60139826d68Smrg } 60239826d68Smrg FailedLogin (d, greet); 603145b7b3cSmrg RUN_AND_CHECK_PAM_ERROR(pam_end, 604145b7b3cSmrg (*pamhp, pam_error)); 605145b7b3cSmrg } 606145b7b3cSmrg#else /* not PAM */ 607145b7b3cSmrg /* 608145b7b3cSmrg * Greet user, requesting name/password 609145b7b3cSmrg */ 610145b7b3cSmrg code = Greet (d, greet); 611145b7b3cSmrg if (code != 0) 612145b7b3cSmrg { 613145b7b3cSmrg CloseGreet (d); 614145b7b3cSmrg SessionExit (d, code, FALSE); 615145b7b3cSmrg } 616145b7b3cSmrg /* 617145b7b3cSmrg * Verify user 618145b7b3cSmrg */ 619145b7b3cSmrg if (Verify (d, greet, verify)) 620145b7b3cSmrg break; 621145b7b3cSmrg else 622145b7b3cSmrg FailedLogin (d, greet); 623145b7b3cSmrg#endif 624145b7b3cSmrg } 625145b7b3cSmrg DeleteXloginResources (d, *dpy); 626145b7b3cSmrg CloseGreet (d); 627145b7b3cSmrg Debug ("Greet loop finished\n"); 628145b7b3cSmrg /* 629145b7b3cSmrg * Run system-wide initialization file 630145b7b3cSmrg */ 631145b7b3cSmrg if (source (verify->systemEnviron, d->startup) != 0) 632145b7b3cSmrg { 633145b7b3cSmrg Debug ("Startup program %s exited with non-zero status\n", 634145b7b3cSmrg d->startup); 635145b7b3cSmrg SessionExit (d, OBEYSESS_DISPLAY, FALSE); 636145b7b3cSmrg } 637145b7b3cSmrg /* 638145b7b3cSmrg * for user-based authorization schemes, 639145b7b3cSmrg * add the user to the server's allowed "hosts" list. 640145b7b3cSmrg */ 641145b7b3cSmrg for (i = 0; i < d->authNum; i++) 642145b7b3cSmrg { 643145b7b3cSmrg#ifdef SECURE_RPC 644145b7b3cSmrg if (d->authorizations[i]->name_length == 9 && 645145b7b3cSmrg memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) 646145b7b3cSmrg { 647145b7b3cSmrg XHostAddress addr; 648145b7b3cSmrg char netname[MAXNETNAMELEN+1]; 649145b7b3cSmrg char domainname[MAXNETNAMELEN+1]; 65039826d68Smrg 651145b7b3cSmrg getdomainname(domainname, sizeof domainname); 652145b7b3cSmrg user2netname (netname, verify->uid, domainname); 653145b7b3cSmrg addr.family = FamilyNetname; 654145b7b3cSmrg addr.length = strlen (netname); 655145b7b3cSmrg addr.address = netname; 656145b7b3cSmrg XAddHost (*dpy, &addr); 657145b7b3cSmrg } 658145b7b3cSmrg#endif 659145b7b3cSmrg#ifdef K5AUTH 660145b7b3cSmrg if (d->authorizations[i]->name_length == 14 && 661145b7b3cSmrg memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) 662145b7b3cSmrg { 663145b7b3cSmrg /* Update server's auth file with user-specific info. 664145b7b3cSmrg * Don't need to AddHost because X server will do that 665145b7b3cSmrg * automatically when it reads the cache we are about 666145b7b3cSmrg * to point it at. 667145b7b3cSmrg */ 668145b7b3cSmrg extern Xauth *Krb5GetAuthFor(); 669145b7b3cSmrg 670145b7b3cSmrg XauDisposeAuth (d->authorizations[i]); 671145b7b3cSmrg d->authorizations[i] = 672145b7b3cSmrg Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name); 673145b7b3cSmrg SaveServerAuthorizations (d, d->authorizations, d->authNum); 67439826d68Smrg } 675145b7b3cSmrg#endif 676145b7b3cSmrg } 677145b7b3cSmrg 678145b7b3cSmrg return Greet_Success; 679145b7b3cSmrg} 680145b7b3cSmrg 681145b7b3cSmrg 682145b7b3cSmrg#ifdef USE_PAM 683145b7b3cSmrgstatic int pamconv(int num_msg, 68439826d68Smrg# ifndef sun 685145b7b3cSmrg const 68639826d68Smrg# endif 687145b7b3cSmrg struct pam_message **msg, 688145b7b3cSmrg struct pam_response **response, void *appdata_ptr) 689145b7b3cSmrg{ 690145b7b3cSmrg int i; 691145b7b3cSmrg int greetCode; 692145b7b3cSmrg int status = PAM_SUCCESS; 693145b7b3cSmrg const char *pam_msg_styles[5] 694145b7b3cSmrg = { "<invalid pam msg style>", 695145b7b3cSmrg "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON", 696145b7b3cSmrg "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ; 69739826d68Smrg 698145b7b3cSmrg struct pam_message *m; 699145b7b3cSmrg struct pam_response *r; 700145b7b3cSmrg 701145b7b3cSmrg struct myconv_data *d = (struct myconv_data *) appdata_ptr; 702145b7b3cSmrg 703145b7b3cSmrg pam_handle_t **pamhp = thepamhp(); 70439826d68Smrg 705145b7b3cSmrg *response = calloc(num_msg, sizeof (struct pam_response)); 706145b7b3cSmrg if (*response == NULL) 707145b7b3cSmrg return (PAM_BUF_ERR); 708145b7b3cSmrg 70939826d68Smrg m = (struct pam_message *)*msg; 710145b7b3cSmrg r = *response; 711145b7b3cSmrg 71243b4c634Smrg if (login == NULL) { 71343b4c634Smrg status = PAM_CONV_ERR; 71443b4c634Smrg goto pam_error; 71543b4c634Smrg } 71643b4c634Smrg 717145b7b3cSmrg for (i = 0; i < num_msg; i++ , m++ , r++) { 718145b7b3cSmrg char *username; 719145b7b3cSmrg int promptId = 0; 720145b7b3cSmrg loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF; 721145b7b3cSmrg 722145b7b3cSmrg if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS) 723145b7b3cSmrg && (username != NULL) && (*username != '\0')) { 724145b7b3cSmrg SetPrompt(login, LOGIN_PROMPT_USERNAME, 725145b7b3cSmrg NULL, LOGIN_TEXT_INFO, False); 726145b7b3cSmrg SetValue(login, LOGIN_PROMPT_USERNAME, username); 727145b7b3cSmrg promptId = 1; 72839826d68Smrg } 72939826d68Smrg 730145b7b3cSmrg Debug("pam_msg: %s (%d): '%s'\n", 731145b7b3cSmrg ((m->msg_style > 0) && (m->msg_style <= 4)) ? 732145b7b3cSmrg pam_msg_styles[m->msg_style] : pam_msg_styles[0], 733145b7b3cSmrg m->msg_style, m->msg); 734145b7b3cSmrg 735145b7b3cSmrg switch (m->msg_style) { 736145b7b3cSmrg case PAM_ERROR_MSG: 737145b7b3cSmrg ErrorMessage(login, m->msg, True); 738145b7b3cSmrg break; 739145b7b3cSmrg 740145b7b3cSmrg case PAM_TEXT_INFO: 741145b7b3cSmrg SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True); 742145b7b3cSmrg SetValue (login, promptId, NULL); 743145b7b3cSmrg break; 74439826d68Smrg 745145b7b3cSmrg case PAM_PROMPT_ECHO_ON: 746145b7b3cSmrg pStyle = LOGIN_PROMPT_ECHO_ON; 747145b7b3cSmrg /* FALLTHROUGH */ 748145b7b3cSmrg case PAM_PROMPT_ECHO_OFF: 749145b7b3cSmrg SetPrompt (login, promptId, m->msg, pStyle, False); 750145b7b3cSmrg SetValue (login, promptId, NULL); 751145b7b3cSmrg greetCode = Greet (d->d, d->greet); 752145b7b3cSmrg if (greetCode != 0) { 753145b7b3cSmrg status = PAM_CONV_ERR; 754145b7b3cSmrg goto pam_error; 755145b7b3cSmrg } else { 756145b7b3cSmrg r->resp = strdup(GetValue(login, promptId)); 757145b7b3cSmrg SetValue(login, promptId, NULL); 758145b7b3cSmrg if (r->resp == NULL) { 759145b7b3cSmrg status = PAM_BUF_ERR; 760145b7b3cSmrg goto pam_error; 761145b7b3cSmrg } 762145b7b3cSmrg /* Debug("pam_resp: '%s'\n", r->resp); */ 763145b7b3cSmrg } 764145b7b3cSmrg break; 765145b7b3cSmrg 766145b7b3cSmrg default: 767145b7b3cSmrg LogError("Unknown PAM msg_style: %d\n", m->msg_style); 768145b7b3cSmrg } 769145b7b3cSmrg } 77039826d68Smrg pam_error: 771145b7b3cSmrg if (status != PAM_SUCCESS) { 772145b7b3cSmrg /* free responses */ 773145b7b3cSmrg r = *response; 774145b7b3cSmrg for (i = 0; i < num_msg; i++, r++) { 775145b7b3cSmrg if (r->resp) { 776145b7b3cSmrg bzero(r->resp, strlen(r->resp)); 777145b7b3cSmrg free(r->resp); 778145b7b3cSmrg } 779145b7b3cSmrg } 780145b7b3cSmrg free(*response); 781145b7b3cSmrg *response = NULL; 782145b7b3cSmrg } 783145b7b3cSmrg return status; 784145b7b3cSmrg} 785145b7b3cSmrg#endif 786