1 /*
2
3 Copyright 1988, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from 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 */
93 extern 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
100 int (*__xdm_PingServer)(struct display *d, Display *alternateDpy) = NULL;
101 void (*__xdm_SessionPingFailed)(struct display *d) = NULL;
102 void (*__xdm_Debug)(const char * fmt, ...) = NULL;
103 void (*__xdm_RegisterCloseOnFork)(int fd) = NULL;
104 void (*__xdm_SecureDisplay)(struct display *d, Display *dpy) = NULL;
105 void (*__xdm_UnsecureDisplay)(struct display *d, Display *dpy) = NULL;
106 void (*__xdm_ClearCloseOnFork)(int fd) = NULL;
107 void (*__xdm_SetupDisplay)(struct display *d) = NULL;
108 void (*__xdm_LogError)(const char * fmt, ...) = NULL;
109 void (*__xdm_SessionExit)(struct display *d, int status, int removeAuth) = NULL;
110 void (*__xdm_DeleteXloginResources)(struct display *d, Display *dpy) = NULL;
111 int (*__xdm_source)(char **environ, char *file) = NULL;
112 char **(*__xdm_defaultEnv)(void) = NULL;
113 char **(*__xdm_setEnv)(char **e, const char *name, const char *value) = NULL;
114 char **(*__xdm_putEnv)(const char *string, char **env) = NULL;
115 char **(*__xdm_parseArgs)(char **argv, const char *string) = NULL;
116 void (*__xdm_printEnv)(char **e) = NULL;
117 char **(*__xdm_systemEnv)(struct display *d, char *user, char *home) = NULL;
118 void (*__xdm_LogOutOfMem)(const char * fmt, ...) = NULL;
119 void (*__xdm_setgrent)(void) = NULL;
120 struct group *(*__xdm_getgrent)(void) = NULL;
121 void (*__xdm_endgrent)(void) = NULL;
122 # ifdef HAVE_GETSPNAM
123 struct spwd *(*__xdm_getspnam)(GETSPNAM_ARGS) = NULL;
124 # ifndef QNX4
125 void (*__xdm_endspent)(void) = NULL;
126 # endif /* QNX4 doesn't use endspent */
127 # endif
128 struct passwd *(*__xdm_getpwnam)(GETPWNAM_ARGS) = NULL;
129 # if defined(linux) || defined(__GLIBC__)
130 void (*__xdm_endpwent)(void) = NULL;
131 # endif
132 char *(*__xdm_crypt)(CRYPT_ARGS) = NULL;
133 # ifdef USE_PAM
134 pam_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
146 static int done, code;
147 #ifndef USE_PAM
148 static char name[NAME_LEN], password[PASSWORD_LEN];
149 #endif
150 static Widget toplevel;
151 static Widget login;
152 static XtAppContext context;
153 static XtIntervalId pingTimeout;
154
155 #ifdef USE_PAM
156 static 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
167 struct myconv_data {
168 struct display *d;
169 struct greet_info *greet;
170 char *username_display;
171 };
172 #endif
173
174
175 /*ARGSUSED*/
176 static void
GreetPingServer(XtPointer closure,XtIntervalId * intervalId)177 GreetPingServer (
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*/
191 static void
GreetDone(Widget w,LoginData * data,int status)192 GreetDone (
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
234 static Display *
InitGreet(struct display * d)235 InitGreet (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
319 static void
CloseGreet(struct display * d)320 CloseGreet (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
350 static int
Greet(struct display * d,struct greet_info * greet)351 Greet (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
404 static void
FailedLogin(struct display * d,const char * username)405 FailedLogin (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
GreetUser(struct display * d,Display ** dpy,struct verify_info * verify,struct greet_info * greet,struct dlfuncs * dlfuncs)419 greet_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 login = NULL;
643 Debug ("Greet loop finished\n");
644 /*
645 * Run system-wide initialization file
646 */
647 if (source (verify->systemEnviron, d->startup) != 0)
648 {
649 Debug ("Startup program %s exited with non-zero status\n",
650 d->startup);
651 SessionExit (d, OBEYSESS_DISPLAY, FALSE);
652 }
653 /*
654 * for user-based authorization schemes,
655 * add the user to the server's allowed "hosts" list.
656 */
657 for (i = 0; i < d->authNum; i++)
658 {
659 #ifdef SECURE_RPC
660 if (d->authorizations[i]->name_length == 9 &&
661 memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
662 {
663 XHostAddress addr;
664 char netname[MAXNETNAMELEN+1];
665 char domainname[MAXNETNAMELEN+1];
666
667 getdomainname(domainname, sizeof domainname);
668 user2netname (netname, verify->uid, domainname);
669 addr.family = FamilyNetname;
670 addr.length = strlen (netname);
671 addr.address = netname;
672 XAddHost (*dpy, &addr);
673 }
674 #endif
675 #ifdef K5AUTH
676 if (d->authorizations[i]->name_length == 14 &&
677 memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
678 {
679 /* Update server's auth file with user-specific info.
680 * Don't need to AddHost because X server will do that
681 * automatically when it reads the cache we are about
682 * to point it at.
683 */
684 extern Xauth *Krb5GetAuthFor();
685
686 XauDisposeAuth (d->authorizations[i]);
687 d->authorizations[i] =
688 Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
689 SaveServerAuthorizations (d, d->authorizations, d->authNum);
690 }
691 #endif
692 }
693
694 return Greet_Success;
695 }
696
697
698 #ifdef USE_PAM
pamconv(int num_msg,const struct pam_message ** msg,struct pam_response ** response,void * appdata_ptr)699 static int pamconv(int num_msg,
700 # ifndef sun
701 const
702 # endif
703 struct pam_message **msg,
704 struct pam_response **response, void *appdata_ptr)
705 {
706 int i;
707 int greetCode;
708 int status = PAM_SUCCESS;
709 const char *pam_msg_styles[5]
710 = { "<invalid pam msg style>",
711 "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON",
712 "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ;
713
714 struct pam_message *m;
715 struct pam_response *r;
716
717 struct myconv_data *d = (struct myconv_data *) appdata_ptr;
718
719 pam_handle_t **pamhp = thepamhp();
720
721 *response = calloc(num_msg, sizeof (struct pam_response));
722 if (*response == NULL)
723 return (PAM_BUF_ERR);
724
725 m = (struct pam_message *)*msg;
726 r = *response;
727
728 if (login == NULL) {
729 status = PAM_CONV_ERR;
730 goto pam_error;
731 }
732
733 for (i = 0; i < num_msg; i++ , m++ , r++) {
734 char *username;
735 int promptId = 0;
736 loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF;
737
738 if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS)
739 && (username != NULL) && (*username != '\0')) {
740 SetPrompt(login, LOGIN_PROMPT_USERNAME,
741 NULL, LOGIN_TEXT_INFO, False);
742 SetValue(login, LOGIN_PROMPT_USERNAME, username);
743 promptId = 1;
744 }
745
746 Debug("pam_msg: %s (%d): '%s'\n",
747 ((m->msg_style > 0) && (m->msg_style <= 4)) ?
748 pam_msg_styles[m->msg_style] : pam_msg_styles[0],
749 m->msg_style, m->msg);
750
751 switch (m->msg_style) {
752 case PAM_ERROR_MSG:
753 ErrorMessage(login, m->msg, True);
754 break;
755
756 case PAM_TEXT_INFO:
757 SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True);
758 SetValue (login, promptId, NULL);
759 break;
760
761 case PAM_PROMPT_ECHO_ON:
762 pStyle = LOGIN_PROMPT_ECHO_ON;
763 /* FALLTHROUGH */
764 case PAM_PROMPT_ECHO_OFF:
765 SetPrompt (login, promptId, m->msg, pStyle, False);
766 SetValue (login, promptId, NULL);
767 greetCode = Greet (d->d, d->greet);
768 if (greetCode != 0) {
769 status = PAM_CONV_ERR;
770 goto pam_error;
771 } else {
772 r->resp = strdup(GetValue(login, promptId));
773 SetValue(login, promptId, NULL);
774 if (r->resp == NULL) {
775 status = PAM_BUF_ERR;
776 goto pam_error;
777 }
778 /* Debug("pam_resp: '%s'\n", r->resp); */
779 }
780 break;
781
782 default:
783 LogError("Unknown PAM msg_style: %d\n", m->msg_style);
784 }
785 }
786 pam_error:
787 if (status != PAM_SUCCESS) {
788 /* free responses */
789 r = *response;
790 for (i = 0; i < num_msg; i++, r++) {
791 if (r->resp) {
792 bzero(r->resp, strlen(r->resp));
793 free(r->resp);
794 }
795 }
796 free(*response);
797 *response = NULL;
798 }
799 return status;
800 }
801 #endif
802