1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* gdm-display-access-file.c - Abstraction around xauth cookies
5
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2, or (at your option)
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
29
#include <sys/types.h>
35
#include <glib-object.h>
36
#include <glib/gstdio.h>
37
#include <glib/gi18n.h>
39
#include <X11/Xauth.h>
41
#include "gdm-display-access-file.h"
42
#include "gdm-common.h"
44
struct _GdmDisplayAccessFilePrivate
51
#ifndef GDM_DISPLAY_ACCESS_COOKIE_SIZE
52
#define GDM_DISPLAY_ACCESS_COOKIE_SIZE 16
59
static void gdm_display_access_file_finalize (GObject * object);
68
G_DEFINE_TYPE (GdmDisplayAccessFile, gdm_display_access_file, G_TYPE_OBJECT)
71
gdm_display_access_file_get_property (GObject *object,
76
GdmDisplayAccessFile *access_file;
78
access_file = GDM_DISPLAY_ACCESS_FILE (object);
82
g_value_set_string (value, access_file->priv->username);
86
g_value_set_string (value, access_file->priv->path);
90
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
95
gdm_display_access_file_set_property (GObject *object,
100
GdmDisplayAccessFile *access_file;
102
access_file = GDM_DISPLAY_ACCESS_FILE (object);
106
g_assert (access_file->priv->username == NULL);
107
access_file->priv->username = g_value_dup_string (value);
111
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116
gdm_display_access_file_class_init (GdmDisplayAccessFileClass *access_file_class)
118
GObjectClass *object_class;
119
GParamSpec *param_spec;
121
object_class = G_OBJECT_CLASS (access_file_class);
123
object_class->finalize = gdm_display_access_file_finalize;
124
object_class->get_property = gdm_display_access_file_get_property;
125
object_class->set_property = gdm_display_access_file_set_property;
127
param_spec = g_param_spec_string ("username",
129
"Owner of Xauthority file",
131
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
132
g_object_class_install_property (object_class, PROP_USERNAME, param_spec);
133
param_spec = g_param_spec_string ("path",
135
"Path to Xauthority file",
138
g_object_class_install_property (object_class, PROP_PATH, param_spec);
139
g_type_class_add_private (access_file_class, sizeof (GdmDisplayAccessFilePrivate));
143
gdm_display_access_file_init (GdmDisplayAccessFile *access_file)
145
access_file->priv = G_TYPE_INSTANCE_GET_PRIVATE (access_file,
146
GDM_TYPE_DISPLAY_ACCESS_FILE,
147
GdmDisplayAccessFilePrivate);
151
gdm_display_access_file_finalize (GObject *object)
153
GdmDisplayAccessFile *file;
154
GObjectClass *parent_class;
156
file = GDM_DISPLAY_ACCESS_FILE (object);
157
parent_class = G_OBJECT_CLASS (gdm_display_access_file_parent_class);
159
if (file->priv->fp != NULL) {
160
gdm_display_access_file_close (file);
162
g_assert (file->priv->path == NULL);
164
if (file->priv->username != NULL) {
165
g_free (file->priv->username);
166
file->priv->username = NULL;
167
g_object_notify (object, "username");
170
if (parent_class->finalize != NULL) {
171
parent_class->finalize (object);
176
gdm_display_access_file_error_quark (void)
178
static GQuark error_quark = 0;
180
if (error_quark == 0) {
181
error_quark = g_quark_from_static_string ("gdm-display-access-file");
187
GdmDisplayAccessFile *
188
gdm_display_access_file_new (const char *username)
190
GdmDisplayAccessFile *access_file;
191
g_return_val_if_fail (username != NULL, NULL);
193
access_file = g_object_new (GDM_TYPE_DISPLAY_ACCESS_FILE,
194
"username", username,
201
_get_uid_and_gid_for_user (const char *username,
205
struct passwd *passwd_entry;
207
g_assert (username != NULL);
208
g_assert (uid != NULL);
209
g_assert (gid != NULL);
212
passwd_entry = getpwnam (username);
214
if (passwd_entry == NULL) {
218
*uid = passwd_entry->pw_uid;
219
*gid = passwd_entry->pw_gid;
225
clean_up_stale_auth_subdirs (void)
228
const char *filename;
230
dir = g_dir_open (GDM_XAUTH_DIR, 0, NULL);
236
while ((filename = g_dir_read_name (dir)) != NULL) {
239
path = g_build_filename (GDM_XAUTH_DIR, filename, NULL);
241
/* Will only succeed if the directory is empty
250
_create_xauth_file_for_user (const char *username,
255
const char *dir_name;
262
g_assert (filename != NULL);
267
auth_filename = NULL;
271
/* Create directory if not exist, then set permission 0711 and ownership root:gdm */
272
if (g_file_test (GDM_XAUTH_DIR, G_FILE_TEST_IS_DIR) == FALSE) {
273
g_unlink (GDM_XAUTH_DIR);
274
if (g_mkdir (GDM_XAUTH_DIR, 0711) != 0) {
277
g_file_error_from_errno (errno),
278
"%s", g_strerror (errno));
282
g_chmod (GDM_XAUTH_DIR, 0711);
283
_get_uid_and_gid_for_user (GDM_USERNAME, &uid, &gid);
284
if (chown (GDM_XAUTH_DIR, 0, gid) != 0) {
285
g_warning ("Unable to change owner of '%s'",
289
/* if it does exist make sure it has correct mode 0711 */
290
g_chmod (GDM_XAUTH_DIR, 0711);
292
/* and clean up any stale auth subdirs */
293
clean_up_stale_auth_subdirs ();
296
if (!_get_uid_and_gid_for_user (username, &uid, &gid)) {
299
GDM_DISPLAY_ERROR_GETTING_USER_INFO,
300
_("could not find user \"%s\" on system"),
306
template = g_strdup_printf (GDM_XAUTH_DIR
307
"/auth-for-%s-XXXXXX",
310
g_debug ("GdmDisplayAccessFile: creating xauth directory %s", template);
311
/* Initially create with mode 01700 then later chmod after we create database */
313
dir_name = gdm_make_temp_dir (template);
314
if (dir_name == NULL) {
317
g_file_error_from_errno (errno),
318
"Unable to create temp dir from tempalte '%s': %s",
324
g_debug ("GdmDisplayAccessFile: chowning %s to %u:%u",
325
dir_name, (guint)uid, (guint)gid);
327
if (chown (dir_name, uid, gid) < 0) {
330
g_file_error_from_errno (errno),
331
"Unable to change permission of '%s': %s",
337
auth_filename = g_build_filename (dir_name, "database", NULL);
339
g_debug ("GdmDisplayAccessFile: creating %s", auth_filename);
342
fd = g_open (auth_filename,
343
O_RDWR | O_CREAT | O_EXCL | O_BINARY,
349
g_file_error_from_errno (errno),
350
"Unable to open '%s': %s",
356
g_debug ("GdmDisplayAccessFile: chowning %s to %u:%u", auth_filename, (guint)uid, (guint)gid);
358
if (fchown (fd, uid, gid) < 0) {
361
g_file_error_from_errno (errno),
362
"Unable to change owner for '%s': %s",
370
/* now open up permissions on per-session directory */
371
g_debug ("GdmDisplayAccessFile: chmoding %s to 0711", dir_name);
372
g_chmod (dir_name, 0711);
375
fp = fdopen (fd, "w");
379
g_file_error_from_errno (errno),
380
"%s", g_strerror (errno));
386
*filename = auth_filename;
387
auth_filename = NULL;
393
g_free (auth_filename);
402
gdm_display_access_file_open (GdmDisplayAccessFile *file,
405
GError *create_error;
407
g_return_val_if_fail (file != NULL, FALSE);
408
g_return_val_if_fail (file->priv->fp == NULL, FALSE);
409
g_return_val_if_fail (file->priv->path == NULL, FALSE);
412
file->priv->fp = _create_xauth_file_for_user (file->priv->username,
416
if (file->priv->fp == NULL) {
417
g_propagate_error (error, create_error);
425
_get_auth_info_for_display (GdmDisplayAccessFile *file,
427
unsigned short *family,
428
unsigned short *address_length,
430
unsigned short *number_length,
432
unsigned short *name_length,
438
gdm_display_is_local (display, &is_local, NULL);
441
char localhost[HOST_NAME_MAX + 1] = "";
442
*family = FamilyLocal;
443
if (gethostname (localhost, HOST_NAME_MAX) == 0) {
444
*address = g_strdup (localhost);
446
*address = g_strdup ("localhost");
449
*family = FamilyWild;
450
gdm_display_get_remote_hostname (display, address, NULL);
452
*address_length = strlen (*address);
454
gdm_display_get_x11_display_number (display, &display_number, NULL);
455
*number = g_strdup_printf ("%d", display_number);
456
*number_length = strlen (*number);
458
*name = g_strdup ("MIT-MAGIC-COOKIE-1");
459
*name_length = strlen (*name);
463
gdm_display_access_file_add_display (GdmDisplayAccessFile *file,
470
gboolean display_added;
472
g_return_val_if_fail (file != NULL, FALSE);
473
g_return_val_if_fail (file->priv->path != NULL, FALSE);
474
g_return_val_if_fail (cookie != NULL, FALSE);
477
*cookie = gdm_generate_random_bytes (GDM_DISPLAY_ACCESS_COOKIE_SIZE,
480
if (*cookie == NULL) {
481
g_propagate_error (error, add_error);
485
*cookie_size = GDM_DISPLAY_ACCESS_COOKIE_SIZE;
487
display_added = gdm_display_access_file_add_display_with_cookie (file, display,
491
if (!display_added) {
494
g_propagate_error (error, add_error);
502
gdm_display_access_file_add_display_with_cookie (GdmDisplayAccessFile *file,
509
gboolean display_added;
511
g_return_val_if_fail (file != NULL, FALSE);
512
g_return_val_if_fail (file->priv->path != NULL, FALSE);
513
g_return_val_if_fail (cookie != NULL, FALSE);
515
_get_auth_info_for_display (file, display,
517
&auth_entry.address_length,
519
&auth_entry.number_length,
521
&auth_entry.name_length,
524
auth_entry.data = (char *) cookie;
525
auth_entry.data_length = cookie_size;
527
/* FIXME: We should lock the file in case the X server is
528
* trying to use it, too.
530
if (!XauWriteAuth (file->priv->fp, &auth_entry)
531
|| fflush (file->priv->fp) == EOF) {
534
g_file_error_from_errno (errno),
535
"%s", g_strerror (errno));
536
display_added = FALSE;
538
display_added = TRUE;
542
g_free (auth_entry.address);
543
g_free (auth_entry.number);
544
g_free (auth_entry.name);
546
return display_added;
550
gdm_display_access_file_remove_display (GdmDisplayAccessFile *file,
555
unsigned short family;
556
unsigned short address_length;
558
unsigned short number_length;
560
unsigned short name_length;
564
g_return_val_if_fail (file != NULL, FALSE);
565
g_return_val_if_fail (file->priv->path != NULL, FALSE);
567
_get_auth_info_for_display (file, display,
576
auth_entry = XauGetAuthByAddr (family,
587
if (auth_entry == NULL) {
589
GDM_DISPLAY_ACCESS_FILE_ERROR,
590
GDM_DISPLAY_ACCESS_FILE_ERROR_FINDING_AUTH_ENTRY,
591
"could not find authorization entry");
595
XauDisposeAuth (auth_entry);
597
if (fflush (file->priv->fp) == EOF) {
600
g_file_error_from_errno (errno),
601
"%s", g_strerror (errno));
609
gdm_display_access_file_close (GdmDisplayAccessFile *file)
613
g_return_if_fail (file != NULL);
614
g_return_if_fail (file->priv->fp != NULL);
615
g_return_if_fail (file->priv->path != NULL);
618
if (g_unlink (file->priv->path) != 0) {
619
g_warning ("GdmDisplayAccessFile: Unable to remove X11 authority database '%s': %s",
624
/* still try to remove dir even if file remove failed,
625
may have already been removed by someone else */
626
/* we own the parent directory too */
627
auth_dir = g_path_get_dirname (file->priv->path);
628
if (auth_dir != NULL) {
630
if (g_rmdir (auth_dir) != 0) {
631
g_warning ("GdmDisplayAccessFile: Unable to remove X11 authority directory '%s': %s",
638
g_free (file->priv->path);
639
file->priv->path = NULL;
640
g_object_notify (G_OBJECT (file), "path");
642
fclose (file->priv->fp);
643
file->priv->fp = NULL;
647
gdm_display_access_file_get_path (GdmDisplayAccessFile *access_file)
649
return g_strdup (access_file->priv->path);