1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3 * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
4 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
5 * Copyright (C) 2009-2010 Red Hat, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
37 #include <glib/gi18n.h>
38 #include <glib-object.h>
39 #include <glib/gstdio.h>
41 #include <gio/gunixinputstream.h>
42 #include <polkit/polkit.h>
46 #include "accounts-user-generated.h"
71 AccountsUserSkeleton parent;
73 GDBusConnection *system_bus_connection;
82 AccountType account_type;
83 PasswordMode password_mode;
91 guint64 login_frequency;
93 gchar *default_icon_file;
95 gboolean automatic_login;
96 gboolean system_account;
99 typedef struct UserClass
101 AccountsUserSkeletonClass parent_class;
104 static void user_accounts_user_iface_init (AccountsUserIface *iface);
106 G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
109 account_type_from_pwent (struct passwd *pwent)
117 if (pwent->pw_uid == 0) {
118 g_debug ("user is root so account type is administrator");
119 return ACCOUNT_TYPE_ADMINISTRATOR;
122 grp = getgrnam ("wheel");
124 g_debug ("wheel group not found");
125 return ACCOUNT_TYPE_STANDARD;
129 ngroups = get_user_groups (pwent->pw_name, pwent->pw_gid, &groups);
131 for (i = 0; i < ngroups; i++) {
132 if (groups[i] == wheel) {
134 return ACCOUNT_TYPE_ADMINISTRATOR;
140 return ACCOUNT_TYPE_STANDARD;
144 user_local_update_from_pwent (User *user,
145 struct passwd *pwent)
156 g_object_freeze_notify (G_OBJECT (user));
160 if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
161 gchar *first_comma = NULL;
162 gchar *valid_utf8_name = NULL;
164 if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
165 valid_utf8_name = pwent->pw_gecos;
166 first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
169 g_warning ("User %s has invalid UTF-8 in GECOS field. "
170 "It would be a good thing to check /etc/passwd.",
171 pwent->pw_name ? pwent->pw_name : "");
175 real_name = g_strndup (valid_utf8_name,
176 (first_comma - valid_utf8_name));
178 else if (valid_utf8_name) {
179 real_name = g_strdup (valid_utf8_name);
185 if (real_name && real_name[0] == '\0') {
193 if (g_strcmp0 (real_name, user->real_name) != 0) {
194 g_free (user->real_name);
195 user->real_name = real_name;
197 g_object_notify (G_OBJECT (user), "real-name");
204 if (pwent->pw_uid != user->uid) {
205 user->uid = pwent->pw_uid;
207 g_object_notify (G_OBJECT (user), "uid");
211 user->gid = pwent->pw_gid;
213 user->account_type = account_type_from_pwent (pwent);
216 if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) {
217 g_free (user->user_name);
218 user->user_name = g_strdup (pwent->pw_name);
220 g_object_notify (G_OBJECT (user), "user-name");
224 if (g_strcmp0 (user->home_dir, pwent->pw_dir) != 0) {
225 g_free (user->home_dir);
226 user->home_dir = g_strdup (pwent->pw_dir);
227 g_free (user->default_icon_file);
228 user->default_icon_file = g_build_filename (user->home_dir, ".face", NULL);
230 g_object_notify (G_OBJECT (user), "home-directory");
234 if (g_strcmp0 (user->shell, pwent->pw_shell) != 0) {
235 g_free (user->shell);
236 user->shell = g_strdup (pwent->pw_shell);
238 g_object_notify (G_OBJECT (user), "shell");
241 passwd = pwent->pw_passwd;
243 spent = getspnam (pwent->pw_name);
245 passwd = spent->sp_pwdp;
248 if (passwd && passwd[0] == '!') {
255 if (user->locked != locked) {
256 user->locked = locked;
258 g_object_notify (G_OBJECT (user), "locked");
261 if (passwd && passwd[0] != 0) {
262 mode = PASSWORD_MODE_REGULAR;
265 mode = PASSWORD_MODE_NONE;
270 if (spent->sp_lstchg == 0) {
271 mode = PASSWORD_MODE_SET_AT_LOGIN;
276 if (user->password_mode != mode) {
277 user->password_mode = mode;
279 g_object_notify (G_OBJECT (user), "password-mode");
282 user->system_account = daemon_local_user_is_excluded (user->daemon,
286 g_object_thaw_notify (G_OBJECT (user));
289 accounts_user_emit_changed (ACCOUNTS_USER (user));
293 user_local_update_from_keyfile (User *user,
298 g_object_freeze_notify (G_OBJECT (user));
300 s = g_key_file_get_string (keyfile, "User", "Language", NULL);
302 /* TODO: validate / normalize */
303 g_free (user->language);
307 s = g_key_file_get_string (keyfile, "User", "XSession", NULL);
309 g_free (user->x_session);
313 s = g_key_file_get_string (keyfile, "User", "Email", NULL);
315 g_free (user->email);
319 s = g_key_file_get_string (keyfile, "User", "Location", NULL);
321 g_free (user->location);
325 s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
327 g_free (user->password_hint);
328 user->password_hint = s;
331 s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
333 g_free (user->icon_file);
337 g_object_thaw_notify (G_OBJECT (user));
341 user_local_save_to_keyfile (User *user,
345 g_key_file_set_string (keyfile, "User", "Email", user->email);
348 g_key_file_set_string (keyfile, "User", "Language", user->language);
351 g_key_file_set_string (keyfile, "User", "XSession", user->x_session);
354 g_key_file_set_string (keyfile, "User", "Location", user->location);
356 if (user->password_hint)
357 g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint);
360 g_key_file_set_string (keyfile, "User", "Icon", user->icon_file);
364 save_extra_data (User *user)
371 keyfile = g_key_file_new ();
372 user_local_save_to_keyfile (user, keyfile);
375 data = g_key_file_to_data (keyfile, NULL, &error);
377 filename = g_build_filename ("/var/lib/AccountsService/users",
380 g_file_set_contents (filename, data, -1, &error);
384 g_warning ("Saving data for user %s failed: %s",
385 user->user_name, error->message);
386 g_error_free (error);
388 g_key_file_free (keyfile);
392 move_extra_data (const gchar *old_name,
393 const gchar *new_name)
398 old_filename = g_build_filename ("/var/lib/AccountsService/users",
400 new_filename = g_build_filename ("/var/lib/AccountsService/users",
403 g_rename (old_filename, new_filename);
405 g_free (old_filename);
406 g_free (new_filename);
410 compute_object_path (User *user)
414 object_path = g_strdup_printf ("/org/freedesktop/Accounts/User%ld",
421 user_local_register (User *user)
423 GError *error = NULL;
425 user->system_bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
426 if (user->system_bus_connection == NULL) {
428 g_critical ("error getting system bus: %s", error->message);
429 g_error_free (error);
434 user->object_path = compute_object_path (user);
436 if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (user),
437 user->system_bus_connection,
441 g_critical ("error exporting user object: %s", error->message);
442 g_error_free (error);
449 user_local_unregister (User *user)
451 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (user));
455 user_local_new (Daemon *daemon, uid_t uid)
459 user = g_object_new (TYPE_USER, NULL);
460 user->daemon = daemon;
467 user_local_get_user_name (User *user)
469 return user->user_name;
473 user_local_get_system_account (User *user)
475 return user->system_account;
479 user_local_get_object_path (User *user)
481 return user->object_path;
485 user_local_get_uid (User *user)
491 user_local_get_shell(User *user)
497 throw_error (GDBusMethodInvocation *context,
505 va_start (args, format);
506 message = g_strdup_vprintf (format, args);
509 g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message);
515 user_change_real_name_authorized_cb (Daemon *daemon,
517 GDBusMethodInvocation *context,
523 const gchar *argv[6];
525 if (g_strcmp0 (user->real_name, name) != 0) {
527 "change real name of user '%s' (%d) to '%s'",
528 user->user_name, user->uid, name);
530 argv[0] = "/usr/sbin/usermod";
534 argv[4] = user->user_name;
538 if (!spawn_with_login_uid (context, argv, &error)) {
539 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
540 g_error_free (error);
544 g_free (user->real_name);
545 user->real_name = g_strdup (name);
547 accounts_user_emit_changed (ACCOUNTS_USER (user));
549 g_object_notify (G_OBJECT (user), "real-name");
552 accounts_user_complete_set_real_name (ACCOUNTS_USER (user), context);
556 user_set_real_name (AccountsUser *auser,
557 GDBusMethodInvocation *context,
558 const gchar *real_name)
560 User *user = (User*)auser;
562 const gchar *action_id;
564 if (!get_caller_uid (context, &uid)) {
565 throw_error (context, ERROR_FAILED, "identifying caller failed");
569 if (user->uid == (uid_t) uid)
570 action_id = "org.freedesktop.accounts.change-own-user-data";
572 action_id = "org.freedesktop.accounts.user-administration";
574 daemon_local_check_auth (user->daemon,
578 user_change_real_name_authorized_cb,
580 g_strdup (real_name),
581 (GDestroyNotify)g_free);
587 user_change_user_name_authorized_cb (Daemon *daemon,
589 GDBusMethodInvocation *context,
596 const gchar *argv[6];
598 if (g_strcmp0 (user->user_name, name) != 0) {
599 old_name = g_strdup (user->user_name);
601 "change name of user '%s' (%d) to '%s'",
602 old_name, user->uid, name);
604 argv[0] = "/usr/sbin/usermod";
608 argv[4] = user->user_name;
612 if (!spawn_with_login_uid (context, argv, &error)) {
613 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
614 g_error_free (error);
618 g_free (user->user_name);
619 user->user_name = g_strdup (name);
621 move_extra_data (old_name, name);
623 accounts_user_emit_changed (ACCOUNTS_USER (user));
625 g_object_notify (G_OBJECT (user), "user-name");
628 accounts_user_complete_set_user_name (ACCOUNTS_USER (user), context);
633 user_set_user_name (AccountsUser *auser,
634 GDBusMethodInvocation *context,
635 const gchar *user_name)
637 User *user = (User*)auser;
638 daemon_local_check_auth (user->daemon,
640 "org.freedesktop.accounts.user-administration",
642 user_change_user_name_authorized_cb,
644 g_strdup (user_name),
645 (GDestroyNotify)g_free);
651 user_change_email_authorized_cb (Daemon *daemon,
653 GDBusMethodInvocation *context,
659 if (g_strcmp0 (user->email, email) != 0) {
660 g_free (user->email);
661 user->email = g_strdup (email);
663 save_extra_data (user);
665 accounts_user_emit_changed (ACCOUNTS_USER (user));
667 g_object_notify (G_OBJECT (user), "email");
670 accounts_user_complete_set_email (ACCOUNTS_USER (user), context);
676 user_set_email (AccountsUser *auser,
677 GDBusMethodInvocation *context,
680 User *user = (User*)auser;
682 const gchar *action_id;
684 if (!get_caller_uid (context, &uid)) {
685 throw_error (context, ERROR_FAILED, "identifying caller failed");
689 if (user->uid == (uid_t) uid)
690 action_id = "org.freedesktop.accounts.change-own-user-data";
692 action_id = "org.freedesktop.accounts.user-administration";
694 daemon_local_check_auth (user->daemon,
698 user_change_email_authorized_cb,
701 (GDestroyNotify)g_free);
707 user_change_language_authorized_cb (Daemon *daemon,
709 GDBusMethodInvocation *context,
713 gchar *language = data;
715 if (g_strcmp0 (user->language, language) != 0) {
716 g_free (user->language);
717 user->language = g_strdup (language);
719 save_extra_data (user);
721 accounts_user_emit_changed (ACCOUNTS_USER (user));
723 g_object_notify (G_OBJECT (user), "language");
726 accounts_user_complete_set_language (ACCOUNTS_USER (user), context);
732 user_set_language (AccountsUser *auser,
733 GDBusMethodInvocation *context,
734 const gchar *language)
736 User *user = (User*)auser;
738 const gchar *action_id;
740 if (!get_caller_uid (context, &uid)) {
741 throw_error (context, ERROR_FAILED, "identifying caller failed");
745 if (user->uid == (uid_t) uid)
746 action_id = "org.freedesktop.accounts.change-own-user-data";
748 action_id = "org.freedesktop.accounts.user-administration";
750 daemon_local_check_auth (user->daemon,
754 user_change_language_authorized_cb,
757 (GDestroyNotify)g_free);
763 user_change_x_session_authorized_cb (Daemon *daemon,
765 GDBusMethodInvocation *context,
769 gchar *x_session = data;
771 if (g_strcmp0 (user->x_session, x_session) != 0) {
772 g_free (user->x_session);
773 user->x_session = g_strdup (x_session);
775 save_extra_data (user);
777 accounts_user_emit_changed (ACCOUNTS_USER (user));
779 g_object_notify (G_OBJECT (user), "xsession");
782 accounts_user_complete_set_xsession (ACCOUNTS_USER (user), context);
786 user_set_x_session (AccountsUser *auser,
787 GDBusMethodInvocation *context,
788 const gchar *x_session)
790 User *user = (User*)auser;
792 const gchar *action_id;
794 if (!get_caller_uid (context, &uid)) {
795 throw_error (context, ERROR_FAILED, "identifying caller failed");
799 if (user->uid == (uid_t) uid)
800 action_id = "org.freedesktop.accounts.change-own-user-data";
802 action_id = "org.freedesktop.accounts.user-administration";
804 daemon_local_check_auth (user->daemon,
808 user_change_x_session_authorized_cb,
810 g_strdup (x_session),
811 (GDestroyNotify) g_free);
817 user_change_location_authorized_cb (Daemon *daemon,
819 GDBusMethodInvocation *context,
823 gchar *location = data;
825 if (g_strcmp0 (user->location, location) != 0) {
826 g_free (user->location);
827 user->location = g_strdup (location);
829 save_extra_data (user);
831 accounts_user_emit_changed (ACCOUNTS_USER (user));
833 g_object_notify (G_OBJECT (user), "location");
836 accounts_user_complete_set_location (ACCOUNTS_USER (user), context);
840 user_set_location (AccountsUser *auser,
841 GDBusMethodInvocation *context,
842 const gchar *location)
844 User *user = (User*)auser;
846 const gchar *action_id;
848 if (!get_caller_uid (context, &uid)) {
849 throw_error (context, ERROR_FAILED, "identifying caller failed");
853 if (user->uid == (uid_t) uid)
854 action_id = "org.freedesktop.accounts.change-own-user-data";
856 action_id = "org.freedesktop.accounts.user-administration";
858 daemon_local_check_auth (user->daemon,
862 user_change_location_authorized_cb,
865 (GDestroyNotify)g_free);
871 user_change_home_dir_authorized_cb (Daemon *daemon,
873 GDBusMethodInvocation *context,
877 gchar *home_dir = data;
879 const gchar *argv[7];
881 if (g_strcmp0 (user->home_dir, home_dir) != 0) {
883 "change home directory of user '%s' (%d) to '%s'",
884 user->user_name, user->uid, home_dir);
886 argv[0] = "/usr/sbin/usermod";
891 argv[5] = user->user_name;
895 if (!spawn_with_login_uid (context, argv, &error)) {
896 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
897 g_error_free (error);
901 g_free (user->home_dir);
902 user->home_dir = g_strdup (home_dir);
903 g_free (user->default_icon_file);
904 user->default_icon_file = g_build_filename (user->home_dir, ".face", NULL);
906 accounts_user_emit_changed (ACCOUNTS_USER (user));
908 g_object_notify (G_OBJECT (user), "home-directory");
911 accounts_user_complete_set_home_directory (ACCOUNTS_USER (user), context);
915 user_set_home_directory (AccountsUser *auser,
916 GDBusMethodInvocation *context,
917 const gchar *home_dir)
919 User *user = (User*)auser;
920 daemon_local_check_auth (user->daemon,
922 "org.freedesktop.accounts.user-administration",
924 user_change_home_dir_authorized_cb,
927 (GDestroyNotify)g_free);
933 user_change_shell_authorized_cb (Daemon *daemon,
935 GDBusMethodInvocation *context,
941 const gchar *argv[6];
943 if (g_strcmp0 (user->shell, shell) != 0) {
945 "change shell of user '%s' (%d) to '%s'",
946 user->user_name, user->uid, shell);
948 argv[0] = "/usr/sbin/usermod";
952 argv[4] = user->user_name;
956 if (!spawn_with_login_uid (context, argv, &error)) {
957 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
958 g_error_free (error);
962 g_free (user->shell);
963 user->shell = g_strdup (shell);
965 accounts_user_emit_changed (ACCOUNTS_USER (user));
967 g_object_notify (G_OBJECT (user), "shell");
970 accounts_user_complete_set_shell (ACCOUNTS_USER (user), context);
974 user_set_shell (AccountsUser *auser,
975 GDBusMethodInvocation *context,
978 User *user = (User*)auser;
979 daemon_local_check_auth (user->daemon,
981 "org.freedesktop.accounts.user-administration",
983 user_change_shell_authorized_cb,
986 (GDestroyNotify)g_free);
992 become_user (gpointer data)
994 struct passwd *pw = data;
997 initgroups (pw->pw_name, pw->pw_gid) != 0 ||
998 setgid (pw->pw_gid) != 0 ||
999 setuid (pw->pw_uid) != 0) {
1005 user_change_icon_file_authorized_cb (Daemon *daemon,
1007 GDBusMethodInvocation *context,
1018 filename = g_strdup (data);
1020 if (filename == NULL ||
1021 *filename == '\0') {
1029 dest_path = g_build_filename (ICONDIR, user->user_name, NULL);
1030 dest = g_file_new_for_path (dest_path);
1034 if (!g_file_delete (dest, NULL, &error) &&
1035 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
1036 g_object_unref (dest);
1037 throw_error (context, ERROR_FAILED, "failed to remove user icon, %s", error->message);
1038 g_error_free (error);
1041 g_object_unref (dest);
1045 file = g_file_new_for_path (filename);
1046 info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_MODE ","
1047 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
1048 G_FILE_ATTRIBUTE_STANDARD_SIZE,
1050 mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
1051 type = g_file_info_get_file_type (info);
1052 size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
1054 g_object_unref (info);
1055 g_object_unref (file);
1057 if (type != G_FILE_TYPE_REGULAR) {
1058 g_debug ("not a regular file\n");
1059 throw_error (context, ERROR_FAILED, "file '%s' is not a regular file", filename);
1064 if (size > 1048576) {
1065 g_debug ("file too large\n");
1066 /* 1MB ought to be enough for everybody */
1067 throw_error (context, ERROR_FAILED, "file '%s' is too large to be used as an icon", filename);
1072 if ((mode & S_IROTH) == 0 ||
1073 (!g_str_has_prefix (filename, DATADIR) &&
1074 !g_str_has_prefix (filename, ICONDIR))) {
1077 const gchar *argv[3];
1080 GInputStream *input;
1081 GOutputStream *output;
1086 if (!get_caller_uid (context, &uid)) {
1087 throw_error (context, ERROR_FAILED, "failed to copy file, could not determine caller UID");
1092 dest_path = g_build_filename (ICONDIR, user->user_name, NULL);
1093 dest = g_file_new_for_path (dest_path);
1096 output = G_OUTPUT_STREAM (g_file_replace (dest, NULL, FALSE, 0, NULL, &error));
1098 throw_error (context, ERROR_FAILED, "creating file '%s' failed: %s", dest_path, error->message);
1099 g_error_free (error);
1102 g_object_unref (dest);
1106 argv[0] = "/bin/cat";
1110 pw = getpwuid (uid);
1113 if (!g_spawn_async_with_pipes (NULL, (gchar**)argv, NULL, 0, become_user, pw, NULL, NULL, &std_out, NULL, &error)) {
1114 throw_error (context, ERROR_FAILED, "reading file '%s' failed: %s", filename, error->message);
1115 g_error_free (error);
1118 g_object_unref (dest);
1122 input = g_unix_input_stream_new (std_out, FALSE);
1125 bytes = g_output_stream_splice (output, input, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
1126 if (bytes < 0 || (gsize)bytes != size) {
1127 throw_error (context, ERROR_FAILED, "copying file '%s' to '%s' failed: %s", filename, dest_path, error ? error->message : "unknown reason");
1129 g_error_free (error);
1131 g_file_delete (dest, NULL, NULL);
1135 g_object_unref (dest);
1136 g_object_unref (input);
1137 g_object_unref (output);
1141 g_object_unref (dest);
1142 g_object_unref (input);
1143 g_object_unref (output);
1146 filename = dest_path;
1150 g_free (user->icon_file);
1151 user->icon_file = filename;
1153 save_extra_data (user);
1155 accounts_user_emit_changed (ACCOUNTS_USER (user));
1157 g_object_notify (G_OBJECT (user), "icon-file");
1159 accounts_user_complete_set_icon_file (ACCOUNTS_USER (user), context);
1163 user_set_icon_file (AccountsUser *auser,
1164 GDBusMethodInvocation *context,
1165 const gchar *filename)
1167 User *user = (User*)auser;
1169 const gchar *action_id;
1171 if (!get_caller_uid (context, &uid)) {
1172 throw_error (context, ERROR_FAILED, "identifying caller failed");
1176 if (user->uid == (uid_t) uid)
1177 action_id = "org.freedesktop.accounts.change-own-user-data";
1179 action_id = "org.freedesktop.accounts.user-administration";
1181 daemon_local_check_auth (user->daemon,
1185 user_change_icon_file_authorized_cb,
1187 g_strdup (filename),
1188 (GDestroyNotify)g_free);
1194 user_change_locked_authorized_cb (Daemon *daemon,
1196 GDBusMethodInvocation *context,
1200 gboolean locked = GPOINTER_TO_INT (data);
1202 const gchar *argv[5];
1204 if (user->locked != locked) {
1206 "%s account of user '%s' (%d)",
1207 locked ? "locking" : "unlocking", user->user_name, user->uid);
1208 argv[0] = "/usr/sbin/usermod";
1209 argv[1] = locked ? "-L" : "-U";
1211 argv[3] = user->user_name;
1215 if (!spawn_with_login_uid (context, argv, &error)) {
1216 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1217 g_error_free (error);
1221 user->locked = locked;
1223 accounts_user_emit_changed (ACCOUNTS_USER (user));
1225 g_object_notify (G_OBJECT (user), "locked");
1228 accounts_user_complete_set_locked (ACCOUNTS_USER (user), context);
1232 user_set_locked (AccountsUser *auser,
1233 GDBusMethodInvocation *context,
1236 User *user = (User*)auser;
1237 daemon_local_check_auth (user->daemon,
1239 "org.freedesktop.accounts.user-administration",
1241 user_change_locked_authorized_cb,
1243 GINT_TO_POINTER (locked),
1250 user_change_account_type_authorized_cb (Daemon *daemon,
1252 GDBusMethodInvocation *context,
1256 AccountType account_type = GPOINTER_TO_INT (data);
1264 const gchar *argv[6];
1266 if (user->account_type != account_type) {
1268 "change account type of user '%s' (%d) to %d",
1269 user->user_name, user->uid, account_type);
1271 grp = getgrnam ("wheel");
1273 throw_error (context, ERROR_FAILED, "failed to set account type: wheel group not found");
1276 wheel = grp->gr_gid;
1278 ngroups = get_user_groups (user->user_name, user->gid, &groups);
1280 str = g_string_new ("");
1281 for (i = 0; i < ngroups; i++) {
1282 if (groups[i] == wheel)
1284 g_string_append_printf (str, "%d,", groups[i]);
1286 switch (account_type) {
1287 case ACCOUNT_TYPE_ADMINISTRATOR:
1288 g_string_append_printf (str, "%d", wheel);
1290 case ACCOUNT_TYPE_STANDARD:
1292 /* remove excess comma */
1293 g_string_truncate (str, str->len - 1);
1299 argv[0] = "/usr/sbin/usermod";
1303 argv[4] = user->user_name;
1306 g_string_free (str, FALSE);
1309 if (!spawn_with_login_uid (context, argv, &error)) {
1310 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1311 g_error_free (error);
1315 user->account_type = account_type;
1317 accounts_user_emit_changed (ACCOUNTS_USER (user));
1319 g_object_notify (G_OBJECT (user), "account-type");
1322 accounts_user_complete_set_account_type (ACCOUNTS_USER (user), context);
1326 user_change_role_authorized_cb (Daemon *daemon,
1328 GDBusMethodInvocation *context,
1333 accounts_user_complete_set_role (ACCOUNTS_USER (user), context);
1339 user_set_account_type (AccountsUser *auser,
1340 GDBusMethodInvocation *context,
1343 User *user = (User*)auser;
1344 if (account_type < 0 || account_type > ACCOUNT_TYPE_LAST) {
1345 throw_error (context, ERROR_FAILED, "unknown account type: %d", account_type);
1349 daemon_local_check_auth (user->daemon,
1351 "org.freedesktop.accounts.user-administration",
1353 user_change_account_type_authorized_cb,
1355 GINT_TO_POINTER (account_type),
1362 user_set_role (AccountsUser *auser,
1363 GDBusMethodInvocation *context,
1368 role_dup = g_strdup (role);
1370 User *user = (User*)auser;
1372 daemon_local_check_auth (user->daemon,
1374 "org.freedesktop.accounts.user-administration",
1376 user_change_role_authorized_cb,
1387 user_change_password_mode_authorized_cb (Daemon *daemon,
1389 GDBusMethodInvocation *context,
1393 PasswordMode mode = GPOINTER_TO_INT (data);
1395 const gchar *argv[6];
1397 if (user->password_mode != mode) {
1399 "change password mode of user '%s' (%d) to %d",
1400 user->user_name, user->uid, mode);
1402 g_object_freeze_notify (G_OBJECT (user));
1404 if (mode == PASSWORD_MODE_SET_AT_LOGIN ||
1405 mode == PASSWORD_MODE_NONE) {
1407 argv[0] = "/usr/bin/passwd";
1410 argv[3] = user->user_name;
1414 if (!spawn_with_login_uid (context, argv, &error)) {
1415 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1416 g_error_free (error);
1420 if (mode == PASSWORD_MODE_SET_AT_LOGIN) {
1421 argv[0] = "/usr/bin/chage";
1425 argv[4] = user->user_name;
1429 if (!spawn_with_login_uid (context, argv, &error)) {
1430 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1431 g_error_free (error);
1436 g_free (user->password_hint);
1437 user->password_hint = NULL;
1439 g_object_notify (G_OBJECT (user), "password-hint");
1441 /* removing the password has the side-effect of
1442 * unlocking the account
1445 user->locked = FALSE;
1446 g_object_notify (G_OBJECT (user), "locked");
1449 else if (user->locked) {
1450 argv[0] = "/usr/sbin/usermod";
1453 argv[3] = user->user_name;
1457 if (!spawn_with_login_uid (context, argv, &error)) {
1458 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1459 g_error_free (error);
1463 user->locked = FALSE;
1464 g_object_notify (G_OBJECT (user), "locked");
1467 user->password_mode = mode;
1469 g_object_notify (G_OBJECT (user), "password-mode");
1471 save_extra_data (user);
1473 g_object_thaw_notify (G_OBJECT (user));
1475 accounts_user_emit_changed (ACCOUNTS_USER (user));
1478 accounts_user_complete_set_password_mode (ACCOUNTS_USER (user), context);
1482 user_set_password_mode (AccountsUser *auser,
1483 GDBusMethodInvocation *context,
1486 User *user = (User*)auser;
1487 const gchar *action_id;
1489 if (mode < 0 || mode > PASSWORD_MODE_LAST) {
1490 throw_error (context, ERROR_FAILED, "unknown password mode: %d", mode);
1494 action_id = "org.freedesktop.accounts.user-administration";
1496 daemon_local_check_auth (user->daemon,
1500 user_change_password_mode_authorized_cb,
1502 GINT_TO_POINTER (mode),
1509 user_change_password_authorized_cb (Daemon *daemon,
1511 GDBusMethodInvocation *context,
1515 gchar **strings = data;
1517 const gchar *argv[6];
1520 "set password and hint of user '%s' (%d)",
1521 user->user_name, user->uid);
1523 g_object_freeze_notify (G_OBJECT (user));
1525 argv[0] = "/usr/sbin/usermod";
1527 argv[2] = strings[0];
1529 argv[4] = user->user_name;
1533 if (!spawn_with_login_uid (context, argv, &error)) {
1534 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1535 g_error_free (error);
1539 if (user->password_mode != PASSWORD_MODE_REGULAR) {
1540 user->password_mode = PASSWORD_MODE_REGULAR;
1541 g_object_notify (G_OBJECT (user), "password-mode");
1545 user->locked = FALSE;
1546 g_object_notify (G_OBJECT (user), "locked");
1549 if (g_strcmp0 (user->password_hint, strings[1]) != 0) {
1550 g_free (user->password_hint);
1551 user->password_hint = g_strdup (strings[1]);
1552 g_object_notify (G_OBJECT (user), "password-hint");
1555 save_extra_data (user);
1557 g_object_thaw_notify (G_OBJECT (user));
1559 accounts_user_emit_changed (ACCOUNTS_USER (user));
1561 accounts_user_complete_set_password (ACCOUNTS_USER (user), context);
1565 free_passwords (gchar **strings)
1567 memset (strings[0], 0, strlen (strings[0]));
1568 g_strfreev (strings);
1572 user_set_password (AccountsUser *auser,
1573 GDBusMethodInvocation *context,
1574 const gchar *password,
1577 User *user = (User*)auser;
1580 data = g_new (gchar *, 3);
1581 data[0] = g_strdup (password);
1582 data[1] = g_strdup (hint);
1585 daemon_local_check_auth (user->daemon,
1587 "org.freedesktop.accounts.user-administration",
1589 user_change_password_authorized_cb,
1592 (GDestroyNotify)free_passwords);
1594 memset ((char*)password, 0, strlen (password));
1600 user_change_automatic_login_authorized_cb (Daemon *daemon,
1602 GDBusMethodInvocation *context,
1605 gboolean enabled = GPOINTER_TO_INT (data);
1606 GError *error = NULL;
1609 "%s automatic login for user '%s' (%d)",
1610 enabled ? "enable" : "disable", user->user_name, user->uid);
1612 if (!daemon_local_set_automatic_login (daemon, user, enabled, &error)) {
1613 throw_error (context, ERROR_FAILED, "failed to change automatic login: %s", error->message);
1614 g_error_free (error);
1618 accounts_user_complete_set_automatic_login (ACCOUNTS_USER (user), context);
1622 user_set_automatic_login (AccountsUser *auser,
1623 GDBusMethodInvocation *context,
1626 User *user = (User*)auser;
1627 daemon_local_check_auth (user->daemon,
1629 "org.freedesktop.accounts.user-administration",
1631 user_change_automatic_login_authorized_cb,
1633 GINT_TO_POINTER (enabled),
1640 user_get_uid (AccountsUser *user)
1642 return (guint64) USER (user)->uid;
1645 static const gchar *
1646 user_get_user_name (AccountsUser *user)
1648 return USER (user)->user_name;
1651 static const gchar *
1652 user_get_real_name (AccountsUser *user)
1654 return USER (user)->real_name;
1658 user_get_account_type (AccountsUser *user)
1660 return (gint) USER (user)->account_type;
1663 static const gchar *
1664 user_get_home_directory (AccountsUser *user)
1666 return USER (user)->home_dir;
1669 static const gchar *
1670 user_get_shell (AccountsUser *user)
1672 return USER (user)->shell;
1675 static const gchar *
1676 user_get_email (AccountsUser *user)
1678 return USER (user)->email;
1681 static const gchar *
1682 user_get_language (AccountsUser *user)
1684 return USER (user)->language;
1687 static const gchar *
1688 user_get_xsession (AccountsUser *user)
1690 return USER (user)->x_session;
1693 static const gchar *
1694 user_get_location (AccountsUser *user)
1696 return USER (user)->location;
1700 user_get_login_frequency (AccountsUser *user)
1702 return USER (user)->login_frequency;
1705 static const gchar *
1706 user_get_icon_file (AccountsUser *user)
1708 if (USER (user)->icon_file)
1709 return USER (user)->icon_file;
1711 return USER (user)->default_icon_file;
1715 user_get_locked (AccountsUser *user)
1717 return USER (user)->locked;
1721 user_get_password_mode (AccountsUser *user)
1723 return USER (user)->password_mode;
1726 static const gchar *
1727 user_get_password_hint (AccountsUser *user)
1729 return USER (user)->password_hint;
1733 user_get_automatic_login (AccountsUser *user)
1735 return USER (user)->automatic_login;
1739 user_get_system_account (AccountsUser *user)
1741 return USER (user)->system_account;
1745 user_finalize (GObject *object)
1749 user = USER (object);
1751 g_free (user->object_path);
1752 g_free (user->user_name);
1753 g_free (user->real_name);
1754 g_free (user->home_dir);
1755 g_free (user->shell);
1756 g_free (user->icon_file);
1757 g_free (user->default_icon_file);
1758 g_free (user->email);
1759 g_free (user->language);
1760 g_free (user->x_session);
1761 g_free (user->location);
1762 g_free (user->password_hint);
1764 if (G_OBJECT_CLASS (user_parent_class)->finalize)
1765 (*G_OBJECT_CLASS (user_parent_class)->finalize) (object);
1769 user_set_property (GObject *object,
1771 const GValue *value,
1774 User *user = USER (object);
1777 case PROP_ACCOUNT_TYPE:
1778 user->account_type = g_value_get_int (value);
1781 user->language = g_value_dup_string (value);
1783 case PROP_X_SESSION:
1784 user->x_session = g_value_dup_string (value);
1787 user->email = g_value_dup_string (value);
1789 case PROP_LOGIN_FREQUENCY:
1790 user->login_frequency = g_value_get_uint64 (value);
1792 case PROP_AUTOMATIC_LOGIN:
1793 user->automatic_login = g_value_get_boolean (value);
1795 case PROP_SYSTEM_ACCOUNT:
1796 user->system_account = g_value_get_boolean (value);
1799 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1805 user_get_property (GObject *object,
1810 User *user = USER (object);
1814 g_value_set_uint64 (value, user->uid);
1816 case PROP_USER_NAME:
1817 g_value_set_string (value, user->user_name);
1819 case PROP_REAL_NAME:
1820 g_value_set_string (value, user->real_name);
1822 case PROP_ACCOUNT_TYPE:
1823 g_value_set_int (value, user->account_type);
1825 case PROP_PASSWORD_MODE:
1826 g_value_set_int (value, user->password_mode);
1828 case PROP_PASSWORD_HINT:
1829 g_value_set_string (value, user->password_hint);
1832 g_value_set_string (value, user->home_dir);
1835 g_value_set_string (value, user->shell);
1838 g_value_set_string (value, user->email);
1841 g_value_set_string (value, user->language);
1843 case PROP_X_SESSION:
1844 g_value_set_string (value, user->x_session);
1847 g_value_set_string (value, user->location);
1849 case PROP_ICON_FILE:
1850 if (user->icon_file)
1851 g_value_set_string (value, user->icon_file);
1855 icon_file = g_build_filename (user->home_dir, ".face", NULL);
1856 g_value_take_string (value, icon_file);
1859 case PROP_LOGIN_FREQUENCY:
1860 g_value_set_uint64 (value, user->login_frequency);
1863 g_value_set_boolean (value, user->locked);
1865 case PROP_AUTOMATIC_LOGIN:
1866 g_value_set_boolean (value, user->automatic_login);
1868 case PROP_SYSTEM_ACCOUNT:
1869 g_value_set_boolean (value, user->system_account);
1872 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1878 user_class_init (UserClass *class)
1880 GObjectClass *gobject_class;
1882 gobject_class = G_OBJECT_CLASS (class);
1884 gobject_class->get_property = user_get_property;
1885 gobject_class->set_property = user_set_property;
1886 gobject_class->finalize = user_finalize;
1888 accounts_user_override_properties (gobject_class, 1);
1892 user_accounts_user_iface_init (AccountsUserIface *iface)
1894 iface->handle_set_account_type = user_set_account_type;
1895 iface->handle_set_role = user_set_role;
1896 iface->handle_set_automatic_login = user_set_automatic_login;
1897 iface->handle_set_email = user_set_email;
1898 iface->handle_set_home_directory = user_set_home_directory;
1899 iface->handle_set_icon_file = user_set_icon_file;
1900 iface->handle_set_language = user_set_language;
1901 iface->handle_set_location = user_set_location;
1902 iface->handle_set_locked = user_set_locked;
1903 iface->handle_set_password = user_set_password;
1904 iface->handle_set_password_mode = user_set_password_mode;
1905 iface->handle_set_real_name = user_set_real_name;
1906 iface->handle_set_shell = user_set_shell;
1907 iface->handle_set_user_name = user_set_user_name;
1908 iface->handle_set_xsession = user_set_x_session;
1909 iface->get_uid = user_get_uid;
1910 iface->get_user_name = user_get_user_name;
1911 iface->get_real_name = user_get_real_name;
1912 iface->get_account_type = user_get_account_type;
1913 iface->get_home_directory = user_get_home_directory;
1914 iface->get_shell = user_get_shell;
1915 iface->get_email = user_get_email;
1916 iface->get_language = user_get_language;
1917 iface->get_xsession = user_get_xsession;
1918 iface->get_location = user_get_location;
1919 iface->get_login_frequency = user_get_login_frequency;
1920 iface->get_icon_file = user_get_icon_file;
1921 iface->get_locked = user_get_locked;
1922 iface->get_password_mode = user_get_password_mode;
1923 iface->get_password_hint = user_get_password_hint;
1924 iface->get_automatic_login = user_get_automatic_login;
1925 iface->get_system_account = user_get_system_account;
1929 user_init (User *user)
1931 user->system_bus_connection = NULL;
1932 user->object_path = NULL;
1933 user->user_name = NULL;
1934 user->real_name = NULL;
1935 user->account_type = ACCOUNT_TYPE_STANDARD;
1936 user->home_dir = NULL;
1938 user->icon_file = NULL;
1939 user->default_icon_file = NULL;
1941 user->language = NULL;
1942 user->x_session = NULL;
1943 user->location = NULL;
1944 user->password_mode = PASSWORD_MODE_REGULAR;
1945 user->password_hint = NULL;
1946 user->locked = FALSE;
1947 user->automatic_login = FALSE;
1948 user->system_account = FALSE;