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 /*
30 * xdm - display manager daemon
31 * Author: Keith Packard, MIT X Consortium
32 *
33 * session.c
34 */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include "dm.h"
41 #include "dm_auth.h"
42 #include "dm_error.h"
43 #include "greet.h"
44
45 #include <X11/Xlib.h>
46 #include <signal.h>
47 #include <X11/Xatom.h>
48 #include <X11/Xmu/Error.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <grp.h> /* for initgroups */
53
54 # ifdef HAVE_SETPROCTITLE
55 # include <sys/types.h>
56 # ifdef __linux__
57 # include <bsd/unistd.h>
58 # else
59 # include <unistd.h>
60 # endif
61 # endif
62
63 #ifndef USE_PAM /* PAM modules should handle these */
64 # ifdef SECURE_RPC
65 # include <rpc/rpc.h>
66 # include <rpc/key_prot.h>
67 # if !HAVE_DECL_KEY_SETNET
68 extern int key_setnet(struct key_netstarg *arg);
69 # endif
70 # endif
71 # ifdef K5AUTH
72 # include <krb5/krb5.h>
73 # endif
74 #endif /* USE_PAM */
75
76 #ifdef USE_SELINUX
77 #include <selinux/selinux.h>
78 #include <selinux/get_context_list.h>
79 #endif /* USE_SELINUX */
80
81 # include <dlfcn.h>
82 # ifndef RTLD_NOW
83 # define RTLD_NOW 1
84 # endif
85
86 #ifdef USE_SYSTEMD_DAEMON
87 #include <systemd/sd-daemon.h>
88 #endif
89
90 #ifdef USE_SELINUX
91 /* This should be run just before we exec the user session. */
92 static int
xdm_selinux_setup(const char * login)93 xdm_selinux_setup (const char *login)
94 {
95 security_context_t scontext;
96 int ret = -1;
97 char *seuser=NULL;
98 char *level=NULL;
99
100 /* If SELinux is not enabled, then we don't do anything. */
101 if ( is_selinux_enabled () <= 0)
102 return TRUE;
103
104 if (getseuserbyname(login, &seuser, &level) == 0) {
105 ret=get_default_context_with_level(seuser, level, 0, &scontext);
106 free(seuser);
107 free(level);
108 }
109 if (ret < 0 || scontext == NULL) {
110 LogError ("SELinux: unable to obtain default security context for %s\n", login);
111 return FALSE;
112 }
113
114 if (setexeccon (scontext) != 0) {
115 freecon (scontext);
116 LogError ("SELinux: unable to set executable context %s\n",
117 (char *)scontext);
118 return FALSE;
119 }
120
121 freecon (scontext);
122 return TRUE;
123 }
124 #endif /* USE_SELINUX */
125
126 static int runAndWait (char **args, char **environ);
127
128 #ifdef HAVE_GRP_H
129 # include <sys/types.h>
130 # include <grp.h>
131 #else
132 /* should be in <grp.h> */
133 extern void setgrent(void);
134 extern struct group *getgrent(void);
135 extern void endgrent(void);
136 #endif
137
138 #ifdef HAVE_GETSPNAM
139 # if defined(SVR4)
140 # include <shadow.h>
141 # else
142 extern struct spwd *getspnam(GETSPNAM_ARGS);
143 extern void endspent(void);
144 # endif
145 #endif
146 #if defined(CSRG_BASED) || defined(__GLIBC__)
147 # include <pwd.h>
148 # include <unistd.h>
149 # if defined(__GLIBC__) && !defined(_XOPEN_CRYPT)
150 # include <crypt.h>
151 # endif
152 #else
153 extern struct passwd *getpwnam(GETPWNAM_ARGS);
154 # ifdef linux
155 extern void endpwent(void);
156 # endif
157 extern char *crypt(CRYPT_ARGS);
158 #endif
159
160 #ifdef USE_PAM
161 pam_handle_t **
thepamhp(void)162 thepamhp(void)
163 {
164 static pam_handle_t *pamh = NULL;
165 return &pamh;
166 }
167
168 pam_handle_t *
thepamh(void)169 thepamh(void)
170 {
171 pam_handle_t **pamhp;
172
173 pamhp = thepamhp();
174 if (pamhp)
175 return *pamhp;
176 else
177 return NULL;
178 }
179 #endif
180
181 static struct dlfuncs dlfuncs = {
182 PingServer,
183 SessionPingFailed,
184 Debug,
185 RegisterCloseOnFork,
186 SecureDisplay,
187 UnsecureDisplay,
188 ClearCloseOnFork,
189 SetupDisplay,
190 LogError,
191 SessionExit,
192 DeleteXloginResources,
193 source,
194 defaultEnv,
195 setEnv,
196 putEnv,
197 parseArgs,
198 printEnv,
199 systemEnv,
200 LogOutOfMem,
201 setgrent,
202 getgrent,
203 endgrent,
204 #ifdef HAVE_GETSPNAM
205 getspnam,
206 # ifndef QNX4
207 endspent,
208 # endif /* QNX4 doesn't use endspent */
209 #endif
210 getpwnam,
211 #if defined(linux) || defined(__GLIBC__)
212 endpwent,
213 #endif
214 crypt,
215 #ifdef USE_PAM
216 thepamhp,
217 #endif
218 };
219
220 static Bool StartClient(
221 struct verify_info *verify,
222 struct display *d,
223 pid_t *pidp,
224 char *name,
225 char *passwd);
226
227 static pid_t clientPid;
228 static struct greet_info greet;
229 static struct verify_info verify;
230
231 static Jmp_buf abortSession;
232
233 /* ARGSUSED */
234 _X_NORETURN
235 static void
catchTerm(int n)236 catchTerm (int n)
237 {
238 Longjmp (abortSession, 1);
239 }
240
241 static Jmp_buf pingTime;
242
243 /* ARGSUSED */
244 _X_NORETURN
245 static void
catchAlrm(int n)246 catchAlrm (int n)
247 {
248 Longjmp (pingTime, 1);
249 }
250
251 static Jmp_buf tenaciousClient;
252
253 /* ARGSUSED */
254 _X_NORETURN
255 static void
waitAbort(int n)256 waitAbort (int n)
257 {
258 Longjmp (tenaciousClient, 1);
259 }
260
261 #if defined(_POSIX_SOURCE) || defined(SYSV) || defined(SVR4)
262 # define killpg(pgrp, sig) kill(-(pgrp), sig)
263 #endif
264
265 static void
AbortClient(pid_t pid)266 AbortClient (pid_t pid)
267 {
268 int sig = SIGTERM;
269 volatile int i;
270 pid_t retId;
271
272 for (i = 0; i < 4; i++) {
273 if (killpg (pid, sig) == -1) {
274 switch (errno) {
275 case EPERM:
276 LogError ("xdm can't kill client\n");
277 case EINVAL:
278 case ESRCH:
279 return;
280 }
281 }
282 if (!Setjmp (tenaciousClient)) {
283 (void) Signal (SIGALRM, waitAbort);
284 (void) alarm ((unsigned) 10);
285 retId = wait ((waitType *) 0);
286 (void) alarm ((unsigned) 0);
287 (void) Signal (SIGALRM, SIG_DFL);
288 if (retId == pid)
289 break;
290 } else
291 (void) Signal (SIGALRM, SIG_DFL);
292 sig = SIGKILL;
293 }
294 }
295
296 void
SessionPingFailed(struct display * d)297 SessionPingFailed (struct display *d)
298 {
299 if (clientPid > 1) {
300 AbortClient (clientPid);
301 source (verify.systemEnviron, d->reset);
302 }
303 SessionExit (d, RESERVER_DISPLAY, TRUE);
304 }
305
306 /*
307 * We need our own error handlers because we can't be sure what exit code Xlib
308 * will use, and our Xlib does exit(1) which matches REMANAGE_DISPLAY, which
309 * can cause a race condition leaving the display wedged. We need to use
310 * RESERVER_DISPLAY for IO errors, to ensure that the manager waits for the
311 * server to terminate. For other X errors, we should give up.
312 */
313
314 /*ARGSUSED*/
315 static int
IOErrorHandler(Display * dpy)316 IOErrorHandler (Display *dpy)
317 {
318 LogError ("fatal IO error %d (%s)\n", errno, _SysErrorMsg(errno));
319 exit(RESERVER_DISPLAY);
320 /*NOTREACHED*/
321 return 0;
322 }
323
324 static int
ErrorHandler(Display * dpy,XErrorEvent * event)325 ErrorHandler(Display *dpy, XErrorEvent *event)
326 {
327 LogError ("X error\n");
328 if (XmuPrintDefaultErrorMessage (dpy, event, stderr) == 0) return 0;
329 exit(UNMANAGE_DISPLAY);
330 /*NOTREACHED*/
331 }
332
333 void
ManageSession(struct display * d)334 ManageSession (struct display *d)
335 {
336 static pid_t pid = 0;
337 Display *dpy;
338 greet_user_rtn greet_stat;
339 static GreetUserProc greet_user_proc = NULL;
340 void *greet_lib_handle;
341
342 Debug ("ManageSession %s\n", d->name);
343 (void)XSetIOErrorHandler(IOErrorHandler);
344 (void)XSetErrorHandler(ErrorHandler);
345 #ifndef HAVE_SETPROCTITLE
346 SetTitle(d->name, (char *) 0);
347 #else
348 setproctitle("%s", d->name);
349 #endif
350 /*
351 * Load system default Resources
352 */
353 LoadXloginResources (d);
354
355 Debug ("ManageSession: loading greeter library %s\n", greeterLib);
356 greet_lib_handle = dlopen(greeterLib, RTLD_NOW);
357 if (greet_lib_handle != NULL)
358 greet_user_proc = (GreetUserProc)dlsym(greet_lib_handle, "GreetUser");
359 if (greet_user_proc == NULL) {
360 LogError ("%s while loading %s\n", dlerror(), greeterLib);
361 exit(UNMANAGE_DISPLAY);
362 }
363
364 #ifdef USE_SYSTEMD_DAEMON
365 /* Subsequent notifications will be ignored by systemd
366 * and calling this function will clean up the env */
367 sd_notify(1, "READY=1");
368 #endif
369
370 /* tell the possibly dynamically loaded greeter function
371 * what data structure formats to expect.
372 * These version numbers are registered with The Open Group. */
373 verify.version = 1;
374 greet.version = 1;
375 greet_stat = (*greet_user_proc)(d, &dpy, &verify, &greet, &dlfuncs);
376
377 if (greet_stat == Greet_Success) {
378 clientPid = 0;
379 if (!Setjmp (abortSession)) {
380 (void) Signal (SIGTERM, catchTerm);
381 /*
382 * Start the clients, changing uid/groups
383 * setting up environment and running the session
384 */
385 if (StartClient (&verify, d, &clientPid, greet.name, greet.password)) {
386 Debug ("Client Started\n");
387
388 /* Save memory; close library */
389 dlclose(greet_lib_handle);
390
391 /*
392 * Wait for session to end,
393 */
394 for (;;) {
395 if (d->pingInterval) {
396 if (!Setjmp (pingTime)) {
397 (void) Signal (SIGALRM, catchAlrm);
398 (void) alarm (d->pingInterval * 60);
399 pid = wait ((waitType *) 0);
400 (void) alarm (0);
401 } else {
402 (void) alarm (0);
403 if (!PingServer (d, (Display *) NULL))
404 SessionPingFailed (d);
405 }
406 } else {
407 pid = wait ((waitType *) 0);
408 }
409 if (pid == clientPid)
410 break;
411 }
412 } else {
413 LogError ("session start failed\n");
414 }
415 } else {
416 /*
417 * when terminating the session, nuke
418 * the child and then run the reset script
419 */
420 AbortClient (clientPid);
421 }
422 }
423 /*
424 * run system-wide reset file
425 */
426 Debug ("Source reset program %s\n", d->reset);
427 source (verify.systemEnviron, d->reset);
428 SessionExit (d, OBEYSESS_DISPLAY, TRUE);
429 }
430
431 void
LoadXloginResources(struct display * d)432 LoadXloginResources (struct display *d)
433 {
434 char **args;
435 char **env = NULL;
436
437 if (d->resources[0] && access (d->resources, 4) == 0) {
438 env = systemEnv (d, (char *) 0, (char *) 0);
439 args = parseArgs ((char **) 0, d->xrdb);
440 args = parseArgs (args, d->resources);
441 Debug ("Loading resource file: %s\n", d->resources);
442 (void) runAndWait (args, env);
443 freeArgs (args);
444 freeEnv (env);
445 }
446 }
447
448 void
SetupDisplay(struct display * d)449 SetupDisplay (struct display *d)
450 {
451 char **env = NULL;
452
453 if (d->setup && d->setup[0]) {
454 env = systemEnv (d, (char *) 0, (char *) 0);
455 (void) source (env, d->setup);
456 freeEnv (env);
457 }
458 }
459
460 /*ARGSUSED*/
461 void
DeleteXloginResources(struct display * d,Display * dpy)462 DeleteXloginResources (struct display *d, Display *dpy)
463 {
464 int i;
465 Atom prop = XInternAtom(dpy, "SCREEN_RESOURCES", True);
466
467 XDeleteProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER);
468 if (prop) {
469 for (i = ScreenCount(dpy); --i >= 0; )
470 XDeleteProperty(dpy, RootWindow (dpy, i), prop);
471 }
472 }
473
474 static Jmp_buf syncJump;
475
476 /* ARGSUSED */
477 _X_NORETURN
478 static void
syncTimeout(int n)479 syncTimeout (int n)
480 {
481 Longjmp (syncJump, 1);
482 }
483
484 void
SecureDisplay(struct display * d,Display * dpy)485 SecureDisplay (struct display *d, Display *dpy)
486 {
487 Debug ("SecureDisplay %s\n", d->name);
488 (void) Signal (SIGALRM, syncTimeout);
489 if (Setjmp (syncJump)) {
490 LogError ("WARNING: display %s could not be secured\n",
491 d->name);
492 SessionExit (d, RESERVER_DISPLAY, FALSE);
493 }
494 (void) alarm ((unsigned) d->grabTimeout);
495 Debug ("Before XGrabServer %s\n", d->name);
496 XGrabServer (dpy);
497 if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync,
498 GrabModeAsync, CurrentTime) != GrabSuccess) {
499 (void) alarm (0);
500 (void) Signal (SIGALRM, SIG_DFL);
501 LogError ("WARNING: keyboard on display %s could not be secured\n",
502 d->name);
503 SessionExit (d, RESERVER_DISPLAY, FALSE);
504 }
505 Debug ("XGrabKeyboard succeeded %s\n", d->name);
506 (void) alarm (0);
507 (void) Signal (SIGALRM, SIG_DFL);
508 pseudoReset (dpy);
509 if (!d->grabServer) {
510 XUngrabServer (dpy);
511 XSync (dpy, 0);
512 }
513 Debug ("done secure %s\n", d->name);
514 }
515
516 void
UnsecureDisplay(struct display * d,Display * dpy)517 UnsecureDisplay (struct display *d, Display *dpy)
518 {
519 Debug ("Unsecure display %s\n", d->name);
520 if (d->grabServer) {
521 XUngrabServer (dpy);
522 XSync (dpy, 0);
523 }
524 }
525
526 void
SessionExit(struct display * d,int status,int removeAuth)527 SessionExit (struct display *d, int status, int removeAuth)
528 {
529 #ifdef USE_PAM
530 pam_handle_t *pamh = thepamh();
531
532 if (pamh) {
533 /* shutdown PAM session */
534 pam_close_session(pamh, 0);
535 pam_end(pamh, PAM_SUCCESS);
536 pamh = NULL;
537 }
538 #endif
539
540 /* make sure the server gets reset after the session is over */
541 if (d->serverPid >= 2 && d->resetSignal)
542 kill (d->serverPid, d->resetSignal);
543 else
544 ResetServer (d);
545 if (removeAuth) {
546 if (setgid (verify.gid) == -1) {
547 LogError( "SessionExit: setgid: %s\n", strerror(errno));
548 exit(status);
549 }
550 if (setuid (verify.uid) == -1) {
551 LogError( "SessionExit: setuid: %s\n", strerror(errno));
552 exit(status);
553 }
554 RemoveUserAuthorization (d, &verify);
555 #if defined(K5AUTH) && !defined(USE_PAM) /* PAM modules should handle this */
556 /* do like "kdestroy" program */
557 {
558 krb5_error_code code;
559 krb5_ccache ccache;
560
561 code = Krb5DisplayCCache(d->name, &ccache);
562 if (code)
563 LogError ("%s while getting Krb5 ccache to destroy\n",
564 error_message(code));
565 else {
566 code = krb5_cc_destroy(ccache);
567 if (code) {
568 if (code == KRB5_FCC_NOFILE) {
569 Debug ("No Kerberos ccache file found to destroy\n");
570 } else
571 LogError ("%s while destroying Krb5 credentials cache\n",
572 error_message(code));
573 } else
574 Debug ("Kerberos ccache destroyed\n");
575 krb5_cc_close(ccache);
576 }
577 }
578 #endif /* K5AUTH */
579 }
580 Debug ("Display %s exiting with status %d\n", d->name, status);
581 exit (status);
582 }
583
584 static Bool
StartClient(struct verify_info * verify,struct display * d,pid_t * pidp,char * name,char * passwd)585 StartClient (
586 struct verify_info *verify,
587 struct display *d,
588 pid_t *pidp,
589 char *name,
590 char *passwd)
591 {
592 char **f, *home;
593 char *failsafeArgv[2];
594 pid_t pid;
595 #ifdef HAVE_SETUSERCONTEXT
596 struct passwd* pwd;
597 extern char **environ;
598 #endif
599 #ifdef USE_PAM
600 pam_handle_t *pamh = thepamh ();
601 int pam_error;
602 #endif
603
604 if (verify->argv) {
605 Debug ("StartSession %s: ", verify->argv[0]);
606 for (f = verify->argv; *f; f++)
607 Debug ("%s ", *f);
608 Debug ("; ");
609 }
610 if (verify->userEnviron) {
611 for (f = verify->userEnviron; *f; f++)
612 Debug ("%s ", *f);
613 Debug ("\n");
614 }
615 #ifdef USE_PAM
616 if (pamh) pam_open_session(pamh, 0);
617 #endif
618 switch (pid = fork ()) {
619 case 0:
620 CleanUpChild ();
621 #ifdef XDMCP
622 /* The chooser socket is not closed by CleanUpChild() */
623 DestroyWellKnownSockets();
624 #endif
625
626 /* Do system-dependent login setup here */
627
628 #ifndef HAVE_SETUSERCONTEXT
629 if (setgid (verify->gid) < 0) {
630 LogError ("setgid %d (user \"%s\") failed: %s\n",
631 verify->gid, name, _SysErrorMsg (errno));
632 return (0);
633 }
634 # if defined(BSD) && (BSD >= 199103)
635 if (setlogin (name) < 0) {
636 LogError ("setlogin for \"%s\" failed: %s\n",
637 name, _SysErrorMsg (errno));
638 return (0);
639 }
640 # endif
641 # ifndef QNX4
642 if (initgroups (name, verify->gid) < 0) {
643 LogError ("initgroups for \"%s\" failed: %s\n",
644 name, _SysErrorMsg (errno));
645 return (0);
646 }
647 # endif /* QNX4 doesn't support multi-groups, no initgroups() */
648 #endif /* !HAVE_SETUSERCONTEXT */
649
650 #ifdef USE_PAM
651 if (pamh) {
652 long i;
653 char **pam_env;
654
655 pam_error = pam_setcred (pamh, PAM_ESTABLISH_CRED);
656 if (pam_error != PAM_SUCCESS) {
657 LogError ("pam_setcred for \"%s\" failed: %s\n",
658 name, pam_strerror(pamh, pam_error));
659 return(0);
660 }
661
662 /* pass in environment variables set by libpam and modules it called */
663 pam_env = pam_getenvlist(pamh);
664 for(i = 0; pam_env && pam_env[i]; i++) {
665 verify->userEnviron = putEnv(pam_env[i], verify->userEnviron);
666 }
667
668 }
669 #endif
670
671 #ifndef HAVE_SETUSERCONTEXT
672 if (setuid(verify->uid) < 0) {
673 LogError ("setuid %d (user \"%s\") failed: %s\n",
674 verify->uid, name, _SysErrorMsg (errno));
675 return (0);
676 }
677 #else /* HAVE_SETUSERCONTEXT */
678 /*
679 * Set the user's credentials: uid, gid, groups,
680 * environment variables, resource limits, and umask.
681 */
682 /* destroy user environment before calling setusercontext */
683 environ = verify->userEnviron;
684 pwd = getpwnam(name);
685 if (pwd) {
686 if (setusercontext(NULL, pwd, pwd->pw_uid, LOGIN_SETALL) < 0) {
687 LogError ("setusercontext for \"%s\" failed: %s\n",
688 name, _SysErrorMsg (errno));
689 return (0);
690 }
691 verify->userEnviron = environ;
692 endpwent();
693 } else {
694 LogError ("getpwnam for \"%s\" failed: %s\n",
695 name, _SysErrorMsg (errno));
696 return (0);
697 }
698 #endif /* HAVE_SETUSERCONTEXT */
699
700 #ifndef USE_PAM /* PAM modules should handle these */
701 /*
702 * for user-based authorization schemes,
703 * use the password to get the user's credentials.
704 */
705 # ifdef SECURE_RPC
706 /* do like "keylogin" program */
707 {
708 char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
709 int nameret, keyret;
710 int len;
711 struct key_netstarg netst;
712 int key_set_ok = 0;
713
714 nameret = getnetname (netname);
715 Debug ("User netname: %s\n", netname);
716 len = strlen (passwd);
717 if (len > 8)
718 bzero (passwd + 8, len - 8);
719 keyret = getsecretkey(netname,secretkey,passwd);
720 Debug ("getsecretkey returns %d, key length %lu\n",
721 keyret, strlen (secretkey));
722 memcpy(&(netst.st_priv_key), secretkey, HEXKEYBYTES);
723 netst.st_netname = strdup(netname);
724 memset(netst.st_pub_key, 0, HEXKEYBYTES);
725 if (key_setnet(&netst) < 0) {
726 Debug ("Could not set secret key.\n");
727 }
728 free(netst.st_netname);
729 /* is there a key, and do we have the right password? */
730 if (keyret == 1) {
731 if (*secretkey) {
732 keyret = key_setsecret(secretkey);
733 Debug ("key_setsecret returns %d\n", keyret);
734 if (keyret == -1)
735 LogError ("failed to set NIS secret key\n");
736 else
737 key_set_ok = 1;
738 } else {
739 /* found a key, but couldn't interpret it */
740 LogError ("password incorrect for NIS principal \"%s\"\n",
741 nameret ? netname : name);
742 }
743 }
744 if (!key_set_ok) {
745 /* remove SUN-DES-1 from authorizations list */
746 int i, j;
747 for (i = 0; i < d->authNum; i++) {
748 if (d->authorizations[i]->name_length == 9 &&
749 memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) {
750 for (j = i+1; j < d->authNum; j++)
751 d->authorizations[j-1] = d->authorizations[j];
752 d->authNum--;
753 break;
754 }
755 }
756 }
757 bzero(secretkey, strlen(secretkey));
758 }
759 # endif
760 # ifdef K5AUTH
761 /* do like "kinit" program */
762 {
763 int i, j;
764 int result;
765 extern char *Krb5CCacheName();
766
767 result = Krb5Init(name, passwd, d);
768 if (result == 0) {
769 /* point session clients at the Kerberos credentials cache */
770 verify->userEnviron =
771 setEnv(verify->userEnviron,
772 "KRB5CCNAME", Krb5CCacheName(d->name));
773 } else {
774 for (i = 0; i < d->authNum; i++) {
775 if (d->authorizations[i]->name_length == 14 &&
776 memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) {
777 /* remove Kerberos from authorizations list */
778 for (j = i+1; j < d->authNum; j++)
779 d->authorizations[j-1] = d->authorizations[j];
780 d->authNum--;
781 break;
782 }
783 }
784 }
785 }
786 # endif /* K5AUTH */
787 #endif /* !USE_PAM */
788
789 if (d->windowPath)
790 verify->userEnviron = setEnv(verify->userEnviron, "WINDOWPATH", d->windowPath);
791
792 if (passwd != NULL)
793 bzero(passwd, strlen(passwd));
794
795 SetUserAuthorization (d, verify);
796 #ifdef USE_SELINUX
797 /*
798 * For Security Enhanced Linux:
799 * set the default security context for this user.
800 */
801 if ( ! xdm_selinux_setup (name)) {
802 LogError ("failed to set security context\n");
803 exit (UNMANAGE_DISPLAY);
804 return (0);
805 }
806 #endif /* USE_SELINUX */
807 home = getEnv (verify->userEnviron, "HOME");
808 if (home)
809 if (chdir (home) == -1) {
810 LogError ("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n",
811 getEnv (verify->userEnviron, "USER"), home, errno);
812 chdir ("/");
813 verify->userEnviron = setEnv(verify->userEnviron, "HOME", "/");
814 }
815 if (verify->argv) {
816 LogInfo ("executing session %s\n", verify->argv[0]);
817 execute (verify->argv, verify->userEnviron);
818 LogError ("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno);
819 } else {
820 LogError ("Session has no command/arguments\n");
821 }
822 failsafeArgv[0] = d->failsafeClient;
823 failsafeArgv[1] = NULL;
824 execute (failsafeArgv, verify->userEnviron);
825 exit (1);
826 case -1:
827 if (passwd != NULL)
828 bzero(passwd, strlen(passwd));
829 Debug ("StartSession, fork failed\n");
830 LogError ("can't start session on \"%s\", fork failed: %s\n",
831 d->name, _SysErrorMsg (errno));
832 return 0;
833 default:
834 if (passwd != NULL)
835 bzero(passwd, strlen(passwd));
836 Debug ("StartSession, fork succeeded %d\n", pid);
837 *pidp = pid;
838 return 1;
839 }
840 }
841
842 int
source(char ** environ,char * file)843 source (char **environ, char *file)
844 {
845 char **args, *args_safe[2];
846 int ret = 0;
847 FILE *f;
848
849 if (file && file[0]) {
850 f = fopen (file, "r");
851 if (!f)
852 LogInfo ("not sourcing %s (%s)\n", file, _SysErrorMsg (errno));
853 else {
854 fclose (f);
855 LogInfo ("sourcing %s\n", file);
856 args = parseArgs ((char **) 0, file);
857 if (!args) {
858 args = args_safe;
859 args[0] = file;
860 args[1] = NULL;
861 }
862 ret = runAndWait (args, environ);
863 freeArgs (args);
864 }
865 } else
866 Debug ("source() given null pointer in file argument\n");
867 return ret;
868 }
869
870 static int
runAndWait(char ** args,char ** environ)871 runAndWait (char **args, char **environ)
872 {
873 pid_t pid;
874 waitType result;
875
876 switch (pid = fork ()) {
877 case 0:
878 CleanUpChild ();
879 #ifdef XDMCP
880 /* The chooser socket is not closed by CleanUpChild() */
881 DestroyWellKnownSockets();
882 #endif
883 execute (args, environ);
884 LogError ("can't execute \"%s\" (err %d)\n", args[0], errno);
885 exit (1);
886 case -1:
887 Debug ("fork failed\n");
888 LogError ("can't fork to execute \"%s\" (err %d)\n", args[0], errno);
889 return 1;
890 default:
891 while (wait (&result) != pid)
892 /* SUPPRESS 530 */
893 ;
894 break;
895 }
896 return waitVal (result);
897 }
898
899 void
execute(char ** argv,char ** environ)900 execute (char **argv, char **environ)
901 {
902 int err;
903 /* give /dev/null as stdin */
904 (void) close (0);
905 open ("/dev/null", O_RDONLY);
906 /* make stdout follow stderr to the log file */
907 dup2 (2,1);
908 Debug ("attempting to execve() %s\n", argv[0]);
909 execve (argv[0], argv, environ);
910 err = errno;
911 Debug ("execve() of %s failed: %s\n", argv[0], _SysErrorMsg (errno));
912 /*
913 * In case this is a shell script which hasn't been
914 * made executable (or this is a SYSV box), do
915 * a reasonable thing
916 */
917 if (err != ENOENT) {
918 char program[1024], *e, *p, *optarg;
919 FILE *f;
920 char **newargv, **av;
921 int argc;
922
923 /*
924 * emulate BSD kernel behaviour -- read
925 * the first line; check if it starts
926 * with "#!", in which case it uses
927 * the rest of the line as the name of
928 * program to run. Else use "/bin/sh".
929 */
930 f = fopen (argv[0], "r");
931 if (!f)
932 return;
933 if (fgets (program, sizeof (program) - 1, f) == NULL) {
934 fclose (f);
935 return;
936 }
937 fclose (f);
938 if (program[0] == '\0')
939 return;
940 e = program + strlen (program) - 1;
941 if (*e == '\n')
942 *e = '\0';
943 if (!strncmp (program, "#!", 2)) {
944 p = program + 2;
945 while (*p && isspace (*p))
946 ++p;
947 optarg = p;
948 while (*optarg && !isspace (*optarg))
949 ++optarg;
950 if (*optarg) {
951 *optarg = '\0';
952 do
953 ++optarg;
954 while (*optarg && isspace (*optarg));
955 } else
956 optarg = NULL;
957 } else {
958 p = "/bin/sh";
959 optarg = NULL;
960 }
961 Debug ("Shell script execution: %s (optarg %s)\n",
962 p, optarg ? optarg : "(null)");
963 for (av = argv, argc = 0; *av; av++, argc++)
964 /* SUPPRESS 530 */
965 ;
966 newargv = malloc ((argc + (optarg ? 3 : 2)) * sizeof (char *));
967 if (!newargv)
968 return;
969 av = newargv;
970 *av++ = p;
971 if (optarg)
972 *av++ = optarg;
973 /* SUPPRESS 560 */
974 while ((*av++ = *argv++))
975 /* SUPPRESS 530 */
976 ;
977 Debug ("Attempting to execve() %s\n", newargv[0]);
978 execve (newargv[0], newargv, environ);
979 }
980 }
981
982 char **
defaultEnv(void)983 defaultEnv (void)
984 {
985 char **env, **exp, *value;
986
987 env = NULL;
988 for (exp = exportList; exp && *exp; ++exp) {
989 value = getenv (*exp);
990 if (value)
991 env = setEnv (env, *exp, value);
992 }
993 return env;
994 }
995
996 char **
systemEnv(struct display * d,char * user,char * home)997 systemEnv (struct display *d, char *user, char *home)
998 {
999 char **env;
1000
1001 env = defaultEnv ();
1002 env = setEnv (env, "DISPLAY", d->name);
1003 if (home)
1004 env = setEnv (env, "HOME", home);
1005 if (user) {
1006 env = setEnv (env, "USER", user);
1007 env = setEnv (env, "LOGNAME", user);
1008 }
1009 env = setEnv (env, "PATH", d->systemPath);
1010 env = setEnv (env, "SHELL", d->systemShell);
1011 if (d->authFile)
1012 env = setEnv (env, "XAUTHORITY", d->authFile);
1013 if (d->windowPath)
1014 env = setEnv (env, "WINDOWPATH", d->windowPath);
1015 return env;
1016 }
1017