source: proiecte/PPPP/gdm/daemon/ck-connector.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 23.5 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * ck-connector.c : Code for login managers to register with ConsoleKit.
4 *
5 * Copyright (c) 2007 David Zeuthen <davidz@redhat.com>
6 * Copyright (c) 2007 William Jon McCann <mccann@jhu.edu>
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following
15 * conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <sys/types.h>
35#include <dbus/dbus.h>
36
37#include "ck-connector.h"
38
39#define N_ELEMENTS(arr)             (sizeof (arr) / sizeof ((arr)[0]))
40
41#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
42#define _CK_FUNCTION_NAME __func__
43#elif defined(__GNUC__) || defined(_MSC_VER)
44#define _CK_FUNCTION_NAME __FUNCTION__
45#else
46#define _CK_FUNCTION_NAME "unknown function"
47#endif
48
49#define CK_CONNECTOR_ERROR "org.freedesktop.CkConnector.Error"
50
51#define _CK_WARNING_FORMAT "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
52#define _ck_return_if_fail(condition) do {                                         \
53  if (!(condition)) {                                                              \
54          fprintf (stderr, _CK_WARNING_FORMAT, _CK_FUNCTION_NAME, #condition, __FILE__, __LINE__); \
55    return;                                                                        \
56  } } while (0)
57
58#define _ck_return_val_if_fail(condition, val) do {                                     \
59  if (!(condition)) {                                                              \
60          fprintf (stderr, _CK_WARNING_FORMAT, _CK_FUNCTION_NAME, #condition, __FILE__, __LINE__); \
61    return val;                                                                        \
62  } } while (0)
63
64struct _CkConnector
65{
66        int             refcount;
67        char           *cookie;
68        dbus_bool_t     session_created;
69        DBusConnection *connection;
70};
71
72static struct {
73        char *name;
74        int   type;
75} parameter_lookup[] = {
76        { "display-device",     DBUS_TYPE_STRING },
77        { "x11-display-device", DBUS_TYPE_STRING },
78        { "x11-display",        DBUS_TYPE_STRING },
79        { "remote-host-name",   DBUS_TYPE_STRING },
80        { "session-type",       DBUS_TYPE_STRING },
81        { "is-local",           DBUS_TYPE_BOOLEAN },
82        { "unix-user",          DBUS_TYPE_INT32 },
83};
84
85static int
86lookup_parameter_type (const char *name)
87{
88        int i;
89        int type;
90
91        type = DBUS_TYPE_INVALID;
92
93        for (i = 0; i < N_ELEMENTS (parameter_lookup); i++) {
94                if (strcmp (name, parameter_lookup[i].name) == 0) {
95                        type = parameter_lookup[i].type;
96                        break;
97                }
98        }
99
100        return type;
101}
102
103static dbus_bool_t
104add_param_basic (DBusMessageIter *iter_array,
105                 const char      *name,
106                 int              type,
107                 const void      *value)
108{
109        DBusMessageIter iter_struct;
110        DBusMessageIter iter_variant;
111        const char     *container_type;
112
113        switch (type) {
114        case DBUS_TYPE_STRING:
115                container_type = DBUS_TYPE_STRING_AS_STRING;
116                break;
117        case DBUS_TYPE_BOOLEAN:
118                container_type = DBUS_TYPE_BOOLEAN_AS_STRING;
119                break;
120        case DBUS_TYPE_INT32:
121                container_type = DBUS_TYPE_INT32_AS_STRING;
122                break;
123        default:
124                goto oom;
125                break;
126        }
127
128        if (! dbus_message_iter_open_container (iter_array,
129                                                DBUS_TYPE_STRUCT,
130                                                NULL,
131                                                &iter_struct)) {
132                goto oom;
133        }
134
135        if (! dbus_message_iter_append_basic (&iter_struct,
136                                              DBUS_TYPE_STRING,
137                                              &name)) {
138                goto oom;
139        }
140
141        if (! dbus_message_iter_open_container (&iter_struct,
142                                                DBUS_TYPE_VARIANT,
143                                                container_type,
144                                                &iter_variant)) {
145                goto oom;
146        }
147
148        if (! dbus_message_iter_append_basic (&iter_variant,
149                                              type,
150                                              value)) {
151                goto oom;
152        }
153
154        if (! dbus_message_iter_close_container (&iter_struct,
155                                                 &iter_variant)) {
156                goto oom;
157        }
158
159        if (! dbus_message_iter_close_container (iter_array,
160                                                 &iter_struct)) {
161                goto oom;
162        }
163
164        return TRUE;
165oom:
166        return FALSE;
167}
168
169/* Frees all resources allocated and disconnects from the system
170 * message bus.
171 */
172static void
173_ck_connector_free (CkConnector *connector)
174{
175        if (connector->connection != NULL) {
176                /* it's a private connection so it's all good */
177                dbus_connection_close (connector->connection);
178        }
179
180        if (connector->cookie != NULL) {
181                free (connector->cookie);
182        }
183
184        free (connector);
185}
186
187/**
188 * Decrements the reference count of a CkConnector, disconnecting
189 * from the bus and freeing the connector if the count reaches 0.
190 *
191 * @param connector the connector
192 * @see ck_connector_ref
193 */
194void
195ck_connector_unref (CkConnector *connector)
196{
197        _ck_return_if_fail (connector != NULL);
198
199        /* Probably should use some kind of atomic op here */
200        connector->refcount -= 1;
201        if (connector->refcount == 0) {
202                _ck_connector_free (connector);
203        }
204}
205
206/**
207 * Increments the reference count of a CkConnector.
208 *
209 * @param connector the connector
210 * @returns the connector
211 * @see ck_connector_unref
212 */
213CkConnector *
214ck_connector_ref (CkConnector *connector)
215{
216        _ck_return_val_if_fail (connector != NULL, NULL);
217
218        /* Probably should use some kind of atomic op here */
219        connector->refcount += 1;
220
221        return connector;
222}
223
224/**
225 * Constructs a new Connector to communicate with the ConsoleKit
226 * daemon. Returns #NULL if memory can't be allocated for the
227 * object.
228 *
229 * @returns a new CkConnector, free with ck_connector_unref()
230 */
231CkConnector *
232ck_connector_new (void)
233{
234        CkConnector *connector;
235
236        connector = calloc (1, sizeof (CkConnector));
237        if (connector == NULL) {
238                goto oom;
239        }
240
241        connector->refcount = 1;
242        connector->connection = NULL;
243        connector->cookie = NULL;
244        connector->session_created = FALSE;
245oom:
246        return connector;
247}
248
249/**
250 * Connects to the D-Bus system bus daemon and issues the method call
251 * OpenSession on the ConsoleKit manager interface. The
252 * connection to the bus is private.
253 *
254 * Returns FALSE on OOM, if the system bus daemon is not running, if
255 * the ConsoleKit daemon is not running or if the caller doesn't have
256 * sufficient privileges.
257 *
258 * @returns #TRUE if the operation succeeds
259 */
260dbus_bool_t
261ck_connector_open_session (CkConnector *connector,
262                           DBusError   *error)
263{
264        DBusError    local_error;
265        DBusMessage *message;
266        DBusMessage *reply;
267        dbus_bool_t  ret;
268        char        *cookie;
269
270        _ck_return_val_if_fail (connector != NULL, FALSE);
271        _ck_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), FALSE);
272
273        reply = NULL;
274        message = NULL;
275        ret = FALSE;
276
277        dbus_error_init (&local_error);
278        connector->connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &local_error);
279        if (connector->connection == NULL) {
280                if (dbus_error_is_set (&local_error)) {
281                        dbus_set_error (error,
282                                        CK_CONNECTOR_ERROR,
283                                        "Unable to open session: %s",
284                                        local_error.message);
285                        dbus_error_free (&local_error);
286                }
287
288                goto out;
289        }
290
291        dbus_connection_set_exit_on_disconnect (connector->connection, FALSE);
292
293        message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
294                                                "/org/freedesktop/ConsoleKit/Manager",
295                                                "org.freedesktop.ConsoleKit.Manager",
296                                                "OpenSession");
297        if (message == NULL) {
298                goto out;
299        }
300
301        dbus_error_init (&local_error);
302        reply = dbus_connection_send_with_reply_and_block (connector->connection,
303                                                           message,
304                                                           -1,
305                                                           &local_error);
306        if (reply == NULL) {
307                if (dbus_error_is_set (&local_error)) {
308                        dbus_set_error (error,
309                                        CK_CONNECTOR_ERROR,
310                                        "Unable to open session: %s",
311                                        local_error.message);
312                        dbus_error_free (&local_error);
313                        goto out;
314                }
315        }
316
317        dbus_error_init (&local_error);
318        if (! dbus_message_get_args (reply,
319                                     &local_error,
320                                     DBUS_TYPE_STRING, &cookie,
321                                     DBUS_TYPE_INVALID)) {
322                if (dbus_error_is_set (&local_error)) {
323                        dbus_set_error (error,
324                                        CK_CONNECTOR_ERROR,
325                                        "Unable to open session: %s",
326                                        local_error.message);
327                        dbus_error_free (&local_error);
328                        goto out;
329                }
330        }
331
332        connector->cookie = strdup (cookie);
333        if (connector->cookie == NULL) {
334                goto out;
335        }
336
337        connector->session_created = TRUE;
338        ret = TRUE;
339
340out:
341        if (reply != NULL) {
342                dbus_message_unref (reply);
343        }
344
345        if (message != NULL) {
346                dbus_message_unref (message);
347        }
348
349        return ret;
350}
351
352static dbus_bool_t
353ck_connector_open_session_with_parameters_valist (CkConnector *connector,
354                                                  DBusError   *error,
355                                                  const char  *first_parameter_name,
356                                                  va_list      var_args)
357{
358        DBusError       local_error;
359        DBusMessage    *message;
360        DBusMessage    *reply;
361        DBusMessageIter iter;
362        DBusMessageIter iter_array;
363        dbus_bool_t     ret;
364        char           *cookie;
365        const char     *name;
366
367        _ck_return_val_if_fail (connector != NULL, FALSE);
368
369        reply = NULL;
370        message = NULL;
371        ret = FALSE;
372
373        dbus_error_init (&local_error);
374        connector->connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &local_error);
375        if (connector->connection == NULL) {
376                if (dbus_error_is_set (&local_error)) {
377                        dbus_set_error (error,
378                                        CK_CONNECTOR_ERROR,
379                                        "Unable to open session: %s",
380                                        local_error.message);
381                        dbus_error_free (&local_error);
382                }
383                goto out;
384        }
385
386        dbus_connection_set_exit_on_disconnect (connector->connection, FALSE);
387
388        message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
389                                                "/org/freedesktop/ConsoleKit/Manager",
390                                                "org.freedesktop.ConsoleKit.Manager",
391                                                "OpenSessionWithParameters");
392        if (message == NULL) {
393                goto out;
394        }
395
396        dbus_message_iter_init_append (message, &iter);
397        if (! dbus_message_iter_open_container (&iter,
398                                                DBUS_TYPE_ARRAY,
399                                                "(sv)",
400                                                &iter_array)) {
401                goto out;
402        }
403
404        name = first_parameter_name;
405        while (name != NULL) {
406                int         type;
407                const void *value;
408                dbus_bool_t res;
409
410                type = lookup_parameter_type (name);
411                value = va_arg (var_args, const void *);
412
413                if (type == DBUS_TYPE_INVALID) {
414                        dbus_set_error (error,
415                                        CK_CONNECTOR_ERROR,
416                                        "Unknown parameter: %s",
417                                        name);
418                        goto out;
419                }
420
421                res = add_param_basic (&iter_array, name, type, value);
422                if (! res) {
423                        dbus_set_error (error,
424                                        CK_CONNECTOR_ERROR,
425                                        "Error adding parameter: %s",
426                                        name);
427                        goto out;
428                }
429
430                name = va_arg (var_args, char *);
431        }
432
433        if (! dbus_message_iter_close_container (&iter, &iter_array)) {
434                goto out;
435        }
436
437        dbus_error_init (&local_error);
438        reply = dbus_connection_send_with_reply_and_block (connector->connection,
439                                                           message,
440                                                           -1,
441                                                           &local_error);
442        if (reply == NULL) {
443                if (dbus_error_is_set (&local_error)) {
444                        dbus_set_error (error,
445                                        CK_CONNECTOR_ERROR,
446                                        "Unable to open session: %s",
447                                        local_error.message);
448                        dbus_error_free (&local_error);
449                        goto out;
450                }
451        }
452
453        dbus_error_init (&local_error);
454        if (! dbus_message_get_args (reply,
455                                     &local_error,
456                                     DBUS_TYPE_STRING, &cookie,
457                                     DBUS_TYPE_INVALID)) {
458                if (dbus_error_is_set (&local_error)) {
459                        dbus_set_error (error,
460                                        CK_CONNECTOR_ERROR,
461                                        "Unable to open session: %s",
462                                        local_error.message);
463                        dbus_error_free (&local_error);
464                        goto out;
465                }
466        }
467
468        connector->cookie = strdup (cookie);
469        if (connector->cookie == NULL) {
470                goto out;
471        }
472
473        connector->session_created = TRUE;
474        ret = TRUE;
475
476out:
477        if (reply != NULL) {
478                dbus_message_unref (reply);
479        }
480
481        if (message != NULL) {
482                dbus_message_unref (message);
483        }
484
485        return ret;
486}
487
488/**
489 * Opens a new session with parameter from variable argument list. The
490 * variable argument list should contain the name of each parameter
491 * followed by the value to append.
492 * For example:
493 *
494 * @code
495 *
496 * DBusError    error;
497 * dbus_int32_t v_INT32 = 500;
498 * const char  *v_STRING = "/dev/tty3";
499 *
500 * dbus_error_init (&error);
501 * ck_connector_open_session_with_parameters (connector,
502 *                                            &error,
503 *                                            "unix-user", &v_INT32,
504 *                                            "display-device", &v_STRING,
505 *                                            NULL);
506 * @endcode
507 *
508 * @param error error output
509 * @param first_parameter_name name of the first parameter
510 * @param ... value of first parameter, list of additional name-value pairs
511 * @returns #TRUE on success
512 */
513dbus_bool_t
514ck_connector_open_session_with_parameters (CkConnector *connector,
515                                           DBusError   *error,
516                                           const char  *first_parameter_name,
517                                           ...)
518{
519        va_list     var_args;
520        dbus_bool_t ret;
521
522        _ck_return_val_if_fail (connector != NULL, FALSE);
523        _ck_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), FALSE);
524
525        va_start (var_args, first_parameter_name);
526        ret = ck_connector_open_session_with_parameters_valist (connector,
527                                                                error,
528                                                                first_parameter_name,
529                                                                var_args);
530        va_end (var_args);
531
532        return ret;
533}
534
535/**
536 * Connects to the D-Bus system bus daemon and issues the method call
537 * OpenSessionWithParameters on the ConsoleKit manager interface. The
538 * connection to the bus is private.
539 *
540 * The only parameter that is optional is x11_display - it may be set
541 * to NULL if there is no X11 server associated with the session.
542 *
543 * Returns FALSE on OOM, if the system bus daemon is not running, if
544 * the ConsoleKit daemon is not running or if the caller doesn't have
545 * sufficient privileges.
546 *
547 * @param user UID for the user owning the session
548 * @param display_device the tty device for the session
549 * @param x11_display the value of the X11 DISPLAY for the session
550 * @returns #TRUE if the operation succeeds
551 */
552dbus_bool_t
553ck_connector_open_session_for_user (CkConnector *connector,
554                                    uid_t        user,
555                                    const char  *display_device,
556                                    const char  *x11_display,
557                                    DBusError   *error)
558{
559        dbus_bool_t ret;
560
561        _ck_return_val_if_fail (connector != NULL, FALSE);
562        _ck_return_val_if_fail (display_device != NULL, FALSE);
563        _ck_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), FALSE);
564
565        ret = ck_connector_open_session_with_parameters (connector,
566                                                         error,
567                                                         "display-device", &display_device,
568                                                         "x11-display", &x11_display,
569                                                         "unix-user", &user,
570                                                         NULL);
571        return ret;
572}
573
574/**
575 * Gets the cookie for the current open session.
576 * Returns #NULL if no session is open.
577 *
578 * @returns a constant string with the cookie.
579 */
580const char *
581ck_connector_get_cookie (CkConnector *connector)
582{
583        _ck_return_val_if_fail (connector != NULL, NULL);
584
585        if (! connector->session_created) {
586                return NULL;
587        } else {
588                return connector->cookie;
589        }
590}
591
592/**
593 * Issues the CloseSession method call on the ConsoleKit manager
594 * interface.
595 *
596 * Returns FALSE on OOM, if the system bus daemon is not running, if
597 * the ConsoleKit daemon is not running, if the caller doesn't have
598 * sufficient privilege or if a session isn't open.
599 *
600 * @returns #TRUE if the operation succeeds
601 */
602dbus_bool_t
603ck_connector_close_session (CkConnector *connector,
604                            DBusError   *error)
605{
606        DBusError    local_error;
607        DBusMessage *message;
608        DBusMessage *reply;
609        dbus_bool_t  ret;
610        dbus_bool_t  session_closed;
611
612        _ck_return_val_if_fail (connector != NULL, FALSE);
613        _ck_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), FALSE);
614
615        reply = NULL;
616        message = NULL;
617        ret = FALSE;
618
619        if (!connector->session_created || connector->cookie == NULL) {
620                dbus_set_error (error,
621                                CK_CONNECTOR_ERROR,
622                                "Unable to close session: %s",
623                                "no session open");
624                goto out;
625        }
626
627        dbus_error_init (&local_error);
628        message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
629                                                "/org/freedesktop/ConsoleKit/Manager",
630                                                "org.freedesktop.ConsoleKit.Manager",
631                                                "CloseSession");
632        if (message == NULL) {
633                goto out;
634        }
635
636        if (! dbus_message_append_args (message,
637                                        DBUS_TYPE_STRING, &(connector->cookie),
638                                        DBUS_TYPE_INVALID)) {
639                goto out;
640        }
641
642        dbus_error_init (&local_error);
643        reply = dbus_connection_send_with_reply_and_block (connector->connection,
644                                                           message,
645                                                           -1,
646                                                           &local_error);
647        if (reply == NULL) {
648                if (dbus_error_is_set (&local_error)) {
649                        dbus_set_error (error,
650                                        CK_CONNECTOR_ERROR,
651                                        "Unable to close session: %s",
652                                        local_error.message);
653                        dbus_error_free (&local_error);
654                        goto out;
655                }
656        }
657
658        dbus_error_init (&local_error);
659        if (! dbus_message_get_args (reply,
660                                     &local_error,
661                                     DBUS_TYPE_BOOLEAN, &session_closed,
662                                     DBUS_TYPE_INVALID)) {
663                if (dbus_error_is_set (&local_error)) {
664                        dbus_set_error (error,
665                                        CK_CONNECTOR_ERROR,
666                                        "Unable to close session: %s",
667                                        local_error.message);
668                        dbus_error_free (&local_error);
669                        goto out;
670                }
671        }
672
673        if (! session_closed) {
674                goto out;
675        }
676
677        connector->session_created = FALSE;
678        ret = TRUE;
679
680out:
681        if (reply != NULL) {
682                dbus_message_unref (reply);
683        }
684
685        if (message != NULL) {
686                dbus_message_unref (message);
687        }
688
689        return ret;
690
691}
Note: See TracBrowser for help on using the repository browser.