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>
43
#include <dbus/dbus-glib.h>
44
#include <dbus/dbus-glib-lowlevel.h>
48
#include "user-glue.h"
51
#define ICONDIR LOCALSTATEDIR "/lib/AccountsService/icons"
81
static guint signals[LAST_SIGNAL] = { 0 };
86
DBusGConnection *system_bus_connection;
95
AccountType account_type;
96
PasswordMode password_mode;
102
gchar *formats_locale;
105
guint64 login_frequency;
106
gchar *background_file;
109
gboolean automatic_login;
110
gboolean system_account;
113
typedef struct UserClass
115
GObjectClass parent_class;
118
static void user_finalize (GObject *object);
119
static gchar *user_get_fallback_value (User *user,
120
const gchar *property);
122
G_DEFINE_TYPE (User, user, G_TYPE_OBJECT)
125
user_set_property (GObject *object,
130
User *user = USER (object);
133
case PROP_ACCOUNT_TYPE:
134
user->account_type = g_value_get_int (value);
137
user->language = g_value_dup_string (value);
139
case PROP_FORMATS_LOCALE:
140
user->formats_locale = g_value_dup_string (value);
143
user->x_session = g_value_dup_string (value);
146
user->email = g_value_dup_string (value);
148
case PROP_LOGIN_FREQUENCY:
149
user->login_frequency = g_value_get_uint64 (value);
151
case PROP_AUTOMATIC_LOGIN:
152
user->automatic_login = g_value_get_boolean (value);
154
case PROP_SYSTEM_ACCOUNT:
155
user->system_account = g_value_get_boolean (value);
158
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
164
user_get_property (GObject *object,
169
User *user = USER (object);
173
g_value_set_uint64 (value, user->uid);
176
g_value_set_string (value, user->user_name);
179
g_value_set_string (value, user->real_name);
181
case PROP_ACCOUNT_TYPE:
182
g_value_set_int (value, user->account_type);
184
case PROP_PASSWORD_MODE:
185
g_value_set_int (value, user->password_mode);
187
case PROP_PASSWORD_HINT:
188
g_value_set_string (value, user->password_hint);
191
g_value_set_string (value, user->home_dir);
194
g_value_set_string (value, user->shell);
197
g_value_set_string (value, user->email);
201
g_value_set_string (value, user->language);
203
g_value_set_string (value, user_get_fallback_value (user, "Language"));
205
case PROP_FORMATS_LOCALE:
206
if (user->formats_locale)
207
g_value_set_string (value, user->formats_locale);
209
g_value_set_string (value, user_get_fallback_value (user, "FormatsLocale"));
212
g_value_set_string (value, user->x_session);
215
g_value_set_string (value, user->location);
217
case PROP_BACKGROUND_FILE:
218
g_value_set_string (value, user->background_file);
222
g_value_set_string (value, user->icon_file);
226
icon_file = g_build_filename (user->home_dir, ".face", NULL);
227
g_value_take_string (value, icon_file);
230
case PROP_LOGIN_FREQUENCY:
231
g_value_set_uint64 (value, user->login_frequency);
234
g_value_set_boolean (value, user->locked);
236
case PROP_AUTOMATIC_LOGIN:
237
g_value_set_boolean (value, user->automatic_login);
239
case PROP_SYSTEM_ACCOUNT:
240
g_value_set_boolean (value, user->system_account);
243
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
249
user_class_init (UserClass *class)
251
GObjectClass *gobject_class;
253
gobject_class = G_OBJECT_CLASS (class);
255
gobject_class->get_property = user_get_property;
256
gobject_class->set_property = user_set_property;
257
gobject_class->finalize = user_finalize;
259
dbus_g_object_type_install_info (TYPE_USER,
260
&dbus_glib_user_object_info);
262
signals[CHANGED] = g_signal_new ("changed",
263
G_OBJECT_CLASS_TYPE (class),
268
g_cclosure_marshal_VOID__VOID,
272
g_object_class_install_property (gobject_class,
274
g_param_spec_string ("real-name",
276
"The real name to display for this user.",
280
g_object_class_install_property (gobject_class,
282
g_param_spec_int ("account-type",
284
"The account type for this user.",
285
0, ACCOUNT_TYPE_LAST,
289
g_object_class_install_property (gobject_class,
291
g_param_spec_int ("password-mode",
293
"The password mode for this user.",
294
0, PASSWORD_MODE_LAST,
295
PASSWORD_MODE_REGULAR,
298
g_object_class_install_property (gobject_class,
300
g_param_spec_string ("password-hint",
302
"Hint to help this user remember his password",
306
g_object_class_install_property (gobject_class,
308
g_param_spec_uint64 ("uid",
310
"The UID for this user.",
313
g_object_class_install_property (gobject_class,
315
g_param_spec_string ("user-name",
317
"The login name for this user.",
321
g_object_class_install_property (gobject_class,
323
g_param_spec_string ("home-directory",
325
"The home directory for this user.",
328
g_object_class_install_property (gobject_class,
330
g_param_spec_string ("shell",
332
"The shell for this user.",
335
g_object_class_install_property (gobject_class,
337
g_param_spec_string ("email",
339
"The email address for this user.",
342
g_object_class_install_property (gobject_class,
344
g_param_spec_string ("language",
346
"The language for this user.",
349
g_object_class_install_property (gobject_class,
351
g_param_spec_string ("formats_locale",
353
"The regional formats for this user.",
356
g_object_class_install_property (gobject_class,
358
g_param_spec_string ("x-session",
360
"The session this user logs into.",
363
g_object_class_install_property (gobject_class,
365
g_param_spec_string ("location",
367
"The location of this user.",
370
g_object_class_install_property (gobject_class,
371
PROP_LOGIN_FREQUENCY,
372
g_param_spec_uint64 ("login-frequency",
379
g_object_class_install_property (gobject_class,
380
PROP_BACKGROUND_FILE,
381
g_param_spec_string ("background-file",
383
"The background file to use for this user.",
386
g_object_class_install_property (gobject_class,
388
g_param_spec_string ("icon-file",
390
"The icon file to use for this user.",
394
g_object_class_install_property (gobject_class,
396
g_param_spec_boolean ("locked",
402
g_object_class_install_property (gobject_class,
403
PROP_AUTOMATIC_LOGIN,
404
g_param_spec_boolean ("automatic-login",
410
g_object_class_install_property (gobject_class,
412
g_param_spec_boolean ("system-account",
421
user_init (User *user)
423
user->system_bus_connection = NULL;
424
user->object_path = NULL;
425
user->user_name = NULL;
426
user->real_name = NULL;
427
user->account_type = ACCOUNT_TYPE_STANDARD;
428
user->home_dir = NULL;
430
user->background_file = NULL;
431
user->icon_file = NULL;
433
user->language = NULL;
434
user->formats_locale = NULL;
435
user->x_session = NULL;
436
user->location = NULL;
437
user->password_mode = PASSWORD_MODE_REGULAR;
438
user->password_hint = NULL;
439
user->locked = FALSE;
440
user->automatic_login = FALSE;
441
user->system_account = FALSE;
445
user_finalize (GObject *object)
449
user = USER (object);
451
g_free (user->object_path);
452
g_free (user->user_name);
453
g_free (user->real_name);
454
g_free (user->home_dir);
455
g_free (user->shell);
456
g_free (user->background_file);
457
g_free (user->icon_file);
458
g_free (user->email);
459
g_free (user->language);
460
g_free (user->formats_locale);
461
g_free (user->x_session);
462
g_free (user->location);
463
g_free (user->password_hint);
465
if (G_OBJECT_CLASS (user_parent_class)->finalize)
466
(*G_OBJECT_CLASS (user_parent_class)->finalize) (object);
470
account_type_from_pwent (struct passwd *pwent)
479
if (pwent->pw_uid == 0) {
480
g_debug ("user is root so account type is administrator");
481
return ACCOUNT_TYPE_ADMINISTRATOR;
484
grp = getgrnam ("sudo");
486
g_debug ("sudo group not found");
487
return ACCOUNT_TYPE_STANDARD;
491
/* Ubuntu prior to 12.04 used "admin" */
492
grp = getgrnam ("admin");
494
g_debug ("admin group not found");
500
ngroups = get_user_groups (pwent->pw_name, pwent->pw_gid, &groups);
502
for (i = 0; i < ngroups; i++) {
503
if (groups[i] == sudo || groups[i] == admin) {
505
return ACCOUNT_TYPE_ADMINISTRATOR;
511
return ACCOUNT_TYPE_STANDARD;
515
user_local_update_from_pwent (User *user,
516
struct passwd *pwent)
527
g_object_freeze_notify (G_OBJECT (user));
531
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
532
gchar *first_comma = NULL;
533
gchar *valid_utf8_name = NULL;
535
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
536
valid_utf8_name = pwent->pw_gecos;
537
first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
540
g_warning ("User %s has invalid UTF-8 in GECOS field. "
541
"It would be a good thing to check /etc/passwd.",
542
pwent->pw_name ? pwent->pw_name : "");
546
real_name = g_strndup (valid_utf8_name,
547
(first_comma - valid_utf8_name));
549
else if (valid_utf8_name) {
550
real_name = g_strdup (valid_utf8_name);
556
if (real_name && real_name[0] == '\0') {
564
if (g_strcmp0 (real_name, user->real_name) != 0) {
565
g_free (user->real_name);
566
user->real_name = real_name;
568
g_object_notify (G_OBJECT (user), "real-name");
575
if (pwent->pw_uid != user->uid) {
576
user->uid = pwent->pw_uid;
578
g_object_notify (G_OBJECT (user), "uid");
582
user->gid = pwent->pw_gid;
584
user->account_type = account_type_from_pwent (pwent);
587
if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) {
588
g_free (user->user_name);
589
user->user_name = g_strdup (pwent->pw_name);
591
g_object_notify (G_OBJECT (user), "user-name");
595
if (g_strcmp0 (user->home_dir, pwent->pw_dir) != 0) {
596
g_free (user->home_dir);
597
user->home_dir = g_strdup (pwent->pw_dir);
599
g_object_notify (G_OBJECT (user), "home-directory");
603
if (g_strcmp0 (user->shell, pwent->pw_shell) != 0) {
604
g_free (user->shell);
605
user->shell = g_strdup (pwent->pw_shell);
607
g_object_notify (G_OBJECT (user), "shell");
610
passwd = pwent->pw_passwd;
612
spent = getspnam (pwent->pw_name);
614
passwd = spent->sp_pwdp;
617
if (passwd && passwd[0] == '!') {
624
if (user->locked != locked) {
625
user->locked = locked;
627
g_object_notify (G_OBJECT (user), "locked");
630
if (passwd[0] == 0) {
631
mode = PASSWORD_MODE_NONE;
634
mode = PASSWORD_MODE_REGULAR;
639
if (spent->sp_lstchg == 0) {
640
mode = PASSWORD_MODE_SET_AT_LOGIN;
645
if (user->password_mode != mode) {
646
user->password_mode = mode;
648
g_object_notify (G_OBJECT (user), "password-mode");
651
user->system_account = daemon_local_user_is_excluded (user->daemon,
655
g_object_thaw_notify (G_OBJECT (user));
658
g_signal_emit (user, signals[CHANGED], 0);
662
user_local_update_from_keyfile (User *user,
667
g_object_freeze_notify (G_OBJECT (user));
669
s = g_key_file_get_string (keyfile, "User", "Language", NULL);
671
/* TODO: validate / normalize */
672
g_free (user->language);
676
s = g_key_file_get_string (keyfile, "User", "FormatsLocale", NULL);
678
g_free (user->formats_locale);
679
user->formats_locale = s;
682
s = g_key_file_get_string (keyfile, "User", "XSession", NULL);
684
g_free (user->x_session);
688
s = g_key_file_get_string (keyfile, "User", "Email", NULL);
690
g_free (user->email);
694
s = g_key_file_get_string (keyfile, "User", "Location", NULL);
696
g_free (user->location);
700
s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
702
g_free (user->password_hint);
703
user->password_hint = s;
706
s = g_key_file_get_string (keyfile, "User", "Background", NULL);
708
g_free (user->background_file);
709
user->background_file = s;
712
s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
714
g_free (user->icon_file);
718
g_object_thaw_notify (G_OBJECT (user));
722
user_local_save_to_keyfile (User *user,
726
g_key_file_set_string (keyfile, "User", "Email", user->email);
729
g_key_file_set_string (keyfile, "User", "Language", user->language);
731
if (user->formats_locale)
732
g_key_file_set_string (keyfile, "User", "FormatsLocale", user->formats_locale);
735
g_key_file_set_string (keyfile, "User", "XSession", user->x_session);
738
g_key_file_set_string (keyfile, "User", "Location", user->location);
740
if (user->password_hint)
741
g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint);
743
if (user->background_file)
744
g_key_file_set_string (keyfile, "User", "Background", user->background_file);
747
g_key_file_set_string (keyfile, "User", "Icon", user->icon_file);
751
save_extra_data (User *user)
758
keyfile = g_key_file_new ();
759
user_local_save_to_keyfile (user, keyfile);
762
data = g_key_file_to_data (keyfile, NULL, &error);
764
filename = g_build_filename ("/var/lib/AccountsService/users",
767
g_file_set_contents (filename, data, -1, &error);
771
g_warning ("Saving data for user %s failed: %s",
772
user->user_name, error->message);
773
g_error_free (error);
775
g_key_file_free (keyfile);
779
move_extra_data (const gchar *old_name,
780
const gchar *new_name)
785
old_filename = g_build_filename ("/var/lib/AccountsService/users",
787
new_filename = g_build_filename ("/var/lib/AccountsService/users",
790
g_rename (old_filename, new_filename);
792
g_free (old_filename);
793
g_free (new_filename);
797
compute_object_path (User *user)
801
object_path = g_strdup_printf ("/org/freedesktop/Accounts/User%ld",
808
user_local_register (User *user)
810
DBusConnection *connection;
811
GError *error = NULL;
813
user->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
814
if (user->system_bus_connection == NULL) {
816
g_critical ("error getting system bus: %s", error->message);
817
g_error_free (error);
822
connection = dbus_g_connection_get_connection (user->system_bus_connection);
823
user->object_path = compute_object_path (user);
825
if (dbus_g_connection_lookup_g_object (user->system_bus_connection, user->object_path) != NULL) {
826
g_critical ("Duplicate object at path %s.", user->object_path);
830
dbus_g_connection_register_g_object (user->system_bus_connection,
839
user_local_unregister (User *user)
841
dbus_g_connection_unregister_g_object (user->system_bus_connection,
846
user_local_new (Daemon *daemon, uid_t uid)
850
user = g_object_new (TYPE_USER, NULL);
851
user->daemon = daemon;
858
user_local_get_user_name (User *user)
860
return user->user_name;
864
user_local_get_object_path (User *user)
866
return user->object_path;
870
user_local_get_uid (User *user)
876
throw_error (DBusGMethodInvocation *context,
885
va_start (args, format);
886
message = g_strdup_vprintf (format, args);
889
error = g_error_new (ERROR, error_code, "%s", message);
890
dbus_g_method_return_error (context, error);
891
g_error_free (error);
897
user_change_real_name_authorized_cb (Daemon *daemon,
899
DBusGMethodInvocation *context,
907
if (g_strcmp0 (user->real_name, name) != 0) {
909
"change real name of user '%s' (%d) to '%s'",
910
user->user_name, user->uid, name);
912
argv[0] = "/usr/sbin/usermod";
916
argv[4] = user->user_name;
920
if (!spawn_with_login_uid (context, argv, &error)) {
921
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
922
g_error_free (error);
926
g_free (user->real_name);
927
user->real_name = g_strdup (name);
929
g_signal_emit (user, signals[CHANGED], 0);
931
g_object_notify (G_OBJECT (user), "real-name");
934
dbus_g_method_return (context);
938
user_set_real_name (User *user,
939
const gchar *real_name,
940
DBusGMethodInvocation *context)
943
DBusConnection *connection;
944
DBusError dbus_error;
946
const gchar *action_id;
948
connection = dbus_g_connection_get_connection (user->system_bus_connection);
949
sender = dbus_g_method_get_sender (context);
950
dbus_error_init (&dbus_error);
951
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
952
if (dbus_error_is_set (&dbus_error)) {
953
throw_error (context, ERROR_FAILED, dbus_error.message);
954
dbus_error_free (&dbus_error);
959
if (user->uid == uid)
960
action_id = "org.freedesktop.accounts.change-own-user-data";
962
action_id = "org.freedesktop.accounts.user-administration";
964
daemon_local_check_auth (user->daemon,
968
user_change_real_name_authorized_cb,
970
g_strdup (real_name),
971
(GDestroyNotify)g_free);
977
user_change_user_name_authorized_cb (Daemon *daemon,
979
DBusGMethodInvocation *context,
988
if (g_strcmp0 (user->user_name, name) != 0) {
989
old_name = g_strdup (user->user_name);
991
"change name of user '%s' (%d) to '%s'",
992
old_name, user->uid, name);
994
argv[0] = "/usr/sbin/usermod";
998
argv[4] = user->user_name;
1002
if (!spawn_with_login_uid (context, argv, &error)) {
1003
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1004
g_error_free (error);
1008
g_free (user->user_name);
1009
user->user_name = g_strdup (name);
1011
move_extra_data (old_name, name);
1013
g_signal_emit (user, signals[CHANGED], 0);
1015
g_object_notify (G_OBJECT (user), "user-name");
1018
dbus_g_method_return (context);
1023
user_set_user_name (User *user,
1024
const gchar *user_name,
1025
DBusGMethodInvocation *context)
1028
DBusConnection *connection;
1029
DBusError dbus_error;
1032
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1033
sender = dbus_g_method_get_sender (context);
1034
dbus_error_init (&dbus_error);
1035
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1036
if (dbus_error_is_set (&dbus_error)) {
1037
throw_error (context, ERROR_FAILED, dbus_error.message);
1038
dbus_error_free (&dbus_error);
1043
daemon_local_check_auth (user->daemon,
1045
"org.freedesktop.accounts.user-administration",
1047
user_change_user_name_authorized_cb,
1049
g_strdup (user_name),
1050
(GDestroyNotify)g_free);
1056
user_change_email_authorized_cb (Daemon *daemon,
1058
DBusGMethodInvocation *context,
1062
gchar *email = data;
1064
if (g_strcmp0 (user->email, email) != 0) {
1065
g_free (user->email);
1066
user->email = g_strdup (email);
1068
save_extra_data (user);
1070
g_signal_emit (user, signals[CHANGED], 0);
1072
g_object_notify (G_OBJECT (user), "email");
1075
dbus_g_method_return (context);
1081
user_set_email (User *user,
1083
DBusGMethodInvocation *context)
1086
DBusConnection *connection;
1087
DBusError dbus_error;
1089
const gchar *action_id;
1091
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1092
sender = dbus_g_method_get_sender (context);
1093
dbus_error_init (&dbus_error);
1094
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1095
if (dbus_error_is_set (&dbus_error)) {
1096
throw_error (context, ERROR_FAILED, dbus_error.message);
1097
dbus_error_free (&dbus_error);
1102
if (user->uid == uid)
1103
action_id = "org.freedesktop.accounts.change-own-user-data";
1105
action_id = "org.freedesktop.accounts.user-administration";
1107
daemon_local_check_auth (user->daemon,
1111
user_change_email_authorized_cb,
1114
(GDestroyNotify)g_free);
1120
user_drop_privileges_to_user (User *user)
1122
if (setresgid (user->gid, user->gid, -1) != 0) {
1123
g_warning ("setresgid() failed");
1126
if (setresuid (user->uid, user->uid, -1) != 0) {
1127
g_warning ("setresuid() failed");
1134
user_regain_privileges ()
1136
setresuid (0, 0, -1);
1137
setresgid (0, 0, -1);
1141
user_get_profile_env (User *user,
1151
gchar *profile_path = g_build_path ("/", user->home_dir, ".profile", NULL);
1153
if ((fp = fopen (profile_path, "r"))) {
1156
while ((fgets (line, 50, fp)) != NULL) {
1157
if (g_str_has_prefix (line, "export LANGUAGE=\"")) {
1158
tokens = g_strsplit (line, "\"", 3);
1159
*language = g_strdup (tokens[1]);
1160
g_strfreev (tokens);
1162
if (g_str_has_prefix (line, "export LANG=\"")) {
1163
tokens = g_strsplit (line, "\"", 3);
1164
*lang = g_strdup (tokens[1]);
1165
g_strfreev (tokens);
1167
if (g_str_has_prefix (line, "export LC_MESSAGES=\"")) {
1168
tokens = g_strsplit (line, "\"", 3);
1169
*lcmess = g_strdup (tokens[1]);
1170
g_strfreev (tokens);
1176
g_free (profile_path);
1180
user_locale_utf8_fix (const gchar *locale)
1182
if (locale == NULL || !g_strrstr (locale, ".utf8"))
1183
return g_strdup (locale);
1185
gchar **tokens = g_strsplit_set (locale, ".8", 3);
1186
gchar *fixed_locale = g_strconcat (tokens[0], ".UTF-8", tokens[2], NULL);
1187
g_strfreev (tokens);
1189
return fixed_locale;
1193
user_language_validate (User *user,
1197
const gchar *program = "/usr/share/language-tools/language-validate";
1198
gchar *command = g_strconcat (program, " ", lang, NULL);
1199
gchar *validated_language;
1200
GError *error = NULL;
1202
if (!user_drop_privileges_to_user (user))
1204
ret = g_spawn_command_line_sync (command, &validated_language, NULL, NULL, &error);
1205
user_regain_privileges ();
1209
g_warning ("Couldn't get validated language: %s", error->message);
1210
g_error_free (error);
1213
return g_strchomp (validated_language);
1217
user_locale_validate (const gchar *locale,
1218
DBusGMethodInvocation *context)
1220
gchar *validated_locale = NULL;
1221
gchar *tmp_locale = NULL;
1222
gchar *current = g_strdup (setlocale (LC_ALL, NULL));
1224
if (locale == NULL || strlen (locale) < 2)
1226
tmp_locale = g_strdup (locale);
1227
g_strchomp (tmp_locale);
1229
if (!setlocale (LC_ALL, tmp_locale)) {
1230
throw_error (context, ERROR_FAILED, "'%s' is not a valid locale name", tmp_locale);
1233
validated_locale = user_locale_utf8_fix (tmp_locale);
1236
setlocale (LC_ALL, current);
1237
g_free (tmp_locale);
1240
return validated_locale;
1244
user_get_fallback_value (User *user,
1245
const gchar *property)
1247
gchar *fallback_value = NULL;
1248
gchar *system_language = NULL;
1249
gchar *system_lang = NULL;
1250
gchar *system_lctime = NULL;
1252
gchar *pam_env_path = g_build_path ("/", user->home_dir, ".pam_environment", NULL);
1253
gchar *profile_language = NULL;
1254
gchar *profile_lang = NULL;
1255
gchar *profile_lcmess = NULL;
1257
/* take ~/.profile into account if not migrated */
1258
if (!g_file_test (pam_env_path, G_FILE_TEST_IS_REGULAR))
1259
user_get_profile_env (user,
1265
if ((fp = fopen ("/etc/default/locale", "r"))) {
1268
while ((fgets (line, 50, fp)) != NULL) {
1269
if (g_str_has_prefix (line, "LANGUAGE=\"")) {
1270
tokens = g_strsplit (line, "\"", 3);
1271
system_language = g_strdup (tokens[1]);
1272
g_strfreev (tokens);
1274
if (g_str_has_prefix (line, "LANG=\"")) {
1275
tokens = g_strsplit (line, "\"", 3);
1276
system_lang = g_strdup (tokens[1]);
1277
g_strfreev (tokens);
1279
if (g_str_has_prefix (line, "LC_TIME=\"")) {
1280
tokens = g_strsplit (line, "\"", 3);
1281
system_lctime = g_strdup (tokens[1]);
1282
g_strfreev (tokens);
1288
if (g_strcmp0 (property, "Language") == 0) {
1290
if (profile_language)
1291
tmp = profile_language;
1292
else if (system_language)
1293
tmp = system_language;
1294
else if (profile_lcmess)
1295
tmp = profile_lcmess;
1296
else if (profile_lang)
1298
else if (system_lang)
1300
fallback_value = user_language_validate (user, tmp);
1303
if (g_strcmp0 (property, "FormatsLocale") == 0) {
1306
tmp = system_lctime;
1307
else if (profile_lang)
1309
else if (system_lang)
1311
fallback_value = user_locale_utf8_fix (tmp);
1314
g_free (system_language);
1315
g_free (system_lang);
1316
g_free (system_lctime);
1317
g_free (pam_env_path);
1318
g_free (profile_language);
1319
g_free (profile_lang);
1320
g_free (profile_lcmess);
1322
return fallback_value;
1326
user_update_environment (User *user,
1328
const gchar *script,
1329
DBusGMethodInvocation *context)
1331
/* This function updates ~/.pam_environment by means of the help files in /usr/share/language-tools. */
1334
gchar *validated_data = NULL;
1336
const gchar *allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._+-:/ @";
1338
GError *error = NULL;
1340
program = g_build_path ("/", "/usr/share/language-tools", script, NULL);
1341
gchar *command[] = { program, user->home_dir, data, NULL };
1343
/* test for odd characters in arguments */
1344
for (i = 1; i <= 2; i++) {
1345
if (strlen (command[i]) != strspn (command[i], allowed_chars)) {
1346
throw_error (context, ERROR_FAILED, "non-permitted character(s) in argument");
1351
/* set applicable environment variables in ~/.pam_environment */
1352
if (!user_drop_privileges_to_user (user))
1354
ret = g_spawn_sync ( NULL,
1357
G_SPAWN_STDERR_TO_DEV_NULL,
1364
user_regain_privileges ();
1366
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", program, error->message);
1367
g_error_free (error);
1368
validated_data = NULL;
1371
if (validated_data == NULL || strlen (validated_data) <= 1) {
1372
throw_error (context, ERROR_FAILED, "running '%s' failed: no output", program);
1373
validated_data = NULL;
1379
if (validated_data == NULL)
1382
return g_strchomp (validated_data);
1386
user_migration_from_profile (User *user,
1387
DBusGMethodInvocation *context,
1388
gboolean *is_migrate,
1389
gchar **profile_language,
1390
gchar **profile_formats)
1392
gchar *pam_env_path;
1393
gchar *language = NULL;
1395
gchar *lcmess = NULL;
1397
gchar *command = NULL;
1398
GError *error = NULL;
1399
gboolean ret = FALSE;
1401
*is_migrate = FALSE;
1402
*profile_language = NULL;
1403
*profile_formats = NULL;
1405
pam_env_path = g_build_path ("/", user->home_dir, ".pam_environment", NULL);
1406
if (g_file_test (pam_env_path, G_FILE_TEST_IS_REGULAR))
1411
user_get_profile_env (user, &language, &lang, &lcmess);
1419
*profile_language = user_update_environment (user,
1421
"set-language-helper",
1423
if (*profile_language == NULL)
1428
if (lang && lcmess && g_strcmp0 (lang, lcmess) != 0)
1430
else if (lang && !lcmess)
1433
*profile_formats = user_update_environment (user,
1434
user_locale_validate (tmp, context),
1437
if (*profile_formats == NULL)
1441
const gchar *program = "/usr/share/language-tools/del-profile-env-settings";
1442
command = g_strconcat (program, " '", user->home_dir, "'", NULL);
1443
if (!user_drop_privileges_to_user (user))
1445
gboolean is_success = g_spawn_command_line_sync (command, NULL, NULL, NULL, &error);
1446
user_regain_privileges ();
1448
throw_error (context, ERROR_FAILED, "couldn't edit ~/.profile: %s", error->message);
1449
g_error_free (error);
1456
g_free (pam_env_path);
1466
user_change_language_authorized_cb (Daemon *daemon,
1468
DBusGMethodInvocation *context,
1472
const gchar *fallback_language = user_get_fallback_value (user, "Language");
1473
gboolean is_language_changed = (user->language && g_strcmp0 (user->language, data) != 0)
1474
|| (!user->language && g_strcmp0 (data, fallback_language) != 0);
1476
gboolean is_migrate;
1478
gchar *profile_formats;
1480
gchar *profile_path = g_build_path ("/", user->home_dir, ".profile", NULL);
1481
if (!g_file_test (profile_path, G_FILE_TEST_IS_REGULAR)) {
1483
/* SetLanguage was probably called from a login greeter,
1484
and HOME not mounted and/or not decrypted.
1485
Hence don't save anything, or else accountsservice
1486
and ~/.pam_environment would become out of sync. */
1487
throw_error (context, ERROR_FAILED, "not access to HOME yet so language not saved");
1491
gboolean is_success = user_migration_from_profile (user,
1496
if (is_migrate && !is_success)
1499
if (is_language_changed || is_migrate) {
1500
gchar *language = user_update_environment (user,
1502
"set-language-helper",
1504
if (language != NULL) {
1505
g_free (user->language);
1506
user->language = g_strdup (language);
1509
gchar *locale = NULL;
1511
if (profile_formats)
1512
locale = profile_formats;
1513
else if (!user->formats_locale && is_language_changed) {
1515
/* set the user formats (certain LC_* variables) explicitly
1516
in order to prevent surprises when LANG is changed */
1518
if ((fp = fopen ("/etc/default/locale", "r"))) {
1520
while ((fgets (line, 50, fp)) != NULL) {
1521
if (g_str_has_prefix (line, "LC_TIME=\"")) {
1522
gchar **tokens = g_strsplit (line, "\"", 3);
1523
locale = g_strdup (tokens[1]);
1524
g_strfreev (tokens);
1530
if (locale == NULL) {
1531
GError *error = NULL;
1532
const gchar *program = "/usr/share/language-tools/language2locale";
1533
if (!user_drop_privileges_to_user (user))
1535
gchar *command = g_strconcat (program, " ", fallback_language, NULL);
1536
gboolean ret = g_spawn_command_line_sync (command, &locale, NULL, NULL, &error);
1537
user_regain_privileges ();
1539
throw_error (context, ERROR_FAILED,
1540
"language-to-locale conversion failed: %s", error->message);
1541
g_error_free (error);
1548
if (locale != NULL && strlen (locale) > 0) {
1549
gchar *formats_locale = user_update_environment (user,
1550
user_locale_validate (locale, context),
1553
if (formats_locale != NULL) {
1554
g_free (user->formats_locale);
1555
user->formats_locale = g_strdup (formats_locale);
1560
save_extra_data (user);
1562
g_signal_emit (user, signals[CHANGED], 0);
1564
g_object_notify (G_OBJECT (user), "language");
1568
g_free (profile_path);
1569
dbus_g_method_return (context);
1575
user_set_language (User *user,
1576
const gchar *language,
1577
DBusGMethodInvocation *context)
1580
DBusConnection *connection;
1581
DBusError dbus_error;
1583
const gchar *action_id;
1585
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1586
sender = dbus_g_method_get_sender (context);
1587
dbus_error_init (&dbus_error);
1588
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1589
if (dbus_error_is_set (&dbus_error)) {
1590
throw_error (context, ERROR_FAILED, dbus_error.message);
1591
dbus_error_free (&dbus_error);
1596
if (user->uid == uid)
1597
action_id = "org.freedesktop.accounts.change-own-user-data";
1599
action_id = "org.freedesktop.accounts.user-administration";
1601
daemon_local_check_auth (user->daemon,
1605
user_change_language_authorized_cb,
1607
g_strdup (language),
1608
(GDestroyNotify)g_free);
1614
user_change_formats_locale_authorized_cb (Daemon *daemon,
1616
DBusGMethodInvocation *context,
1620
gboolean is_migrate;
1621
gchar *profile_language;
1624
gboolean is_success = user_migration_from_profile (user,
1629
if (is_migrate && !is_success)
1632
if (g_strcmp0 (user->formats_locale, data) != 0 || is_migrate) {
1633
gchar *formats_locale = user_update_environment (user,
1634
user_locale_validate (data, context),
1637
if (formats_locale != NULL) {
1638
g_free (user->formats_locale);
1639
user->formats_locale = g_strdup (formats_locale);
1642
if (profile_language != NULL) {
1643
gchar *language = user_update_environment (user,
1645
"set-language-helper",
1647
if (language != NULL) {
1648
g_free (user->language);
1649
user->language = g_strdup (language);
1653
save_extra_data (user);
1655
g_signal_emit (user, signals[CHANGED], 0);
1657
g_object_notify (G_OBJECT (user), "formats_locale");
1661
dbus_g_method_return (context);
1665
user_set_formats_locale (User *user,
1666
const gchar *formats_locale,
1667
DBusGMethodInvocation *context)
1670
DBusConnection *connection;
1671
DBusError dbus_error;
1673
const gchar *action_id;
1675
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1676
sender = dbus_g_method_get_sender (context);
1677
dbus_error_init (&dbus_error);
1678
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1679
if (dbus_error_is_set (&dbus_error)) {
1680
throw_error (context, ERROR_FAILED, dbus_error.message);
1681
dbus_error_free (&dbus_error);
1686
if (user->uid == uid)
1687
action_id = "org.freedesktop.accounts.change-own-user-data";
1689
action_id = "org.freedesktop.accounts.user-administration";
1691
daemon_local_check_auth (user->daemon,
1695
user_change_formats_locale_authorized_cb,
1697
g_strdup (formats_locale),
1698
(GDestroyNotify) g_free);
1704
user_change_x_session_authorized_cb (Daemon *daemon,
1706
DBusGMethodInvocation *context,
1710
gchar *x_session = data;
1712
if (g_strcmp0 (user->x_session, x_session) != 0) {
1713
g_free (user->x_session);
1714
user->x_session = g_strdup (x_session);
1716
save_extra_data (user);
1718
g_signal_emit (user, signals[CHANGED], 0);
1720
g_object_notify (G_OBJECT (user), "x-session");
1723
dbus_g_method_return (context);
1727
user_set_x_session (User *user,
1728
const gchar *x_session,
1729
DBusGMethodInvocation *context)
1732
DBusConnection *connection;
1733
DBusError dbus_error;
1735
const gchar *action_id;
1737
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1738
sender = dbus_g_method_get_sender (context);
1739
dbus_error_init (&dbus_error);
1740
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1741
if (dbus_error_is_set (&dbus_error)) {
1742
throw_error (context, ERROR_FAILED, dbus_error.message);
1743
dbus_error_free (&dbus_error);
1748
if (user->uid == uid)
1749
action_id = "org.freedesktop.accounts.change-own-user-data";
1751
action_id = "org.freedesktop.accounts.user-administration";
1753
daemon_local_check_auth (user->daemon,
1757
user_change_x_session_authorized_cb,
1759
g_strdup (x_session),
1760
(GDestroyNotify) g_free);
1766
user_change_location_authorized_cb (Daemon *daemon,
1768
DBusGMethodInvocation *context,
1772
gchar *location = data;
1774
if (g_strcmp0 (user->location, location) != 0) {
1775
g_free (user->location);
1776
user->location = g_strdup (location);
1778
save_extra_data (user);
1780
g_signal_emit (user, signals[CHANGED], 0);
1782
g_object_notify (G_OBJECT (user), "location");
1785
dbus_g_method_return (context);
1789
user_set_location (User *user,
1790
const gchar *location,
1791
DBusGMethodInvocation *context)
1794
DBusConnection *connection;
1795
DBusError dbus_error;
1797
const gchar *action_id;
1799
connection = dbus_g_connection_get_connection (user->system_bus_connection);
1800
sender = dbus_g_method_get_sender (context);
1801
dbus_error_init (&dbus_error);
1802
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
1803
if (dbus_error_is_set (&dbus_error)) {
1804
throw_error (context, ERROR_FAILED, dbus_error.message);
1805
dbus_error_free (&dbus_error);
1810
if (user->uid == uid)
1811
action_id = "org.freedesktop.accounts.change-own-user-data";
1813
action_id = "org.freedesktop.accounts.user-administration";
1815
daemon_local_check_auth (user->daemon,
1819
user_change_location_authorized_cb,
1821
g_strdup (location),
1822
(GDestroyNotify)g_free);
1828
user_change_home_dir_authorized_cb (Daemon *daemon,
1830
DBusGMethodInvocation *context,
1834
gchar *home_dir = data;
1838
if (g_strcmp0 (user->home_dir, home_dir) != 0) {
1840
"change home directory of user '%s' (%d) to '%s'",
1841
user->user_name, user->uid, home_dir);
1843
argv[0] = "/usr/sbin/usermod";
1848
argv[5] = user->user_name;
1852
if (!spawn_with_login_uid (context, argv, &error)) {
1853
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1854
g_error_free (error);
1858
g_free (user->home_dir);
1859
user->home_dir = g_strdup (home_dir);
1861
g_signal_emit (user, signals[CHANGED], 0);
1863
g_object_notify (G_OBJECT (user), "home-directory");
1866
dbus_g_method_return (context);
1870
user_set_home_directory (User *user,
1871
const gchar *home_dir,
1872
DBusGMethodInvocation *context)
1874
daemon_local_check_auth (user->daemon,
1876
"org.freedesktop.accounts.user-administration",
1878
user_change_home_dir_authorized_cb,
1880
g_strdup (home_dir),
1881
(GDestroyNotify)g_free);
1887
user_change_shell_authorized_cb (Daemon *daemon,
1889
DBusGMethodInvocation *context,
1893
gchar *shell = data;
1897
if (g_strcmp0 (user->shell, shell) != 0) {
1899
"change shell of user '%s' (%d) to '%s'",
1900
user->user_name, user->uid, shell);
1902
argv[0] = "/usr/sbin/usermod";
1906
argv[4] = user->user_name;
1910
if (!spawn_with_login_uid (context, argv, &error)) {
1911
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
1912
g_error_free (error);
1916
g_free (user->shell);
1917
user->shell = g_strdup (shell);
1919
g_signal_emit (user, signals[CHANGED], 0);
1921
g_object_notify (G_OBJECT (user), "shell");
1924
dbus_g_method_return (context);
1928
user_set_shell (User *user,
1930
DBusGMethodInvocation *context)
1932
daemon_local_check_auth (user->daemon,
1934
"org.freedesktop.accounts.user-administration",
1936
user_change_shell_authorized_cb,
1939
(GDestroyNotify)g_free);
1945
become_user (gpointer data)
1947
struct passwd *pw = data;
1950
initgroups (pw->pw_name, pw->pw_gid) != 0 ||
1951
setgid (pw->pw_gid) != 0 ||
1952
setuid (pw->pw_uid) != 0) {
1958
user_change_background_file_authorized_cb (Daemon *daemon,
1960
DBusGMethodInvocation *context,
1968
filename = g_strdup (data);
1970
if (filename == NULL ||
1971
*filename == '\0') {
1975
goto background_saved;
1978
file = g_file_new_for_path (filename);
1979
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
1981
type = g_file_info_get_file_type (info);
1983
g_object_unref (info);
1984
g_object_unref (file);
1986
if (type != G_FILE_TYPE_REGULAR) {
1987
g_debug ("not a regular file\n");
1988
throw_error (context, ERROR_FAILED, "file '%s' is not a regular file", filename);
1994
g_free (user->background_file);
1995
user->background_file = filename;
1997
save_extra_data (user);
1999
g_signal_emit (user, signals[CHANGED], 0);
2001
g_object_notify (G_OBJECT (user), "background-file");
2003
dbus_g_method_return (context);
2007
user_set_background_file (User *user,
2008
const gchar *filename,
2009
DBusGMethodInvocation *context)
2012
DBusConnection *connection;
2013
DBusError dbus_error;
2015
const gchar *action_id;
2017
connection = dbus_g_connection_get_connection (user->system_bus_connection);
2018
sender = dbus_g_method_get_sender (context);
2019
dbus_error_init (&dbus_error);
2020
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
2021
if (dbus_error_is_set (&dbus_error)) {
2022
throw_error (context, ERROR_FAILED, dbus_error.message);
2023
dbus_error_free (&dbus_error);
2028
if (user->uid == uid)
2029
action_id = "org.freedesktop.accounts.change-own-user-data";
2031
action_id = "org.freedesktop.accounts.user-administration";
2033
daemon_local_check_auth (user->daemon,
2037
user_change_background_file_authorized_cb,
2039
g_strdup (filename),
2040
(GDestroyNotify)g_free);
2046
user_change_icon_file_authorized_cb (Daemon *daemon,
2048
DBusGMethodInvocation *context,
2059
filename = g_strdup (data);
2061
if (filename == NULL ||
2062
*filename == '\0') {
2070
dest_path = g_build_filename (ICONDIR, user->user_name, NULL);
2071
dest = g_file_new_for_path (dest_path);
2075
if (!g_file_delete (dest, NULL, &error)) {
2076
g_object_unref (dest);
2077
throw_error (context, ERROR_FAILED, "failed to remove user icon, %s", error->message);
2078
g_error_free (error);
2081
g_object_unref (dest);
2085
file = g_file_new_for_path (filename);
2086
info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_MODE ","
2087
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
2088
G_FILE_ATTRIBUTE_STANDARD_SIZE,
2090
mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
2091
type = g_file_info_get_file_type (info);
2092
size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
2094
g_object_unref (info);
2095
g_object_unref (file);
2097
if (type != G_FILE_TYPE_REGULAR) {
2098
g_debug ("not a regular file\n");
2099
throw_error (context, ERROR_FAILED, "file '%s' is not a regular file", filename);
2104
if (size > 1048576) {
2105
g_debug ("file too large\n");
2106
/* 1MB ought to be enough for everybody */
2107
throw_error (context, ERROR_FAILED, "file '%s' is too large to be used as an icon", filename);
2112
if ((mode & S_IROTH) == 0 ||
2113
(!g_str_has_prefix (filename, DATADIR) &&
2114
!g_str_has_prefix (filename, ICONDIR))) {
2120
GInputStream *input;
2121
GOutputStream *output;
2126
if (!get_caller_uid (context, &uid)) {
2127
throw_error (context, ERROR_FAILED, "failed to copy file, could not determine caller UID");
2132
dest_path = g_build_filename (ICONDIR, user->user_name, NULL);
2133
dest = g_file_new_for_path (dest_path);
2136
output = G_OUTPUT_STREAM (g_file_replace (dest, NULL, FALSE, 0, NULL, &error));
2138
throw_error (context, ERROR_FAILED, "creating file '%s' failed: %s", dest_path, error->message);
2139
g_error_free (error);
2142
g_object_unref (dest);
2146
argv[0] = "/bin/cat";
2150
pw = getpwuid (uid);
2153
if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, become_user, pw, NULL, NULL, &std_out, NULL, &error)) {
2154
throw_error (context, ERROR_FAILED, "reading file '%s' failed: %s", filename, error->message);
2155
g_error_free (error);
2158
g_object_unref (dest);
2162
input = g_unix_input_stream_new (std_out, FALSE);
2165
bytes = g_output_stream_splice (output, input, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
2166
if (bytes < 0 || bytes != size) {
2167
throw_error (context, ERROR_FAILED, "copying file '%s' to '%s' failed: %s", filename, dest_path, error ? error->message : "unknown reason");
2169
g_error_free (error);
2171
g_file_delete (dest, NULL, NULL);
2175
g_object_unref (dest);
2176
g_object_unref (input);
2177
g_object_unref (output);
2181
g_object_unref (dest);
2182
g_object_unref (input);
2183
g_object_unref (output);
2186
filename = dest_path;
2190
g_free (user->icon_file);
2191
user->icon_file = filename;
2193
save_extra_data (user);
2195
g_signal_emit (user, signals[CHANGED], 0);
2197
g_object_notify (G_OBJECT (user), "icon-file");
2199
dbus_g_method_return (context);
2203
user_set_icon_file (User *user,
2204
const gchar *filename,
2205
DBusGMethodInvocation *context)
2208
DBusConnection *connection;
2209
DBusError dbus_error;
2211
const gchar *action_id;
2213
connection = dbus_g_connection_get_connection (user->system_bus_connection);
2214
sender = dbus_g_method_get_sender (context);
2215
dbus_error_init (&dbus_error);
2216
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
2217
if (dbus_error_is_set (&dbus_error)) {
2218
throw_error (context, ERROR_FAILED, dbus_error.message);
2219
dbus_error_free (&dbus_error);
2224
if (user->uid == uid)
2225
action_id = "org.freedesktop.accounts.change-own-user-data";
2227
action_id = "org.freedesktop.accounts.user-administration";
2229
daemon_local_check_auth (user->daemon,
2233
user_change_icon_file_authorized_cb,
2235
g_strdup (filename),
2236
(GDestroyNotify)g_free);
2242
user_change_locked_authorized_cb (Daemon *daemon,
2244
DBusGMethodInvocation *context,
2248
gboolean locked = GPOINTER_TO_INT (data);
2252
if (user->locked != locked) {
2254
"%s account of user '%s' (%d)",
2255
locked ? "locking" : "unlocking", user->user_name, user->uid);
2256
argv[0] = "/usr/sbin/usermod";
2257
argv[1] = locked ? "-L" : "-U";
2259
argv[3] = user->user_name;
2263
if (!spawn_with_login_uid (context, argv, &error)) {
2264
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2265
g_error_free (error);
2269
user->locked = locked;
2271
g_signal_emit (user, signals[CHANGED], 0);
2273
g_object_notify (G_OBJECT (user), "locked");
2276
dbus_g_method_return (context);
2280
user_set_locked (User *user,
2282
DBusGMethodInvocation *context)
2284
daemon_local_check_auth (user->daemon,
2286
"org.freedesktop.accounts.user-administration",
2288
user_change_locked_authorized_cb,
2290
GINT_TO_POINTER (locked),
2297
user_change_account_type_authorized_cb (Daemon *daemon,
2299
DBusGMethodInvocation *context,
2303
gint account_type = GPOINTER_TO_INT (data);
2313
if (user->account_type != account_type) {
2315
"change account type of user '%s' (%d) to %d",
2316
user->user_name, user->uid, account_type);
2318
grp = getgrnam ("sudo");
2320
throw_error (context, ERROR_FAILED, "failed to set account type: sudo group not found");
2323
admin = grp->gr_gid;
2325
ngroups = get_user_groups (user->user_name, user->gid, &groups);
2327
str = g_string_new ("");
2328
for (i = 0; i < ngroups; i++) {
2329
if (groups[i] == admin)
2331
g_string_append_printf (str, "%d,", groups[i]);
2333
switch (account_type) {
2334
case ACCOUNT_TYPE_ADMINISTRATOR:
2335
g_string_append_printf (str, "%d", admin);
2338
/* remove excess comma */
2339
g_string_truncate (str, str->len - 1);
2344
argv[0] = "/usr/sbin/usermod";
2348
argv[4] = user->user_name;
2351
g_string_free (str, FALSE);
2354
if (!spawn_with_login_uid (context, argv, &error)) {
2355
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2356
g_error_free (error);
2360
user->account_type = account_type;
2362
g_signal_emit (user, signals[CHANGED], 0);
2364
g_object_notify (G_OBJECT (user), "account-type");
2367
dbus_g_method_return (context);
2371
user_set_account_type (User *user,
2373
DBusGMethodInvocation *context)
2375
if (account_type < 0 || account_type > ACCOUNT_TYPE_LAST) {
2376
throw_error (context, ERROR_FAILED, "unknown account type: %d", account_type);
2380
daemon_local_check_auth (user->daemon,
2382
"org.freedesktop.accounts.user-administration",
2384
user_change_account_type_authorized_cb,
2386
GINT_TO_POINTER (account_type),
2393
user_change_password_mode_authorized_cb (Daemon *daemon,
2395
DBusGMethodInvocation *context,
2399
gint mode = GPOINTER_TO_INT (data);
2403
if (user->password_mode != mode) {
2405
"change password mode of user '%s' (%d) to %d",
2406
user->user_name, user->uid, mode);
2408
g_object_freeze_notify (G_OBJECT (user));
2410
if (mode == PASSWORD_MODE_SET_AT_LOGIN ||
2411
mode == PASSWORD_MODE_NONE) {
2413
argv[0] = "/usr/bin/passwd";
2416
argv[3] = user->user_name;
2420
if (!spawn_with_login_uid (context, argv, &error)) {
2421
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2422
g_error_free (error);
2426
if (mode == PASSWORD_MODE_NONE) {
2427
argv[0] = "/usr/bin/gpasswd";
2429
argv[2] = user->user_name;
2430
argv[3] = "nopasswdlogin";
2434
if (!spawn_with_login_uid (context, argv, &error)) {
2435
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2436
g_error_free (error);
2441
if (mode == PASSWORD_MODE_SET_AT_LOGIN) {
2442
argv[0] = "/usr/bin/chage";
2446
argv[4] = user->user_name;
2450
if (!spawn_with_login_uid (context, argv, &error)) {
2451
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2452
g_error_free (error);
2457
g_free (user->password_hint);
2458
user->password_hint = NULL;
2460
g_object_notify (G_OBJECT (user), "password-hint");
2462
/* removing the password has the side-effect of
2463
* unlocking the account
2466
user->locked = FALSE;
2467
g_object_notify (G_OBJECT (user), "locked");
2470
else if (user->locked) {
2471
argv[0] = "/usr/sbin/usermod";
2474
argv[3] = user->user_name;
2478
if (!spawn_with_login_uid (context, argv, &error)) {
2479
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2480
g_error_free (error);
2484
user->locked = FALSE;
2485
g_object_notify (G_OBJECT (user), "locked");
2488
/* Remember to remove user from nopasswdlogin group if we're
2489
switching away from no-password mode */
2490
if (user->password_mode == PASSWORD_MODE_NONE) {
2491
argv[0] = "/usr/bin/gpasswd";
2493
argv[2] = user->user_name;
2494
argv[3] = "nopasswdlogin";
2498
if (!spawn_with_login_uid (context, argv, &error)) {
2499
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2500
g_error_free (error);
2505
user->password_mode = mode;
2507
g_object_notify (G_OBJECT (user), "password-mode");
2509
save_extra_data (user);
2511
g_object_thaw_notify (G_OBJECT (user));
2513
g_signal_emit (user, signals[CHANGED], 0);
2516
dbus_g_method_return (context);
2520
user_set_password_mode (User *user,
2522
DBusGMethodInvocation *context)
2525
DBusConnection *connection;
2526
DBusError dbus_error;
2528
const gchar *action_id;
2530
if (mode < 0 || mode > PASSWORD_MODE_LAST) {
2531
throw_error (context, ERROR_FAILED, "unknown password mode: %d", mode);
2535
connection = dbus_g_connection_get_connection (user->system_bus_connection);
2536
sender = dbus_g_method_get_sender (context);
2537
dbus_error_init (&dbus_error);
2538
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
2539
if (dbus_error_is_set (&dbus_error)) {
2540
throw_error (context, ERROR_FAILED, dbus_error.message);
2541
dbus_error_free (&dbus_error);
2546
action_id = "org.freedesktop.accounts.user-administration";
2548
daemon_local_check_auth (user->daemon,
2552
user_change_password_mode_authorized_cb,
2554
GINT_TO_POINTER (mode),
2561
user_change_password_authorized_cb (Daemon *daemon,
2563
DBusGMethodInvocation *context,
2567
gchar **strings = data;
2572
"set password and hint of user '%s' (%d)",
2573
user->user_name, user->uid);
2575
g_object_freeze_notify (G_OBJECT (user));
2577
argv[0] = "/usr/sbin/usermod";
2579
argv[2] = strings[0];
2581
argv[4] = user->user_name;
2585
if (!spawn_with_login_uid (context, argv, &error)) {
2586
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2587
g_error_free (error);
2591
/* Drop user from nopasswdlogin group */
2592
argv[0] = "/usr/bin/gpasswd";
2594
argv[2] = user->user_name;
2595
argv[3] = "nopasswdlogin";
2599
if (!spawn_with_login_uid (context, argv, &error)) {
2600
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
2601
g_error_free (error);
2605
if (user->password_mode != PASSWORD_MODE_REGULAR) {
2606
user->password_mode = PASSWORD_MODE_REGULAR;
2607
g_object_notify (G_OBJECT (user), "password-mode");
2611
user->locked = FALSE;
2612
g_object_notify (G_OBJECT (user), "locked");
2615
if (g_strcmp0 (user->password_hint, strings[1]) != 0) {
2616
g_free (user->password_hint);
2617
user->password_hint = g_strdup (strings[1]);
2618
g_object_notify (G_OBJECT (user), "password-hint");
2621
save_extra_data (user);
2623
g_object_thaw_notify (G_OBJECT (user));
2625
g_signal_emit (user, signals[CHANGED], 0);
2627
dbus_g_method_return (context);
2631
free_passwords (gchar **strings)
2633
memset (strings[0], 0, strlen (strings[0]));
2634
g_strfreev (strings);
2638
user_set_password (User *user,
2639
const gchar *password,
2641
DBusGMethodInvocation *context)
2644
DBusConnection *connection;
2645
DBusError dbus_error;
2649
connection = dbus_g_connection_get_connection (user->system_bus_connection);
2650
sender = dbus_g_method_get_sender (context);
2651
dbus_error_init (&dbus_error);
2652
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
2653
if (dbus_error_is_set (&dbus_error)) {
2654
throw_error (context, ERROR_FAILED, dbus_error.message);
2655
dbus_error_free (&dbus_error);
2660
data = g_new (gchar *, 3);
2661
data[0] = g_strdup (password);
2662
data[1] = g_strdup (hint);
2665
daemon_local_check_auth (user->daemon,
2667
"org.freedesktop.accounts.user-administration",
2669
user_change_password_authorized_cb,
2672
(GDestroyNotify)free_passwords);
2674
memset ((char*)password, 0, strlen (password));
2680
user_change_automatic_login_authorized_cb (Daemon *daemon,
2682
DBusGMethodInvocation *context,
2685
gboolean enabled = GPOINTER_TO_INT (data);
2686
GError *error = NULL;
2689
"%s automatic login for user '%s' (%d)",
2690
enabled ? "enable" : "disable", user->user_name, user->uid);
2692
if (!daemon_local_set_automatic_login (daemon, user, enabled, &error)) {
2693
throw_error (context, ERROR_FAILED, "failed to change automatic login: %s", error->message);
2694
g_error_free (error);
2698
dbus_g_method_return (context);
2702
user_set_automatic_login (User *user,
2704
DBusGMethodInvocation *context)
2706
daemon_local_check_auth (user->daemon,
2708
"org.freedesktop.accounts.user-administration",
2710
user_change_automatic_login_authorized_cb,
2712
GINT_TO_POINTER (enabled),