summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog64
-rw-r--r--TODO3
-rw-r--r--acconfig.h1
-rw-r--r--config/Makefile.am11
-rw-r--r--config/gdm.conf.in2
-rw-r--r--configure.in5
-rw-r--r--daemon/auth.c6
-rw-r--r--daemon/display.c46
-rw-r--r--daemon/errorgui.c4
-rw-r--r--daemon/gdm.c122
-rw-r--r--daemon/gdm.h2
-rw-r--r--daemon/misc.c22
-rw-r--r--daemon/server.c25
-rw-r--r--daemon/slave.c401
-rw-r--r--daemon/verify-pam.c26
-rw-r--r--docs/C/gdm.xml25
-rw-r--r--gdm.spec.in3
-rw-r--r--gui/gdmchooser.c117
-rw-r--r--gui/gdmlogin.c15
-rw-r--r--gui/greeter/greeter_item_ulist.c15
20 files changed, 706 insertions, 209 deletions
diff --git a/ChangeLog b/ChangeLog
index 6c4daced..6d47f16a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,67 @@
+Thu Jul 24 14:58:23 2003 George Lebl <jirka@5z.com>
+
+ * daemon/gdm.c, daemon/slave.c, daemon/auth.c: change some
+ g_strconcat's to g_build_filename's to address #118040.
+ still more need to be converted
+
+ * gdm.spec.in, daemon/gdm.h, config/gdm.conf.in, config/Makefile.am,
+ configure.in: By default use logdir of /var/log/gdm just
+ like redhat does it
+
+ * daemon/gdm.c: check logdir to exist and if not set it to
+ ServAuthDir
+
+ * gdm.spec.in, daemon/gdm.c, config/Makefile.am: Make the
+ ServAuthDir permissions to be 1770 with owenership root.gdm.
+ That makes it impossible for the gdm user to run DoS attacks
+ against the gdm daemon (though without any process limits set
+ it can still somewhat do that)
+
+ * daemon/slave.c, daemon/display.c, daemon/gdm.c, daemon/misc.c,
+ daemon/server.c: Hunt more races and hangs. Make sure we really
+ don't do anything bad in signal handlers by making a setjmp
+ at the beginning of the slave_start function and returning
+ there from signal handlers to do final cleanup kind of stuff.
+ Also when we are receiving TERM signals while waiting on stuff
+ to die, be very un-nice to things and SIGKILL them. Also stop
+ using sleep if we might be using alarm at the same time.
+
+ * daemon/display.c: whack non-useful signal block push on unmanage,
+ and if we get a TERM signal while waiting on the slave, then send
+ a TERM signal to the slave again.
+
+ * daemon/errorgui.c: set USER, USERNAME and LOGNAME to "gdm" so that
+ they don't end up root by some mistake
+
+ * daemon/slave.c: Use home of root rather then /root for the home
+ directory of gdmsetup. Also if we can't change to the home
+ directory chdir to / instead of leaving it at servauthdir.
+ Be anal about COOKIEs in the logfile. Also when things go
+ just a bit wrong and not completely whacko, don't ABORT but
+ just REMANAGE, the toplevel loop of death will handle things
+ for us correctly. And setsid a very close to the start of
+ the session to avoid a race ABORTing a display by mistake.
+
+ * daemon/slave.c: make the PostLogin behave just like PostSession
+ with respect to the return value
+
+ * daemon/verify-pam.c: avoid races on termination with the
+ verify_cleanup and handle some cases where crashes may (but
+ should not) occur.
+
+ * daemon/gdm.c: whack unneeded signal blockers (the main daemon
+ is all async with a nice mainloop)
+
+ * gui/gdmchooser.c: handle HUP gracefully, when one of the
+ config options we care about changes just restart self
+ instead of
+
+ * gui/gdmlogin.c, gui/greeter/greeter_item_ulist.c: make
+ the username bold
+
+ * docs/C/gdm.xml: update the PostLogin behaviour and the permissions
+ on the ServAuthDir
+
Wed Jul 23 15:13:33 2003 George Lebl <jirka@5z.com>
* Release 2.4.2.98
diff --git a/TODO b/TODO
index 0329afb4..7b1909ff 100644
--- a/TODO
+++ b/TODO
@@ -12,6 +12,9 @@ thing and just ignore the ping if a signal comes, not sure how this will play wi
the X stuff and if this would completely whack us out. The other option is to have
a separate "pinger process" but that seems to heavyweight.
+All the GUIs running as the gdm user should have some resource limits set to
+make it hard to do DoS attacks by somehow exploiting a leak or some such.
+
Small TODO things:
- If we can't setup pam display user visible errors and not just syslog stuff
diff --git a/acconfig.h b/acconfig.h
index 1b074e1f..3c2b3bd3 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -27,6 +27,7 @@
#undef EXPANDED_GDMCONFIGDIR
#undef EXPANDED_LOCALEDIR
#undef EXPANDED_AUTHDIR
+#undef EXPANDED_LOGDIR
#undef EXPANDED_SYSCONFDIR
#undef EXPANDED_SESSDIR
#undef X_SERVER
diff --git a/config/Makefile.am b/config/Makefile.am
index 1e4bb289..0c61b676 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -5,6 +5,7 @@ localedir = $(sysconfdir)/gdm
sessdir = $(sysconfdir)/dm/Sessions
initdir = $(sysconfdir)/gdm/Init
authdir = $(localstatedir)/gdm
+logdir = $(localstatedir)/gdm
gnomercdir = $(sysconfdir)/gdm
postdir = $(sysconfdir)/gdm/PostSession
predir = $(sysconfdir)/gdm/PreSession
@@ -121,10 +122,16 @@ install-data-hook: gdm.conf Xsession gnome.desktop Default.desktop CDE.desktop D
chmod 755 $(DESTDIR)$(gnomercdir); \
fi
+ if test '!' -d $(DESTDIR)$(logdir); then \
+ $(mkinstalldirs) $(DESTDIR)$(logdir); \
+ chown root.root $(DESTDIR)$(logdir); \
+ chmod 755 $(DESTDIR)$(logdir); \
+ fi
+
if test '!' -d $(DESTDIR)$(authdir); then \
$(mkinstalldirs) $(DESTDIR)$(authdir); \
- chown gdm.gdm $(DESTDIR)$(authdir); \
- chmod 750 $(DESTDIR)$(authdir); \
+ chown root.gdm $(DESTDIR)$(authdir); \
+ chmod 1770 $(DESTDIR)$(authdir); \
fi
system=`uname`; \
diff --git a/config/gdm.conf.in b/config/gdm.conf.in
index 31a27f66..07e12808 100644
--- a/config/gdm.conf.in
+++ b/config/gdm.conf.in
@@ -59,7 +59,7 @@ Group=gdm
# To try to kill all clients started at greeter time or in the Init script.
# doesn't always work, only if those clients have a window of their own
KillInitClients=true
-LogDir=@EXPANDED_AUTHDIR@
+LogDir=@EXPANDED_LOGDIR@
# You should probably never change this value unless you have a weird setup
PidFile=/var/run/gdm.pid
# Note that a post login script is run before a PreSession script.
diff --git a/configure.in b/configure.in
index ec5865f2..39b9c432 100644
--- a/configure.in
+++ b/configure.in
@@ -498,6 +498,11 @@ EXPANDED_AUTHDIR=`eval echo $AUTHDIR_TMP`
AC_SUBST(EXPANDED_AUTHDIR)
AC_DEFINE_UNQUOTED(EXPANDED_AUTHDIR,"$EXPANDED_AUTHDIR")
+LOGDIR_TMP="$localstatedir/log/gdm"
+EXPANDED_LOGDIR=`eval echo $LOGDIR_TMP`
+AC_SUBST(EXPANDED_LOGDIR)
+AC_DEFINE_UNQUOTED(EXPANDED_LOGDIR,"$EXPANDED_LOGDIR")
+
if test -x /usr/X11R6/bin/X; then
X_PATH="/usr/bin/X11:/usr/X11R6/bin:/opt/X11R6/bin"
X_SERVER_PATH="/usr/X11R6/bin"
diff --git a/daemon/auth.c b/daemon/auth.c
index 6fff5cc2..a1d0a155 100644
--- a/daemon/auth.c
+++ b/daemon/auth.c
@@ -178,7 +178,7 @@ gdm_auth_secure_display (GdmDisplay *d)
/* Note, Xnest can't use the ServAuthDir unless running as
* root, which is rare anyway, unless the user is a wanker */
- d->authfile = g_strconcat (GdmUserAuthFB, "/.gdmXXXXXX", NULL);
+ d->authfile = g_build_filename (GdmUserAuthFB, ".gdmXXXXXX", NULL);
umask (077);
authfd = g_mkstemp (d->authfile);
@@ -438,7 +438,7 @@ try_user_add_again:
if (authdir == NULL)
d->userauth = NULL;
else
- d->userauth = g_strconcat (authdir, "/", GdmUserAuthFile, NULL);
+ d->userauth = g_build_filename (authdir, GdmUserAuthFile, NULL);
/* Find out if the Xauthority file passes the paranoia check */
if (automatic_tmp_dir ||
@@ -450,7 +450,7 @@ try_user_add_again:
/* No go. Let's create a fallback file in GdmUserAuthFB (/tmp) */
d->authfb = TRUE;
g_free (d->userauth);
- d->userauth = g_strconcat (GdmUserAuthFB, "/.gdmXXXXXX", NULL);
+ d->userauth = g_build_filename (GdmUserAuthFB, ".gdmXXXXXX", NULL);
authfd = g_mkstemp (d->userauth);
if (authfd == -1) {
diff --git a/daemon/display.c b/daemon/display.c
index aaf5f286..7d4033d6 100644
--- a/daemon/display.c
+++ b/daemon/display.c
@@ -43,6 +43,7 @@ extern gboolean GdmXdmcp;
extern gint xdmcp_sessions;
extern gint flexi_servers;
extern gint xdmcp_pending;
+extern gboolean gdm_in_final_cleanup;
extern GSList *displays;
extern GdmConnection *fifoconn;
extern GdmConnection *pipeconn;
@@ -249,28 +250,12 @@ gdm_display_manage (GdmDisplay *d)
d->slave_notify_fd = fds[0];
- if (d->type == TYPE_LOCAL) {
- gdm_slave_start (d);
- /* if we ever return, bad things are happening */
- gdm_server_stop (d);
- _exit (DISPLAY_ABORT);
- } else if (SERVER_IS_FLEXI (d)) {
- gdm_slave_start (d);
- gdm_server_stop (d);
- /* we expect to return after the session finishes */
- _exit (DISPLAY_REMANAGE);
- } else if (d->type == TYPE_XDMCP &&
- d->dispstat == XDMCP_MANAGED) {
- gdm_slave_start (d);
- gdm_server_stop (d);
- /* we expect to return after the session finishes */
- _exit (DISPLAY_REMANAGE);
- }
+ gdm_slave_start (d);
+ /* should never retern */
- /* yaikes, how did we ever get here, though I suppose
- * it could be possible if XMDCP thing wasn't really set up */
+ /* yaikes, how did we ever get here? */
gdm_server_stop (d);
- _exit (DISPLAY_ABORT);
+ _exit (DISPLAY_REMANAGE);
break;
@@ -327,12 +312,25 @@ gdm_display_unmanage (GdmDisplay *d)
d->name, (int)d->slavepid);
/* Kill slave */
- gdm_sigchld_block_push ();
if (d->slavepid > 1 &&
- kill (d->slavepid, SIGTERM) == 0)
- ve_waitpid_no_signal (d->slavepid, 0, 0);
+ kill (d->slavepid, SIGTERM) == 0) {
+ int ret;
+wait_again:
+ errno = 0;
+ ret = waitpid (d->slavepid, NULL, 0);
+ if (ret < 0 &&
+ errno == EINTR) {
+ /* rekill the slave to tell it to
+ hurry up and die if we're getting
+ killed ourselves */
+ if (ve_signal_was_notified (SIGTERM) ||
+ ve_signal_was_notified (SIGINT)) {
+ kill (d->slavepid, SIGTERM);
+ }
+ goto wait_again;
+ }
+ }
d->slavepid = 0;
- gdm_sigchld_block_pop ();
if (d->type == TYPE_LOCAL)
d->dispstat = DISPLAY_DEAD;
diff --git a/daemon/errorgui.c b/daemon/errorgui.c
index ef5d831f..328f8e6b 100644
--- a/daemon/errorgui.c
+++ b/daemon/errorgui.c
@@ -211,6 +211,10 @@ setup_dialog (GdmDisplay *d, const char *name, int closefdexcept)
openlog ("gdm", LOG_PID, LOG_DAEMON);
+ ve_setenv ("LOGNAME", GdmUser, TRUE);
+ ve_setenv ("USER", GdmUser, TRUE);
+ ve_setenv ("USERNAME", GdmUser, TRUE);
+
ve_setenv ("DISPLAY", d->name, TRUE);
ve_unsetenv ("XAUTHORITY");
diff --git a/daemon/gdm.c b/daemon/gdm.c
index 5615e349..686dec85 100644
--- a/daemon/gdm.c
+++ b/daemon/gdm.c
@@ -101,6 +101,7 @@ gboolean gdm_emergency_server = FALSE;
gboolean gdm_first_login = TRUE;
int gdm_in_signal = 0;
+gboolean gdm_in_final_cleanup = FALSE;
/* Configuration options */
gchar *GdmUser = NULL;
@@ -212,6 +213,51 @@ compare_displays (gconstpointer a, gconstpointer b)
return 0;
}
+static void
+check_servauthdir (struct stat *statbuf)
+{
+ /* Enter paranoia mode */
+ if (stat (GdmServAuthDir, statbuf) == -1) {
+ char *s = g_strdup_printf
+ (_("Server Authorization directory "
+ "(daemon/ServAuthDir) is set to %s "
+ "but this does not exist. Please "
+ "correct gdm configuration %s and "
+ "restart gdm."), GdmServAuthDir,
+ GDM_CONFIG_FILE);
+ gdm_text_message_dialog (s);
+ GdmPidFile = NULL;
+ gdm_fail (_("%s: Authdir %s does not exist. Aborting."), "gdm_config_parse", GdmServAuthDir);
+ }
+
+ if (! S_ISDIR (statbuf->st_mode)) {
+ char *s = g_strdup_printf
+ (_("Server Authorization directory "
+ "(daemon/ServAuthDir) is set to %s "
+ "but this is not a directory. Please "
+ "correct gdm configuration %s and "
+ "restart gdm."), GdmServAuthDir,
+ GDM_CONFIG_FILE);
+ gdm_text_message_dialog (s);
+ GdmPidFile = NULL;
+ gdm_fail (_("%s: Authdir %s is not a directory. Aborting."), "gdm_config_parse", GdmServAuthDir);
+ }
+}
+
+static void
+check_logdir (void)
+{
+ struct stat statbuf;
+
+ if (stat (GdmLogDir, &statbuf) == -1 ||
+ ! S_ISDIR (statbuf.st_mode)) {
+ gdm_error (_("%s: Logdir %s does not exist or isn't a directory. Using ServAuthDir %s."), "gdm_config_parse",
+ GdmLogDir, GdmServAuthDir);
+ g_free (GdmLogDir);
+ GdmLogDir = g_strdup (GdmServAuthDir);
+ }
+}
+
/**
* gdm_config_parse:
*
@@ -400,8 +446,10 @@ gdm_config_parse (void)
gdm_fail (_("%s: No authdir specified."), "gdm_config_parse");
}
- if (ve_string_empty (GdmLogDir))
- GdmLogDir = GdmServAuthDir;
+ if (ve_string_empty (GdmLogDir)) {
+ g_free (GdmLogDir);
+ GdmLogDir = g_strdup (GdmServAuthDir);
+ }
if (ve_string_empty (GdmSessDir))
gdm_error (_("%s: No sessions directory specified."), "gdm_config_parse");
@@ -640,35 +688,23 @@ gdm_config_parse (void)
g_free (bin);
-
/* Enter paranoia mode */
- if (stat (GdmServAuthDir, &statbuf) == -1) {
- char *s = g_strdup_printf
- (_("Server Authorization directory "
- "(daemon/ServAuthDir) is set to %s "
- "but this does not exist. Please "
- "correct gdm configuration %s and "
- "restart gdm."), GdmServAuthDir,
- GDM_CONFIG_FILE);
- gdm_text_message_dialog (s);
- GdmPidFile = NULL;
- gdm_fail (_("%s: Authdir %s does not exist. Aborting."), "gdm_config_parse", GdmServAuthDir);
- }
+ check_servauthdir (&statbuf);
- if (! S_ISDIR (statbuf.st_mode)) {
- char *s = g_strdup_printf
- (_("Server Authorization directory "
- "(daemon/ServAuthDir) is set to %s "
- "but this is not a directory. Please "
- "correct gdm configuration %s and "
- "restart gdm."), GdmServAuthDir,
- GDM_CONFIG_FILE);
- gdm_text_message_dialog (s);
- GdmPidFile = NULL;
- gdm_fail (_("%s: Authdir %s is not a directory. Aborting."), "gdm_config_parse", GdmServAuthDir);
- }
+ seteuid (0);
+ setegid (0);
+
+ /* Now set things up for us as */
+ chown (GdmServAuthDir, 0, GdmGroupId);
+ chmod (GdmServAuthDir, (S_IRWXU|S_IRWXG|S_ISVTX));
+
+ setegid (GdmGroupId);
+ seteuid (GdmUserId);
+
+ /* again paranoid */
+ check_servauthdir (&statbuf);
- if (statbuf.st_uid != GdmUserId || statbuf.st_gid != GdmGroupId) {
+ if (statbuf.st_uid != 0 || statbuf.st_gid != GdmGroupId) {
char *s = g_strdup_printf
(_("Server Authorization directory "
"(daemon/ServAuthDir) is set to %s "
@@ -681,28 +717,30 @@ gdm_config_parse (void)
gdm_text_message_dialog (s);
GdmPidFile = NULL;
gdm_fail (_("%s: Authdir %s is not owned by user %s, group %s. Aborting."), "gdm_config_parse",
- GdmServAuthDir, GdmUser, GdmGroup);
+ GdmServAuthDir, gdm_root_user (), GdmGroup);
}
- if (statbuf.st_mode != (S_IFDIR|S_IRWXU|S_IRGRP|S_IXGRP)) {
+ if (statbuf.st_mode != (S_IFDIR|S_IRWXU|S_IRWXG|S_ISVTX)) {
char *s = g_strdup_printf
(_("Server Authorization directory "
"(daemon/ServAuthDir) is set to %s "
"but has the wrong permissions, it "
- "should have permissions of 0750. "
+ "should have permissions of %o. "
"Please correct the permissions or "
"the gdm configuration %s and "
"restart gdm."),
- GdmServAuthDir, GDM_CONFIG_FILE);
+ GdmServAuthDir, (S_IRWXU|S_IRWXG|S_ISVTX), GDM_CONFIG_FILE);
gdm_text_message_dialog (s);
GdmPidFile = NULL;
- gdm_fail (_("%s: Authdir %s has wrong permissions %o. Should be 0750. Aborting."), "gdm_config_parse",
- GdmServAuthDir, statbuf.st_mode);
+ gdm_fail (_("%s: Authdir %s has wrong permissions %o. Should be %o. Aborting."), "gdm_config_parse",
+ GdmServAuthDir, statbuf.st_mode, (S_IRWXU|S_IRWXG|S_ISVTX));
}
seteuid (0);
setegid (0);
+ check_logdir ();
+
/* Check that user authentication is properly configured */
gdm_verify_check ();
@@ -814,7 +852,7 @@ gdm_final_cleanup (void)
gdm_debug ("gdm_final_cleanup");
- gdm_sigchld_block_push ();
+ gdm_in_final_cleanup = TRUE;
if (extra_process > 1) {
/* we sigterm extra processes, and we
@@ -823,8 +861,6 @@ gdm_final_cleanup (void)
extra_process = 0;
}
- gdm_sigchld_block_pop ();
-
list = g_slist_copy (displays);
for (li = list; li != NULL; li = li->next) {
GdmDisplay *d = li->data;
@@ -1839,11 +1875,9 @@ send_slave_ack (GdmDisplay *d, const char *resp)
g_free (not);
}
}
- gdm_sigchld_block_push ();
if (d->slavepid > 1) {
kill (d->slavepid, SIGUSR2);
}
- gdm_sigchld_block_pop ();
}
static void
@@ -1856,11 +1890,9 @@ send_slave_command (GdmDisplay *d, const char *command)
write (d->master_notify_fd, cmd, strlen (cmd));
g_free (cmd);
}
- gdm_sigchld_block_push ();
if (d->slavepid > 1) {
kill (d->slavepid, SIGUSR2);
}
- gdm_sigchld_block_pop ();
}
@@ -2265,10 +2297,10 @@ gdm_handle_message (GdmConnection *conn, const char *msg, gpointer data)
GSList *li;
for (li = displays; li != NULL; li = li->next) {
GdmDisplay *d = li->data;
- gdm_sigchld_block_push ();
if (d->greetpid > 1)
kill (d->greetpid, SIGHUP);
- gdm_sigchld_block_pop ();
+ else if (d->chooserpid > 1)
+ kill (d->chooserpid, SIGHUP);
}
} else if (strncmp (msg, GDM_SOP_WRITE_X_SERVERS " ",
strlen (GDM_SOP_WRITE_X_SERVERS " ")) == 0) {
@@ -2659,10 +2691,8 @@ notify_displays_int (const char *key, int val)
gdm_fdprintf (disp->master_notify_fd,
"%c%s %d\n",
GDM_SLAVE_NOTIFY_KEY, key, val);
- gdm_sigchld_block_push ();
if (disp->slavepid > 1)
kill (disp->slavepid, SIGUSR2);
- gdm_sigchld_block_pop ();
}
}
}
@@ -2677,10 +2707,8 @@ notify_displays_string (const char *key, const char *val)
gdm_fdprintf (disp->master_notify_fd,
"%c%s %s\n",
GDM_SLAVE_NOTIFY_KEY, key, val);
- gdm_sigchld_block_push ();
if (disp->slavepid > 1)
kill (disp->slavepid, SIGUSR2);
- gdm_sigchld_block_pop ();
}
}
}
diff --git a/daemon/gdm.h b/daemon/gdm.h
index 106e814c..e77a1dba 100644
--- a/daemon/gdm.h
+++ b/daemon/gdm.h
@@ -134,7 +134,7 @@ enum {
#define GDM_KEY_HALT "daemon/HaltCommand=/usr/bin/poweroff;/sbin/poweroff;/sbin/shutdown -h now;/usr/sbin/shutdown -h now"
#define GDM_KEY_INITDIR "daemon/DisplayInitDir=" EXPANDED_SYSCONFDIR "/gdm/Init"
#define GDM_KEY_KILLIC "daemon/KillInitClients=true"
-#define GDM_KEY_LOGDIR "daemon/LogDir=" EXPANDED_AUTHDIR
+#define GDM_KEY_LOGDIR "daemon/LogDir=" EXPANDED_LOGDIR
#define GDM_KEY_PATH "daemon/DefaultPath=/bin:/usr/bin:" X_CONF_PATH ":" EXPANDED_BINDIR
#define GDM_KEY_PIDFILE "daemon/PidFile=/var/run/gdm.pid"
#define GDM_KEY_POSTSESS "daemon/PostSessionScriptDir=" EXPANDED_SYSCONFDIR "/gdm/PostSession/"
diff --git a/daemon/misc.c b/daemon/misc.c
index a72d5b4c..9d7d51f7 100644
--- a/daemon/misc.c
+++ b/daemon/misc.c
@@ -1240,6 +1240,13 @@ static struct sigaction oldterm, oldint, oldhup;
static void
jumpback_sighandler (int signal)
{
+ /* this avoids a race see Note below.
+ We want to jump back only on the first
+ signal invocation, even if the signal
+ handler didn't return. */
+ gboolean old_do_jumpback = do_jumpback;
+ do_jumpback = FALSE;
+
if (signal == SIGINT)
oldint.sa_handler (signal);
else if (signal == SIGTERM)
@@ -1247,13 +1254,24 @@ jumpback_sighandler (int signal)
else if (signal == SIGHUP)
oldint.sa_handler (signal);
/* no others should be set up */
+
+ /* Note that we may not get here since
+ the SIGTERM handler in slave.c
+ might have in fact done the big Longjmp
+ to the slave's death */
- if (do_jumpback) {
- do_jumpback = FALSE;
+ if (old_do_jumpback) {
Longjmp (signal_jumpback, 1);
}
}
+/*
+ * This sets up interruptes to be proxied and the
+ * gethostbyname/addr to be whacked using longjmp,
+ * in case INT/TERM/HUP was gotten in which case
+ * we no longer care for the result of the
+ * resolution.
+ */
#define SETUP_INTERRUPTS_FOR_TERM_DECLS \
struct sigaction term;
diff --git a/daemon/server.c b/daemon/server.c
index 2094746e..7fc834da 100644
--- a/daemon/server.c
+++ b/daemon/server.c
@@ -173,8 +173,12 @@ gdm_server_reinit (GdmDisplay *disp)
gdm_sigchld_block_pop ();
/* a hack we have no way of knowing when the server died */
sleep (1);
+ return;
}
+ /* Do note the interaction of this Setjmp and the signal
+ handlers and the Setjmp in slave.c */
+
if (Setjmp (reinitjmp) == 0) {
/* come here and we'll whack the server and wait to get
an xio error */
@@ -192,6 +196,7 @@ gdm_server_reinit (GdmDisplay *disp)
XCloseDisplay (disp->dsp);
disp->dsp = NULL;
}
+ sleep (1);
Longjmp (reinitjmp, 1);
}
gdm_sigchld_block_pop ();
@@ -218,6 +223,8 @@ gdm_server_reinit (GdmDisplay *disp)
void
gdm_server_stop (GdmDisplay *disp)
{
+ static gboolean waiting_for_server = FALSE;
+
if (disp == NULL)
return;
@@ -242,13 +249,23 @@ gdm_server_stop (GdmDisplay *disp)
/* avoid SIGCHLD race */
gdm_sigchld_block_push ();
-
servpid = disp->servpid;
+
+ if (waiting_for_server) {
+ gdm_error ("gdm_server_stop: Some problem killing server, whacking with SIGKILL");
+ if (disp->servpid > 1)
+ kill (disp->servpid, SIGKILL);
+
+ } else {
+ if (disp->servpid > 1 &&
+ kill (disp->servpid, SIGTERM) == 0) {
+ waiting_for_server = TRUE;
+ ve_waitpid_no_signal (disp->servpid, 0, 0);
+ waiting_for_server = FALSE;
+ }
+ }
disp->servpid = 0;
- if (servpid > 1 &&
- kill (servpid, SIGTERM) == 0)
- ve_waitpid_no_signal (servpid, 0, 0);
gdm_sigchld_block_pop ();
gdm_server_whack_lockfile (disp);
diff --git a/daemon/slave.c b/daemon/slave.c
index 7fc6e0b4..71a4e8ef 100644
--- a/daemon/slave.c
+++ b/daemon/slave.c
@@ -84,8 +84,8 @@ static gboolean gdm_wait_for_ack = TRUE; /* wait for ack on all messages to
* the daemon */
static int in_session_stop = 0;
static int in_usr2_signal = 0;
-static gboolean need_to_abort_after_session_stop = FALSE;
-static gboolean just_abort_on_TERM = FALSE;
+static gboolean need_to_quit_after_session_stop = FALSE;
+static int exit_code_to_use = DISPLAY_REMANAGE;
static gboolean session_started = FALSE;
static gboolean greeter_disabled = FALSE;
static gboolean greeter_no_focus = FALSE;
@@ -196,6 +196,31 @@ static gboolean gdm_got_ack = FALSE;
static char * gdm_ack_response = NULL;
static GList *unhandled_notifies = NULL;
+
+/* for signals that want to exit */
+static Jmp_buf slave_start_jmp;
+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); \
+ } \
+ }
+
/* notify all waitpids, make waitpids check notifies */
static void
slave_waitpid_notify_all (void)
@@ -258,7 +283,13 @@ slave_waitpid (GdmWaitPid *wp)
/* This is a real stupid fallback for a real stupid case */
while (wp->pid > 1) {
- sleep (5);
+ struct timeval tv;
+ /* Wait 5 seconds. */
+ tv.tv_sec = 5;
+ 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 ();
}
check_notifies_now ();
@@ -381,6 +412,45 @@ whack_greeter_fds (void)
greeter_fd_in = -1;
}
+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");
+
+ 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;
+
+ gdm_debug ("term_session_stop_and_quit: Final cleanup");
+
+ gdm_slave_quick_exit (exit_code_to_use);
+}
void
gdm_slave_start (GdmDisplay *display)
@@ -390,11 +460,28 @@ gdm_slave_start (GdmDisplay *display)
static sigset_t mask;
struct sigaction alrm, term, child, usr2;
- if (!display)
- return;
+ if (display == NULL) {
+ /* saaay ... what? */
+ _exit (DISPLAY_REMANAGE);
+ }
gdm_debug ("gdm_slave_start: Starting slave process for %s", display->name);
+ 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);
+ }
+
if (display->type == TYPE_XDMCP &&
GdmPingInterval > 0) {
/* Handle a ALRM signals from our ping alarms */
@@ -466,8 +553,10 @@ gdm_slave_start (GdmDisplay *display)
gdm_slave_run (display);
/* remote and flexi only run once */
- if (display->type != TYPE_LOCAL)
- break;
+ if (display->type != TYPE_LOCAL) {
+ gdm_server_stop (display);
+ gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ }
the_time = time (NULL);
@@ -478,9 +567,7 @@ gdm_slave_start (GdmDisplay *display)
first_time = the_time;
death_count = 0;
} else if (death_count > 6) {
- /* exitting the loop will cause an
- * abort actually */
- break;
+ gdm_slave_quick_exit (DISPLAY_ABORT);
}
gdm_debug ("gdm_slave_start: Reinitializing things");
@@ -494,13 +581,17 @@ gdm_slave_start (GdmDisplay *display)
} else {
/* OK about to start again so rebake our cookies and reinit
* the server */
- if ( ! gdm_auth_secure_display (d))
- break;
+ if ( ! gdm_auth_secure_display (d)) {
+ gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ }
gdm_slave_send_string (GDM_SOP_COOKIE, d->cookie);
gdm_server_reinit (d);
}
}
+ /* very very very evil, should never break, we can't return from
+ here sanely */
+ _exit (DISPLAY_ABORT);
}
static gboolean
@@ -1008,6 +1099,10 @@ gdm_slave_run (GdmDisplay *display)
* so no need to reinit the server nor rebake cookies
* nor such nonsense */
} while (greet);
+
+ /* If XDMCP stop pinging */
+ if (d->type == TYPE_XDMCP)
+ alarm (0);
}
/* A hack really, this will wait around until the first mapped window
@@ -1210,7 +1305,7 @@ run_config (GdmDisplay *display, struct passwd *pwent)
openlog ("gdm", LOG_PID, LOG_DAEMON);
- if (chdir ("/root") != 0)
+ if (chdir (pwent->pw_dir) != 0)
chdir ("/");
/* exec the configurator */
@@ -1607,7 +1702,7 @@ run_pictures (void)
g_free (cfgdir);
if (picfile == NULL) {
- picfile = g_strconcat (pwent->pw_dir, "/.face", NULL);
+ picfile = g_build_filename (pwent->pw_dir, ".face", NULL);
if (access (picfile, R_OK) != 0) {
g_free (picfile);
picfile = NULL;
@@ -1802,7 +1897,7 @@ gdm_slave_greeter (void)
/* Open a pipe for greeter communications */
if (pipe (pipe1) < 0 || pipe (pipe2) < 0)
- gdm_slave_exit (DISPLAY_ABORT, _("%s: Can't init pipe to gdmgreeter"),
+ gdm_slave_exit (DISPLAY_REMANAGE, _("%s: Can't init pipe to gdmgreeter"),
"gdm_slave_greeter");
/* hackish ain't it */
@@ -2018,7 +2113,7 @@ gdm_slave_greeter (void)
case -1:
d->greetpid = 0;
- gdm_slave_exit (DISPLAY_ABORT, _("%s: Can't fork gdmgreeter process"), "gdm_slave_greeter");
+ gdm_slave_exit (DISPLAY_REMANAGE, _("%s: Can't fork gdmgreeter process"), "gdm_slave_greeter");
default:
close (pipe1[0]);
@@ -2067,8 +2162,19 @@ gdm_slave_send (const char *str, gboolean wait_for_ack)
if ( ! gdm_wait_for_ack)
wait_for_ack = FALSE;
- if (gdm_in_signal == 0)
- gdm_debug ("Sending %s", str);
+ /* Evil!, all this for debugging? */
+ if (GdmDebug && gdm_in_signal == 0) {
+ if (strncmp (str, GDM_SOP_COOKIE " ",
+ strlen (GDM_SOP_COOKIE " ")) == 0) {
+ char *s = g_strndup
+ (str, strlen (GDM_SOP_COOKIE " XXXX XX"));
+ /* cut off most of the cookie for "security" */
+ gdm_debug ("Sending %s...", s);
+ g_free (s);
+ } else {
+ gdm_debug ("Sending %s", str);
+ }
+ }
if (wait_for_ack) {
gdm_got_ack = FALSE;
@@ -2084,8 +2190,12 @@ gdm_slave_send (const char *str, gboolean wait_for_ack)
}
if (fd < 0) {
+ /* FIXME: This is not likely to ever be used, remove
+ at some point. Other then slaves shouldn't be using
+ these functions. And if the pipe creation failed
+ in main daemon just abort the main daemon. */
/* Use the fifo as a fallback only now that we have a pipe */
- fifopath = g_strconcat (GdmServAuthDir, "/.gdmfifo", NULL);
+ fifopath = g_build_filename (GdmServAuthDir, ".gdmfifo", NULL);
old = geteuid ();
if (old != 0)
seteuid (0);
@@ -2132,14 +2242,30 @@ gdm_slave_send (const char *str, gboolean wait_for_ack)
gdm_slave_handle_usr2_message ();
}
} else {
- sleep (1);
+ 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 */
}
}
if (wait_for_ack &&
! gdm_got_ack &&
- gdm_in_signal == 0)
- gdm_error ("Timeout occured for sending message %s", str);
+ gdm_in_signal == 0) {
+ if (strncmp (str, GDM_SOP_COOKIE " ",
+ strlen (GDM_SOP_COOKIE " ")) == 0) {
+ char *s = g_strndup
+ (str, strlen (GDM_SOP_COOKIE " XXXX XX"));
+ /* cut off most of the cookie for "security" */
+ gdm_debug ("Timeout occured for sending message %s...", s);
+ g_free (s);
+ } else {
+ gdm_debug ("Timeout occured for sending message %s", str);
+ }
+ }
}
void
@@ -2233,7 +2359,7 @@ gdm_slave_chooser (void)
/* Open a pipe for chooser communications */
if (pipe (p) < 0)
- gdm_slave_exit (DISPLAY_ABORT, _("gdm_slave_chooser: Can't init pipe to gdmchooser"));
+ gdm_slave_exit (DISPLAY_REMANAGE, _("gdm_slave_chooser: Can't init pipe to gdmchooser"));
/* Run the init script. gdmslave suspends until script has terminated */
gdm_slave_exec_script (d, GdmDisplayInit, NULL, NULL,
@@ -2327,7 +2453,7 @@ gdm_slave_chooser (void)
gdm_child_exit (DISPLAY_REMANAGE, _("gdm_slave_chooser: Error starting chooser on display %s"), d->name);
case -1:
- gdm_slave_exit (DISPLAY_ABORT, _("gdm_slave_chooser: Can't fork gdmchooser process"));
+ gdm_slave_exit (DISPLAY_REMANAGE, _("gdm_slave_chooser: Can't fork gdmchooser process"));
default:
gdm_debug ("gdm_slave_chooser: Chooser on pid %d", d->chooserpid);
@@ -2389,7 +2515,7 @@ is_session_ok (const char *session_name)
if (ve_string_empty (GdmSessDir))
return FALSE;
- file = g_strconcat (GdmSessDir, "/", session_name, NULL);
+ file = g_build_filename (GdmSessDir, session_name, NULL);
if (access (file, F_OK) == 0) {
g_free (file);
return TRUE;
@@ -2431,7 +2557,7 @@ get_session_exec (const char *desktop)
VeConfig *cfg;
char *exec;
- file = g_strconcat (GdmSessDir, "/", desktop, NULL);
+ file = g_build_filename (GdmSessDir, desktop, NULL);
cfg = ve_config_get (file);
g_free (file);
exec = ve_config_get_string (cfg, "Desktop Entry/Exec");
@@ -2491,6 +2617,10 @@ session_child_run (struct passwd *pwent,
char *argv[4];
gdm_unset_signals ();
+ if (setsid() < 0)
+ /* should never happen */
+ gdm_error (_("%s: setsid() failed: %s!"),
+ "session_child_run", strerror(errno));
ve_setenv ("XAUTHORITY", GDM_AUTHFILE (d), TRUE);
@@ -2501,9 +2631,9 @@ session_child_run (struct passwd *pwent,
* unless in failsafe mode which needs to work when there is
* no diskspace as well */
if ( ! failsafe && home_dir_ok) {
- char *filename = g_strconcat (home_dir,
- "/.xsession-errors",
- NULL);
+ char *filename = g_build_filename (home_dir,
+ ".xsession-errors",
+ NULL);
uid_t old = geteuid ();
uid_t oldg = getegid ();
@@ -2558,11 +2688,6 @@ session_child_run (struct passwd *pwent,
gdm_clearenv ();
- if (setsid() < 0)
- /* should never happen */
- gdm_error (_("%s: setsid() failed: %s!"),
- "session_child_run", strerror(errno));
-
/* Prepare user session */
ve_setenv ("XAUTHORITY", d->userauth, TRUE);
ve_setenv ("DISPLAY", d->name, TRUE);
@@ -2613,6 +2738,10 @@ session_child_run (struct passwd *pwent,
* not to leave the egid around */
setegid (pwent->pw_gid);
+ if (chdir (home_dir) != 0) {
+ chdir ("/");
+ }
+
#ifdef HAVE_LOGINCAP
if (setusercontext (NULL, pwent, pwent->pw_uid,
LOGIN_SETLOGIN | LOGIN_SETPATH |
@@ -2637,10 +2766,8 @@ session_child_run (struct passwd *pwent,
ve_setenv ("GDM_LANG", language, TRUE);
}
- chdir (home_dir);
-
if (usrcfgok && savesess && home_dir_ok) {
- gchar *cfgstr = g_strconcat (home_dir, "/.dmrc", NULL);
+ gchar *cfgstr = g_build_filename (home_dir, ".dmrc", NULL);
if (dmrc == NULL)
dmrc = ve_config_new (cfgstr);
ve_config_set_string (dmrc, "Desktop/Session",
@@ -2649,7 +2776,7 @@ session_child_run (struct passwd *pwent,
}
if (usrcfgok && savelang && home_dir_ok) {
- gchar *cfgstr = g_strconcat (home_dir, "/.dmrc", NULL);
+ gchar *cfgstr = g_build_filename (home_dir, ".dmrc", NULL);
if (dmrc == NULL)
dmrc = ve_config_new (cfgstr);
if (ve_string_empty (language))
@@ -2857,11 +2984,19 @@ gdm_slave_session_start (void)
}
/* Run the PostLogin script */
- gdm_slave_exec_script (d, GdmPostLogin,
- login, pwent,
- TRUE /* pass_stdout */,
- TRUE /* set_parent */);
- /* FIXME: ignore errors? */
+ if (gdm_slave_exec_script (d, GdmPostLogin,
+ login, pwent,
+ TRUE /* pass_stdout */,
+ TRUE /* set_parent */) != EXIT_SUCCESS &&
+ /* ignore errors in failsafe modes */
+ ! failsafe) {
+ session_started = FALSE;
+ gdm_verify_cleanup (d);
+ gdm_error (_("gdm_slave_session_start: Execution of PostLogin script returned > 0. Aborting."));
+ /* script failed so just try again */
+ return;
+
+ }
if (pwent->pw_dir == NULL ||
! g_file_test (pwent->pw_dir, G_FILE_TEST_IS_DIR)) {
@@ -2909,7 +3044,7 @@ gdm_slave_session_start (void)
}
if (usrcfgok) {
- gchar *cfgfile = g_strconcat (home_dir, "/.dmrc", NULL);
+ gchar *cfgfile = g_build_filename (home_dir, ".dmrc", NULL);
VeConfig *cfg = ve_config_new (cfgfile);
g_free (cfgfile);
@@ -3113,7 +3248,7 @@ gdm_slave_session_start (void)
if ((/* sanity */ end_time >= session_start_time) &&
(end_time - 10 <= session_start_time)) {
- char *errfile = g_strconcat (home_dir, "/.xsession-errors", NULL);
+ char *errfile = g_build_filename (home_dir, ".xsession-errors", NULL);
gdm_debug ("Session less than 10 seconds!");
/* FIXME: perhaps do some checking to display a better error,
@@ -3218,10 +3353,10 @@ gdm_slave_session_stop (gboolean run_post_session,
in_session_stop --;
- if (need_to_abort_after_session_stop) {
+ if (need_to_quit_after_session_stop) {
gdm_debug ("gdm_slave_session_stop: Final cleanup");
- gdm_slave_quick_exit (DISPLAY_ABORT);
+ gdm_slave_quick_exit (exit_code_to_use);
}
#ifdef __linux__
@@ -3235,7 +3370,7 @@ gdm_slave_session_stop (gboolean run_post_session,
up again and then whacked. Waiting is safer then DISPLAY_ABORT,
since if we really do get this wrong, then at the worst case the
user will wait for a few moments. */
- if ( ! need_to_abort_after_session_stop &&
+ if ( ! need_to_quit_after_session_stop &&
! no_shutdown_check &&
access ("/sbin/runlevel", X_OK) == 0) {
char ign;
@@ -3247,15 +3382,19 @@ gdm_slave_session_stop (gboolean run_post_session,
/* this is a stupid loop, but we may be getting signals,
so we don't want to just do sleep (30) */
time_t c = time (NULL);
- just_abort_on_TERM = TRUE;
gdm_info (_("GDM detected a shutdown or reboot "
"in progress."));
fclose (fp);
while (c + 30 > time (NULL)) {
- sleep (5);
+ struct timeval tv;
+ /* Wait 30 seconds. */
+ tv.tv_sec = 30;
+ tv.tv_usec = 0;
+ select (0, NULL, NULL, NULL, &tv);
+ /* don't want to use sleep since we're using alarm
+ for pinging */
}
/* hmm, didn't get TERM, weird */
- just_abort_on_TERM = FALSE;
} else {
fclose (fp);
}
@@ -3268,28 +3407,50 @@ gdm_slave_term_handler (int sig)
{
gdm_in_signal++;
gdm_wait_for_ack = FALSE;
+ static gboolean got_term_before = FALSE;
gdm_debug ("gdm_slave_term_handler: %s got TERM/INT signal", d->name);
- if ( ! just_abort_on_TERM) {
- /* this should stop some races */
- if (in_session_stop > 0 && ! need_to_abort_after_session_stop) {
- gdm_in_signal--;
- gdm_wait_for_ack = TRUE;
- need_to_abort_after_session_stop = TRUE;
- return;
- }
+ exit_code_to_use = DISPLAY_ABORT;
+ need_to_quit_after_session_stop = TRUE;
+
+ if (already_in_slave_start_jmp ||
+ (got_term_before && in_session_stop > 0)) {
+ gdm_sigchld_block_push ();
+ /* be very very very nasty to the extra process if the user is really
+ trying to get rid of us */
+ if (extra_process > 1)
+ kill (-(extra_process), SIGKILL);
+ /* also be very nasty to the X server at this stage */
+ if (d->servpid > 1)
+ kill (d->servpid, SIGKILL);
+ gdm_sigchld_block_pop ();
+ gdm_in_signal--;
+ got_term_before = TRUE;
+ /* we're already quitting, just a matter of killing all the processes */
+ return;
+ }
+ got_term_before = TRUE;
- /* 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 */);
+ /* just in case this was set to something else, like during
+ * server reinit */
+ XSetIOErrorHandler (gdm_slave_xioerror_handler);
+
+ if (in_session_stop > 0) {
+ /* the need_to_quit_after_session_stop is now set so things will
+ work out right */
+ gdm_in_signal--;
+ return;
}
- gdm_debug ("gdm_slave_term_handler: Final cleanup");
+ if (session_started) {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_SESSION_STOP_AND_QUIT);
+ } else {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ }
- gdm_slave_quick_exit (DISPLAY_ABORT);
+ /* never reached */
+ gdm_in_signal--;
}
/* called on alarms to ping */
@@ -3298,6 +3459,9 @@ gdm_slave_alrm_handler (int sig)
{
static gboolean in_ping = FALSE;
+ if (already_in_slave_start_jmp)
+ return;
+
gdm_in_signal++;
gdm_debug ("gdm_slave_alrm_handler: %s got ARLM signal, "
@@ -3310,13 +3474,17 @@ gdm_slave_alrm_handler (int sig)
}
if (in_ping) {
- /* darn, the last ping didn't succeed, wipe this display */
- gdm_slave_session_stop (d->logged_in && login != NULL,
- FALSE /* no_shutdown_check */);
-
- gdm_slave_exit (DISPLAY_REMANAGE,
- _("Ping to %s failed, whacking display!"),
- d->name);
+ slave_start_jmp_error_to_print =
+ g_strdup_printf (_("Ping to %s failed, whacking display!"),
+ d->name);
+ need_to_quit_after_session_stop = TRUE;
+ exit_code_to_use = DISPLAY_REMANAGE;
+
+ if (session_started) {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_SESSION_STOP_AND_QUIT);
+ } else {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ }
}
in_ping = TRUE;
@@ -3339,6 +3507,9 @@ gdm_slave_child_handler (int sig)
pid_t pid;
uid_t old;
+ if (already_in_slave_start_jmp)
+ return;
+
gdm_in_signal++;
gdm_debug ("gdm_slave_child_handler");
@@ -3372,7 +3543,9 @@ gdm_slave_child_handler (int sig)
if (pid == d->greetpid && greet) {
if (WIFEXITED (status) &&
WEXITSTATUS (status) == DISPLAY_RESTARTGREETER) {
- gdm_slave_desensitize_config ();
+ /* FIXME: shouldn't do this from
+ a signal handler */
+ /*gdm_slave_desensitize_config ();*/
greet = FALSE;
d->greetpid = 0;
@@ -3401,16 +3574,19 @@ gdm_slave_child_handler (int sig)
WEXITSTATUS (status) == DISPLAY_SUSPEND ||
WEXITSTATUS (status) == DISPLAY_RUN_CHOOSER ||
WEXITSTATUS (status) == DISPLAY_RESTARTGDM)) {
- gdm_slave_quick_exit (WEXITSTATUS (status));
+ exit_code_to_use = WEXITSTATUS (status);
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
} else {
if (WIFSIGNALED (status) &&
(WTERMSIG (status) == SIGSEGV ||
WTERMSIG (status) == SIGABRT ||
WTERMSIG (status) == SIGPIPE ||
WTERMSIG (status) == SIGBUS)) {
- gdm_slave_quick_exit (DISPLAY_GREETERFAILED);
+ exit_code_to_use = DISPLAY_GREETERFAILED;
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
} else {
- gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ exit_code_to_use = DISPLAY_REMANAGE;
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
}
}
} else if (pid != 0 && pid == d->sesspid) {
@@ -3426,8 +3602,10 @@ gdm_slave_child_handler (int sig)
/* if not handled there is no need for further formalities,
* we just have to die */
- if ( ! d->handled)
- gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ if ( ! d->handled) {
+ exit_code_to_use = DISPLAY_REMANAGE;
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ }
gdm_slave_send_num (GDM_SOP_XPID, 0);
@@ -3506,7 +3684,13 @@ gdm_slave_handle_usr2_message (void)
if (d->type != TYPE_FLEXI_XNEST &&
d->type != TYPE_FLEXI) {
if ( ! d->logged_in) {
- gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ if (gdm_in_signal > 0) {
+ exit_code_to_use = DISPLAY_REMANAGE;
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ } else {
+ /* FIXME: are we ever not in signal here? */
+ gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ }
} else {
remanage_asap = TRUE;
}
@@ -3544,28 +3728,40 @@ gdm_slave_xerror_handler (Display *disp, XErrorEvent *evt)
static gint
gdm_slave_xioerror_handler (Display *disp)
{
+ if (already_in_slave_start_jmp) {
+ /* eki eki eki, this is not good,
+ should only happen if we get some io error after
+ we have gotten a SIGTERM */
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ }
+
gdm_in_signal++;
/* Display is all gone */
d->dsp = NULL;
- gdm_debug ("gdm_slave_xioerror_handler: I/O error for display %s", d->name);
-
- gdm_slave_session_stop (d->logged_in && login != NULL,
- FALSE /* no_shutdown_check */);
-
- gdm_error (_("%s: Fatal X error - Restarting %s"),
- "gdm_slave_xioerror_handler", d->name);
-
if ((d->type == TYPE_LOCAL ||
d->type == TYPE_FLEXI) &&
(do_xfailed_on_xio_error ||
d->starttime + 5 >= time (NULL))) {
- gdm_slave_quick_exit (DISPLAY_XFAILED);
+ exit_code_to_use = DISPLAY_XFAILED;
} else {
- gdm_slave_quick_exit (DISPLAY_REMANAGE);
+ exit_code_to_use = DISPLAY_REMANAGE;
}
+ slave_start_jmp_error_to_print =
+ g_strdup_printf (_("%s: Fatal X error - Restarting %s"),
+ "gdm_slave_xioerror_handler", d->name);
+
+ need_to_quit_after_session_stop = TRUE;
+
+ if (session_started) {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_SESSION_STOP_AND_QUIT);
+ } else {
+ SIGNAL_EXIT_WITH_JMP (d, JMP_JUST_QUIT_QUICKLY);
+ }
+
+ /* never reached */
gdm_in_signal--;
return 0;
@@ -3694,6 +3890,10 @@ gdm_slave_quick_exit (gint status)
* so no need doing XCloseDisplay which
* may just get us an XIOError */
d->dsp = NULL;
+ /* just in case we do get the XIOError,
+ don't run session_stop since we've
+ requested a quick exit */
+ session_started = FALSE;
/* No need to send the PIDS to the daemon
* since we'll just exit cleanly */
@@ -3714,13 +3914,13 @@ gdm_slave_quick_exit (gint status)
kill (-(d->sesspid), SIGTERM);
d->sesspid = 0;
- gdm_server_stop (d);
- gdm_verify_cleanup (d);
-
if (extra_process > 1)
kill (-(extra_process), SIGTERM);
extra_process = 0;
+ gdm_verify_cleanup (d);
+ gdm_server_stop (d);
+
if (d->servpid > 1)
kill (d->servpid, SIGTERM);
d->servpid = 0;
@@ -3822,14 +4022,14 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login,
if (!d || ve_string_empty (dir))
return EXIT_SUCCESS;
- script = g_strconcat (dir, "/", d->name, NULL);
+ script = g_build_filename (dir, d->name, NULL);
if (access (script, R_OK|X_OK) != 0) {
g_free (script);
script = NULL;
}
if (script == NULL &&
! ve_string_empty (d->hostname)) {
- script = g_strconcat (dir, "/", d->hostname, NULL);
+ script = g_build_filename (dir, d->hostname, NULL);
if (access (script, R_OK|X_OK) != 0) {
g_free (script);
script = NULL;
@@ -3837,7 +4037,7 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login,
}
if (script == NULL &&
d->type == TYPE_XDMCP) {
- script = g_strconcat (dir, "/XDMCP", NULL);
+ script = g_build_filename (dir, "XDMCP", NULL);
if (access (script, R_OK|X_OK) != 0) {
g_free (script);
script = NULL;
@@ -3845,14 +4045,14 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login,
}
if (script == NULL &&
SERVER_IS_FLEXI (d)) {
- script = g_strconcat (dir, "/Flexi", NULL);
+ script = g_build_filename (dir, "Flexi", NULL);
if (access (script, R_OK|X_OK) != 0) {
g_free (script);
script = NULL;
}
}
if (script == NULL) {
- script = g_strconcat (dir, "/Default", NULL);
+ script = g_build_filename (dir, "Default", NULL);
if (access (script, R_OK|X_OK) != 0) {
g_free (script);
script = NULL;
@@ -3906,7 +4106,10 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login,
} else {
ve_setenv ("HOME", pwent->pw_dir, TRUE);
ve_setenv ("PWD", pwent->pw_dir, TRUE);
- chdir (pwent->pw_dir);
+ if (chdir (pwent->pw_dir) != 0) {
+ chdir ("/");
+ ve_setenv ("PWD", "/", TRUE);
+ }
}
ve_setenv ("SHELL", pwent->pw_shell, TRUE);
} else {
diff --git a/daemon/verify-pam.c b/daemon/verify-pam.c
index e0900de1..0446f5e5 100644
--- a/daemon/verify-pam.c
+++ b/daemon/verify-pam.c
@@ -122,10 +122,13 @@ gdm_verify_pam_conv (int num_msg, const struct pam_message **msg,
char *s;
struct pam_response *reply = NULL;
const char *login;
+
+ if (pamh == NULL)
+ return PAM_CONV_ERR;
reply = malloc (sizeof (struct pam_response) * num_msg);
- if (!reply)
+ if (reply == NULL)
return PAM_CONV_ERR;
memset (reply, 0, sizeof (struct pam_response) * num_msg);
@@ -261,9 +264,12 @@ gdm_verify_standalone_pam_conv (int num_msg, const struct pam_message **msg,
char *s, *text;
struct pam_response *reply = NULL;
+ if (pamh == NULL)
+ return PAM_CONV_ERR;
+
reply = malloc (sizeof (struct pam_response) * num_msg);
- if (!reply)
+ if (reply == NULL)
return PAM_CONV_ERR;
memset (reply, 0, sizeof (struct pam_response) * num_msg);
@@ -894,16 +900,22 @@ gdm_verify_cleanup (GdmDisplay *d)
if (pamh != NULL) {
gint pamerr;
+ pam_handle_t *tmp_pamh;
+
+ gdm_debug ("Running gdm_verify_cleanup and pamh != NULL");
+
+ gdm_sigterm_block_push ();
+ tmp_pamh = pamh;
+ pamh = NULL;
+ gdm_sigterm_block_pop ();
/* Close the users session */
- pamerr = pam_close_session (pamh, 0);
+ pamerr = pam_close_session (tmp_pamh, 0);
/* Throw away the credentials */
- pamerr = pam_setcred (pamh, PAM_DELETE_CRED);
+ pamerr = pam_setcred (tmp_pamh, PAM_DELETE_CRED);
- if (pamh != NULL)
- pam_end (pamh, pamerr);
- pamh = NULL;
+ pam_end (tmp_pamh, pamerr);
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
closelog ();
diff --git a/docs/C/gdm.xml b/docs/C/gdm.xml
index 87629758..80d5841d 100644
--- a/docs/C/gdm.xml
+++ b/docs/C/gdm.xml
@@ -574,7 +574,9 @@
if you need to (though you should use the
<filename>pam_mount</filename> module if you can for this).
You have the $USER and $DISPLAY environment variables set for this script,
- and again it is run as root.
+ and again it is run as root. The script should return 0 on success
+ as otherwise the user won't be logged in. This is not true for
+ failsafe session showever.
</para>
<para>
@@ -585,9 +587,9 @@
script for local session management or accounting stuff. The
$USER environment variable contains the login of the
authenticated user and $DISPLAY is set to the current display.
- The script should return 0 on success. Any
+ The script should return 0 on success. Any
other value will cause GDM to terminate the current login
- process.
+ process. This is not true for failsafe sessions however.
Also $X_SERVERS environmental variable is set and this points
to a fake generated x servers file for use with the
sessreg accounting program.
@@ -1014,7 +1016,7 @@
<synopsis>RootPath=/sbin:/usr/sbin:/bin:/usr/bin:/usr/bin/X11:/usr/local/bin</synopsis>
<para>
Specifies the path which will be set in the root's
- session and the {Init,PreSession,PostSession} scripts
+ session and the {Init,PostLogin,PreSession,PostSession} scripts
executed by GDM.
</para>
</listitem>
@@ -1027,11 +1029,20 @@
<para>
Directory containing the X authentication files for the
individual displays. Should be owned by
- <filename>gdm.gdm</filename> with permissions 750.
+ <filename>root.gdm</filename> with permissions 1770.
+ That is should be owned by root, with gdm group having
+ full write permissions and the directory should be
+ sticky and others should have no permission to the directory.
+ This way the gdm user can't remove files owned
+ by root in that directory, while still being able to
+ write its own files there. GDM will attempt to change
+ permissions for you when it's first run if the permissions
+ are not the above.
This directory is also used for other private files that
- the daemon needs to store. Other user should not
+ the daemon needs to store. Other users should not
have any way to get into this directory and read/change
- it's contents.
+ it's contents. Anybody who can read this directory can
+ connect to any display on this machine.
</para>
</listitem>
</varlistentry>
diff --git a/gdm.spec.in b/gdm.spec.in
index a770ce6a..20623e77 100644
--- a/gdm.spec.in
+++ b/gdm.spec.in
@@ -134,7 +134,8 @@ exit 0
# %{_datadir}/pixmaps/*
# %{_datadir}/gnome/help/gdm/*
# %{_datadir}/gnome/help/gdmsetup/*
-%attr(750, gdm, gdm) %dir %{localstatedir}/gdm
+%attr(1770, root, gdm) %dir %{localstatedir}/gdm
+%attr(755, root, root) %dir %{localstatedir}/log/gdm
%changelog
diff --git a/gui/gdmchooser.c b/gui/gdmchooser.c
index 6681c297..aa71495b 100644
--- a/gui/gdmchooser.c
+++ b/gui/gdmchooser.c
@@ -83,6 +83,7 @@ static gint connection_type = 0;
static void gdm_chooser_abort (const gchar *format, ...) G_GNUC_PRINTF (1, 2);
static void gdm_chooser_warn (const gchar *format, ...) G_GNUC_PRINTF (1, 2);
+static void set_background (void);
/* Exported for glade */
void gdm_chooser_cancel (void);
@@ -112,6 +113,10 @@ static guint scan_time_handler = 0;
static int ping_tries = PING_TRIES;
static guint ping_try_handler = 0;
+/* set in the main function */
+static char **stored_argv = NULL;
+static int stored_argc = 0;
+
/* Fixetyfix */
int XdmcpReallocARRAY8 (ARRAY8Ptr array, int length);
@@ -142,6 +147,7 @@ static gchar *GdmHostIconDir;
static gchar *GdmHostDefaultIcon;
static gchar *GdmGtkRC;
static gchar *GdmHosts;
+static gchar *GdmHostsOrig;
static gboolean GdmBroadcast;
static gboolean GdmAllowAdd;
static gchar *GdmBackgroundColor;
@@ -1055,6 +1061,7 @@ gdm_chooser_parse_config (void)
/* note that command line arguments will prevail over these */
GdmHosts = ve_config_get_string (cfg, GDM_KEY_HOSTS);
+ GdmHostsOrig = g_strdup (GdmHosts);
GdmBroadcast = ve_config_get_bool (cfg, GDM_KEY_BROADCAST);
/* if broadcasting, then append BROADCAST to hosts */
if (GdmBroadcast) {
@@ -1250,24 +1257,111 @@ gdm_chooser_gui_init (void)
}
}
+static gboolean
+string_same (VeConfig *config, const char *cur, const char *key)
+{
+ char *val = ve_config_get_string (config, key);
+ if (strcmp (ve_sure_string (cur), ve_sure_string (val)) == 0) {
+ g_free (val);
+ return TRUE;
+ } else {
+ g_free (val);
+ return FALSE;
+ }
+}
+
+static gboolean
+bool_same (VeConfig *config, gboolean cur, const char *key)
+{
+ gboolean val = ve_config_get_bool (config, key);
+ if (ve_bool_equal (cur, val)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static gboolean
+int_same (VeConfig *config, int cur, const char *key)
+{
+ int val = ve_config_get_int (config, key);
+ if (cur == val) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+static gboolean
+gdm_reread_config (int sig, gpointer data)
+{
+ VeConfig *config;
+ /* reparse config stuff here. At least ones we care about */
+
+ config = ve_config_get (GDM_CONFIG_FILE);
+
+ /* FIXME: The following is evil, we should update on the fly rather
+ * then just restarting */
+ /* Also we may not need to check ALL those keys but just a few */
+ if ( ! string_same (config, GdmHostsOrig, GDM_KEY_HOSTS) ||
+ ! string_same (config, GdmGtkRC, GDM_KEY_GTKRC) ||
+ ! string_same (config, GdmHostDefaultIcon, GDM_KEY_HOST) ||
+ ! string_same (config, GdmHostIconDir, GDM_KEY_HOSTDIR) ||
+ ! int_same (config,
+ GdmXineramaScreen, GDM_KEY_XINERAMASCREEN) ||
+ ! int_same (config, GdmIconMaxWidth, GDM_KEY_ICONWIDTH) ||
+ ! int_same (config, GdmIconMaxHeight, GDM_KEY_ICONHEIGHT) ||
+ ! int_same (config, GdmScanTime, GDM_KEY_SCAN) ||
+ ! bool_same (config, GdmDebug, GDM_KEY_DEBUG)) {
+ if (RUNNING_UNDER_GDM) {
+ /* Set busy cursor */
+ setup_cursor (GDK_WATCH);
+
+ gdm_wm_save_wm_order ();
+ }
+
+ /* we don't need to tell the slave that we're restarting
+ it doesn't care about our state. Unlike with the greeter */
+ execvp (stored_argv[0], stored_argv);
+ _exit (DISPLAY_REMANAGE);
+ }
+
+ /* we only use the color and do it for all types except NONE */
+ if ( ! string_same (config, GdmBackgroundColor, GDM_KEY_BACKGROUNDCOLOR) ||
+ ! int_same (config, GdmBackgroundType, GDM_KEY_BACKGROUNDTYPE)) {
+ set_background ();
+ }
+
+ return TRUE;
+}
+
static void
gdm_chooser_signals_init (void)
{
struct sigaction hup;
+ struct sigaction term;
sigset_t mask;
- hup.sa_handler = (void *) gdm_chooser_cancel;
+ ve_signal_add (SIGHUP, gdm_reread_config, NULL);
+
+ hup.sa_handler = ve_signal_notify;
hup.sa_flags = 0;
- sigemptyset (&hup.sa_mask);
+ sigemptyset(&hup.sa_mask);
+ sigaddset (&hup.sa_mask, SIGCHLD);
+
+ term.sa_handler = (void *) gdm_chooser_cancel;
+ term.sa_flags = 0;
+ sigemptyset (&term.sa_mask);
if (sigaction (SIGHUP, &hup, NULL) < 0)
gdm_chooser_abort (_("gdm_signals_init: Error setting up HUP signal handler"));
- if (sigaction (SIGINT, &hup, NULL) < 0)
+ if (sigaction (SIGINT, &term, NULL) < 0)
gdm_chooser_abort (_("gdm_signals_init: Error setting up INT signal handler"));
- if (sigaction (SIGTERM, &hup, NULL) < 0)
+ if (sigaction (SIGTERM, &term, NULL) < 0)
gdm_chooser_abort (_("gdm_signals_init: Error setting up TERM signal handler"));
sigfillset (&mask);
@@ -1358,6 +1452,13 @@ main (int argc, char *argv[])
poptContext ctx;
int nextopt;
const char *gdm_version;
+ int i;
+
+ stored_argv = g_new0 (char *, argc + 1);
+ for (i = 0; i < argc; i++)
+ stored_argv[i] = g_strdup (argv[i]);
+ stored_argv[i] = NULL;
+ stored_argc = argc;
if (g_getenv ("RUNNING_UNDER_GDM") != NULL)
RUNNING_UNDER_GDM = TRUE;
@@ -1472,14 +1573,16 @@ main (int argc, char *argv[])
gdm_wm_focus_window (GDK_WINDOW_XWINDOW (chooser->window));
}
- if (RUNNING_UNDER_GDM)
- setup_cursor (GDK_LEFT_PTR);
-
if (GdmAllowAdd)
gtk_widget_grab_focus (add_entry);
gdm_chooser_add_entry_changed ();
+ if (RUNNING_UNDER_GDM) {
+ gdm_wm_restore_wm_order ();
+ setup_cursor (GDK_LEFT_PTR);
+ }
+
gtk_main();
exit (EXIT_SUCCESS);
diff --git a/gui/gdmlogin.c b/gui/gdmlogin.c
index e93277a0..b3423f78 100644
--- a/gui/gdmlogin.c
+++ b/gui/gdmlogin.c
@@ -2177,7 +2177,18 @@ gdm_login_browser_populate (void)
for (li = users; li != NULL; li = li->next) {
GdmLoginUser *usr = li->data;
GtkTreeIter iter = {0};
- char *label = g_strdup_printf ("%s\n%s", usr->login, usr->gecos);
+ char *label;
+ char *login, *gecos;
+
+ login = g_markup_escape_text (usr->login, -1);
+ gecos = g_markup_escape_text (usr->gecos, -1);
+
+ label = g_strdup_printf ("<b>%s</b>\n%s",
+ login,
+ gecos);
+
+ g_free (login);
+ g_free (gecos);
gtk_list_store_append (GTK_LIST_STORE (browser_model), &iter);
gtk_list_store_set (GTK_LIST_STORE (browser_model), &iter,
GREETER_ULIST_ICON_COLUMN, usr->picture,
@@ -2746,7 +2757,7 @@ gdm_login_gui_init (void)
column = gtk_tree_view_column_new_with_attributes
(_("Username"),
gtk_cell_renderer_text_new (),
- "text", GREETER_ULIST_LABEL_COLUMN,
+ "markup", GREETER_ULIST_LABEL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (browser), column);
diff --git a/gui/greeter/greeter_item_ulist.c b/gui/greeter/greeter_item_ulist.c
index 12b08dbb..d0225471 100644
--- a/gui/greeter/greeter_item_ulist.c
+++ b/gui/greeter/greeter_item_ulist.c
@@ -298,7 +298,18 @@ greeter_populate_user_list (GtkTreeModel *tm)
{
GdmGreeterUser *usr = li->data;
GtkTreeIter iter = {0};
- char *label = g_strdup_printf ("%s\n%s", usr->login, usr->gecos);
+ char *label;
+ char *login, *gecos;
+
+ login = g_markup_escape_text (usr->login, -1);
+ gecos = g_markup_escape_text (usr->gecos, -1);
+
+ label = g_strdup_printf ("<b>%s</b>\n%s",
+ login,
+ gecos);
+
+ g_free (login);
+ g_free (gecos);
gtk_list_store_append (GTK_LIST_STORE (tm), &iter);
gtk_list_store_set (GTK_LIST_STORE (tm), &iter,
GREETER_ULIST_ICON_COLUMN, usr->picture,
@@ -402,7 +413,7 @@ greeter_generate_userlist (GtkWidget *tv)
column = gtk_tree_view_column_new_with_attributes
(_("Username"),
gtk_cell_renderer_text_new (),
- "text", GREETER_ULIST_LABEL_COLUMN,
+ "markup", GREETER_ULIST_LABEL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column);