~ubuntu-branches/ubuntu/raring/shadow/raring-proposed

« back to all changes in this revision

Viewing changes to src/groupdel.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2009-05-05 09:45:21 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20090505094521-wpk2wn3q7957tlah
Tags: 1:4.1.3.1-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Ubuntu specific:
    + debian/login.defs: use SHA512 by default for password crypt routine.
  - debian/patches/stdout-encrypted-password.patch: chpasswd can report
    password hashes on stdout (debian bug 505640).
  - debian/login.pam: Enable SELinux support (debian bug 527106).
  - debian/securetty.linux: support Freescale MX-series (debian bug 527095).
* Add debian/patches/300_lastlog_failure: fixed upstream (debian bug 524873).
* Drop debian/patches/593_omit_lastchange_field_if_clock_is_misset: fixed
  upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright 1991 - 1994, Julianne Frances Haugh
 
2
 * Copyright (c) 1991 - 1994, Julianne Frances Haugh
 
3
 * Copyright (c) 1996 - 2000, Marek Michałkiewicz
 
4
 * Copyright (c) 2000 - 2006, Tomasz Kłoczko
 
5
 * Copyright (c) 2007 - 2008, Nicolas François
3
6
 * All rights reserved.
4
7
 *
5
8
 * Redistribution and use in source and binary forms, with or without
10
13
 * 2. Redistributions in binary form must reproduce the above copyright
11
14
 *    notice, this list of conditions and the following disclaimer in the
12
15
 *    documentation and/or other materials provided with the distribution.
13
 
 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14
 
 *    may be used to endorse or promote products derived from this software
15
 
 *    without specific prior written permission.
 
16
 * 3. The name of the copyright holders or contributors may not be used to
 
17
 *    endorse or promote products derived from this software without
 
18
 *    specific prior written permission.
16
19
 *
17
 
 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18
 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 
 * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21
 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 
 * SUCH DAMAGE.
 
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
21
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
22
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
23
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
 
24
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
25
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
26
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
27
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
28
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
29
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
30
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
31
 */
29
32
 
30
33
#include <config.h>
31
34
 
32
 
#ident "$Id: groupdel.c 1894 2008-03-08 23:52:50Z nekral-guest $"
 
35
#ident "$Id: groupdel.c 2473 2008-12-22 23:23:14Z nekral-guest $"
33
36
 
34
37
#include <ctype.h>
35
38
#include <fcntl.h>
36
39
#include <grp.h>
37
40
#include <pwd.h>
 
41
#ifdef ACCT_TOOLS_SETUID
38
42
#ifdef USE_PAM
39
43
#include "pam_defs.h"
40
44
#endif                          /* USE_PAM */
 
45
#endif                          /* ACCT_TOOLS_SETUID */
41
46
#include <stdio.h>
42
47
#include <sys/types.h>
43
48
#include "defines.h"
50
55
/*
51
56
 * Global variables
52
57
 */
 
58
char *Prog;
 
59
 
53
60
static char *group_name;
54
 
static char *Prog;
55
61
static gid_t group_id = -1;
56
62
 
57
63
#ifdef  SHADOWGRP
58
 
static int is_shadow_grp;
 
64
static bool is_shadow_grp;
59
65
#endif
60
66
 
61
67
/*
69
75
 
70
76
/* local function prototypes */
71
77
static void usage (void);
72
 
static void fail_exit (int);
73
78
static void grp_update (void);
74
79
static void close_files (void);
75
80
static void open_files (void);
85
90
}
86
91
 
87
92
/*
88
 
 * fail_exit - exit with a failure code after unlocking the files
89
 
 */
90
 
static void fail_exit (int code)
91
 
{
92
 
        (void) gr_unlock ();
93
 
#ifdef  SHADOWGRP
94
 
        if (is_shadow_grp) {
95
 
                sgr_unlock ();
96
 
        }
97
 
#endif
98
 
 
99
 
#ifdef  WITH_AUDIT
100
 
        audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group",
101
 
                      group_name, -1, 0);
102
 
#endif
103
 
 
104
 
        exit (code);
105
 
}
106
 
 
107
 
/*
108
93
 * grp_update - update group file entries
109
94
 *
110
95
 *      grp_update() writes the new records to the group files.
111
96
 */
112
97
static void grp_update (void)
113
98
{
114
 
        if (!gr_remove (group_name)) {
115
 
                fprintf (stderr, _("%s: error removing group entry\n"), Prog);
116
 
                fail_exit (E_GRP_UPDATE);
117
 
        }
 
99
        /*
 
100
         * To add the group, we need to update /etc/group.
 
101
         * Make sure failures will be reported.
 
102
         */
 
103
        add_cleanup (cleanup_report_del_group_group, group_name);
 
104
#ifdef  SHADOWGRP
 
105
        if (is_shadow_grp) {
 
106
                /* We also need to update /etc/gshadow */
 
107
                add_cleanup (cleanup_report_del_group_gshadow, group_name);
 
108
        }
 
109
#endif
 
110
 
 
111
        /*
 
112
         * Delete the group entry.
 
113
         */
 
114
        if (gr_remove (group_name) == 0) {
 
115
                fprintf (stderr,
 
116
                         _("%s: cannot remove entry '%s' from %s\n"),
 
117
                         Prog, group_name, gr_dbname ());
 
118
                exit (E_GRP_UPDATE);
 
119
        }
 
120
 
118
121
#ifdef  SHADOWGRP
119
122
        /*
120
123
         * Delete the shadow group entries as well.
121
124
         */
122
125
        if (is_shadow_grp && (sgr_locate (group_name) != NULL)) {
123
 
                if (!sgr_remove (group_name)) {
 
126
                if (sgr_remove (group_name) == 0) {
124
127
                        fprintf (stderr,
125
 
                                 _("%s: error removing shadow group entry\n"),
126
 
                                 Prog);
127
 
                        fail_exit (E_GRP_UPDATE);
 
128
                                 _("%s: cannot remove entry '%s' from %s\n"),
 
129
                                 Prog, group_name, sgr_dbname ());
 
130
                        exit (E_GRP_UPDATE);
128
131
                }
129
132
        }
130
133
#endif                          /* SHADOWGRP */
131
 
        return;
132
134
}
133
135
 
134
136
/*
139
141
 */
140
142
static void close_files (void)
141
143
{
 
144
        /* First, write the changes in the regular group database */
 
145
        if (gr_close () == 0) {
 
146
                fprintf (stderr,
 
147
                         _("%s: failure while writing changes to %s\n"),
 
148
                         Prog, gr_dbname ());
 
149
                exit (E_GRP_UPDATE);
 
150
        }
 
151
 
142
152
#ifdef WITH_AUDIT
143
 
        audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group", group_name,
144
 
                      group_id, 1);
 
153
        audit_logger (AUDIT_DEL_GROUP, Prog,
 
154
                      "removing group from /etc/group",
 
155
                      group_name, (unsigned int) group_id,
 
156
                      SHADOW_AUDIT_SUCCESS);
145
157
#endif
146
 
        SYSLOG ((LOG_INFO, "remove group `%s'\n", group_name));
147
 
 
148
 
        if (!gr_close ()) {
149
 
                fprintf (stderr, _("%s: cannot rewrite group file\n"), Prog);
150
 
                fail_exit (E_GRP_UPDATE);
151
 
        }
152
 
        gr_unlock ();
 
158
        SYSLOG ((LOG_INFO,
 
159
                 "group '%s' removed from %s",
 
160
                 group_name, gr_dbname ()));
 
161
        del_cleanup (cleanup_report_del_group_group);
 
162
 
 
163
        cleanup_unlock_group (NULL);
 
164
        del_cleanup (cleanup_unlock_group);
 
165
 
 
166
 
 
167
        /* Then, write the changes in the shadow database */
153
168
#ifdef  SHADOWGRP
154
 
        if (is_shadow_grp && !sgr_close ()) {
155
 
                fprintf (stderr,
156
 
                         _("%s: cannot rewrite shadow group file\n"), Prog);
157
 
                fail_exit (E_GRP_UPDATE);
 
169
        if (is_shadow_grp) {
 
170
                if (sgr_close () == 0) {
 
171
                        fprintf (stderr,
 
172
                                 _("%s: failure while writing changes to %s\n"),
 
173
                                 Prog, sgr_dbname ());
 
174
                        exit (E_GRP_UPDATE);
 
175
                }
 
176
 
 
177
#ifdef WITH_AUDIT
 
178
                audit_logger (AUDIT_DEL_GROUP, Prog,
 
179
                              "removing group from /etc/gshadow",
 
180
                              group_name, (unsigned int) group_id,
 
181
                              SHADOW_AUDIT_SUCCESS);
 
182
#endif
 
183
                SYSLOG ((LOG_INFO,
 
184
                         "group '%s' removed from %s",
 
185
                         group_name, sgr_dbname ()));
 
186
                del_cleanup (cleanup_report_del_group_gshadow);
 
187
 
 
188
                cleanup_unlock_gshadow (NULL);
 
189
                del_cleanup (cleanup_unlock_gshadow);
158
190
        }
159
 
        if (is_shadow_grp)
160
 
                sgr_unlock ();
161
191
#endif                          /* SHADOWGRP */
 
192
 
 
193
        /* Report success at the system level */
 
194
#ifdef WITH_AUDIT
 
195
        audit_logger (AUDIT_DEL_GROUP, Prog,
 
196
                      "",
 
197
                      group_name, (unsigned int) group_id,
 
198
                      SHADOW_AUDIT_SUCCESS);
 
199
#endif
 
200
        SYSLOG ((LOG_INFO, "group '%s' removed\n", group_name));
 
201
        del_cleanup (cleanup_report_del_group);
162
202
}
163
203
 
164
204
/*
168
208
 */
169
209
static void open_files (void)
170
210
{
171
 
        if (!gr_lock ()) {
172
 
                fprintf (stderr, _("%s: unable to lock group file\n"), Prog);
173
 
                fail_exit (E_GRP_UPDATE);
174
 
        }
175
 
        if (!gr_open (O_RDWR)) {
176
 
                fprintf (stderr, _("%s: unable to open group file\n"), Prog);
177
 
                fail_exit (E_GRP_UPDATE);
178
 
        }
179
 
#ifdef  SHADOWGRP
180
 
        if (is_shadow_grp && !sgr_lock ()) {
181
 
                fprintf (stderr,
182
 
                         _("%s: unable to lock shadow group file\n"), Prog);
183
 
                fail_exit (E_GRP_UPDATE);
184
 
        }
185
 
        if (is_shadow_grp && !sgr_open (O_RDWR)) {
186
 
                fprintf (stderr,
187
 
                         _("%s: unable to open shadow group file\n"), Prog);
188
 
                fail_exit (E_GRP_UPDATE);
 
211
        /* First, lock the databases */
 
212
        if (gr_lock () == 0) {
 
213
                fprintf (stderr,
 
214
                         _("%s: cannot lock %s; try again later.\n"),
 
215
                         Prog, gr_dbname ());
 
216
                exit (E_GRP_UPDATE);
 
217
        }
 
218
        add_cleanup (cleanup_unlock_group, NULL);
 
219
#ifdef  SHADOWGRP
 
220
        if (is_shadow_grp) {
 
221
                if (sgr_lock () == 0) {
 
222
                        fprintf (stderr,
 
223
                                 _("%s: cannot lock %s; try again later.\n"),
 
224
                                 Prog, sgr_dbname ());
 
225
                        exit (E_GRP_UPDATE);
 
226
                }
 
227
                add_cleanup (cleanup_unlock_gshadow, NULL);
 
228
        }
 
229
#endif
 
230
 
 
231
        /*
 
232
         * Now, if the group is not removed, it's our fault.
 
233
         * Make sure failures will be reported.
 
234
         */
 
235
        add_cleanup (cleanup_report_del_group, group_name);
 
236
 
 
237
        /* An now open the databases */
 
238
        if (gr_open (O_RDWR) == 0) {
 
239
                fprintf (stderr,
 
240
                         _("%s: cannot open %s\n"),
 
241
                         Prog, gr_dbname ());
 
242
                SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
 
243
                exit (E_GRP_UPDATE);
 
244
        }
 
245
#ifdef  SHADOWGRP
 
246
        if (is_shadow_grp) {
 
247
                if (sgr_open (O_RDWR) == 0) {
 
248
                        fprintf (stderr,
 
249
                                 _("%s: cannot open %s\n"),
 
250
                                 Prog, sgr_dbname ());
 
251
                        SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
 
252
                        exit (E_GRP_UPDATE);
 
253
                }
189
254
        }
190
255
#endif                          /* SHADOWGRP */
191
256
}
207
272
 
208
273
        setpwent ();
209
274
 
210
 
        while ((pwd = getpwent ()) && pwd->pw_gid != gid);
 
275
        while ( ((pwd = getpwent ()) != NULL) && (pwd->pw_gid != gid) );
211
276
 
212
277
        endpwent ();
213
278
 
215
280
         * If pwd isn't NULL, it stopped because the gid's matched.
216
281
         */
217
282
 
218
 
        if (pwd == (struct passwd *) 0)
 
283
        if (pwd == (struct passwd *) 0) {
219
284
                return;
 
285
        }
220
286
 
221
287
        /*
222
288
         * Can't remove the group.
223
289
         */
224
 
        fprintf (stderr, _("%s: cannot remove user's primary group.\n"), Prog);
225
 
        fail_exit (E_GROUP_BUSY);
 
290
        fprintf (stderr,
 
291
                 _("%s: cannot remove the primary group of user '%s'\n"),
 
292
                 Prog, pwd->pw_name);
 
293
        exit (E_GROUP_BUSY);
226
294
}
227
295
 
228
296
/*
237
305
 
238
306
int main (int argc, char **argv)
239
307
{
 
308
#ifdef ACCT_TOOLS_SETUID
240
309
#ifdef USE_PAM
241
310
        pam_handle_t *pamh = NULL;
242
311
        int retval;
243
 
#endif
 
312
#endif                          /* USE_PAM */
 
313
#endif                          /* ACCT_TOOLS_SETUID */
244
314
 
245
315
#ifdef WITH_AUDIT
246
316
        audit_help_open ();
247
317
#endif
 
318
        atexit (do_cleanups);
248
319
 
249
320
        /*
250
321
         * Get my name so that I can use it to report errors.
252
323
 
253
324
        Prog = Basename (argv[0]);
254
325
 
255
 
        setlocale (LC_ALL, "");
256
 
        bindtextdomain (PACKAGE, LOCALEDIR);
257
 
        textdomain (PACKAGE);
 
326
        (void) setlocale (LC_ALL, "");
 
327
        (void) bindtextdomain (PACKAGE, LOCALEDIR);
 
328
        (void) textdomain (PACKAGE);
258
329
 
259
 
        if (argc != 2)
 
330
        if (argc != 2) {
260
331
                usage ();
 
332
        }
261
333
 
262
334
        group_name = argv[1];
263
335
 
264
336
        OPENLOG ("groupdel");
265
337
 
 
338
#ifdef ACCT_TOOLS_SETUID
266
339
#ifdef USE_PAM
267
 
        retval = PAM_SUCCESS;
268
 
 
269
340
        {
270
341
                struct passwd *pampw;
271
342
                pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
272
343
                if (pampw == NULL) {
273
 
                        retval = PAM_USER_UNKNOWN;
 
344
                        fprintf (stderr,
 
345
                                 _("%s: Cannot determine your user name.\n"),
 
346
                                 Prog);
 
347
                        exit (1);
274
348
                }
275
349
 
276
 
                if (retval == PAM_SUCCESS) {
277
 
                        retval = pam_start ("groupdel", pampw->pw_name,
278
 
                                            &conv, &pamh);
279
 
                }
 
350
                retval = pam_start ("groupdel", pampw->pw_name, &conv, &pamh);
280
351
        }
281
352
 
282
 
        if (retval == PAM_SUCCESS) {
 
353
        if (PAM_SUCCESS == retval) {
283
354
                retval = pam_authenticate (pamh, 0);
284
 
                if (retval != PAM_SUCCESS) {
285
 
                        pam_end (pamh, retval);
286
 
                }
287
355
        }
288
356
 
289
 
        if (retval == PAM_SUCCESS) {
 
357
        if (PAM_SUCCESS == retval) {
290
358
                retval = pam_acct_mgmt (pamh, 0);
291
 
                if (retval != PAM_SUCCESS) {
292
 
                        pam_end (pamh, retval);
293
 
                }
294
359
        }
295
360
 
296
 
        if (retval != PAM_SUCCESS) {
 
361
        if (NULL != pamh) {
 
362
                (void) pam_end (pamh, retval);
 
363
        }
 
364
        if (PAM_SUCCESS != retval) {
297
365
                fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
298
366
                exit (1);
299
367
        }
300
368
#endif                          /* USE_PAM */
 
369
#endif                          /* ACCT_TOOLS_SETUID */
301
370
 
302
371
#ifdef SHADOWGRP
303
372
        is_shadow_grp = sgr_file_present ();
308
377
                /*
309
378
                 * Start with a quick check to see if the group exists.
310
379
                 */
311
 
                /* local, no need for xgetgrnam */
312
 
                if (!(grp = getgrnam (group_name))) {
313
 
                        fprintf (stderr, _("%s: group %s does not exist\n"),
314
 
                                 Prog, group_name);
315
 
#ifdef WITH_AUDIT
316
 
                        audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
317
 
                                      "deleting group",
318
 
                                      group_name, -1, 0);
319
 
#endif
 
380
                grp = getgrnam (group_name); /* local, no need for xgetgrnam */
 
381
                if (NULL == grp) {
 
382
                        fprintf (stderr,
 
383
                                 _("%s: group '%s' does not exist\n"),
 
384
                                 Prog, group_name);
320
385
                        exit (E_NOTFOUND);
321
386
                }
322
387
 
323
 
                group_id = grp->gr_gid; /* LAUS */
 
388
                group_id = grp->gr_gid;
324
389
        }
325
390
 
326
391
#ifdef  USE_NIS
331
396
                char *nis_domain;
332
397
                char *nis_master;
333
398
 
334
 
                fprintf (stderr, _("%s: group %s is a NIS group\n"),
335
 
                         Prog, group_name);
 
399
                fprintf (stderr,
 
400
                         _("%s: group '%s' is a NIS group\n"),
 
401
                         Prog, group_name);
336
402
 
337
 
#ifdef WITH_AUDIT
338
 
                audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "deleting group",
339
 
                              group_name, -1, 0);
340
 
#endif
341
403
                if (!yp_get_default_domain (&nis_domain) &&
342
404
                    !yp_master (nis_domain, "group.byname", &nis_master)) {
343
 
                        fprintf (stderr, _("%s: %s is the NIS master\n"),
344
 
                                 Prog, nis_master);
 
405
                        fprintf (stderr,
 
406
                                 _("%s: %s is the NIS master\n"),
 
407
                                 Prog, nis_master);
345
408
                }
346
409
                exit (E_NOTFOUND);
347
410
        }
348
411
#endif
349
412
 
350
413
        /*
351
 
         * Now check to insure that this isn't the primary group of
352
 
         * anyone.
 
414
         * Make sure this isn't the primary group of anyone.
353
415
         */
354
416
        group_busy (group_id);
355
417
 
365
427
 
366
428
        nscd_flush_cache ("group");
367
429
 
368
 
#ifdef USE_PAM
369
 
        if (retval == PAM_SUCCESS)
370
 
                pam_end (pamh, PAM_SUCCESS);
371
 
#endif                          /* USE_PAM */
372
 
 
373
430
        return E_SUCCESS;
374
431
}
375
432