diff options
-rw-r--r-- | ChangeLog | 44 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rwxr-xr-x | config/XKeepsCrashing | 75 | ||||
-rw-r--r-- | configure.in | 17 | ||||
-rw-r--r-- | daemon/gdm.c | 72 | ||||
-rw-r--r-- | daemon/gdm.h | 2 | ||||
-rw-r--r-- | daemon/misc.c | 192 | ||||
-rw-r--r-- | daemon/misc.h | 4 | ||||
-rw-r--r-- | daemon/server.c | 88 | ||||
-rw-r--r-- | daemon/server.h | 1 | ||||
-rw-r--r-- | daemon/slave.c | 40 | ||||
-rw-r--r-- | daemon/verify-crypt.c | 3 | ||||
-rw-r--r-- | daemon/verify-pam.c | 3 | ||||
-rw-r--r-- | daemon/verify-shadow.c | 3 | ||||
-rw-r--r-- | daemon/xdmcp.c | 2 | ||||
-rw-r--r-- | gdm.spec.in | 1 | ||||
-rw-r--r-- | gui/gdmflexiserver.desktop.in | 1 | ||||
-rw-r--r-- | utils/.cvsignore | 6 | ||||
-rw-r--r-- | utils/Makefile.am | 41 | ||||
-rw-r--r-- | utils/gdmaskpass.c | 58 | ||||
-rw-r--r-- | utils/gdmopen.c | 201 |
22 files changed, 736 insertions, 126 deletions
@@ -1,3 +1,47 @@ +Wed Aug 22 23:01:59 2001 George Lebl <jirka@5z.com> + + * configure.in, Makefile.am, utils/gdmopen.c, utils/gdmaskpass.c: + Add two new small sbin utils. gdmopen is like open (based on it) + but better suited for gdm. Exitcode is returned so no temp files + are needed. Process is cleaned up on a signal, the new vt is + deallocated after use. And unlike openvt this thing actually waits + for the child. Gdmaskpass just asks for the root password, for + use in the XKeepsCrashing script. Both of these things will only + run as root as I'm too paranoid and it doesn't make sense for + them to run otherwise for gdm anyway. + + * configure.in: Fix sbin expansion. + + * daemon/gdm.c, daemon/misc.[ch], daemon/slave.c, daemon/server.c: + Use gdmopen to run dialog and add helper functions for doing this. + + * daemon/gdm.h, daemon/slave.c, daemon/server.[ch]: When a server is + busy, ask the user if we want to run it on a new display number + or retry. + + * daemon/gdm.c, daemon/misc.c, daemon/slave.c: Make sure to whack + any extra helper processes we launch when we are killed so that + we don't leave things like 'dialog' processes around + + * daemon/gdm.c, config/XKeepsCrashing: Use gdmaskpass, ask if + the user wants to view X logs if X is crashing. And use gdmopen + in the script and correctly abort with exit 32. Also make it + not use the ugly tempfile stuff (Though a tempfile is still given + to the script for now) + + * gdm.spec.in: raise epoch to 1, people abuse this field, and if they + do abuse it again and raise it beyond 1, I'll just max it out since + it makes package upgrading not work. + + * daemon/slave.c, daemon/verify-(pam|crypt|shadow).c: add + /sbin/nologin as a thing to test for for disabled logins in + addition to /bin/false and /bin/true (it worked, but this adds a + nicer message) + + * daemon/xdmcp.c: fix a warning. + + * gui/gdmflexiserver.desktop.in: kill TryExec here + Tue Aug 21 04:42:05 2001 George Lebl <jirka@5z.com> * gui/gdmconfig.[ch]: Finish the editting of the server definitions. diff --git a/Makefile.am b/Makefile.am index f8d3dc0c..9ca0b6b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ SUBDIRS = config macros pixmaps intl vicious-extensions \ - daemon gui docs omf-install po + daemon gui utils docs omf-install po EXTRA_DIST = \ ChangeLog \ @@ -17,15 +17,11 @@ xsri like logo functionality the photosetup proggie should be put into some sort of crapplet and there should be other settings in the crapplet as well. -Added configs, do docs and gdmconfig stuff: +Added configs, do docs: daemon/StandardXServer daemon/FlexibleXServers daemon/Xnest -On busy server start up local server on a free display optionaly - -investigate doc building stuff - handle all the XFree86 Xserver error thingies, such as No "Display" subsection for etc... diff --git a/config/XKeepsCrashing b/config/XKeepsCrashing index 98a128af..44f615d6 100755 --- a/config/XKeepsCrashing +++ b/config/XKeepsCrashing @@ -12,68 +12,89 @@ # The second argument is a temporary file we can use # # $3 = 'Your X server is b0rk I will disable this server' -# $4 = 'Your X server is b0rk would you like to try to reconfigure it?" +# $4 = 'Would you like to try to reconfigure your server?" # $5 = 'Please type in the root password' # $6 = 'I will now restart the X server again' # $7 = 'I will disable this X server' +# $8 = 'Your X server is b0rk, do ya wanna view X logs?' + +# there are some env vars defined: +# XLOG = the log file for the X server +# BINDIR = location of gdm binaries +# SBINDIR = location of gdm system binaries + +# return values are +# 0 = try again, runs this server again +# 1 = abort this display, removes this server from the list +# 32 = something went very wrong, things will just get logged. +# this means this script didn't work so do alternative things +# to tell the user if possible + +# we require "gdmopen", to open a console, because we really don't +# have one. Perhaps someone should try to figure out some shell +# black magic to get this to work on other then linux systems +if test ! -x $SBINDIR/gdmopen ; then + exit 32 +fi # when we run ourselves from the open we will pass a -noopen argument if test x$1 = x-noopen ; then - shift + shift else - TEMPFILE="$2" - # we require "open", to open a console, because we really don't - # have one. Perhaps someone should try to figure out some shell - # black magic to get this to work on other then linux systems - if test -x /usr/bin/open ; then - /usr/bin/open -s -w -- $0 -noopen "$@" - if grep TRYAGAIN "$TEMPFILE" >/dev/null ; then - exit 0 - else - exit 1 - fi - else - exit 1 - fi + $SBINDIR/gdmopen $0 -noopen "$@" + exit $? fi SETUP=`which $1` -TEMPFILE="$2" DIALOG=`which dialog` if test x$DIALOG = x ; then - DIALOG=`which gdialog` + DIALOG=`which gdialog` +fi +if test -x $SBINDIR/gdmaskpass ; then + ASKPASS=$SBINDIR/gdmaskpass +else + ASKPASS= fi clear # Note, dialog required, though this script could be fixed to not require it # I suppose -if test x = x$SETUP -o x = x$DIALOG -o x = x$TEMPFILE ; then +if test x = x$SETUP -o x = x$DIALOG ; then + echo ======================================================================= + echo + cat $XLOG + echo echo ======================================================================= echo echo "$3" echo echo ======================================================================= read - if test x != x$TEMPFILE ; then - echo ABORT > $TEMPFILE - fi exit 1 fi +if $DIALOG --yesno "$8" 10 50 ; then + $DIALOG --textbox $XLOG 22 76 +fi + if $DIALOG --yesno "$4" 10 50 ; then clear echo echo "$5" - # dirty trick to fool su into asking the root password even if we're - # root - su nobody -c "su -c $SETUP" + if test x$ASKPASS = x ; then + # dirty trick to fool su into asking the root password even if we're + # root + su nobody -c "su -c $SETUP" + else + if $ASKPASS ; then + $SETUP + fi + fi clear $DIALOG --msgbox "$6" 8 50 - echo TRYAGAIN > $TEMPFILE exit 0 else $DIALOG --msgbox "$7" 8 50 - echo ABORT > $TEMPFILE exit 1 fi diff --git a/configure.in b/configure.in index 8c7cff98..7c5f8c86 100644 --- a/configure.in +++ b/configure.in @@ -193,6 +193,13 @@ fi AC_MSG_CHECKING("for corrupt government") AC_MSG_RESULT(yes) +dnl ## gdmopen building +dnl There are perhaps others where this works +GDMOPEN= +AC_CHECK_HEADERS(linux/vt.h, [ + GDMOPEN=gdmopen]) +AC_SUBST(GDMOPEN) + dnl ## Autentication scheme have_pam=no VRFY="verify-crypt" @@ -205,6 +212,13 @@ if test x$enable_authentication_scheme != xcrypt -a \ AC_DEFINE(HAVE_PAM)]) fi +GDMASKPASS= +if test x$have_pam = xyes ; then + AC_CHECK_HEADERS(security/pam_misc.h, [ + GDMASKPASS=gdmaskpass]) +fi +AC_SUBST(GDMASKPASS) + if test x$enable_authentication_scheme = xpam -a x$have_pam = xno ; then AC_MSG_ERROR(PAM support requested but not available) fi @@ -327,7 +341,7 @@ EXPANDED_BINDIR=`eval echo $BINDIR_TMP` AC_SUBST(EXPANDED_BINDIR) AC_DEFINE_UNQUOTED(EXPANDED_BINDIR,"$EXPANDED_BINDIR") -SBINDIR_TMP="$bindir" +SBINDIR_TMP="$sbindir" EXPANDED_SBINDIR=`eval echo $SBINDIR_TMP` AC_SUBST(EXPANDED_SBINDIR) AC_DEFINE_UNQUOTED(EXPANDED_SBINDIR,"$EXPANDED_SBINDIR") @@ -382,6 +396,7 @@ AC_OUTPUT([ Makefile daemon/Makefile gui/Makefile +utils/Makefile pixmaps/Makefile macros/Makefile config/Makefile diff --git a/daemon/gdm.c b/daemon/gdm.c index 97c1338e..ae8fb903 100644 --- a/daemon/gdm.c +++ b/daemon/gdm.c @@ -70,6 +70,8 @@ gint flexi_servers = 0; /* Number of flexi servers */ sigset_t sysmask; /* Inherited system signal mask */ uid_t GdmUserId; /* Userid under which gdm should run */ gid_t GdmGroupId; /* Groupid under which gdm should run */ +pid_t extra_process = -1; /* An extra process. Used for quickie + processes, so that they also get whacked */ static GdmConnection *fifoconn = NULL; /* Fifo connection */ static GdmConnection *unixconn = NULL; /* UNIX Socket connection */ @@ -602,6 +604,13 @@ final_cleanup (void) sigaddset (&mask, SIGCHLD); sigprocmask (SIG_BLOCK, &mask, NULL); + if (extra_process > 1) { + /* we sigterm extra processes, and we + * don't wait */ + kill (extra_process, SIGTERM); + extra_process = -1; + } + list = g_slist_copy (displays); g_slist_foreach (list, (GFunc) gdm_display_unmanage, NULL); g_slist_free (list); @@ -658,19 +667,25 @@ deal_with_x_crashes (GdmDisplay *d) if (configurators[i] != NULL) { strcpy (tempname, "/tmp/gdm-X-failed-XXXXXX"); tempfd = mkstemp (tempname); - close (tempfd); + if (tempfd >= 0) { + close (tempfd); - gdm_info (_("deal_with_x_crashes: Running the " - "XKeepsCrashing script")); + gdm_info (_("deal_with_x_crashes: Running the " + "XKeepsCrashing script")); - pid = fork (); + extra_process = pid = fork (); + } else { + /* no forking, we're screwing this */ + pid = -1; + } } else { tempfd = -1; /* no forking, we're screwing this */ pid = -1; } if (pid == 0) { - char *argv[9]; + char *argv[10]; + char *xlog = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL); argv[0] = GdmXKeepsCrashing; argv[1] = configurators[i]; @@ -680,9 +695,7 @@ deal_with_x_crashes (GdmDisplay *d) "up correctly. You will need to log in on a " "console and rerun the X configuration " "program. Then restart GDM."); - argv[4] = _("I cannot start the X server (your graphical " - "interface). It is likely that it is not set " - "up correctly. Would you like me to try to " + argv[4] = _("Would you like me to try to " "run the X configuration program? Note that " "you will need the root password for this."); argv[5] = _("Please type in the root (privilaged user) " @@ -691,7 +704,15 @@ deal_with_x_crashes (GdmDisplay *d) "again."); argv[7] = _("I will disable this X server for now. " "Restart GDM when it is configured correctly."); - argv[8] = NULL; + argv[8] = _("I cannot start the X server (your graphical " + "interface). It is likely that it is not set " + "up correctly. Would you like to view the " + "X server output to diagnose the problem?"); + argv[9] = NULL; + + ve_setenv ("XLOG", xlog, TRUE); + ve_setenv ("BINDIR", EXPANDED_BINDIR, TRUE); + ve_setenv ("SBINDIR", EXPANDED_SBINDIR, TRUE); execv (argv[0], argv); @@ -700,13 +721,16 @@ deal_with_x_crashes (GdmDisplay *d) } else if (pid > 0) { int status; waitpid (pid, &status, 0); + + extra_process = -1; + if (WIFEXITED (status) && WEXITSTATUS (status) == 0) { /* Yay, the user wants to try again, so * here we go */ return TRUE; } else if (WIFEXITED (status) && - WEXITSTATUS (status) == 32) { + WEXITSTATUS (status) == 32) { /* We couldn't run the script, just drop through */ ; } else { @@ -726,9 +750,7 @@ deal_with_x_crashes (GdmDisplay *d) /* if we have "open" we can talk to the user, not as user * friendly as the above script, but getting there */ if ( ! just_abort && - access ("/usr/bin/open", X_OK) == 0) { - char *dialog; /* do we have dialog?*/ - + access (EXPANDED_SBINDIR "/gdmopen", X_OK) == 0) { /* Shit if we knew what the program was to tell the user, * the above script would have been defined and we'd run * it for them */ @@ -737,29 +759,7 @@ deal_with_x_crashes (GdmDisplay *d) "up correctly. You will need to log in on a " "console and rerun the X configuration " "program. Then restart GDM."); - - dialog = gnome_is_program_in_path ("dialog"); - if (dialog == NULL) - dialog = gnome_is_program_in_path ("gdialog"); - if (dialog != NULL) { - char *command = - g_strdup_printf - ("/usr/bin/open -s -w -- /bin/sh -c 'clear ; " - "%s --msgbox \"%s\" 10 70 ; clear'", - dialog, - error); - system (command); - g_free (command); - g_free (dialog); - } else { - char *command = - g_strdup_printf - ("/usr/bin/open -s -w -- /bin/sh -c 'clear ; " - "echo \"%s\" 10 70 ; read ; clear'", - error); - system (command); - g_free (command); - } + gdm_text_message_dialog (error); } /* else { * At this point .... screw the user, we don't know how to * talk to him. He's on some 'l33t system anyway, so syslog diff --git a/daemon/gdm.h b/daemon/gdm.h index c93a65a5..f90686f1 100644 --- a/daemon/gdm.h +++ b/daemon/gdm.h @@ -268,6 +268,8 @@ struct _GdmDisplay { int vt; #endif + gboolean busy_display; + gboolean console; time_t last_start_time; diff --git a/daemon/misc.c b/daemon/misc.c index 8b6549ad..7db6d5b1 100644 --- a/daemon/misc.c +++ b/daemon/misc.c @@ -16,12 +16,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <config.h> +#include "config.h" #include <gnome.h> #include <syslog.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/wait.h> #include <sys/socket.h> +#include <fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> @@ -41,6 +43,8 @@ extern GSList *displays; extern char **environ; +extern pid_t extra_process; + /** * gdm_fail: @@ -216,7 +220,8 @@ gdm_get_free_display (int start, int server_uid) serv_addr.sin_port = htons (6000 + i); errno = 0; - if (connect (sock, &serv_addr, sizeof (serv_addr)) >= 0 || + if (connect (sock, (struct sockaddr *)&serv_addr, + sizeof (serv_addr)) >= 0 || errno != ECONNREFUSED) { close (sock); continue; @@ -241,4 +246,187 @@ gdm_get_free_display (int start, int server_uid) return -1; } +gboolean +gdm_text_message_dialog (const char *msg) +{ + char *dialog; /* do we have dialog?*/ + + if (access (EXPANDED_SBINDIR "/gdmopen", X_OK) != 0) + return FALSE; + + dialog = gnome_is_program_in_path ("dialog"); + if (dialog == NULL) + dialog = gnome_is_program_in_path ("gdialog"); + if (dialog != NULL) { + char *argv[7]; + + argv[0] = EXPANDED_SBINDIR "/gdmopen"; + argv[1] = dialog; + argv[2] = "--msgbox"; + argv[3] = (char *)msg; + argv[4] = "11"; + argv[5] = "70"; + argv[6] = NULL; + + if (gdm_exec_wait (argv) < 0) { + g_free (dialog); + return FALSE; + } + + g_free (dialog); + } else { + char *argv[5]; + + argv[0] = EXPANDED_SBINDIR "/gdmopen"; + argv[1] = "/bin/sh"; + argv[2] = "-c"; + argv[3] = g_strdup_printf + ("clear ; " + "echo \"%s\" ; read ; clear", + msg); + argv[4] = NULL; + + if (gdm_exec_wait (argv) < 0) { + g_free (argv[3]); + return FALSE; + } + g_free (argv[3]); + } + return TRUE; +} + +gboolean +gdm_text_yesno_dialog (const char *msg, gboolean *ret) +{ + char *dialog; /* do we have dialog?*/ + + if (access (EXPANDED_SBINDIR "/gdmopen", X_OK) != 0) + return FALSE; + + if (ret != NULL) + *ret = FALSE; + + dialog = gnome_is_program_in_path ("dialog"); + if (dialog == NULL) + dialog = gnome_is_program_in_path ("gdialog"); + if (dialog != NULL) { + char *argv[7]; + int retint; + + argv[0] = EXPANDED_SBINDIR "/gdmopen"; + argv[1] = dialog; + argv[2] = "--yesno"; + argv[3] = (char *)msg; + argv[4] = "11"; + argv[5] = "70"; + argv[6] = NULL; + + retint = gdm_exec_wait (argv); + if (retint < 0) { + g_free (dialog); + return FALSE; + } + + if (ret != NULL) + *ret = (retint == 0) ? TRUE : FALSE; + + g_free (dialog); + + return TRUE; + } else { + char tempname[] = "/tmp/gdm-yesno-XXXXXX"; + int tempfd; + FILE *fp; + char buf[256]; + char *argv[5]; + + tempfd = mkstemp (tempname); + if (tempfd < 0) + return FALSE; + + close (tempfd); + + argv[0] = EXPANDED_SBINDIR "/gdmopen"; + argv[1] = "/bin/sh"; + argv[2] = "-c"; + argv[3] = g_strdup_printf + ("clear ; " + "echo \"%s\" ; echo ; echo \"%s\" ; " + "read RETURN ; echo $RETURN > %s ; clear'", + msg, + /* Translators, don't translate the 'y' and 'n' */ + _("y = Yes or n = No? >"), + tempname); + argv[4] = NULL; + + if (gdm_exec_wait (argv) < 0) { + g_free (argv[3]); + return FALSE; + } + g_free (argv[3]); + + if (ret != NULL) { + fp = fopen (tempname, "r"); + if (fp != NULL) { + if (fgets (buf, sizeof (buf), fp) != NULL && + (buf[0] == 'y' || buf[0] == 'Y')) + *ret = TRUE; + fclose (fp); + } else { + return FALSE; + } + } + + unlink (tempname); + + return TRUE; + } +} + +int +gdm_exec_wait (char * const *argv) +{ + int status; + pid_t pid; + + if (argv == NULL || + argv[0] == NULL || + access (argv[0], X_OK) != 0) + return -1; + + /* Note a fun and unavoidable (also almost + * impossible to happen race. If the parent gets + * whacked before it executes any code, it will + * not whack the child. Oh well. */ + extra_process = pid = fork (); + if (pid == 0) { + int i; + + for (i = 0; i < sysconf (_SC_OPEN_MAX); i++) + close (i); + + /* No error checking here - if it's messed the best response + * is to ignore & try to continue */ + open ("/dev/null", O_RDONLY); /* open stdin - fd 0 */ + open ("/dev/null", O_RDWR); /* open stdout - fd 1 */ + open ("/dev/null", O_RDWR); /* open stderr - fd 2 */ + + execv (argv[0], argv); + + _exit (-1); + } + + if (pid < 0) + return -1; + + waitpid (pid, &status, 0); + + extra_process = -1; + + if (WIFEXITED (status)) + return WEXITSTATUS (status); + else + return -1; +} + /* EOF */ diff --git a/daemon/misc.h b/daemon/misc.h index b90a0886..7e6c73f0 100644 --- a/daemon/misc.h +++ b/daemon/misc.h @@ -33,6 +33,10 @@ void gdm_clearenv_no_lang (void); int gdm_get_free_display (int start, int server_uid); +gboolean gdm_text_message_dialog (const char *msg); +gboolean gdm_text_yesno_dialog (const char *msg, gboolean *ret); +int gdm_exec_wait (char * const *argv); + #endif /* GDM_MISC_H */ /* EOF */ diff --git a/daemon/server.c b/daemon/server.c index 46274821..13b563b5 100644 --- a/daemon/server.c +++ b/daemon/server.c @@ -127,55 +127,37 @@ gdm_server_stop (GdmDisplay *disp) unlink (disp->authfile); } -static void -busy_inform_user (GdmDisplay *disp) +static gboolean +busy_ask_user (GdmDisplay *disp) { /* if we have "open" we can talk to the user */ - if (access ("/usr/bin/open", X_OK) == 0) { - char *dialog; /* do we have dialog?*/ + if (access (EXPANDED_SBINDIR "/gdmopen", X_OK) == 0) { char *error = g_strdup_printf (_("There already appears to be an X server " - "running on display %s. Please quit this " - "server and then press Enter.%s"), + "running on display %s. Should I try another " + "display number? If you answer no, I will " + "attempt to start the server on %s again.%s"), + disp->name, disp->name, #ifdef __linux__ - _(" You can change consoles by pressing Ctrl-Alt " + _(" (You can change consoles by pressing Ctrl-Alt " "plus a function key, such as Ctrl-Alt-F7 to go " "to console 7. X servers usually run on consoles " - "7 and higher.") + "7 and higher.)") #else /* ! __linux__ */ /* no info for non linux users */ "" #endif /* __linux__ */ ); - dialog = gnome_is_program_in_path ("dialog"); - if (dialog == NULL) - dialog = gnome_is_program_in_path ("gdialog"); - if (dialog != NULL) { - char *command = - g_strdup_printf - ("/usr/bin/open -s -w -- /bin/sh -c 'clear ; " - "%s --msgbox \"%s\" 10 70 ; clear'", - dialog, - error); - system (command); - g_free (command); - g_free (dialog); - } else { - char *command = - g_strdup_printf - ("/usr/bin/open -s -w -- /bin/sh -c 'clear ; " - "echo \"%s\" 10 70 ; read ; clear'", - error); - system (command); - g_free (command); - } + gboolean ret = TRUE; + /* default ret to TRUE */ + if ( ! gdm_text_yesno_dialog (error, &ret)) + ret = TRUE; g_free (error); + return ret; } else { - /* If we can't ask, sleep 30 seconds and try again */ - gdm_info (_("Sleeping 30 seconds before retrying display %s"), - disp->name); - sleep (30); + /* Well we'll just try another display number */ + return TRUE; } } @@ -276,7 +258,8 @@ display_vt (GdmDisplay *disp) */ gboolean -gdm_server_start (GdmDisplay *disp, int min_flexi_disp, int flexi_retries) +gdm_server_start (GdmDisplay *disp, gboolean treat_as_flexi, + int min_flexi_disp, int flexi_retries) { struct sigaction usr1, chld, alrm; struct sigaction old_usr1, old_chld, old_alrm; @@ -291,7 +274,8 @@ gdm_server_start (GdmDisplay *disp, int min_flexi_disp, int flexi_retries) /* if an X server exists, wipe it */ gdm_server_stop (d); - if (SERVER_IS_FLEXI (d)) { + if (SERVER_IS_FLEXI (d) || + treat_as_flexi) { flexi_disp = gdm_get_free_display (MAX (high_display_num + 1, min_flexi_disp) /* start */, 0 /* server uid */); @@ -432,25 +416,37 @@ gdm_server_start (GdmDisplay *disp, int min_flexi_disp, int flexi_retries) * this we'll exit with DISPLAY_REMANAGE to try again if the * user wants to, or abort this display */ if (display_busy (disp)) { - if (SERVER_IS_FLEXI (disp)) { + if (SERVER_IS_FLEXI (disp) || + treat_as_flexi) { /* for flexi displays, try again a few times with different * display numbers */ if (flexi_retries <= 0) { /* Send X too busy */ - gdm_slave_send_num (GDM_SOP_FLEXI_ERR, - 4 /* X too busy */); + gdm_error (_("%s: Cannot find a free " + "display number"), + "gdm_server_start"); + if (SERVER_IS_FLEXI (disp)) { + gdm_slave_send_num (GDM_SOP_FLEXI_ERR, + 4 /* X too busy */); + } /* eki eki */ _exit (DISPLAY_REMANAGE); } - return gdm_server_start (d, flexi_disp + 1, + return gdm_server_start (d, treat_as_flexi, + flexi_disp + 1, flexi_retries - 1); } else { - /* FIXME: find first free display here above - * high_display_num optionally, and if the user - * has no dialog/gdialog, then just do that - * immediately. Must give an error as well on - * the X server once greeter is up. */ - busy_inform_user (disp); + if (busy_ask_user (disp)) { + gdm_error (_("%s: Display %s busy. Trying " + "another display number."), + "gdm_server_start", + d->name); + d->busy_display = TRUE; + return gdm_server_start (d, + TRUE /* treat as flexi */, + high_display_num + 1, + flexi_retries - 1); + } _exit (DISPLAY_REMANAGE); } } diff --git a/daemon/server.h b/daemon/server.h index 6ab2abfe..823606da 100644 --- a/daemon/server.h +++ b/daemon/server.h @@ -22,6 +22,7 @@ #include "gdm.h" gboolean gdm_server_start (GdmDisplay *d, + gboolean treat_as_flexi, int min_flexi_disp, int flexi_retries); void gdm_server_stop (GdmDisplay *d); diff --git a/daemon/slave.c b/daemon/slave.c index 1e3bd71e..235143d6 100644 --- a/daemon/slave.c +++ b/daemon/slave.c @@ -74,6 +74,7 @@ static gchar *ParsedTimedLogin = NULL; extern gboolean gdm_first_login; extern gboolean gdm_emergency_server; +extern pid_t extra_process; /* Configuration option variables */ extern gchar *GdmUser; @@ -356,6 +357,7 @@ gdm_slave_run (GdmDisplay *display) if (SERVER_IS_LOCAL (d) && d->servpid <= 0) { gdm_server_start (d, + FALSE /* treat_as_flexi */, 20 /* min_flexi_disp */, 5 /* flexi_retries */); gdm_slave_send_num (GDM_SOP_XPID, d->servpid); @@ -1105,6 +1107,15 @@ gdm_slave_greeter (void) "configure the X server.")); } + if (d->busy_display) { + char *msg = g_strdup_printf + (_("The specified display number was busy, so " + "this server was started on display %s."), + d->name); + gdm_error_box (d, GNOME_MESSAGE_BOX_ERROR, msg); + g_free (msg); + } + argv = ve_split (GdmGreeter); execv (argv[0], argv); @@ -2063,7 +2074,9 @@ gdm_slave_session_start (void) /* just a stupid test, the below would fail, but this gives a better * message */ - if (strcmp (shell, "/bin/false") == 0) { + if (strcmp (shell, "/sbin/nologin") == 0 || + strcmp (shell, "/bin/false") == 0 || + strcmp (shell, "/bin/true") == 0) { gdm_error (_("gdm_slave_session_start: User not allowed to log in")); gdm_error_box (d, GNOME_MESSAGE_BOX_ERROR, _("The system administrator has\n" @@ -2196,6 +2209,12 @@ gdm_slave_term_handler (int sig) sigaddset (&tmask, SIGCHLD); sigprocmask (SIG_BLOCK, &tmask, &omask); + if (extra_process > 1) { + /* we sigterm extra processes, and we + * don't wait */ + kill (extra_process, SIGTERM); + extra_process = -1; + } if (d->greetpid != 0) { greet = FALSE; @@ -2461,6 +2480,7 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login, gchar *script, *defscript, *scr; gchar **argv; gint status; + int i; if (!d || !dir) return EXIT_SUCCESS; @@ -2475,9 +2495,19 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login, else return EXIT_SUCCESS; - switch (pid = fork()) { + extra_process = pid = fork(); + switch (pid) { case 0: + for (i = 0; i < sysconf (_SC_OPEN_MAX); i++) + close (i); + + /* No error checking here - if it's messed the best response + * is to ignore & try to continue */ + open ("/dev/null", O_RDONLY); /* open stdin - fd 0 */ + open ("/dev/null", O_RDWR); /* open stdout - fd 1 */ + open ("/dev/null", O_RDWR); /* open stderr - fd 2 */ + if (login != NULL) { ve_setenv ("LOGNAME", login, TRUE); ve_setenv ("USER", login, TRUE); @@ -2512,6 +2542,8 @@ gdm_slave_exec_script (GdmDisplay *d, const gchar *dir, const char *login, default: waitpid (pid, &status, 0); /* Wait for script to finish */ + extra_process = -1; + if (WIFEXITED (status)) return WEXITSTATUS (status); else @@ -2630,7 +2662,8 @@ gdm_parse_enriched_login (const gchar *s, GdmDisplay *display) if (pipe(pipe1) < 0) syslog (LOG_ERR, _("gdm_parse_enriched_login: Failed creating pipe")); - switch (pid = fork()) { + extra_process = pid = fork(); + switch (pid) { case 0: /* The child will write the username to stdout based on the DISPLAY @@ -2670,6 +2703,7 @@ gdm_parse_enriched_login (const gchar *s, GdmDisplay *display) close(pipe1[0]); waitpid (pid, &status, 0); /* Wait for script to finish */ + extra_process = -1; } } diff --git a/daemon/verify-crypt.c b/daemon/verify-crypt.c index 65722bd3..14cd8f23 100644 --- a/daemon/verify-crypt.c +++ b/daemon/verify-crypt.c @@ -166,7 +166,8 @@ gdm_verify_user (const char *username, /* check for the standard method of disallowing users */ if (pwent->pw_shell != NULL && - (strcmp (pwent->pw_shell, "/bin/true") == 0 || + (strcmp (pwent->pw_shell, "/sbin/nologin") == 0 || + strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { gdm_error (_("User %s not allowed to log in"), login); if (GdmVerboseAuth) { diff --git a/daemon/verify-pam.c b/daemon/verify-pam.c index bd7d1a9f..137662b9 100644 --- a/daemon/verify-pam.c +++ b/daemon/verify-pam.c @@ -234,7 +234,8 @@ gdm_verify_user (const char *username, /* check for the standard method of disallowing users */ if (pwent != NULL && pwent->pw_shell != NULL && - (strcmp (pwent->pw_shell, "/bin/true") == 0 || + (strcmp (pwent->pw_shell, "/sbin/nologin") == 0 || + strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { gdm_error (_("User %s not allowed to log in"), login); if (GdmVerboseAuth) { diff --git a/daemon/verify-shadow.c b/daemon/verify-shadow.c index bd96293a..0bbe2547 100644 --- a/daemon/verify-shadow.c +++ b/daemon/verify-shadow.c @@ -175,7 +175,8 @@ gdm_verify_user (const char *username, const gchar *display, gboolean local) /* check for the standard method of disallowing users */ if (pwent->pw_shell != NULL && - (strcmp (pwent->pw_shell, "/bin/true") == 0 || + (strcmp (pwent->pw_shell, "/sbin/nologin") == 0 || + strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { gdm_error (_("User %s not allowed to log in"), login); if (GdmVerboseAuth) { diff --git a/daemon/xdmcp.c b/daemon/xdmcp.c index 80742edf..78b3b47a 100644 --- a/daemon/xdmcp.c +++ b/daemon/xdmcp.c @@ -419,7 +419,7 @@ gdm_xdmcp_decode_packet (GIOChannel *source, GIOCondition cond, gpointer data) "MANAGED_FORWARD" }; - if (!XdmcpFill (xdmcpfd, &buf, &clnt_sa, &sa_len)) { + if (!XdmcpFill (xdmcpfd, &buf, (XdmcpNetaddr)&clnt_sa, &sa_len)) { gdm_error (_("gdm_xdmcp_decode: Could not create XDMCP buffer!")); return TRUE; } diff --git a/gdm.spec.in b/gdm.spec.in index 8ae30aac..3ac68f6e 100644 --- a/gdm.spec.in +++ b/gdm.spec.in @@ -14,6 +14,7 @@ BuildRoot: %{_tmppath}/gdm-%{version}-root Prereq: /usr/sbin/useradd Requires: pam >= 0.68 Requires: gnome-libs >= 1.0.17 +Epoch: 1 %description Gdm (the GNOME Display Manager) is a highly configurable diff --git a/gui/gdmflexiserver.desktop.in b/gui/gdmflexiserver.desktop.in index d18c2282..3f112ddf 100644 --- a/gui/gdmflexiserver.desktop.in +++ b/gui/gdmflexiserver.desktop.in @@ -1,7 +1,6 @@ [Desktop Entry] _Name=New login _Comment=Log in as another user without loging out -TryExec=gdmflexiserver Exec=gdmflexiserver Icon= Terminal=0 diff --git a/utils/.cvsignore b/utils/.cvsignore new file mode 100644 index 00000000..005306fe --- /dev/null +++ b/utils/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.libs +.deps +gdmaskpass +gdmopen diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 00000000..d24fce3e --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,41 @@ +## Process this file with automake to produce makefile.in +CFLAGS += -g -Wall \ + -Wpointer-arith \ + -Wmissing-prototypes -Wmissing-declarations + +DEFS += -DGDM_CONFIG_FILE=\"@sysconfdir@/gdm/gdm.conf\" \ + -DGDM_FACTORY_CONFIG_FILE=\"@sysconfdir@/gdm/factory-gdm.conf\" \ + -DGDM_GLADE_DIR=\"@datadir@/gdm\" + +INCLUDES = \ + -I. \ + -I.. \ + -I$(top_srcdir)/daemon \ + -I$(top_srcdir)/vicious-extensions \ + -I$(includedir) \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + @LIBGLADE_CFLAGS@ \ + @PIXBUF_CFLAGS@ \ + $(GNOME_CFLAGS) \ + $(GNOME_INCLUDEDIR) + +sbin_PROGRAMS = \ + @GDMASKPASS@ \ + @GDMOPEN@ +EXTRA_PROGRAMS = gdmaskpass gdmopen + +gdmaskpass_SOURCES = \ + gdmaskpass.c + +gdmopen_SOURCES = \ + gdmopen.c + +gdmaskpass_LDADD = \ + $(GNOME_LIBDIR) \ + $(INTLLIBS) \ + -lpam \ + -lpam_misc + +gdmopen_LDADD = \ + $(GNOME_LIBDIR) \ + $(INTLLIBS) diff --git a/utils/gdmaskpass.c b/utils/gdmaskpass.c new file mode 100644 index 00000000..8c083a68 --- /dev/null +++ b/utils/gdmaskpass.c @@ -0,0 +1,58 @@ +/* Simple pam thingie to ask the root password, for use in XKeepsCrashing + * script. */ +#include "config.h" +#include <gnome.h> +#include <stdio.h> +#include <locale.h> +#include <unistd.h> +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +int +main (int argc, char *argv[]) +{ + pam_handle_t *pamh; + const char *username = "root"; + int retval; + int tries = 3; + + if (getuid () != geteuid () || + getuid () != 0) { + fprintf (stderr, _("gdmaskpass only runs as root\n")); + return 1; + } + + if (argc >= 2) { + username = argv[1]; + } + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE); + + for (tries = 3; tries > 0; tries --) { + if ((retval = pam_start ("gdm", username, &conv, &pamh)) != PAM_SUCCESS) { + pam_end (pamh, retval); + pamh = NULL; + printf (_("Authentication failure!\n")); + continue; + } + if ((retval = pam_authenticate (pamh, 0)) != PAM_SUCCESS) { + pam_end (pamh, retval); + pamh = NULL; + printf (_("Authentication failure!\n")); + continue; + } + break; + } + + if (pamh != NULL) + pam_end (pamh, retval); + + return (retval == PAM_SUCCESS) ? 0 : 1; +} diff --git a/utils/gdmopen.c b/utils/gdmopen.c new file mode 100644 index 00000000..d5c8574d --- /dev/null +++ b/utils/gdmopen.c @@ -0,0 +1,201 @@ +/* + * gdmopen.c by the Queen of England, based upon original open. + * Simplified for the purposes of gdm. All useless (to me) + * functionality stripped. Also returns what the command returns. + * Return of 66 means error with open. + * + * Original header: + * + * open.c open a vt to run a new command (or shell). + * + * Copyright (c) 1994 by Jon Tombs <jon@gtex02.us.es> + * + * 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. + */ + +#include "config.h" +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <dirent.h> +#include <pwd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/vt.h> +#include <sys/types.h> +#include <sys/wait.h> + +#ifndef FALSE +#define FALSE 0 +#define TRUE !FALSE +#endif + + +/* + * Where your VTs are hidden + */ +#ifdef __linux__ +#define VTNAME "/dev/tty%d" +#endif + +#ifdef ESIX_5_3_2_D +#define VTBASE "/dev/vt%02d" +#endif + +const char *GDMOPENversion = "gdmopen " VERSION " simplified (was: open: 1.4 (c) Jon Tombs 1994)"; + +#ifndef VTNAME +#error vt device name must be defined in open.c +#endif + +static pid_t child_pid = -1; +struct vt_stat vt; +static int vtno; +static int fd = 0; +static int do_dealloc = FALSE; + +static void +sighandler (int sig) +{ + if (child_pid > 1) { + if (kill (child_pid, sig) == 0) + waitpid (child_pid, NULL, 0); + } + + if (do_dealloc) { + /* Switch back... */ + (void) ioctl(fd, VT_ACTIVATE, vt.v_active); + /* wait to be really sure we have switched */ + (void) ioctl(fd, VT_WAITACTIVE, vt.v_active); + + /* Now deallocate our new one */ + (void) ioctl(fd, VT_DISALLOCATE, vtno); + } + + /* Kill myself with this signal */ + signal (sig, SIG_DFL); + kill (getpid (), sig); +} + +int +main (int argc, char *argv[]) +{ + char vtname[256]; + int status; + + if (getuid () != geteuid () || + getuid () != 0) { + fprintf (stderr, "gdmopen: Only root wants to run me\n"); + return 66; + } + + signal (SIGTERM, sighandler); + signal (SIGINT, sighandler); + signal (SIGHUP, sighandler); + + if (argc <= 1) { + fprintf (stderr, "gdmopen: must supply a command!\n"); + return 66; + } + + fd = open ("/dev/console", O_WRONLY, 0); + if (fd < 0) { + perror ("gdmopen: Failed to open /dev/console"); + return 66; + } + + errno = 0; + if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) { + perror ("gdmopen: Cannot find a free VT"); + close (fd); + return 66; + } + + if (ioctl(fd, VT_GETSTATE, &vt) < 0) { + perror ("gdmopen: can't get VTstate"); + close(fd); + return 66; + } + + snprintf (vtname, sizeof (vtname), VTNAME, vtno); + + chown (vtname, 0, -1); + + child_pid = fork(); + if (child_pid == 0) { + + signal (SIGTERM, SIG_DFL); + signal (SIGINT, SIG_DFL); + signal (SIGHUP, SIG_DFL); + + /* leave current vt */ + if ( +#ifdef ESIX_5_3_2_D + setpgrp() < 0 +#else + setsid() < 0 +#endif + ) { + fprintf(stderr, "open: Unable to set new session (%s)\n", + strerror(errno)); + } + close(0); + close(1); + close(2); + close(fd); + + /* and grab new one */ + fd = open (vtname, O_RDWR); + if (fd < 0) { /* Shouldn't happen */ + _exit (66); /* silently die */ + } + dup(fd); + dup(fd); + + /* + * Can't tell anyone if any of these fail, so throw away + * the return values + */ + (void) ioctl(fd, VT_ACTIVATE, vtno); + /* wait to be really sure we have switched */ + (void) ioctl(fd, VT_WAITACTIVE, vtno); + + execvp (argv[1], &argv[1]); + + _exit (66); /* failed */ + } + + if (child_pid < 0) { + perror ("gdmopen: fork() error"); + return 66; + } + + do_dealloc = TRUE; + + waitpid (child_pid, &status, 0); + child_pid = -1; + + do_dealloc = FALSE; + + /* Switch back... */ + (void) ioctl(fd, VT_ACTIVATE, vt.v_active); + /* wait to be really sure we have switched */ + (void) ioctl(fd, VT_WAITACTIVE, vt.v_active); + + /* Now deallocate our new one */ + (void) ioctl(fd, VT_DISALLOCATE, vtno); + + close (fd); + + if (WIFEXITED (status)) + return WEXITSTATUS (status); + else + return 66; +} |