~ubuntu-branches/ubuntu/dapper/gnome-screensaver/dapper

« back to all changes in this revision

Viewing changes to src/cut-n-paste/gdmcomm.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-10 00:18:18 UTC
  • Revision ID: james.westby@ubuntu.com-20051010001818-3mujs05r8rht7xi1
Tags: upstream-0.0.15
ImportĀ upstreamĀ versionĀ 0.0.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *    GDMcommunication routines
 
3
 *    (c)2001 Queen of England, (c)2002,2003 George Lebl
 
4
 *    (c)2005 James M. Cape.
 
5
 *    
 
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.
 
10
 *   
 
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.
 
15
 *   
 
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.
 
19
 * 
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
# include <config.h>
 
24
#endif /* HAVE_CONFIG_H */
 
25
 
 
26
#include <stdlib.h>
 
27
#include <stdio.h>
 
28
#include <unistd.h>
 
29
#include <stdio.h>
 
30
#include <sys/types.h>
 
31
#include <signal.h>
 
32
#include <sys/socket.h>
 
33
#include <sys/stat.h>
 
34
#include <sys/un.h>
 
35
#include <errno.h>
 
36
 
 
37
#include <X11/Xauth.h>
 
38
 
 
39
#include <gdk/gdkdisplay.h>
 
40
 
 
41
#include <glib/gi18n.h>
 
42
 
 
43
#include "gdmcomm.h"
 
44
 
 
45
 
 
46
/* ***************************************************************** *
 
47
 *  From gdm2/vicious-extensions/ve-misc.h                           *
 
48
 *  Copyright (c) 2000 Eazel, Inc., (c) 2001,2002 George Lebl        *
 
49
 * ***************************************************************** */
 
50
 
 
51
#define VE_IGNORE_EINTR(expr) \
 
52
  do {          \
 
53
    errno = 0;  \
 
54
    expr;               \
 
55
  } while G_UNLIKELY (errno == EINTR);
 
56
 
 
57
 
 
58
static const gboolean debug = FALSE;
 
59
 
 
60
static char *
 
61
do_command (int         fd,
 
62
            const char *command,
 
63
            gboolean    get_response)
 
64
{
 
65
        GString *str;
 
66
        char buf[1];
 
67
        char *cstr;
 
68
        int ret;
 
69
#ifndef MSG_NOSIGNAL
 
70
        void (*old_handler)(int);
 
71
#endif
 
72
 
 
73
        if (debug)
 
74
                g_print ("Sending command: '%s'\n", command);
 
75
 
 
76
        cstr = g_strdup_printf ("%s\n", command);
 
77
 
 
78
#ifdef MSG_NOSIGNAL
 
79
        ret = send (fd, cstr, strlen (cstr), MSG_NOSIGNAL);
 
80
#else
 
81
        old_handler = signal (SIGPIPE, SIG_IGN);
 
82
        ret = send (fd, cstr, strlen (cstr), 0);
 
83
        signal (SIGPIPE, old_handler);
 
84
#endif
 
85
        g_free (cstr);
 
86
 
 
87
        if (ret < 0)
 
88
                return NULL;
 
89
 
 
90
        if ( ! get_response)
 
91
                return NULL;
 
92
 
 
93
        str = g_string_sized_new (10);
 
94
        while (read (fd, buf, 1) == 1 &&
 
95
               buf[0] != '\n') {
 
96
                g_string_append_c (str, buf[0]);
 
97
        }
 
98
 
 
99
        if (debug)
 
100
                g_print ("  Got response: '%s'\n", str->str);
 
101
 
 
102
        cstr = str->str;
 
103
        g_string_free (str, FALSE);
 
104
        return cstr;
 
105
}
 
106
 
 
107
static gboolean
 
108
version_ok_p (const char *version,
 
109
              const char *min_version)
 
110
{
 
111
        int a = 0, b = 0, c = 0, d = 0;
 
112
        int mina = 0, minb = 0, minc = 0, mind = 0;
 
113
 
 
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);
 
118
 
 
119
        if ((a > mina) ||
 
120
            (a == mina && b > minb) ||
 
121
            (a == mina && b == minb && c > minc) ||
 
122
            (a == mina && b == minb && c == minc && d >= mind))
 
123
                return TRUE;
 
124
        else
 
125
                return FALSE;
 
126
}
 
127
 
 
128
char *
 
129
gdmcomm_call_gdm (const char *command,
 
130
                  const char *auth_cookie,
 
131
                  const char *min_version,
 
132
                  int         tries)
 
133
{
 
134
        struct sockaddr_un addr;
 
135
        int fd;
 
136
        char *ret;
 
137
 
 
138
        if (tries <= 0)
 
139
                return NULL;
 
140
 
 
141
        fd = socket (AF_UNIX, SOCK_STREAM, 0);
 
142
        if (fd < 0) {
 
143
                return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
 
144
        }
 
145
 
 
146
        strcpy (addr.sun_path, GDM_SUP_SOCKET);
 
147
        addr.sun_family = AF_UNIX;
 
148
 
 
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);
 
152
        }
 
153
 
 
154
        /* Version check first */
 
155
        ret = do_command (fd, GDM_SUP_VERSION, TRUE /* get_response */);
 
156
        if (ret == NULL) {
 
157
                VE_IGNORE_EINTR (close (fd));
 
158
                return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
 
159
        }
 
160
        if (strncmp (ret, "GDM ", strlen ("GDM ")) != 0) {
 
161
                g_free (ret);
 
162
                VE_IGNORE_EINTR (close (fd));
 
163
                return NULL;
 
164
        }
 
165
        if ( ! version_ok_p (&ret[4], min_version)) {
 
166
                g_free (ret);
 
167
                do_command (fd, GDM_SUP_CLOSE, FALSE /* get_response */);
 
168
                VE_IGNORE_EINTR (close (fd));
 
169
                return NULL;
 
170
        }
 
171
        g_free (ret);
 
172
 
 
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 */);
 
178
                g_free (auth_cmd);
 
179
                if (ret == NULL) {
 
180
                        VE_IGNORE_EINTR (close (fd));
 
181
                        return gdmcomm_call_gdm (command, auth_cookie,
 
182
                                                 min_version, tries - 1);
 
183
                }
 
184
                /* not auth'ed */
 
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 */
 
190
                        return ret;
 
191
                }
 
192
                g_free (ret);
 
193
        }
 
194
 
 
195
        ret = do_command (fd, command, TRUE /* get_response */);
 
196
        if (ret == NULL) {
 
197
                VE_IGNORE_EINTR (close (fd));
 
198
                return gdmcomm_call_gdm (command, auth_cookie, min_version, tries - 1);
 
199
        }
 
200
 
 
201
        do_command (fd, GDM_SUP_CLOSE, FALSE /* get_response */);
 
202
 
 
203
        VE_IGNORE_EINTR (close (fd));
 
204
 
 
205
        return ret;
 
206
}
 
207
 
 
208
static gchar *
 
209
get_dispnum (GdkScreen *screen)
 
210
{
 
211
  gchar *tmp, *retval;
 
212
 
 
213
  tmp = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen)));
 
214
  if (tmp)
 
215
    {
 
216
      gchar *ptr;
 
217
 
 
218
      ptr = strchr (tmp, '.');
 
219
      if (ptr)
 
220
        *ptr = '\0';
 
221
 
 
222
      ptr = strchr (tmp, ':');
 
223
      if (ptr)
 
224
        {
 
225
          while (*ptr == ':')
 
226
            ptr++;
 
227
 
 
228
          retval = g_strdup (ptr);
 
229
        }
 
230
      else
 
231
        retval = g_strdup (tmp);
 
232
 
 
233
      g_free (tmp);
 
234
    }
 
235
  else
 
236
    retval = g_strdup ("0");
 
237
 
 
238
  return retval;
 
239
}
 
240
 
 
241
/* This just gets a cookie of MIT-MAGIC-COOKIE-1 type */
 
242
gchar *
 
243
gdmcomm_get_a_cookie (GdkScreen *screen,
 
244
                      gboolean   binary)
 
245
{
 
246
        FILE *fp;
 
247
        char *number;
 
248
        char *cookie = NULL;
 
249
        Xauth *xau;
 
250
 
 
251
        VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r"));
 
252
        if (fp == NULL) {
 
253
                return NULL;
 
254
        }
 
255
 
 
256
        number = get_dispnum (screen);
 
257
 
 
258
        cookie = NULL;
 
259
 
 
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);
 
271
                        continue;
 
272
                }
 
273
 
 
274
                if (binary) {
 
275
                        cookie = g_new0 (char, 16);
 
276
                        memcpy (cookie, xau->data, 16);
 
277
                } else {
 
278
                        int i;
 
279
                        GString *str;
 
280
 
 
281
                        str = g_string_new (NULL);
 
282
 
 
283
                        for (i = 0; i < xau->data_length; i++) {
 
284
                                g_string_append_printf
 
285
                                        (str, "%02x",
 
286
                                         (guint)(guchar)xau->data[i]);
 
287
                        }
 
288
                        cookie = g_string_free (str, FALSE);
 
289
                }
 
290
 
 
291
                XauDisposeAuth (xau);
 
292
 
 
293
                break;
 
294
        }
 
295
        VE_IGNORE_EINTR (fclose (fp));
 
296
 
 
297
        return cookie;
 
298
}
 
299
 
 
300
const char *
 
301
gdmcomm_get_auth_cookie (GdkScreen *screen)
 
302
{
 
303
        FILE *fp;
 
304
        char *number;
 
305
        static gboolean tried = FALSE;
 
306
        static char *cookie = NULL;
 
307
        Xauth *xau;
 
308
 
 
309
        if (tried)
 
310
                return cookie;
 
311
 
 
312
        VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r"));
 
313
        if (fp == NULL) {
 
314
                cookie = NULL;
 
315
                tried = TRUE;
 
316
                return NULL;
 
317
        }
 
318
 
 
319
        number = get_dispnum (screen);
 
320
 
 
321
        cookie = NULL;
 
322
 
 
323
        while ((xau = XauReadAuth (fp)) != NULL) {
 
324
                char *cmd;
 
325
                char *ret;
 
326
                int i;
 
327
                char buffer[40 /* 2*16 == 32, so 40 is enough */];
 
328
 
 
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
 
332
                 * course) */
 
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);
 
344
                        continue;
 
345
                }
 
346
 
 
347
                buffer[0] = '\0';
 
348
                for (i = 0; i < 16; i++) {
 
349
                        char sub[3];
 
350
                        g_snprintf (sub, sizeof (sub), "%02x",
 
351
                                    (guint)(guchar)xau->data[i]);
 
352
                        strcat (buffer, sub);
 
353
                }
 
354
 
 
355
                XauDisposeAuth (xau);
 
356
 
 
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);
 
359
                if (ret != NULL &&
 
360
                    strcmp (ret, "OK") == 0) {
 
361
                        g_free (ret);
 
362
                        cookie = g_strdup (buffer);
 
363
                        break;
 
364
                }
 
365
                g_free (ret);
 
366
        }
 
367
        VE_IGNORE_EINTR (fclose (fp));
 
368
      
 
369
        g_free (number);
 
370
 
 
371
        tried = TRUE;
 
372
        return cookie;
 
373
}
 
374
 
 
375
#if 0
 
376
gboolean
 
377
gdmcomm_check (gboolean gui_bitching)
 
378
{
 
379
        GtkWidget *dialog;
 
380
        FILE *fp = NULL;
 
381
        long pid;
 
382
        char *pidfile;
 
383
        struct stat s;
 
384
        int statret;
 
385
 
 
386
        pidfile = ve_config_get_string (ve_config_get (GDM_CONFIG_FILE),
 
387
                                        GDM_KEY_PIDFILE);
 
388
 
 
389
        pid = 0;
 
390
        if (pidfile != NULL)
 
391
                VE_IGNORE_EINTR (fp = fopen (pidfile, "r"));
 
392
        if (fp != NULL) {
 
393
                int r;
 
394
                VE_IGNORE_EINTR (r = fscanf (fp, "%ld", &pid));
 
395
                VE_IGNORE_EINTR (fclose (fp));
 
396
                if (r != 1)
 
397
                        pid = 0;
 
398
        }
 
399
 
 
400
        g_free (pidfile);
 
401
 
 
402
        errno = 0;
 
403
        if (pid <= 1 ||
 
404
            (kill (pid, 0) < 0 &&
 
405
             errno != EPERM)) {
 
406
                if (gui_bitching) {
 
407
                        dialog = ve_hig_dialog_new
 
408
                                (NULL /* parent */,
 
409
                                 GTK_DIALOG_MODAL /* flags */,
 
410
                                 GTK_MESSAGE_WARNING,
 
411
                                 GTK_BUTTONS_OK,
 
412
                                 FALSE /* markup */,
 
413
                                 _("GDM (The GNOME Display Manager) "
 
414
                                   "is not running."),
 
415
                                 "%s\n%s",
 
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."));
 
422
 
 
423
                        gtk_widget_show_all (dialog);
 
424
                        gtk_dialog_run (GTK_DIALOG (dialog));
 
425
                        gtk_widget_destroy (dialog);
 
426
                }
 
427
                return FALSE;
 
428
        }
 
429
 
 
430
        VE_IGNORE_EINTR (statret = stat (GDM_SUP_SOCKET, &s));
 
431
        if (statret < 0 ||
 
432
            s.st_uid != 0 ||
 
433
            access (GDM_SUP_SOCKET, R_OK|W_OK) != 0) {
 
434
                if (gui_bitching) {
 
435
                        dialog = ve_hig_dialog_new
 
436
                                (NULL /* parent */,
 
437
                                 GTK_DIALOG_MODAL /* flags */,
 
438
                                 GTK_MESSAGE_WARNING,
 
439
                                 GTK_BUTTONS_OK,
 
440
                                 FALSE /* markup */,
 
441
                                 _("Cannot communicate with GDM "
 
442
                                   "(The GNOME Display Manager)"),
 
443
                                 "%s",
 
444
                                 _("Perhaps you have an old version "
 
445
                                   "of GDM running."));
 
446
                        gtk_widget_show_all (dialog);
 
447
                        gtk_dialog_run (GTK_DIALOG (dialog));
 
448
                        gtk_widget_destroy (dialog);
 
449
                }
 
450
                return FALSE;
 
451
        }
 
452
 
 
453
        return TRUE;
 
454
}
 
455
#endif /* 0 */
 
456
 
 
457
const char *
 
458
gdmcomm_get_error_message (const char *ret,
 
459
                           gboolean    use_xnest)
 
460
{
 
461
        /* These need a bit more refinement */
 
462
        if (ret == NULL) {
 
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 "
 
474
                         "configured well.");
 
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) {
 
482
                if (use_xnest)
 
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.");
 
487
                else
 
488
                        return _("The X server is not available, "
 
489
                                 "it is likely that gdm is badly "
 
490
                                 "configured.");
 
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"
 
506
                         "on us.");
 
507
        } else {
 
508
                return _("Unknown error occured.");
 
509
        }
 
510
}