~ubuntu-branches/ubuntu/utopic/libuser/utopic-proposed

« back to all changes in this revision

Viewing changes to apps/lusermod.c

  • Committer: Bazaar Package Importer
  • Author(s): Ghe Rivero
  • Date: 2005-09-30 16:22:04 UTC
  • Revision ID: james.westby@ubuntu.com-20050930162204-qubxaa7e2lbovdgh
Tags: upstream-0.54.dfsg.1
ImportĀ upstreamĀ versionĀ 0.54.dfsg.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2000-2002, 2004 Red Hat, Inc.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
#ident "$Id: lusermod.c,v 1.33 2005/09/12 21:52:02 mitr Exp $"
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include "config.h"
 
23
#endif
 
24
#include <errno.h>
 
25
#include <inttypes.h>
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <unistd.h>
 
29
#include <libintl.h>
 
30
#include <locale.h>
 
31
#include <popt.h>
 
32
#include <string.h>
 
33
#include "../lib/user_private.h"
 
34
#include "apputil.h"
 
35
 
 
36
int
 
37
main(int argc, const char **argv)
 
38
{
 
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;
 
51
        GValue *value, val;
 
52
        size_t i, j;
 
53
        int change = FALSE, move_home = FALSE, lock = FALSE, unlock = FALSE;
 
54
        int interactive = FALSE;
 
55
        int c;
 
56
 
 
57
        poptContext popt;
 
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
 
83
        };
 
84
 
 
85
        /* Set up i18n. */
 
86
        bindtextdomain(PACKAGE, LOCALEDIR);
 
87
        textdomain(PACKAGE);
 
88
        setlocale(LC_ALL, "");
 
89
 
 
90
        /* Start up the library. */
 
91
        popt = poptGetContext("lusermod", argc, argv, options, 0);
 
92
        poptSetOtherOptionHelp(popt, _("[OPTION...] user"));
 
93
        c = poptGetNextOpt(popt);
 
94
        if (c != -1) {
 
95
                fprintf(stderr, _("Error parsing arguments: %s.\n"),
 
96
                        poptStrerror(c));
 
97
                poptPrintUsage(popt, stderr, 0);
 
98
                exit(1);
 
99
        }
 
100
 
 
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);
 
105
        if (user == NULL) {
 
106
                fprintf(stderr, _("No user name specified.\n"));
 
107
                poptPrintUsage(popt, stderr, 0);
 
108
                return 1;
 
109
        }
 
110
        if (gid_number_str != NULL) {
 
111
                intmax_t val;
 
112
                char *p;
 
113
 
 
114
                errno = 0;
 
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"),
 
119
                                gid_number_str);
 
120
                        poptPrintUsage(popt, stderr, 0);
 
121
                        return 1;
 
122
                }
 
123
                gidNumber = val;
 
124
        }
 
125
        if (uid_number_str != NULL) {
 
126
                intmax_t val;
 
127
                char *p;
 
128
 
 
129
                errno = 0;
 
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"),
 
134
                                uid_number_str);
 
135
                        poptPrintUsage(popt, stderr, 0);
 
136
                        return 1;
 
137
                }
 
138
                uidNumber = val;
 
139
        }
 
140
 
 
141
 
 
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);
 
146
        if (ctx == NULL) {
 
147
                fprintf(stderr, _("Error initializing %s: %s.\n"), PACKAGE,
 
148
                        lu_strerror(error));
 
149
                return 1;
 
150
        }
 
151
 
 
152
        /* Sanity-check arguments. */
 
153
        if (lock && unlock) {
 
154
                fprintf(stderr, _("Both -L and -U specified.\n"));
 
155
                return 2;
 
156
        }
 
157
 
 
158
        /* Look up the user's record. */
 
159
        ent = lu_ent_new();
 
160
        if (lu_user_lookup_name(ctx, user, ent, &error) == FALSE) {
 
161
                fprintf(stderr, _("User %s does not exist.\n"), user);
 
162
                return 3;
 
163
        }
 
164
 
 
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)
 
168
                    == FALSE) {
 
169
                        fprintf(stderr,
 
170
                                _("Failed to set password for user %s: %s.\n"),
 
171
                                user, lu_strerror(error));
 
172
                        return 5;
 
173
                }
 
174
        }
 
175
 
 
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
 
178
         * using them. */
 
179
        if (cryptedUserPassword != NULL) {
 
180
                if (lu_user_setpass(ctx, ent, cryptedUserPassword, TRUE,
 
181
                                    &error) == FALSE) {
 
182
                        fprintf(stderr,
 
183
                                _("Failed to set password for user %s: %s.\n"),
 
184
                                user, lu_strerror(error));
 
185
                        return 6;
 
186
                }
 
187
        }
 
188
 
 
189
        /* If we need to lock/unlock the user's account, do that. */
 
190
        if (lock) {
 
191
                if (lu_user_lock(ctx, ent, &error) == FALSE) {
 
192
                        fprintf(stderr,
 
193
                                _("User %s could not be locked: %s.\n"),
 
194
                                user, lu_strerror(error));
 
195
                        return 7;
 
196
                }
 
197
        }
 
198
        if (unlock) {
 
199
                if (lu_user_unlock(ctx, ent, &error) == FALSE) {
 
200
                        fprintf(stderr,
 
201
                                _("User %s could not be unlocked: %s.\n"),
 
202
                                user, lu_strerror(error));
 
203
                        return 8;
 
204
                }
 
205
        }
 
206
 
 
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;
 
211
 
 
212
        /* Change the user's UID and GID. */
 
213
        memset(&val, 0, sizeof(val));
 
214
 
 
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);
 
219
                g_value_unset(&val);
 
220
        }
 
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);
 
225
                g_value_unset(&val);
 
226
        }
 
227
 
 
228
        /* Change the user's shell and GECOS information. */
 
229
        g_value_init(&val, G_TYPE_STRING);
 
230
 
 
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);
 
235
        }
 
236
        if (gecos != NULL) {
 
237
                g_value_set_string(&val, gecos);
 
238
                lu_ent_clear(ent, LU_GECOS);
 
239
                lu_ent_add(ent, LU_GECOS, &val);
 
240
        }
 
241
 
 
242
        /* If the user changed names or home directories, we need to keep track
 
243
         * of the old values. */
 
244
        old_uid = NULL;
 
245
        if (uid != NULL) {
 
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);
 
253
                if (error)
 
254
                        lu_error_free(&error);
 
255
        }
 
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);
 
264
        }
 
265
 
 
266
        g_value_unset(&val);
 
267
 
 
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));
 
272
                return 9;
 
273
        }
 
274
        lu_hup_nscd();
 
275
 
 
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;
 
281
 
 
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,
 
289
                                                 &error)) {
 
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);
 
293
                        }
 
294
                        /* Search for this user in the member list. */
 
295
                        for (j = 0;
 
296
                             (members != NULL) && (j < members->n_values);
 
297
                             j++) {
 
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);
 
305
                                        break;
 
306
                                }
 
307
                        }
 
308
                        /* Do the same for the administrator list. */
 
309
                        for (j = 0;
 
310
                             (admins != NULL) && (j < admins->n_values);
 
311
                             j++) {
 
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);
 
319
                                        break;
 
320
                                }
 
321
                        }
 
322
                        /* Save the changes to the group. */
 
323
                        if (lu_group_modify(ctx, group, &error) == FALSE)
 
324
                                fprintf(stderr, _("Group %s could not be "
 
325
                                                  "modified: %s.\n"),
 
326
                                        groupname, lu_strerror(error));
 
327
                        lu_ent_free(group);
 
328
                }
 
329
                lu_hup_nscd();
 
330
        }
 
331
 
 
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"),
 
336
                                user);
 
337
                        return 10;
 
338
                }
 
339
                if (homeDirectory == NULL) {
 
340
                        fprintf(stderr, _("No new home directory for %s.\n"),
 
341
                                user);
 
342
                        return 11;
 
343
                }
 
344
                if (lu_homedir_move(oldHomeDirectory, homeDirectory,
 
345
                                    &error) == FALSE) {
 
346
                        fprintf(stderr, _("Error moving %s to %s: %s.\n"),
 
347
                                oldHomeDirectory, homeDirectory,
 
348
                                lu_strerror(error));
 
349
                        return 12;
 
350
                }
 
351
        }
 
352
 
 
353
        lu_ent_free(ent);
 
354
 
 
355
        lu_end(ctx);
 
356
 
 
357
        return 0;
 
358
}