1/* 2 3Copyright 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28/* 29 * Copyright (c) 2006, Oracle and/or its affiliates. 30 * 31 * Permission is hereby granted, free of charge, to any person obtaining a 32 * copy of this software and associated documentation files (the "Software"), 33 * to deal in the Software without restriction, including without limitation 34 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 35 * and/or sell copies of the Software, and to permit persons to whom the 36 * Software is furnished to do so, subject to the following conditions: 37 * 38 * The above copyright notice and this permission notice (including the next 39 * paragraph) shall be included in all copies or substantial portions of the 40 * Software. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 45 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 47 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 48 * DEALINGS IN THE SOFTWARE. 49 */ 50 51 52/* 53 * xdm - display manager daemon 54 * Author: Keith Packard, X Consortium 55 * 56 * widget to get username/password 57 * 58 */ 59 60#ifdef HAVE_CONFIG_H 61# include "config.h" 62#endif 63 64#include <X11/Intrinsic.h> 65#include <X11/StringDefs.h> 66#include <X11/Shell.h> 67#include <X11/XKBlib.h> 68 69#ifdef USE_XINERAMA 70# include <X11/extensions/Xinerama.h> 71#endif 72 73#include "dm.h" 74#include "dm_error.h" 75#include "greet.h" 76#include "LoginP.h" 77 78#if defined(HAVE_OPENLOG) && defined(HAVE_SYSLOG_H) 79# define USE_SYSLOG 80# include <syslog.h> 81# ifndef LOG_AUTHPRIV 82# define LOG_AUTHPRIV LOG_AUTH 83# endif 84# ifndef LOG_PID 85# define LOG_PID 0 86# endif 87#endif 88 89#include <string.h> 90 91#if defined(SECURE_RPC) && defined(sun) 92/* Go figure, there's no getdomainname() prototype available */ 93extern int getdomainname(char *name, size_t len); 94#endif 95 96/* 97 * Function pointers filled in by the initial call ito the library 98 */ 99 100int (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL; 101void (*__xdm_SessionPingFailed)(struct display *d) = NULL; 102void (*__xdm_Debug)(const char * fmt, ...) = NULL; 103void (*__xdm_RegisterCloseOnFork)(int fd) = NULL; 104void (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL; 105void (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL; 106void (*__xdm_ClearCloseOnFork)(int fd) = NULL; 107void (*__xdm_SetupDisplay)(struct display *d) = NULL; 108void (*__xdm_LogError)(const char * fmt, ...) = NULL; 109void (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL; 110void (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL; 111int (*__xdm_source)(char **environ, char *file) = NULL; 112char **(*__xdm_defaultEnv)(void) = NULL; 113char **(*__xdm_setEnv)(char **e, const char *name, const char *value) = NULL; 114char **(*__xdm_putEnv)(const char *string, char **env) = NULL; 115char **(*__xdm_parseArgs)(char **argv, const char *string) = NULL; 116void (*__xdm_printEnv)(char **e) = NULL; 117char **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL; 118void (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL; 119void (*__xdm_setgrent)(void) = NULL; 120struct group *(*__xdm_getgrent)(void) = NULL; 121void (*__xdm_endgrent)(void) = NULL; 122# ifdef HAVE_GETSPNAM 123struct spwd *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL; 124void (*__xdm_endspent)(void) = NULL; 125# endif 126struct passwd *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL; 127# if defined(linux) || defined(__GLIBC__) 128void (*__xdm_endpwent)(void) = NULL; 129# endif 130char *(*__xdm_crypt)(CRYPT_ARGS) = NULL; 131# ifdef USE_PAM 132pam_handle_t **(*__xdm_thepamhp)(void) = NULL; 133# endif 134 135#ifdef SECURE_RPC 136# include <rpc/rpc.h> 137# include <rpc/key_prot.h> 138#endif 139 140#ifdef K5AUTH 141# include <krb5/krb5.h> 142#endif 143 144static int done, code; 145#ifndef USE_PAM 146static char name[NAME_LEN], password[PASSWORD_LEN]; 147#endif 148static Widget toplevel; 149static Widget login; 150static XtAppContext context; 151static XtIntervalId pingTimeout; 152 153#ifdef USE_PAM 154 155#ifdef __sun 156/* Solaris does not const qualify arguments to pam_get_item() or the 157 PAM conversation function that Linux-PAM and others do. */ 158# define XDM_PAM_QUAL /**/ 159#else 160# define XDM_PAM_QUAL const 161#endif 162 163static int pamconv(int num_msg, XDM_PAM_QUAL struct pam_message **msg, 164 struct pam_response **response, void *appdata_ptr); 165 166# define PAM_ERROR_PRINT(pamfunc, pamh) \ 167 LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error)) 168 169 170struct myconv_data { 171 struct display *d; 172 struct greet_info *greet; 173 char *username_display; 174}; 175#endif 176 177 178/*ARGSUSED*/ 179static void 180GreetPingServer ( 181 XtPointer closure, 182 XtIntervalId *intervalId) 183{ 184 struct display *d; 185 186 d = (struct display *) closure; 187 if (!PingServer (d, XtDisplay (toplevel))) 188 SessionPingFailed (d); 189 pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, 190 GreetPingServer, (closure)); 191} 192 193/*ARGSUSED*/ 194static void 195GreetDone ( 196 Widget w, 197 LoginData *data, 198 int status) 199{ 200 Debug ("GreetDone: %s, (password is %zu long)\n", 201 data->name, strlen (data->passwd)); 202 switch (status) { 203 case NOTIFY_OK: 204#ifndef USE_PAM 205 strncpy (name, data->name, sizeof(name)); 206 name[sizeof(name)-1] = '\0'; 207 strncpy (password, data->passwd, sizeof(password)); 208 password[sizeof(password)-1] = '\0'; 209#endif 210 code = 0; 211 done = 1; 212 break; 213 case NOTIFY_ABORT: 214 Debug ("RESERVER_DISPLAY\n"); 215 code = RESERVER_DISPLAY; 216 done = 1; 217 break; 218 case NOTIFY_RESTART: 219 Debug ("REMANAGE_DISPLAY\n"); 220 code = REMANAGE_DISPLAY; 221 done = 1; 222 break; 223 case NOTIFY_ABORT_DISPLAY: 224 Debug ("UNMANAGE_DISPLAY\n"); 225 code = UNMANAGE_DISPLAY; 226 done = 1; 227 break; 228 } 229#ifndef USE_PAM 230 if (done) { 231 bzero (data->name, NAME_LEN); 232 bzero (data->passwd, PASSWORD_LEN); 233 } 234#endif 235} 236 237static Display * 238InitGreet (struct display *d) 239{ 240 Arg arglist[10]; 241 int i; 242 static int argc; 243 Screen *scrn; 244 static char *argv[] = { "xlogin", NULL }; 245 Display *dpy; 246#ifdef USE_XINERAMA 247 XineramaScreenInfo *screens; 248 int s_num; 249#endif 250 251 Debug ("greet %s\n", d->name); 252 argc = 1; 253 XtToolkitInitialize (); 254 context = XtCreateApplicationContext(); 255 dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", NULL, 0, 256 &argc, argv); 257 258 if (!dpy) 259 return NULL; 260 261#ifdef XKB 262 { 263 int opcode, evbase, errbase, majret, minret; 264 unsigned int value = XkbPCF_GrabsUseXKBStateMask; 265 if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) { 266 if (!XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value)) 267 LogError ("%s\n", "SetPerClientControls failed"); 268 } 269 } 270#endif 271 RegisterCloseOnFork (ConnectionNumber (dpy)); 272 273 SecureDisplay (d, dpy); 274 275 i = 0; 276 scrn = XDefaultScreenOfDisplay(dpy); 277 XtSetArg(arglist[i], XtNscreen, scrn); i++; 278 XtSetArg(arglist[i], XtNargc, argc); i++; 279 XtSetArg(arglist[i], XtNargv, argv); i++; 280 281 toplevel = XtAppCreateShell ((String) NULL, "Xlogin", 282 applicationShellWidgetClass, dpy, arglist, i); 283 284 i = 0; 285 XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++; 286 if (!d->authorize || d->authorizations || !d->authComplain) 287 { 288 XtSetArg (arglist[i], XtNsecureSession, True); i++; 289 } 290 login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel, 291 arglist, i); 292 XtRealizeWidget (toplevel); 293 294#ifdef USE_XINERAMA 295 if ( 296 XineramaIsActive(dpy) && 297 (screens = XineramaQueryScreens(dpy, &s_num)) != NULL 298 ) 299 { 300 XWarpPointer(dpy, None, XRootWindowOfScreen (scrn), 301 0, 0, 0, 0, 302 screens[0].x_org + screens[0].width / 2, 303 screens[0].y_org + screens[0].height / 2); 304 305 XFree(screens); 306 } 307 else 308#endif 309 XWarpPointer(dpy, None, XRootWindowOfScreen (scrn), 310 0, 0, 0, 0, 311 XWidthOfScreen(scrn) / 2, 312 XHeightOfScreen(scrn) / 2); 313 314 if (d->pingInterval) 315 { 316 pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, 317 GreetPingServer, (XtPointer) d); 318 } 319 return dpy; 320} 321 322static void 323CloseGreet (struct display *d) 324{ 325 Boolean allow; 326 Arg arglist[1]; 327 Display *dpy = XtDisplay(toplevel); 328 329 if (pingTimeout) 330 { 331 XtRemoveTimeOut (pingTimeout); 332 pingTimeout = 0; 333 } 334 UnsecureDisplay (d, dpy); 335 XtSetArg (arglist[0], XtNallowAccess, (char *) &allow); 336 XtGetValues (login, arglist, 1); 337 if (allow) 338 { 339 Debug ("Disabling access control\n"); 340 XSetAccessControl (dpy, DisableAccess); 341 } 342 XtDestroyWidget (toplevel); 343 toplevel = NULL; 344 login = NULL; /* child of toplevel, which we just destroyed */ 345 ClearCloseOnFork (XConnectionNumber (dpy)); 346 XCloseDisplay (dpy); 347 Debug ("Greet connection closed\n"); 348} 349 350#define WHITESPACE 0 351#define ARGUMENT 1 352 353static int 354Greet (struct display *d, struct greet_info *greet) 355{ 356 XEvent event; 357 Arg arglist[1]; 358 359 XtSetArg (arglist[0], XtNallowAccess, False); 360 XtSetValues (login, arglist, 1); 361 362 Debug ("dispatching %s\n", d->name); 363 done = 0; 364 while (!done) { 365 XtAppNextEvent (context, &event); 366 switch (event.type) { 367 case MappingNotify: 368 XRefreshKeyboardMapping(&event.xmapping); 369 break; 370 default: 371 XtDispatchEvent (&event); 372 break; 373 } 374 } 375 XFlush (XtDisplay (toplevel)); 376 Debug ("Done dispatch %s\n", d->name); 377 if (code == 0) 378 { 379#ifndef USE_PAM 380 char *ptr; 381 unsigned int c,state = WHITESPACE; 382 383 /* 384 * Process the name string to get rid of white spaces. 385 */ 386 for (ptr = name; state == WHITESPACE; ptr++) 387 { 388 c = (unsigned int)(*ptr); 389 if (c == ' ') 390 continue; 391 392 state = ARGUMENT; 393 break; 394 } 395 396 greet->name = ptr; 397 greet->password = password; 398#endif /* USE_PAM */ 399 XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string)); 400 XtGetValues (login, arglist, 1); 401 Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>"); 402 } 403 return code; 404} 405 406 407static void 408FailedLogin (struct display *d, const char *username) 409{ 410#ifdef USE_SYSLOG 411 if (username == NULL) 412 username = "username unavailable"; 413 414 syslog(LOG_AUTHPRIV|LOG_NOTICE, 415 "LOGIN FAILURE ON %s, %s", 416 d->name, username); 417#endif 418 DrawFail (login); 419} 420 421_X_EXPORT 422greet_user_rtn GreetUser( 423 struct display *d, 424 Display ** dpy, 425 struct verify_info *verify, 426 struct greet_info *greet, 427 struct dlfuncs *dlfuncs) 428{ 429 int i; 430 Arg arglist[2]; 431 432/* 433 * These must be set before they are used. 434 */ 435 __xdm_PingServer = dlfuncs->_PingServer; 436 __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed; 437 __xdm_Debug = dlfuncs->_Debug; 438 __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork; 439 __xdm_SecureDisplay = dlfuncs->_SecureDisplay; 440 __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay; 441 __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork; 442 __xdm_SetupDisplay = dlfuncs->_SetupDisplay; 443 __xdm_LogError = dlfuncs->_LogError; 444 __xdm_SessionExit = dlfuncs->_SessionExit; 445 __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources; 446 __xdm_source = dlfuncs->_source; 447 __xdm_defaultEnv = dlfuncs->_defaultEnv; 448 __xdm_setEnv = dlfuncs->_setEnv; 449 __xdm_putEnv = dlfuncs->_putEnv; 450 __xdm_parseArgs = dlfuncs->_parseArgs; 451 __xdm_printEnv = dlfuncs->_printEnv; 452 __xdm_systemEnv = dlfuncs->_systemEnv; 453 __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem; 454 __xdm_setgrent = dlfuncs->_setgrent; 455 __xdm_getgrent = dlfuncs->_getgrent; 456 __xdm_endgrent = dlfuncs->_endgrent; 457# ifdef HAVE_GETSPNAM 458 __xdm_getspnam = dlfuncs->_getspnam; 459 __xdm_endspent = dlfuncs->_endspent; 460# endif 461 __xdm_getpwnam = dlfuncs->_getpwnam; 462# if defined(linux) || defined(__GLIBC__) 463 __xdm_endpwent = dlfuncs->_endpwent; 464# endif 465 __xdm_crypt = dlfuncs->_crypt; 466# ifdef USE_PAM 467 __xdm_thepamhp = dlfuncs->_thepamhp; 468# endif 469 470 *dpy = InitGreet (d); 471 /* 472 * Run the setup script - note this usually will not work when 473 * the server is grabbed, so we don't even bother trying. 474 */ 475 if (!d->grabServer) 476 SetupDisplay (d); 477 if (!*dpy) { 478 LogError ("Cannot reopen display %s for greet window\n", d->name); 479 exit (RESERVER_DISPLAY); 480 } 481 482 XtSetArg (arglist[0], XtNallowNullPasswd, 483 (char *) &(greet->allow_null_passwd)); 484 XtSetArg (arglist[1], XtNallowRootLogin, 485 (char *) &(greet->allow_root_login)); 486 XtGetValues (login, arglist, 2); 487 488 for (;;) { 489#ifdef USE_PAM 490 491 /* Run PAM conversation */ 492 pam_handle_t **pamhp = thepamhp(); 493 int pam_error; 494 unsigned int pam_flags = 0; 495 struct myconv_data pcd = { d, greet, NULL }; 496 struct pam_conv pc = { pamconv, &pcd }; 497 const char * pam_fname; 498 const char * login_prompt; 499 500 501 SetPrompt(login, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_NOT_SHOWN, False); 502 login_prompt = GetPrompt(login, LOGIN_PROMPT_USERNAME); 503 SetPrompt(login, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_NOT_SHOWN, False); 504 505# define RUN_AND_CHECK_PAM_ERROR(function, args) \ 506 do { \ 507 pam_error = function args; \ 508 if (pam_error != PAM_SUCCESS) { \ 509 PAM_ERROR_PRINT(#function, *pamhp); \ 510 goto pam_done; \ 511 } \ 512 } while (0) 513 514 515 RUN_AND_CHECK_PAM_ERROR(pam_start, 516 ("xdm", NULL, &pc, pamhp)); 517 518 /* Set default login prompt to xdm's default from Xresources */ 519 if (login_prompt != NULL) { 520 RUN_AND_CHECK_PAM_ERROR(pam_set_item, 521 (*pamhp, PAM_USER_PROMPT, login_prompt)); 522 } 523 524 if (d->name[0] != ':') { /* Displaying to remote host */ 525 char *hostname = strdup(d->name); 526 527 if (hostname == NULL) { 528 LogOutOfMem("GreetUser"); 529 } else { 530 char *colon = strrchr(hostname, ':'); 531 532 if (colon != NULL) 533 *colon = '\0'; 534 535 RUN_AND_CHECK_PAM_ERROR(pam_set_item, 536 (*pamhp, PAM_RHOST, hostname)); 537 free(hostname); 538 } 539 } else { /* Displaying on local host */ 540 const char *ttyname = NULL; 541 542#ifdef __sun 543 /* Solaris PAM & auditing insist this is a device file that can 544 be found under /dev, so we can't use the display name */ 545 char vtpath[16]; 546 547 if ((d->windowPath) && !(strchr(d->windowPath, ':'))) { 548 /* if path is simply a VT, with no intermediaries, use it */ 549 snprintf(vtpath, sizeof(vtpath), "/dev/vt/%s", d->windowPath); 550 ttyname = vtpath; 551 } 552#else 553 /* On all other OS'es we just pass the display name for PAM_TTY */ 554 ttyname = d->name; 555#endif 556 RUN_AND_CHECK_PAM_ERROR(pam_set_item, (*pamhp, PAM_TTY, ttyname)); 557 } 558 559 if (!greet->allow_null_passwd) { 560 pam_flags |= PAM_DISALLOW_NULL_AUTHTOK; 561 } 562 RUN_AND_CHECK_PAM_ERROR(pam_authenticate, 563 (*pamhp, pam_flags)); 564 565 /* handle expired passwords */ 566 pam_error = pam_acct_mgmt(*pamhp, pam_flags); 567 pam_fname = "pam_acct_mgmt"; 568 if (pam_error == PAM_NEW_AUTHTOK_REQD) { 569 ShowChangePasswdMessage(login); 570 do { 571 pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK); 572 } while ((pam_error == PAM_AUTHTOK_ERR) || 573 (pam_error == PAM_TRY_AGAIN)); 574 pam_fname = "pam_chauthtok"; 575 } 576 if (pam_error != PAM_SUCCESS) { 577 PAM_ERROR_PRINT(pam_fname, *pamhp); 578 goto pam_done; 579 } 580 581 RUN_AND_CHECK_PAM_ERROR(pam_setcred, 582 (*pamhp, 0)); 583 { 584 char *username = NULL; 585 586 RUN_AND_CHECK_PAM_ERROR(pam_get_item, 587 (*pamhp, PAM_USER, 588 (XDM_PAM_QUAL void **) &username)); 589 if (username != NULL) { 590 Debug("PAM_USER: %s\n", username); 591 greet->name = username; 592 greet->password = NULL; 593 } 594 } 595 596 pam_done: 597 if (code != 0) 598 { 599 CloseGreet (d); 600 SessionExit (d, code, FALSE); 601 } 602 if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) { 603 SetPrompt (login, 1, "Login Successful", LOGIN_TEXT_INFO, False); 604 SetValue (login, 1, NULL); 605 break; 606 } else { 607 /* Try to fill in username for failed login error log */ 608 XDM_PAM_QUAL char *username = greet->name; 609 610 if (username == NULL) { 611 RUN_AND_CHECK_PAM_ERROR(pam_get_item, 612 (*pamhp, PAM_USER, 613 (XDM_PAM_QUAL void **) &username)); 614 } 615 FailedLogin (d, username); 616 RUN_AND_CHECK_PAM_ERROR(pam_end, 617 (*pamhp, pam_error)); 618 } 619#else /* not PAM */ 620 /* 621 * Greet user, requesting name/password 622 */ 623 code = Greet (d, greet); 624 if (code != 0) 625 { 626 CloseGreet (d); 627 SessionExit (d, code, FALSE); 628 } 629 /* 630 * Verify user 631 */ 632 if (Verify (d, greet, verify)) 633 break; 634 else 635 { 636 FailedLogin (d, greet->name); 637 bzero (greet->name, strlen(greet->name)); 638 bzero (greet->password, strlen(greet->password)); 639 } 640#endif 641 } 642 DeleteXloginResources (d, *dpy); 643 CloseGreet (d); 644 Debug ("Greet loop finished\n"); 645 /* 646 * Run system-wide initialization file 647 */ 648 if (source (verify->systemEnviron, d->startup) != 0) 649 { 650 Debug ("Startup program %s exited with non-zero status\n", 651 d->startup); 652 SessionExit (d, OBEYSESS_DISPLAY, FALSE); 653 } 654 /* 655 * for user-based authorization schemes, 656 * add the user to the server's allowed "hosts" list. 657 */ 658 for (i = 0; i < d->authNum; i++) 659 { 660#ifdef SECURE_RPC 661 if (d->authorizations[i]->name_length == 9 && 662 memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) 663 { 664 XHostAddress addr; 665 char netname[MAXNETNAMELEN+1]; 666 char domainname[MAXNETNAMELEN+1]; 667 668 getdomainname(domainname, sizeof domainname); 669 user2netname (netname, verify->uid, domainname); 670 addr.family = FamilyNetname; 671 addr.length = strlen (netname); 672 addr.address = netname; 673 XAddHost (*dpy, &addr); 674 } 675#endif 676#ifdef K5AUTH 677 if (d->authorizations[i]->name_length == 14 && 678 memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) 679 { 680 /* Update server's auth file with user-specific info. 681 * Don't need to AddHost because X server will do that 682 * automatically when it reads the cache we are about 683 * to point it at. 684 */ 685 extern Xauth *Krb5GetAuthFor(); 686 687 XauDisposeAuth (d->authorizations[i]); 688 d->authorizations[i] = 689 Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name); 690 SaveServerAuthorizations (d, d->authorizations, d->authNum); 691 } 692#endif 693 } 694 695 return Greet_Success; 696} 697 698 699#ifdef USE_PAM 700static int pamconv(int num_msg, XDM_PAM_QUAL struct pam_message **msg, 701 struct pam_response **response, void *appdata_ptr) 702{ 703 int i; 704 int greetCode; 705 int status = PAM_SUCCESS; 706 const char *pam_msg_styles[5] 707 = { "<invalid pam msg style>", 708 "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON", 709 "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ; 710 711 struct pam_message *m; 712 struct pam_response *r; 713 714 struct myconv_data *d = (struct myconv_data *) appdata_ptr; 715 716 pam_handle_t **pamhp = thepamhp(); 717 718 *response = calloc(num_msg, sizeof (struct pam_response)); 719 if (*response == NULL) 720 return (PAM_BUF_ERR); 721 722 m = (struct pam_message *)*msg; 723 r = *response; 724 725 if (login == NULL) { 726 status = PAM_CONV_ERR; 727 goto pam_error; 728 } 729 730 for (i = 0; i < num_msg; i++ , m++ , r++) { 731 XDM_PAM_QUAL char *username; 732 int promptId = 0; 733 loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF; 734 735 if ((pam_get_item(*pamhp, PAM_USER, (XDM_PAM_QUAL void **) &username) 736 == PAM_SUCCESS) && (username != NULL) && (*username != '\0')) { 737 SetPrompt(login, LOGIN_PROMPT_USERNAME, 738 NULL, LOGIN_TEXT_INFO, False); 739 SetValue(login, LOGIN_PROMPT_USERNAME, username); 740 promptId = 1; 741 } 742 743 Debug("pam_msg: %s (%d): '%s'\n", 744 ((m->msg_style > 0) && (m->msg_style <= 4)) ? 745 pam_msg_styles[m->msg_style] : pam_msg_styles[0], 746 m->msg_style, m->msg); 747 748 switch (m->msg_style) { 749 case PAM_ERROR_MSG: 750 ErrorMessage(login, m->msg, True); 751 break; 752 753 case PAM_TEXT_INFO: 754 SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True); 755 SetValue (login, promptId, NULL); 756 break; 757 758 case PAM_PROMPT_ECHO_ON: 759 pStyle = LOGIN_PROMPT_ECHO_ON; 760 /* FALLTHROUGH */ 761 case PAM_PROMPT_ECHO_OFF: 762 SetPrompt (login, promptId, m->msg, pStyle, False); 763 SetValue (login, promptId, NULL); 764 greetCode = Greet (d->d, d->greet); 765 if (greetCode != 0) { 766 status = PAM_CONV_ERR; 767 goto pam_error; 768 } else { 769 r->resp = strdup(GetValue(login, promptId)); 770 SetValue(login, promptId, NULL); 771 if (r->resp == NULL) { 772 status = PAM_BUF_ERR; 773 goto pam_error; 774 } 775 /* Debug("pam_resp: '%s'\n", r->resp); */ 776 } 777 break; 778 779 default: 780 LogError("Unknown PAM msg_style: %d\n", m->msg_style); 781 } 782 } 783 pam_error: 784 if (status != PAM_SUCCESS) { 785 /* free responses */ 786 r = *response; 787 for (i = 0; i < num_msg; i++, r++) { 788 if (r->resp) { 789 bzero(r->resp, strlen(r->resp)); 790 free(r->resp); 791 } 792 } 793 free(*response); 794 *response = NULL; 795 } 796 return status; 797} 798#endif 799