~ubuntu-branches/ubuntu/oneiric/gdm3/oneiric

« back to all changes in this revision

Viewing changes to common/gdm-common.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette
  • Date: 2010-03-25 20:02:20 UTC
  • Revision ID: james.westby@ubuntu.com-20100325200220-12cap62s6p304nuh
Tags: upstream-2.29.92
ImportĀ upstreamĀ versionĀ 2.29.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <string.h>
 
24
#include <unistd.h>
 
25
#include <stdlib.h>
 
26
#include <locale.h>
 
27
#include <fcntl.h>
 
28
#include <sys/wait.h>
 
29
 
 
30
#include <glib.h>
 
31
#include <glib/gi18n.h>
 
32
#include <glib/gstdio.h>
 
33
 
 
34
#include "gdm-common.h"
 
35
 
 
36
#ifndef HAVE_MKDTEMP
 
37
#include "mkdtemp.h"
 
38
#endif
 
39
 
 
40
const char *
 
41
gdm_make_temp_dir (char *template)
 
42
{
 
43
        return mkdtemp (template);
 
44
}
 
45
 
 
46
gboolean
 
47
gdm_is_version_unstable (void)
 
48
{
 
49
        char   **versions;
 
50
        gboolean unstable;
 
51
 
 
52
        unstable = FALSE;
 
53
 
 
54
        versions = g_strsplit (VERSION, ".", 3);
 
55
        if (versions && versions [0] && versions [1]) {
 
56
                int major;
 
57
                major = atoi (versions [1]);
 
58
                if ((major % 2) != 0) {
 
59
                        unstable = TRUE;
 
60
                }
 
61
        }
 
62
        g_strfreev (versions);
 
63
 
 
64
        return unstable;
 
65
}
 
66
 
 
67
void
 
68
gdm_set_fatal_warnings_if_unstable (void)
 
69
{
 
70
        if (gdm_is_version_unstable ()) {
 
71
                g_setenv ("G_DEBUG", "fatal_criticals", FALSE);
 
72
                g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
 
73
        }
 
74
}
 
75
 
 
76
int
 
77
gdm_wait_on_pid (int pid)
 
78
{
 
79
        int status;
 
80
 
 
81
 wait_again:
 
82
        errno = 0;
 
83
        if (waitpid (pid, &status, 0) < 0) {
 
84
                if (errno == EINTR) {
 
85
                        goto wait_again;
 
86
                } else if (errno == ECHILD) {
 
87
                        ; /* do nothing, child already reaped */
 
88
                } else {
 
89
                        g_debug ("GdmCommon: waitpid () should not fail");
 
90
                }
 
91
        }
 
92
 
 
93
        g_debug ("GdmCommon: process (pid:%d) done (%s:%d)",
 
94
                 (int) pid,
 
95
                 WIFEXITED (status) ? "status"
 
96
                 : WIFSIGNALED (status) ? "signal"
 
97
                 : "unknown",
 
98
                 WIFEXITED (status) ? WEXITSTATUS (status)
 
99
                 : WIFSIGNALED (status) ? WTERMSIG (status)
 
100
                 : -1);
 
101
 
 
102
        return status;
 
103
}
 
104
 
 
105
int
 
106
gdm_signal_pid (int pid,
 
107
                int signal)
 
108
{
 
109
        int status = -1;
 
110
 
 
111
        /* perhaps block sigchld */
 
112
        g_debug ("GdmCommon: sending signal %d to process %d", signal, pid);
 
113
        errno = 0;
 
114
        status = kill (pid, signal);
 
115
 
 
116
        if (status < 0) {
 
117
                if (errno == ESRCH) {
 
118
                        g_warning ("Child process %d was already dead.",
 
119
                                   (int)pid);
 
120
                } else {
 
121
                        g_warning ("Couldn't kill child process %d: %s",
 
122
                                   pid,
 
123
                                   g_strerror (errno));
 
124
                }
 
125
        }
 
126
 
 
127
        /* perhaps unblock sigchld */
 
128
 
 
129
        return status;
 
130
}
 
131
 
 
132
/* hex conversion adapted from D-Bus */
 
133
/**
 
134
 * Appends a two-character hex digit to a string, where the hex digit
 
135
 * has the value of the given byte.
 
136
 *
 
137
 * @param str the string
 
138
 * @param byte the byte
 
139
 */
 
140
static void
 
141
_gdm_string_append_byte_as_hex (GString *str,
 
142
                                int      byte)
 
143
{
 
144
        const char hexdigits[16] = {
 
145
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 
146
                'a', 'b', 'c', 'd', 'e', 'f'
 
147
        };
 
148
 
 
149
        str = g_string_append_c (str, hexdigits[(byte >> 4)]);
 
150
 
 
151
        str = g_string_append_c (str, hexdigits[(byte & 0x0f)]);
 
152
}
 
153
 
 
154
/**
 
155
 * Encodes a string in hex, the way MD5 and SHA-1 are usually
 
156
 * encoded. (Each byte is two hex digits.)
 
157
 *
 
158
 * @param source the string to encode
 
159
 * @param start byte index to start encoding
 
160
 * @param dest string where encoded data should be placed
 
161
 * @param insert_at where to place encoded data
 
162
 * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
 
163
 */
 
164
gboolean
 
165
gdm_string_hex_encode (const GString *source,
 
166
                       int            start,
 
167
                       GString       *dest,
 
168
                       int            insert_at)
 
169
{
 
170
        GString             *result;
 
171
        const unsigned char *p;
 
172
        const unsigned char *end;
 
173
        gboolean             retval;
 
174
 
 
175
        g_return_val_if_fail (source != NULL, FALSE);
 
176
        g_return_val_if_fail (dest != NULL, FALSE);
 
177
        g_return_val_if_fail (source != dest, FALSE);
 
178
        g_return_val_if_fail (start >= 0, FALSE);
 
179
        g_return_val_if_fail (dest >= 0, FALSE);
 
180
        g_assert (start <= source->len);
 
181
 
 
182
        result = g_string_new (NULL);
 
183
 
 
184
        retval = FALSE;
 
185
 
 
186
        p = (const unsigned char*) source->str;
 
187
        end = p + source->len;
 
188
        p += start;
 
189
 
 
190
        while (p != end) {
 
191
                _gdm_string_append_byte_as_hex (result, *p);
 
192
                ++p;
 
193
        }
 
194
 
 
195
        dest = g_string_insert (dest, insert_at, result->str);
 
196
 
 
197
        retval = TRUE;
 
198
 
 
199
        g_string_free (result, TRUE);
 
200
 
 
201
        return retval;
 
202
}
 
203
 
 
204
/**
 
205
 * Decodes a string from hex encoding.
 
206
 *
 
207
 * @param source the string to decode
 
208
 * @param start byte index to start decode
 
209
 * @param end_return return location of the end of the hex data, or #NULL
 
210
 * @param dest string where decoded data should be placed
 
211
 * @param insert_at where to place decoded data
 
212
 * @returns #TRUE if decoding was successful, #FALSE if no memory.
 
213
 */
 
214
gboolean
 
215
gdm_string_hex_decode (const GString *source,
 
216
                       int            start,
 
217
                       int           *end_return,
 
218
                       GString       *dest,
 
219
                       int            insert_at)
 
220
{
 
221
        GString             *result;
 
222
        const unsigned char *p;
 
223
        const unsigned char *end;
 
224
        gboolean             retval;
 
225
        gboolean             high_bits;
 
226
 
 
227
        g_return_val_if_fail (source != NULL, FALSE);
 
228
        g_return_val_if_fail (dest != NULL, FALSE);
 
229
        g_return_val_if_fail (source != dest, FALSE);
 
230
        g_return_val_if_fail (start >= 0, FALSE);
 
231
        g_return_val_if_fail (dest >= 0, FALSE);
 
232
 
 
233
        g_assert (start <= source->len);
 
234
 
 
235
        result = g_string_new (NULL);
 
236
 
 
237
        retval = FALSE;
 
238
 
 
239
        high_bits = TRUE;
 
240
        p = (const unsigned char*) source->str;
 
241
        end = p + source->len;
 
242
        p += start;
 
243
 
 
244
        while (p != end) {
 
245
                unsigned int val;
 
246
 
 
247
                switch (*p) {
 
248
                case '0':
 
249
                        val = 0;
 
250
                        break;
 
251
                case '1':
 
252
                        val = 1;
 
253
                        break;
 
254
                case '2':
 
255
                        val = 2;
 
256
                        break;
 
257
                case '3':
 
258
                        val = 3;
 
259
                        break;
 
260
                case '4':
 
261
                        val = 4;
 
262
                        break;
 
263
                case '5':
 
264
                        val = 5;
 
265
                        break;
 
266
                case '6':
 
267
                        val = 6;
 
268
                        break;
 
269
                case '7':
 
270
                        val = 7;
 
271
                        break;
 
272
                case '8':
 
273
                        val = 8;
 
274
                        break;
 
275
                case '9':
 
276
                        val = 9;
 
277
                        break;
 
278
                case 'a':
 
279
                case 'A':
 
280
                        val = 10;
 
281
                        break;
 
282
                case 'b':
 
283
                case 'B':
 
284
                        val = 11;
 
285
                        break;
 
286
                case 'c':
 
287
                case 'C':
 
288
                        val = 12;
 
289
                        break;
 
290
                case 'd':
 
291
                case 'D':
 
292
                        val = 13;
 
293
                        break;
 
294
                case 'e':
 
295
                case 'E':
 
296
                        val = 14;
 
297
                        break;
 
298
                case 'f':
 
299
                case 'F':
 
300
                        val = 15;
 
301
                        break;
 
302
                default:
 
303
                        goto done;
 
304
                }
 
305
 
 
306
                if (high_bits) {
 
307
                        result = g_string_append_c (result, val << 4);
 
308
                } else {
 
309
                        int           len;
 
310
                        unsigned char b;
 
311
 
 
312
                        len = result->len;
 
313
 
 
314
                        b = result->str[len - 1];
 
315
 
 
316
                        b |= val;
 
317
 
 
318
                        result->str[len - 1] = b;
 
319
                }
 
320
 
 
321
                high_bits = !high_bits;
 
322
 
 
323
                ++p;
 
324
        }
 
325
 
 
326
 done:
 
327
        dest = g_string_insert (dest, insert_at, result->str);
 
328
 
 
329
        if (end_return) {
 
330
                *end_return = p - (const unsigned char*) source->str;
 
331
        }
 
332
 
 
333
        retval = TRUE;
 
334
 
 
335
        g_string_free (result, TRUE);
 
336
 
 
337
        return retval;
 
338
}
 
339
 
 
340
static gboolean
 
341
_fd_is_character_device (int fd)
 
342
{
 
343
        struct stat file_info;
 
344
 
 
345
        if (fstat (fd, &file_info) < 0) {
 
346
                return FALSE;
 
347
        }
 
348
 
 
349
        return S_ISCHR (file_info.st_mode);
 
350
}
 
351
 
 
352
static gboolean
 
353
_read_bytes (int      fd,
 
354
             char    *bytes,
 
355
             gsize    number_of_bytes,
 
356
             GError **error)
 
357
{
 
358
        size_t bytes_left_to_read;
 
359
        size_t total_bytes_read = 0;
 
360
        gboolean premature_eof;
 
361
 
 
362
        bytes_left_to_read = number_of_bytes;
 
363
        premature_eof = FALSE;
 
364
        do {
 
365
                size_t bytes_read = 0;
 
366
 
 
367
                errno = 0;
 
368
                bytes_read = read (fd, ((guchar *) bytes) + total_bytes_read,
 
369
                                   bytes_left_to_read);
 
370
 
 
371
                if (bytes_read > 0) {
 
372
                        total_bytes_read += bytes_read;
 
373
                        bytes_left_to_read -= bytes_read;
 
374
                } else if (bytes_read == 0) {
 
375
                        premature_eof = TRUE;
 
376
                        break;
 
377
                } else if ((errno != EINTR)) {
 
378
                        break;
 
379
                }
 
380
        } while (bytes_left_to_read > 0);
 
381
 
 
382
        if (premature_eof) {
 
383
                g_set_error (error,
 
384
                             G_FILE_ERROR,
 
385
                             g_file_error_from_errno (ENODATA),
 
386
                             "%s", g_strerror (ENODATA));
 
387
 
 
388
                return FALSE;
 
389
        } else if (bytes_left_to_read > 0) {
 
390
                g_set_error (error,
 
391
                             G_FILE_ERROR,
 
392
                             g_file_error_from_errno (errno),
 
393
                             "%s", g_strerror (errno));
 
394
                return FALSE;
 
395
        }
 
396
 
 
397
        return TRUE;
 
398
}
 
399
 
 
400
/**
 
401
 * Pulls a requested number of bytes from /dev/urandom
 
402
 *
 
403
 * @param size number of bytes to pull
 
404
 * @param error error if read fails
 
405
 * @returns The requested number of random bytes or #NULL if fail
 
406
 */
 
407
 
 
408
char *
 
409
gdm_generate_random_bytes (gsize    size,
 
410
                           GError **error)
 
411
{
 
412
        int fd;
 
413
        char *bytes;
 
414
        GError *read_error;
 
415
 
 
416
        /* We don't use the g_rand_* glib apis because they don't document
 
417
         * how much entropy they are seeded with, and it might be less
 
418
         * than the passed in size.
 
419
         */
 
420
 
 
421
        errno = 0;
 
422
        fd = open ("/dev/urandom", O_RDONLY);
 
423
 
 
424
        if (fd < 0) {
 
425
                g_set_error (error,
 
426
                             G_FILE_ERROR,
 
427
                             g_file_error_from_errno (errno),
 
428
                             "%s", g_strerror (errno));
 
429
                close (fd);
 
430
                return NULL;
 
431
        }
 
432
 
 
433
        if (!_fd_is_character_device (fd)) {
 
434
                g_set_error (error,
 
435
                             G_FILE_ERROR,
 
436
                             g_file_error_from_errno (ENODEV),
 
437
                             _("/dev/urandom is not a character device"));
 
438
                close (fd);
 
439
                return NULL;
 
440
        }
 
441
 
 
442
        bytes = g_malloc (size);
 
443
        read_error = NULL;
 
444
        if (!_read_bytes (fd, bytes, size, &read_error)) {
 
445
                g_propagate_error (error, read_error);
 
446
                g_free (bytes);
 
447
                close (fd);
 
448
                return NULL;
 
449
        }
 
450
 
 
451
        close (fd);
 
452
        return bytes;
 
453
}