~xnox/ubuntu/quantal/shadow/clear-locks

« back to all changes in this revision

Viewing changes to src/login.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 - 2001, 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: login.c 1902 2008-03-17 23:04:46Z nekral-guest $"
 
35
#ident "$Id: login.c 2690 2009-04-15 17:50:17Z nekral-guest $"
33
36
 
34
37
#include <errno.h>
35
38
#include <grp.h>
57
60
#define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
58
61
        fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
59
62
        SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
60
 
        pam_end(pamh, retcode); exit(1); \
 
63
        (void) pam_end(pamh, retcode); \
 
64
        exit(1); \
61
65
   }
62
66
#define PAM_END { retcode = pam_close_session(pamh,0); \
63
 
                pam_end(pamh,retcode); }
 
67
                (void) pam_end(pamh,retcode); }
64
68
 
65
69
#endif                          /* USE_PAM */
66
70
 
74
78
/*
75
79
 * Global variables
76
80
 */
77
 
const char *hostname = "";
 
81
char *Prog;
 
82
 
 
83
static const char *hostname = "";
 
84
static char *username = NULL;
 
85
static int reason = PW_LOGIN;
78
86
 
79
87
static struct passwd pwent;
80
88
 
87
95
extern struct utmp utent;
88
96
 
89
97
struct lastlog lastlog;
90
 
static int pflg = 0;
91
 
static int fflg = 0;
 
98
static bool pflg = false;
 
99
static bool fflg = false;
92
100
 
93
101
#ifdef RLOGIN
94
 
static int rflg = 0;
95
 
#else
96
 
#define rflg 0
97
 
#endif
98
 
static int hflg = 0;
99
 
static int preauth_flag = 0;
100
 
 
101
 
/*
102
 
 * Global variables.
103
 
 */
104
 
 
105
 
static char *Prog;
106
 
static int amroot;
 
102
static bool rflg = false;
 
103
#else                           /* RLOGIN */
 
104
#define rflg false
 
105
#endif                          /* !RLOGIN */
 
106
static bool hflg = false;
 
107
static bool preauth_flag = false;
 
108
 
 
109
static bool amroot;
107
110
static int timeout;
108
111
 
109
112
/*
125
128
/* local function prototypes */
126
129
static void usage (void);
127
130
static void setup_tty (void);
128
 
static void check_flags (int, char *const *);
 
131
static void process_flags (int, char *const *);
129
132
 
130
133
#ifndef USE_PAM
131
134
static struct faillog faillog;
148
151
static void usage (void)
149
152
{
150
153
        fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
151
 
        if (!amroot)
 
154
        if (!amroot) {
152
155
                exit (1);
 
156
        }
153
157
        fprintf (stderr, _("       %s [-p] [-h host] [-f name]\n"), Prog);
154
158
#ifdef RLOGIN
155
159
        fprintf (stderr, _("       %s [-p] -r host\n"), Prog);
156
 
#endif
 
160
#endif                          /* RLOGIN */
157
161
        exit (1);
158
162
}
159
163
 
169
173
        termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
170
174
        termio.c_iflag |= ICRNL;
171
175
 
 
176
#if defined(ECHOKE) && defined(ECHOCTL)
 
177
        termio.c_lflag |= ECHOKE | ECHOCTL;
 
178
#endif
 
179
#if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
 
180
        termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
 
181
#endif
 
182
#ifdef ONLCR
 
183
        termio.c_oflag |= ONLCR;
 
184
#endif
 
185
 
172
186
        /* leave these values unchanged if not specified in login.defs */
173
187
        termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
174
188
        termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
187
201
 */
188
202
static void bad_time_notify (void)
189
203
{
190
 
        puts (_("Invalid login time"));
191
 
        fflush (stdout);
 
204
        (void) puts (_("Invalid login time"));
 
205
        (void) fflush (stdout);
192
206
}
193
207
 
194
208
static void check_nologin (void)
203
217
         * forgotten about it ...
204
218
         */
205
219
        fname = getdef_str ("NOLOGINS_FILE");
206
 
        if (fname != NULL && access (fname, F_OK) == 0) {
 
220
        if ((NULL != fname) && (access (fname, F_OK) == 0)) {
207
221
                FILE *nlfp;
208
222
                int c;
209
223
 
211
225
                 * Cat the file if it can be opened, otherwise just
212
226
                 * print a default message
213
227
                 */
214
 
                if ((nlfp = fopen (fname, "r"))) {
 
228
                nlfp = fopen (fname, "r");
 
229
                if (NULL != nlfp) {
215
230
                        while ((c = getc (nlfp)) != EOF) {
216
 
                                if (c == '\n')
217
 
                                        putchar ('\r');
 
231
                                if (c == '\n') {
 
232
                                        (void) putchar ('\r');
 
233
                                }
218
234
 
219
 
                                putchar (c);
 
235
                                (void) putchar (c);
220
236
                        }
221
 
                        fflush (stdout);
222
 
                        fclose (nlfp);
223
 
                } else
224
 
                        puts (_("\nSystem closed for routine maintenance"));
 
237
                        (void) fflush (stdout);
 
238
                        (void) fclose (nlfp);
 
239
                } else {
 
240
                        (void) puts (_("\nSystem closed for routine maintenance"));
 
241
                }
225
242
                /*
226
243
                 * Non-root users must exit. Root gets the message, but
227
244
                 * gets to login.
236
253
}
237
254
#endif                          /* !USE_PAM */
238
255
 
239
 
static void check_flags (int argc, char *const *argv)
 
256
static void process_flags (int argc, char *const *argv)
240
257
{
241
258
        int arg;
 
259
        int flag;
242
260
 
243
261
        /*
244
262
         * Check the flags for proper form. Every argument starting with
246
264
         * clever rlogin, telnet, and getty holes.
247
265
         */
248
266
        for (arg = 1; arg < argc; arg++) {
249
 
                if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
250
 
                        usage ();
251
 
        }
 
267
                if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
 
268
                        usage ();
 
269
                }
 
270
                if (strcmp(argv[arg], "--") == 0) {
 
271
                        break; /* stop checking on a "--" */
 
272
                }
 
273
        }
 
274
 
 
275
        /*
 
276
         * Process options.
 
277
         */
 
278
        while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
 
279
                switch (flag) {
 
280
                case 'd':
 
281
                        /* "-d device" ignored for compatibility */
 
282
                        break;
 
283
                case 'f':
 
284
                        fflg = true;
 
285
                        break;
 
286
                case 'h':
 
287
                        hflg = true;
 
288
                        hostname = optarg;
 
289
                        reason = PW_TELNET;
 
290
                        break;
 
291
#ifdef  RLOGIN
 
292
                case 'r':
 
293
                        rflg = true;
 
294
                        hostname = optarg;
 
295
                        reason = PW_RLOGIN;
 
296
                        break;
 
297
#endif                          /* RLOGIN */
 
298
                case 'p':
 
299
                        pflg = true;
 
300
                        break;
 
301
                default:
 
302
                        usage ();
 
303
                }
 
304
        }
 
305
 
 
306
#ifdef RLOGIN
 
307
        /*
 
308
         * Neither -h nor -f should be combined with -r.
 
309
         */
 
310
 
 
311
        if (rflg && (hflg || fflg)) {
 
312
                usage ();
 
313
        }
 
314
#endif                          /* RLOGIN */
 
315
 
 
316
        /*
 
317
         * Allow authentication bypass only if real UID is zero.
 
318
         */
 
319
 
 
320
        if ((rflg || fflg || hflg) && !amroot) {
 
321
                fprintf (stderr, _("%s: Permission denied.\n"), Prog);
 
322
                exit (1);
 
323
        }
 
324
 
 
325
        /*
 
326
         *  Get the user name.
 
327
         */
 
328
        if (optind < argc) {
 
329
                username = xstrdup (argv[optind]);
 
330
                strzero (argv[optind]);
 
331
                ++optind;
 
332
        }
 
333
 
 
334
#ifdef  RLOGIN
 
335
        if (rflg && (NULL != username)) {
 
336
                usage ();
 
337
        }
 
338
#endif                          /* RLOGIN */
 
339
        if (fflg && (NULL == username)) {
 
340
                usage ();
 
341
        }
 
342
 
252
343
}
253
344
 
254
345
 
259
350
#endif
260
351
        char *tmp;
261
352
 
262
 
        if ((tmp = getenv ("LANG"))) {
 
353
        tmp = getenv ("LANG");
 
354
        if (NULL != tmp) {
263
355
                addenv ("LANG", tmp);
264
356
        }
265
357
 
267
359
         * Add the timezone environmental variable so that time functions
268
360
         * work correctly.
269
361
         */
270
 
        if ((tmp = getenv ("TZ"))) {
 
362
        tmp = getenv ("TZ");
 
363
        if (NULL != tmp) {
271
364
                addenv ("TZ", tmp);
272
365
        }
273
366
#ifndef USE_PAM
274
 
        else if ((cp = getdef_str ("ENV_TZ")))
275
 
                addenv (*cp == '/' ? tz (cp) : cp, NULL);
 
367
        else {
 
368
                cp = getdef_str ("ENV_TZ");
 
369
                if (NULL != cp) {
 
370
                        addenv (('/' == *cp) ? tz (cp) : cp, NULL);
 
371
                }
 
372
        }
276
373
#endif                          /* !USE_PAM */
277
374
        /* 
278
375
         * Add the clock frequency so that profiling commands work
279
376
         * correctly.
280
377
         */
281
 
        if ((tmp = getenv ("HZ"))) {
 
378
        tmp = getenv ("HZ");
 
379
        if (NULL != tmp) {
282
380
                addenv ("HZ", tmp);
283
381
        }
284
382
#ifndef USE_PAM
285
 
        else if ((cp = getdef_str ("ENV_HZ")))
286
 
                addenv (cp, NULL);
 
383
        else {
 
384
                cp = getdef_str ("ENV_HZ");
 
385
                if (NULL != cp) {
 
386
                        addenv (cp, NULL);
 
387
                }
 
388
        }
287
389
#endif                          /* !USE_PAM */
288
390
}
289
391
 
314
416
 */
315
417
int main (int argc, char **argv)
316
418
{
317
 
        char username[32];
318
419
        char tty[BUFSIZ];
319
420
 
320
421
#ifdef RLOGIN
321
422
        char term[128] = "";
322
 
#endif
 
423
#endif                          /* RLOGIN */
323
424
#if defined(HAVE_STRFTIME) && !defined(USE_PAM)
324
425
        char ptime[80];
325
426
#endif
326
 
        int reason = PW_LOGIN;
327
427
        int delay;
328
428
        int retries;
329
 
        int failed;
330
 
        int flag;
331
 
        int subroot = 0;
 
429
        bool failed;
 
430
        bool subroot = false;
332
431
#ifndef USE_PAM
333
 
        int is_console;
 
432
        bool is_console;
334
433
#endif
335
434
        int err;
336
435
        const char *cp;
338
437
        char fromhost[512];
339
438
        struct passwd *pwd;
340
439
        char **envp = environ;
 
440
#ifndef USE_PAM
341
441
        static char temp_pw[2];
342
442
        static char temp_shell[] = "/bin/sh";
 
443
#endif
343
444
 
344
445
#ifdef USE_PAM
345
446
        int retcode;
355
456
 
356
457
        sanitize_env ();
357
458
 
358
 
        setlocale (LC_ALL, "");
359
 
        bindtextdomain (PACKAGE, LOCALEDIR);
360
 
        textdomain (PACKAGE);
 
459
        (void) setlocale (LC_ALL, "");
 
460
        (void) bindtextdomain (PACKAGE, LOCALEDIR);
 
461
        (void) textdomain (PACKAGE);
361
462
 
362
463
        initenv ();
363
464
 
364
 
        username[0] = '\0';
365
465
        amroot = (getuid () == 0);
366
466
        Prog = Basename (argv[0]);
367
467
 
368
 
        check_flags (argc, argv);
369
 
 
370
 
        while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
371
 
                switch (flag) {
372
 
                case 'd':
373
 
                        /* "-d device" ignored for compatibility */
374
 
                        break;
375
 
                case 'f':
376
 
                        /*
377
 
                         * username must be a separate token
378
 
                         * (-f root, *not* -froot).  --marekm
379
 
                         *
380
 
                         * if -f has an arg, use that, else use the
381
 
                         * normal user name passed after all options
382
 
                         * --benc
383
 
                         */
384
 
                        if (optarg != NULL && optarg != argv[optind - 1])
385
 
                                usage ();
386
 
                        fflg++;
387
 
                        if (optarg)
388
 
                                STRFCPY (username, optarg);
389
 
                        break;
390
 
                case 'h':
391
 
                        hflg++;
392
 
                        hostname = optarg;
393
 
                        reason = PW_TELNET;
394
 
                        break;
395
 
#ifdef  RLOGIN
396
 
                case 'r':
397
 
                        rflg++;
398
 
                        hostname = optarg;
399
 
                        reason = PW_RLOGIN;
400
 
                        break;
401
 
#endif
402
 
                case 'p':
403
 
                        pflg++;
404
 
                        break;
405
 
                default:
406
 
                        usage ();
407
 
                }
408
 
        }
409
 
 
410
 
#ifdef RLOGIN
411
 
        /*
412
 
         * Neither -h nor -f should be combined with -r.
413
 
         */
414
 
 
415
 
        if (rflg && (hflg || fflg))
416
 
                usage ();
417
 
#endif
418
 
 
419
 
        /*
420
 
         * Allow authentication bypass only if real UID is zero.
421
 
         */
422
 
 
423
 
        if ((rflg || fflg || hflg) && !amroot) {
424
 
                fprintf (stderr, _("%s: Permission denied.\n"), Prog);
425
 
                exit (1);
426
 
        }
427
 
 
428
 
        if (!isatty (0) || !isatty (1) || !isatty (2))
 
468
        process_flags (argc, argv);
 
469
 
 
470
        if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
429
471
                exit (1);       /* must be a terminal */
 
472
        }
430
473
 
431
474
        /*
432
475
         * Be picky if run by normal users (possible if installed setuid
454
497
                 * gethostbyname() is not 100% reliable (the remote host may
455
498
                 * be unknown, etc.).  --marekm
456
499
                 */
457
 
                if ((he = gethostbyname (hostname))) {
 
500
                he = gethostbyname (hostname);
 
501
                if (NULL != he) {
458
502
                        utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
 
503
                }
459
504
#endif
460
505
#ifdef UT_HOST
461
 
                        strncpy (utent.ut_host, hostname,
462
 
                                 sizeof (utent.ut_host));
 
506
                strncpy (utent.ut_host, hostname, sizeof (utent.ut_host));
463
507
#endif
464
508
#if HAVE_UTMPX_H
465
 
                        strncpy (utxent.ut_host, hostname,
466
 
                                 sizeof (utxent.ut_host));
 
509
                strncpy (utxent.ut_host, hostname, sizeof (utxent.ut_host));
467
510
#endif
468
 
                        /*
469
 
                         * Add remote hostname to the environment. I think
470
 
                         * (not sure) I saw it once on Irix.  --marekm
471
 
                         */
472
 
                        addenv ("REMOTEHOST", hostname);
473
 
                }
 
511
                /*
 
512
                 * Add remote hostname to the environment. I think
 
513
                 * (not sure) I saw it once on Irix.  --marekm
 
514
                 */
 
515
                addenv ("REMOTEHOST", hostname);
 
516
        }
474
517
#ifdef __linux__
475
 
                /*
476
 
                 * workaround for init/getty leaving junk in ut_host at least in
477
 
                 * some version of RedHat.  --marekm
478
 
                 */
479
 
                else if (amroot)
480
 
                        memzero (utent.ut_host, sizeof utent.ut_host);
 
518
        /*
 
519
         * workaround for init/getty leaving junk in ut_host at least in
 
520
         * some version of RedHat.  --marekm
 
521
         */
 
522
        else if (amroot) {
 
523
                memzero (utent.ut_host, sizeof utent.ut_host);
 
524
        }
481
525
#endif
482
 
                if (fflg)
483
 
                        preauth_flag++;
484
 
                if (hflg)
485
 
                        reason = PW_RLOGIN;
 
526
        if (fflg) {
 
527
                preauth_flag = true;
 
528
        }
 
529
        if (hflg) {
 
530
                reason = PW_RLOGIN;
 
531
        }
486
532
#ifdef RLOGIN
487
 
                if (rflg
488
 
                    && do_rlogin (hostname, username, sizeof username,
489
 
                                  term, sizeof term))
490
 
                        preauth_flag++;
491
 
#endif
492
 
 
493
 
                OPENLOG ("login");
494
 
 
495
 
                setup_tty ();
 
533
        if (rflg) {
 
534
                username = malloc (32 * sizeof (char));
 
535
                if (do_rlogin (hostname, username, 32, term, sizeof term)) {
 
536
                        preauth_flag = true;
 
537
                } else {
 
538
                        free (username);
 
539
                        username = NULL;
 
540
                }
 
541
        }
 
542
#endif                          /* RLOGIN */
 
543
 
 
544
        OPENLOG ("login");
 
545
 
 
546
        setup_tty ();
496
547
 
497
548
#ifndef USE_PAM
498
 
                umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
499
 
 
500
 
                {
501
 
                        /* 
502
 
                         * Use the ULIMIT in the login.defs file, and if
503
 
                         * there isn't one, use the default value. The
504
 
                         * user may have one for themselves, but otherwise,
505
 
                         * just take what you get.
506
 
                         */
507
 
                        long limit = getdef_long ("ULIMIT", -1L);
508
 
 
509
 
                        if (limit != -1)
510
 
                                set_filesize_limit (limit);
511
 
                }
512
 
 
513
 
#endif
514
 
                /*
515
 
                 * The entire environment will be preserved if the -p flag
516
 
                 * is used.
 
549
        umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
 
550
 
 
551
        {
 
552
                /* 
 
553
                 * Use the ULIMIT in the login.defs file, and if
 
554
                 * there isn't one, use the default value. The
 
555
                 * user may have one for themselves, but otherwise,
 
556
                 * just take what you get.
517
557
                 */
518
 
                if (pflg)
519
 
                        while (*envp)   /* add inherited environment, */
520
 
                                addenv (*envp++, NULL); /* some variables change later */
 
558
                long limit = getdef_long ("ULIMIT", -1L);
 
559
 
 
560
                if (limit != -1) {
 
561
                        set_filesize_limit (limit);
 
562
                }
 
563
        }
 
564
 
 
565
#endif
 
566
        /*
 
567
         * The entire environment will be preserved if the -p flag
 
568
         * is used.
 
569
         */
 
570
        if (pflg) {
 
571
                while (NULL != *envp) { /* add inherited environment, */
 
572
                        addenv (*envp, NULL); /* some variables change later */
 
573
                        envp++;
 
574
                }
 
575
        }
521
576
 
522
577
#ifdef RLOGIN
523
 
                if (term[0] != '\0')
524
 
                        addenv ("TERM", term);
525
 
                else
526
 
#endif
527
 
                        /* preserve TERM from getty */
528
 
                if (!pflg && (tmp = getenv ("TERM")))
529
 
                        addenv ("TERM", tmp);
530
 
 
531
 
                init_env ();
532
 
 
533
 
                if (optind < argc) {    /* get the user name */
534
 
                        if (rflg || (fflg && username[0]))
535
 
                                usage ();
536
 
 
537
 
                        STRFCPY (username, argv[optind]);
538
 
                        strzero (argv[optind]);
539
 
                        ++optind;
 
578
        if (term[0] != '\0') {
 
579
                addenv ("TERM", term);
 
580
        } else
 
581
#endif                          /* RLOGIN */
 
582
        {
 
583
                /* preserve TERM from getty */
 
584
                if (!pflg) {
 
585
                        tmp = getenv ("TERM");
 
586
                        if (NULL != tmp) {
 
587
                                addenv ("TERM", tmp);
 
588
                        }
540
589
                }
541
 
                if (optind < argc)      /* now set command line variables */
542
 
                        set_env (argc - optind, &argv[optind]);
543
 
 
544
 
                if (rflg || hflg)
545
 
                        cp = hostname;
546
 
                else
 
590
        }
 
591
 
 
592
        init_env ();
 
593
 
 
594
        if (optind < argc) {    /* now set command line variables */
 
595
                set_env (argc - optind, &argv[optind]);
 
596
        }
 
597
 
 
598
        if (rflg || hflg) {
 
599
                cp = hostname;
 
600
        } else {
 
601
                /* FIXME: What is the priority:
 
602
                 *        UT_HOST or HAVE_UTMPX_H? */
547
603
#ifdef  UT_HOST
548
 
                if (utent.ut_host[0])
 
604
                if ('\0' != utent.ut_host[0]) {
549
605
                        cp = utent.ut_host;
550
 
                else
 
606
                } else
551
607
#endif
552
608
#if HAVE_UTMPX_H
553
 
                if (utxent.ut_host[0])
 
609
                if ('\0' != utxent.ut_host[0]) {
554
610
                        cp = utxent.ut_host;
555
 
                else
 
611
                } else
556
612
#endif
 
613
                {
557
614
                        cp = "";
558
 
 
559
 
                if (*cp)
560
 
                        snprintf (fromhost, sizeof fromhost,
561
 
                                  " on '%.100s' from '%.200s'", tty, cp);
562
 
                else
563
 
                        snprintf (fromhost, sizeof fromhost,
564
 
                                  " on '%.100s'", tty);
565
 
 
566
 
              top:
567
 
                /* only allow ALARM sec. for login */
568
 
                signal (SIGALRM, alarm_handler);
569
 
                timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
570
 
                if (timeout > 0)
571
 
                        alarm (timeout);
572
 
 
573
 
                environ = newenvp;      /* make new environment active */
574
 
                delay = getdef_num ("FAIL_DELAY", 1);
575
 
                retries = getdef_num ("LOGIN_RETRIES", RETRIES);
 
615
                }
 
616
        }
 
617
 
 
618
        if ('\0' != *cp) {
 
619
                snprintf (fromhost, sizeof fromhost,
 
620
                          " on '%.100s' from '%.200s'", tty, cp);
 
621
        } else {
 
622
                snprintf (fromhost, sizeof fromhost,
 
623
                          " on '%.100s'", tty);
 
624
        }
 
625
 
 
626
      top:
 
627
        /* only allow ALARM sec. for login */
 
628
        (void) signal (SIGALRM, alarm_handler);
 
629
        timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
 
630
        if (timeout > 0) {
 
631
                alarm (timeout);
 
632
        }
 
633
 
 
634
        environ = newenvp;      /* make new environment active */
 
635
        delay = getdef_num ("FAIL_DELAY", 1);
 
636
        retries = getdef_num ("LOGIN_RETRIES", RETRIES);
576
637
 
577
638
#ifdef USE_PAM
578
 
                retcode = pam_start ("login", username, &conv, &pamh);
579
 
                if (retcode != PAM_SUCCESS) {
580
 
                        fprintf (stderr,
581
 
                                 _("login: PAM Failure, aborting: %s\n"),
582
 
                                 pam_strerror (pamh, retcode));
583
 
                        SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
584
 
                                 pam_strerror (pamh, retcode)));
585
 
                        exit (99);
 
639
        retcode = pam_start ("login", username, &conv, &pamh);
 
640
        if (retcode != PAM_SUCCESS) {
 
641
                fprintf (stderr,
 
642
                         _("login: PAM Failure, aborting: %s\n"),
 
643
                         pam_strerror (pamh, retcode));
 
644
                SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
 
645
                         pam_strerror (pamh, retcode)));
 
646
                exit (99);
 
647
        }
 
648
 
 
649
        /*
 
650
         * hostname & tty are either set to NULL or their correct values,
 
651
         * depending on how much we know. We also set PAM's fail delay to
 
652
         * ours.
 
653
         */
 
654
        retcode = pam_set_item (pamh, PAM_RHOST, hostname);
 
655
        PAM_FAIL_CHECK;
 
656
        retcode = pam_set_item (pamh, PAM_TTY, tty);
 
657
        PAM_FAIL_CHECK;
 
658
#ifdef HAS_PAM_FAIL_DELAY
 
659
        retcode = pam_fail_delay (pamh, 1000000 * delay);
 
660
        PAM_FAIL_CHECK;
 
661
#endif
 
662
        /* if fflg, then the user has already been authenticated */
 
663
        if (!fflg || (getuid () != 0)) {
 
664
                int failcount = 0;
 
665
                char hostn[256];
 
666
                char loginprompt[256];  /* That's one hell of a prompt :) */
 
667
 
 
668
                /* Make the login prompt look like we want it */
 
669
                if (gethostname (hostn, sizeof (hostn)) == 0) {
 
670
                        snprintf (loginprompt,
 
671
                                  sizeof (loginprompt),
 
672
                                  _("%s login: "), hostn);
 
673
                } else {
 
674
                        snprintf (loginprompt,
 
675
                                  sizeof (loginprompt), _("login: "));
 
676
                }
 
677
 
 
678
                retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
 
679
                PAM_FAIL_CHECK;
 
680
 
 
681
                /* if we didn't get a user on the command line,
 
682
                   set it to NULL */
 
683
                retcode = pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
 
684
                PAM_FAIL_CHECK;
 
685
                if ((NULL != pam_user) && ('\0' == pam_user[0])) {
 
686
                        retcode = pam_set_item (pamh, PAM_USER, NULL);
 
687
                        PAM_FAIL_CHECK;
586
688
                }
587
689
 
588
690
                /*
589
 
                 * hostname & tty are either set to NULL or their correct values,
590
 
                 * depending on how much we know. We also set PAM's fail delay to
591
 
                 * ours.
 
691
                 * There may be better ways to deal with some of
 
692
                 * these conditions, but at least this way I don't
 
693
                 * think we'll be giving away information. Perhaps
 
694
                 * someday we can trust that all PAM modules will
 
695
                 * pay attention to failure count and get rid of
 
696
                 * MAX_LOGIN_TRIES?
592
697
                 */
593
 
                retcode = pam_set_item (pamh, PAM_RHOST, hostname);
594
 
                PAM_FAIL_CHECK;
595
 
                retcode = pam_set_item (pamh, PAM_TTY, tty);
596
 
                PAM_FAIL_CHECK;
597
 
#ifdef HAVE_PAM_FAIL_DELAY
598
 
                retcode = pam_fail_delay (pamh, 1000000 * delay);
599
 
                PAM_FAIL_CHECK;
 
698
                failcount = 0;
 
699
                while (true) {
 
700
                        const char *failent_user;
 
701
                        failed = false;
 
702
 
 
703
                        failcount++;
 
704
#ifdef HAS_PAM_FAIL_DELAY
 
705
                        if (delay > 0) {
 
706
                                retcode = pam_fail_delay(pamh, 1000000*delay);
 
707
                                PAM_FAIL_CHECK;
 
708
                        }
600
709
#endif
601
 
                /* if fflg == 1, then the user has already been authenticated */
602
 
                if (!fflg || (getuid () != 0)) {
603
 
                        int failcount = 0;
604
 
                        char hostn[256];
605
 
                        char loginprompt[256];  /* That's one hell of a prompt :) */
606
 
 
607
 
                        /* Make the login prompt look like we want it */
608
 
                        if (!gethostname (hostn, sizeof (hostn)))
609
 
                                snprintf (loginprompt,
610
 
                                          sizeof (loginprompt),
611
 
                                          _("%s login: "), hostn);
612
 
                        else
613
 
                                snprintf (loginprompt,
614
 
                                          sizeof (loginprompt), _("login: "));
615
 
 
616
 
                        retcode =
617
 
                            pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
618
 
                        PAM_FAIL_CHECK;
619
 
 
620
 
                        /* if we didn't get a user on the command line,
621
 
                           set it to NULL */
622
 
                        pam_get_item (pamh, PAM_USER,
623
 
                                      (const void **)ptr_pam_user);
624
 
                        if (pam_user[0] == '\0')
625
 
                                pam_set_item (pamh, PAM_USER, NULL);
626
 
 
627
 
                        /*
628
 
                         * There may be better ways to deal with some of
629
 
                         * these conditions, but at least this way I don't
630
 
                         * think we'll be giving away information. Perhaps
631
 
                         * someday we can trust that all PAM modules will
632
 
                         * pay attention to failure count and get rid of
633
 
                         * MAX_LOGIN_TRIES?
634
 
                         */
635
 
                        failcount = 0;
636
 
                        while (1) {
637
 
                          const char *failent_user;
638
 
                          failed = 0;
639
 
 
640
 
                          failcount++;
641
 
                          if (delay > 0)
642
 
                            retcode = pam_fail_delay(pamh, 1000000*delay);
643
 
 
644
 
                          retcode = pam_authenticate (pamh, 0);
645
 
 
646
 
                          pam_get_item (pamh, PAM_USER,
647
 
                                        (const void **) ptr_pam_user);
648
 
 
649
 
                          if (pam_user && pam_user[0]) {
650
 
                            pwd = xgetpwnam(pam_user);
651
 
                            if (pwd) {
652
 
                              pwent = *pwd;
653
 
                              failent_user = pwent.pw_name;
654
 
                            } else {
655
 
                              if (getdef_bool("LOG_UNKFAIL_ENAB") && pam_user)
656
 
                                failent_user = pam_user;
657
 
                              else
658
 
                                failent_user = "UNKNOWN";
659
 
                            }
660
 
                          } else {
661
 
                            pwd = NULL;
662
 
                            failent_user = "UNKNOWN";
663
 
                          }
664
 
 
665
 
                          if (retcode == PAM_MAXTRIES || failcount >= retries) {
666
 
                            SYSLOG ((LOG_NOTICE,
667
 
                                    "TOO MANY LOGIN TRIES (%d)%s FOR `%s'",
668
 
                                    failcount, fromhost, failent_user));
669
 
                            fprintf(stderr,
670
 
                                    _("Maximum number of tries exceeded (%d)\n"),
671
 
                                    failcount);
672
 
                            PAM_END;
673
 
                            exit(0);
674
 
                          } else if (retcode == PAM_ABORT) {
675
 
                            /* Serious problems, quit now */
676
 
                            fputs (_("login: abort requested by PAM\n"),stderr);
677
 
                            SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
678
 
                            PAM_END;
679
 
                            exit(99);
680
 
                          } else if (retcode != PAM_SUCCESS) {
681
 
                            SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR `%s', %s",
682
 
                                   failcount, fromhost, failent_user,
683
 
                                   pam_strerror (pamh, retcode)));
684
 
                            failed = 1;
685
 
                          }
686
 
 
687
 
                          if (!failed)
688
 
                            break;
689
 
 
690
 
#ifdef WITH_AUDIT
691
 
                                {
692
 
                                        struct passwd *pw;
693
 
                                        char buf[64];
694
 
 
695
 
                                        audit_fd = audit_open ();
696
 
                                        /* local, no need for xgetpwnam */
697
 
                                        pw = getpwnam (username);
698
 
                                        if (pw) {
699
 
                                                snprintf (buf, sizeof (buf),
700
 
                                                  "uid=%d", pw->pw_uid);
701
 
                                                audit_log_user_message
702
 
                                                    (audit_fd, AUDIT_USER_LOGIN,
703
 
                                                     buf, hostname, NULL,
704
 
                                                     tty, 0);
 
710
 
 
711
                        retcode = pam_authenticate (pamh, 0);
 
712
 
 
713
                        {
 
714
                                int saved_retcode = retcode;
 
715
                                retcode = pam_get_item (pamh, PAM_USER,
 
716
                                                        (const void **) ptr_pam_user);
 
717
                                PAM_FAIL_CHECK;
 
718
                                retcode = saved_retcode;
 
719
                        }
 
720
 
 
721
                        if ((NULL != pam_user) && ('\0' != pam_user[0])) {
 
722
                                pwd = xgetpwnam(pam_user);
 
723
                                if (NULL != pwd) {
 
724
                                        pwent = *pwd;
 
725
                                        failent_user = pwent.pw_name;
 
726
                                } else {
 
727
                                        if (   getdef_bool("LOG_UNKFAIL_ENAB")
 
728
                                            && (NULL != pam_user)) {
 
729
                                                failent_user = pam_user;
705
730
                                        } else {
706
 
                                                snprintf (buf, sizeof (buf),
707
 
                                                          "acct=%s", username);
708
 
                                                audit_log_user_message
709
 
                                                    (audit_fd, AUDIT_USER_LOGIN,
710
 
                                                     buf, hostname, NULL,
711
 
                                                     tty, 0);
 
731
                                                failent_user = "UNKNOWN";
712
732
                                        }
713
 
                                        close (audit_fd);
714
733
                                }
 
734
                        } else {
 
735
                                pwd = NULL;
 
736
                                failent_user = "UNKNOWN";
 
737
                        }
 
738
 
 
739
                        if (retcode == PAM_MAXTRIES) {
 
740
                                SYSLOG ((LOG_NOTICE,
 
741
                                         "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
 
742
                                         failcount, fromhost, failent_user));
 
743
                                fprintf(stderr,
 
744
                                        _("Maximum number of tries exceeded (%d)\n"),
 
745
                                        failcount);
 
746
                                PAM_END;
 
747
                                exit(0);
 
748
                        } else if (retcode == PAM_ABORT) {
 
749
                                /* Serious problems, quit now */
 
750
                                fputs (_("login: abort requested by PAM\n"),stderr);
 
751
                                SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
 
752
                                PAM_END;
 
753
                                exit(99);
 
754
                        } else if (retcode != PAM_SUCCESS) {
 
755
                                SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
 
756
                                         failcount, fromhost, failent_user,
 
757
                                         pam_strerror (pamh, retcode)));
 
758
                                failed = true;
 
759
                        }
 
760
 
 
761
                        if (!failed) {
 
762
                                break;
 
763
                        }
 
764
 
 
765
#ifdef WITH_AUDIT
 
766
                        audit_fd = audit_open ();
 
767
                        audit_log_acct_message (audit_fd,
 
768
                                                AUDIT_USER_LOGIN,
 
769
                                                NULL,    /* Prog. name */
 
770
                                                "login",
 
771
                                                failent_user,
 
772
                                                AUDIT_NO_ID,
 
773
                                                hostname,
 
774
                                                NULL,    /* addr */
 
775
                                                tty,
 
776
                                                0);      /* result */
 
777
                        close (audit_fd);
715
778
#endif                          /* WITH_AUDIT */
716
779
 
717
 
                          fprintf(stderr,"\nLogin incorrect\n");
718
 
 
719
 
                          /* Let's give it another go around */
720
 
                          pam_set_item(pamh,PAM_USER,NULL);
721
 
                        }
722
 
 
723
 
                        /* We don't get here unless they were authenticated above */
724
 
                        alarm (0);
725
 
                        retcode = pam_acct_mgmt (pamh, 0);
726
 
 
727
 
                        if (retcode == PAM_NEW_AUTHTOK_REQD) {
728
 
                                retcode =
729
 
                                    pam_chauthtok (pamh,
730
 
                                                   PAM_CHANGE_EXPIRED_AUTHTOK);
731
 
                        }
732
 
 
733
 
                        PAM_FAIL_CHECK;
734
 
                }
735
 
 
736
 
                /* Grab the user information out of the password file for future usage
737
 
                   First get the username that we are actually using, though.
738
 
                 */
739
 
                retcode =
740
 
                    pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
741
 
                setpwent ();
742
 
                pwd = xgetpwnam (pam_user);
743
 
                if (!pwd) {
744
 
                        SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
745
 
                                 getdef_bool ("LOG_UNKFAIL_ENAB") ?
746
 
                                 pam_user : "UNKNOWN"));
747
 
                        exit (1);
748
 
                }
749
 
 
750
 
                if (fflg) {
751
 
                        retcode = pam_acct_mgmt (pamh, 0);
752
 
                        PAM_FAIL_CHECK;
753
 
                }
754
 
 
755
 
                if (setup_groups (pwd))
756
 
                        exit (1);
757
 
 
758
 
                pwent = *pwd;
759
 
 
760
 
                retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
761
 
                PAM_FAIL_CHECK;
762
 
 
763
 
                retcode = pam_open_session (pamh,
764
 
                                            hushed (&pwent) ? PAM_SILENT : 0);
765
 
                PAM_FAIL_CHECK;
 
780
                        fprintf (stderr, "\nLogin incorrect\n");
 
781
 
 
782
                        if (failcount >= retries) {
 
783
                                SYSLOG ((LOG_NOTICE,
 
784
                                         "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
 
785
                                         failcount, fromhost, failent_user));
 
786
                                fprintf(stderr,
 
787
                                        _("Maximum number of tries exceeded (%d)\n"),
 
788
                                        failcount);
 
789
                                PAM_END;
 
790
                                exit(0);
 
791
                        }
 
792
 
 
793
                        /*
 
794
                         * Let's give it another go around.
 
795
                         * Even if a username was given on the command
 
796
                         * line, prompt again for the username.
 
797
                         */
 
798
                        retcode = pam_set_item (pamh, PAM_USER, NULL);
 
799
                        PAM_FAIL_CHECK;
 
800
                }
 
801
 
 
802
                /* We don't get here unless they were authenticated above */
 
803
                alarm (0);
 
804
                retcode = pam_acct_mgmt (pamh, 0);
 
805
 
 
806
                if (retcode == PAM_NEW_AUTHTOK_REQD) {
 
807
                        retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
 
808
                }
 
809
 
 
810
                PAM_FAIL_CHECK;
 
811
        }
 
812
 
 
813
        /* Grab the user information out of the password file for future usage
 
814
           First get the username that we are actually using, though.
 
815
         */
 
816
        retcode = pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
 
817
        PAM_FAIL_CHECK;
 
818
        if (NULL != username) {
 
819
                free (username);
 
820
        }
 
821
        username = xstrdup (pam_user);
 
822
 
 
823
        pwd = xgetpwnam (username);
 
824
        if (NULL == pwd) {
 
825
                SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
 
826
                         getdef_bool ("LOG_UNKFAIL_ENAB") ?
 
827
                         username : "UNKNOWN"));
 
828
                exit (1);
 
829
        }
 
830
 
 
831
        if (fflg) {
 
832
                retcode = pam_acct_mgmt (pamh, 0);
 
833
                PAM_FAIL_CHECK;
 
834
        }
 
835
 
 
836
        if (setup_groups (pwd) != 0) {
 
837
                exit (1);
 
838
        }
 
839
 
 
840
        pwent = *pwd;
 
841
 
 
842
        retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
 
843
        PAM_FAIL_CHECK;
 
844
 
 
845
        retcode = pam_open_session (pamh, hushed (&pwent) ? PAM_SILENT : 0);
 
846
        PAM_FAIL_CHECK;
766
847
 
767
848
#else                           /* ! USE_PAM */
768
 
                while (1) {     /* repeatedly get login/password pairs */
769
 
                        failed = 0;     /* haven't failed authentication yet */
770
 
                        if (!username[0]) {     /* need to get a login id */
771
 
                                if (subroot) {
772
 
                                        closelog ();
773
 
                                        exit (1);
774
 
                                }
775
 
                                preauth_flag = 0;
776
 
                                login_prompt (_("\n%s login: "), username,
777
 
                                              sizeof username);
 
849
        while (true) {  /* repeatedly get login/password pairs */
 
850
                failed = false; /* haven't failed authentication yet */
 
851
                if (NULL == username) { /* need to get a login id */
 
852
                        if (subroot) {
 
853
                                closelog ();
 
854
                                exit (1);
 
855
                        }
 
856
                        preauth_flag = false;
 
857
                        username = malloc (32);
 
858
                        login_prompt (_("\n%s login: "), username, 32);
 
859
 
 
860
                        if ('\0' == username) {
 
861
                                /* Prompt for a new login */
 
862
                                free (username);
 
863
                                username = NULL;
778
864
                                continue;
779
865
                        }
780
 
#endif                          /* ! USE_PAM */
 
866
                }
781
867
 
782
 
#ifdef USE_PAM
783
 
                if (!(pwd = xgetpwnam (pam_user))) {
784
 
                        pwent.pw_name = pam_user;
785
 
#else
786
 
                if (!(pwd = xgetpwnam (username))) {
 
868
                pwd = xgetpwnam (username);
 
869
                if (NULL == pwd) {
787
870
                        pwent.pw_name = username;
788
 
#endif
789
871
                        strcpy (temp_pw, "!");
790
872
                        pwent.pw_passwd = temp_pw;
791
873
                        pwent.pw_shell = temp_shell;
792
874
 
793
 
                        preauth_flag = 0;
794
 
                        failed = 1;
 
875
                        preauth_flag = false;
 
876
                        failed = true;
795
877
                } else {
796
878
                        pwent = *pwd;
797
879
                }
798
 
#ifndef USE_PAM
 
880
 
799
881
                spwd = NULL;
800
 
                if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
 
882
                if (   (NULL != pwd)
 
883
                    && (strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0)) {
801
884
                        /* !USE_PAM, no need for xgetspnam */
802
885
                        spwd = getspnam (username);
803
 
                        if (spwd)
 
886
                        if (NULL != spwd) {
804
887
                                pwent.pw_passwd = spwd->sp_pwdp;
805
 
                        else
 
888
                        } else {
806
889
                                SYSLOG ((LOG_WARN,
807
 
                                         "no shadow password for `%s'%s",
808
 
                                         username, fromhost));
 
890
                                         "no shadow password for '%s'%s",
 
891
                                         username, fromhost));
 
892
                        }
809
893
                }
810
894
 
811
895
                /*
813
897
                 * is locked and the user cannot login, even if they have
814
898
                 * been "pre-authenticated."
815
899
                 */
816
 
                if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
817
 
                        failed = 1;
 
900
                if (   ('!' == pwent.pw_passwd[0])
 
901
                    || ('*' == pwent.pw_passwd[0])) {
 
902
                        failed = true;
 
903
                }
818
904
 
819
905
                /*
820
906
                 * The -r and -f flags provide a name which has already
821
907
                 * been authenticated by some server.
822
908
                 */
823
 
                if (preauth_flag)
 
909
                if (preauth_flag) {
824
910
                        goto auth_ok;
 
911
                }
825
912
 
826
 
                if (pw_auth
827
 
                    (pwent.pw_passwd, username, reason, (char *) 0) == 0)
 
913
                if (pw_auth (pwent.pw_passwd, username,
 
914
                             reason, (char *) 0) == 0) {
828
915
                        goto auth_ok;
 
916
                }
829
917
 
830
918
                /*
831
919
                 * Don't log unknown usernames - I mistyped the password for
832
920
                 * username at least once. Should probably use LOG_AUTHPRIV
833
921
                 * for those who really want to log them.  --marekm
834
922
                 */
835
 
                SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
836
 
                         (pwd
837
 
                          || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
838
 
                         username : "UNKNOWN", fromhost));
839
 
                failed = 1;
 
923
                SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
 
924
                         (   (NULL != pwd)
 
925
                          || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
 
926
                         username : "UNKNOWN", fromhost));
 
927
                failed = true;
840
928
 
841
929
              auth_ok:
842
930
                /*
844
932
                 * If you reach this far, your password has been
845
933
                 * authenticated and so on.
846
934
                 */
847
 
                if (!failed && pwent.pw_name && pwent.pw_uid == 0
 
935
                if (   !failed
 
936
                    && (NULL != pwent.pw_name)
 
937
                    && (0 == pwent.pw_uid)
848
938
                    && !is_console) {
849
939
                        SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
850
 
                        failed = 1;
 
940
                        failed = true;
851
941
                }
852
 
                if (!failed
 
942
                if (   !failed
853
943
                    && !login_access (username, *hostname ? hostname : tty)) {
854
 
                        SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
855
 
                                 username, fromhost));
856
 
                        failed = 1;
 
944
                        SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
 
945
                                 username, fromhost));
 
946
                        failed = true;
857
947
                }
858
 
                if (pwd && getdef_bool ("FAILLOG_ENAB") &&
859
 
                    !failcheck (pwent.pw_uid, &faillog, failed)) {
 
948
                if (   (NULL != pwd)
 
949
                    && getdef_bool ("FAILLOG_ENAB")
 
950
                    && !failcheck (pwent.pw_uid, &faillog, failed)) {
860
951
                        SYSLOG ((LOG_CRIT,
861
 
                                 "exceeded failure limit for `%s' %s",
862
 
                                 username, fromhost));
863
 
                        failed = 1;
 
952
                                 "exceeded failure limit for '%s' %s",
 
953
                                 username, fromhost));
 
954
                        failed = true;
864
955
                }
865
 
                if (!failed)
 
956
                if (!failed) {
866
957
                        break;
 
958
                }
867
959
 
868
960
                /* don't log non-existent users */
869
 
                if (pwd && getdef_bool ("FAILLOG_ENAB"))
 
961
                if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
870
962
                        failure (pwent.pw_uid, tty, &faillog);
 
963
                }
871
964
                if (getdef_str ("FTMP_FILE") != NULL) {
872
965
                        const char *failent_user;
873
966
 
874
967
#if HAVE_UTMPX_H
875
968
                        failent = utxent;
876
 
                        if (sizeof (failent.ut_tv) == sizeof (struct timeval))
877
 
                                gettimeofday ((struct timeval *)
878
 
                                              &failent.ut_tv, NULL);
879
 
                        else {
 
969
                        if (sizeof (failent.ut_tv) == sizeof (struct timeval)) {
 
970
                                gettimeofday ((struct timeval *) &failent.ut_tv,
 
971
                                              NULL);
 
972
                        } else {
880
973
                                struct timeval tv;
881
974
 
882
975
                                gettimeofday (&tv, NULL);
887
980
                        failent = utent;
888
981
                        failent.ut_time = time (NULL);
889
982
#endif
890
 
                        if (pwd) {
 
983
                        if (NULL != pwd) {
891
984
                                failent_user = pwent.pw_name;
892
985
                        } else {
893
 
                                if (getdef_bool ("LOG_UNKFAIL_ENAB"))
 
986
                                if (getdef_bool ("LOG_UNKFAIL_ENAB")) {
894
987
                                        failent_user = username;
895
 
                                else
 
988
                                } else {
896
989
                                        failent_user = "UNKNOWN";
 
990
                                }
897
991
                        }
898
992
                        strncpy (failent.ut_user, failent_user,
899
 
                                 sizeof (failent.ut_user));
 
993
                                 sizeof (failent.ut_user));
900
994
                        failent.ut_type = USER_PROCESS;
901
995
                        failtmp (&failent);
902
996
                }
903
 
                memzero (username, sizeof username);
904
997
 
905
 
                if (--retries <= 0)
 
998
                retries--;
 
999
                if (retries <= 0) {
906
1000
                        SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
907
 
                                 fromhost));
 
1001
                                 fromhost));
 
1002
                }
 
1003
 
908
1004
                /*
909
1005
                 * If this was a passwordless account and we get here, login
910
1006
                 * was denied (securetty, faillog, etc.). There was no
912
1008
                 * guys won't see that the passwordless account exists at
913
1009
                 * all).  --marekm
914
1010
                 */
915
 
                if (pwent.pw_passwd[0] == '\0')
 
1011
                if (pwent.pw_passwd[0] == '\0') {
916
1012
                        pw_auth ("!", username, reason, (char *) 0);
 
1013
                }
 
1014
 
 
1015
                /*
 
1016
                 * Authentication of this user failed.
 
1017
                 * The username must be confirmed in the next try.
 
1018
                 */
 
1019
                free (username);
 
1020
                username = NULL;
917
1021
 
918
1022
                /*
919
1023
                 * Wait a while (a la SVR4 /usr/bin/login) before attempting
920
1024
                 * to login the user again. If the earlier alarm occurs
921
1025
                 * before the sleep() below completes, login will exit.
922
1026
                 */
923
 
                if (delay > 0)
 
1027
                if (delay > 0) {
924
1028
                        sleep (delay);
 
1029
                }
925
1030
 
926
1031
                puts (_("Login incorrect"));
927
1032
 
928
1033
                /* allow only one attempt with -r or -f */
929
 
                if (rflg || fflg || retries <= 0) {
 
1034
                if (rflg || fflg || (retries <= 0)) {
930
1035
                        closelog ();
931
1036
                        exit (1);
932
1037
                }
933
 
        }                       /* while (1) */
 
1038
        }                       /* while (true) */
934
1039
#endif                          /* ! USE_PAM */
 
1040
 
935
1041
        alarm (0);              /* turn off alarm clock */
 
1042
 
936
1043
#ifndef USE_PAM                 /* PAM does this */
937
1044
        /*
938
1045
         * porttime checks moved here, after the user has been
939
1046
         * authenticated. now prints a message, as suggested
940
1047
         * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
941
1048
         */
942
 
        if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
943
 
            !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
944
 
                SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
945
 
                         username, fromhost));
 
1049
        if (   getdef_bool ("PORTTIME_CHECKS_ENAB")
 
1050
            && !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
 
1051
                SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
 
1052
                         username, fromhost));
946
1053
                closelog ();
947
1054
                bad_time_notify ();
948
1055
                exit (1);
951
1058
        check_nologin ();
952
1059
#endif
953
1060
 
954
 
        if (getenv ("IFS"))     /* don't export user IFS ... */
 
1061
        if (getenv ("IFS")) {   /* don't export user IFS ... */
955
1062
                addenv ("IFS= \t\n", NULL);     /* ... instead, set a safe IFS */
 
1063
        }
956
1064
 
957
 
#ifdef USE_PAM
958
 
        setutmp (pam_user, tty, hostname);      /* make entry in utmp & wtmp files */
959
 
#else
960
1065
        setutmp (username, tty, hostname);      /* make entry in utmp & wtmp files */
961
 
#endif
962
1066
        if (pwent.pw_shell[0] == '*') { /* subsystem root */
963
1067
                pwent.pw_shell++;       /* skip the '*' */
964
1068
                subsystem (&pwent);     /* figure out what to execute */
965
 
                subroot++;      /* say i was here again */
 
1069
                subroot = true; /* say I was here again */
966
1070
                endpwent ();    /* close all of the file which were */
967
1071
                endgrent ();    /* open in the original rooted file */
968
1072
                endspent ();    /* system. they will be re-opened */
973
1077
        }
974
1078
 
975
1079
#ifdef WITH_AUDIT
976
 
        {
977
 
                char buf[32];
978
 
 
979
 
                audit_fd = audit_open ();
980
 
                snprintf (buf, sizeof (buf), "uid=%d", pwd->pw_uid);
981
 
                audit_log_user_message (audit_fd, AUDIT_USER_LOGIN,
982
 
                                        buf, hostname, NULL, tty, 1);
983
 
                close (audit_fd);
984
 
        }
 
1080
        audit_fd = audit_open ();
 
1081
        audit_log_acct_message (audit_fd,
 
1082
                                AUDIT_USER_LOGIN,
 
1083
                                NULL,    /* Prog. name */
 
1084
                                "login",
 
1085
                                pwd->pw_name,
 
1086
                                AUDIT_NO_ID,
 
1087
                                hostname,
 
1088
                                NULL,    /* addr */
 
1089
                                tty,
 
1090
                                1);      /* result */
 
1091
        close (audit_fd);
985
1092
#endif                          /* WITH_AUDIT */
986
1093
 
987
1094
#ifndef USE_PAM                 /* pam_lastlog handles this */
988
 
        if (getdef_bool ("LASTLOG_ENAB"))       /* give last login and log this one */
 
1095
        if (getdef_bool ("LASTLOG_ENAB")) {     /* give last login and log this one */
989
1096
                dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
 
1097
        }
990
1098
#endif
991
1099
 
992
1100
#ifndef USE_PAM                 /* PAM handles this as well */
1002
1110
                        pwd = getpwnam (username);
1003
1111
                        /* !USE_PAM, no need for xgetspnam */
1004
1112
                        spwd = getspnam (username);
1005
 
                        if (pwd)
 
1113
                        if (pwd) {
1006
1114
                                pwent = *pwd;
 
1115
                        }
1007
1116
                }
1008
1117
        }
1009
1118
        setup_limits (&pwent);  /* nice, ulimit etc. */
1010
1119
#endif                          /* ! USE_PAM */
1011
 
        chown_tty (tty, &pwent);
 
1120
        chown_tty (&pwent);
1012
1121
 
1013
1122
#ifdef USE_PAM
1014
1123
        /*
1015
1124
         * We must fork before setuid() because we need to call
1016
1125
         * pam_close_session() as root.
1017
1126
         */
1018
 
        signal (SIGINT, SIG_IGN);
 
1127
        (void) signal (SIGINT, SIG_IGN);
1019
1128
        child = fork ();
1020
1129
        if (child < 0) {
1021
1130
                /* error in fork() */
1022
1131
                fprintf (stderr, _("%s: failure forking: %s"),
1023
 
                         Prog, strerror (errno));
 
1132
                         Prog, strerror (errno));
1024
1133
                PAM_END;
1025
1134
                exit (0);
1026
 
        } else if (child) {
 
1135
        } else if (child != 0) {
1027
1136
                /*
1028
1137
                 * parent - wait for child to finish, then cleanup
1029
1138
                 * session
1037
1146
        /* If we were init, we need to start a new session */
1038
1147
        if (getppid() == 1) {
1039
1148
                setsid();
1040
 
                if (ioctl(0, TIOCSCTTY, 1))
1041
 
                        fprintf(stderr,_("TIOCSCTTY failed on %s"),tty);
 
1149
                if (ioctl(0, TIOCSCTTY, 1) != 0) {
 
1150
                        fprintf (stderr,_("TIOCSCTTY failed on %s"),tty);
 
1151
                }
1042
1152
        }
1043
1153
 
1044
1154
        /* We call set_groups() above because this clobbers pam_groups.so */
1047
1157
#else
1048
1158
        if (change_uid (&pwent))
1049
1159
#endif
 
1160
        {
1050
1161
                exit (1);
 
1162
        }
1051
1163
 
1052
1164
        setup_env (&pwent);     /* set env vars, cd to the home dir */
1053
1165
 
1056
1168
                const char *const *env;
1057
1169
 
1058
1170
                env = (const char *const *) pam_getenvlist (pamh);
1059
 
                while (env && *env) {
 
1171
                while ((NULL != env) && (NULL != *env)) {
1060
1172
                        addenv (*env, NULL);
1061
1173
                        env++;
1062
1174
                }
1063
1175
        }
1064
1176
#endif
1065
1177
 
1066
 
        setlocale (LC_ALL, "");
1067
 
        bindtextdomain (PACKAGE, LOCALEDIR);
1068
 
        textdomain (PACKAGE);
 
1178
        (void) setlocale (LC_ALL, "");
 
1179
        (void) bindtextdomain (PACKAGE, LOCALEDIR);
 
1180
        (void) textdomain (PACKAGE);
1069
1181
 
1070
1182
        if (!hushed (&pwent)) {
1071
1183
                addenv ("HUSHLOGIN=FALSE", NULL);
1075
1187
                 */
1076
1188
#ifndef USE_PAM
1077
1189
                motd ();        /* print the message of the day */
1078
 
                if (getdef_bool ("FAILLOG_ENAB")
1079
 
                    && faillog.fail_cnt != 0) {
 
1190
                if (   getdef_bool ("FAILLOG_ENAB")
 
1191
                    && (0 != faillog.fail_cnt)) {
1080
1192
                        failprint (&faillog);
1081
1193
                        /* Reset the lockout times if logged in */
1082
 
                        if (faillog.fail_max &&
1083
 
                            faillog.fail_cnt >= faillog.fail_max) {
 
1194
                        if (   (0 != faillog.fail_max)
 
1195
                            && (faillog.fail_cnt >= faillog.fail_max)) {
1084
1196
                                puts (_
1085
1197
                                      ("Warning: login re-enabled after temporary lockout."));
1086
1198
                                SYSLOG ((LOG_WARN,
1087
 
                                         "login `%s' re-enabled after temporary lockout (%d failures)",
1088
 
                                         username, (int) faillog.fail_cnt));
 
1199
                                         "login '%s' re-enabled after temporary lockout (%d failures)",
 
1200
                                         username, (int) faillog.fail_cnt));
1089
1201
                        }
1090
1202
                }
1091
 
                if (getdef_bool ("LASTLOG_ENAB")
1092
 
                    && lastlog.ll_time != 0) {
 
1203
                if (   getdef_bool ("LASTLOG_ENAB")
 
1204
                    && (lastlog.ll_time != 0)) {
1093
1205
                        time_t ll_time = lastlog.ll_time;
1094
1206
 
1095
1207
#ifdef HAVE_STRFTIME
1096
1208
                        strftime (ptime, sizeof (ptime),
1097
 
                                  "%a %b %e %H:%M:%S %z %Y",
1098
 
                                  localtime (&ll_time));
 
1209
                                  "%a %b %e %H:%M:%S %z %Y",
 
1210
                                  localtime (&ll_time));
1099
1211
                        printf (_("Last login: %s on %s"),
1100
 
                                ptime, lastlog.ll_line);
 
1212
                                ptime, lastlog.ll_line);
1101
1213
#else
1102
1214
                        printf (_("Last login: %.19s on %s"),
1103
 
                                ctime (&ll_time), lastlog.ll_line);
 
1215
                                ctime (&ll_time), lastlog.ll_line);
1104
1216
#endif
1105
1217
#ifdef HAVE_LL_HOST             /* __linux__ || SUN4 */
1106
 
                        if (lastlog.ll_host[0])
 
1218
                        if ('\0' != lastlog.ll_host[0]) {
1107
1219
                                printf (_(" from %.*s"),
1108
 
                                        (int) sizeof lastlog.
1109
 
                                        ll_host, lastlog.ll_host);
 
1220
                                        (int) sizeof lastlog.
 
1221
                                        ll_host, lastlog.ll_host);
 
1222
                        }
1110
1223
#endif
1111
1224
                        printf (".\n");
1112
1225
                }
1113
 
                agecheck (&pwent, spwd);
 
1226
                agecheck (spwd);
1114
1227
 
1115
1228
                mailcheck ();   /* report on the status of mail */
1116
1229
#endif                          /* !USE_PAM */
1117
 
        } else
 
1230
        } else {
1118
1231
                addenv ("HUSHLOGIN=TRUE", NULL);
 
1232
        }
1119
1233
 
1120
 
        if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
 
1234
        if (   (NULL != getdef_str ("TTYTYPE_FILE"))
 
1235
            && (NULL == getenv ("TERM"))) {
1121
1236
                ttytype (tty);
 
1237
        }
1122
1238
 
1123
 
        signal (SIGQUIT, SIG_DFL);      /* default quit signal */
1124
 
        signal (SIGTERM, SIG_DFL);      /* default terminate signal */
1125
 
        signal (SIGALRM, SIG_DFL);      /* default alarm signal */
1126
 
        signal (SIGHUP, SIG_DFL);       /* added this.  --marekm */
1127
 
        signal (SIGINT, SIG_DFL);       /* default interrupt signal */
 
1239
        (void) signal (SIGQUIT, SIG_DFL);       /* default quit signal */
 
1240
        (void) signal (SIGTERM, SIG_DFL);       /* default terminate signal */
 
1241
        (void) signal (SIGALRM, SIG_DFL);       /* default alarm signal */
 
1242
        (void) signal (SIGHUP, SIG_DFL);        /* added this.  --marekm */
 
1243
        (void) signal (SIGINT, SIG_DFL);        /* default interrupt signal */
1128
1244
 
1129
1245
        endpwent ();            /* stop access to password file */
1130
1246
        endgrent ();            /* stop access to group file */
1132
1248
#ifdef  SHADOWGRP
1133
1249
        endsgent ();            /* stop access to shadow group file */
1134
1250
#endif
1135
 
        if (pwent.pw_uid == 0)
 
1251
        if (0 == pwent.pw_uid) {
1136
1252
                SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1137
 
        else if (getdef_bool ("LOG_OK_LOGINS"))
1138
 
#ifdef USE_PAM
1139
 
                SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1140
 
#else
1141
 
                SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1142
 
#endif
 
1253
        } else if (getdef_bool ("LOG_OK_LOGINS")) {
 
1254
                SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
 
1255
        }
1143
1256
        closelog ();
1144
 
        if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
 
1257
        tmp = getdef_str ("FAKE_SHELL");
 
1258
        if (NULL != tmp) {
1145
1259
                err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1146
 
        else
 
1260
        } else {
1147
1261
                /* exec the shell finally */
1148
1262
                err = shell (pwent.pw_shell, (char *) 0, newenvp);
 
1263
        }
1149
1264
        exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
1150
1265
        /* NOT REACHED */
1151
1266
        return 0;
1152
1267
}
 
1268