Line data Source code
1 : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : /* gkr-daemon-util.c - Helper utilities for the daemon
3 :
4 : Copyright (C) 2007, Stefan Walter
5 :
6 : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Library General Public License as
8 : published by the Free Software Foundation; either version 2 of the
9 : License, or (at your option) any later version.
10 :
11 : The Gnome Keyring Library 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 GNU
14 : Library General Public License for more details.
15 :
16 : You should have received a copy of the GNU Library General Public
17 : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : <http://www.gnu.org/licenses/>.
19 :
20 : Author: Stef Walter <stef@memberwebs.com>
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkd-util.h"
26 :
27 : #include "egg/egg-cleanup.h"
28 : #include "egg/egg-unix-credentials.h"
29 :
30 : #include <glib.h>
31 :
32 : #include <sys/stat.h>
33 :
34 : #include <errno.h>
35 : #include <stdlib.h>
36 : #include <string.h>
37 : #include <unistd.h>
38 :
39 : /*
40 : * A list of all the environment variables the daemon can
41 : * possibly send out when it starts.
42 : */
43 : const gchar *GKD_UTIL_OUT_ENVIRONMENT[] = {
44 : "SSH_AUTH_SOCK",
45 : "GNOME_KEYRING_CONTROL",
46 : "SSH_AGENT_PID",
47 : NULL
48 : };
49 :
50 : /*
51 : * A list of all the environment variables the daemon
52 : * is interested in from clients if it was started
53 : * early before these environment variables were set.
54 : */
55 : const gchar *GKD_UTIL_IN_ENVIRONMENT[] = {
56 : "DBUS_SESSION_BUS_ADDRESS",
57 : "DESKTOP_AUTOSTART_ID",
58 : "LANG",
59 : "XDG_RUNTIME_DIR",
60 : "LOGNAME",
61 : "USERNAME",
62 : NULL
63 : };
64 :
65 : static gchar* master_directory = NULL;
66 : static GArray* published_environ = NULL;
67 :
68 : static GFunc watch_environ = NULL;
69 : static gpointer watch_user_data = NULL;
70 : static GDestroyNotify watch_destroy_notify = NULL;
71 :
72 : static void
73 27 : uninit_master_directory (gpointer data)
74 : {
75 27 : g_assert (master_directory);
76 27 : rmdir (master_directory);
77 27 : g_free (master_directory);
78 27 : master_directory = NULL;
79 27 : }
80 :
81 : static gboolean
82 29 : validate_master_directory (const gchar *directory,
83 : gboolean *exists)
84 : {
85 : struct stat st;
86 :
87 29 : if (lstat (directory, &st) < 0) {
88 22 : if (errno == ENOTDIR || errno == ENOENT) {
89 21 : *exists = FALSE;
90 21 : return TRUE;
91 : }
92 1 : g_message ("The gnome-keyring control directory cannot be accessed: %s: %s",
93 : directory, g_strerror (errno));
94 1 : return FALSE;
95 7 : } else if (st.st_uid != geteuid ()) {
96 0 : g_message ("The gnome-keyring control directory is not owned with the same "
97 : "credentials as the user login: %s", directory);
98 0 : return FALSE;
99 7 : } else if ((st.st_mode & 0777) != 0700) {
100 1 : g_message ("The gnome-keyring control directory has invalid permissions. It "
101 : "must be only be accessible by its owner (ie: 0700): %s", directory);
102 1 : return FALSE;
103 : } else {
104 6 : *exists = TRUE;
105 6 : return TRUE;
106 : }
107 : }
108 :
109 : void
110 27 : gkd_util_init_master_directory (const gchar *replace)
111 : {
112 27 : gboolean exists = FALSE;
113 27 : gboolean is_default = FALSE;
114 :
115 27 : g_free (master_directory);
116 27 : master_directory = NULL;
117 :
118 27 : if (replace && validate_master_directory (replace, &exists)) {
119 22 : master_directory = g_strdup (replace);
120 :
121 : /* Only use default directory if it has an predictable explicit path */
122 5 : } else if (g_getenv ("XDG_RUNTIME_DIR")) {
123 5 : master_directory = g_build_filename (g_get_user_runtime_dir (), "keyring", NULL);
124 5 : if (validate_master_directory (master_directory, &exists)) {
125 5 : is_default = TRUE;
126 : } else {
127 0 : g_free (master_directory);
128 0 : master_directory = NULL;
129 : }
130 : }
131 :
132 : /* No directory yet, make one up */
133 27 : if (!master_directory) {
134 0 : master_directory = g_build_filename (g_get_user_runtime_dir (), "keyring-XXXXXX", NULL);
135 0 : if (g_mkdtemp (master_directory) == NULL) {
136 0 : g_warning ("couldn't create socket directory: %s: %s",
137 : master_directory, g_strerror (errno));
138 : }
139 0 : exists = TRUE;
140 : }
141 :
142 : /* A directory was supplied, but doesn't exist yet */
143 27 : if (!exists) {
144 21 : if (g_mkdir_with_parents (master_directory, 0700) < 0) {
145 0 : g_warning ("couldn't create socket directory: %s: %s",
146 : master_directory, g_strerror (errno));
147 : }
148 : }
149 :
150 27 : if (!is_default)
151 22 : gkd_util_push_environment (GKD_UTIL_ENV_CONTROL, master_directory);
152 27 : egg_cleanup_register (uninit_master_directory, NULL);
153 27 : }
154 :
155 : const gchar*
156 38 : gkd_util_get_master_directory (void)
157 : {
158 38 : g_return_val_if_fail (master_directory, NULL);
159 38 : return master_directory;
160 : }
161 :
162 : static void
163 27 : uninit_environment (gpointer data)
164 : {
165 : guint i;
166 :
167 27 : if (published_environ) {
168 49 : for (i = 0; i < published_environ->len; ++i)
169 22 : g_free (g_array_index (published_environ, gchar*, i));
170 27 : g_array_free (published_environ, TRUE);
171 : }
172 :
173 27 : published_environ = NULL;
174 :
175 27 : if (watch_destroy_notify && watch_user_data)
176 27 : (watch_destroy_notify) (watch_user_data);
177 27 : watch_user_data = NULL;
178 27 : watch_destroy_notify = NULL;
179 27 : watch_environ = NULL;
180 27 : }
181 :
182 : static void
183 76 : init_environment ()
184 : {
185 76 : if (published_environ)
186 49 : return;
187 27 : published_environ = g_array_new (TRUE, TRUE, sizeof (gchar*));
188 27 : egg_cleanup_register (uninit_environment, NULL);
189 : }
190 :
191 : void
192 22 : gkd_util_push_environment (const gchar *name, const gchar *value)
193 : {
194 : gchar *env;
195 :
196 22 : init_environment ();
197 :
198 22 : env = g_strdup_printf ("%s=%s", name, value);
199 22 : g_array_append_val (published_environ, env);
200 :
201 22 : if (watch_environ)
202 0 : (watch_environ) (env, watch_user_data);
203 22 : }
204 :
205 : void
206 0 : gkd_util_push_environment_full (const gchar *var)
207 : {
208 : gchar *env;
209 :
210 0 : g_return_if_fail (strchr (var, '=') != NULL);
211 0 : init_environment ();
212 :
213 0 : env = g_strdup (var);
214 0 : g_array_append_val (published_environ, env);
215 :
216 0 : if (watch_environ)
217 0 : (watch_environ) (env, watch_user_data);
218 : }
219 :
220 : const gchar**
221 54 : gkd_util_get_environment (void)
222 : {
223 54 : init_environment ();
224 54 : return (const gchar**)published_environ->data;
225 : }
226 :
227 : void
228 27 : gkd_util_watch_environment (GFunc func, gpointer user_data,
229 : GDestroyNotify destroy_notify)
230 : {
231 27 : g_return_if_fail (func);
232 27 : g_return_if_fail (!watch_environ);
233 :
234 27 : watch_environ = func;
235 27 : watch_user_data = user_data;
236 27 : watch_destroy_notify = destroy_notify;
237 : }
238 :
239 : gchar**
240 0 : gkd_util_build_environment (const gchar **names)
241 : {
242 0 : GArray *array = g_array_sized_new (TRUE, TRUE, sizeof (gchar*), 8);
243 : const gchar *value;
244 : const gchar **name;
245 : gchar *env;
246 :
247 : /* Transform them into NAME=VALUE pairs */
248 0 : for (name = names; *name; ++name) {
249 0 : value = g_getenv (*name);
250 0 : if (value) {
251 0 : env = g_strdup_printf ("%s=%s", *name, value);
252 0 : g_array_append_val (array, env);
253 : }
254 : }
255 :
256 0 : return (gchar**)g_array_free (array, FALSE);
257 : }
|