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