Back to index

lightdm  1.3.2
accounts.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
00002  *
00003  * Copyright (C) 2010-2011 Robert Ancell.
00004  * Author: Robert Ancell <robert.ancell@canonical.com>
00005  * 
00006  * This program is free software: you can redistribute it and/or modify it under
00007  * the terms of the GNU General Public License as published by the Free Software
00008  * Foundation, either version 3 of the License, or (at your option) any later
00009  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
00010  * license.
00011  */
00012 
00013 #include <errno.h>
00014 #include <pwd.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 
00018 #include "accounts.h"
00019 #include "dmrc.h"
00020 
00021 struct UserPrivate
00022 {
00023     /* Name of user */
00024     gchar *name;
00025 
00026     /* Accounts interface proxy */
00027     GDBusProxy *proxy;
00028 
00029     /* User ID */
00030     uid_t uid;
00031 
00032     /* Group ID */
00033     gid_t gid;
00034 
00035     /* GECOS information */
00036     gchar *gecos;
00037 
00038     /* Home directory */
00039     gchar *home_directory;
00040 
00041     /* Shell */
00042     gchar *shell;
00043 
00044     /* Language */
00045     gchar *language;
00046 
00047     /* Locale */
00048     gchar *locale;
00049 
00050     /* X session */
00051     gchar *xsession;
00052 };
00053 
00054 G_DEFINE_TYPE (User, user, G_TYPE_OBJECT);
00055 
00056 /* Connection to AccountsService */
00057 static GDBusProxy *accounts_service_proxy = NULL;
00058 static gboolean have_accounts_service_proxy = FALSE;
00059 
00060 static gboolean
00061 call_method (GDBusProxy *proxy, const gchar *method, GVariant *args,
00062              const gchar *expected, GVariant **result)
00063 {
00064     GVariant *answer;
00065     GError *error = NULL;
00066 
00067     if (!proxy)
00068         return FALSE;
00069 
00070     answer = g_dbus_proxy_call_sync (proxy,
00071                                      method,
00072                                      args,
00073                                      G_DBUS_CALL_FLAGS_NONE,
00074                                      -1,
00075                                      NULL,
00076                                      &error);
00077     if (error)
00078         g_warning ("Could not call %s: %s", method, error->message);
00079     g_clear_error (&error);
00080 
00081     if (!answer)
00082         return FALSE;
00083 
00084     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
00085     {
00086         g_warning ("Unexpected response from %s: %s",
00087                    method, g_variant_get_type_string (answer));
00088         g_variant_unref (answer);
00089         return FALSE;
00090     }
00091 
00092     if (result)
00093         *result = answer;
00094     else
00095         g_variant_unref (answer);
00096 
00097     return TRUE;
00098 }
00099 
00100 static gboolean
00101 get_property (GDBusProxy *proxy, const gchar *property,
00102               const gchar *expected, GVariant **result)
00103 {
00104     GVariant *answer;
00105 
00106     answer = g_dbus_proxy_get_cached_property (proxy, property);
00107 
00108     if (!answer)
00109     {
00110         g_warning ("Could not get accounts property %s", property);
00111         return FALSE;
00112     }
00113 
00114     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
00115     {
00116         g_warning ("Unexpected accounts property type for %s: %s",
00117                    property, g_variant_get_type_string (answer));
00118         g_variant_unref (answer);
00119         return FALSE;
00120     }
00121 
00122     if (result)
00123         *result = answer;
00124     else
00125         g_variant_unref (answer);
00126     return TRUE;
00127 }
00128 
00129 static void
00130 save_string_to_dmrc (const gchar *username, const gchar *group,
00131                      const gchar *key, const gchar *value)
00132 {
00133     GKeyFile *dmrc;
00134 
00135     dmrc = dmrc_load (username);
00136     g_key_file_set_string (dmrc, group, key, value);
00137     dmrc_save (dmrc, username);
00138 
00139     g_key_file_free (dmrc);
00140 }
00141 
00142 static gchar *
00143 get_string_from_dmrc (const gchar *username, const gchar *group,
00144                       const gchar *key)
00145 {
00146     GKeyFile *dmrc;
00147     gchar *value;
00148 
00149     dmrc = dmrc_load (username);
00150     value = g_key_file_get_string (dmrc, group, key, NULL);
00151 
00152     g_key_file_free (dmrc);
00153     return value;
00154 }
00155 
00156 static GDBusProxy *
00157 get_accounts_service_proxy ()
00158 {
00159     GError *error = NULL;
00160 
00161     if (have_accounts_service_proxy)
00162         return accounts_service_proxy;
00163 
00164     have_accounts_service_proxy = TRUE;
00165     accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
00166                                                             G_DBUS_PROXY_FLAGS_NONE,
00167                                                             NULL,
00168                                                             "org.freedesktop.Accounts",
00169                                                             "/org/freedesktop/Accounts",
00170                                                             "org.freedesktop.Accounts",
00171                                                             NULL, &error);
00172     if (error)
00173         g_warning ("Could not get accounts proxy: %s", error->message);
00174     g_clear_error (&error);
00175 
00176     if (accounts_service_proxy)
00177     {
00178         gchar *name;
00179         name = g_dbus_proxy_get_name_owner (accounts_service_proxy);
00180         if (!name)
00181         {
00182             g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
00183             g_object_unref (accounts_service_proxy);
00184             accounts_service_proxy = NULL;
00185         }
00186         g_free (name);
00187     }  
00188 
00189     return accounts_service_proxy;
00190 }
00191 
00192 static GDBusProxy *
00193 get_accounts_proxy_for_user (const gchar *user)
00194 {
00195     GDBusProxy *proxy;
00196     GError *error = NULL;
00197     GVariant *result;
00198     gboolean success;
00199     gchar *user_path = NULL;
00200 
00201     g_return_val_if_fail (user != NULL, NULL);  
00202 
00203     proxy = get_accounts_service_proxy ();
00204     if (!proxy)
00205         return NULL;
00206 
00207     success = call_method (proxy, "FindUserByName", g_variant_new ("(s)", user), "(o)", &result);
00208 
00209     if (!success)
00210         return NULL;
00211 
00212     g_variant_get (result, "(o)", &user_path);
00213     g_variant_unref (result);
00214 
00215     if (!user_path)
00216         return NULL;
00217   
00218     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
00219                                            G_DBUS_PROXY_FLAGS_NONE,
00220                                            NULL,
00221                                            "org.freedesktop.Accounts",
00222                                            user_path,
00223                                            "org.freedesktop.Accounts.User",
00224                                            NULL, &error);
00225     if (error)
00226         g_warning ("Could not get accounts user proxy: %s", error->message);
00227     g_clear_error (&error);
00228     g_free (user_path);
00229 
00230     return proxy;
00231 }
00232 
00233 static User *
00234 user_from_passwd (struct passwd *user_info)
00235 {
00236     User *user;
00237 
00238     user = g_object_new (USER_TYPE, NULL);
00239     user->priv->name = g_strdup (user_info->pw_name);
00240     user->priv->uid = user_info->pw_uid;
00241     user->priv->gid = user_info->pw_gid;
00242     user->priv->gecos = g_strdup (user_info->pw_gecos);
00243     user->priv->home_directory = g_strdup (user_info->pw_dir);
00244     user->priv->shell = g_strdup (user_info->pw_shell);
00245     user->priv->proxy = get_accounts_proxy_for_user (user->priv->name);
00246 
00247     return user;
00248 }
00249 
00250 User *
00251 accounts_get_user_by_name (const gchar *username)
00252 {
00253     struct passwd *user_info;
00254     User *user = NULL;
00255 
00256     g_return_val_if_fail (username != NULL, NULL);
00257 
00258     errno = 0;
00259     user_info = getpwnam (username);
00260     if (user_info)
00261         user = user_from_passwd (user_info);
00262 
00263     if (!user && errno != 0)
00264         g_warning ("Unable to get information on user %s: %s", username, strerror (errno));
00265 
00266     return user;
00267 }
00268 
00269 User *
00270 accounts_get_user_by_uid (uid_t uid)
00271 {
00272     User *user = NULL;
00273 
00274     errno = 0;
00275     struct passwd *user_info;
00276 
00277     user_info = getpwuid (uid);
00278     if (user_info)
00279         user = user_from_passwd (user_info);
00280 
00281     if (!user && errno != 0)
00282         g_warning ("Unable to get information on user %d: %s", uid, strerror (errno));
00283 
00284     return user;
00285 }
00286 
00287 User *
00288 accounts_get_current_user ()
00289 {
00290     return user_from_passwd (getpwuid (getuid ()));
00291 }
00292 
00293 const gchar *
00294 user_get_name (User *user)
00295 {
00296     g_return_val_if_fail (user != NULL, NULL);
00297     return user->priv->name;
00298 }
00299 
00300 uid_t
00301 user_get_uid (User *user)
00302 {
00303     g_return_val_if_fail (user != NULL, 0);
00304     return user->priv->uid;
00305 }
00306 
00307 gid_t
00308 user_get_gid (User *user)
00309 {
00310     g_return_val_if_fail (user != NULL, 0);
00311     return user->priv->gid;
00312 }
00313 
00314 const gchar *
00315 user_get_gecos (User *user)
00316 {
00317     g_return_val_if_fail (user != NULL, NULL);
00318     return user->priv->gecos;
00319 }
00320 
00321 const gchar *
00322 user_get_home_directory (User *user)
00323 {
00324     g_return_val_if_fail (user != NULL, NULL);
00325     return user->priv->home_directory;
00326 }
00327 
00328 const gchar *
00329 user_get_shell (User *user)
00330 {
00331     g_return_val_if_fail (user != NULL, NULL);
00332     return user->priv->shell;
00333 }
00334 
00335 const gchar *
00336 user_get_locale (User *user)
00337 {
00338     g_return_val_if_fail (user != NULL, NULL);
00339 
00340     g_free (user->priv->locale);
00341     if (user->priv->proxy)
00342         user->priv->locale = NULL;
00343     else
00344         user->priv->locale = get_string_from_dmrc (user->priv->name, "Desktop", "Language");
00345 
00346     /* Treat a blank locale as unset */
00347     if (g_strcmp0 (user->priv->locale, "") == 0)
00348     {
00349         g_free (user->priv->locale);
00350         user->priv->locale = NULL;
00351     }
00352 
00353     return user->priv->locale;
00354 }
00355 
00356 void
00357 user_set_language (User *user, const gchar *language)
00358 {
00359     g_return_if_fail (user != NULL);
00360 
00361     if (user->priv->proxy)
00362         call_method (user->priv->proxy, "SetLanguage", g_variant_new ("(s)", language), "()", NULL);
00363     else
00364         save_string_to_dmrc (user->priv->name, "Desktop", "Language", language);
00365 }
00366 
00367 void
00368 user_set_xsession (User *user, const gchar *xsession)
00369 {
00370     g_return_if_fail (user != NULL);
00371 
00372     call_method (user->priv->proxy, "SetXSession", g_variant_new ("(s)", xsession), "()", NULL);
00373     save_string_to_dmrc (user->priv->name, "Desktop", "Session", xsession);
00374 }
00375 
00376 const gchar *
00377 user_get_xsession (User *user)
00378 {
00379     GVariant *result;
00380 
00381     g_return_val_if_fail (user != NULL, NULL);
00382 
00383     g_free (user->priv->xsession);
00384     if (user->priv->proxy)
00385     {
00386         if (get_property (user->priv->proxy, "XSession", "s", &result))
00387         {
00388             g_variant_get (result, "s", &user->priv->xsession);
00389             g_variant_unref (result);
00390         }
00391         else
00392             user->priv->xsession = NULL;
00393     }
00394     else
00395         user->priv->xsession = get_string_from_dmrc (user->priv->name, "Desktop", "Session");
00396 
00397     if (g_strcmp0 (user->priv->xsession, "") == 0)
00398     {
00399         g_free (user->priv->xsession);
00400         user->priv->xsession = NULL;
00401     }
00402 
00403     return user->priv->xsession;
00404 }
00405 
00406 static void
00407 user_init (User *user)
00408 {
00409     user->priv = G_TYPE_INSTANCE_GET_PRIVATE (user, USER_TYPE, UserPrivate);
00410 }
00411 
00412 static void
00413 user_dispose (GObject *object)
00414 {
00415     User *self;
00416 
00417     self = USER (object);
00418 
00419     if (self->priv->proxy)
00420     {
00421         g_object_unref (self->priv->proxy);
00422         self->priv->proxy = NULL;
00423     }
00424 
00425     G_OBJECT_CLASS (user_parent_class)->dispose (object);
00426 }
00427 
00428 static void
00429 user_finalize (GObject *object)
00430 {
00431     User *self;
00432 
00433     self = USER (object);
00434 
00435     g_free (self->priv->name);
00436     g_free (self->priv->gecos);
00437     g_free (self->priv->home_directory);
00438     g_free (self->priv->shell);
00439 
00440     G_OBJECT_CLASS (user_parent_class)->finalize (object);  
00441 }
00442 
00443 static void
00444 user_class_init (UserClass *klass)
00445 {
00446     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00447 
00448     object_class->dispose = user_dispose;
00449     object_class->finalize = user_finalize;  
00450 
00451     g_type_class_add_private (klass, sizeof (UserPrivate));
00452 }