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

« back to all changes in this revision

Viewing changes to src/chfn.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 1989 - 1994, Julianne Frances Haugh
 
2
 * Copyright (c) 1989 - 1994, Julianne Frances Haugh
 
3
 * Copyright (c) 1996 - 2000, Marek Michałkiewicz
 
4
 * Copyright (c) 2001 - 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: chfn.c 1751 2008-02-03 16:28:03Z nekral-guest $"
 
35
#ident "$Id: chfn.c 2363 2008-09-06 23:46:44Z nekral-guest $"
33
36
 
34
37
#include <fcntl.h>
35
38
#include <pwd.h>
53
56
/*
54
57
 * Global variables.
55
58
 */
56
 
static char *Prog;
 
59
char *Prog;
57
60
static char fullnm[BUFSIZ];
58
61
static char roomno[BUFSIZ];
59
62
static char workph[BUFSIZ];
60
63
static char homeph[BUFSIZ];
61
64
static char slop[BUFSIZ];
62
 
static int amroot;
 
65
static bool amroot;
63
66
/* Flags */
64
 
static int fflg = 0;            /* -f - set full name                */
65
 
static int rflg = 0;            /* -r - set room number              */
66
 
static int wflg = 0;            /* -w - set work phone number        */
67
 
static int hflg = 0;            /* -h - set home phone number        */
68
 
static int oflg = 0;            /* -o - set other information        */
69
 
#ifdef USE_PAM
70
 
static pam_handle_t *pamh = NULL;
71
 
#endif
 
67
static bool fflg = false;               /* -f - set full name                */
 
68
static bool rflg = false;               /* -r - set room number              */
 
69
static bool wflg = false;               /* -w - set work phone number        */
 
70
static bool hflg = false;               /* -h - set home phone number        */
 
71
static bool oflg = false;               /* -o - set other information        */
 
72
static bool pw_locked = false;
72
73
 
73
74
/*
74
75
 * External identifiers
75
76
 */
76
77
 
77
78
/* local function prototypes */
 
79
static void fail_exit (int code);
78
80
static void usage (void);
79
 
static int may_change_field (int);
 
81
static bool may_change_field (int);
80
82
static void new_fields (void);
81
83
static char *copy_field (char *, char *, char *);
82
84
static void process_flags (int argc, char **argv);
85
87
static void get_old_fields (const char *gecos);
86
88
 
87
89
/*
 
90
 * fail_exit - exit with an error and do some cleanup
 
91
 */
 
92
static void fail_exit (int code)
 
93
{
 
94
        if (pw_locked) {
 
95
                if (pw_unlock () == 0) {
 
96
                        fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
 
97
                        SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
 
98
                        /* continue */
 
99
                }
 
100
        }
 
101
        pw_locked = false;
 
102
 
 
103
        closelog ();
 
104
 
 
105
        exit (code);
 
106
}
 
107
 
 
108
/*
88
109
 * usage - print command line syntax and exit
89
110
 */
90
111
static void usage (void)
110
131
 *
111
132
 *      field should be one of 'f', 'r', 'w', 'h'
112
133
 *
113
 
 *      Return 1 if the user can change the field and 0 otherwise.
 
134
 *      Return true if the user can change the field and false otherwise.
114
135
 */
115
 
static int may_change_field (int field)
 
136
static bool may_change_field (int field)
116
137
{
117
138
        const char *cp;
118
139
 
134
155
         * if the string is empty or not defined at all.
135
156
         */
136
157
        if (amroot) {
137
 
                return 1;
 
158
                return true;
138
159
        }
139
160
 
140
161
        cp = getdef_str ("CHFN_RESTRICT");
147
168
        }
148
169
 
149
170
        if (strchr (cp, field) != NULL) {
150
 
                return 1;
 
171
                return true;
151
172
        }
152
173
 
153
 
        return 0;
 
174
        return false;
154
175
}
155
176
 
156
177
/*
166
187
        if (may_change_field ('f')) {
167
188
                change_field (fullnm, sizeof fullnm, _("Full Name"));
168
189
        } else {
169
 
                printf (_("\tFull Name: %s\n"), fullnm);
 
190
                printf (_("\t%s: %s\n"), _("Full Name"), fullnm);
170
191
        }
171
192
 
172
193
        if (may_change_field ('r')) {
173
194
                change_field (roomno, sizeof roomno, _("Room Number"));
174
195
        } else {
175
 
                printf (_("\tRoom Number: %s\n"), roomno);
 
196
                printf (_("\t%s: %s\n"), _("Room Number"), fullnm);
176
197
        }
177
198
 
178
199
        if (may_change_field ('w')) {
179
200
                change_field (workph, sizeof workph, _("Work Phone"));
180
201
        } else {
181
 
                printf (_("\tWork Phone: %s\n"), workph);
 
202
                printf (_("\t%s: %s\n"), _("Work Phone"), fullnm);
182
203
        }
183
204
 
184
205
        if (may_change_field ('h')) {
185
206
                change_field (homeph, sizeof homeph, _("Home Phone"));
186
207
        } else {
187
 
                printf (_("\tHome Phone: %s\n"), homeph);
 
208
                printf (_("\t%s: %s\n"), _("Home Phone"), fullnm);
188
209
        }
189
210
 
190
211
        if (amroot) {
256
277
                                         _("%s: Permission denied.\n"), Prog);
257
278
                                exit (E_NOPERM);
258
279
                        }
259
 
                        fflg++;
 
280
                        fflg = true;
260
281
                        STRFCPY (fullnm, optarg);
261
282
                        break;
262
283
                case 'h':
265
286
                                         _("%s: Permission denied.\n"), Prog);
266
287
                                exit (E_NOPERM);
267
288
                        }
268
 
                        hflg++;
 
289
                        hflg = true;
269
290
                        STRFCPY (homeph, optarg);
270
291
                        break;
271
292
                case 'r':
274
295
                                         _("%s: Permission denied.\n"), Prog);
275
296
                                exit (E_NOPERM);
276
297
                        }
277
 
                        rflg++;
 
298
                        rflg = true;
278
299
                        STRFCPY (roomno, optarg);
279
300
                        break;
280
301
                case 'o':
283
304
                                         _("%s: Permission denied.\n"), Prog);
284
305
                                exit (E_NOPERM);
285
306
                        }
286
 
                        oflg++;
 
307
                        oflg = true;
287
308
                        STRFCPY (slop, optarg);
288
309
                        break;
289
310
                case 'w':
292
313
                                         _("%s: Permission denied.\n"), Prog);
293
314
                                exit (E_NOPERM);
294
315
                        }
295
 
                        wflg++;
 
316
                        wflg = true;
296
317
                        STRFCPY (workph, optarg);
297
318
                        break;
298
319
                default:
314
335
static void check_perms (const struct passwd *pw)
315
336
{
316
337
#ifdef USE_PAM
 
338
        pam_handle_t *pamh = NULL;
317
339
        int retval;
318
340
        struct passwd *pampw;
319
341
#endif
353
375
        }
354
376
 
355
377
#else                           /* !USE_PAM */
356
 
        retval = PAM_SUCCESS;
357
 
 
358
378
        pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
359
 
        if (pampw == NULL) {
360
 
                retval = PAM_USER_UNKNOWN;
361
 
        }
362
 
 
363
 
        if (retval == PAM_SUCCESS) {
364
 
                retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh);
365
 
        }
366
 
 
367
 
        if (retval == PAM_SUCCESS) {
 
379
        if (NULL == pampw) {
 
380
                fprintf (stderr,
 
381
                         _("%s: Cannot determine your user name.\n"),
 
382
                         Prog);
 
383
                exit (E_NOPERM);
 
384
        }
 
385
 
 
386
        retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh);
 
387
 
 
388
        if (PAM_SUCCESS == retval) {
368
389
                retval = pam_authenticate (pamh, 0);
369
 
                if (retval != PAM_SUCCESS) {
370
 
                        pam_end (pamh, retval);
371
 
                }
372
390
        }
373
391
 
374
 
        if (retval == PAM_SUCCESS) {
 
392
        if (PAM_SUCCESS == retval) {
375
393
                retval = pam_acct_mgmt (pamh, 0);
376
 
                if (retval != PAM_SUCCESS) {
377
 
                        pam_end (pamh, retval);
378
 
                }
379
394
        }
380
395
 
381
 
        if (retval != PAM_SUCCESS) {
 
396
        if (NULL != pamh) {
 
397
                (void) pam_end (pamh, retval);
 
398
        }
 
399
        if (PAM_SUCCESS != retval) {
382
400
                fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
383
401
                exit (E_NOPERM);
384
402
        }
404
422
        if (setuid (0) != 0) {
405
423
                fputs (_("Cannot change ID to root.\n"), stderr);
406
424
                SYSLOG ((LOG_ERR, "can't setuid(0)"));
407
 
                closelog ();
408
 
                exit (E_NOPERM);
 
425
                fail_exit (E_NOPERM);
409
426
        }
410
427
        pwd_init ();
411
428
 
414
431
         * password file. Get a lock on the file and open it.
415
432
         */
416
433
        if (pw_lock () == 0) {
417
 
                fputs (_("Cannot lock the password file; try again later.\n"),
418
 
                       stderr);
419
 
                SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
420
 
                closelog ();
421
 
                exit (E_NOPERM);
 
434
                fprintf (stderr,
 
435
                         _("%s: cannot lock %s; try again later.\n"),
 
436
                         Prog, pw_dbname ());
 
437
                fail_exit (E_NOPERM);
422
438
        }
 
439
        pw_locked = true;
423
440
        if (pw_open (O_RDWR) == 0) {
424
 
                fputs (_("Cannot open the password file.\n"), stderr);
425
 
                pw_unlock ();
426
 
                SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
427
 
                closelog ();
428
 
                exit (E_NOPERM);
 
441
                fprintf (stderr,
 
442
                         _("%s: cannot open %s\n"), Prog, pw_dbname ());
 
443
                fail_exit (E_NOPERM);
429
444
        }
430
445
 
431
446
        /*
436
451
         */
437
452
        pw = pw_locate (user);
438
453
        if (NULL == pw) {
439
 
                pw_unlock ();
440
454
                fprintf (stderr,
441
 
                         _("%s: %s not found in /etc/passwd\n"), Prog, user);
442
 
                exit (E_NOPERM);
 
455
                         _("%s: user '%s' does not exist in %s\n"),
 
456
                         Prog, user, pw_dbname ());
 
457
                fail_exit (E_NOPERM);
443
458
        }
444
459
 
445
460
        /*
454
469
         * entry as well.
455
470
         */
456
471
        if (pw_update (&pwent) == 0) {
457
 
                fputs (_("Error updating the password entry.\n"), stderr);
458
 
                pw_unlock ();
459
 
                SYSLOG ((LOG_ERR, "error updating passwd entry"));
460
 
                closelog ();
461
 
                exit (E_NOPERM);
 
472
                fprintf (stderr,
 
473
                         _("%s: failed to prepare the new %s entry '%s'\n"),
 
474
                         Prog, pw_dbname (), pwent.pw_name);
 
475
                fail_exit (E_NOPERM);
462
476
        }
463
477
 
464
478
        /*
465
479
         * Changes have all been made, so commit them and unlock the file.
466
480
         */
467
481
        if (pw_close () == 0) {
468
 
                fputs (_("Cannot commit password file changes.\n"), stderr);
469
 
                pw_unlock ();
470
 
                SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
471
 
                closelog ();
472
 
                exit (E_NOPERM);
 
482
                fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ());
 
483
                SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ()));
 
484
                fail_exit (E_NOPERM);
473
485
        }
474
486
        if (pw_unlock () == 0) {
475
 
                fputs (_("Cannot unlock the password file.\n"), stderr);
476
 
                SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
477
 
                closelog ();
478
 
                exit (E_NOPERM);
 
487
                fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
 
488
                SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
 
489
                /* continue */
479
490
        }
 
491
        pw_locked = false;
480
492
}
481
493
 
482
494
/*
536
548
 */
537
549
static void check_fields (void)
538
550
{
539
 
        if (valid_field (fullnm, ":,=")) {
 
551
        int err;
 
552
        err = valid_field (fullnm, ":,=");
 
553
        if (err > 0) {
 
554
                fprintf (stderr, _("%s: name with non-ASCII characters: '%s'\n"), Prog, fullnm);
 
555
        } else if (err < 0) {
540
556
                fprintf (stderr, _("%s: invalid name: '%s'\n"), Prog, fullnm);
541
 
                closelog ();
542
 
                exit (E_NOPERM);
 
557
                fail_exit (E_NOPERM);
543
558
        }
544
 
        if (valid_field (roomno, ":,=")) {
 
559
        err = valid_field (roomno, ":,=");
 
560
        if (err > 0) {
 
561
                fprintf (stderr, _("%s: room number with non-ASCII characters: '%s'\n"), Prog, roomno);
 
562
        } else if (err < 0) {
545
563
                fprintf (stderr, _("%s: invalid room number: '%s'\n"),
546
564
                         Prog, roomno);
547
 
                closelog ();
548
 
                exit (E_NOPERM);
 
565
                fail_exit (E_NOPERM);
549
566
        }
550
 
        if (valid_field (workph, ":,=")) {
 
567
        if (valid_field (workph, ":,=") != 0) {
551
568
                fprintf (stderr, _("%s: invalid work phone: '%s'\n"),
552
569
                         Prog, workph);
553
 
                closelog ();
554
 
                exit (E_NOPERM);
 
570
                fail_exit (E_NOPERM);
555
571
        }
556
 
        if (valid_field (homeph, ":,=")) {
 
572
        if (valid_field (homeph, ":,=") != 0) {
557
573
                fprintf (stderr, _("%s: invalid home phone: '%s'\n"),
558
574
                         Prog, homeph);
559
 
                closelog ();
560
 
                exit (E_NOPERM);
 
575
                fail_exit (E_NOPERM);
561
576
        }
562
 
        if (valid_field (slop, ":")) {
 
577
        err = valid_field (slop, ":");
 
578
        if (err > 0) {
 
579
                fprintf (stderr, _("%s: '%s' contains non-ASCII characters\n"), Prog, slop);
 
580
        } else if (err < 0) {
563
581
                fprintf (stderr,
564
582
                         _("%s: '%s' contains illegal characters\n"),
565
583
                         Prog, slop);
566
 
                closelog ();
567
 
                exit (E_NOPERM);
 
584
                fail_exit (E_NOPERM);
568
585
        }
569
586
}
570
587
 
591
608
        char *user;
592
609
 
593
610
        sanitize_env ();
594
 
        setlocale (LC_ALL, "");
595
 
        bindtextdomain (PACKAGE, LOCALEDIR);
596
 
        textdomain (PACKAGE);
 
611
        (void) setlocale (LC_ALL, "");
 
612
        (void) bindtextdomain (PACKAGE, LOCALEDIR);
 
613
        (void) textdomain (PACKAGE);
597
614
 
598
615
        /*
599
616
         * This command behaves different for root and non-root
620
637
                user = argv[optind];
621
638
                pw = xgetpwnam (user);
622
639
                if (NULL == pw) {
623
 
                        fprintf (stderr, _("%s: unknown user %s\n"), Prog,
 
640
                        fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog,
624
641
                                 user);
625
 
                        exit (E_NOPERM);
 
642
                        fail_exit (E_NOPERM);
626
643
                }
627
644
        } else {
628
645
                pw = get_my_pwent ();
629
646
                if (NULL == pw) {
630
647
                        fprintf (stderr,
631
 
                                 _
632
 
                                 ("%s: Cannot determine your user name.\n"),
 
648
                                 _("%s: Cannot determine your user name.\n"),
633
649
                                 Prog);
634
 
                        exit (E_NOPERM);
 
650
                        SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
 
651
                                 (unsigned long) getuid ()));
 
652
                        fail_exit (E_NOPERM);
635
653
                }
636
654
                user = xstrdup (pw->pw_name);
637
655
        }
655
673
                                 ("%s: '%s' is the NIS master for this client.\n"),
656
674
                                 Prog, nis_master);
657
675
                }
658
 
                exit (E_NOPERM);
 
676
                fail_exit (E_NOPERM);
659
677
        }
660
678
#endif
661
679
 
688
706
        if ((strlen (fullnm) + strlen (roomno) + strlen (workph) +
689
707
             strlen (homeph) + strlen (slop)) > (unsigned int) 80) {
690
708
                fprintf (stderr, _("%s: fields too long\n"), Prog);
691
 
                closelog ();
692
 
                exit (E_NOPERM);
 
709
                fail_exit (E_NOPERM);
693
710
        }
694
711
        snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
695
 
                  fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);
 
712
                  fullnm, roomno, workph, homeph,
 
713
                  ('\0' != slop[0]) ? "," : "", slop);
696
714
 
697
715
        /* Rewrite the user's gecos in the passwd file */
698
716
        update_gecos (user, new_gecos);
699
717
 
700
 
        SYSLOG ((LOG_INFO, "changed user `%s' information", user));
 
718
        SYSLOG ((LOG_INFO, "changed user '%s' information", user));
701
719
 
702
720
        nscd_flush_cache ("passwd");
703
721
 
704
 
#ifdef USE_PAM
705
 
        pam_end (pamh, PAM_SUCCESS);
706
 
#endif                          /* USE_PAM */
707
 
 
708
722
        closelog ();
709
723
        exit (E_SUCCESS);
710
724
}