/* * This file is part of Cockpit. * * Copyright (C) 2014 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * Cockpit is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Cockpit; If not, see . */ #include "config.h" #include "cockpitdbusinternal.h" #include #include #include #include #include static void variant_table_sink (GHashTable *props, const gchar *name, GVariant *value) { g_hash_table_insert (props, (gchar *)name, g_variant_ref_sink (value)); } static void populate_passwd_props (GHashTable *props, struct passwd *pw) { if (pw == NULL) { variant_table_sink (props, "Id", g_variant_new_int64 (geteuid ())); variant_table_sink (props, "Name", g_variant_new_string ("")); variant_table_sink (props, "Full", g_variant_new_string ("")); variant_table_sink (props, "Home", g_variant_new_string ("")); variant_table_sink (props, "Shell", g_variant_new_string ("")); } else { size_t n; gchar *full; n = strlen (pw->pw_gecos); while (n > 0 && pw->pw_gecos[n - 1] == ',') n--; full = g_strndup (pw->pw_gecos, n); variant_table_sink (props, "Id", g_variant_new_int64 (pw->pw_uid)); variant_table_sink (props, "Name", g_variant_new_string (pw->pw_name)); variant_table_sink (props, "Full", g_variant_new_string (full)); variant_table_sink (props, "Home", g_variant_new_string (pw->pw_dir)); variant_table_sink (props, "Shell", g_variant_new_string (pw->pw_shell)); g_free (full); } } static void populate_group_prop (GHashTable *props) { struct group *gr; GPtrArray *array; gid_t *list = NULL; gid_t gid; int ret, i; gid = getegid (); ret = getgroups (0, NULL); if (ret > 0) { list = g_new (gid_t, ret); ret = getgroups (ret, list); } if (ret < 0) { g_warning ("couldn't load list of groups: %s", g_strerror (errno)); ret = 0; } array = g_ptr_array_new (); gr = getgrgid (gid); if (gr == NULL) g_warning ("couldn't load group info for %d: %s", (int)gid, g_strerror (errno)); else g_ptr_array_add (array, g_variant_new_string (gr->gr_name)); for (i = 0; i < ret; i++) { if (list[i] == gid) continue; gr = getgrgid (list[i]); if (gr == NULL) { g_warning ("couldn't load group info for %d: %s", (int)gid, g_strerror (errno)); continue; } g_ptr_array_add (array, g_variant_new_string (gr->gr_name)); } variant_table_sink (props, "Groups", g_variant_new_array (G_VARIANT_TYPE_STRING, (GVariant * const*)array->pdata,array->len)); g_ptr_array_free (array, TRUE); g_free (list); } static GVariant * user_get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { GHashTable *props = user_data; if (!g_hash_table_lookup (props, "Groups")) populate_group_prop (props); GVariant *value = g_hash_table_lookup (props, property_name); g_return_val_if_fail (value != NULL, NULL); return g_variant_ref (value); } static GDBusPropertyInfo user_name_property = { -1, "Name", "s", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo user_full_property = { -1, "Full", "s", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo user_id_property = { -1, "Id", "x", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo user_home_property = { -1, "Home", "s", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo user_shell_property = { -1, "Shell", "s", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo user_groups_property = { -1, "Groups", "as", G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }; static GDBusPropertyInfo *user_properties[] = { &user_name_property, &user_full_property, &user_id_property, &user_shell_property, &user_home_property, &user_groups_property, NULL }; static GDBusInterfaceInfo user_interface = { -1, "cockpit.User", NULL, NULL, user_properties, NULL }; static GDBusInterfaceVTable user_vtable = { .get_property = user_get_property, }; void cockpit_dbus_user_startup (struct passwd *pwd) { GDBusConnection *connection; GHashTable *props; GError *error = NULL; connection = cockpit_dbus_internal_server (); g_return_if_fail (connection != NULL); props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref); populate_passwd_props (props, pwd); g_dbus_connection_register_object (connection, "/user", &user_interface, &user_vtable, props, (GDestroyNotify)g_hash_table_unref, &error); if (error != NULL) { g_critical ("couldn't register user object: %s", error->message); g_hash_table_unref (props); g_error_free (error); } g_object_unref (connection); }