Lines 1-490
Link Here
|
1 |
/* |
|
|
2 |
* Copyright (C) 2011 Red Hat, Inc. |
3 |
* |
4 |
* This library is free software; you can redistribute it and/or |
5 |
* modify it under the terms of the GNU Lesser General Public |
6 |
* License as published by the Free Software Foundation; either |
7 |
* version 2 of the License, or (at your option) any later version. |
8 |
* |
9 |
* This library is distributed in the hope that it will be useful, |
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 |
* Lesser General Public License for more details. |
13 |
* |
14 |
* You should have received a copy of the GNU Lesser General |
15 |
* Public License along with this library; if not, write to the |
16 |
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
17 |
* Boston, MA 02111-1307, USA. |
18 |
* |
19 |
* Author: Matthias Clasen |
20 |
*/ |
21 |
|
22 |
#ifdef HAVE_CONFIG_H |
23 |
# include "config.h" |
24 |
#endif |
25 |
|
26 |
#include <stdlib.h> |
27 |
#include <string.h> |
28 |
#include "polkitunixsession.h" |
29 |
#include "polkitsubject.h" |
30 |
#include "polkiterror.h" |
31 |
#include "polkitprivate.h" |
32 |
|
33 |
#include <systemd/sd-login.h> |
34 |
|
35 |
/** |
36 |
* SECTION:polkitunixsession |
37 |
* @title: PolkitUnixSession |
38 |
* @short_description: Unix sessions |
39 |
* |
40 |
* An object that represents an user session. |
41 |
* |
42 |
* The session id is an opaque string obtained from ConsoleKit. |
43 |
*/ |
44 |
|
45 |
/** |
46 |
* PolkitUnixSession: |
47 |
* |
48 |
* The #PolkitUnixSession struct should not be accessed directly. |
49 |
*/ |
50 |
struct _PolkitUnixSession |
51 |
{ |
52 |
GObject parent_instance; |
53 |
|
54 |
gchar *session_id; |
55 |
|
56 |
gint pid; |
57 |
}; |
58 |
|
59 |
struct _PolkitUnixSessionClass |
60 |
{ |
61 |
GObjectClass parent_class; |
62 |
}; |
63 |
|
64 |
enum |
65 |
{ |
66 |
PROP_0, |
67 |
PROP_SESSION_ID, |
68 |
PROP_PID, |
69 |
}; |
70 |
|
71 |
static void subject_iface_init (PolkitSubjectIface *subject_iface); |
72 |
static void initable_iface_init (GInitableIface *initable_iface); |
73 |
static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); |
74 |
|
75 |
G_DEFINE_TYPE_WITH_CODE (PolkitUnixSession, polkit_unix_session, G_TYPE_OBJECT, |
76 |
G_IMPLEMENT_INTERFACE (POLKIT_TYPE_SUBJECT, subject_iface_init) |
77 |
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init) |
78 |
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init) |
79 |
); |
80 |
|
81 |
static void |
82 |
polkit_unix_session_init (PolkitUnixSession *session) |
83 |
{ |
84 |
} |
85 |
|
86 |
static void |
87 |
polkit_unix_session_finalize (GObject *object) |
88 |
{ |
89 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (object); |
90 |
|
91 |
g_free (session->session_id); |
92 |
|
93 |
if (G_OBJECT_CLASS (polkit_unix_session_parent_class)->finalize != NULL) |
94 |
G_OBJECT_CLASS (polkit_unix_session_parent_class)->finalize (object); |
95 |
} |
96 |
|
97 |
static void |
98 |
polkit_unix_session_get_property (GObject *object, |
99 |
guint prop_id, |
100 |
GValue *value, |
101 |
GParamSpec *pspec) |
102 |
{ |
103 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (object); |
104 |
|
105 |
switch (prop_id) |
106 |
{ |
107 |
case PROP_SESSION_ID: |
108 |
g_value_set_string (value, session->session_id); |
109 |
break; |
110 |
|
111 |
default: |
112 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
113 |
break; |
114 |
} |
115 |
} |
116 |
|
117 |
static void |
118 |
polkit_unix_session_set_property (GObject *object, |
119 |
guint prop_id, |
120 |
const GValue *value, |
121 |
GParamSpec *pspec) |
122 |
{ |
123 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (object); |
124 |
|
125 |
switch (prop_id) |
126 |
{ |
127 |
case PROP_SESSION_ID: |
128 |
polkit_unix_session_set_session_id (session, g_value_get_string (value)); |
129 |
break; |
130 |
|
131 |
case PROP_PID: |
132 |
session->pid = g_value_get_int (value); |
133 |
break; |
134 |
|
135 |
default: |
136 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
137 |
break; |
138 |
} |
139 |
} |
140 |
|
141 |
static void |
142 |
polkit_unix_session_class_init (PolkitUnixSessionClass *klass) |
143 |
{ |
144 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
145 |
|
146 |
gobject_class->finalize = polkit_unix_session_finalize; |
147 |
gobject_class->get_property = polkit_unix_session_get_property; |
148 |
gobject_class->set_property = polkit_unix_session_set_property; |
149 |
|
150 |
/** |
151 |
* PolkitUnixSession:session-id: |
152 |
* |
153 |
* The UNIX session id. |
154 |
*/ |
155 |
g_object_class_install_property (gobject_class, |
156 |
PROP_SESSION_ID, |
157 |
g_param_spec_string ("session-id", |
158 |
"Session ID", |
159 |
"The UNIX session ID", |
160 |
NULL, |
161 |
G_PARAM_CONSTRUCT | |
162 |
G_PARAM_READWRITE | |
163 |
G_PARAM_STATIC_NAME | |
164 |
G_PARAM_STATIC_BLURB | |
165 |
G_PARAM_STATIC_NICK)); |
166 |
|
167 |
|
168 |
/** |
169 |
* PolkitUnixSession:pid: |
170 |
* |
171 |
* The UNIX process id to look up the session. |
172 |
*/ |
173 |
g_object_class_install_property (gobject_class, |
174 |
PROP_PID, |
175 |
g_param_spec_int ("pid", |
176 |
"Process ID", |
177 |
"Process ID to use for looking up the session", |
178 |
0, |
179 |
G_MAXINT, |
180 |
0, |
181 |
G_PARAM_CONSTRUCT_ONLY | |
182 |
G_PARAM_WRITABLE | |
183 |
G_PARAM_STATIC_NAME | |
184 |
G_PARAM_STATIC_BLURB | |
185 |
G_PARAM_STATIC_NICK)); |
186 |
|
187 |
} |
188 |
|
189 |
/** |
190 |
* polkit_unix_session_get_session_id: |
191 |
* @session: A #PolkitUnixSession. |
192 |
* |
193 |
* Gets the session id for @session. |
194 |
* |
195 |
* Returns: The session id for @session. Do not free this string, it |
196 |
* is owned by @session. |
197 |
**/ |
198 |
const gchar * |
199 |
polkit_unix_session_get_session_id (PolkitUnixSession *session) |
200 |
{ |
201 |
g_return_val_if_fail (POLKIT_IS_UNIX_SESSION (session), NULL); |
202 |
return session->session_id; |
203 |
} |
204 |
|
205 |
/** |
206 |
* polkit_unix_session_set_session_id: |
207 |
* @session: A #PolkitUnixSession. |
208 |
* @session_id: The session id. |
209 |
* |
210 |
* Sets the session id for @session to @session_id. |
211 |
**/ |
212 |
void |
213 |
polkit_unix_session_set_session_id (PolkitUnixSession *session, |
214 |
const gchar *session_id) |
215 |
{ |
216 |
g_return_if_fail (POLKIT_IS_UNIX_SESSION (session)); |
217 |
/*g_return_if_fail (session_id != NULL);*/ |
218 |
g_free (session->session_id); |
219 |
session->session_id = g_strdup (session_id); |
220 |
} |
221 |
|
222 |
/** |
223 |
* polkit_unix_session_new: |
224 |
* @session_id: The session id. |
225 |
* |
226 |
* Creates a new #PolkitUnixSession for @session_id. |
227 |
* |
228 |
* Returns: (transfer full): A #PolkitUnixSession. Free with g_object_unref(). |
229 |
**/ |
230 |
PolkitSubject * |
231 |
polkit_unix_session_new (const gchar *session_id) |
232 |
{ |
233 |
return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_SESSION, |
234 |
"session-id", session_id, |
235 |
NULL)); |
236 |
} |
237 |
|
238 |
/** |
239 |
* polkit_unix_session_new_for_process: |
240 |
* @pid: The process id of the process to get the session for. |
241 |
* @cancellable: (allow-none): A #GCancellable or %NULL. |
242 |
* @callback: A #GAsyncReadyCallback to call when the request is satisfied |
243 |
* @user_data: The data to pass to @callback. |
244 |
* |
245 |
* Asynchronously creates a new #PolkitUnixSession object for the |
246 |
* process with process id @pid. |
247 |
* |
248 |
* When the operation is finished, @callback will be invoked in the |
249 |
* <link linkend="g-main-context-push-thread-default">thread-default |
250 |
* main loop</link> of the thread you are calling this method |
251 |
* from. You can then call |
252 |
* polkit_unix_session_new_for_process_finish() to get the result of |
253 |
* the operation. |
254 |
* |
255 |
* This method constructs the object asynchronously, for the synchronous and blocking version |
256 |
* use polkit_unix_session_new_for_process_sync(). |
257 |
**/ |
258 |
void |
259 |
polkit_unix_session_new_for_process (gint pid, |
260 |
GCancellable *cancellable, |
261 |
GAsyncReadyCallback callback, |
262 |
gpointer user_data) |
263 |
{ |
264 |
g_async_initable_new_async (POLKIT_TYPE_UNIX_SESSION, |
265 |
G_PRIORITY_DEFAULT, |
266 |
cancellable, |
267 |
callback, |
268 |
user_data, |
269 |
"pid", pid, |
270 |
NULL); |
271 |
} |
272 |
|
273 |
/** |
274 |
* polkit_unix_session_new_for_process_finish: |
275 |
* @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to polkit_unix_session_new_for_process(). |
276 |
* @error: (allow-none): Return location for error. |
277 |
* |
278 |
* Finishes constructing a #PolkitSubject for a process id. |
279 |
* |
280 |
* Returns: (transfer full) (allow-none): A #PolkitUnixSession for the @pid passed to |
281 |
* polkit_unix_session_new_for_process() or %NULL if @error is |
282 |
* set. Free with g_object_unref(). |
283 |
**/ |
284 |
PolkitSubject * |
285 |
polkit_unix_session_new_for_process_finish (GAsyncResult *res, |
286 |
GError **error) |
287 |
{ |
288 |
GObject *object; |
289 |
GObject *source_object; |
290 |
|
291 |
source_object = g_async_result_get_source_object (res); |
292 |
g_assert (source_object != NULL); |
293 |
|
294 |
object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), |
295 |
res, |
296 |
error); |
297 |
g_object_unref (source_object); |
298 |
|
299 |
if (object != NULL) |
300 |
return POLKIT_SUBJECT (object); |
301 |
else |
302 |
return NULL; |
303 |
} |
304 |
|
305 |
|
306 |
/** |
307 |
* polkit_unix_session_new_for_process_sync: |
308 |
* @pid: The process id of the process to get the session for. |
309 |
* @cancellable: (allow-none): A #GCancellable or %NULL. |
310 |
* @error: (allow-none): Return location for error. |
311 |
* |
312 |
* Creates a new #PolkitUnixSession for the process with process id @pid. |
313 |
* |
314 |
* This is a synchronous call - the calling thread is blocked until a |
315 |
* reply is received. For the asynchronous version, see |
316 |
* polkit_unix_session_new_for_process(). |
317 |
* |
318 |
* Returns: (allow-none) (transfer full): A #PolkitUnixSession for |
319 |
* @pid or %NULL if @error is set. Free with g_object_unref(). |
320 |
**/ |
321 |
PolkitSubject * |
322 |
polkit_unix_session_new_for_process_sync (gint pid, |
323 |
GCancellable *cancellable, |
324 |
GError **error) |
325 |
{ |
326 |
return POLKIT_SUBJECT (g_initable_new (POLKIT_TYPE_UNIX_SESSION, |
327 |
cancellable, |
328 |
error, |
329 |
"pid", pid, |
330 |
NULL)); |
331 |
} |
332 |
|
333 |
static guint |
334 |
polkit_unix_session_hash (PolkitSubject *subject) |
335 |
{ |
336 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject); |
337 |
|
338 |
return g_str_hash (session->session_id); |
339 |
} |
340 |
|
341 |
static gboolean |
342 |
polkit_unix_session_equal (PolkitSubject *a, |
343 |
PolkitSubject *b) |
344 |
{ |
345 |
PolkitUnixSession *session_a; |
346 |
PolkitUnixSession *session_b; |
347 |
|
348 |
session_a = POLKIT_UNIX_SESSION (a); |
349 |
session_b = POLKIT_UNIX_SESSION (b); |
350 |
|
351 |
return g_strcmp0 (session_a->session_id, session_b->session_id) == 0; |
352 |
} |
353 |
|
354 |
static gchar * |
355 |
polkit_unix_session_to_string (PolkitSubject *subject) |
356 |
{ |
357 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject); |
358 |
|
359 |
return g_strdup_printf ("unix-session:%s", session->session_id); |
360 |
} |
361 |
|
362 |
static gboolean |
363 |
polkit_unix_session_exists_sync (PolkitSubject *subject, |
364 |
GCancellable *cancellable, |
365 |
GError **error) |
366 |
{ |
367 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (subject); |
368 |
gboolean ret = FALSE; |
369 |
uid_t uid; |
370 |
|
371 |
if (sd_session_get_uid (session->session_id, &uid) == 0) |
372 |
ret = TRUE; |
373 |
|
374 |
return ret; |
375 |
} |
376 |
|
377 |
static void |
378 |
exists_in_thread_func (GSimpleAsyncResult *res, |
379 |
GObject *object, |
380 |
GCancellable *cancellable) |
381 |
{ |
382 |
GError *error; |
383 |
error = NULL; |
384 |
if (!polkit_unix_session_exists_sync (POLKIT_SUBJECT (object), |
385 |
cancellable, |
386 |
&error)) |
387 |
{ |
388 |
g_simple_async_result_set_from_error (res, error); |
389 |
g_error_free (error); |
390 |
} |
391 |
} |
392 |
|
393 |
static void |
394 |
polkit_unix_session_exists (PolkitSubject *subject, |
395 |
GCancellable *cancellable, |
396 |
GAsyncReadyCallback callback, |
397 |
gpointer user_data) |
398 |
{ |
399 |
GSimpleAsyncResult *simple; |
400 |
|
401 |
g_return_if_fail (POLKIT_IS_UNIX_SESSION (subject)); |
402 |
|
403 |
simple = g_simple_async_result_new (G_OBJECT (subject), |
404 |
callback, |
405 |
user_data, |
406 |
polkit_unix_session_exists); |
407 |
g_simple_async_result_run_in_thread (simple, |
408 |
exists_in_thread_func, |
409 |
G_PRIORITY_DEFAULT, |
410 |
cancellable); |
411 |
g_object_unref (simple); |
412 |
} |
413 |
|
414 |
static gboolean |
415 |
polkit_unix_session_exists_finish (PolkitSubject *subject, |
416 |
GAsyncResult *res, |
417 |
GError **error) |
418 |
{ |
419 |
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); |
420 |
gboolean ret; |
421 |
|
422 |
g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_unix_session_exists); |
423 |
|
424 |
ret = FALSE; |
425 |
|
426 |
if (g_simple_async_result_propagate_error (simple, error)) |
427 |
goto out; |
428 |
|
429 |
ret = g_simple_async_result_get_op_res_gboolean (simple); |
430 |
|
431 |
out: |
432 |
return ret; |
433 |
} |
434 |
|
435 |
static void |
436 |
subject_iface_init (PolkitSubjectIface *subject_iface) |
437 |
{ |
438 |
subject_iface->hash = polkit_unix_session_hash; |
439 |
subject_iface->equal = polkit_unix_session_equal; |
440 |
subject_iface->to_string = polkit_unix_session_to_string; |
441 |
subject_iface->exists = polkit_unix_session_exists; |
442 |
subject_iface->exists_finish = polkit_unix_session_exists_finish; |
443 |
subject_iface->exists_sync = polkit_unix_session_exists_sync; |
444 |
} |
445 |
|
446 |
static gboolean |
447 |
polkit_unix_session_initable_init (GInitable *initable, |
448 |
GCancellable *cancellable, |
449 |
GError **error) |
450 |
{ |
451 |
PolkitUnixSession *session = POLKIT_UNIX_SESSION (initable); |
452 |
gboolean ret = FALSE; |
453 |
char *s; |
454 |
|
455 |
if (session->session_id != NULL) |
456 |
{ |
457 |
/* already set, nothing to do */ |
458 |
ret = TRUE; |
459 |
goto out; |
460 |
} |
461 |
|
462 |
if (sd_pid_get_session (session->pid, &s) == 0) |
463 |
{ |
464 |
session->session_id = g_strdup (s); |
465 |
free (s); |
466 |
ret = TRUE; |
467 |
goto out; |
468 |
} |
469 |
|
470 |
g_set_error (error, |
471 |
POLKIT_ERROR, |
472 |
POLKIT_ERROR_FAILED, |
473 |
"No session for pid %d", |
474 |
(gint) session->pid); |
475 |
|
476 |
out: |
477 |
return ret; |
478 |
} |
479 |
|
480 |
static void |
481 |
initable_iface_init (GInitableIface *initable_iface) |
482 |
{ |
483 |
initable_iface->init = polkit_unix_session_initable_init; |
484 |
} |
485 |
|
486 |
static void |
487 |
async_initable_iface_init (GAsyncInitableIface *async_initable_iface) |
488 |
{ |
489 |
/* use default implementation to run GInitable code in a thread */ |
490 |
} |