diff options
-rw-r--r-- | libck-connector/ck-connector.c | 886 | ||||
-rw-r--r-- | libck-connector/ck-connector.h | 108 | ||||
-rw-r--r-- | pam-ck-connector/pam-ck-connector.c | 287 |
3 files changed, 762 insertions, 519 deletions
diff --git a/libck-connector/ck-connector.c b/libck-connector/ck-connector.c index b22f76c..ebd8cf7 100644 --- a/libck-connector/ck-connector.c +++ b/libck-connector/ck-connector.c @@ -1,8 +1,10 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * * ck-connector.c : Code for login managers to register with ConsoleKit. * * Copyright (c) 2007 David Zeuthen <davidz@redhat.com> - * + * Copyright (c) 2007 William Jon McCann <mccann@jhu.edu> + * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without @@ -11,10 +13,10 @@ * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -34,348 +36,620 @@ #include "ck-connector.h" +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define _CK_FUNCTION_NAME __func__ +#elif defined(__GNUC__) || defined(_MSC_VER) +#define _CK_FUNCTION_NAME __FUNCTION__ +#else +#define _CK_FUNCTION_NAME "unknown function" +#endif + +#define CK_CONNECTOR_ERROR "org.freedesktop.CkConnector.Error" + +#define _CK_WARNING_FORMAT "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n" +#define _ck_return_if_fail(condition) do { \ + if (!(condition)) { \ + fprintf (stderr, _CK_WARNING_FORMAT, _CK_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ + return; \ + } } while (0) + +#define _ck_return_val_if_fail(condition, val) do { \ + if (!(condition)) { \ + fprintf (stderr, _CK_WARNING_FORMAT, _CK_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ + return val; \ + } } while (0) + +struct _CkConnector +{ + int refcount; + char *cookie; + dbus_bool_t session_created; + DBusConnection *connection; +}; + static dbus_bool_t -add_param_int32 (DBusMessageIter *iter_array, const char *key, dbus_int32_t value) +add_param_int32 (DBusMessageIter *iter_array, + const char *key, + dbus_int32_t value) { - DBusMessageIter iter_struct; - DBusMessageIter iter_variant; - - if (!dbus_message_iter_open_container (iter_array, - DBUS_TYPE_STRUCT, - NULL, - &iter_struct)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &key)) - goto oom; - if (!dbus_message_iter_open_container (&iter_struct, - DBUS_TYPE_VARIANT, - DBUS_TYPE_INT32_AS_STRING, - &iter_variant)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, &value)) - goto oom; - if (!dbus_message_iter_close_container (&iter_struct, &iter_variant)) - goto oom; - if (!dbus_message_iter_close_container (iter_array, &iter_struct)) - goto oom; - - return TRUE; + DBusMessageIter iter_struct; + DBusMessageIter iter_variant; + + if (! dbus_message_iter_open_container (iter_array, + DBUS_TYPE_STRUCT, + NULL, + &iter_struct)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_struct, + DBUS_TYPE_STRING, + &key)) { + goto oom; + } + + if (! dbus_message_iter_open_container (&iter_struct, + DBUS_TYPE_VARIANT, + DBUS_TYPE_INT32_AS_STRING, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_variant, + DBUS_TYPE_INT32, + &value)) { + goto oom; + } + + if (! dbus_message_iter_close_container (&iter_struct, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_close_container (iter_array, + &iter_struct)) { + goto oom; + } + + return TRUE; oom: - return FALSE; + return FALSE; } static dbus_bool_t -add_param_string (DBusMessageIter *iter_array, const char *key, const char *value) +add_param_string (DBusMessageIter *iter_array, + const char *key, + const char *value) { - DBusMessageIter iter_struct; - DBusMessageIter iter_variant; - - if (!dbus_message_iter_open_container (iter_array, - DBUS_TYPE_STRUCT, - NULL, - &iter_struct)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &key)) - goto oom; - if (!dbus_message_iter_open_container (&iter_struct, - DBUS_TYPE_VARIANT, - DBUS_TYPE_STRING_AS_STRING, - &iter_variant)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_STRING, &value)) - goto oom; - if (!dbus_message_iter_close_container (&iter_struct, &iter_variant)) - goto oom; - if (!dbus_message_iter_close_container (iter_array, &iter_struct)) - goto oom; - - return TRUE; + DBusMessageIter iter_struct; + DBusMessageIter iter_variant; + + if (! dbus_message_iter_open_container (iter_array, + DBUS_TYPE_STRUCT, + NULL, + &iter_struct)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_struct, + DBUS_TYPE_STRING, + &key)) { + goto oom; + } + + if (! dbus_message_iter_open_container (&iter_struct, + DBUS_TYPE_VARIANT, + DBUS_TYPE_STRING_AS_STRING, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_variant, + DBUS_TYPE_STRING, + &value)) { + goto oom; + } + + if (! dbus_message_iter_close_container (&iter_struct, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_close_container (iter_array, + &iter_struct)) { + goto oom; + } + + return TRUE; oom: - return FALSE; + return FALSE; } static dbus_bool_t -add_param_bool (DBusMessageIter *iter_array, const char *key, dbus_bool_t value) +add_param_bool (DBusMessageIter *iter_array, + const char *key, + dbus_bool_t value) { - DBusMessageIter iter_struct; - DBusMessageIter iter_variant; - - if (!dbus_message_iter_open_container (iter_array, - DBUS_TYPE_STRUCT, - NULL, - &iter_struct)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &key)) - goto oom; - if (!dbus_message_iter_open_container (&iter_struct, - DBUS_TYPE_VARIANT, - DBUS_TYPE_BOOLEAN_AS_STRING, - &iter_variant)) - goto oom; - if (!dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_BOOLEAN, &value)) - goto oom; - if (!dbus_message_iter_close_container (&iter_struct, &iter_variant)) - goto oom; - if (!dbus_message_iter_close_container (iter_array, &iter_struct)) - goto oom; - - return TRUE; + DBusMessageIter iter_struct; + DBusMessageIter iter_variant; + + if (! dbus_message_iter_open_container (iter_array, + DBUS_TYPE_STRUCT, + NULL, + &iter_struct)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_struct, + DBUS_TYPE_STRING, + &key)) { + goto oom; + } + + if (! dbus_message_iter_open_container (&iter_struct, + DBUS_TYPE_VARIANT, + DBUS_TYPE_BOOLEAN_AS_STRING, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_append_basic (&iter_variant, + DBUS_TYPE_BOOLEAN, + &value)) { + goto oom; + } + + if (! dbus_message_iter_close_container (&iter_struct, + &iter_variant)) { + goto oom; + } + + if (! dbus_message_iter_close_container (iter_array, + &iter_struct)) { + goto oom; + } + + return TRUE; oom: - return FALSE; + return FALSE; +} + +/* Frees all resources allocated and disconnects from the system + * message bus. + */ +static void +_ck_connector_free (CkConnector *connector) +{ + if (connector->connection != NULL) { + /* it's a private connection so it's all good */ + dbus_connection_close (connector->connection); + } + + if (connector->cookie != NULL) { + free (connector->cookie); + } + + free (connector); } +/** + * Decrements the reference count of a CkConnector, disconnecting + * from the bus and freeing the connector if the count reaches 0. + * + * @param connector the connector + * @see ck_connector_ref + */ +void +ck_connector_unref (CkConnector *connector) +{ + _ck_return_if_fail (connector != NULL); -struct CKConnector_s + /* Probably should use some kind of atomic op here */ + connector->refcount -= 1; + if (connector->refcount == 0) { + _ck_connector_free (connector); + } +} + +/** + * Increments the reference count of a CkConnector. + * + * @param connector the connector + * @returns the connector + * @see ck_connector_unref + */ +CkConnector * +ck_connector_ref (CkConnector *connector) { - char *cookie; - dbus_bool_t session_created; - DBusConnection *con; -}; + _ck_return_val_if_fail (connector != NULL, NULL); + + /* Probably should use some kind of atomic op here */ + connector->refcount += 1; -CKConnector* -ckc_new (void) + return connector; +} + +/** + * Constructs a new Connector to communicate with the ConsoleKit + * daemon. Returns #NULL if memory can't be allocated for the + * object. + * + * @returns a new CkConnector, free with ck_connector_unref() + */ +CkConnector * +ck_connector_new (void) { - CKConnector *ckc; - - ckc = calloc (1, sizeof (CKConnector)); - if (ckc == NULL) - goto oom; - ckc->con = NULL; - ckc->cookie = NULL; - ckc->session_created = FALSE; + CkConnector *connector; + + connector = calloc (1, sizeof (CkConnector)); + if (connector == NULL) { + goto oom; + } + + connector->refcount = 1; + connector->connection = NULL; + connector->cookie = NULL; + connector->session_created = FALSE; oom: - return ckc; -}; + return connector; +} +/** + * Connects to the D-Bus system bus daemon and issues the method call + * OpenSession on the ConsoleKit manager interface. The + * connection to the bus is private. + * + * Returns FALSE on OOM, if the system bus daemon is not running, if + * the ConsoleKit daemon is not running or if the caller doesn't have + * sufficient privileges. + * + * @returns #TRUE if the operation succeeds + */ dbus_bool_t -ckc_create_local_session2 (CKConnector *ckc) +ck_connector_open_session (CkConnector *connector, + DBusError *out_error) { - DBusError error; - DBusMessage *message; - DBusMessage *reply; - dbus_bool_t ret; - char *cookie; - - reply = NULL; - message = NULL; - ret = FALSE; - - dbus_error_init (&error); - ckc->con = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); - if (ckc->con == NULL) { - goto out; - } - dbus_connection_set_exit_on_disconnect (ckc->con, FALSE); - - message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "OpenSession"); - if (message == NULL) - goto out; - - reply = dbus_connection_send_with_reply_and_block (ckc->con, message, -1, &error); - if (reply == NULL) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - if (!dbus_message_get_args (reply, - &error, - DBUS_TYPE_STRING, &cookie, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - ckc->cookie = strdup (cookie); - if (ckc->cookie == NULL) - goto out; - - ckc->session_created = TRUE; - ret = TRUE; - + DBusError error; + DBusMessage *message; + DBusMessage *reply; + dbus_bool_t ret; + char *cookie; + + _ck_return_val_if_fail (connector != NULL, FALSE); + + reply = NULL; + message = NULL; + ret = FALSE; + + dbus_error_init (&error); + connector->connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); + if (connector->connection == NULL) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + } + + goto out; + } + + dbus_connection_set_exit_on_disconnect (connector->connection, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "OpenSession"); + if (message == NULL) { + goto out; + } + + reply = dbus_connection_send_with_reply_and_block (connector->connection, + message, + -1, + &error); + if (reply == NULL) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + if (! dbus_message_get_args (reply, + &error, + DBUS_TYPE_STRING, &cookie, + DBUS_TYPE_INVALID)) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + connector->cookie = strdup (cookie); + if (connector->cookie == NULL) { + goto out; + } + + connector->session_created = TRUE; + ret = TRUE; + out: - if (reply != NULL) - dbus_message_unref (reply); + if (reply != NULL) { + dbus_message_unref (reply); + } + + if (message != NULL) { + dbus_message_unref (message); + } - if (message != NULL) - dbus_message_unref (message); - - return ret; + return ret; } +/** + * Connects to the D-Bus system bus daemon and issues the method call + * OpenSessionWithParameters on the ConsoleKit manager interface. The + * connection to the bus is private. + * + * The only parameter that is optional is x11_display - it may be set + * to NULL if there is no X11 server associated with the session. + * + * Returns FALSE on OOM, if the system bus daemon is not running, if + * the ConsoleKit daemon is not running or if the caller doesn't have + * sufficient privileges. + * + * @param user UID for the user owning the session + * @param tty the tty device for the session + * @param x11_display the value of the X11 DISPLAY for the session + * @returns #TRUE if the operation succeeds + */ dbus_bool_t -ckc_create_local_session (CKConnector *ckc, uid_t user, const char *tty, const char *x11_display) +ck_connector_open_session_for_user (CkConnector *connector, + uid_t user, + const char *tty, + const char *x11_display, + DBusError *out_error) { - DBusError error; - DBusMessage *message; - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter iter_array; - dbus_bool_t ret; - char *cookie; - - reply = NULL; - message = NULL; - ret = FALSE; - - dbus_error_init (&error); - ckc->con = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); - if (ckc->con == NULL) { - goto out; - } - dbus_connection_set_exit_on_disconnect (ckc->con, FALSE); - - message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "OpenSessionWithParameters"); - if (message == NULL) - goto out; - - dbus_message_iter_init_append (message, &iter); - if (!dbus_message_iter_open_container (&iter, - DBUS_TYPE_ARRAY, - "(sv)", - &iter_array)) - goto out; - - if (!add_param_string (&iter_array, "host-name", "localhost")) - goto out; - if (!add_param_string (&iter_array, "display-device", tty)) - goto out; - if (x11_display != NULL) - if (!add_param_string (&iter_array, "x11-display", x11_display)) - goto out; - if (!add_param_int32 (&iter_array, "user", user)) - goto out; - if (!add_param_bool (&iter_array, "is-local", TRUE)) - goto out; - - if (!dbus_message_iter_close_container (&iter, &iter_array)) - goto out; - - reply = dbus_connection_send_with_reply_and_block (ckc->con, message, -1, &error); - if (reply == NULL) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - if (!dbus_message_get_args (reply, - &error, - DBUS_TYPE_STRING, &cookie, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - ckc->cookie = strdup (cookie); - if (ckc->cookie == NULL) - goto out; - - ckc->session_created = TRUE; - ret = TRUE; - + DBusError error; + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter iter_array; + dbus_bool_t ret; + char *cookie; + + _ck_return_val_if_fail (connector != NULL, FALSE); + _ck_return_val_if_fail (user > 0, FALSE); + _ck_return_val_if_fail (tty != NULL, FALSE); + + reply = NULL; + message = NULL; + ret = FALSE; + + dbus_error_init (&error); + connector->connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); + if (connector->connection == NULL) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + } + goto out; + } + + dbus_connection_set_exit_on_disconnect (connector->connection, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "OpenSessionWithParameters"); + if (message == NULL) { + goto out; + } + + dbus_message_iter_init_append (message, &iter); + if (! dbus_message_iter_open_container (&iter, + DBUS_TYPE_ARRAY, + "(sv)", + &iter_array)) { + goto out; + } + + if (! add_param_string (&iter_array, "host-name", "localhost")) { + goto out; + } + + if (! add_param_string (&iter_array, "display-device", tty)) { + goto out; + } + + if (x11_display != NULL) { + if (! add_param_string (&iter_array, "x11-display", x11_display)) { + goto out; + } + } + + if (! add_param_int32 (&iter_array, "user", user)) { + goto out; + } + + if (! add_param_bool (&iter_array, "is-local", TRUE)) { + goto out; + } + + if (! dbus_message_iter_close_container (&iter, &iter_array)) { + goto out; + } + + reply = dbus_connection_send_with_reply_and_block (connector->connection, + message, + -1, + &error); + if (reply == NULL) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + if (! dbus_message_get_args (reply, + &error, + DBUS_TYPE_STRING, &cookie, + DBUS_TYPE_INVALID)) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to open session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + connector->cookie = strdup (cookie); + if (connector->cookie == NULL) { + goto out; + } + + connector->session_created = TRUE; + ret = TRUE; + out: - if (reply != NULL) - dbus_message_unref (reply); + if (reply != NULL) { + dbus_message_unref (reply); + } - if (message != NULL) - dbus_message_unref (message); - - return ret; + if (message != NULL) { + dbus_message_unref (message); + } + + return ret; } -char * -ckc_get_cookie (CKConnector *ckc) +/** + * Gets the cookie for the current open session. + * Returns #NULL if no session is open. + * + * @returns a constant string with the cookie. + */ +const char * +ck_connector_get_cookie (CkConnector *connector) { - if (!ckc->session_created) - return NULL; - else - return ckc->cookie; + _ck_return_val_if_fail (connector != NULL, NULL); + + if (! connector->session_created) { + return NULL; + } else { + return connector->cookie; + } } +/** + * Issues the CloseSession method call on the ConsoleKit manager + * interface. + * + * Returns FALSE on OOM, if the system bus daemon is not running, if + * the ConsoleKit daemon is not running, if the caller doesn't have + * sufficient privilege or if a session isn't open. + * + * @returns #TRUE if the operation succeeds + */ dbus_bool_t -ckc_close_session (CKConnector *ckc) +ck_connector_close_session (CkConnector *connector, + DBusError *out_error) { - DBusError error; - DBusMessage *message; - DBusMessage *reply; - dbus_bool_t ret; - dbus_bool_t session_closed; - - reply = NULL; - message = NULL; - ret = FALSE; - if (!ckc->session_created || ckc->cookie == NULL) - goto out; - - dbus_error_init (&error); - message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "CloseSession"); - if (message == NULL) - goto out; - - if (!dbus_message_append_args (message, - DBUS_TYPE_STRING, &(ckc->cookie), - DBUS_TYPE_INVALID)) - goto out; - - reply = dbus_connection_send_with_reply_and_block (ckc->con, message, -1, &error); - if (reply == NULL) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - if (!dbus_message_get_args (reply, - &error, - DBUS_TYPE_BOOLEAN, &session_closed, - DBUS_TYPE_INVALID)) { - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - goto out; - } - } - - if (!session_closed) - goto out; - - ckc->session_created = FALSE; - ret = TRUE; - + DBusError error; + DBusMessage *message; + DBusMessage *reply; + dbus_bool_t ret; + dbus_bool_t session_closed; + + reply = NULL; + message = NULL; + ret = FALSE; + + if (!connector->session_created || connector->cookie == NULL) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to close session: %s", + "no session open"); + goto out; + } + + dbus_error_init (&error); + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "CloseSession"); + if (message == NULL) { + goto out; + } + + if (! dbus_message_append_args (message, + DBUS_TYPE_STRING, &(connector->cookie), + DBUS_TYPE_INVALID)) { + goto out; + } + + reply = dbus_connection_send_with_reply_and_block (connector->connection, + message, + -1, + &error); + if (reply == NULL) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to close session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + if (! dbus_message_get_args (reply, + &error, + DBUS_TYPE_BOOLEAN, &session_closed, + DBUS_TYPE_INVALID)) { + if (dbus_error_is_set (&error)) { + dbus_set_error (out_error, + CK_CONNECTOR_ERROR, + "Unable to close session: %s", + error.message); + dbus_error_free (&error); + goto out; + } + } + + if (! session_closed) { + goto out; + } + + connector->session_created = FALSE; + ret = TRUE; + out: - if (reply != NULL) - dbus_message_unref (reply); + if (reply != NULL) { + dbus_message_unref (reply); + } - if (message != NULL) - dbus_message_unref (message); - - return ret; + if (message != NULL) { + dbus_message_unref (message); + } -} + return ret; -void -ckc_free (CKConnector *ckc) -{ - if (ckc->con != NULL) { - /* it's a private connection so it's all good */ - dbus_connection_close (ckc->con); - } - if (ckc->cookie != NULL) { - free (ckc->cookie); - } - free (ckc); } diff --git a/libck-connector/ck-connector.h b/libck-connector/ck-connector.h index e92712d..2ea1bbb 100644 --- a/libck-connector/ck-connector.h +++ b/libck-connector/ck-connector.h @@ -1,8 +1,10 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * * ck-connector.h : Code for login managers to register with ConsoleKit. * * Copyright (c) 2007 David Zeuthen <davidz@redhat.com> - * + * Copyright (c) 2007 William Jon McCann <mccann@jhu.edu> + * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without @@ -11,10 +13,10 @@ * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -31,92 +33,28 @@ #include <sys/types.h> #include <dbus/dbus.h> -struct CKConnecter_s; -typedef struct CKConnector_s CKConnector; +DBUS_BEGIN_DECLS -/* Allocates a new CKConnector instance. - * - * Returns NULL on OOM */ -CKConnector *ckc_new (void); +struct _CkConnecter; +typedef struct _CkConnector CkConnector; -/* Connects to the D-Bus system bus daemon and issues the method call - * OpenSessionWithParameters on the ConsoleKit manager interface. The - * connection to the bus is private. - * - * The only parameter that is optional is x11_display - it may be set - * to NULL if there is no X11 server associated with the session. - * - * Returns FALSE on OOM, if the system bus daemon is not running, if - * the ConsoleKit daemon is not running or if the caller doesn't have - * sufficient privileges. - */ -dbus_bool_t ckc_create_local_session (CKConnector *ckc, uid_t user, const char *tty, const char *x11_display); +CkConnector *ck_connector_new (void); -dbus_bool_t ckc_create_local_session2 (CKConnector *ckc); +CkConnector *ck_connector_ref (CkConnector *ckc); +void ck_connector_unref (CkConnector *ckc); -/* Gets the cookie that should be set as XDG_SESSION_COOKIE in the - * users environment. - * - * Returns NULL unless ckc_create_local_session() succeeded - */ -char *ckc_get_cookie (CKConnector *ckc); +dbus_bool_t ck_connector_open_session_for_user (CkConnector *ckc, + uid_t user, + const char *tty, + const char *x11_display, + DBusError *error); +dbus_bool_t ck_connector_open_session (CkConnector *ckc, + DBusError *error); -/* Issues the CloseSession method call on the ConsoleKit manager - * interface. - * - * Returns FALSE on OOM, if the system bus daemon is not running, if - * the ConsoleKit daemon is not running, if the caller doesn't have - * sufficient privilege or if ckc_create_local_session() wasn't - * successfully invoked. - */ -dbus_bool_t ckc_close_session (CKConnector *ckc); +const char *ck_connector_get_cookie (CkConnector *ckc); +dbus_bool_t ck_connector_close_session (CkConnector *ckc, + DBusError *error); -/* Frees all resources allocated and disconnects from the system - * message bus. - */ -void ckc_free (CKConnector *ckc); - -/* example code: - -#include <stdio.h> -#include <stdlib.h> -#include "ck-connector.h" - -int -main (int argc, char *argv[]) -{ - CKConnector *ckc; - - ckc = ckc_new (); - if (ckc == NULL) { - printf ("OOM creating CKConnector\n"); - goto out; - } - - if (!ckc_create_local_session (ckc, 500, "/dev/tty2", ":1")) { - printf ("cannot create CK session: OOM, D-Bus system bus not available,\n" - "ConsoleKit not available or insufficient privileges.\n"); - goto out; - } - - printf ("Session cookie is '%s'\n", ckc_get_cookie (ckc)); - sleep (20); - - if (!ckc_close_session (ckc)) { - printf ("Cannot close CK session: OOM, D-Bus system bus not available,\n" - "ConsoleKit not available or insufficient privileges.\n"); - goto out; - } - -out: - if (ckc != NULL) { - ckc_free (ckc); - } -} - -*/ +DBUS_END_DECLS #endif /* CK_CONNECTOR_H */ - - - diff --git a/pam-ck-connector/pam-ck-connector.c b/pam-ck-connector/pam-ck-connector.c index 835be0c..c026806 100644 --- a/pam-ck-connector/pam-ck-connector.c +++ b/pam-ck-connector/pam-ck-connector.c @@ -1,8 +1,9 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * * pam-ck-connector.c : PAM module for registering with CK * * Copyright (c) 2007 David Zeuthen <davidz@redhat.com> - * + * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without @@ -11,10 +12,10 @@ * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -50,40 +51,50 @@ static int opt_debug = FALSE; static void -_parse_pam_args (const pam_handle_t *pamh, int flags, int argc, const char **argv) +_parse_pam_args (const pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { - int i; - - opt_debug = FALSE; - for (i = 0; i < argc && argv[i] != NULL; i++) { - if (strcmp (argv[i] ,"debug") == 0) { - opt_debug = TRUE; - } else { - pam_syslog (pamh, LOG_ERR, "unknown option: %s", argv[i]); - } - } + int i; + + opt_debug = FALSE; + for (i = 0; i < argc && argv[i] != NULL; i++) { + if (strcmp (argv[i] ,"debug") == 0) { + opt_debug = TRUE; + } else { + pam_syslog (pamh, LOG_ERR, "unknown option: %s", argv[i]); + } + } } PAM_EXTERN int -pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv) +pam_sm_authenticate (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { - return PAM_IGNORE; + return PAM_IGNORE; } -PAM_EXTERN int -pam_sm_setcred (pam_handle_t *pamh, int flags, int argc, const char **argv) +PAM_EXTERN int +pam_sm_setcred (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { - return PAM_IGNORE; + return PAM_IGNORE; } static uid_t -_util_name_to_uid (const char *username, gid_t *default_gid) +_util_name_to_uid (const char *username, + gid_t *default_gid) { - int rc; - uid_t res; - char *buf = NULL; - unsigned int bufsize; + int rc; + uid_t res; + char *buf = NULL; + unsigned int bufsize; struct passwd pwd; struct passwd *pwdp; @@ -97,8 +108,9 @@ _util_name_to_uid (const char *username, gid_t *default_gid) } res = pwdp->pw_uid; - if (default_gid != NULL) + if (default_gid != NULL) { *default_gid = pwdp->pw_gid; + } out: free (buf); @@ -108,119 +120,138 @@ out: /* our singleton */ static CKConnector *ckc = NULL; -PAM_EXTERN int -pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, const char **argv) +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { - if (ckc != NULL) { - ckc_free (ckc); - ckc = NULL; - } - return PAM_SUCCESS; + if (ckc != NULL) { + ck_connector_unref (ckc); + ckc = NULL; + } + return PAM_SUCCESS; } -PAM_EXTERN int -pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char **argv) +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) { - int ret; - const char *user; - const char *tty; - const char *x11_display; - const char *s; - uid_t uid; - char buf[256]; - - ret = PAM_IGNORE; - - _parse_pam_args (pamh, flags, argc, argv); - - /* Register with ConsoleKit as part of the session management */ - if (ckc != NULL) { - pam_syslog (pamh, LOG_ERR, "process already registered with ConsoleKit"); - goto out; - } - - ckc = ckc_new (); - if (ckc == NULL) { - pam_syslog (pamh, LOG_ERR, "oom creating ConsoleKit connector object"); - goto out; - } - - if (pam_get_user (pamh, &user, NULL) != PAM_SUCCESS || user == NULL) { - pam_syslog (pamh, LOG_ERR, "cannot determine username"); - goto out; - } - - if (pam_get_item (pamh, PAM_TTY, (const void **) &tty) != PAM_SUCCESS || tty == NULL) { - pam_syslog (pamh, LOG_ERR, "cannot determine tty"); - goto out; - } - - if ((s = pam_getenv (pamh, "CKCON_TTY")) != NULL) { - tty = s; - if (opt_debug) - pam_syslog (pamh, LOG_INFO, "using '%s' as tty (from CKCON_TTY)", tty); - } - - x11_display = NULL; - if ((s = pam_getenv (pamh, "CKCON_X11_DISPLAY")) != NULL) { - x11_display = s; - if (opt_debug) - pam_syslog (pamh, LOG_INFO, "using '%s' as X11 display (from CKCON_X11_DISPLAY)", x11_display); - } - - uid = _util_name_to_uid (user, NULL); - if (uid == (uid_t) -1) { - pam_syslog (pamh, LOG_ERR, "cannot determine uid for user '%s'", user); - goto out; - } - - if (!ckc_create_local_session (ckc, uid, tty, x11_display)) { - /* this might not be a bug for servers that don't have - * the message bus or ConsoleKit daemon running - so - * only log a message in debugging mode. - */ - if (opt_debug) - pam_syslog (pamh, LOG_DEBUG, "insufficient privileges or D-Bus / ConsoleKit not available"); - goto out; - } - - /* now set the cookie */ - buf[sizeof (buf) - 1] = '\0'; - snprintf (buf, sizeof (buf) - 1, "XDG_SESSION_COOKIE=%s", ckc_get_cookie (ckc)); - if (pam_putenv (pamh, buf) != PAM_SUCCESS) { - pam_syslog (pamh, LOG_ERR, "unable to set XDG_SESSION_COOKIE vairable"); - /* tear down session the hard way */ - ckc_free (ckc); - ckc = NULL; - goto out; - } - - if (opt_debug) { - pam_syslog (pamh, LOG_DEBUG, "registered uid=%d on tty='%s' with ConsoleKit", uid, tty); - } - - /* note that we're leaking our CKConnector instance ckc - this - * is *by design* such that when the login manager (that uses - * us) exits / crashes / etc. ConsoleKit will notice, via D-Bus - * connection tracking, that the login session ended. - */ - - ret = PAM_SUCCESS; + int ret; + const char *user; + const char *tty; + const char *x11_display; + const char *s; + uid_t uid; + char buf[256]; + DBusError error; + + ret = PAM_IGNORE; + + _parse_pam_args (pamh, flags, argc, argv); + + /* Register with ConsoleKit as part of the session management */ + if (ckc != NULL) { + pam_syslog (pamh, LOG_ERR, "process already registered with ConsoleKit"); + goto out; + } + + ckc = ck_connector_new (); + if (ckc == NULL) { + pam_syslog (pamh, LOG_ERR, "oom creating ConsoleKit connector object"); + goto out; + } + + if (pam_get_user (pamh, &user, NULL) != PAM_SUCCESS || user == NULL) { + pam_syslog (pamh, LOG_ERR, "cannot determine username"); + goto out; + } + + if (pam_get_item (pamh, PAM_TTY, (const void **) &tty) != PAM_SUCCESS || tty == NULL) { + pam_syslog (pamh, LOG_ERR, "cannot determine tty"); + goto out; + } + + if ((s = pam_getenv (pamh, "CKCON_TTY")) != NULL) { + tty = s; + if (opt_debug) { + pam_syslog (pamh, LOG_INFO, "using '%s' as tty (from CKCON_TTY)", tty); + } + } + + x11_display = NULL; + if ((s = pam_getenv (pamh, "CKCON_X11_DISPLAY")) != NULL) { + x11_display = s; + if (opt_debug) + pam_syslog (pamh, LOG_INFO, "using '%s' as X11 display (from CKCON_X11_DISPLAY)", x11_display); + } + + uid = _util_name_to_uid (user, NULL); + if (uid == (uid_t) -1) { + pam_syslog (pamh, LOG_ERR, "cannot determine uid for user '%s'", user); + goto out; + } + + dbus_error_init (&error); + if (! ck_connector_open_session_for_user (ckc, uid, tty, x11_display, &error)) { + /* this might not be a bug for servers that don't have + * the message bus or ConsoleKit daemon running - so + * only log a message in debugging mode. + */ + if (dbus_error_is_set (&error)) { + if (opt_debug) { + pam_syslog (pamh, LOG_DEBUG, "%s", error.message); + } + dbus_error_free (&error); + } else { + if (opt_debug) { + pam_syslog (pamh, LOG_DEBUG, "insufficient privileges or + D-Bus / ConsoleKit not available"); + } + } + + goto out; + } + + /* now set the cookie */ + buf[sizeof (buf) - 1] = '\0'; + snprintf (buf, sizeof (buf) - 1, "XDG_SESSION_COOKIE=%s", ck_connector_get_cookie (ckc)); + if (pam_putenv (pamh, buf) != PAM_SUCCESS) { + pam_syslog (pamh, LOG_ERR, "unable to set XDG_SESSION_COOKIE vairable"); + /* tear down session the hard way */ + ck_connector_unref (ckc); + ckc = NULL; + goto out; + } + + if (opt_debug) { + pam_syslog (pamh, LOG_DEBUG, "registered uid=%d on tty='%s' with ConsoleKit", uid, tty); + } + + /* note that we're leaking our CKConnector instance ckc - this + * is *by design* such that when the login manager (that uses + * us) exits / crashes / etc. ConsoleKit will notice, via D-Bus + * connection tracking, that the login session ended. + */ + + ret = PAM_SUCCESS; out: - return ret; + return ret; } #ifdef PAM_STATIC struct pam_module _pam_ckconnector_modstruct = { - "pam_ck_connector", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, + "pam_ck_connector", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, }; #endif |