slave.c 143 KB
Newer Older
1 2 3
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * GDM - The GNOME Display Manager
4
 * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
Martin Peterson's avatar
Martin Peterson committed
5 6 7 8 9 10 11 12
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Martin Peterson's avatar
Martin Peterson committed
14 15 16 17
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Martin Peterson's avatar
Martin Peterson committed
19 20 21
 */

/* This is the gdm slave process. gdmslave runs the chooser, greeter
22
 * and the user's session scripts. */
Martin Peterson's avatar
Martin Peterson committed
23

24
#include "config.h"
25

Martin Peterson's avatar
Martin Peterson committed
26 27
#include <stdio.h>
#include <stdlib.h>
28
#include <dirent.h>
29
#include <unistd.h>
30
#include <utime.h>
31
#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
32 33
#include <sched.h>
#endif
34 35 36
#ifdef HAVE_LOGINCAP
#include <login_cap.h>
#endif
Martin Peterson's avatar
Martin Peterson committed
37 38 39 40 41
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <strings.h>
42 43 44 45
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
46
#include <arpa/inet.h>
47

Martin Peterson's avatar
Martin Peterson committed
48
#include <X11/Xlib.h>
49
#include <X11/Xatom.h>
50
#ifdef HAVE_XFREE_XINERAMA
51
#include <X11/extensions/Xinerama.h>
52 53
#elif HAVE_SOLARIS_XINERAMA
#include <X11/extensions/xinerama.h>
54
#endif
55

56
#if defined (CAN_USE_SETPENV) && defined (HAVE_USERSEC_H)
57 58 59
#include <usersec.h>
#endif

Martin Peterson's avatar
Martin Peterson committed
60 61 62 63
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
64
#include <time.h>
65
#include <syslog.h>
Martin Peterson's avatar
Martin Peterson committed
66

67 68 69 70 71
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/get_context_list.h>
#endif /* HAVE_SELINUX */

72 73 74 75
#include <glib/gi18n.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

Martin Peterson's avatar
Martin Peterson committed
76
#include "gdm.h"
77 78 79 80 81
#include "slave.h"
#include "misc.h"
#include "verify.h"
#include "filecheck.h"
#include "auth.h"
1's avatar
1 committed
82
#include "server.h"
83
#include "choose.h"
84
#include "getvt.h"
85
#include "errorgui.h"
86
#include "cookie.h"
87
#include "gdmconfig.h"
88

89
/* Some per slave globals */
90
static GdmDisplay *d = 0;
91 92
static gchar *login = NULL;
static gboolean greet = FALSE;
93
static gboolean configurator = FALSE;
94
static gboolean remanage_asap = FALSE;
95
static gboolean got_xfsz_signal = FALSE;
96 97 98 99
static gboolean do_timed_login = FALSE; /* if this is true,
					   login the timed login */
static gboolean do_configurator = FALSE; /* if this is true, login as root
					  * and start the configurator */
100 101 102
static gboolean do_cancel = FALSE; /* if this is true, go back to 
                                      username entry & unselect face
                                      browser (if present) */
103 104
static gboolean do_restart_greeter = FALSE; /* if this is true, whack the
					       greeter and try again */
105 106
static gboolean restart_greeter_now = FALSE; /* restart_greeter_when the
						SIGCHLD hits */
107 108
static gboolean gdm_wait_for_ack = TRUE; /* wait for ack on all messages to
				      * the daemon */
109
static int in_session_stop = 0;
110
static int in_usr2_signal = 0;
111 112
static gboolean need_to_quit_after_session_stop = FALSE;
static int exit_code_to_use = DISPLAY_REMANAGE;
113
static gboolean session_started = FALSE;
114 115 116
static gboolean greeter_disabled = FALSE;
static gboolean greeter_no_focus = FALSE;

117 118 119
static uid_t logged_in_uid = -1;
static gid_t logged_in_gid = -1;

120
static gboolean interrupted = FALSE;
121 122
static gchar *ParsedAutomaticLogin = NULL;
static gchar *ParsedTimedLogin = NULL;
123

124 125 126 127 128 129 130
static int greeter_fd_out = -1;
static int greeter_fd_in = -1;

typedef struct {
	pid_t pid;
} GdmWaitPid;

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
131 132
static int slave_waitpid_r = -1;
static int slave_waitpid_w = -1;
133
static GSList *slave_waitpids = NULL;
134

135
extern gboolean gdm_first_login;
136
extern gboolean gdm_emergency_server;
137
extern pid_t extra_process;
138
extern int extra_status;
139
extern int gdm_in_signal;
140
extern int gdm_normal_runlevel;
141

142 143
extern int slave_fifo_pipe_fd; /* the slavepipe (like fifo) connection, this is the write end */

144 145 146
/* wait for a GO in the SOP protocol */
extern gboolean gdm_wait_for_go;

147 148 149
/* Local prototypes */
static gint     gdm_slave_xerror_handler (Display *disp, XErrorEvent *evt);
static gint     gdm_slave_xioerror_handler (Display *disp);
150
static gint     gdm_slave_ignore_xioerror_handler (Display *disp);
151 152
static void	gdm_slave_run (GdmDisplay *display);
static void	gdm_slave_wait_for_login (void);
153
static void     gdm_slave_greeter (void);
154
static void     gdm_slave_chooser (void);
155
static void     gdm_slave_session_start (void);
156 157
static void     gdm_slave_session_stop (gboolean run_post_session,
					gboolean no_shutdown_check);
158
static void     gdm_slave_alrm_handler (int sig);
159
static void     gdm_slave_term_handler (int sig);
160
static void     gdm_slave_usr2_handler (int sig);
161
static void     gdm_slave_quick_exit (gint status);
162 163
static void     gdm_slave_exit (gint status, const gchar *format, ...) G_GNUC_PRINTF (2, 3);
static void     gdm_child_exit (gint status, const gchar *format, ...) G_GNUC_PRINTF (2, 3);
164
static gint     gdm_slave_exec_script (GdmDisplay *d, const gchar *dir,
165
				       const char *login, struct passwd *pwent,
166
				       gboolean pass_stdout);
167
static gchar *  gdm_parse_enriched_login (const gchar *s, GdmDisplay *display);
168
static void	gdm_slave_handle_usr2_message (void);
169
static void	gdm_slave_handle_notify (const char *msg);
170 171
static void	create_temp_auth_file (void);
static void	set_xnest_parent_stuff (void);
172 173
static void	check_notifies_now (void);
static void	restart_the_greeter (void);
174

175
/* Yay thread unsafety */
176
static gboolean x_error_occurred = FALSE;
177
static gboolean gdm_got_ack = FALSE;
178
static char * gdm_ack_response = NULL;
179 180
static GList *unhandled_notifies = NULL;

181 182 183

/* for signals that want to exit */
static Jmp_buf slave_start_jmp;
184 185
/* for handling xioerror during ctl-alt-bs */
static Jmp_buf ignore_xioerror_jmp;
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
static gboolean return_to_slave_start_jmp = FALSE;
static gboolean already_in_slave_start_jmp = FALSE;
static char *slave_start_jmp_error_to_print = NULL;
enum {
	JMP_FIRST_RUN = 0,
	JMP_SESSION_STOP_AND_QUIT = 1,
	JMP_JUST_QUIT_QUICKLY = 2
};
#define SIGNAL_EXIT_WITH_JMP(d,how) \
   {											\
	if ((d)->slavepid == getpid () && return_to_slave_start_jmp) {			\
		already_in_slave_start_jmp = TRUE;					\
		Longjmp (slave_start_jmp, how);						\
	} else {									\
		/* evil! how this this happen */					\
		if (slave_start_jmp_error_to_print != NULL)				\
			gdm_error (slave_start_jmp_error_to_print);			\
		gdm_error ("Bad (very very VERY bad!) things happening in signal");	\
		_exit (DISPLAY_REMANAGE);						\
	}										\
   }

208 209
/* notify all waitpids, make waitpids check notifies */
static void
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
210
slave_waitpid_notify (void)
211
{
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
212
	/* we're in no slave waitpids */
213 214 215 216 217
	if (slave_waitpids == NULL)
		return;

	gdm_sigchld_block_push ();

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
218
	if (slave_waitpid_w >= 0)
219
		VE_IGNORE_EINTR (write (slave_waitpid_w, "N", 1));
220 221 222 223 224 225 226 227 228 229 230

	gdm_sigchld_block_pop ();
}

/* make sure to wrap this call with sigchld blocks */
static GdmWaitPid *
slave_waitpid_setpid (pid_t pid)
{
	int p[2];
	GdmWaitPid *wp;

231
	if G_UNLIKELY (pid <= 1)
232 233 234 235 236
		return NULL;

	wp = g_new0 (GdmWaitPid, 1);
	wp->pid = pid;

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
237 238 239 240 241 242 243
	if (slave_waitpid_r < 0) {
		if G_UNLIKELY (pipe (p) < 0) {
			gdm_error ("slave_waitpid_setpid: cannot create pipe, trying to wing it");
		} else {
			slave_waitpid_r = p[0];
			slave_waitpid_w = p[1];
		}
244 245 246 247 248 249
	}

	slave_waitpids = g_slist_prepend (slave_waitpids, wp);
	return wp;
}

250
static void
251
run_session_output (gboolean read_until_eof)
252 253 254 255 256 257 258 259 260
{
	char buf[256];
	int r, written;
	uid_t old;
	gid_t oldg;
	
	old = geteuid ();
	oldg = getegid ();

261 262 263
	/* make sure we can set the gid */
	NEVER_FAILS_seteuid (0);

264 265 266
	/* make sure we are the user when we do this,
	   for purposes of file limits and all that kind of
	   stuff */
267 268
	if G_LIKELY (logged_in_gid >= 0) {
		if G_UNLIKELY (setegid (logged_in_gid) != 0) {
269 270
			gdm_error (_("Can't set EGID to user GID"));
			NEVER_FAILS_root_set_euid_egid (old, oldg);
271 272 273 274 275 276
			return;
		}
	}

	if G_LIKELY (logged_in_uid >= 0) {
		if G_UNLIKELY (seteuid (logged_in_uid) != 0) {
277 278
			gdm_error (_("Can't set EUID to user UID"));
			NEVER_FAILS_root_set_euid_egid (old, oldg);
279 280 281
			return;
		}
	}
282 283 284

	/* the fd is non-blocking */
	for (;;) {
285
		VE_IGNORE_EINTR (r = read (d->session_output_fd, buf, sizeof (buf)));
286

287 288
		/* EOF */
		if G_UNLIKELY (r == 0) {
289
			VE_IGNORE_EINTR (close (d->session_output_fd));
290
			d->session_output_fd = -1;
291
			VE_IGNORE_EINTR (close (d->xsession_errors_fd));
292 293 294 295 296 297 298 299 300 301 302
			d->xsession_errors_fd = -1;
			break;
		}

		/* Nothing to read */
		if (r < 0 && errno == EAGAIN)
			break;

		/* some evil error */
		if G_UNLIKELY (r < 0) {
			gdm_error ("error reading from session output, closing the pipe");
303
			VE_IGNORE_EINTR (close (d->session_output_fd));
304
			d->session_output_fd = -1;
305
			VE_IGNORE_EINTR (close (d->xsession_errors_fd));
306 307 308 309 310 311
			d->xsession_errors_fd = -1;
			break;
		}

		if G_UNLIKELY (d->xsession_errors_bytes >= MAX_XSESSION_ERRORS_BYTES ||
			       got_xfsz_signal)
312 313 314
			continue;

		/* write until we succeed in writing something */
315
		VE_IGNORE_EINTR (written = write (d->xsession_errors_fd, buf, r));
316
		if G_UNLIKELY (written < 0 || got_xfsz_signal) {
317
			/* evil! */
318
			break;
319 320 321 322 323
		}

		/* write until we succeed in writing everything */
		while G_UNLIKELY (written < r) {
			int n;
324
			VE_IGNORE_EINTR (n = write (d->xsession_errors_fd, &buf[written], r-written));
325
			if G_UNLIKELY (n < 0 || got_xfsz_signal) {
326
				/* evil! */
327
				break;
328 329 330 331 332 333
			}
			written += n;
		}

		d->xsession_errors_bytes += r;

334 335
		if G_UNLIKELY (d->xsession_errors_bytes >= MAX_XSESSION_ERRORS_BYTES &&
			       ! got_xfsz_signal) {
336
			VE_IGNORE_EINTR (write (d->xsession_errors_fd,
337 338
					     "\n...Too much output, ignoring rest...\n",
					     strlen ("\n...Too much output, ignoring rest...\n")));
339
		}
340 341 342 343 344

		/* there wasn't more then buf available, so no need to try reading
		 * again, unless we really want to */
		if (r < sizeof (buf) && ! read_until_eof)
			break;
345
	}
346

347
	NEVER_FAILS_root_set_euid_egid (old, oldg);
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
static void
run_chooser_output (void)
{
	char *bf;

	if G_UNLIKELY (d->chooser_output_fd < 0)
		return;

	/* the fd is non-blocking */
	do {
		bf = gdm_fdgets (d->chooser_output_fd);
		if (bf != NULL) {
			g_free (d->chooser_last_line);
			d->chooser_last_line = bf;
		}
	} while (bf != NULL);
}

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
#define TIME_UNSET_P(tv) ((tv)->tv_sec == 0 && (tv)->tv_usec == 0)

/* Try to touch an authfb auth file every 12 hours.  That way if it's
 * in /tmp it doesn't get whacked by tmpwatch */
#define TRY_TO_TOUCH_TIME (60*60*12)

static struct timeval *
min_time_to_wait (struct timeval *tv)
{
	if (d->authfb) {
		time_t ct = time (NULL);
		time_t sec_to_wait;

		if (d->last_auth_touch + TRY_TO_TOUCH_TIME + 5 <= ct)
			sec_to_wait = 5;
		else
			sec_to_wait = (d->last_auth_touch + TRY_TO_TOUCH_TIME) - ct;

		if (TIME_UNSET_P (tv) ||
		    sec_to_wait < tv->tv_sec)
			tv->tv_sec = sec_to_wait;
	}
	if (TIME_UNSET_P (tv))
		return NULL;
	else
		return tv;
}

static void
try_to_touch_fb_userauth (void)
{
	if (d->authfb && d->userauth != NULL && logged_in_uid >= 0) {
		time_t ct = time (NULL);

		if (d->last_auth_touch + TRY_TO_TOUCH_TIME <= ct) {
			uid_t old;
			gid_t oldg;

			old = geteuid ();
			oldg = getegid ();

409 410
			NEVER_FAILS_seteuid (0);

411 412 413 414 415 416
			/* make sure we are the user when we do this,
			   for purposes of file limits and all that kind of
			   stuff */
			if G_LIKELY (logged_in_gid >= 0) {
				if G_UNLIKELY (setegid (logged_in_gid) != 0) {
					gdm_error ("Can't set GID to user GID");
417
					NEVER_FAILS_root_set_euid_egid (old, oldg);
418 419 420 421 422 423 424
					return;
				}
			}

			if G_LIKELY (logged_in_uid >= 0) {
				if G_UNLIKELY (seteuid (logged_in_uid) != 0) {
					gdm_error ("Can't set UID to user UID");
425
					NEVER_FAILS_root_set_euid_egid (old, oldg);
426 427 428 429 430 431 432
					return;
				}
			}

			/* This will "touch" the file */
			utime (d->userauth, NULL);

433
			NEVER_FAILS_root_set_euid_egid (old, oldg);
434 435 436 437 438 439

			d->last_auth_touch = ct;
		}
	}
}

440 441 442 443
/* must call slave_waitpid_setpid before calling this */
static void
slave_waitpid (GdmWaitPid *wp)
{
444
	if G_UNLIKELY (wp == NULL)
445 446 447 448
		return;

	gdm_debug ("slave_waitpid: waiting on %d", (int)wp->pid);

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
449
	if G_UNLIKELY (slave_waitpid_r < 0) {
450 451 452 453
		gdm_error ("slave_waitpid: no pipe, trying to wing it");

		/* This is a real stupid fallback for a real stupid case */
		while (wp->pid > 1) {
454 455 456 457
			struct timeval tv;
			/* Wait 5 seconds. */
			tv.tv_sec = 5;
			tv.tv_usec = 0;
458
			select (0, NULL, NULL, NULL, min_time_to_wait (&tv));
459 460
			/* don't want to use sleep since we're using alarm
			   for pinging */
461

462 463 464
			/* try to touch an fb auth file */
			try_to_touch_fb_userauth ();

465 466
			if (d->session_output_fd >= 0)
				run_session_output (FALSE /* read_until_eof */);
467 468
			if (d->chooser_output_fd >= 0)
				run_chooser_output ();
469 470 471 472
			check_notifies_now ();
		}
		check_notifies_now ();
	} else {
473 474
		gboolean read_session_output = TRUE;

475 476
		do {
			char buf[1];
477 478
			fd_set rfds;
			int ret;
479
			struct timeval tv;
480
			int maxfd;
481 482

			FD_ZERO (&rfds);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
483
			FD_SET (slave_waitpid_r, &rfds);
484 485 486
			if (read_session_output &&
			    d->session_output_fd >= 0)
				FD_SET (d->session_output_fd, &rfds);
487 488
			if (d->chooser_output_fd >= 0)
				FD_SET (d->chooser_output_fd, &rfds);
489

490 491 492
			/* unset time */
			tv.tv_sec = 0;
			tv.tv_usec = 0;
493 494
			maxfd = MAX (slave_waitpid_r, d->session_output_fd);
			maxfd = MAX (maxfd, d->chooser_output_fd);
495

496
			ret = select (maxfd + 1, &rfds, NULL, NULL, min_time_to_wait (&tv));
497 498 499 500

			/* try to touch an fb auth file */
			try_to_touch_fb_userauth ();

501
			if (ret > 0) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
502
			       	if (FD_ISSET (slave_waitpid_r, &rfds)) {
503
					VE_IGNORE_EINTR (read (slave_waitpid_r, buf, 1));
504 505 506 507
				}
				if (d->session_output_fd >= 0 &&
				    FD_ISSET (d->session_output_fd, &rfds)) {
					run_session_output (FALSE /* read_until_eof */);
508
				}
509 510 511 512
				if (d->chooser_output_fd >= 0 &&
				    FD_ISSET (d->chooser_output_fd, &rfds)) {
					run_chooser_output ();
				}
513 514 515
			} else if (errno == EBADF) {
				read_session_output = FALSE;
			}
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
			check_notifies_now ();
		} while (wp->pid > 1);
		check_notifies_now ();
	}

	gdm_sigchld_block_push ();

	wp->pid = -1;

	slave_waitpids = g_slist_remove (slave_waitpids, wp);
	g_free (wp);

	gdm_sigchld_block_pop ();

	gdm_debug ("slave_waitpid: done_waiting");
}

533 534 535 536 537
static void
check_notifies_now (void)
{
	GList *list, *li;

538 539 540 541 542 543 544 545 546 547 548
	if (restart_greeter_now &&
	    do_restart_greeter) {
		do_restart_greeter = FALSE;
		restart_the_greeter ();
	}

	while (unhandled_notifies != NULL) {
		gdm_sigusr2_block_push ();
		list = unhandled_notifies;
		unhandled_notifies = NULL;
		gdm_sigusr2_block_pop ();
549

550 551 552
		for (li = list; li != NULL; li = li->next) {
			char *s = li->data;
			li->data = NULL;
553

554 555 556 557 558 559
			gdm_slave_handle_notify (s);

			g_free (s);
		}
		g_list_free (list);
	}
560

561 562 563 564
	if (restart_greeter_now &&
	    do_restart_greeter) {
		do_restart_greeter = FALSE;
		restart_the_greeter ();
565 566
	}
}
567

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
static void
gdm_slave_desensitize_config (void)
{
	if (configurator &&
	    d->dsp != NULL) {
		gulong foo = 1;
		Atom atom = XInternAtom (d->dsp,
					 "_GDM_SETUP_INSENSITIVE",
					 False);
		XChangeProperty (d->dsp,
				 DefaultRootWindow (d->dsp),
				 atom,
				 XA_CARDINAL, 32, PropModeReplace,
				 (unsigned char *) &foo, 1);
		XSync (d->dsp, False);
	}

}

static void
gdm_slave_sensitize_config (void)
{
	if (d->dsp != NULL) {
		XDeleteProperty (d->dsp,
				 DefaultRootWindow (d->dsp),
				 XInternAtom (d->dsp,
					      "_GDM_SETUP_INSENSITIVE",
					      False));
		XSync (d->dsp, False);
	}
}

600 601 602 603
/* ignore handlers */
static int
ignore_xerror_handler (Display *disp, XErrorEvent *evt)
{
604
	x_error_occurred = TRUE;
605 606 607
	return 0;
}

608 609 610 611
static void
whack_greeter_fds (void)
{
	if (greeter_fd_out > 0)
612
		VE_IGNORE_EINTR (close (greeter_fd_out));
613 614
	greeter_fd_out = -1;
	if (greeter_fd_in > 0)
615
		VE_IGNORE_EINTR (close (greeter_fd_in));
616 617 618
	greeter_fd_in = -1;
}

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
static void
term_session_stop_and_quit (void)
{
	gdm_in_signal = 0;
	already_in_slave_start_jmp = TRUE;
	gdm_wait_for_ack = FALSE;
	need_to_quit_after_session_stop = TRUE;

	if (slave_start_jmp_error_to_print != NULL)
		gdm_error (slave_start_jmp_error_to_print);
	slave_start_jmp_error_to_print = NULL;

	/* only if we're not hanging in session stop and getting a
	   TERM signal again */
	if (in_session_stop == 0 && session_started)
		gdm_slave_session_stop (d->logged_in && login != NULL,
					TRUE /* no_shutdown_check */);

	gdm_debug ("term_session_stop_and_quit: Final cleanup");

639 640 641 642 643 644
	/* Well now we're just going to kill
	 * everything including the X server,
	 * so no need doing XCloseDisplay which
	 * may just get us an XIOError */
	d->dsp = NULL;

645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
	gdm_slave_quick_exit (exit_code_to_use);
}

static void
term_quit (void)
{
	gdm_in_signal = 0;
	already_in_slave_start_jmp = TRUE;
	gdm_wait_for_ack = FALSE;
	need_to_quit_after_session_stop = TRUE;

	if (slave_start_jmp_error_to_print != NULL)
		gdm_error (slave_start_jmp_error_to_print);
	slave_start_jmp_error_to_print = NULL;

660 661 662 663 664 665 666
	gdm_debug ("term_quit: Final cleanup");

	/* Well now we're just going to kill
	 * everything including the X server,
	 * so no need doing XCloseDisplay which
	 * may just get us an XIOError */
	d->dsp = NULL;
667 668 669

	gdm_slave_quick_exit (exit_code_to_use);
}
670

671 672 673 674 675 676
static gboolean
parent_exists (void)
{
	pid_t ppid = getppid ();
	static gboolean parent_dead = FALSE; /* once dead, always dead */

677 678 679
	if G_UNLIKELY (parent_dead ||
		       ppid <= 1 ||
		       kill (ppid, 0) < 0) {
680 681 682 683 684 685
		parent_dead = TRUE;
		return FALSE;
	}
	return TRUE;
}

686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
#ifdef SIGXFSZ
static void
gdm_slave_xfsz_handler (int signal)
{
	gdm_in_signal++;

	/* in places where we care we can check
	 * and stop writing */
	got_xfsz_signal = TRUE;

	/* whack self ASAP */
	remanage_asap = TRUE;

	gdm_in_signal--;
}
#endif /* SIGXFSZ */

Martin Peterson's avatar
Martin Peterson committed
703
void 
704 705
gdm_slave_start (GdmDisplay *display)
{  
706 707
	time_t first_time;
	int death_count;
708
	struct sigaction alrm, term, child, usr2;
709 710 711
#ifdef SIGXFSZ
	struct sigaction xfsz;
#endif /* SIGXFSZ */
712
	sigset_t mask;
713
	int pinginterval = gdm_get_value_int (GDM_KEY_PING_INTERVAL);
714

715 716 717
	/*
	 * Set d global to display before setting signal handlers,
	 * since the signal handlers use the d value.  Avoids a 
718 719
	 * race condition.  It is also set again in gdm_slave_run
	 * since it is called in a loop.
720 721 722
	 */
	d = display;

723
	/* Ignore SIGUSR1/SIGPIPE, and especially ignore it
724
	   before the Setjmp */
725 726 727
	gdm_signal_ignore (SIGUSR1);
	gdm_signal_ignore (SIGPIPE);

728 729 730 731 732 733
	/* ignore power failures, up to user processes to
	 * handle things correctly */
#ifdef SIGPWR
	gdm_signal_ignore (SIGPWR);
#endif

734 735 736 737 738 739 740
	/* The signals we wish to listen to */
	sigemptyset (&mask);
	sigaddset (&mask, SIGINT);
	sigaddset (&mask, SIGTERM);
	sigaddset (&mask, SIGCHLD);
	sigaddset (&mask, SIGUSR2);
	sigaddset (&mask, SIGUSR1); /* normally we ignore USR1 */
741
	if ( ! SERVER_IS_LOCAL (display) && pinginterval > 0) {
742 743 744 745 746 747
		sigaddset (&mask, SIGALRM);
	}
	/* must set signal mask before the Setjmp as it will be
	   restored, and we're only interested in catching the above signals */
	sigprocmask (SIG_UNBLOCK, &mask, NULL);

748

749
	if G_UNLIKELY (display == NULL) {
750 751 752
		/* saaay ... what? */
		_exit (DISPLAY_REMANAGE);
	}
753 754

	gdm_debug ("gdm_slave_start: Starting slave process for %s", display->name);
755

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
	switch (Setjmp (slave_start_jmp)) {
	case JMP_FIRST_RUN:
		return_to_slave_start_jmp = TRUE;
		break;
	case JMP_SESSION_STOP_AND_QUIT:
		term_session_stop_and_quit ();
		/* huh? should never get here */
		_exit (DISPLAY_REMANAGE);
	default:
	case JMP_JUST_QUIT_QUICKLY:
		term_quit ();
		/* huh? should never get here */
		_exit (DISPLAY_REMANAGE);
	}

771
	if ( ! SERVER_IS_LOCAL (display) && pinginterval > 0) {
772 773 774 775 776 777
		/* Handle a ALRM signals from our ping alarms */
		alrm.sa_handler = gdm_slave_alrm_handler;
		alrm.sa_flags = SA_RESTART | SA_NODEFER;
		sigemptyset (&alrm.sa_mask);
		sigaddset (&alrm.sa_mask, SIGALRM);

778
		if G_UNLIKELY (sigaction (SIGALRM, &alrm, NULL) < 0)
779
			gdm_slave_exit (DISPLAY_ABORT,
780 781
					_("%s: Error setting up %s signal handler: %s"),
					"gdm_slave_start", "ALRM", strerror (errno));
782 783
	}

784 785 786 787 788 789 790
	/* Handle a INT/TERM signals from gdm master */
	term.sa_handler = gdm_slave_term_handler;
	term.sa_flags = SA_RESTART;
	sigemptyset (&term.sa_mask);
	sigaddset (&term.sa_mask, SIGTERM);
	sigaddset (&term.sa_mask, SIGINT);

791 792
	if G_UNLIKELY ((sigaction (SIGTERM, &term, NULL) < 0) ||
		       (sigaction (SIGINT, &term, NULL) < 0))
793
		gdm_slave_exit (DISPLAY_ABORT,
794 795
				_("%s: Error setting up %s signal handler: %s"),
				"gdm_slave_start", "TERM/INT", strerror (errno));
796 797 798 799 800 801 802

	/* Child handler. Keeps an eye on greeter/session */
	child.sa_handler = gdm_slave_child_handler;
	child.sa_flags = SA_RESTART|SA_NOCLDSTOP;
	sigemptyset (&child.sa_mask);
	sigaddset (&child.sa_mask, SIGCHLD);

803
	if G_UNLIKELY (sigaction (SIGCHLD, &child, NULL) < 0) 
804 805
		gdm_slave_exit (DISPLAY_ABORT, _("%s: Error setting up %s signal handler: %s"),
				"gdm_slave_start", "CHLD", strerror (errno));
806

807 808 809 810 811 812
	/* Handle a USR2 which is ack from master that it received a message */
	usr2.sa_handler = gdm_slave_usr2_handler;
	usr2.sa_flags = SA_RESTART;
	sigemptyset (&usr2.sa_mask);
	sigaddset (&usr2.sa_mask, SIGUSR2);

813
	if G_UNLIKELY (sigaction (SIGUSR2, &usr2, NULL) < 0)
814 815
		gdm_slave_exit (DISPLAY_ABORT, _("%s: Error setting up %s signal handler: %s"),
				"gdm_slave_start", "USR2", strerror (errno));
816

817 818 819 820 821 822 823 824 825 826 827 828 829
#ifdef SIGXFSZ
	/* handle the filesize signal */
	xfsz.sa_handler = gdm_slave_xfsz_handler;
	xfsz.sa_flags = SA_RESTART;
	sigemptyset (&xfsz.sa_mask);
	sigaddset (&xfsz.sa_mask, SIGXFSZ);

	if G_UNLIKELY (sigaction (SIGXFSZ, &xfsz, NULL) < 0)
		gdm_slave_exit (DISPLAY_ABORT,
				_("%s: Error setting up %s signal handler: %s"),
				"gdm_slave_start", "XFSZ", strerror (errno));
#endif /* SIGXFSZ */

830 831 832 833 834 835
	first_time = time (NULL);
	death_count = 0;

	for (;;) {
		time_t the_time;

836 837
		check_notifies_now ();

838 839 840
		gdm_debug ("gdm_slave_start: Loop Thingie");
		gdm_slave_run (display);

841
		/* remote and flexi only run once */
842
		if (display->type != TYPE_STATIC ||
843
		    ! parent_exists ()) {
844
			gdm_server_stop (display);
845
			gdm_slave_send_num (GDM_SOP_XPID, 0);
846 847
			gdm_slave_quick_exit (DISPLAY_REMANAGE);
		}
848 849 850

		the_time = time (NULL);

851
		death_count++;
852 853

		if ((the_time - first_time) <= 0 ||
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
854
		    (the_time - first_time) > 60) {
855 856
			first_time = the_time;
			death_count = 0;
857
		} else if G_UNLIKELY (death_count > 6) {
858
			gdm_slave_quick_exit (DISPLAY_ABORT);
859
		}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
860 861 862

		gdm_debug ("gdm_slave_start: Reinitializing things");

863
		if (gdm_get_value_bool (GDM_KEY_ALWAYS_RESTART_SERVER)) {
864 865 866
			/* Whack the server if we want to restart it next time
			 * we run gdm_slave_run */
			gdm_server_stop (display);
867
			gdm_slave_send_num (GDM_SOP_XPID, 0);
868
		} else {
869
			/* OK about to start again so rebake our cookies and reinit
870
			 * the server */
871
			if G_UNLIKELY ( ! gdm_auth_secure_display (d)) {
872 873
				gdm_slave_quick_exit (DISPLAY_REMANAGE);
			}
874
			gdm_slave_send_string (GDM_SOP_COOKIE, d->cookie);
875
			gdm_slave_send_string (GDM_SOP_AUTHFILE, d->authfile);
876

877
			if G_UNLIKELY ( ! gdm_server_reinit (d)) {
878 879 880
				gdm_error ("Error reinitilizing server");
				gdm_slave_quick_exit (DISPLAY_REMANAGE);
			}
881
		}
882
	}
883 884 885
	/* very very very evil, should never break, we can't return from
	   here sanely */
	_exit (DISPLAY_ABORT);
886
}
Martin Peterson's avatar
Martin Peterson committed
887

888
static gboolean
889 890
setup_automatic_session (GdmDisplay *display, const char *name)
{
891
	char *new_login;
892 893 894 895
	g_free (login);
	login = g_strdup (name);

	greet = FALSE;
896
	gdm_debug ("setup_automatic_session: Automatic login: %s", login);
897 898 899

	/* Run the init script. gdmslave suspends until script
	 * has terminated */
900 901
	gdm_slave_exec_script (display, gdm_get_value_string (GDM_KEY_DISPLAY_INIT_DIR),
			       NULL, NULL, FALSE /* pass_stdout */);
902

903
	gdm_debug ("setup_automatic_session: DisplayInit script finished");
904

905 906 907
	new_login = NULL;
	if ( ! gdm_verify_setup_user (display, login,
				      display->name, &new_login))
908 909
		return FALSE;

910 911 912 913 914
	if (new_login != NULL) {
		g_free (login);
		login = g_strdup (new_login);
	}

915 916
	gdm_debug ("setup_automatic_session: Automatic login successful");

917
	return TRUE;
918 919
}

920 921 922
static void 
gdm_screen_init (GdmDisplay *display) 
{
923
#ifdef HAVE_XFREE_XINERAMA
924 925 926
	int (* old_xerror_handler) (Display *, XErrorEvent *);
	gboolean have_xinerama = FALSE;

927
	x_error_occurred = FALSE;
928 929 930 931 932 933 934
	old_xerror_handler = XSetErrorHandler (ignore_xerror_handler);

	have_xinerama = XineramaIsActive (display->dsp);

	XSync (display->dsp, False);
	XSetErrorHandler (old_xerror_handler);

935
	if (x_error_occurred)
936 937 938 939
		have_xinerama = FALSE;

	if (have_xinerama) {
		int screen_num;
940
		int xineramascreen;
941 942 943 944 945
		XineramaScreenInfo *xscreens =
			XineramaQueryScreens (display->dsp,
					      &screen_num);


946
		if G_UNLIKELY (screen_num <= 0)
947 948
			gdm_fail ("Xinerama active, but <= 0 screens?");

949 950
		if (screen_num <= gdm_get_value_int (GDM_KEY_XINERAMA_SCREEN))
			gdm_set_value_int (GDM_KEY_XINERAMA_SCREEN, 0);
951

952
		xineramascreen = gdm_get_value_int (GDM_KEY_XINERAMA_SCREEN);
953 954 955 956 957

		display->screenx = xscreens[xineramascreen].x_org;
		display->screeny = xscreens[xineramascreen].y_org;
		display->screenwidth = xscreens[xineramascreen].width;
		display->screenheight = xscreens[xineramascreen].height;
958

959 960 961 962 963 964 965 966 967
		display->lrh_offsetx =
			DisplayWidth (display->dsp,
				      DefaultScreen (display->dsp))
			- (display->screenx + display->screenwidth);
		display->lrh_offsety =
			DisplayHeight (display->dsp,
				       DefaultScreen (display->dsp))
			- (display->screeny + display->screenheight);

968 969
		XFree (xscreens);
	} else
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
#elif HAVE_SOLARIS_XINERAMA
 /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
 	int opcode;
	int firstevent;
	int firsterror;
	int n_monitors = 0;

	gboolean have_xinerama = FALSE;
	have_xinerama = XQueryExtension (display->dsp,
			"XINERAMA",
			&opcode,
			&firstevent,
			&firsterror);

	if (have_xinerama) {
	
		int result;
		XRectangle monitors[MAXFRAMEBUFFERS];
		unsigned char  hints[16];
989
		int xineramascreen;
990 991 992 993 994
		
		result = XineramaGetInfo (display->dsp, 0, monitors, hints, &n_monitors);
		/* Yes I know it should be Success but the current implementation 
		 * returns the num of monitor
		 */
995
		if G_UNLIKELY (result <= 0)
996 997
			gdm_fail ("Xinerama active, but <= 0 screens?");

998 999
		if (n_monitors <= gdm_get_value_int (GDM_KEY_XINERAMA_SCREEN))
			gdm_set_value_int (GDM_KEY_XINERAMA_SCREEN, 0);
1000

1001 1002 1003 1004 1005
		xineramascreen = gdm_get_value_int (GDM_KEY_XINERAMA_SCREEN);
		display->screenx = monitors[xineramascreen].x;
		display->screeny = monitors[xineramascreen].y;
		display->screenwidth = monitors[xineramascreen].width;
		display->screenheight = monitors[xineramascreen].height;
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016

		display->lrh_offsetx =
			DisplayWidth (display->dsp,
				      DefaultScreen (display->dsp))
			- (display->screenx + display->screenwidth);
		display->lrh_offsety =
			DisplayHeight (display->dsp,
				       DefaultScreen (display->dsp))
			- (display->screeny + display->screenheight);

	} else
1017 1018 1019 1020
#endif
	{
		display->screenx = 0;
		display->screeny = 0;
1021 1022
		display->screenwidth = 0; /* we'll use the gdk size */
		display->screenheight = 0;
1023 1024 1025

		display->lrh_offsetx = 0;
		display->lrh_offsety = 0;
1026 1027 1028
	}
}

1029 1030 1031
static void
gdm_slave_whack_greeter (void)
{
1032 1033
	GdmWaitPid *wp;

1034 1035 1036 1037 1038 1039 1040
	gdm_sigchld_block_push ();

	/* do what you do when you quit, this will hang until the
	 * greeter decides to print an STX\n and die, meaning it can do some
	 * last minute cleanup */
	gdm_slave_greeter_ctl_no_ret (GDM_QUIT, "");

1041 1042
	greet = FALSE;

1043 1044 1045 1046 1047
	wp = slave_waitpid_setpid (d->greetpid);
	gdm_sigchld_block_pop ();

	slave_waitpid (wp);

1048 1049
	d->greetpid = 0;

1050 1051
	whack_greeter_fds ();

1052 1053
	gdm_slave_send_num (GDM_SOP_GREETPID, 0);

1054
	gdm_slave_whack_temp_auth_file ();
1055 1056
}

1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
static void
wait_for_display_to_die (Display    *display,
			 const char *display_name)
{
	fd_set rfds;
	int    fd;

	gdm_debug ("wait_for_display_to_die: waiting for display '%s' to die",
		   display_name);

	fd = ConnectionNumber (display);

	FD_ZERO (&rfds);
	FD_SET (fd, &rfds);

	while (1) {
		char           buf[256];
		struct timeval tv;
		int            n;

		tv.tv_sec  = 5;
		tv.tv_usec = 0;

		n = select (fd + 1, &rfds, NULL, NULL, &tv);
		if (G_LIKELY (n == 0)) {
			XSync (display, True);
		} else if (n > 0) {
			VE_IGNORE_EINTR (n = read (fd, buf, sizeof (buf)));
			if (n <= 0)
				break;
		} else if (errno != EINTR) {
			break;
		}

		FD_CLR (fd, &rfds);
	}

	gdm_debug ("wait_for_display_to_die: '%s' dead", display_name);
}

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
static int
ask_migrate (const char *migrate_to)
{
	int   r;
	char *msg;
	char *but[4];

	but[0] = _("Log in anyway");
	if (migrate_to != NULL) {
		msg = _("You are already logged in.  "
			"You can log in anyway, return to your "
			"previous login session, or abort this "
			"login");
		but[1] = _("Return to previous login");
		but[2] = _("Abort login");
		but[3] = NULL;
	} else {
		msg = _("You are already logged in.  "
			"You can log in anyway or abort this "
			"login");
		but[1] = _("Abort login");
		but[2] = NULL;
	}

	if (greet)
		gdm_slave_greeter_ctl_no_ret (GDM_DISABLE, "");

	r = gdm_failsafe_ask_buttons (d, msg, but);

	if (greet)
		gdm_slave_greeter_ctl_no_ret (GDM_ENABLE, "");

	return r;
}

1132 1133 1134 1135 1136 1137
gboolean
gdm_slave_check_user_wants_to_log_in (const char *user)
{
	gboolean loggedin = FALSE;
	int i;
	char **vec;
1138 1139 1140 1141 1142 1143 1144
	char *migrate_to = NULL;

	/* always ignore root here, this is mostly a special case
	 * since a root login may not be a real login, such as the
	 * config stuff, and people shouldn't log in as root anyway
	 */
	if (strcmp (user, gdm_root_user ()) == 0)
1145 1146 1147
		return TRUE;

	gdm_slave_send_string (GDM_SOP_QUERYLOGIN, user);
1148
	if G_LIKELY (ve_string_empty (gdm_ack_response))
1149 1150 1151 1152 1153
	       return TRUE;	
	vec = g_strsplit (gdm_ack_response, ",", -1);
	if (vec == NULL)
		return TRUE;

1154 1155
	gdm_debug ("QUERYLOGIN response: %s\n", gdm_ack_response);

1156 1157 1158
	for (i = 0; vec[i] != NULL && vec[i+1] != NULL; i += 2) {
		int ii;
		loggedin = TRUE;
1159 1160 1161 1162
		if (sscanf (vec[i+1], "%d", &ii) == 1 && ii == 1) {
			migrate_to = g_strdup (vec[i]);
			break;
		}
1163 1164 1165 1166
	}

	g_strfreev (vec);

1167
	if ( ! loggedin)
1168 1169
		return TRUE;

1170 1171
	if (d->type != TYPE_XDMCP_PROXY) {
		int r;
1172

1173
		if (!gdm_get_value_bool (GDM_KEY_DOUBLE_LOGIN_WARNING)) {
1174
			g_free (migrate_to);
1175
			return TRUE;
1176
		}
1177

1178
		if (gdm_get_value_bool (GDM_KEY_ALWAYS_LOGIN_CURRENT_SESSION))
1179 1180 1181
			r = 1;
		else
			r = ask_migrate (migrate_to);
1182

1183 1184
		if (r <= 0) {
			g_free (migrate_to);
1185
			return TRUE;
1186
		}
1187

1188 1189 1190
		if (migrate_to == NULL ||
		    (migrate_to != NULL && r == 2)) {
			g_free (migrate_to);
1191
			return FALSE;
1192
		}
1193 1194 1195 1196 1197 1198 1199

		/* Must be that r == 1, that is
		   return to previous login */

		if (d->type == TYPE_FLEXI) {
			gdm_slave_whack_greeter ();
			gdm_server_stop (d);
1200
			gdm_slave_send_num (GDM_SOP_XPID, 0);
1201 1202 1203

			/* wait for a few seconds to avoid any vt changing race
			 */
1204
			gdm_sleep_no_signal (1);
1205

1206 1207
			gdm_slave_send_string (GDM_SOP_MIGRATE, migrate_to);
			g_free (migrate_to);
1208 1209 1210 1211 1212 1213

			/* we are no longer needed so just die.
			   REMANAGE == ABORT here really */
			gdm_slave_quick_exit (DISPLAY_REMANAGE);
		}

1214 1215
		gdm_slave_send_string (GDM_SOP_MIGRATE, migrate_to);
		g_free (migrate_to);
1216
	} else {
1217 1218 1219
		Display *parent_dsp;

		if (migrate_to == NULL)
1220
			return TRUE;
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
		
		gdm_slave_send_string (GDM_SOP_MIGRATE, migrate_to);
		g_free (migrate_to);

		/*
		 * We must stay running and hold open our connection to the
		 * parent display because with XDMCP the Xserver resets when
		 * the initial X client closes its connection (rather than
		 * when *all* X clients have closed their connection)
		 */

		gdm_slave_whack_greeter ();

		parent_dsp = d->parent_dsp;
		d->parent_dsp = NULL;
		gdm_server_stop (d);

		gdm_slave_send_num (GDM_SOP_XPID, 0);

		gdm_debug ("Slave not exiting in order to hold open the connection to the parent display");

		wait_for_display_to_die (d->parent_dsp, d->parent_disp);

		gdm_slave_quick_exit (DISPLAY_ABORT);
1245
	}
1246 1247 1248

	/* abort this login attempt */
	return FALSE;
1249
}
1250

1251
static gboolean do_xfailed_on_xio_error = FALSE;
1252 1253 1254 1255 1256

static void 
gdm_slave_run (GdmDisplay *display)
{  
    gint openretries = 0;
1257
    gint maxtries = 0;
1258
    gint pinginterval = gdm_get_value_int (GDM_KEY_PING_INTERVAL);
1259
    
1260 1261 1262
    /* Reset d since gdm_slave_run is called in a loop */
    d = display;

1263 1264
    gdm_random_tick ();

1265
    if (d->sleep_before_run > 0) {
1266
	    gdm_debug ("gdm_slave_run: Sleeping %d seconds before server start", d->sleep_before_run);
1267
	    gdm_sleep_no_signal (d->sleep_before_run);
1268
	    d->sleep_before_run = 0;
1269 1270

	    check_notifies_now ();
1271 1272
    }

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1273 1274 1275 1276
    /* set it before we run the server, it may be that we're using
     * the XOpenDisplay to find out if a server is ready (as with Xnest) */
    d->dsp = NULL;

1277 1278
    /* if this is local display start a server if one doesn't
     * exist */
1279
    if (SERVER_IS_LOCAL (d) &&
1280
	d->servpid <= 0) {
1281
	    if G_UNLIKELY ( ! gdm_server_start (d,
1282
						TRUE /* try_again_if_busy */,
1283 1284 1285
						FALSE /* treat_as_flexi */,
						20 /* min_flexi_disp */,
						5 /* flexi_retries */)) {
1286 1287 1288 1289 1290
		    /* We're really not sure what is going on,
		     * so we throw up our hands and tell the user
		     * that we've given up.  The error is likely something
		     * internal. */
		    gdm_text_message_dialog
1291
			    (C_(N_("Could not start the X\n"
1292 1293 1294 1295 1296
				   "server (your graphical environment)\n"
				   "due to some internal error.\n"
				   "Please contact your system administrator\n"
				   "or check your syslog to diagnose.\n"
				   "In the meantime this display will be\n"
1297
				   "disabled.  Please restart GDM when\n"
1298
				   "the problem is corrected.")));
1299
		    gdm_slave_quick_exit (DISPLAY_ABORT);
1300
	    }
1301
	    gdm_slave_send_num (GDM_SOP_XPID, d->servpid);
1302 1303

	    check_notifies_now ();
1304
    }
1305 1306 1307

    /* We can use d->handled from now on on this display,
     * since the lookup was done in server start */
1308
    
1309 1310
    g_setenv ("DISPLAY", d->name, TRUE);
    g_unsetenv ("XAUTHORITY"); /* just in case it's set */
1311 1312

    gdm_auth_set_local_auth (d);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1313

1314 1315
    if (d->handled) {
	    /* Now the display name and hostname is final */
1316 1317 1318 1319

	    char *automaticlogin = gdm_get_value_string (GDM_KEY_AUTOMATIC_LOGIN);
	    char *timedlogin     = gdm_get_value_string (GDM_KEY_TIMED_LOGIN);

1320 1321
	    if (gdm_get_value_bool (GDM_KEY_AUTOMATIC_LOGIN_ENABLE) && 
		! ve_string_empty (automaticlogin)) {
1322
		    g_free (ParsedAutomaticLogin);
1323
		    ParsedAutomaticLogin = gdm_parse_enriched_login (automaticlogin,
1324 1325
								     display);
	    }
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1326

1327 1328
	    if (gdm_get_value_bool (GDM_KEY_TIMED_LOGIN_ENABLE) &&
		! ve_string_empty (timedlogin)) {
1329
		    g_free (ParsedTimedLogin);
1330
		    ParsedTimedLogin = gdm_parse_enriched_login (timedlogin,
1331 1332
								 display);
	    }
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1333
    }
1334 1335
    
    /* X error handlers to avoid the default one (i.e. exit (1)) */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1336
    do_xfailed_on_xio_error = TRUE;
1337 1338 1339
    XSetErrorHandler (gdm_slave_xerror_handler);
    XSetIOErrorHandler (gdm_slave_xioerror_handler);
    
Martin Peterson's avatar
Martin Peterson committed
1340 1341 1342
    /* We keep our own (windowless) connection (dsp) open to avoid the
     * X server resetting due to lack of active connections. */

1343
    gdm_debug ("gdm_slave_run: Opening display %s", d->name);
1344 1345 1346

    /* if local then the the server should be ready for openning, so
     * don't try so long before killing it and trying again */
1347
    if (SERVER_IS_LOCAL (d))
1348 1349 1350
	    maxtries = 2;
    else
	    maxtries = 10;
1351
    
1352 1353
    while (d->handled &&
	   openretries < maxtries &&
1354
	   d->dsp == NULL &&
1355
	   ( ! SERVER_IS_LOCAL (d) || d->servpid > 1)) {
1356 1357
	d->dsp = XOpenDisplay (d->name);
	
1358
	if G_UNLIKELY (d->dsp == NULL) {
1359
	    gdm_debug ("gdm_slave_run: Sleeping %d on a retry", 1+openretries*2);
1360
	    gdm_sleep_no_signal (1+openretries*2);
Martin Peterson's avatar
Martin Peterson committed
1361 1362 1363
	    openretries++;
	}
    }
1364

1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
    /* Really this will only be useful for the first local server,
       since that's the only time this can really be on */
    while G_UNLIKELY (gdm_wait_for_go) {
	    struct timeval tv;
	    /* Wait 1 second. */
	    tv.tv_sec = 1;
	    tv.tv_usec = 0;
	    select (0, NULL, NULL, NULL, &tv);
	    /* don't want to use sleep since we're using alarm
	       for pinging */
	    check_notifies_now ();
    }

1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
    /* Set the busy cursor */
    if (d->dsp != NULL) {
	    Cursor xcursor = XCreateFontCursor (d->dsp, GDK_WATCH);
	    XDefineCursor (d->dsp,
			   DefaultRootWindow (d->dsp),
			   xcursor);
	    XFreeCursor (d->dsp, xcursor);
	    XSync (d->dsp, False);
    }

1388 1389 1390
    /* Just a race avoiding sleep, probably not necessary though,
     * but doesn't hurt anything */
    if ( ! d->handled)
1391
	    gdm_sleep_no_signal (1);
1392

Gregory Leblanc's avatar
Gregory Leblanc committed
1393 1394 1395 1396
    if (SERVER_IS_LOCAL (d)) {
	    gdm_slave_send (GDM_SOP_START_NEXT_LOCAL, FALSE);
    }

1397 1398
    check_notifies_now ();

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1399
    /* something may have gone wrong, try xfailed, if local (non-flexi),
1400
     * the toplevel loop of death will handle us */ 
1401
    if G_UNLIKELY (d->handled && d->dsp == NULL) {
1402
	    if (d->type == TYPE_STATIC)
1403
		    gdm_slave_quick_exit (DISPLAY_XFAILED);
1404
	    else
1405
		    gdm_slave_quick_exit (DISPLAY_ABORT);
1406
    }
1407

1408 1409 1410 1411
    /* OK from now on it's really the user whacking us most likely,
     * we have already started up well */
    do_xfailed_on_xio_error = FALSE;

1412
    /* If XDMCP setup pinging */