2
* Copyright (C) 2000-2002, 2004 Red Hat, Inc.
4
* This is free software; you can redistribute it and/or modify it under
5
* the terms of the GNU Library General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this program; if not, write to the Free Software
16
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
#ident "$Id: lusermod.c,v 1.33 2005/09/12 21:52:02 mitr Exp $"
33
#include "../lib/user_private.h"
37
main(int argc, const char **argv)
39
const char *userPassword = NULL, *cryptedUserPassword = NULL,
40
*uid = NULL, *old_uid = NULL, *user = NULL, *gecos = NULL,
41
*oldHomeDirectory, *homeDirectory = NULL,
42
*loginShell = NULL, *gid_number_str = NULL,
43
*uid_number_str = NULL;
44
const char *username, *groupname;
45
uid_t uidNumber = LU_VALUE_INVALID_ID;
46
gid_t gidNumber = LU_VALUE_INVALID_ID;
47
struct lu_context *ctx = NULL;
48
struct lu_ent *ent = NULL;
49
struct lu_error *error = NULL;
50
GValueArray *values, *members, *admins, *groups = NULL;
53
int change = FALSE, move_home = FALSE, lock = FALSE, unlock = FALSE;
54
int interactive = FALSE;
58
struct poptOption options[] = {
59
{"interactive", 'i', POPT_ARG_NONE, &interactive, 0,
60
"prompt for all information", NULL},
61
{"gecos", 'c', POPT_ARG_STRING, &gecos, 0,
62
"GECOS information", "STRING"},
63
{"directory", 'd', POPT_ARG_STRING, &homeDirectory, 0,
64
"home directory", "STRING"},
65
{"movedirectory", 'm', POPT_ARG_NONE, &move_home, 0,
66
"move home directory contents", NULL},
67
{"shell", 's', POPT_ARG_STRING, &loginShell, 0,
68
"set shell for user", "STRING"},
69
{"uid", 'u', POPT_ARG_STRING, &uid_number_str, 0,
70
"set UID for user", "NUM"},
71
{"gid", 'g', POPT_ARG_STRING, &gid_number_str, 0,
72
"set primary GID for user", "NUM"},
73
{"login", 'l', POPT_ARG_STRING, &uid, 0,
74
"change login name for user", "STRING"},
75
{"plainpassword", 'P', POPT_ARG_STRING, &userPassword, 0,
76
"plaintext password for the user", "STRING"},
77
{"password", 'p', POPT_ARG_STRING, &cryptedUserPassword, 0,
78
"pre-hashed password for the user", "STRING"},
79
{"lock", 'L', POPT_ARG_NONE, &lock, 0, "lock account", NULL},
80
{"unlock", 'U', POPT_ARG_NONE, &unlock, 0,
81
"unlock account", NULL},
82
POPT_AUTOHELP POPT_TABLEEND
86
bindtextdomain(PACKAGE, LOCALEDIR);
88
setlocale(LC_ALL, "");
90
/* Start up the library. */
91
popt = poptGetContext("lusermod", argc, argv, options, 0);
92
poptSetOtherOptionHelp(popt, _("[OPTION...] user"));
93
c = poptGetNextOpt(popt);
95
fprintf(stderr, _("Error parsing arguments: %s.\n"),
97
poptPrintUsage(popt, stderr, 0);
101
/* We need to have been passed a user name on the command-line. We
102
* could just delete some randomly-selected victim^H^H^H^H^H^Huser,
103
* but that would probably upset most system administrators. */
104
user = poptGetArg(popt);
106
fprintf(stderr, _("No user name specified.\n"));
107
poptPrintUsage(popt, stderr, 0);
110
if (gid_number_str != NULL) {
115
val = strtoimax(gid_number_str, &p, 10);
116
if (errno != 0 || *p != 0 || p == gid_number_str
117
|| (gid_t)val != val) {
118
fprintf(stderr, _("Invalid group ID %s\n"),
120
poptPrintUsage(popt, stderr, 0);
125
if (uid_number_str != NULL) {
130
val = strtoimax(uid_number_str, &p, 10);
131
if (errno != 0 || *p != 0 || p == uid_number_str
132
|| (uid_t)val != val) {
133
fprintf(stderr, _("Invalid user ID %s\n"),
135
poptPrintUsage(popt, stderr, 0);
142
/* Start up the library. */
143
ctx = lu_start(NULL, 0, NULL, NULL,
144
interactive ? lu_prompt_console :
145
lu_prompt_console_quiet, NULL, &error);
147
fprintf(stderr, _("Error initializing %s: %s.\n"), PACKAGE,
152
/* Sanity-check arguments. */
153
if (lock && unlock) {
154
fprintf(stderr, _("Both -L and -U specified.\n"));
158
/* Look up the user's record. */
160
if (lu_user_lookup_name(ctx, user, ent, &error) == FALSE) {
161
fprintf(stderr, _("User %s does not exist.\n"), user);
165
/* If the user's password needs to be changed, try to change it. */
166
if (userPassword != NULL) {
167
if (lu_user_setpass(ctx, ent, userPassword, FALSE, &error)
170
_("Failed to set password for user %s: %s.\n"),
171
user, lu_strerror(error));
176
/* If we need to change a user's crypted password, try to change it,
177
* though it might fail if an underlying mechanism doesn't support
179
if (cryptedUserPassword != NULL) {
180
if (lu_user_setpass(ctx, ent, cryptedUserPassword, TRUE,
183
_("Failed to set password for user %s: %s.\n"),
184
user, lu_strerror(error));
189
/* If we need to lock/unlock the user's account, do that. */
191
if (lu_user_lock(ctx, ent, &error) == FALSE) {
193
_("User %s could not be locked: %s.\n"),
194
user, lu_strerror(error));
199
if (lu_user_unlock(ctx, ent, &error) == FALSE) {
201
_("User %s could not be unlocked: %s.\n"),
202
user, lu_strerror(error));
207
/* Determine if we actually need to change anything. */
208
change = uid || gecos || homeDirectory || loginShell ||
209
uidNumber != LU_VALUE_INVALID_ID ||
210
gidNumber != LU_VALUE_INVALID_ID;
212
/* Change the user's UID and GID. */
213
memset(&val, 0, sizeof(val));
215
if (uidNumber != LU_VALUE_INVALID_ID) {
216
lu_value_init_set_id(&val, uidNumber);
217
lu_ent_clear(ent, LU_UIDNUMBER);
218
lu_ent_add(ent, LU_UIDNUMBER, &val);
221
if (gidNumber != LU_VALUE_INVALID_ID) {
222
lu_value_init_set_id(&val, gidNumber);
223
lu_ent_clear(ent, LU_GIDNUMBER);
224
lu_ent_add(ent, LU_GIDNUMBER, &val);
228
/* Change the user's shell and GECOS information. */
229
g_value_init(&val, G_TYPE_STRING);
231
if (loginShell != NULL) {
232
g_value_set_string(&val, loginShell);
233
lu_ent_clear(ent, LU_LOGINSHELL);
234
lu_ent_add(ent, LU_LOGINSHELL, &val);
237
g_value_set_string(&val, gecos);
238
lu_ent_clear(ent, LU_GECOS);
239
lu_ent_add(ent, LU_GECOS, &val);
242
/* If the user changed names or home directories, we need to keep track
243
* of the old values. */
246
values = lu_ent_get(ent, LU_USERNAME);
247
value = g_value_array_get_nth(values, 0);
248
old_uid = lu_value_strdup(value);
249
g_value_set_string(&val, uid);
250
lu_ent_clear(ent, LU_USERNAME);
251
lu_ent_add(ent, LU_USERNAME, &val);
252
groups = lu_groups_enumerate_by_user(ctx, old_uid, &error);
254
lu_error_free(&error);
256
oldHomeDirectory = NULL;
257
if (homeDirectory != NULL) {
258
values = lu_ent_get(ent, LU_HOMEDIRECTORY);
259
value = g_value_array_get_nth(values, 0);
260
oldHomeDirectory = lu_value_strdup(value);
261
g_value_set_string(&val, homeDirectory);
262
lu_ent_clear(ent, LU_HOMEDIRECTORY);
263
lu_ent_add(ent, LU_HOMEDIRECTORY, &val);
268
/* If we need to change anything about the user, do it. */
269
if (change && (lu_user_modify(ctx, ent, &error) == FALSE)) {
270
fprintf(stderr, _("User %s could not be modified: %s.\n"),
271
user, lu_strerror(error));
276
/* If the user's name changed, we need to update supplemental
277
* group membership information. */
278
if (change && (old_uid != NULL)) {
279
for (i = 0; (groups != NULL) && (i < groups->n_values); i++) {
280
struct lu_ent *group;
282
/* Get the name of this group. */
283
value = g_value_array_get_nth(groups, i);
284
groupname = g_value_get_string(value);
285
/* Look up the group. */
286
members = admins = NULL;
287
group = lu_ent_new();
288
if (lu_group_lookup_name(ctx, groupname, group,
290
/* Get a list of the group's members. */
291
members = lu_ent_get(group, LU_MEMBERNAME);
292
admins = lu_ent_get(group, LU_ADMINISTRATORNAME);
294
/* Search for this user in the member list. */
296
(members != NULL) && (j < members->n_values);
298
value = g_value_array_get_nth(members, j);
299
username = g_value_get_string(value);
300
/* If it holds the user's old name, then
301
* set its value to the new name. */
302
if (strcmp(old_uid, username) == 0) {
303
/* Modifies the entity in-place. */
304
g_value_set_string(value, uid);
308
/* Do the same for the administrator list. */
310
(admins != NULL) && (j < admins->n_values);
312
value = g_value_array_get_nth(admins, j);
313
username = g_value_get_string(value);
314
/* If it holds the user's old name, then
315
* set its value to the new name. */
316
if (strcmp(old_uid, username) == 0) {
317
/* Modifies the entity in-place. */
318
g_value_set_string(value, uid);
322
/* Save the changes to the group. */
323
if (lu_group_modify(ctx, group, &error) == FALSE)
324
fprintf(stderr, _("Group %s could not be "
326
groupname, lu_strerror(error));
332
/* If we need to move the user's directory, we do that now. */
333
if (change && move_home) {
334
if (oldHomeDirectory == NULL) {
335
fprintf(stderr, _("No old home directory for %s.\n"),
339
if (homeDirectory == NULL) {
340
fprintf(stderr, _("No new home directory for %s.\n"),
344
if (lu_homedir_move(oldHomeDirectory, homeDirectory,
346
fprintf(stderr, _("Error moving %s to %s: %s.\n"),
347
oldHomeDirectory, homeDirectory,