diff options
Diffstat (limited to 'gui/gdmcomm.c')
-rw-r--r-- | gui/gdmcomm.c | 711 |
1 files changed, 0 insertions, 711 deletions
diff --git a/gui/gdmcomm.c b/gui/gdmcomm.c deleted file mode 100644 index a5d5080e..00000000 --- a/gui/gdmcomm.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * GDMcommunication routines - * (c)2001 Queen of England, (c)2002,2003 George Lebl - * - * 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 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * 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 - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "config.h" -#include <glib/gi18n.h> -#include <gtk/gtk.h> -#include <gdk/gdkx.h> -#include <X11/Xauth.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <stdio.h> -#include <sys/types.h> -#include <signal.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <errno.h> - -#include "vicious.h" - -#include "gdm.h" -#include "gdmcommon.h" -#include "gdmcomm.h" -#include "gdmconfig.h" - -static gboolean bulk_acs = FALSE; -static gboolean debug = FALSE; -static gboolean quiet = FALSE; -static int num_cmds = 0; - -/* - * Note, in this function we have to call gdm_common_error instead - * of gdm_common_debug, since gdm_common_debug accesses the - * GDM_KEY_DEBUG which can cause a sockets connection to get the - * config data, causing an infinite loop. This is why clients must - * call the gdmcomm_set_debug function to turn on debug for these - * functions. - */ -void -gdmcomm_set_debug (gboolean enable) -{ - debug = enable; -} - -/* - * Normally errors are printed. Setting quiet to TRUE turns off - * display of error messages. - */ -void -gdmcomm_set_quiet_errors (gboolean enable) -{ - quiet = enable; -} - -static char * -do_command (int fd, const char *command, gboolean get_response) -{ - GString *str; - char buf[1]; - char *cstr; - int ret; -#ifndef MSG_NOSIGNAL - void (*old_handler)(int); -#endif - - if (debug) { - gdm_common_error ("Sending command: '%s'", command); - } - - cstr = g_strdup_printf ("%s\n", command); - -#ifdef MSG_NOSIGNAL - ret = send (fd, cstr, strlen (cstr), MSG_NOSIGNAL); -#else - old_handler = signal (SIGPIPE, SIG_IGN); - ret = send (fd, cstr, strlen (cstr), 0); - signal (SIGPIPE, old_handler); -#endif - g_free (cstr); - - num_cmds++; - - if (ret < 0) { - if ( !quiet) - gdm_common_error ("Command failed, no data returned"); - return NULL; - } - - /* No need to print debug, this is only used when closing */ - if ( ! get_response) - return NULL; - - str = g_string_new (NULL); - while (read (fd, buf, 1) == 1 && - buf[0] != '\n') { - g_string_append_c (str, buf[0]); - } - - if (debug) - gdm_common_error (" Got response: '%s'", str->str); - - cstr = str->str; - g_string_free (str, FALSE); - - /* - * If string is empty, then the daemon likely closed the connection - * because of too many subconnections. At any rate the daemon should - * not return an empty string. All return values should start with - * "OK" or "ERROR". Daemon should never complain about too many - * messages since the slave keeps track of the number of commands sent - * and should not send too many, but it does not hurt to check and - * manage it if it somehow happens. In either case return NULL - * instead so the caller can try again. - */ - if (ve_string_empty (cstr) || - strcmp (ve_sure_string (cstr), "ERROR 200 Too many messages") == 0) { - if ( !quiet) - gdm_common_error ("Command failed, daemon busy."); - g_free (cstr); - return NULL; - } - - return cstr; -} - -static gboolean -version_ok_p (const char *version, const char *min_version) -{ - int a = 0, b = 0, c = 0, d = 0; - int mina = 0, minb = 0, minc = 0, mind = 0; - - /* Note that if some fields in the version don't exist, then - * we don't mind, they are zero */ - sscanf (version, "%d.%d.%d.%d", &a, &b, &c, &d); - sscanf (min_version, "%d.%d.%d.%d", &mina, &minb, &minc, &mind); - - if ((a > mina) || - (a == mina && b > minb) || - (a == mina && b == minb && c > minc) || - (a == mina && b == minb && c == minc && d >= mind)) - return TRUE; - else - return FALSE; -} - -static gboolean allow_sleep = TRUE; -static gboolean did_sleep_on_failure = FALSE; -static int comm_fd = 0; - -static char * -gdmcomm_call_gdm_real (const char *command, - const char *auth_cookie, - const char *min_version, - int tries, - int try_start) -{ - char *ret; - - /* - * If already sent the max number of commands, close the connection - * and reopen. Subtract 1 to allow the "CLOSE" to get through. - */ - if (num_cmds == (GDM_SUP_MAX_MESSAGES - 1)) { - if (debug) - gdm_common_error (" Closing and reopening connection."); - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - num_cmds = 0; - } - - if (tries <= 0) { - if ( !quiet) - gdm_common_error (" Command failed %d times, aborting.", try_start); - return NULL; - } - - if (!quiet && tries != try_start) { - gdm_common_error (" Trying failed command again. Try %d of %d.", - (try_start - tries + 1), try_start); - } - - if (comm_fd <= 0) { - struct sockaddr_un addr; - strcpy (addr.sun_path, GDM_SUP_SOCKET); - addr.sun_family = AF_UNIX; - comm_fd = socket (AF_UNIX, SOCK_STREAM, 0); - if (comm_fd < 0) { - if ( !quiet) - gdm_common_error (" Failed to open socket"); - - return gdmcomm_call_gdm_real (command, auth_cookie, min_version, tries - 1, try_start); - } - - if (connect (comm_fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { - - - /* - * If there is a failure on connect, there are probably - * other clients fighting for the connection, so sleep - * for 1 second before retry to avoid failing over and - * over in a tight loop. - * - * Only do this if allow_sleep is true. allow_sleep - * will get set to FALSE if the first call to this - * function fails all retries. - */ - if (allow_sleep == TRUE) { - - did_sleep_on_failure = TRUE; - - /* - * Only actualy sleep if we are going to try - * again. - */ - if (tries > 1) { - if ( !quiet) - gdm_common_error (" Failed to connect to socket, sleep 1 second and retry"); - sleep (1); - } - } else { - if ( !quiet) - gdm_common_error (" Failed to connect to socket, not sleeping"); - } - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return gdmcomm_call_gdm_real (command, auth_cookie, - min_version, tries - 1, try_start); - } - - /* - * If we get this far, then even if we did sleep in the past, - * we did get a connection, so no need to prevent future - * sleeps if required. - */ - allow_sleep = TRUE; - did_sleep_on_failure = FALSE; - - /* Version check first - only check first time */ - ret = do_command (comm_fd, GDM_SUP_VERSION, TRUE); - if (ret == NULL) { - if ( !quiet) - gdm_common_error (" Version check failed"); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return gdmcomm_call_gdm_real (command, auth_cookie, - min_version, tries - 1, try_start); - } - if (strncmp (ret, "GDM ", strlen ("GDM ")) != 0) { - if ( !quiet) - gdm_common_error (" Version check failed, bad name"); - - g_free (ret); - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return NULL; - } - if ( ! version_ok_p (&ret[4], min_version)) { - if ( !quiet) - gdm_common_error (" Version check failed, bad version"); - g_free (ret); - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return NULL; - } - g_free (ret); - } - - /* require authentication */ - if (auth_cookie != NULL) { - char *auth_cmd = g_strdup_printf - (GDM_SUP_AUTH_LOCAL " %s", auth_cookie); - ret = do_command (comm_fd, auth_cmd, TRUE); - g_free (auth_cmd); - if (ret == NULL) { - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return gdmcomm_call_gdm_real (command, auth_cookie, - min_version, tries - 1, try_start); - } - /* not auth'ed */ - if (strcmp (ve_sure_string (ret), "OK") != 0) { - if ( !quiet) - gdm_common_error (" Error, auth check failed"); - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - /* returns the error */ - return ret; - } - g_free (ret); - } - - ret = do_command (comm_fd, command, TRUE); - if (ret == NULL) { - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - return gdmcomm_call_gdm_real (command, auth_cookie, - min_version, tries - 1, try_start); - } - - /* - * We want to leave the connection open if bulk_acs is set to - * true, so clients can read as much config data in one - * sockets connection when it is set. This requires that - * GDM client programs ensure that they call the bulk_start - * and bulk_stop functions around blocks of code that - * need to read data in bulk. If a client reads config data - * outside of the bulk_start/stop functions, then this - * will just negatively affect performance since an additional - * socket will be opened to read that config data. - */ - if (bulk_acs == FALSE) { - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - comm_fd = 0; - } - - return ret; -} - -char * -gdmcomm_call_gdm (const char *command, const char * auth_cookie, - const char *min_version, int tries) -{ - - char *retstr; - - retstr = gdmcomm_call_gdm_real (command, auth_cookie, min_version, - tries, tries); - - /* - * Disallow sleeping on future calls if it failed to connect. - * did_sleep_on_failure will only be TRUE if the function returned - * without ever connecting. - */ - if (did_sleep_on_failure == TRUE) - allow_sleep = FALSE; - - return (retstr); -} - -/** - * gdmcomm_did_connection_fail - * - * If allow_sleep is TRUE, then connection was able to go through. - * so the client can call this function after calling to see if - * the failure was due to the connection being too busy. This is - * useful for gdmdynamic. - */ -gboolean -gdmcomm_did_connection_fail (void) -{ - return !allow_sleep; -} - -void -gdmcomm_set_allow_sleep (gboolean val) -{ - allow_sleep = val; -} - -void -gdmcomm_comm_bulk_start (void) -{ - bulk_acs = TRUE; -} - -void -gdmcomm_comm_bulk_stop (void) -{ - /* Close the connection */ - if (comm_fd > 0) { - do_command (comm_fd, GDM_SUP_CLOSE, FALSE); - VE_IGNORE_EINTR (close (comm_fd)); - } - comm_fd = 0; - num_cmds = 0; - bulk_acs = FALSE; -} - -const char * -gdmcomm_get_display (void) -{ - static char *display = NULL; - - if (display == NULL) { - char *p; - - display = gdk_get_display (); - if (display == NULL) { - display = g_strdup (g_getenv ("DISPLAY")); - if (display == NULL) /*eek!*/ { - display = g_strdup (":0"); - } - } - - /* whack screen part, GDM doesn't like those */ - p = strchr (display, '.'); - if (p != NULL) - *p = '\0'; - } - - return display; -} - -static char * -get_dispnum (void) -{ - static char *number = NULL; - - if (number == NULL) { - char *p; - number = g_strdup (gdmcomm_get_display ()); - - /* whee! handles even DECnet */ - number = strchr (number, ':'); - if (number != NULL) { - while (*number == ':') { - number++; - } - p = strchr (number, '.'); - if (p != NULL) - *p = '\0'; - } else { - number = "0"; - } - } - - return number; -} - -/* This just gets a cookie of MIT-MAGIC-COOKIE-1 type */ -char * -gdmcomm_get_a_cookie (gboolean binary) -{ - FILE *fp; - char *number; - char *cookie = NULL; - Xauth *xau; - - VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r")); - if (fp == NULL) { - return NULL; - } - - number = get_dispnum (); - - cookie = NULL; - - while ((xau = XauReadAuth (fp)) != NULL) { - /* Just find the FIRST magic cookie, that's what gdm uses */ - if (xau->number_length != strlen (number) || - strncmp (xau->number, number, xau->number_length) != 0 || - /* gdm sends MIT-MAGIC-COOKIE-1 cookies of length 16, - * so just do those */ - xau->data_length != 16 || - xau->name_length != strlen ("MIT-MAGIC-COOKIE-1") || - strncmp (xau->name, "MIT-MAGIC-COOKIE-1", - xau->name_length) != 0) { - XauDisposeAuth (xau); - continue; - } - - if (binary) { - cookie = g_new0 (char, 16); - memcpy (cookie, xau->data, 16); - } else { - int i; - GString *str; - - str = g_string_new (NULL); - - for (i = 0; i < xau->data_length; i++) { - g_string_append_printf - (str, "%02x", - (guint)(guchar)xau->data[i]); - } - cookie = g_string_free (str, FALSE); - } - - XauDisposeAuth (xau); - - break; - } - VE_IGNORE_EINTR (fclose (fp)); - - return cookie; -} - -char * -gdmcomm_get_auth_cookie (void) -{ - FILE *fp; - char *number; - static gboolean tried = FALSE; - static char *cookie = NULL; - Xauth *xau; - - if (tried) - return cookie; - - VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r")); - if (fp == NULL) { - cookie = NULL; - tried = TRUE; - return NULL; - } - - number = get_dispnum (); - - cookie = NULL; - - while ((xau = XauReadAuth (fp)) != NULL) { - char *cmd; - char *ret; - int i; - char buffer[40 /* 2*16 == 32, so 40 is enough */]; - - /* Only Family local things are considered, all console - * logins DO have this family (and even some local xdmcp - * logins, though those will not pass by gdm itself of - * course) */ - if (xau->family != FamilyLocal || - xau->number_length != strlen (number) || - strncmp (xau->number, number, xau->number_length) != 0 || - /* gdm sends MIT-MAGIC-COOKIE-1 cookies of length 16, - * so just do those */ - xau->data_length != 16 || - xau->name_length != strlen ("MIT-MAGIC-COOKIE-1") || - strncmp (xau->name, "MIT-MAGIC-COOKIE-1", - xau->name_length) != 0 || - xau->data_length != 16) { - XauDisposeAuth (xau); - continue; - } - - buffer[0] = '\0'; - for (i = 0; i < 16; i++) { - char sub[3]; - g_snprintf (sub, sizeof (sub), "%02x", - (guint)(guchar)xau->data[i]); - strcat (buffer, sub); - } - - XauDisposeAuth (xau); - - cmd = g_strdup_printf (GDM_SUP_AUTH_LOCAL " %s", buffer); - ret = gdmcomm_call_gdm (cmd, NULL /* auth cookie */, "2.2.4.0", 5); - g_free (cmd); - if (ret != NULL && - strcmp (ve_sure_string (ret), "OK") == 0) { - g_free (ret); - cookie = g_strdup (buffer); - break; - } - g_free (ret); - } - VE_IGNORE_EINTR (fclose (fp)); - - tried = TRUE; - return cookie; -} - -gboolean -gdmcomm_check (gboolean show_dialog) -{ - GtkWidget *dialog; - FILE *fp = NULL; - long pid; - char *pidfile; - struct stat s; - int statret; - - pidfile = gdm_config_get_string (GDM_KEY_PID_FILE); - - pid = 0; - if (pidfile != NULL) - VE_IGNORE_EINTR (fp = fopen (pidfile, "r")); - if (fp != NULL) { - int r; - VE_IGNORE_EINTR (r = fscanf (fp, "%ld", &pid)); - VE_IGNORE_EINTR (fclose (fp)); - if (r != 1) - pid = 0; - } - - errno = 0; - if (pid <= 1 || - (kill (pid, 0) < 0 && - errno != EPERM)) { - if (show_dialog) { - dialog = ve_hig_dialog_new - (NULL /* parent */, - GTK_DIALOG_MODAL /* flags */, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_OK, - _("GDM (The GNOME Display Manager) " - "is not running."), - _("You might in fact be using a different " - "display manager, such as KDM " - "(KDE Display Manager) or xdm. " - "If you still wish to use this feature, " - "either start GDM yourself or ask your " - "system administrator to start GDM.")); - - gtk_widget_show_all (dialog); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - } - return FALSE; - } - - VE_IGNORE_EINTR (statret = g_stat (GDM_SUP_SOCKET, &s)); - if (statret < 0 || - s.st_uid != 0 || - g_access (GDM_SUP_SOCKET, R_OK|W_OK) != 0) { - if (show_dialog) { - dialog = ve_hig_dialog_new - (NULL /* parent */, - GTK_DIALOG_MODAL /* flags */, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_OK, - _("Cannot communicate with GDM " - "(The GNOME Display Manager)"), - _("Perhaps you have an old version " - "of GDM running.")); - gtk_widget_show_all (dialog); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - } - return FALSE; - } - - return TRUE; -} - -const char * -gdmcomm_get_error_message (const char *ret, gboolean use_xnest) -{ - /* These need a bit more refinement */ - if (ret == NULL) { - return _("Cannot communicate with GDM. Perhaps " - "you have an old version running."); - } else if (strncmp (ret, "ERROR 0 ", strlen ("ERROR 0 ")) == 0) { - return _("Cannot communicate with GDM. Perhaps " - "you have an old version running."); - } else if (strncmp (ret, "ERROR 1 ", strlen ("ERROR 1 ")) == 0) { - return _("The allowed limit of flexible X servers reached."); - } else if (strncmp (ret, "ERROR 2 ", strlen ("ERROR 2 ")) == 0) { - return _("There were errors trying to start the X server."); - } else if (strncmp (ret, "ERROR 3 ", strlen ("ERROR 3 ")) == 0) { - return _("The X server failed. Perhaps it is not " - "configured well."); - } else if (strncmp (ret, "ERROR 4 ", strlen ("ERROR 4 ")) == 0) { - return _("Too many X sessions running."); - } else if (strncmp (ret, "ERROR 5 ", strlen ("ERROR 5 ")) == 0) { - return _("The nested X server (Xnest) cannot connect to " - "your current X server. You may be missing an " - "X authorization file."); - } else if (strncmp (ret, "ERROR 6 ", strlen ("ERROR 6 ")) == 0) { - if (use_xnest) - return _("The nested X server (Xnest) is not " - "available, or GDM is badly configured.\n" - "Please install the Xnest package in " - "order to use the nested login."); - else - return _("The X server is not available. " - "GDM may be misconfigured."); - } else if (strncmp (ret, "ERROR 7 ", strlen ("ERROR 7 ")) == 0) { - return _("Trying to set an unknown logout action, or trying " - "to set a logout action which is not available."); - } else if (strncmp (ret, "ERROR 8 ", strlen ("ERROR 8 ")) == 0) { - return _("Virtual terminals not supported."); - } else if (strncmp (ret, "ERROR 9 ", strlen ("ERROR 9 ")) == 0) { - return _("Trying to change to an invalid virtual terminal number."); - } else if (strncmp (ret, "ERROR 50 ", strlen ("ERROR 50 ")) == 0) { - return _("Trying to update an unsupported configuration key."); - } else if (strncmp (ret, "ERROR 100 ", strlen ("ERROR 100 ")) == 0) { - return _("You do not seem to have the authentication needed " - "for this operation. Perhaps your .Xauthority " - "file is not set up correctly."); - } else if (strncmp (ret, "ERROR 200 ", strlen ("ERROR 200 ")) == 0) { - return _("Too many messages were sent to GDM and it hung up " - "on us."); - } else { - return _("Unknown error occurred."); - } -} - |