2
* GDMcommunication routines
3
* (c)2001 Queen of England, (c)2002,2003 George Lebl
4
* (c)2005 James M. Cape.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
#endif /* HAVE_CONFIG_H */
30
#include <sys/types.h>
32
#include <sys/socket.h>
37
#include <X11/Xauth.h>
39
#include <gdk/gdkdisplay.h>
41
#include <glib/gi18n.h>
46
/* ***************************************************************** *
47
* From gdm2/vicious-extensions/ve-misc.h *
48
* Copyright (c) 2000 Eazel, Inc., (c) 2001,2002 George Lebl *
49
* ***************************************************************** */
51
#define VE_IGNORE_EINTR(expr) \
55
} while G_UNLIKELY (errno == EINTR);
58
static const gboolean debug = FALSE;
63
gboolean get_response)
70
void (*old_handler)(int);
74
g_print ("Sending command: '%s'\n", command);
76
cstr = g_strdup_printf ("%s\n", command);
79
ret = send (fd, cstr, strlen (cstr), MSG_NOSIGNAL);
81
old_handler = signal (SIGPIPE, SIG_IGN);
82
ret = send (fd, cstr, strlen (cstr), 0);
83
signal (SIGPIPE, old_handler);
93
str = g_string_sized_new (10);
94
while (read (fd, buf, 1) == 1 &&
96
g_string_append_c (str, buf[0]);
100
g_print (" Got response: '%s'\n", str->str);
103
g_string_free (str, FALSE);
108
version_ok_p (const char *version,
109
const char *min_version)
111
int a = 0, b = 0, c = 0, d = 0;
112
int mina = 0, minb = 0, minc = 0, mind = 0;
114
/* Note that if some fields in the version don't exist, then
115
* we don't mind, they are zero */
116
sscanf (version, "%d.%d.%d.%d", &a, &b, &c, &d);
117
sscanf (min_version, "%d.%d.%d.%d", &mina, &minb, &minc, &mind);
120
(a == mina && b > minb) ||
121
(a == mina && b == minb && c > minc) ||
122
(a == mina && b == minb && c == minc && d >= mind))
129
gdmcomm_call_gdm (const char *command,
130
const char *auth_cookie,
131
const char *min_version,
134
struct sockaddr_un addr;
141
fd = socket (AF_UNIX, SOCK_STREAM, 0);
143
return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
146
strcpy (addr.sun_path, GDM_SUP_SOCKET);
147
addr.sun_family = AF_UNIX;
149
if (connect (fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
150
VE_IGNORE_EINTR (close (fd));
151
return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
154
/* Version check first */
155
ret = do_command (fd, GDM_SUP_VERSION, TRUE /* get_response */);
157
VE_IGNORE_EINTR (close (fd));
158
return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
160
if (strncmp (ret, "GDM ", strlen ("GDM ")) != 0) {
162
VE_IGNORE_EINTR (close (fd));
165
if ( ! version_ok_p (&ret[4], min_version)) {
167
do_command (fd, GDM_SUP_CLOSE, FALSE /* get_response */);
168
VE_IGNORE_EINTR (close (fd));
173
/* require authentication */
174
if (auth_cookie != NULL) {
175
char *auth_cmd = g_strdup_printf
176
(GDM_SUP_AUTH_LOCAL " %s", auth_cookie);
177
ret = do_command (fd, auth_cmd, TRUE /* get_response */);
180
VE_IGNORE_EINTR (close (fd));
181
return gdmcomm_call_gdm (command, auth_cookie,
182
min_version, tries - 1);
185
if (strcmp (ret, "OK") != 0) {
186
do_command (fd, GDM_SUP_CLOSE,
187
FALSE /* get_response */);
188
VE_IGNORE_EINTR (close (fd));
189
/* returns the error */
195
ret = do_command (fd, command, TRUE /* get_response */);
197
VE_IGNORE_EINTR (close (fd));
198
return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
201
do_command (fd, GDM_SUP_CLOSE, FALSE /* get_response */);
203
VE_IGNORE_EINTR (close (fd));
209
get_dispnum (GdkScreen *screen)
213
tmp = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen)));
218
ptr = strchr (tmp, '.');
222
ptr = strchr (tmp, ':');
228
retval = g_strdup (ptr);
231
retval = g_strdup (tmp);
236
retval = g_strdup ("0");
241
/* This just gets a cookie of MIT-MAGIC-COOKIE-1 type */
243
gdmcomm_get_a_cookie (GdkScreen *screen,
251
VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r"));
256
number = get_dispnum (screen);
260
while ((xau = XauReadAuth (fp)) != NULL) {
261
/* Just find the FIRST magic cookie, that's what gdm uses */
262
if (xau->number_length != strlen (number) ||
263
strncmp (xau->number, number, xau->number_length) != 0 ||
264
/* gdm sends MIT-MAGIC-COOKIE-1 cookies of length 16,
265
* so just do those */
266
xau->data_length != 16 ||
267
xau->name_length != strlen ("MIT-MAGIC-COOKIE-1") ||
268
strncmp (xau->name, "MIT-MAGIC-COOKIE-1",
269
xau->name_length) != 0) {
270
XauDisposeAuth (xau);
275
cookie = g_new0 (char, 16);
276
memcpy (cookie, xau->data, 16);
281
str = g_string_new (NULL);
283
for (i = 0; i < xau->data_length; i++) {
284
g_string_append_printf
286
(guint)(guchar)xau->data[i]);
288
cookie = g_string_free (str, FALSE);
291
XauDisposeAuth (xau);
295
VE_IGNORE_EINTR (fclose (fp));
301
gdmcomm_get_auth_cookie (GdkScreen *screen)
305
static gboolean tried = FALSE;
306
static char *cookie = NULL;
312
VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r"));
319
number = get_dispnum (screen);
323
while ((xau = XauReadAuth (fp)) != NULL) {
327
char buffer[40 /* 2*16 == 32, so 40 is enough */];
329
/* Only Family local things are considered, all console
330
* logins DO have this family (and even some local xdmcp
331
* logins, though those will not pass by gdm itself of
333
if (xau->family != FamilyLocal ||
334
xau->number_length != strlen (number) ||
335
strncmp (xau->number, number, xau->number_length) != 0 ||
336
/* gdm sends MIT-MAGIC-COOKIE-1 cookies of length 16,
337
* so just do those */
338
xau->data_length != 16 ||
339
xau->name_length != strlen ("MIT-MAGIC-COOKIE-1") ||
340
strncmp (xau->name, "MIT-MAGIC-COOKIE-1",
341
xau->name_length) != 0 ||
342
xau->data_length != 16) {
343
XauDisposeAuth (xau);
348
for (i = 0; i < 16; i++) {
350
g_snprintf (sub, sizeof (sub), "%02x",
351
(guint)(guchar)xau->data[i]);
352
strcat (buffer, sub);
355
XauDisposeAuth (xau);
357
cmd = g_strdup_printf (GDM_SUP_AUTH_LOCAL " %s", buffer);
358
ret = gdmcomm_call_gdm (cmd, NULL /* auth cookie */, "2.2.4.0", 5);
360
strcmp (ret, "OK") == 0) {
362
cookie = g_strdup (buffer);
367
VE_IGNORE_EINTR (fclose (fp));
377
gdmcomm_check (gboolean gui_bitching)
386
pidfile = ve_config_get_string (ve_config_get (GDM_CONFIG_FILE),
391
VE_IGNORE_EINTR (fp = fopen (pidfile, "r"));
394
VE_IGNORE_EINTR (r = fscanf (fp, "%ld", &pid));
395
VE_IGNORE_EINTR (fclose (fp));
404
(kill (pid, 0) < 0 &&
407
dialog = ve_hig_dialog_new
409
GTK_DIALOG_MODAL /* flags */,
413
_("GDM (The GNOME Display Manager) "
416
_("You might in fact be using a different "
417
"display manager, such as KDM "
418
"(KDE Display Manager) or xdm."),
419
_("If you still wish to use this feature, "
420
"either start GDM yourself or ask your "
421
"system administrator to start GDM."));
423
gtk_widget_show_all (dialog);
424
gtk_dialog_run (GTK_DIALOG (dialog));
425
gtk_widget_destroy (dialog);
430
VE_IGNORE_EINTR (statret = stat (GDM_SUP_SOCKET, &s));
433
access (GDM_SUP_SOCKET, R_OK|W_OK) != 0) {
435
dialog = ve_hig_dialog_new
437
GTK_DIALOG_MODAL /* flags */,
441
_("Cannot communicate with GDM "
442
"(The GNOME Display Manager)"),
444
_("Perhaps you have an old version "
446
gtk_widget_show_all (dialog);
447
gtk_dialog_run (GTK_DIALOG (dialog));
448
gtk_widget_destroy (dialog);
458
gdmcomm_get_error_message (const char *ret,
461
/* These need a bit more refinement */
463
return _("Cannot communicate with gdm, perhaps "
464
"you have an old version running.");
465
} else if (strncmp (ret, "ERROR 0 ", strlen ("ERROR 0 ")) == 0) {
466
return _("Cannot communicate with gdm, perhaps "
467
"you have an old version running.");
468
} else if (strncmp (ret, "ERROR 1 ", strlen ("ERROR 1 ")) == 0) {
469
return _("The allowed limit of flexible X servers reached.");
470
} else if (strncmp (ret, "ERROR 2 ", strlen ("ERROR 2 ")) == 0) {
471
return _("There were errors trying to start the X server.");
472
} else if (strncmp (ret, "ERROR 3 ", strlen ("ERROR 3 ")) == 0) {
473
return _("The X server failed. Perhaps it is not "
475
} else if (strncmp (ret, "ERROR 4 ", strlen ("ERROR 4 ")) == 0) {
476
return _("Too many X sessions running.");
477
} else if (strncmp (ret, "ERROR 5 ", strlen ("ERROR 5 ")) == 0) {
478
return _("The nested X server (Xnest) cannot connect to "
479
"your current X server. You may be missing an "
480
"X authorization file.");
481
} else if (strncmp (ret, "ERROR 6 ", strlen ("ERROR 6 ")) == 0) {
483
return _("The nested X server (Xnest) is not "
484
"available, or gdm is badly configured.\n"
485
"Please install the Xnest package in "
486
"order to use the nested login.");
488
return _("The X server is not available, "
489
"it is likely that gdm is badly "
491
} else if (strncmp (ret, "ERROR 7 ", strlen ("ERROR 7 ")) == 0) {
492
return _("Trying to set an unknown logout action, or trying "
493
"to set a logout action which is not available.");
494
} else if (strncmp (ret, "ERROR 8 ", strlen ("ERROR 8 ")) == 0) {
495
return _("Virtual terminals not supported.");
496
} else if (strncmp (ret, "ERROR 9 ", strlen ("ERROR 9 ")) == 0) {
497
return _("Trying to change to an invalid virtual terminal number.");
498
} else if (strncmp (ret, "ERROR 50 ", strlen ("ERROR 50 ")) == 0) {
499
return _("Trying to update an unsupported configuration key.");
500
} else if (strncmp (ret, "ERROR 100 ", strlen ("ERROR 100 ")) == 0) {
501
return _("You do not seem to have authentication needed "
502
"be for this operation. Perhaps your .Xauthority "
503
"file is not set up correctly.");
504
} else if (strncmp (ret, "ERROR 200 ", strlen ("ERROR 200 ")) == 0) {
505
return _("Too many messages were sent to gdm and it hung up"
508
return _("Unknown error occured.");