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