Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/loginutils


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

Location:
branches/2.2.5/mindi-busybox/loginutils
Files:
3 added
2 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/loginutils/Config.in

    r902 r1765  
    66menu "Login/Password Management Utilities"
    77
    8 config CONFIG_FEATURE_SHADOWPASSWDS
     8config FEATURE_SHADOWPASSWDS
    99    bool "Support for shadow passwords"
    1010    default n
     
    1414      publicly readable.
    1515
    16 config CONFIG_USE_BB_SHADOW
     16config USE_BB_SHADOW
    1717    bool "  Use busybox shadow password functions"
    1818    default y
    19     depends on CONFIG_USE_BB_PWD_GRP && CONFIG_FEATURE_SHADOWPASSWDS
     19    depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS
    2020    help
    2121        If you leave this disabled, busybox will use the system's shadow
     
    3333        password servers and whatnot.
    3434
    35 config CONFIG_USE_BB_PWD_GRP
     35config USE_BB_PWD_GRP
    3636    bool "Use internal password and group functions rather than system functions"
    3737    default n
     
    5454        If you enable this option, it will add about 1.5k to busybox.
    5555
    56 config CONFIG_ADDGROUP
     56config ADDGROUP
    5757    bool "addgroup"
    5858    default n
     
    6060      Utility for creating a new group account.
    6161
    62 config CONFIG_DELGROUP
     62config FEATURE_ADDUSER_TO_GROUP
     63    bool "Support for adding users to groups"
     64    default n
     65    depends on ADDGROUP
     66    help
     67      If  called  with two non-option arguments,
     68      addgroup will add an existing user to an
     69      existing group.
     70
     71config DELGROUP
    6372    bool "delgroup"
    6473    default n
     
    6675      Utility for deleting a group account.
    6776
    68 config CONFIG_ADDUSER
     77config FEATURE_DEL_USER_FROM_GROUP
     78    bool "Support for removing users from groups."
     79    default n
     80    depends on DELGROUP
     81    help
     82      If called with two non-option arguments, deluser
     83      or delgroup will remove an user from a specified group.
     84
     85config ADDUSER
    6986    bool "adduser"
    7087    default n
     
    7289      Utility for creating a new user account.
    7390
    74 config CONFIG_DELUSER
     91config DELUSER
    7592    bool "deluser"
    7693    default n
     
    7895      Utility for deleting a user account.
    7996
    80 config CONFIG_GETTY
     97config GETTY
    8198    bool "getty"
    8299    default n
     100    select FEATURE_SYSLOG
    83101    help
    84102      getty lets you log in on a tty, it is normally invoked by init.
    85103
    86 config CONFIG_FEATURE_UTMP
     104config FEATURE_UTMP
    87105    bool "Support utmp file"
    88     depends on CONFIG_GETTY || CONFIG_LOGIN || CONFIG_SU || CONFIG_WHO
     106    depends on GETTY || LOGIN || SU || WHO
    89107    default n
    90108    help
    91109      The file /var/run/utmp is used to track who is currently logged in.
    92110
    93 config CONFIG_FEATURE_WTMP
     111config FEATURE_WTMP
    94112    bool "Support wtmp file"
    95     depends on CONFIG_GETTY || CONFIG_LOGIN || CONFIG_SU || CONFIG_LAST
    96     default n
    97     select CONFIG_FEATURE_UTMP
     113    depends on GETTY || LOGIN || SU || LAST
     114    default n
     115    select FEATURE_UTMP
    98116    help
    99117      The file /var/run/wtmp is used to track when user's have logged into
    100118      and logged out of the system.
    101119
    102 config CONFIG_LOGIN
     120config LOGIN
    103121    bool "login"
    104122    default n
    105     select CONFIG_FEATURE_SUID
     123    select FEATURE_SUID
     124    select FEATURE_SYSLOG
    106125    help
    107126      login is used when signing onto a system.
     
    110129      work properly.
    111130
    112 config CONFIG_FEATURE_SECURETTY
     131config PAM
     132    bool "Support for PAM (Pluggable Authentication Modules)"
     133    default n
     134    depends on LOGIN
     135    help
     136      Use PAM in login(1) instead of direct access to password database.
     137
     138config LOGIN_SCRIPTS
     139    bool "Support for login scripts"
     140    depends on LOGIN
     141    default n
     142    help
     143      Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT
     144      just prior to switching from root to logged-in user.
     145
     146config FEATURE_NOLOGIN
     147    bool "Support for /etc/nologin"
     148    default y
     149    depends on LOGIN
     150    help
     151      The file /etc/nologin is used by (some versions of) login(1).
     152      If it exists, non-root logins are prohibited.
     153
     154config FEATURE_SECURETTY
    113155    bool "Support for /etc/securetty"
    114156    default y
    115     depends on CONFIG_LOGIN
    116     help
    117       The file  /etc/securetty is used by (some versions of) login(1).
     157    depends on LOGIN
     158    help
     159      The file /etc/securetty is used by (some versions of) login(1).
    118160      The file contains the device names of tty lines (one per line,
    119161      without leading /dev/) on which root is allowed to login.
    120162
    121 config CONFIG_PASSWD
     163config PASSWD
    122164    bool "passwd"
    123165    default n
    124     select CONFIG_FEATURE_SUID
     166    select FEATURE_SUID
     167    select FEATURE_SYSLOG
    125168    help
    126169      passwd changes passwords for user and group accounts.  A normal user
     
    132175      work properly.
    133176
    134 config CONFIG_SU
     177config FEATURE_PASSWD_WEAK_CHECK
     178    bool "Check new passwords for weakness"
     179    default y
     180    depends on PASSWD
     181    help
     182      With this option passwd will refuse new passwords which are "weak".
     183
     184config CRYPTPW
     185    bool "cryptpw"
     186    default n
     187    help
     188      Applet for crypting a string.
     189
     190config CHPASSWD
     191       bool "chpasswd"
     192       default n
     193       help
     194         chpasswd  reads  a  file  of user name and password pairs from
     195         standard input and uses this information to update a group of
     196         existing users.
     197
     198config SU
    135199    bool "su"
    136200    default n
    137     select CONFIG_FEATURE_SUID
     201    select FEATURE_SUID
     202    select FEATURE_SYSLOG
    138203    help
    139204      su is used to become another user during a login session.
     
    143208      work properly.
    144209
    145 config CONFIG_SULOGIN
     210config FEATURE_SU_SYSLOG
     211    bool "Enable su to write to syslog"
     212    default y
     213    depends on SU
     214
     215config FEATURE_SU_CHECKS_SHELLS
     216    bool "Enable su to check user's shell to be listed in /etc/shells"
     217    depends on SU
     218    default y
     219
     220config SULOGIN
    146221    bool "sulogin"
    147222    default n
     223    select FEATURE_SYSLOG
    148224    help
    149225      sulogin is invoked when the system goes into single user
    150226      mode (this is done through an entry in inittab).
    151227
    152 config CONFIG_VLOCK
     228config VLOCK
    153229    bool "vlock"
    154230    default n
    155     select CONFIG_FEATURE_SUID
     231    select FEATURE_SUID
    156232    help
    157233      Build the "vlock" applet which allows you to lock (virtual) terminals.
  • branches/2.2.5/mindi-busybox/loginutils/addgroup.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * addgroup - add users to /etc/passwd and /etc/shadow
     3 * addgroup - add groups to /etc/group and /etc/gshadow
    44 *
    55 * Copyright (C) 1999 by Lineo, inc. and John Beppu
    66 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
     7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
    78 *
    89 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     
    1011 */
    1112
    12 #include <stdio.h>
    13 #include <string.h>
    14 #include <sys/types.h>
    15 #include <unistd.h>
     13#include "libbb.h"
    1614
    17 #include "busybox.h"
     15static void xgroup_study(struct group *g)
     16{
     17    /* Make sure gr_name is unused */
     18    if (getgrnam(g->gr_name)) {
     19        goto error;
     20    }
    1821
    19 /* make sure gr_name isn't taken, make sure gid is kosher
    20  * return 1 on failure */
    21 static int group_study(struct group *g)
    22 {
    23     FILE *etc_group;
    24     gid_t desired;
    25 
    26     struct group *grp;
    27     const int max = 65000;
    28 
    29     etc_group = bb_xfopen(bb_path_group_file, "r");
    30 
    31     /* make sure gr_name isn't taken, make sure gid is kosher */
    32     desired = g->gr_gid;
    33     while ((grp = fgetgrent(etc_group))) {
    34         if ((strcmp(grp->gr_name, g->gr_name)) == 0) {
    35             bb_error_msg_and_die("%s: group already in use", g->gr_name);
     22    /* Check if the desired gid is free
     23     * or find the first free one */
     24    while (1) {
     25        if (!getgrgid(g->gr_gid)) {
     26            return; /* found free group: return */
    3627        }
    37         if ((desired) && grp->gr_gid == desired) {
    38             bb_error_msg_and_die("%d: gid already in use",
    39                               desired);
     28        if (option_mask32) {
     29            /* -g N, cannot pick gid other than N: error */
     30            g->gr_name = itoa(g->gr_gid);
     31            goto error;
    4032        }
    41         if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) {
    42             g->gr_gid = grp->gr_gid;
     33        g->gr_gid++;
     34        if (g->gr_gid <= 0) {
     35            /* overflowed: error */
     36            bb_error_msg_and_die("no gids left");
    4337        }
    4438    }
    45     fclose(etc_group);
    4639
    47     /* gid */
    48     if (desired) {
    49         g->gr_gid = desired;
    50     } else {
    51         g->gr_gid++;
    52     }
    53     /* return 1; */
    54     return 0;
     40 error:
     41    /* exit */
     42    bb_error_msg_and_die("group %s already exists", g->gr_name);
    5543}
    5644
    5745/* append a new user to the passwd file */
    58 static int addgroup(char *group, gid_t gid, const char *user)
     46static void new_group(char *group, gid_t gid)
    5947{
    6048    FILE *file;
     
    6452    gr.gr_gid = gid;
    6553    gr.gr_name = group;
    66     if (group_study(&gr))
    67         return 1;
     54    xgroup_study(&gr);
    6855
    6956    /* add entry to group */
    70     file = bb_xfopen(bb_path_group_file, "a");
     57    file = xfopen(bb_path_group_file, "a");
    7158    /* group:passwd:gid:userlist */
    72     fprintf(file, "%s:%s:%d:%s\n", group, "x", gr.gr_gid, user);
    73     fclose(file);
     59    fprintf(file, "%s:x:%d:\n", group, gr.gr_gid);
     60    if (ENABLE_FEATURE_CLEAN_UP)
     61        fclose(file);
     62#if ENABLE_FEATURE_SHADOWPASSWDS
     63    file = fopen_or_warn(bb_path_gshadow_file, "a");
     64    if (file) {
     65        fprintf(file, "%s:!::\n", group);
     66        if (ENABLE_FEATURE_CLEAN_UP)
     67            fclose(file);
     68    }
     69#endif
     70}
    7471
    75 #if ENABLE_FEATURE_SHADOWPASSWDS
    76     file = bb_xfopen(bb_path_gshadow_file, "a");
    77     fprintf(file, "%s:!::\n", group);
    78     fclose(file);
     72#if ENABLE_FEATURE_ADDUSER_TO_GROUP
     73static void add_user_to_group(char **args,
     74        const char *path,
     75        FILE *(*fopen_func)(const char *fileName, const char *mode))
     76{
     77    char *line;
     78    int len = strlen(args[1]);
     79    llist_t *plist = NULL;
     80    FILE *group_file;
     81
     82    group_file = fopen_func(path, "r");
     83
     84    if (!group_file) return;
     85
     86    while ((line = xmalloc_getline(group_file))) {
     87        /* Find the group */
     88        if (!strncmp(line, args[1], len)
     89         && line[len] == ':'
     90        ) {
     91            /* Add the new user */
     92            line = xasprintf("%s%s%s", line,
     93                        last_char_is(line, ':') ? "" : ",",
     94                        args[0]);
     95        }
     96        llist_add_to_end(&plist, line);
     97    }
     98
     99    if (ENABLE_FEATURE_CLEAN_UP) {
     100        fclose(group_file);
     101        group_file = fopen_func(path, "w");
     102        while ((line = llist_pop(&plist))) {
     103            if (group_file)
     104                fprintf(group_file, "%s\n", line);
     105            free(line);
     106        }
     107        if (group_file)
     108            fclose(group_file);
     109    } else {
     110        group_file = fopen_func(path, "w");
     111        if (group_file)
     112            while ((line = llist_pop(&plist)))
     113                fprintf(group_file, "%s\n", line);
     114    }
     115}
    79116#endif
    80 
    81     /* return 1; */
    82     return 0;
    83 }
    84117
    85118/*
    86119 * addgroup will take a login_name as its first parameter.
    87120 *
    88  * gid
    89  *
    90  * can be customized via command-line parameters.
    91  * ________________________________________________________________________ */
     121 * gid can be customized via command-line parameters.
     122 * If called with two non-option arguments, addgroup
     123 * will add an existing user to an existing group.
     124 */
     125int addgroup_main(int argc, char **argv);
    92126int addgroup_main(int argc, char **argv)
    93127{
    94128    char *group;
    95129    gid_t gid = 0;
    96    
    97     /* check for min, max and missing args and exit on error */
    98     bb_opt_complementally = "-1:?2:?";
    99130
    100     if (bb_getopt_ulflags(argc, argv, "g:", &group)) {
    101         gid = bb_xgetlarg(group, 10, 0, LONG_MAX);
     131    /* need to be root */
     132    if (geteuid()) {
     133        bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
     134    }
     135
     136    /* Syntax:
     137     *  addgroup group
     138     *  addgroup -g num group
     139     *  addgroup user group
     140     * Check for min, max and missing args */
     141    opt_complementary = "-1:?2";
     142    if (getopt32(argv, "g:", &group)) {
     143        gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1);
    102144    }
    103145    /* move past the commandline options */
    104146    argv += optind;
     147    argc -= optind;
    105148
    106     /* need to be root */
    107     if(geteuid()) {
    108         bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    109     }
     149#if ENABLE_FEATURE_ADDUSER_TO_GROUP
     150    if (argc == 2) {
     151        struct group *gr;
    110152
    111     /* werk */
    112     return addgroup(argv[0], gid, (argv[1]) ? argv[1] : "");
     153        if (option_mask32) {
     154            /* -g was there, but "addgroup -g num user group"
     155             * is a no-no */
     156            bb_show_usage();
     157        }
     158
     159        /* check if group and user exist */
     160        xuname2uid(argv[0]); /* unknown user: exit */
     161        xgroup2gid(argv[1]); /* unknown group: exit */
     162        /* check if user is already in this group */
     163        gr = getgrnam(argv[1]);
     164        for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
     165            if (!strcmp(argv[0], *(gr->gr_mem))) {
     166                /* user is already in group: do nothing */
     167                return EXIT_SUCCESS;
     168            }
     169        }
     170        add_user_to_group(argv, bb_path_group_file, xfopen);
     171#if ENABLE_FEATURE_SHADOWPASSWDS
     172        add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn);
     173#endif /* ENABLE_FEATURE_SHADOWPASSWDS */
     174    } else
     175#endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
     176        new_group(argv[0], gid);
     177
     178    /* Reached only on success */
     179    return EXIT_SUCCESS;
    113180}
  • branches/2.2.5/mindi-busybox/loginutils/adduser.c

    r821 r1765  
    99 */
    1010
    11 #include <stdio.h>
    12 #include <sys/types.h>
    13 #include <string.h>
    14 #include <unistd.h>
    15 #include <time.h>
    16 #include <getopt.h>
    17 #include <sys/stat.h>
    18 
    19 #include "busybox.h"
    20 
    21 #define DONT_SET_PASS           (1 << 4)
    22 #define DONT_MAKE_HOME          (1 << 6)
     11#include "libbb.h"
     12
     13#define OPT_DONT_SET_PASS  (1 << 4)
     14#define OPT_DONT_MAKE_HOME (1 << 6)
    2315
    2416
     
    2719static int passwd_study(const char *filename, struct passwd *p)
    2820{
    29     struct passwd *pw;
     21    enum { min = 500, max = 65000 };
    3022    FILE *passwd;
    31 
    32     const int min = 500;
    33     const int max = 65000;
    34 
    35     passwd = bb_xfopen(filename, "r");
     23    /* We are using reentrant fgetpwent_r() in order to avoid
     24     * pulling in static buffers from libc (think static build here) */
     25    char buffer[256];
     26    struct passwd pw;
     27    struct passwd *result;
     28
     29    passwd = xfopen(filename, "r");
    3630
    3731    /* EDR if uid is out of bounds, set to min */
     
    4337     * find free uid and gid;
    4438     */
    45     while ((pw = fgetpwent(passwd))) {
    46         if (strcmp(pw->pw_name, p->pw_name) == 0) {
     39    while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) {
     40        if (strcmp(pw.pw_name, p->pw_name) == 0) {
    4741            /* return 0; */
    4842            return 1;
    4943        }
    50         if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
    51             && (pw->pw_uid >= min)) {
    52             p->pw_uid = pw->pw_uid + 1;
     44        if ((pw.pw_uid >= p->pw_uid) && (pw.pw_uid < max)
     45            && (pw.pw_uid >= min)) {
     46            p->pw_uid = pw.pw_uid + 1;
    5347        }
    5448    }
     
    7973    char *cmd;
    8074
    81     cmd = bb_xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
     75    cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
    8276    system(cmd);
    8377    free(cmd);
     
    8882static void passwd_wrapper(const char *login)
    8983{
    90     static const char prog[] = "passwd";
    91     execlp(prog, prog, login, NULL);
    92     bb_error_msg_and_die("Failed to execute '%s', you must set the password for '%s' manually", prog, login);
     84    static const char prog[] ALIGN1 = "passwd";
     85
     86    BB_EXECLP(prog, prog, login, NULL);
     87    bb_error_msg_and_die("failed to execute '%s', you must set the password for '%s' manually", prog, login);
    9388}
    9489
    9590/* putpwent(3) remix */
    96 static int adduser(struct passwd *p, unsigned long flags)
     91static int adduser(struct passwd *p)
    9792{
    9893    FILE *file;
     
    10095
    10196    /* make sure everything is kosher and setup uid && gid */
    102     file = bb_xfopen(bb_path_passwd_file, "a");
     97    file = xfopen(bb_path_passwd_file, "a");
    10398    fseek(file, 0, SEEK_END);
    10499
     
    110105        case 3:
    111106            bb_error_msg_and_die("%s: group name already in use", p->pw_name);
    112     }
     107    }
    113108
    114109    /* add to passwd */
     
    116111        bb_perror_nomsg_and_die();
    117112    }
     113    /* Do fclose even if !ENABLE_FEATURE_CLEAN_UP.
     114     * We will exec passwd, files must be flushed & closed before that! */
    118115    fclose(file);
    119116
    120117#if ENABLE_FEATURE_SHADOWPASSWDS
    121118    /* add to shadow if necessary */
    122     file = bb_xfopen(bb_path_shadow_file, "a");
    123     fseek(file, 0, SEEK_END);
    124     fprintf(file, "%s:!:%ld:%d:%d:%d:::\n",
    125                     p->pw_name,             /* username */
    126                     time(NULL) / 86400,     /* sp->sp_lstchg */
    127                     0,                      /* sp->sp_min */
    128                     99999,                  /* sp->sp_max */
    129                     7);                     /* sp->sp_warn */
    130     fclose(file);
     119    file = fopen_or_warn(bb_path_shadow_file, "a");
     120    if (file) {
     121        fseek(file, 0, SEEK_END);
     122        fprintf(file, "%s:!:%ld:%d:%d:%d:::\n",
     123                p->pw_name,             /* username */
     124                time(NULL) / 86400,     /* sp->sp_lstchg */
     125                0,                      /* sp->sp_min */
     126                99999,                  /* sp->sp_max */
     127                7);                     /* sp->sp_warn */
     128        fclose(file);
     129    }
    131130#endif
    132131
     
    137136
    138137    /* Clear the umask for this process so it doesn't
    139      * * screw up the permissions on the mkdir and chown. */
     138     * screw up the permissions on the mkdir and chown. */
    140139    umask(0);
    141     if (!(flags & DONT_MAKE_HOME)) {
     140    if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
    142141        /* Set the owner and group so it is owned by the new user,
    143142           then fix up the permissions to 2755. Can't do it before
     
    146145        || chown(p->pw_dir, p->pw_uid, p->pw_gid)
    147146        || chmod(p->pw_dir, 02755)) {
    148             bb_perror_msg("%s", p->pw_dir);
    149         }
    150     }
    151 
    152     if (!(flags & DONT_SET_PASS)) {
     147            bb_perror_msg("%s", p->pw_dir);
     148        }
     149    }
     150
     151    if (!(option_mask32 & OPT_DONT_SET_PASS)) {
    153152        /* interactively set passwd */
    154153        passwd_wrapper(p->pw_name);
     
    166165 *
    167166 * can be customized via command-line parameters.
    168  * ________________________________________________________________________ */
     167 */
     168int adduser_main(int argc, char **argv);
    169169int adduser_main(int argc, char **argv)
    170170{
    171171    struct passwd pw;
    172172    const char *usegroup = NULL;
    173     unsigned long flags;
    174 
    175     pw.pw_gecos = "Linux User,,,";
     173
     174    /* got root? */
     175    if (geteuid()) {
     176        bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
     177    }
     178
     179    pw.pw_gecos = (char *)"Linux User,,,";
    176180    pw.pw_shell = (char *)DEFAULT_SHELL;
    177181    pw.pw_dir = NULL;
    178182
    179     /* check for min, max and missing args and exit on error */
    180     bb_opt_complementally = "-1:?1:?";
    181     flags = bb_getopt_ulflags(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
    182 
    183     /* got root? */
    184     if(geteuid()) {
    185         bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    186     }
    187 
    188     /* create string for $HOME if not specified already */
     183    /* exactly one non-option arg */
     184    opt_complementary = "=1";
     185    getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
     186    argv += optind;
     187
     188    /* create a passwd struct */
     189    pw.pw_name = argv[0];
    189190    if (!pw.pw_dir) {
    190         snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]);
    191         pw.pw_dir =  &bb_common_bufsiz1[0];
    192     }
    193 
    194     /* create a passwd struct */
    195     pw.pw_name = argv[optind];
    196     pw.pw_passwd = "x";
     191        /* create string for $HOME if not specified already */
     192        pw.pw_dir = xasprintf("/home/%s", argv[0]);
     193    }
     194    pw.pw_passwd = (char *)"x";
    197195    pw.pw_uid = 0;
    198     pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */
     196    pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */
    199197
    200198    /* grand finale */
    201     return adduser(&pw, flags);
    202 }
     199    return adduser(&pw);
     200}
  • branches/2.2.5/mindi-busybox/loginutils/deluser.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * deluser (remove lusers from the system ;) for TinyLogin
     3 * deluser/delgroup implementation for busybox
    44 *
    55 * Copyright (C) 1999 by Lineo, inc. and John Beppu
    66 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
    7  * Unified with delgroup by Tito Ragusa <farmatito@tiscali.it>
     7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
    1010 *
    1111 */
    1212
    13 #include <sys/stat.h>
    14 #include <unistd.h>
    15 #include <stdio.h>
    16 #include <stdlib.h>
    17 #include <string.h>
    18 #include "busybox.h"
     13#include "libbb.h"
    1914
    20 /* where to start and stop deletion */
    21 typedef struct {
    22     size_t start;
    23     size_t stop;
    24 } Bounds;
     15/* Status */
     16#define STATUS_OK            0
     17#define NAME_NOT_FOUND       1
     18#define MEMBER_NOT_FOUND     2
    2519
    26 /* An interesting side-effect of boundary()'s
    27  * implementation is that the first user (typically root)
    28  * cannot be removed.  Let's call it a feature. */
    29 static inline Bounds boundary(const char *buffer, const char *login)
     20static void del_line_matching(char **args,
     21        const char *filename,
     22        FILE *(*fopen_func)(const char *fileName, const char *mode))
    3023{
    31     char needle[256];
    32     char *start;
    33     char *stop;
    34     Bounds b;
     24    FILE *passwd;
     25    smallint error = NAME_NOT_FOUND;
     26    char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1];
     27    char *line, *del;
     28    char *new = xzalloc(1);
    3529
    36     snprintf(needle, 256, "\n%s:", login);
    37     needle[255] = 0;
    38     start = strstr(buffer, needle);
    39     if (!start) {
    40         b.start = 0;
    41         b.stop = 0;
    42         return b;
     30    passwd = fopen_func(filename, "r");
     31    if (passwd) {
     32        while ((line = xmalloc_fgets(passwd))) {
     33            int len = strlen(name);
     34
     35            if (strncmp(line, name, len) == 0
     36             && line[len] == ':'
     37            ) {
     38                error = STATUS_OK;
     39                if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) {
     40                    struct group *gr;
     41                    char *p;
     42                    if (args[2]
     43                     /* There were two args on commandline */
     44                     && (gr = getgrnam(name))
     45                     /* The group was not deleted in the meanwhile */
     46                     && (p = strrchr(line, ':'))
     47                     /* We can find a pointer to the last ':' */
     48                    ) {
     49                        error = MEMBER_NOT_FOUND;
     50                        /* Move past ':' (worst case to '\0') and cut the line */
     51                        p[1] = '\0';
     52                        /* Reuse p */
     53                        for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) {
     54                            /* Add all the other group members */
     55                            if (strcmp(args[1], *gr->gr_mem) != 0) {
     56                                del = p;
     57                                p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem);
     58                                free(del);
     59                            } else
     60                                error = STATUS_OK;
     61                        }
     62                        /* Recompose the line */
     63                        line = xasprintf("%s%s\n", line, p);
     64                        if (ENABLE_FEATURE_CLEAN_UP) free(p);
     65                    } else
     66                        goto skip;
     67                }
     68            }
     69            del = new;
     70            new = xasprintf("%s%s", new, line);
     71            free(del);
     72 skip:
     73            free(line);
     74        }
     75
     76        if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd);
     77
     78        if (error) {
     79            if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) {
     80                /* Set the correct values for error message */
     81                filename = name;
     82                name = args[1];
     83            }
     84            bb_error_msg("can't find %s in %s", name, filename);
     85        } else {
     86            passwd = fopen_func(filename, "w");
     87            if (passwd) {
     88                fputs(new, passwd);
     89                if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd);
     90            }
     91        }
    4392    }
    44     start++;
    45 
    46     stop = strchr(start, '\n');
    47     b.start = start - buffer;
    48     b.stop = stop - buffer;
    49     return b;
     93    free(new);
    5094}
    5195
    52 /* grep -v ^login (except it only deletes the first match) */
    53 /* ...in fact, I think I'm going to simplify this later */
    54 static void del_line_matching(const char *login, const char *filename)
    55 {
    56     char *buffer;
    57     FILE *passwd;
    58     Bounds b;
    59     struct stat statbuf;
    60 
    61 
    62     if ((passwd = bb_wfopen(filename, "r"))) {
    63         xstat(filename, &statbuf);
    64         buffer = (char *) xmalloc(statbuf.st_size * sizeof(char));
    65         fread(buffer, statbuf.st_size, sizeof(char), passwd);
    66         fclose(passwd);
    67         /* find the user to remove */
    68         b = boundary(buffer, login);
    69         if (b.stop != 0) {
    70             /* write the file w/o the user */
    71             if ((passwd = bb_wfopen(filename, "w"))) {
    72                 fwrite(buffer, (b.start - 1), sizeof(char), passwd);
    73                 fwrite(&buffer[b.stop], (statbuf.st_size - b.stop), sizeof(char), passwd);
    74                 fclose(passwd);
    75             }
    76         } else {
    77             bb_error_msg("Can't find '%s' in '%s'", login, filename);
    78         }
    79         free(buffer);
    80     }
    81 }
    82 
     96int deluser_main(int argc, char **argv);
    8397int deluser_main(int argc, char **argv)
    8498{
    85     if (argc != 2) {
     99    if (argc == 2
     100     || (ENABLE_FEATURE_DEL_USER_FROM_GROUP
     101        && (applet_name[3] == 'g' && argc == 3))
     102    ) {
     103        if (geteuid())
     104            bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
     105
     106        if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3)
     107         || ENABLE_DELUSER
     108         || (ENABLE_DELGROUP && ENABLE_DESKTOP)
     109        ) {
     110            if (ENABLE_DELUSER
     111             && (!ENABLE_DELGROUP || applet_name[3] == 'u')
     112            ) {
     113                del_line_matching(argv, bb_path_passwd_file, xfopen);
     114                if (ENABLE_FEATURE_SHADOWPASSWDS)
     115                    del_line_matching(argv, bb_path_shadow_file, fopen_or_warn);
     116            } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1]))
     117                bb_error_msg_and_die("can't remove primary group of user %s", argv[1]);
     118        }
     119        del_line_matching(argv, bb_path_group_file, xfopen);
     120        if (ENABLE_FEATURE_SHADOWPASSWDS)
     121            del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn);
     122        return EXIT_SUCCESS;
     123    } else
    86124        bb_show_usage();
    87     } else {
    88         if (ENABLE_DELUSER && bb_applet_name[3] == 'u') {
    89             del_line_matching(argv[1], bb_path_passwd_file);
    90             if (ENABLE_FEATURE_SHADOWPASSWDS)
    91                 del_line_matching(argv[1], bb_path_shadow_file);
    92         }
    93         del_line_matching(argv[1], bb_path_group_file);
    94         if (ENABLE_FEATURE_SHADOWPASSWDS)
    95             del_line_matching(argv[1], bb_path_gshadow_file);
    96     }
    97     return (EXIT_SUCCESS);
    98125}
    99 
    100 /* $Id: deluser.c,v 1.4 2003/07/14 20:20:45 andersen Exp $ */
  • branches/2.2.5/mindi-busybox/loginutils/getty.c

    r902 r1765  
    11/* vi: set sw=4 ts=4: */
    22/* agetty.c - another getty program for Linux. By W. Z. Venema 1989
    3    Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
    4    This program is freely distributable. The entire man-page used to
    5    be here. Now read the real man-page agetty.8 instead.
    6 
    7    -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
    8 
    9    1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
    10    - added Native Language Support
    11 
    12    1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
    13    - enable hardware flow control before displaying /etc/issue
    14 
    15 */
    16 
    17 #include <stdio.h>
    18 #include <stdlib.h>
    19 #include <unistd.h>
    20 #include <string.h>
    21 #include <sys/ioctl.h>
    22 #include <errno.h>
    23 #include <sys/stat.h>
    24 #include <signal.h>
    25 #include <fcntl.h>
    26 #include <stdarg.h>
    27 #include <ctype.h>
    28 #include <getopt.h>
    29 #include <termios.h>
    30 #include "busybox.h"
    31 
    32 #ifdef CONFIG_FEATURE_UTMP
     3 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
     4 * This program is freely distributable. The entire man-page used to
     5 * be here. Now read the real man-page agetty.8 instead.
     6 *
     7 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
     8 *
     9 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
     10 * - added Native Language Support
     11
     12 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
     13 * - enable hardware flow control before displaying /etc/issue
     14 *
     15 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     16 *
     17 */
     18
     19#include "libbb.h"
     20#include <syslog.h>
     21
     22#if ENABLE_FEATURE_UTMP
    3323#include <utmp.h>
    3424#endif
    3525
    36 #define _PATH_LOGIN     "/bin/login"
    37 
    38  /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
    39 #ifdef CONFIG_SYSLOGD
    40 #include <sys/param.h>
    41 #include <syslog.h>
    42 #endif
    43 
    44 
    45  /*
    46   * Some heuristics to find out what environment we are in: if it is not
    47   * System V, assume it is SunOS 4.
    48   */
    49 
     26/*
     27 * Some heuristics to find out what environment we are in: if it is not
     28 * System V, assume it is SunOS 4.
     29 */
    5030#ifdef LOGIN_PROCESS                    /* defined in System V utmp.h */
    5131#define SYSV_STYLE                      /* select System V style getty */
    52 #ifdef CONFIG_FEATURE_WTMP
    53 extern void updwtmp(const char *filename, const struct utmp *ut);
    54 #endif
    55 #endif  /* LOGIN_PROCESS */
    56 
    57  /*
    58   * Things you may want to modify.
    59   *
    60   * You may disagree with the default line-editing etc. characters defined
    61   * below. Note, however, that DEL cannot be used for interrupt generation
    62   * and for line editing at the same time.
    63   */
    64 
    65 #ifdef  SYSV_STYLE
    6632#include <sys/utsname.h>
    6733#include <time.h>
    68 #endif
    69 
    70  /* If ISSUE is not defined, agetty will never display the contents of the
    71   * /etc/issue file. You will not want to spit out large "issue" files at the
    72   * wrong baud rate.
    73   */
     34#if ENABLE_FEATURE_WTMP
     35extern void updwtmp(const char *filename, const struct utmp *ut);
     36static void update_utmp(const char *line);
     37#endif
     38#endif  /* LOGIN_PROCESS */
     39
     40/*
     41 * Things you may want to modify.
     42 *
     43 * You may disagree with the default line-editing etc. characters defined
     44 * below. Note, however, that DEL cannot be used for interrupt generation
     45 * and for line editing at the same time.
     46 */
     47
     48/* I doubt there are systems which still need this */
     49#undef HANDLE_ALLCAPS
     50
     51#define _PATH_LOGIN "/bin/login"
     52
     53/* If ISSUE is not defined, getty will never display the contents of the
     54 * /etc/issue file. You will not want to spit out large "issue" files at the
     55 * wrong baud rate.
     56 */
    7457#define ISSUE "/etc/issue"              /* displayed before the login prompt */
    7558
    7659/* Some shorthands for control characters. */
    77 
    7860#define CTL(x)          (x ^ 0100)      /* Assumes ASCII dialect */
    7961#define CR              CTL('M')        /* carriage return */
     
    8365
    8466/* Defaults for line-editing etc. characters; you may want to change this. */
    85 
    8667#define DEF_ERASE       DEL             /* default erase character */
    8768#define DEF_INTR        CTL('C')        /* default interrupt character */
     
    9273#define DEF_SWITCH      0               /* default switch char */
    9374
    94  /*
    95   * SunOS 4.1.1 termio is broken. We must use the termios stuff instead,
    96   * because the termio -> termios translation does not clear the termios
    97   * CIBAUD bits. Therefore, the tty driver would sometimes report that input
    98   * baud rate != output baud rate. I did not notice that problem with SunOS
    99   * 4.1. We will use termios where available, and termio otherwise.
    100   */
    101 
    102 /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set
    103    properly, but all is well if we use termios?! */
    104 
    105 #ifdef  TCGETS
    106 #undef  TCGETA
    107 #undef  TCSETA
    108 #undef  TCSETAW
    109 #define termio  termios
    110 #define TCGETA  TCGETS
    111 #define TCSETA  TCSETS
    112 #define TCSETAW TCSETSW
    113 #endif
    114 
    115  /*
    116   * When multiple baud rates are specified on the command line, the first one
    117   * we will try is the first one specified.
    118   */
    119 
     75/*
     76 * When multiple baud rates are specified on the command line, the first one
     77 * we will try is the first one specified.
     78 */
    12079#define FIRST_SPEED     0
    12180
     
    12685struct options {
    12786    int flags;                      /* toggle switches, see below */
    128     int timeout;                    /* time-out period */
    129     char *login;                    /* login program */
    130     char *tty;                      /* name of tty */
    131     char *initstring;               /* modem init string */
    132     char *issue;                    /* alternative issue file */
     87    unsigned timeout;               /* time-out period */
     88    const char *login;                    /* login program */
     89    const char *tty;                      /* name of tty */
     90    const char *initstring;               /* modem init string */
     91    const char *issue;                    /* alternative issue file */
    13392    int numspeed;                   /* number of baud rates to try */
    13493    int speeds[MAX_SPEED];          /* baud rates to be tried */
    13594};
    13695
    137 static const char opt_string[] = "I:LH:f:hil:mt:wn";
     96static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
    13897#define F_INITSTRING    (1<<0)          /* initstring is set */
    13998#define F_LOCAL         (1<<1)          /* force local */
     
    149108
    150109/* Storage for things detected while the login name was read. */
    151 
    152110struct chardata {
    153     int erase;                      /* erase character */
    154     int kill;                       /* kill character */
    155     int eol;                        /* end-of-line character */
    156     int parity;                     /* what parity did we see */
    157     int capslock;                   /* upper case without lower case */
     111    unsigned char erase;    /* erase character */
     112    unsigned char kill;     /* kill character */
     113    unsigned char eol;      /* end-of-line character */
     114    unsigned char parity;   /* what parity did we see */
     115#ifdef HANDLE_ALLCAPS
     116    unsigned char capslock; /* upper case without lower case */
     117#endif
    158118};
    159119
    160120/* Initial values for the above. */
    161 
    162 static struct chardata init_chardata = {
     121static const struct chardata init_chardata = {
    163122    DEF_ERASE,                              /* default erase character */
    164123    DEF_KILL,                               /* default kill character */
    165124    13,                                     /* default eol char */
    166125    0,                                      /* space parity */
     126#ifdef HANDLE_ALLCAPS
    167127    0,                                      /* no capslock */
     128#endif
    168129};
    169 
    170 #if 0
    171 struct Speedtab {
    172     long speed;
    173     int code;
    174 };
    175 
    176 static struct Speedtab speedtab[] = {
    177     {50, B50},
    178     {75, B75},
    179     {110, B110},
    180     {134, B134},
    181     {150, B150},
    182     {200, B200},
    183     {300, B300},
    184     {600, B600},
    185     {1200, B1200},
    186     {1800, B1800},
    187     {2400, B2400},
    188     {4800, B4800},
    189     {9600, B9600},
    190 #ifdef  B19200
    191     {19200, B19200},
    192 #endif
    193 #ifdef  B38400
    194     {38400, B38400},
    195 #endif
    196 #ifdef  EXTA
    197     {19200, EXTA},
    198 #endif
    199 #ifdef  EXTB
    200     {38400, EXTB},
    201 #endif
    202 #ifdef B57600
    203     {57600, B57600},
    204 #endif
    205 #ifdef B115200
    206     {115200, B115200},
    207 #endif
    208 #ifdef B230400
    209     {230400, B230400},
    210 #endif
    211     {0, 0},
    212 };
    213 #endif
    214 
    215 
    216 #ifdef  SYSV_STYLE
    217 #ifdef CONFIG_FEATURE_UTMP
    218 static void update_utmp(char *line);
    219 #endif
    220 #endif
    221130
    222131/* The following is used for understandable diagnostics. */
     
    229138#define debug(s) fprintf(dbf,s); fflush(dbf)
    230139#define DEBUGTERM "/dev/ttyp0"
    231 FILE *dbf;
     140static FILE *dbf;
    232141#else
    233 #define debug(s)                                /* nothing */
    234 #endif
    235 
    236 
    237 /*
    238  * output error messages
    239  */
    240 static void error(const char *fmt, ...) ATTRIBUTE_NORETURN;
    241 static void error(const char *fmt, ...)
    242 {
    243     va_list va_alist;
    244     char buf[256];
    245 
    246 #ifdef CONFIG_SYSLOGD
    247     va_start(va_alist, fmt);
    248     vsnprintf(buf, sizeof(buf), fmt, va_alist);
    249     openlog(bb_applet_name, 0, LOG_AUTH);
    250     syslog(LOG_ERR, "%s", buf);
    251     closelog();
    252 #else
    253     int fd;
    254     size_t l;
    255 
    256     snprintf(buf, sizeof(buf), "%s: ", bb_applet_name);
    257     l = strlen(buf);
    258     va_start(va_alist, fmt);
    259     vsnprintf(buf + l, sizeof(buf) - l, fmt, va_alist);
    260     l = strlen(buf);
    261     /* truncate if need */
    262     if((l + 3) > sizeof(buf))
    263         l = sizeof(buf) - 3;
    264     /* add \r\n always */
    265     buf[l++] = '\r';
    266     buf[l++] = '\n';
    267     buf[l] = 0;
    268     if ((fd = open("/dev/console", 1)) >= 0) {
    269         write(fd, buf, l);
    270         close(fd);
    271     }
    272 #endif
    273 
    274     va_end(va_alist);
    275 
    276     (void) sleep((unsigned) 10);    /* be kind to init(8) */
    277     exit(1);
    278 }
    279 
     142#define debug(s) /* nothing */
     143#endif
    280144
    281145
     
    284148{
    285149    int r;
    286     unsigned long value;
    287     if (safe_strtoul((char *)s, &value)) {
     150    unsigned value = bb_strtou(s, NULL, 10);
     151    if (errno) {
    288152        return -1;
    289153    }
    290     if ((r = tty_value_to_baud(value)) > 0) {
     154    r = tty_value_to_baud(value);
     155    if (r > 0) {
    291156        return r;
    292157    }
     
    303168    for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
    304169        if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
    305             error("bad speed: %s", cp);
     170            bb_error_msg_and_die("bad speed: %s", cp);
    306171        if (op->numspeed > MAX_SPEED)
    307             error("too many alternate speeds");
     172            bb_error_msg_and_die("too many alternate speeds");
    308173    }
    309174    debug("exiting parsespeeds\n");
     
    311176
    312177
    313 /* parse-args - parse command-line arguments */
     178/* parse_args - parse command-line arguments */
    314179static void parse_args(int argc, char **argv, struct options *op)
    315180{
    316181    char *ts;
    317182
    318     op->flags = bb_getopt_ulflags(argc, argv, opt_string,
     183    op->flags = getopt32(argv, opt_string,
    319184        &(op->initstring), &fakehost, &(op->issue),
    320185        &(op->login), &ts);
    321     if(op->flags & F_INITSTRING) {
     186    if (op->flags & F_INITSTRING) {
    322187        const char *p = op->initstring;
    323188        char *q;
    324189
    325         q = op->initstring = bb_xstrdup(op->initstring);
     190        op->initstring = q = xstrdup(op->initstring);
    326191        /* copy optarg into op->initstring decoding \ddd
    327192           octal codes into chars */
     
    337202    }
    338203    op->flags ^= F_ISSUE;           /* revert flag show /etc/issue */
    339     if(op->flags & F_TIMEOUT) {
    340         if ((op->timeout = atoi(ts)) <= 0)
    341             error("bad timeout value: %s", ts);
    342     }
     204    if (op->flags & F_TIMEOUT) {
     205        op->timeout = xatoul_range(ts, 1, INT_MAX);
     206    }
     207    argv += optind;
     208    argc -= optind;
    343209    debug("after getopt loop\n");
    344     if (argc < optind + 2)          /* check parameter count */
     210    if (argc < 2)          /* check parameter count */
    345211        bb_show_usage();
    346212
    347213    /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
    348     if ('0' <= argv[optind][0] && argv[optind][0] <= '9') {
     214    if (isdigit(argv[0][0])) {
    349215        /* a number first, assume it's a speed (BSD style) */
    350         parse_speeds(op, argv[optind++]);       /* baud rate(s) */
    351         op->tty = argv[optind]; /* tty name */
     216        parse_speeds(op, argv[0]);       /* baud rate(s) */
     217        op->tty = argv[1]; /* tty name */
    352218    } else {
    353         op->tty = argv[optind++];       /* tty name */
    354         parse_speeds(op, argv[optind]); /* baud rate(s) */
    355     }
    356 
    357     optind++;
    358     if (argc > optind && argv[optind])
    359         setenv("TERM", argv[optind], 1);
     219        op->tty = argv[0];       /* tty name */
     220        parse_speeds(op, argv[1]); /* baud rate(s) */
     221    }
     222
     223    if (argv[2])
     224        setenv("TERM", argv[2], 1);
    360225
    361226    debug("exiting parseargs\n");
     
    363228
    364229/* open_tty - set up tty as standard { input, output, error } */
    365 static void open_tty(char *tty, struct termio *tp, int local)
     230static void open_tty(const char *tty, struct termios *tp, int local)
    366231{
    367232    int chdir_to_root = 0;
    368233
    369234    /* Set up new standard input, unless we are given an already opened port. */
    370 
    371     if (strcmp(tty, "-")) {
     235    if (NOT_LONE_DASH(tty)) {
    372236        struct stat st;
    373237        int fd;
    374238
    375239        /* Sanity checks... */
    376 
    377         if (chdir("/dev"))
    378             error("/dev: chdir() failed: %m");
     240        xchdir("/dev");
    379241        chdir_to_root = 1;
    380         if (stat(tty, &st) < 0)
    381             error("/dev/%s: %m", tty);
     242        xstat(tty, &st);
    382243        if ((st.st_mode & S_IFMT) != S_IFCHR)
    383             error("/dev/%s: not a character device", tty);
     244            bb_error_msg_and_die("%s: not a character device", tty);
    384245
    385246        /* Open the tty as standard input. */
    386 
    387         close(0);
    388247        debug("open(2)\n");
    389         fd = open(tty, O_RDWR | O_NONBLOCK, 0);
    390         if (fd != 0)
    391             error("/dev/%s: cannot open as standard input: %m", tty);
     248        fd = xopen(tty, O_RDWR | O_NONBLOCK);
     249        xdup2(fd, 0);
     250        while (fd > 2)
     251            close(fd--);
    392252    } else {
    393 
    394253        /*
    395254         * Standard input should already be connected to an open port. Make
    396255         * sure it is open for read/write.
    397256         */
    398 
    399         if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR)
    400             error("%s: not open for read/write", tty);
     257        if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR)
     258            bb_error_msg_and_die("stdin is not open for read/write");
    401259    }
    402260
    403261    /* Replace current standard output/error fd's with new ones */
    404262    debug("duping\n");
    405     if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1 ||
    406         dup2(STDIN_FILENO, STDERR_FILENO) == -1)
    407         error("%s: dup problem: %m", tty);      /* we have a problem */
     263    xdup2(0, 1);
     264    xdup2(0, 2);
    408265
    409266    /*
     
    415272     * 5 seconds seems to be a good value.
    416273     */
    417 
    418     if (ioctl(0, TCGETA, tp) < 0)
    419         error("%s: ioctl: %m", tty);
     274    ioctl_or_perror_and_die(0, TCGETS, tp, "%s: TCGETS", tty);
    420275
    421276    /*
     
    427282
    428283#ifdef DEBIAN
     284#warning Debian /dev/vcs[a]NN hack is deprecated and will be removed
    429285    {
    430286        /* tty to root.dialout 660 */
     
    432288        int id;
    433289
    434         id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0;
     290        gr = getgrnam("dialout");
     291        id = gr ? gr->gr_gid : 0;
    435292        chown(tty, 0, id);
    436293        chmod(tty, 0660);
     
    440297            char *vcs, *vcsa;
    441298
    442             if (!(vcs = strdup(tty)))
    443                 error("Can't malloc for vcs");
    444             if (!(vcsa = malloc(strlen(tty) + 2)))
    445                 error("Can't malloc for vcsa");
     299            vcs = xstrdup(tty);
     300            vcsa = xmalloc(strlen(tty) + 2);
    446301            strcpy(vcs, "vcs");
    447302            strcpy(vcs + 3, tty + 3);
     
    449304            strcpy(vcsa + 4, tty + 3);
    450305
    451             id = (gr = getgrnam("sys")) ? gr->gr_gid : 0;
     306            gr = getgrnam("sys");
     307            id = gr ? gr->gr_gid : 0;
    452308            chown(vcs, 0, id);
    453309            chmod(vcs, 0600);
     
    460316    }
    461317#else
    462     (void) chown(tty, 0, 0);        /* root, sys */
    463     (void) chmod(tty, 0622);        /* crw--w--w- */
    464 #endif
    465     if(chdir_to_root && chdir("/"))
    466         error("chdir to / failed: %m");
    467 }
    468 
    469 /* termio_init - initialize termio settings */
    470 static void termio_init(struct termio *tp, int speed, struct options *op)
     318    if (NOT_LONE_DASH(tty)) {
     319        chown(tty, 0, 0);        /* 0:0 */
     320        chmod(tty, 0622);        /* crw--w--w- */
     321    }
     322#endif
     323    if (chdir_to_root)
     324        xchdir("/");
     325}
     326
     327/* termios_init - initialize termios settings */
     328static void termios_init(struct termios *tp, int speed, struct options *op)
    471329{
    472330    /*
    473      * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
     331     * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
    474332     * Special characters are set after we have read the login name; all
    475333     * reads will be done in raw mode anyway. Errors will be dealt with
    476      * lateron.
     334     * later on.
    477335     */
    478336#ifdef __linux__
    479337    /* flush input and output queues, important for modems! */
    480     (void) ioctl(0, TCFLSH, TCIOFLUSH);
     338    ioctl(0, TCFLSH, TCIOFLUSH);
    481339#endif
    482340
     
    498356#endif
    499357
    500     (void) ioctl(0, TCSETA, tp);
     358    ioctl(0, TCSETS, tp);
    501359
    502360    /* go to blocking input even in local mode */
    503     fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK);
     361    ndelay_off(0);
    504362
    505363    debug("term_io 2\n");
     
    507365
    508366/* auto_baud - extract baud rate from modem status message */
    509 static void auto_baud(struct termio *tp)
     367static void auto_baud(char *buf, unsigned size_buf, struct termios *tp)
    510368{
    511369    int speed;
    512370    int vmin;
    513371    unsigned iflag;
    514     char buf[BUFSIZ];
    515372    char *bp;
    516373    int nread;
     
    533390    /*
    534391     * Use 7-bit characters, don't block if input queue is empty. Errors will
    535      * be dealt with lateron.
     392     * be dealt with later on.
    536393     */
    537394
     
    540397    vmin = tp->c_cc[VMIN];
    541398    tp->c_cc[VMIN] = 0;                     /* don't block if queue empty */
    542     (void) ioctl(0, TCSETA, tp);
     399    ioctl(0, TCSETS, tp);
    543400
    544401    /*
     
    547404     */
    548405
    549     (void) sleep(1);
    550     if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
     406    sleep(1);
     407    nread = read(0, buf, size_buf - 1);
     408    if (nread > 0) {
    551409        buf[nread] = '\0';
    552410        for (bp = buf; bp < buf + nread; bp++) {
    553411            if (isascii(*bp) && isdigit(*bp)) {
    554                 if ((speed = bcode(bp))) {
     412                speed = bcode(bp);
     413                if (speed) {
    555414                    tp->c_cflag &= ~CBAUD;
    556415                    tp->c_cflag |= speed;
     
    560419        }
    561420    }
    562     /* Restore terminal settings. Errors will be dealt with lateron. */
     421    /* Restore terminal settings. Errors will be dealt with later on. */
    563422
    564423    tp->c_iflag = iflag;
    565424    tp->c_cc[VMIN] = vmin;
    566     (void) ioctl(0, TCSETA, tp);
     425    ioctl(0, TCSETS, tp);
    567426}
    568427
    569428/* next_speed - select next baud rate */
    570 static void next_speed(struct termio *tp, struct options *op)
     429static void next_speed(struct termios *tp, struct options *op)
    571430{
    572431    static int baud_index = FIRST_SPEED;    /* current speed index */
     
    575434    tp->c_cflag &= ~CBAUD;
    576435    tp->c_cflag |= op->speeds[baud_index];
    577     (void) ioctl(0, TCSETA, tp);
     436    ioctl(0, TCSETS, tp);
    578437}
    579438
    580439
    581440/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
    582 static void do_prompt(struct options *op, struct termio *tp)
    583 {
    584 #ifdef  ISSUE                                   /* optional: show /etc/issue */
     441static void do_prompt(struct options *op, struct termios *tp)
     442{
     443#ifdef ISSUE
    585444    print_login_issue(op->issue, op->tty);
    586445#endif
     
    588447}
    589448
     449#ifdef HANDLE_ALLCAPS
    590450/* caps_lock - string contains upper case without lower case */
    591451/* returns 1 if true, 0 if false */
    592452static int caps_lock(const char *s)
    593453{
    594     int capslock;
    595 
    596     for (capslock = 0; *s; s++) {
    597         if (islower(*s))
    598             return (0);
    599         if (capslock == 0)
    600             capslock = isupper(*s);
    601     }
    602     return (capslock);
    603 }
    604 
    605 #define logname bb_common_bufsiz1
     454    while (*s)
     455        if (islower(*s++))
     456            return 0;
     457    return 1;
     458}
     459#endif
     460
    606461/* get_logname - get user name, establish parity, speed, erase, kill, eol */
    607462/* return NULL on failure, logname on success */
    608 static char *get_logname(struct options *op, struct chardata *cp, struct termio *tp)
     463static char *get_logname(char *logname, unsigned size_logname,
     464        struct options *op, struct chardata *cp, struct termios *tp)
    609465{
    610466    char *bp;
     
    613469    int bits;                       /* # of "1" bits per character */
    614470    int mask;                       /* mask with 1 bit up */
    615     static char *erase[] = {        /* backspace-space-backspace */
     471    static const char erase[][3] = {    /* backspace-space-backspace */
    616472        "\010\040\010",                 /* space parity */
    617473        "\010\040\010",                 /* odd parity */
     
    626482    /* Flush pending input (esp. after parsing or switching the baud rate). */
    627483
    628     (void) sleep(1);
    629     (void) ioctl(0, TCFLSH, TCIFLUSH);
     484    sleep(1);
     485    ioctl(0, TCFLSH, TCIFLUSH);
    630486
    631487    /* Prompt for and read a login name. */
    632488
    633     for (*logname = 0; *logname == 0; /* void */ ) {
     489    logname[0] = '\0';
     490    while (!logname[0]) {
    634491
    635492        /* Write issue file and prompt, with "parity" bit == 0. */
     
    639496        /* Read name, watch for break, parity, erase, kill, end-of-line. */
    640497
    641         for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
     498        bp = logname;
     499        cp->eol = '\0';
     500        while (cp->eol == '\0') {
    642501
    643502            /* Do not report trivial EINTR/EIO errors. */
    644 
    645503            if (read(0, &c, 1) < 1) {
    646504                if (errno == EINTR || errno == EIO)
    647505                    exit(0);
    648                 error("%s: read: %m", op->tty);
     506                bb_perror_msg_and_die("%s: read", op->tty);
    649507            }
     508
    650509            /* Do BREAK handling elsewhere. */
    651 
    652             if ((c == 0) && op->numspeed > 1)
    653                 /* return (0); */
     510            if (c == '\0' && op->numspeed > 1)
    654511                return NULL;
    655512
    656513            /* Do parity bit handling. */
    657 
    658             if (c != (ascval = (c & 0177))) {       /* "parity" bit on ? */
    659                 for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
     514            ascval = c & 0177;
     515            if (c != ascval) {       /* "parity" bit on ? */
     516                bits = 1;
     517                mask = 1;
     518                while (mask & 0177) {
    660519                    if (mask & ascval)
    661520                        bits++; /* count "1" bits */
    662                 cp->parity |= ((bits & 1) ? 1 : 2);
     521                    mask <<= 1;
     522                }
     523                /* ... |= 2 - even, 1 - odd */
     524                cp->parity |= 2 - (bits & 1);
    663525            }
     526
    664527            /* Do erase, kill and end-of-line processing. */
    665 
    666528            switch (ascval) {
    667529            case CR:
    668530            case NL:
    669                 *bp = 0;                /* terminate logname */
     531                *bp = '\0';             /* terminate logname */
    670532                cp->eol = ascval;       /* set end-of-line char */
    671533                break;
     
    675537                cp->erase = ascval;     /* set erase character */
    676538                if (bp > logname) {
    677                     (void) write(1, erase[cp->parity], 3);
     539                    write(1, erase[cp->parity], 3);
    678540                    bp--;
    679541                }
     
    683545                cp->kill = ascval;      /* set kill character */
    684546                while (bp > logname) {
    685                     (void) write(1, erase[cp->parity], 3);
     547                    write(1, erase[cp->parity], 3);
    686548                    bp--;
    687549                }
     
    691553            default:
    692554                if (!isascii(ascval) || !isprint(ascval)) {
    693                     /* ignore garbage characters */ ;
    694                 } else if (bp - logname >= sizeof(logname) - 1) {
    695                     error("%s: input overrun", op->tty);
     555                    /* ignore garbage characters */
     556                } else if (bp - logname >= size_logname - 1) {
     557                    bb_error_msg_and_die("%s: input overrun", op->tty);
    696558                } else {
    697                     (void) write(1, &c, 1); /* echo the character */
     559                    write(1, &c, 1); /* echo the character */
    698560                    *bp++ = ascval; /* and store it */
    699561                }
     
    704566    /* Handle names with upper case and no lower case. */
    705567
    706     if ((cp->capslock = caps_lock(logname))) {
     568#ifdef HANDLE_ALLCAPS
     569    cp->capslock = caps_lock(logname);
     570    if (cp->capslock) {
    707571        for (bp = logname; *bp; bp++)
    708572            if (isupper(*bp))
    709573                *bp = tolower(*bp);     /* map name to lower case */
    710574    }
    711     return (logname);
    712 }
    713 
    714 /* termio_final - set the final tty mode bits */
    715 static void termio_final(struct options *op, struct termio *tp, struct chardata *cp)
     575#endif
     576    return logname;
     577}
     578
     579/* termios_final - set the final tty mode bits */
     580static void termios_final(struct options *op, struct termios *tp, struct chardata *cp)
    716581{
    717582    /* General terminal-independent stuff. */
     
    754619        break;
    755620    }
     621
    756622    /* Account for upper case without lower case. */
    757 
     623#ifdef HANDLE_ALLCAPS
    758624    if (cp->capslock) {
    759625        tp->c_iflag |= IUCLC;
     
    761627        tp->c_oflag |= OLCUC;
    762628    }
     629#endif
    763630    /* Optionally enable hardware flow control */
    764631
     
    770637    /* Finally, make the new settings effective */
    771638
    772     if (ioctl(0, TCSETA, tp) < 0)
    773         error("%s: ioctl: TCSETA: %m", op->tty);
    774 }
    775 
    776 
    777 #ifdef  SYSV_STYLE
    778 #ifdef CONFIG_FEATURE_UTMP
     639    ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty);
     640}
     641
     642
     643#ifdef SYSV_STYLE
     644#if ENABLE_FEATURE_UTMP
    779645/* update_utmp - update our utmp entry */
    780 static void update_utmp(char *line)
     646static void update_utmp(const char *line)
    781647{
    782648    struct utmp ut;
     
    784650    time_t t;
    785651    int mypid = getpid();
    786 #if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))
    787     struct flock lock;
    788 #endif
    789652
    790653    /*
     
    802665    setutent();
    803666    while ((utp = getutent())
    804            && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid))  /* nothing */
    805         ;
     667           && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid))
     668        /* nothing */;
    806669
    807670    if (utp) {
     
    812675        safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
    813676    }
    814     /*endutent(); */
     677    /* endutent(); */
    815678
    816679    strcpy(ut.ut_user, "LOGIN");
     
    826689    endutent();
    827690
    828 #ifdef CONFIG_FEATURE_WTMP
     691#if ENABLE_FEATURE_WTMP
    829692    if (access(bb_path_wtmp_file, R_OK|W_OK) == -1)
    830693        close(creat(bb_path_wtmp_file, 0664));
     
    837700
    838701
    839 #undef logname
     702int getty_main(int argc, char **argv);
    840703int getty_main(int argc, char **argv)
    841704{
     705    int nullfd;
    842706    char *logname = NULL;           /* login name, given to /bin/login */
     707    /* Merging these into "struct local" may _seem_ to reduce
     708     * parameter passing, but today's gcc will inline
     709     * statics which are called once anyway, so don't do that */
    843710    struct chardata chardata;       /* set by get_logname() */
    844     struct termio termio;           /* terminal mode bits */
    845     static struct options options = {
     711    struct termios termios;           /* terminal mode bits */
     712    struct options options = {
    846713        0,                      /* show /etc/issue (SYSV_STYLE) */
    847714        0,                      /* no timeout */
     
    857724    };
    858725
     726    /* Already too late because of theoretical
     727     * possibility of getty --help somehow triggered
     728     * inadvertently before we reach this. Oh well. */
     729    logmode = LOGMODE_NONE;
     730    setsid();
     731    nullfd = xopen(bb_dev_null, O_RDWR);
     732    /* dup2(nullfd, 0); - no, because of possible "getty - 9600" */
     733    /* open_tty() will take care of fd# 0 anyway */
     734    dup2(nullfd, 1);
     735    dup2(nullfd, 2);
     736    while (nullfd > 2) close(nullfd--);
     737    /* We want special flavor of error_msg_and_die */
     738    die_sleep = 10;
     739    msg_eol = "\r\n";
     740    openlog(applet_name, LOG_PID, LOG_AUTH);
     741    logmode = LOGMODE_BOTH;
     742
    859743#ifdef DEBUGGING
    860     dbf = bb_xfopen(DEBUGTERM, "w");
     744    dbf = xfopen(DEBUGTERM, "w");
    861745
    862746    {
     
    871755
    872756    /* Parse command-line arguments. */
    873 
    874757    parse_args(argc, argv, &options);
    875758
    876 #ifdef __linux__
    877     setsid();
    878 #endif
    879 
     759#ifdef SYSV_STYLE
     760#if ENABLE_FEATURE_UTMP
    880761    /* Update the utmp file. */
    881 
    882 
    883 #ifdef  SYSV_STYLE
    884 #ifdef CONFIG_FEATURE_UTMP
    885762    update_utmp(options.tty);
    886763#endif
     
    889766    debug("calling open_tty\n");
    890767    /* Open the tty as standard { input, output, error }. */
    891     open_tty(options.tty, &termio, options.flags & F_LOCAL);
     768    open_tty(options.tty, &termios, options.flags & F_LOCAL);
    892769
    893770#ifdef __linux__
     
    899776    }
    900777#endif
    901     /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
    902     debug("calling termio_init\n");
    903     termio_init(&termio, options.speeds[FIRST_SPEED], &options);
     778    /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
     779    debug("calling termios_init\n");
     780    termios_init(&termios, options.speeds[FIRST_SPEED], &options);
    904781
    905782    /* write the modem init string and DON'T flush the buffers */
     
    911788    if (!(options.flags & F_LOCAL)) {
    912789        /* go to blocking write mode unless -L is specified */
    913         fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK);
     790        ndelay_off(1);
    914791    }
    915792
     
    917794    debug("before autobaud\n");
    918795    if (options.flags & F_PARSE)
    919         auto_baud(&termio);
     796        auto_baud(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), &termios);
    920797
    921798    /* Set the optional timer. */
    922799    if (options.timeout)
    923         (void) alarm((unsigned) options.timeout);
     800        alarm(options.timeout);
    924801
    925802    /* optionally wait for CR or LF before writing /etc/issue */
     
    942819        /* Read the login name. */
    943820        debug("reading login name\n");
    944         /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */
    945         while ((logname = get_logname(&options, &chardata, &termio)) ==
    946                NULL) next_speed(&termio, &options);
     821        logname = get_logname(bb_common_bufsiz1, sizeof(bb_common_bufsiz1),
     822                &options, &chardata, &termios);
     823        while (logname == NULL)
     824            next_speed(&termios, &options);
    947825    }
    948826
     
    950828
    951829    if (options.timeout)
    952         (void) alarm(0);
    953 
    954     /* Finalize the termio settings. */
    955 
    956     termio_final(&options, &termio, &chardata);
     830        alarm(0);
     831
     832    /* Finalize the termios settings. */
     833
     834    termios_final(&options, &termios, &chardata);
    957835
    958836    /* Now the newline character should be properly written. */
    959837
    960     (void) write(1, "\n", 1);
     838    write(1, "\n", 1);
    961839
    962840    /* Let the login program take care of password validation. */
    963841
    964     (void) execl(options.login, options.login, "--", logname, (char *) 0);
    965     error("%s: can't exec %s: %m", options.tty, options.login);
    966 }
    967 
     842    execl(options.login, options.login, "--", logname, (char *) 0);
     843    bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login);
     844}
  • branches/2.2.5/mindi-busybox/loginutils/login.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
    2 #include <fcntl.h>
    3 #include <signal.h>
    4 #include <stdio.h>
    5 #include <stdlib.h>
    6 #include <string.h>
    7 #include <syslog.h>
    8 #include <termios.h>
    9 #include <unistd.h>
     2/*
     3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     4 */
     5
     6#include "libbb.h"
    107#include <utmp.h>
    118#include <sys/resource.h>
    12 #include <sys/stat.h>
    13 #include <sys/types.h>
    14 #include <ctype.h>
    15 #include <time.h>
    16 
    17 #include "busybox.h"
    18 #ifdef CONFIG_SELINUX
     9#include <syslog.h>
     10
     11#if ENABLE_SELINUX
    1912#include <selinux/selinux.h>  /* for is_selinux_enabled()  */
    2013#include <selinux/get_context_list.h> /* for get_default_context() */
    2114#include <selinux/flask.h> /* for security class definitions  */
    22 #include <errno.h>
    23 #endif
    24 
    25 #ifdef CONFIG_FEATURE_UTMP
    26 // import from utmp.c
    27 static void checkutmp(int picky);
    28 static void setutmp(const char *name, const char *line);
    29 /* Stuff global to this file */
    30 static struct utmp utent;
    31 #endif
    32 
    33 // login defines
    34 #define TIMEOUT       60
    35 #define EMPTY_USERNAME_COUNT    10
    36 #define USERNAME_SIZE 32
    37 
    38 
    39 static int check_nologin ( int amroot );
    40 
    41 #if defined CONFIG_FEATURE_SECURETTY
    42 static int check_tty ( const char *tty );
    43 
    44 #else
    45 static inline int check_tty ( const char *tty )  { return 1; }
    46 
    47 #endif
    48 
    49 static int is_my_tty ( const char *tty );
    50 static int login_prompt ( char *buf_name );
    51 static void motd ( void );
    52 
    53 
    54 static void alarm_handler ( int sig ATTRIBUTE_UNUSED)
    55 {
    56     fprintf (stderr, "\nLogin timed out after %d seconds.\n", TIMEOUT );
    57     exit ( EXIT_SUCCESS );
    58 }
    59 
    60 
    61 int login_main(int argc, char **argv)
    62 {
    63     char tty[BUFSIZ];
    64     char full_tty[200];
    65     char fromhost[512];
    66     char username[USERNAME_SIZE];
    67     const char *tmp;
    68     int amroot;
    69     int flag;
    70     int failed;
    71     int count=0;
    72     struct passwd *pw, pw_copy;
    73 #ifdef CONFIG_WHEEL_GROUP
    74     struct group *grp;
    75 #endif
    76     int opt_preserve = 0;
    77     int opt_fflag = 0;
    78     char *opt_host = 0;
    79     int alarmstarted = 0;
    80 #ifdef CONFIG_SELINUX
    81     security_context_t user_sid = NULL;
    82 #endif
    83 
    84     username[0]=0;
    85     amroot = ( getuid ( ) == 0 );
    86     signal ( SIGALRM, alarm_handler );
    87     alarm ( TIMEOUT );
    88     alarmstarted = 1;
    89 
    90     while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
    91         switch ( flag ) {
    92         case 'p':
    93             opt_preserve = 1;
    94             break;
    95         case 'f':
    96             /*
    97              * username must be a separate token
    98              * (-f root, *NOT* -froot). --marekm
    99              */
    100             if ( optarg != argv[optind-1] )
    101                 bb_show_usage( );
    102 
    103             if ( !amroot )      /* Auth bypass only if real UID is zero */
    104                 bb_error_msg_and_die ( "-f permission denied" );
    105 
    106             safe_strncpy(username, optarg, USERNAME_SIZE);
    107             opt_fflag = 1;
    108             break;
    109         case 'h':
    110             opt_host = optarg;
    111             break;
    112         default:
    113             bb_show_usage( );
    114         }
    115     }
    116 
    117     if (optind < argc)             // user from command line (getty)
    118         safe_strncpy(username, argv[optind], USERNAME_SIZE);
    119 
    120     if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
    121         return EXIT_FAILURE;        /* Must be a terminal */
    122 
    123 #ifdef CONFIG_FEATURE_UTMP
    124     checkutmp ( !amroot );
    125 #endif
    126 
    127     tmp = ttyname ( 0 );
    128     if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
    129         safe_strncpy ( tty, tmp + 5, sizeof( tty ));
    130     else if ( tmp && *tmp == '/' )
    131         safe_strncpy ( tty, tmp, sizeof( tty ));
    132     else
    133         safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));
    134 
    135 #ifdef CONFIG_FEATURE_UTMP
    136     if ( amroot )
    137         memset ( utent.ut_host, 0, sizeof utent.ut_host );
    138 #endif
    139 
    140     if ( opt_host ) {
    141 #ifdef CONFIG_FEATURE_UTMP
    142         safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
    143 #endif
    144         snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
    145     }
    146     else
    147         snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );
    148 
    149     bb_setpgrp;
    150 
    151     openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );
    152 
    153     while ( 1 ) {
    154         failed = 0;
    155 
    156         if ( !username[0] )
    157             if(!login_prompt ( username ))
    158                 return EXIT_FAILURE;
    159 
    160         if ( !alarmstarted && ( TIMEOUT > 0 )) {
    161             alarm ( TIMEOUT );
    162             alarmstarted = 1;
    163         }
    164 
    165         if (!( pw = getpwnam ( username ))) {
    166             pw_copy.pw_name   = "UNKNOWN";
    167             pw_copy.pw_passwd = "!";
    168             opt_fflag = 0;
    169             failed = 1;
    170         } else
    171             pw_copy = *pw;
    172 
    173         pw = &pw_copy;
    174 
    175         if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
    176             failed = 1;
    177 
    178         if ( opt_fflag ) {
    179             opt_fflag = 0;
    180             goto auth_ok;
    181         }
    182 
    183         if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty )))
    184             failed = 1;
    185 
    186         /* Don't check the password if password entry is empty (!) */
    187         if ( !pw-> pw_passwd[0] )
    188             goto auth_ok;
    189 
    190         /* authorization takes place here */
    191         if ( correct_password ( pw ))
    192             goto auth_ok;
    193 
    194         failed = 1;
    195 
    196 auth_ok:
    197         if ( !failed)
    198             break;
    199 
    200         bb_do_delay(FAIL_DELAY);
    201         puts("Login incorrect");
    202         username[0] = 0;
    203         if ( ++count == 3 ) {
    204             syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost);
    205             return EXIT_FAILURE;
    206     }
    207     }
    208 
    209     alarm ( 0 );
    210     if ( check_nologin ( pw-> pw_uid == 0 ))
    211         return EXIT_FAILURE;
    212 
    213 #ifdef CONFIG_FEATURE_UTMP
    214     setutmp ( username, tty );
    215 #endif
    216 
    217     if ( *tty != '/' )
    218         snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
    219     else
    220         safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
    221 
    222 #ifdef CONFIG_SELINUX
    223     if (is_selinux_enabled())
    224     {
    225         security_context_t old_tty_sid, new_tty_sid;
    226 
    227         if (get_default_context(username, NULL, &user_sid))
    228         {
    229             fprintf(stderr, "Unable to get SID for %s\n", username);
    230             exit(1);
    231         }
    232         if (getfilecon(full_tty, &old_tty_sid) < 0)
    233         {
    234             fprintf(stderr, "getfilecon(%.100s) failed: %.100s\n", full_tty, strerror(errno));
    235             return EXIT_FAILURE;
    236         }
    237         if (security_compute_relabel(user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
    238         {
    239             fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
    240             return EXIT_FAILURE;
    241         }
    242         if(setfilecon(full_tty, new_tty_sid) != 0)
    243         {
    244             fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
    245             return EXIT_FAILURE;
    246         }
    247     }
    248 #endif
    249     if ( !is_my_tty ( full_tty ))
    250         syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
    251 
    252     /* Try these, but don't complain if they fail
    253      * (for example when the root fs is read only) */
    254     chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
    255     chmod ( full_tty, 0600 );
    256 
    257     change_identity ( pw );
    258     tmp = pw-> pw_shell;
    259     if(!tmp || !*tmp)
    260         tmp = DEFAULT_SHELL;
    261     setup_environment ( tmp, 1, !opt_preserve, pw );
    262 
    263     motd ( );
    264     signal ( SIGALRM, SIG_DFL );    /* default alarm signal */
    265 
    266     if ( pw-> pw_uid == 0 )
    267         syslog ( LOG_INFO, "root login %s\n", fromhost );
    268 #ifdef CONFIG_SELINUX
    269     /* well, a simple setexeccon() here would do the job as well,
    270      * but let's play the game for now */
    271     set_current_security_context(user_sid);
    272 #endif
    273     run_shell ( tmp, 1, 0, 0);  /* exec the shell finally. */
    274 
    275     return EXIT_FAILURE;
    276 }
    277 
    278 
    279 
    280 static int login_prompt ( char *buf_name )
    281 {
    282     char buf [1024];
    283     char *sp, *ep;
    284     int i;
    285 
    286     for(i=0; i<EMPTY_USERNAME_COUNT; i++) {
    287         print_login_prompt();
    288 
    289         if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
    290             return 0;
    291 
    292         if ( !strchr ( buf, '\n' ))
    293             return 0;
    294 
    295         for ( sp = buf; isspace ( *sp ); sp++ ) { }
    296         for ( ep = sp; isgraph ( *ep ); ep++ ) { }
    297 
    298         *ep = 0;
    299         safe_strncpy(buf_name, sp, USERNAME_SIZE);
    300         if(buf_name[0])
    301             return 1;
    302     }
    303     return 0;
    304 }
    305 
    306 
    307 static int check_nologin ( int amroot )
    308 {
    309     if ( access ( bb_path_nologin_file, F_OK ) == 0 ) {
    310         FILE *fp;
    311         int c;
    312 
    313         if (( fp = fopen ( bb_path_nologin_file, "r" ))) {
    314             while (( c = getc ( fp )) != EOF )
    315                 putchar (( c == '\n' ) ? '\r' : c );
    316 
    317             fflush ( stdout );
    318             fclose ( fp );
    319         } else {
    320             puts ( "\r\nSystem closed for routine maintenance.\r" );
    321         }
    322         if ( !amroot )
    323             return 1;
    324 
    325         puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" );
    326     }
    327     return 0;
    328 }
    329 
    330 #ifdef CONFIG_FEATURE_SECURETTY
    331 
    332 static int check_tty ( const char *tty )
    333 {
    334     FILE *fp;
    335     int i;
    336     char buf[BUFSIZ];
    337 
    338     if (( fp = fopen ( bb_path_securetty_file, "r" ))) {
    339         while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
    340             for ( i = strlen( buf ) - 1; i >= 0; --i ) {
    341                 if ( !isspace ( buf[i] ))
    342                     break;
    343             }
    344             buf[++i] = '\0';
    345             if (( buf [0] == '\0' ) || ( buf [0] == '#' ))
    346                 continue;
    347 
    348             if ( strcmp ( buf, tty ) == 0 ) {
    349                 fclose ( fp );
    350                 return 1;
    351             }
    352         }
    353         fclose(fp);
    354         return 0;
    355     }
    356     /* A missing securetty file is not an error. */
    357     return 1;
    358 }
    359 
    360 #endif
    361 
    362 /* returns 1 if true */
    363 static int is_my_tty ( const char *tty )
    364 {
    365     struct stat by_name, by_fd;
    366 
    367     if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd ))
    368         return 0;
    369 
    370     if ( by_name. st_rdev != by_fd. st_rdev )
    371         return 0;
    372     else
    373         return 1;
    374 }
    375 
    376 
    377 static void motd (void)
    378 {
    379     FILE *fp;
    380     register int c;
    381 
    382     if (( fp = fopen ( bb_path_motd_file, "r" ))) {
    383         while (( c = getc ( fp )) != EOF )
    384             putchar ( c );
    385         fclose ( fp );
    386     }
    387 }
    388 
    389 
    390 #ifdef CONFIG_FEATURE_UTMP
    391 // vv  Taken from tinylogin utmp.c  vv
    392 
    393 #define NO_UTENT \
    394     "No utmp entry.  You must exec \"login\" from the lowest level \"sh\""
    395 #define NO_TTY \
    396     "Unable to determine your tty name."
    397 
     15#endif
     16
     17#if ENABLE_PAM
     18/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
     19#undef setlocale
     20/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
     21 * Apparently they like to confuse people. */
     22#include <security/pam_appl.h>
     23#include <security/pam_misc.h>
     24static const struct pam_conv conv = {
     25    misc_conv,
     26    NULL
     27};
     28#endif
     29
     30enum {
     31    TIMEOUT = 60,
     32    EMPTY_USERNAME_COUNT = 10,
     33    USERNAME_SIZE = 32,
     34    TTYNAME_SIZE = 32,
     35};
     36
     37static char* short_tty;
     38
     39#if ENABLE_FEATURE_UTMP
     40/* vv  Taken from tinylogin utmp.c  vv */
    39841/*
    399  * checkutmp - see if utmp file is correct for this process
     42 * read_or_build_utent - see if utmp file is correct for this process
    40043 *
    40144 *  System V is very picky about the contents of the utmp file
     
    41053 */
    41154
    412 static void checkutmp(int picky)
    413 {
    414     char *line;
     55static void read_or_build_utent(struct utmp *utptr, int picky)
     56{
    41557    struct utmp *ut;
    41658    pid_t pid = getpid();
     
    42163    while ((ut = getutent()))
    42264        if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
    423             (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
     65        (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
    42466            break;
    42567
    42668    /* If there is one, just use it, otherwise create a new one.  */
    42769    if (ut) {
    428         utent = *ut;
     70        *utptr = *ut;
    42971    } else {
    430         time_t t_tmp;
    431        
    432         if (picky) {
    433             puts(NO_UTENT);
    434             exit(1);
    435         }
    436         line = ttyname(0);
    437         if (!line) {
    438             puts(NO_TTY);
    439             exit(1);
    440         }
    441         if (strncmp(line, "/dev/", 5) == 0)
    442             line += 5;
    443         memset((void *) &utent, 0, sizeof utent);
    444         utent.ut_type = LOGIN_PROCESS;
    445         utent.ut_pid = pid;
    446         strncpy(utent.ut_line, line, sizeof utent.ut_line);
    447         /* XXX - assumes /dev/tty?? */
    448         strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
    449         strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user);
    450         t_tmp = (time_t)utent.ut_time;
    451         time(&t_tmp);
    452     }
     72        if (picky)
     73            bb_error_msg_and_die("no utmp entry found");
     74
     75        memset(utptr, 0, sizeof(*utptr));
     76        utptr->ut_type = LOGIN_PROCESS;
     77        utptr->ut_pid = pid;
     78        strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
     79        /* This one is only 4 chars wide. Try to fit something
     80         * remotely meaningful by skipping "tty"... */
     81        strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
     82        strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
     83        utptr->ut_time = time(NULL);
     84    }
     85    if (!picky) /* root login */
     86        memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
    45387}
    45488
    45589/*
    456  * setutmp - put a USER_PROCESS entry in the utmp file
     90 * write_utent - put a USER_PROCESS entry in the utmp file
    45791 *
    458  *  setutmp changes the type of the current utmp entry to
     92 *  write_utent changes the type of the current utmp entry to
    45993 *  USER_PROCESS.  the wtmp file will be updated as well.
    46094 */
    461 
    462 static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED)
    463 {
    464     time_t t_tmp = (time_t)utent.ut_time;
    465 
    466     utent.ut_type = USER_PROCESS;
    467     strncpy(utent.ut_user, name, sizeof utent.ut_user);
    468     time(&t_tmp);
    469     /* other fields already filled in by checkutmp above */
     95static void write_utent(struct utmp *utptr, const char *username)
     96{
     97    utptr->ut_type = USER_PROCESS;
     98    strncpy(utptr->ut_user, username, sizeof(utptr->ut_user));
     99    utptr->ut_time = time(NULL);
     100    /* other fields already filled in by read_or_build_utent above */
    470101    setutent();
    471     pututline(&utent);
     102    pututline(utptr);
    472103    endutent();
    473 #ifdef CONFIG_FEATURE_WTMP
     104#if ENABLE_FEATURE_WTMP
    474105    if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
    475106        close(creat(bb_path_wtmp_file, 0664));
    476107    }
    477     updwtmp(bb_path_wtmp_file, &utent);
    478 #endif
    479 }
    480 #endif /* CONFIG_FEATURE_UTMP */
     108    updwtmp(bb_path_wtmp_file, utptr);
     109#endif
     110}
     111#else /* !ENABLE_FEATURE_UTMP */
     112#define read_or_build_utent(utptr, picky) ((void)0)
     113#define write_utent(utptr, username) ((void)0)
     114#endif /* !ENABLE_FEATURE_UTMP */
     115
     116#if ENABLE_FEATURE_NOLOGIN
     117static void die_if_nologin_and_non_root(int amroot)
     118{
     119    FILE *fp;
     120    int c;
     121
     122    if (access("/etc/nologin", F_OK))
     123        return;
     124
     125    fp = fopen("/etc/nologin", "r");
     126    if (fp) {
     127        while ((c = getc(fp)) != EOF)
     128            putchar((c=='\n') ? '\r' : c);
     129        fflush(stdout);
     130        fclose(fp);
     131    } else
     132        puts("\r\nSystem closed for routine maintenance\r");
     133    if (!amroot)
     134        exit(1);
     135    puts("\r\n[Disconnect bypassed -- root login allowed]\r");
     136}
     137#else
     138static ALWAYS_INLINE void die_if_nologin_and_non_root(int amroot) {}
     139#endif
     140
     141#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
     142static int check_securetty(void)
     143{
     144    FILE *fp;
     145    int i;
     146    char buf[256];
     147
     148    fp = fopen("/etc/securetty", "r");
     149    if (!fp) {
     150        /* A missing securetty file is not an error. */
     151        return 1;
     152    }
     153    while (fgets(buf, sizeof(buf)-1, fp)) {
     154        for (i = strlen(buf)-1; i >= 0; --i) {
     155            if (!isspace(buf[i]))
     156                break;
     157        }
     158        buf[++i] = '\0';
     159        if (!buf[0] || (buf[0] == '#'))
     160            continue;
     161        if (strcmp(buf, short_tty) == 0) {
     162            fclose(fp);
     163            return 1;
     164        }
     165    }
     166    fclose(fp);
     167    return 0;
     168}
     169#else
     170static ALWAYS_INLINE int check_securetty(void) { return 1; }
     171#endif
     172
     173static void get_username_or_die(char *buf, int size_buf)
     174{
     175    int c, cntdown;
     176
     177    cntdown = EMPTY_USERNAME_COUNT;
     178 prompt:
     179    print_login_prompt();
     180    /* skip whitespace */
     181    do {
     182        c = getchar();
     183        if (c == EOF) exit(1);
     184        if (c == '\n') {
     185            if (!--cntdown) exit(1);
     186            goto prompt;
     187        }
     188    } while (isspace(c));
     189
     190    *buf++ = c;
     191    if (!fgets(buf, size_buf-2, stdin))
     192        exit(1);
     193    if (!strchr(buf, '\n'))
     194        exit(1);
     195    while (isgraph(*buf)) buf++;
     196    *buf = '\0';
     197}
     198
     199static void motd(void)
     200{
     201    int fd;
     202
     203    fd = open(bb_path_motd_file, O_RDONLY);
     204    if (fd) {
     205        fflush(stdout);
     206        bb_copyfd_eof(fd, STDOUT_FILENO);
     207        close(fd);
     208    }
     209}
     210
     211static void alarm_handler(int sig ATTRIBUTE_UNUSED)
     212{
     213    /* This is the escape hatch!  Poor serial line users and the like
     214     * arrive here when their connection is broken.
     215     * We don't want to block here */
     216    ndelay_on(1);
     217    ndelay_on(2);
     218    printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
     219    exit(EXIT_SUCCESS);
     220}
     221
     222int login_main(int argc, char **argv);
     223int login_main(int argc, char **argv)
     224{
     225    enum {
     226        LOGIN_OPT_f = (1<<0),
     227        LOGIN_OPT_h = (1<<1),
     228        LOGIN_OPT_p = (1<<2),
     229    };
     230    char *fromhost;
     231    char username[USERNAME_SIZE];
     232    const char *tmp;
     233    int amroot;
     234    unsigned opt;
     235    int count = 0;
     236    struct passwd *pw;
     237    char *opt_host = NULL;
     238    char *opt_user = NULL;
     239    char full_tty[TTYNAME_SIZE];
     240    USE_SELINUX(security_context_t user_sid = NULL;)
     241    USE_FEATURE_UTMP(struct utmp utent;)
     242    USE_PAM(pam_handle_t *pamh;)
     243    USE_PAM(int pamret;)
     244    USE_PAM(const char *failed_msg;)
     245
     246    short_tty = full_tty;
     247    username[0] = '\0';
     248    amroot = (getuid() == 0);
     249    signal(SIGALRM, alarm_handler);
     250    alarm(TIMEOUT);
     251
     252    /* Mandatory paranoia for suid applet:
     253     * ensure that fd# 0,1,2 are opened (at least to /dev/null)
     254     * and any extra open fd's are closed.
     255     * (The name of the function is misleading. Not daemonizing here.) */
     256    bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
     257
     258    opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
     259    if (opt & LOGIN_OPT_f) {
     260        if (!amroot)
     261            bb_error_msg_and_die("-f is for root only");
     262        safe_strncpy(username, opt_user, sizeof(username));
     263    }
     264    if (optind < argc) /* user from command line (getty) */
     265        safe_strncpy(username, argv[optind], sizeof(username));
     266
     267    /* Let's find out and memorize our tty */
     268    if (!isatty(0) || !isatty(1) || !isatty(2))
     269        return EXIT_FAILURE;        /* Must be a terminal */
     270    safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty));
     271    tmp = ttyname(0);
     272    if (tmp) {
     273        safe_strncpy(full_tty, tmp, sizeof(full_tty));
     274        if (strncmp(full_tty, "/dev/", 5) == 0)
     275            short_tty = full_tty + 5;
     276    }
     277
     278    read_or_build_utent(&utent, !amroot);
     279
     280    if (opt_host) {
     281        USE_FEATURE_UTMP(
     282            safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
     283        )
     284        fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
     285    } else
     286        fromhost = xasprintf(" on '%s'", short_tty);
     287
     288    /* Was breaking "login <username>" from shell command line: */
     289    /*bb_setpgrp();*/
     290
     291    openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
     292
     293    while (1) {
     294        if (!username[0])
     295            get_username_or_die(username, sizeof(username));
     296
     297#if ENABLE_PAM
     298        pamret = pam_start("login", username, &conv, &pamh);
     299        if (pamret != PAM_SUCCESS) {
     300            failed_msg = "pam_start";
     301            goto pam_auth_failed;
     302        }
     303        /* set TTY (so things like securetty work) */
     304        pamret = pam_set_item(pamh, PAM_TTY, short_tty);
     305        if (pamret != PAM_SUCCESS) {
     306            failed_msg = "pam_set_item(TTY)";
     307            goto pam_auth_failed;
     308        }
     309        pamret = pam_authenticate(pamh, 0);
     310        if (pamret != PAM_SUCCESS) {
     311            failed_msg = "pam_authenticate";
     312            goto pam_auth_failed;
     313            /* TODO: or just "goto auth_failed"
     314             * since user seems to enter wrong password
     315             * (in this case pamret == 7)
     316             */
     317        }
     318        /* check that the account is healthy */
     319        pamret = pam_acct_mgmt(pamh, 0);
     320        if (pamret != PAM_SUCCESS) {
     321            failed_msg = "account setup";
     322            goto pam_auth_failed;
     323        }
     324        /* read user back */
     325        {
     326            const char *pamuser;
     327            /* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
     328             * thus we cast to (void*) */
     329            if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
     330                failed_msg = "pam_get_item(USER)";
     331                goto pam_auth_failed;
     332            }
     333            safe_strncpy(username, pamuser, sizeof(username));
     334        }
     335        /* If we get here, the user was authenticated, and is
     336         * granted access. */
     337        pw = getpwnam(username);
     338        if (pw)
     339            break;
     340        goto auth_failed;
     341 pam_auth_failed:
     342        bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret);
     343        safe_strncpy(username, "UNKNOWN", sizeof(username));
     344#else /* not PAM */
     345        pw = getpwnam(username);
     346        if (!pw) {
     347            strcpy(username, "UNKNOWN");
     348            goto fake_it;
     349        }
     350
     351        if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
     352            goto auth_failed;
     353
     354        if (opt & LOGIN_OPT_f)
     355            break; /* -f USER: success without asking passwd */
     356
     357        if (pw->pw_uid == 0 && !check_securetty())
     358            goto auth_failed;
     359
     360        /* Don't check the password if password entry is empty (!) */
     361        if (!pw->pw_passwd[0])
     362            break;
     363 fake_it:
     364        /* authorization takes place here */
     365        if (correct_password(pw))
     366            break;
     367#endif /* ENABLE_PAM */
     368 auth_failed:
     369        opt &= ~LOGIN_OPT_f;
     370        bb_do_delay(FAIL_DELAY);
     371        /* TODO: doesn't sound like correct English phrase to me */
     372        puts("Login incorrect");
     373        if (++count == 3) {
     374            syslog(LOG_WARNING, "invalid password for '%s'%s",
     375                        username, fromhost);
     376            return EXIT_FAILURE;
     377        }
     378        username[0] = '\0';
     379    }
     380
     381    alarm(0);
     382    die_if_nologin_and_non_root(pw->pw_uid == 0);
     383
     384    write_utent(&utent, username);
     385
     386#if ENABLE_SELINUX
     387    if (is_selinux_enabled()) {
     388        security_context_t old_tty_sid, new_tty_sid;
     389
     390        if (get_default_context(username, NULL, &user_sid)) {
     391            bb_error_msg_and_die("cannot get SID for %s",
     392                    username);
     393        }
     394        if (getfilecon(full_tty, &old_tty_sid) < 0) {
     395            bb_perror_msg_and_die("getfilecon(%s) failed",
     396                    full_tty);
     397        }
     398        if (security_compute_relabel(user_sid, old_tty_sid,
     399                    SECCLASS_CHR_FILE, &new_tty_sid) != 0) {
     400            bb_perror_msg_and_die("security_change_sid(%s) failed",
     401                    full_tty);
     402        }
     403        if (setfilecon(full_tty, new_tty_sid) != 0) {
     404            bb_perror_msg_and_die("chsid(%s, %s) failed",
     405                    full_tty, new_tty_sid);
     406        }
     407    }
     408#endif
     409    /* Try these, but don't complain if they fail.
     410     * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */
     411    fchown(0, pw->pw_uid, pw->pw_gid);
     412    fchmod(0, 0600);
     413
     414    if (ENABLE_LOGIN_SCRIPTS) {
     415        char *t_argv[2];
     416
     417        t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");
     418        if (t_argv[0]) {
     419            t_argv[1] = NULL;
     420            xsetenv("LOGIN_TTY", full_tty);
     421            xsetenv("LOGIN_USER", pw->pw_name);
     422            xsetenv("LOGIN_UID", utoa(pw->pw_uid));
     423            xsetenv("LOGIN_GID", utoa(pw->pw_gid));
     424            xsetenv("LOGIN_SHELL", pw->pw_shell);
     425            xspawn(t_argv); /* NOMMU-friendly */
     426            /* All variables are unset by setup_environment */
     427            wait(NULL);
     428        }
     429    }
     430
     431    change_identity(pw);
     432    tmp = pw->pw_shell;
     433    if (!tmp || !*tmp)
     434        tmp = DEFAULT_SHELL;
     435    /* setup_environment params: shell, loginshell, changeenv, pw */
     436    setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw);
     437    /* FIXME: login shell = 1 -> 3rd parameter is ignored! */
     438
     439    motd();
     440
     441    if (pw->pw_uid == 0)
     442        syslog(LOG_INFO, "root login%s", fromhost);
     443#if ENABLE_SELINUX
     444    /* well, a simple setexeccon() here would do the job as well,
     445     * but let's play the game for now */
     446    set_current_security_context(user_sid);
     447#endif
     448
     449    // util-linux login also does:
     450    // /* start new session */
     451    // setsid();
     452    // /* TIOCSCTTY: steal tty from other process group */
     453    // if (ioctl(0, TIOCSCTTY, 1)) error_msg...
     454    // BBox login used to do this (see above):
     455    // bb_setpgrp();
     456    // If this stuff is really needed, add it and explain why!
     457
     458    /* set signals to defaults */
     459    signal(SIGALRM, SIG_DFL);
     460    /* Is this correct? This way user can ctrl-c out of /etc/profile,
     461     * potentially creating security breach (tested with bash 3.0).
     462     * But without this, bash 3.0 will not enable ctrl-c either.
     463     * Maybe bash is buggy?
     464     * Need to find out what standards say about /bin/login -
     465     * should it leave SIGINT etc enabled or disabled? */
     466    signal(SIGINT, SIG_DFL);
     467
     468    /* Exec login shell with no additional parameters */
     469    run_shell(tmp, 1, NULL, NULL);
     470
     471    /* return EXIT_FAILURE; - not reached */
     472}
  • branches/2.2.5/mindi-busybox/loginutils/passwd.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
    2 #include <fcntl.h>
    3 #include <stdio.h>
    4 #include <string.h>
    5 #include <signal.h>
    6 #include <sys/stat.h>
    7 #include <sys/types.h>
    8 #include <unistd.h>
    9 #include <utime.h>
     2/*
     3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     4 */
     5
     6#include "libbb.h"
    107#include <syslog.h>
    11 #include <time.h>
    12 #include <sys/resource.h>
    13 #include <errno.h>
    14 
    15 #include "busybox.h"
    16 
    17 static char crypt_passwd[128];
    18 
    19 static int create_backup(const char *backup, FILE * fp);
    20 static int new_password(const struct passwd *pw, int amroot, int algo);
    21 static void set_filesize_limit(int blocks);
    22 
    23 
    24 static int get_algo(char *a)
     8
     9
     10static void nuke_str(char *str)
    2511{
    26     int x = 1;                  /* standard: MD5 */
    27 
    28     if (strcasecmp(a, "des") == 0)
    29         x = 0;
    30     return x;
     12    if (str) memset(str, 0, strlen(str));
    3113}
    3214
    33 
    34 static int update_passwd(const struct passwd *pw, const char *crypt_pw)
     15static char* new_password(const struct passwd *pw, uid_t myuid, int algo)
    3516{
    36     char filename[1024];
    37     char buf[1025];
    38     char buffer[80];
    39     char username[32];
    40     char *pw_rest;
    41     int mask;
    42     int continued;
    43     FILE *fp;
    44     FILE *out_fp;
    45     struct stat sb;
    46     struct flock lock;
    47 
    48 #if ENABLE_FEATURE_SHADOWPASSWDS
    49     if (access(bb_path_shadow_file, F_OK) == 0) {
    50         snprintf(filename, sizeof filename, "%s", bb_path_shadow_file);
    51     } else
    52 #endif
    53     {
    54         snprintf(filename, sizeof filename, "%s", bb_path_passwd_file);
    55     }
    56 
    57     if (((fp = fopen(filename, "r+")) == 0) || (fstat(fileno(fp), &sb))) {
    58         /* return 0; */
    59         return 1;
    60     }
    61 
    62     /* Lock the password file before updating */
    63     lock.l_type = F_WRLCK;
    64     lock.l_whence = SEEK_SET;
    65     lock.l_start = 0;
    66     lock.l_len = 0;
    67     if (fcntl(fileno(fp), F_SETLK, &lock) < 0) {
    68         fprintf(stderr, "%s: %s\n", filename, strerror(errno));
    69         return 1;
    70     }
    71     lock.l_type = F_UNLCK;
    72 
    73     snprintf(buf, sizeof buf, "%s-", filename);
    74     if (create_backup(buf, fp)) {
    75         fcntl(fileno(fp), F_SETLK, &lock);
    76         fclose(fp);
    77         return 1;
    78     }
    79     snprintf(buf, sizeof buf, "%s+", filename);
    80     mask = umask(0777);
    81     out_fp = fopen(buf, "w");
    82     umask(mask);
    83     if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777))
    84         || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) {
    85         fcntl(fileno(fp), F_SETLK, &lock);
    86         fclose(fp);
    87         fclose(out_fp);
    88         return 1;
    89     }
    90 
    91     continued = 0;
    92     snprintf(username, sizeof username, "%s:", pw->pw_name);
    93     rewind(fp);
    94     while (!feof(fp)) {
    95         fgets(buffer, sizeof buffer, fp);
    96         if (!continued) { /* Check to see if we're updating this line.  */
    97             if (strncmp(username, buffer, strlen(username)) == 0) {
    98                 /* we have a match. */
    99                 pw_rest = strchr(buffer, ':');
    100                 *pw_rest++ = '\0';
    101                 pw_rest = strchr(pw_rest, ':');
    102                 fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest);
    103             } else {
    104                 fputs(buffer, out_fp);
    105             }
    106         } else {
    107             fputs(buffer, out_fp);
     17    char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
     18    char *orig = (char*)"";
     19    char *newp = NULL;
     20    char *cipher = NULL;
     21    char *cp = NULL;
     22    char *ret = NULL; /* failure so far */
     23
     24    if (myuid && pw->pw_passwd[0]) {
     25        orig = bb_askpass(0, "Old password:"); /* returns ptr to static */
     26        if (!orig)
     27            goto err_ret;
     28        cipher = pw_encrypt(orig, pw->pw_passwd); /* returns ptr to static */
     29        if (strcmp(cipher, pw->pw_passwd) != 0) {
     30            syslog(LOG_WARNING, "incorrect password for '%s'",
     31                pw->pw_name);
     32            bb_do_delay(FAIL_DELAY);
     33            puts("Incorrect password");
     34            goto err_ret;
    10835        }
    109         if (buffer[strlen(buffer) - 1] == '\n') {
    110             continued = 0;
    111         } else {
    112             continued = 1;
    113         }
    114         memset(buffer, 0, sizeof buffer);
    115     }
    116 
    117     if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) {
    118         unlink(buf);
    119         fcntl(fileno(fp), F_SETLK, &lock);
    120         fclose(fp);
    121         return 1;
    122     }
    123     if (rename(buf, filename) < 0) {
    124         fcntl(fileno(fp), F_SETLK, &lock);
    125         fclose(fp);
    126         return 1;
    127     } else {
    128         fcntl(fileno(fp), F_SETLK, &lock);
    129         fclose(fp);
    130         return 0;
    131     }
     36    }
     37    orig = xstrdup(orig); /* or else bb_askpass() will destroy it */
     38    newp = bb_askpass(0, "New password:"); /* returns ptr to static */
     39    if (!newp)
     40        goto err_ret;
     41    newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */
     42    if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
     43     && obscure(orig, newp, pw) && myuid)
     44        goto err_ret; /* non-root is not allowed to have weak passwd */
     45
     46    cp = bb_askpass(0, "Retype password:");
     47    if (!cp)
     48        goto err_ret;
     49    if (strcmp(cp, newp)) {
     50        puts("Passwords don't match");
     51        goto err_ret;
     52    }
     53
     54    crypt_make_salt(salt, 1, 0); /* des */
     55    if (algo) { /* MD5 */
     56        strcpy(salt, "$1$");
     57        crypt_make_salt(salt + 3, 4, 0);
     58    }
     59    /* pw_encrypt returns ptr to static */
     60    ret = xstrdup(pw_encrypt(newp, salt));
     61    /* whee, success! */
     62
     63 err_ret:
     64    nuke_str(orig);
     65    if (ENABLE_FEATURE_CLEAN_UP) free(orig);
     66    nuke_str(newp);
     67    if (ENABLE_FEATURE_CLEAN_UP) free(newp);
     68    nuke_str(cipher);
     69    nuke_str(cp);
     70    return ret;
    13271}
    13372
    134 
     73int passwd_main(int argc, char **argv);
    13574int passwd_main(int argc, char **argv)
    13675{
    137     int amroot;
    138     char *cp;
    139     char *np;
     76    enum {
     77        OPT_algo = 0x1, /* -a - password algorithm */
     78        OPT_lock = 0x2, /* -l - lock account */
     79        OPT_unlock = 0x4, /* -u - unlock account */
     80        OPT_delete = 0x8, /* -d - delete password */
     81        OPT_lud = 0xe,
     82        STATE_ALGO_md5 = 0x10,
     83        //STATE_ALGO_des = 0x20, not needed yet
     84    };
     85    unsigned opt;
     86    int rc;
     87    const char *opt_a = "";
     88    const char *filename;
     89    char *myname;
    14090    char *name;
    141     char *myname;
    142     int flag;
    143     int algo = 1;               /* -a - password algorithm */
    144     int lflg = 0;               /* -l - lock account */
    145     int uflg = 0;               /* -u - unlock account */
    146     int dflg = 0;               /* -d - delete password */
    147     const struct passwd *pw;
     91    char *newp;
     92    struct passwd *pw;
     93    uid_t myuid;
     94    struct rlimit rlimit_fsize;
     95    char c;
    14896
    14997#if ENABLE_FEATURE_SHADOWPASSWDS
    150     const struct spwd *sp;
     98    /* Using _r function to avoid pulling in static buffers */
     99    struct spwd spw;
     100    struct spwd *result;
     101    char buffer[256];
    151102#endif
    152     amroot = (getuid() == 0);
    153     openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
    154     while ((flag = getopt(argc, argv, "a:dlu")) != EOF) {
    155         switch (flag) {
    156         case 'a':
    157             algo = get_algo(optarg);
    158             break;
    159         case 'd':
    160             dflg++;
    161             break;
    162         case 'l':
    163             lflg++;
    164             break;
    165         case 'u':
    166             uflg++;
    167             break;
    168         default:
    169             bb_show_usage();
    170         }
    171     }
    172     myname = (char *) bb_xstrdup(bb_getpwuid(NULL, getuid(), -1));
    173     /* exits on error */
    174     if (optind < argc) {
    175         name = argv[optind];
     103
     104    logmode = LOGMODE_BOTH;
     105    openlog(applet_name, LOG_NOWAIT, LOG_AUTH);
     106    opt = getopt32(argv, "a:lud", &opt_a);
     107    //argc -= optind;
     108    argv += optind;
     109
     110    if (strcasecmp(opt_a, "des") != 0) /* -a */
     111        opt |= STATE_ALGO_md5;
     112    //else
     113    //  opt |= STATE_ALGO_des;
     114    myuid = getuid();
     115    /* -l, -u, -d require root priv and username argument */
     116    if ((opt & OPT_lud) && (myuid || !argv[0]))
     117        bb_show_usage();
     118
     119    /* Will complain and die if username not found */
     120    myname = xstrdup(bb_getpwuid(NULL, -1, myuid));
     121    name = argv[0] ? argv[0] : myname;
     122
     123    pw = getpwnam(name);
     124    if (!pw) bb_error_msg_and_die("unknown user %s", name);
     125    if (myuid && pw->pw_uid != myuid) {
     126        /* LOGMODE_BOTH */
     127        bb_error_msg_and_die("%s can't change password for %s", myname, name);
     128    }
     129
     130#if ENABLE_FEATURE_SHADOWPASSWDS
     131    /* getspnam_r() can lie! Even if user isn't in shadow, it can
     132     * return success (pwd field was seen set to "!" in this case) */
     133    if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result)
     134     || LONE_CHAR(spw.sp_pwdp, '!')) {
     135        /* LOGMODE_BOTH */
     136        bb_error_msg("no record of %s in %s, using %s",
     137                name, bb_path_shadow_file,
     138                bb_path_passwd_file);
    176139    } else {
    177         name = myname;
    178     }
    179     if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) {
    180         bb_show_usage();
    181     }
    182     pw = getpwnam(name);
    183     if (!pw) {
    184         bb_error_msg_and_die("Unknown user %s\n", name);
    185     }
    186     if (!amroot && pw->pw_uid != getuid()) {
    187         syslog(LOG_WARNING, "can't change pwd for `%s'", name);
    188         bb_error_msg_and_die("Permission denied.\n");
    189     }
    190 #if ENABLE_FEATURE_SHADOWPASSWDS
    191     sp = getspnam(name);
    192     if (!sp) {
    193         sp = (struct spwd *) pwd_to_spwd(pw);
    194     }
    195     cp = sp->sp_pwdp;
    196     np = sp->sp_namp;
    197 #else
    198     cp = pw->pw_passwd;
    199     np = name;
     140        pw->pw_passwd = spw.sp_pwdp;
     141    }
    200142#endif
    201143
    202     safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
    203     if (!(dflg || lflg || uflg)) {
    204         if (!amroot) {
    205             if (cp[0] == '!') {
    206                 syslog(LOG_WARNING, "password locked for `%s'", np);
    207                 bb_error_msg_and_die( "The password for `%s' cannot be changed.\n", np);
    208             }
     144    /* Decide what the new password will be */
     145    newp = NULL;
     146    c = pw->pw_passwd[0] - '!';
     147    if (!(opt & OPT_lud)) {
     148        if (myuid && !c) { /* passwd starts with '!' */
     149            /* LOGMODE_BOTH */
     150            bb_error_msg_and_die("cannot change "
     151                    "locked password for %s", name);
    209152        }
    210153        printf("Changing password for %s\n", name);
    211         if (new_password(pw, amroot, algo)) {
    212             bb_error_msg_and_die( "The password for %s is unchanged.\n", name);
     154        newp = new_password(pw, myuid, opt & STATE_ALGO_md5);
     155        if (!newp) {
     156            logmode = LOGMODE_STDIO;
     157            bb_error_msg_and_die("password for %s is unchanged", name);
    213158        }
    214     } else if (lflg) {
    215         if (crypt_passwd[0] != '!') {
    216             memmove(&crypt_passwd[1], crypt_passwd,
    217                     sizeof crypt_passwd - 1);
    218             crypt_passwd[sizeof crypt_passwd - 1] = '\0';
    219             crypt_passwd[0] = '!';
    220         }
    221     } else if (uflg) {
    222         if (crypt_passwd[0] == '!') {
    223             memmove(crypt_passwd, &crypt_passwd[1],
    224                     sizeof crypt_passwd - 1);
    225         }
    226     } else if (dflg) {
    227         crypt_passwd[0] = '\0';
    228     }
    229     set_filesize_limit(30000);
     159    } else if (opt & OPT_lock) {
     160        if (!c) goto skip; /* passwd starts with '!' */
     161        newp = xasprintf("!%s", pw->pw_passwd);
     162    } else if (opt & OPT_unlock) {
     163        if (c) goto skip; /* not '!' */
     164        /* pw->pw_passwd pints to static storage,
     165         * strdup'ing to avoid nasty surprizes */
     166        newp = xstrdup(&pw->pw_passwd[1]);
     167    } else if (opt & OPT_delete) {
     168        //newp = xstrdup("");
     169        newp = (char*)"";
     170    }
     171
     172    rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
     173    setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
    230174    signal(SIGHUP, SIG_IGN);
    231175    signal(SIGINT, SIG_IGN);
     
    233177    umask(077);
    234178    xsetuid(0);
    235     if (!update_passwd(pw, crypt_passwd)) {
    236         syslog(LOG_INFO, "password for `%s' changed by user `%s'", name,
    237                myname);
    238         printf("Password changed.\n");
    239     } else {
    240         syslog(LOG_WARNING, "an error occurred updating the password file");
    241         bb_error_msg_and_die("An error occurred updating the password file.\n");
    242     }
    243     return (0);
    244 }
    245 
    246 
    247 
    248 static int create_backup(const char *backup, FILE * fp)
    249 {
    250     struct stat sb;
    251     struct utimbuf ub;
    252     FILE *bkfp;
    253     int c, mask;
    254 
    255     if (fstat(fileno(fp), &sb))
    256         /* return -1; */
    257         return 1;
    258 
    259     mask = umask(077);
    260     bkfp = fopen(backup, "w");
    261     umask(mask);
    262     if (!bkfp)
    263         /* return -1; */
    264         return 1;
    265 
    266     /* TODO: faster copy, not one-char-at-a-time.  --marekm */
    267     rewind(fp);
    268     while ((c = getc(fp)) != EOF) {
    269         if (putc(c, bkfp) == EOF)
    270             break;
    271     }
    272     if (c != EOF || fflush(bkfp)) {
    273         fclose(bkfp);
    274         /* return -1; */
    275         return 1;
    276     }
    277     if (fclose(bkfp))
    278         /* return -1; */
    279         return 1;
    280 
    281     ub.actime = sb.st_atime;
    282     ub.modtime = sb.st_mtime;
    283     utime(backup, &ub);
     179
     180#if ENABLE_FEATURE_SHADOWPASSWDS
     181    filename = bb_path_shadow_file;
     182    rc = update_passwd(bb_path_shadow_file, name, newp);
     183    if (rc == 0) /* no lines updated, no errors detected */
     184#endif
     185    {
     186        filename = bb_path_passwd_file;
     187        rc = update_passwd(bb_path_passwd_file, name, newp);
     188    }
     189    /* LOGMODE_BOTH */
     190    if (rc < 0)
     191        bb_error_msg_and_die("cannot update password file %s",
     192                filename);
     193    bb_info_msg("Password for %s changed by %s", name, myname);
     194
     195    //if (ENABLE_FEATURE_CLEAN_UP) free(newp);
     196 skip:
     197    if (!newp) {
     198        bb_error_msg_and_die("password for %s is already %slocked",
     199            name, (opt & OPT_unlock) ? "un" : "");
     200    }
     201    if (ENABLE_FEATURE_CLEAN_UP) free(myname);
    284202    return 0;
    285203}
    286 
    287 static int i64c(int i)
    288 {
    289     if (i <= 0)
    290         return ('.');
    291     if (i == 1)
    292         return ('/');
    293     if (i >= 2 && i < 12)
    294         return ('0' - 2 + i);
    295     if (i >= 12 && i < 38)
    296         return ('A' - 12 + i);
    297     if (i >= 38 && i < 63)
    298         return ('a' - 38 + i);
    299     return ('z');
    300 }
    301 
    302 static char *crypt_make_salt(void)
    303 {
    304     time_t now;
    305     static unsigned long x;
    306     static char result[3];
    307 
    308     time(&now);
    309     x += now + getpid() + clock();
    310     result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
    311     result[1] = i64c(((x >> 12) ^ x) & 077);
    312     result[2] = '\0';
    313     return result;
    314 }
    315 
    316 
    317 static int new_password(const struct passwd *pw, int amroot, int algo)
    318 {
    319     char *clear;
    320     char *cipher;
    321     char *cp;
    322     char salt[12]; /* "$N$XXXXXXXX" or "XX" */
    323     char orig[200];
    324     char pass[200];
    325 
    326     if (!amroot && crypt_passwd[0]) {
    327         if (!(clear = bb_askpass(0, "Old password:"))) {
    328             /* return -1; */
    329             return 1;
    330         }
    331         cipher = pw_encrypt(clear, crypt_passwd);
    332         if (strcmp(cipher, crypt_passwd) != 0) {
    333             syslog(LOG_WARNING, "incorrect password for `%s'",
    334                    pw->pw_name);
    335             bb_do_delay(FAIL_DELAY);
    336             fprintf(stderr, "Incorrect password.\n");
    337             /* return -1; */
    338             return 1;
    339         }
    340         safe_strncpy(orig, clear, sizeof(orig));
    341         memset(clear, 0, strlen(clear));
    342         memset(cipher, 0, strlen(cipher));
    343     } else {
    344         orig[0] = '\0';
    345     }
    346     if (! (cp=bb_askpass(0, "Enter the new password (minimum of 5, maximum of 8 characters)\n"
    347                       "Please use a combination of upper and lower case letters and numbers.\n"
    348                       "Enter new password: ")))
    349     {
    350         memset(orig, 0, sizeof orig);
    351         /* return -1; */
    352         return 1;
    353     }
    354     safe_strncpy(pass, cp, sizeof(pass));
    355     memset(cp, 0, strlen(cp));
    356     /* if (!obscure(orig, pass, pw)) { */
    357     if (obscure(orig, pass, pw)) {
    358         if (amroot) {
    359             printf("\nWarning: weak password (continuing).\n");
    360         } else {
    361             /* return -1; */
    362             return 1;
    363         }
    364     }
    365     if (!(cp = bb_askpass(0, "Re-enter new password: "))) {
    366         memset(orig, 0, sizeof orig);
    367         /* return -1; */
    368         return 1;
    369     }
    370     if (strcmp(cp, pass)) {
    371         fprintf(stderr, "Passwords do not match.\n");
    372         /* return -1; */
    373         return 1;
    374     }
    375     memset(cp, 0, strlen(cp));
    376     memset(orig, 0, sizeof(orig));
    377     memset(salt, 0, sizeof(salt));
    378 
    379     if (algo == 1) {
    380         strcpy(salt, "$1$");
    381         strcat(salt, crypt_make_salt());
    382         strcat(salt, crypt_make_salt());
    383         strcat(salt, crypt_make_salt());
    384     }
    385 
    386     strcat(salt, crypt_make_salt());
    387     cp = pw_encrypt(pass, salt);
    388 
    389     memset(pass, 0, sizeof pass);
    390     safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
    391     return 0;
    392 }
    393 
    394 static void set_filesize_limit(int blocks)
    395 {
    396     struct rlimit rlimit_fsize;
    397 
    398     rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
    399     setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
    400 }
  • branches/2.2.5/mindi-busybox/loginutils/su.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
    22/*
    3    Licensed under the GPL v2, see the file LICENSE in this tarball.
    4 */
     3 *  Mini su implementation for busybox
     4 *
     5 *  Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     6 */
    57
    6 #include <fcntl.h>
    7 #include <signal.h>
    8 #include <stdio.h>
    9 #include <stdlib.h>
    10 #include <string.h>
     8#include "libbb.h"
    119#include <syslog.h>
    12 #include <termios.h>
    13 #include <unistd.h>
    14 #include <utmp.h>
    15 #include <sys/resource.h>
    16 #include <sys/stat.h>
    17 #include <sys/types.h>
    18 #include <ctype.h>
    19 #include <time.h>
    2010
    21 #include "busybox.h"
     11#define SU_OPT_mp (3)
     12#define SU_OPT_l (4)
    2213
    23 /* The shell to run if none is given in the user's passwd entry.  */
    24 #ifndef DEFAULT_SHELL
    25 #define DEFAULT_SHELL "/bin/sh"
    26 #endif
    27 
    28 /* Default user.  */
    29 #define DEFAULT_USER  "root"
    30 
    31 /* #define SYSLOG_SUCCESS */
    32 #define SYSLOG_FAILURE
    33 
    34 
    35 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
    36 /* Log the fact that someone has run su */
    37 
    38 # if defined( SYSLOG_SUCCESS ) && defined( SYSLOG_FAILURE )
    39 static void log_su (const char *successful, const char *old_user,
    40                     const char *tty)
     14int su_main(int argc, char **argv);
     15int su_main(int argc, char **argv)
    4116{
    42     syslog ( LOG_NOTICE, "%s%s on %s", successful, old_user, tty);
    43 }
    44 #  define log_su_successful(cu, u, tty) if(!cu) log_su("", u, tty)
    45 #  define log_su_failure(cu, u, tty)    if(!cu) log_su("FAILED SU ", u, tty)
    46 # else
    47     /* partial logging */
    48 #  if !defined( SYSLOG_SUCESS )
    49 #   define log_su_successful(cu, u, tty)
    50 #   define log_su_failure(cu, u, t) if(!cu) \
    51             syslog(LOG_NOTICE, "FAILED SU %s on %s", u, t)
    52 #  else
    53 #   define log_su_successful(cu, u, t) if(!cu) \
    54             syslog(LOG_NOTICE, "%s on %s", u, t)
    55 #   define log_su_failure(cu, u, tty)
    56 #  endif
    57 # endif
    58 #else
    59     /* logging not used */
    60 # define log_su_successful(cu, u, tty)
    61 # define log_su_failure(cu, u, tty)
    62 #endif
    63 
    64 
    65 int su_main ( int argc, char **argv )
    66 {
    67     unsigned long flags;
    68     char *opt_shell = 0;
    69     char *opt_command = 0;
    70     char *opt_username = DEFAULT_USER;
    71     char **opt_args = 0;
     17    unsigned flags;
     18    char *opt_shell = NULL;
     19    char *opt_command = NULL;
     20    const char *opt_username = "root";
    7221    struct passwd *pw;
    7322    uid_t cur_uid = getuid();
     23    const char *tty;
     24    char *old_user;
    7425
    75 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
    76     const char *tty;
    77     const char *old_user;
    78 #endif
     26    flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
     27    argc -= optind;
     28    argv += optind;
    7929
    80     flags = bb_getopt_ulflags(argc, argv, "mplc:s:",
    81                           &opt_command, &opt_shell);
    82 #define SU_OPT_m (3)
    83 #define SU_OPT_p (3)
    84 #define SU_OPT_l (4)
    85 
    86     if (optind < argc  && argv[optind][0] == '-' && argv[optind][1] == 0) {
     30    if (argc && LONE_DASH(argv[0])) {
    8731        flags |= SU_OPT_l;
    88         ++optind;
    89     }
     32        argc--;
     33        argv++;
     34    }
    9035
    9136    /* get user if specified */
    92     if ( optind < argc )
    93         opt_username = argv [optind++];
     37    if (argc) {
     38        opt_username = argv[0];
     39//      argc--;
     40        argv++;
     41    }
    9442
    95     if ( optind < argc )
    96         opt_args = argv + optind;
     43    if (ENABLE_FEATURE_SU_SYSLOG) {
     44        /* The utmp entry (via getlogin) is probably the best way to identify
     45        the user, especially if someone su's from a su-shell.
     46        But getlogin can fail -- usually due to lack of utmp entry.
     47        in this case resort to getpwuid.  */
     48        old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : "");
     49        tty = ttyname(2) ? : "none";
     50        openlog(applet_name, 0, LOG_AUTH);
     51    }
    9752
    98 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
    99 #ifdef CONFIG_FEATURE_UTMP
    100     /* The utmp entry (via getlogin) is probably the best way to identify
    101        the user, especially if someone su's from a su-shell.  */
    102     old_user = getlogin ( );
    103     if ( !old_user )
    104 #endif
    105         {
    106         /* getlogin can fail -- usually due to lack of utmp entry.
    107            Resort to getpwuid.  */
    108         pw = getpwuid ( cur_uid );
    109         old_user = ( pw ? pw->pw_name : "" );
    110     }
    111     tty = ttyname ( 2 );
    112     if(!tty)
    113         tty = "none";
    114 
    115     openlog ( bb_applet_name, 0, LOG_AUTH );
    116 #endif
    117 
    118     pw = getpwnam ( opt_username );
    119     if ( !pw )
    120         bb_error_msg_and_die ( "user %s does not exist", opt_username );
     53    pw = getpwnam(opt_username);
     54    if (!pw)
     55        bb_error_msg_and_die("unknown id: %s", opt_username);
    12156
    12257    /* Make sure pw->pw_shell is non-NULL.  It may be NULL when NEW_USER
    12358       is a username that is retrieved via NIS (YP), but that doesn't have
    12459       a default shell listed.  */
    125     if ( !pw->pw_shell || !pw->pw_shell [0] )
    126         pw->pw_shell = (char *) DEFAULT_SHELL;
     60    if (!pw->pw_shell || !pw->pw_shell[0])
     61        pw->pw_shell = (char *)DEFAULT_SHELL;
    12762
    128     if ((( cur_uid == 0 ) || correct_password ( pw ))) {
    129         log_su_successful(pw->pw_uid, old_user, tty );
     63    if ((cur_uid == 0) || correct_password(pw)) {
     64        if (ENABLE_FEATURE_SU_SYSLOG)
     65            syslog(LOG_NOTICE, "%c %s %s:%s",
     66                '+', tty, old_user, opt_username);
    13067    } else {
    131         log_su_failure (pw->pw_uid, old_user, tty );
    132         bb_error_msg_and_die ( "incorrect password" );
     68        if (ENABLE_FEATURE_SU_SYSLOG)
     69            syslog(LOG_NOTICE, "%c %s %s:%s",
     70                '-', tty, old_user, opt_username);
     71        bb_error_msg_and_die("incorrect password");
    13372    }
    13473
    135 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
    136     closelog();
    137 #endif
     74    if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) {
     75        closelog();
     76        free(old_user);
     77    }
    13878
    139     if ( !opt_shell && (flags & SU_OPT_p))
    140         opt_shell = getenv ( "SHELL" );
     79    if (!opt_shell && (flags & SU_OPT_mp))
     80        opt_shell = getenv("SHELL");
    14181
    142     if ( opt_shell && cur_uid && restricted_shell ( pw->pw_shell )) {
     82#if ENABLE_FEATURE_SU_CHECKS_SHELLS
     83    if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) {
    14384        /* The user being su'd to has a nonstandard shell, and so is
    14485           probably a uucp account or has restricted access.  Don't
    14586           compromise the account by allowing access with a standard
    14687           shell.  */
    147         fputs ( "using restricted shell\n", stderr );
     88        bb_error_msg("using restricted shell");
    14889        opt_shell = 0;
    14990    }
    150 
    151     if ( !opt_shell )
     91#endif
     92    if (!opt_shell)
    15293        opt_shell = pw->pw_shell;
    15394
    154     change_identity ( pw );
    155     setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_p), pw);
    156 #if ENABLE_SELINUX
    157        set_current_security_context(NULL);
    158 #endif
    159     run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)opt_args);
     95    change_identity(pw);
     96    setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw);
     97    USE_SELINUX(set_current_security_context(NULL);)
     98
     99    /* Never returns */
     100    run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
    160101
    161102    return EXIT_FAILURE;
  • branches/2.2.5/mindi-busybox/loginutils/sulogin.c

    r902 r1765  
    11/* vi: set sw=4 ts=4: */
    2 #include <fcntl.h>
    3 #include <signal.h>
    4 #include <stdio.h>
    5 #include <stdlib.h>
    6 #include <string.h>
     2/*
     3 * Mini sulogin implementation for busybox
     4 *
     5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 */
     7
    78#include <syslog.h>
    8 #include <unistd.h>
    9 #include <utmp.h>
    10 #include <sys/resource.h>
    11 #include <sys/stat.h>
    12 #include <sys/types.h>
    13 #include <ctype.h>
    14 #include <time.h>
    159
    16 #include "busybox.h"
     10#include "libbb.h"
    1711
    18 
    19 #define SULOGIN_PROMPT "\nGive root password for system maintenance\n" \
    20     "(or type Control-D for normal startup):"
    21 
    22 static const char * const forbid[] = {
     12static const char *const forbid[] = {
    2313    "ENV",
    2414    "BASH_ENV",
     
    3929
    4030
    41 
    4231static void catchalarm(int ATTRIBUTE_UNUSED junk)
    4332{
     
    4635
    4736
     37int sulogin_main(int argc, char **argv);
    4838int sulogin_main(int argc, char **argv)
    4939{
    5040    char *cp;
    51     char *device = NULL;
    52     const char *name = "root";
    5341    int timeout = 0;
    54 
    55 #define pass bb_common_bufsiz1
    56 
    57     struct passwd pwent;
     42    char *timeout_arg;
     43    const char *const *p;
    5844    struct passwd *pwd;
    59     const char * const *p;
     45    const char *shell;
    6046#if ENABLE_FEATURE_SHADOWPASSWDS
    61     struct spwd *spwd = NULL;
     47    /* Using _r function to avoid pulling in static buffers */
     48    char buffer[256];
     49    struct spwd spw;
     50    struct spwd *result;
    6251#endif
    6352
    64     openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
    65     if (argc > 1) {
    66         if (strncmp(argv[1], "-t", 2) == 0) {
    67             if (argv[1][2] == '\0') { /* -t NN */
    68                 if (argc > 2) {
    69                     timeout = atoi(argv[2]);
    70                     if (argc > 3) {
    71                         device = argv[3];
    72                     }
    73                 }
    74             } else { /* -tNNN */
    75                 timeout = atoi(&argv[1][2]);
    76                 if (argc > 2) {
    77                     device = argv[2];
    78                 }
    79             }
    80         } else {
    81             device = argv[1];
    82         }
    83         if (device) {
    84             close(0);
    85             close(1);
    86             close(2);
    87             if (open(device, O_RDWR) == 0) {
    88                 dup(0);
    89                 dup(0);
    90             } else {
    91                 syslog(LOG_WARNING, "cannot open %s\n", device);
    92                 exit(EXIT_FAILURE);
    93             }
    94         }
    95     }
    96     if (access(bb_path_passwd_file, 0) == -1) {
    97         syslog(LOG_WARNING, "No password file\n");
    98         bb_error_msg_and_die("No password file\n");
    99     }
    100     if (!isatty(0) || !isatty(1) || !isatty(2)) {
    101         exit(EXIT_FAILURE);
     53    logmode = LOGMODE_BOTH;
     54    openlog(applet_name, 0, LOG_AUTH);
     55
     56    if (getopt32(argv, "t:", &timeout_arg)) {
     57        timeout = xatoi_u(timeout_arg);
    10258    }
    10359
     60    if (argv[optind]) {
     61        close(0);
     62        close(1);
     63        dup(xopen(argv[optind], O_RDWR));
     64        close(2);
     65        dup(0);
     66    }
     67
     68    if (!isatty(0) || !isatty(1) || !isatty(2)) {
     69        logmode = LOGMODE_SYSLOG;
     70        bb_error_msg_and_die("not a tty");
     71    }
    10472
    10573    /* Clear out anything dangerous from the environment */
     
    10775        unsetenv(*p);
    10876
     77    signal(SIGALRM, catchalarm);
    10978
    110     signal(SIGALRM, catchalarm);
    111     if (!(pwd = getpwnam(name))) {
    112         syslog(LOG_WARNING, "No password entry for `root'\n");
    113         bb_error_msg_and_die("No password entry for `root'\n");
     79    pwd = getpwuid(0);
     80    if (!pwd) {
     81        goto auth_error;
    11482    }
    115     pwent = *pwd;
     83
    11684#if ENABLE_FEATURE_SHADOWPASSWDS
    117     spwd = NULL;
    118     if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0)
    119                 || (strcmp(pwd->pw_passwd, "*") == 0))) {
    120         endspent();
    121         spwd = getspnam(name);
    122         if (spwd) {
    123             pwent.pw_passwd = spwd->sp_pwdp;
     85    if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) {
     86        goto auth_error;
     87    }
     88    pwd->pw_passwd = spw.sp_pwdp;
     89#endif
     90
     91    while (1) {
     92        /* cp points to a static buffer that is zeroed every time */
     93        cp = bb_askpass(timeout,
     94                "Give root password for system maintenance\n"
     95                "(or type Control-D for normal startup):");
     96
     97        if (!cp || !*cp) {
     98            bb_info_msg("Normal startup");
     99            return 0;
    124100        }
    125     }
    126 #endif
    127     while (1) {
    128         cp = bb_askpass(timeout, SULOGIN_PROMPT);
    129         if (!cp || !*cp) {
    130             puts("\n");
    131             fflush(stdout);
    132             syslog(LOG_INFO, "Normal startup\n");
    133             exit(EXIT_SUCCESS);
    134         } else {
    135             safe_strncpy(pass, cp, sizeof(pass));
    136             memset(cp, 0, strlen(cp));
    137         }
    138         if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) {
     101        if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) {
    139102            break;
    140103        }
    141104        bb_do_delay(FAIL_DELAY);
    142         puts("Login incorrect");
    143         fflush(stdout);
    144         syslog(LOG_WARNING, "Incorrect root password\n");
     105        bb_error_msg("login incorrect");
    145106    }
    146     memset(pass, 0, strlen(pass));
     107    memset(cp, 0, strlen(cp));
    147108    signal(SIGALRM, SIG_DFL);
    148     puts("Entering System Maintenance Mode\n");
    149     fflush(stdout);
    150     syslog(LOG_INFO, "System Maintenance Mode\n");
    151109
    152 #if ENABLE_SELINUX
    153     renew_current_security_context();
    154 #endif
     110    bb_info_msg("System Maintenance Mode");
    155111
    156     run_shell(pwent.pw_shell, 1, 0, 0);
     112    USE_SELINUX(renew_current_security_context());
    157113
    158     return (0);
     114    shell = getenv("SUSHELL");
     115    if (!shell) shell = getenv("sushell");
     116    if (!shell) {
     117        shell = "/bin/sh";
     118        if (pwd->pw_shell[0])
     119            shell = pwd->pw_shell;
     120    }
     121    run_shell(shell, 1, 0, 0);
     122    /* never returns */
     123
     124auth_error:
     125    bb_error_msg_and_die("no password entry for 'root'");
    159126}
  • branches/2.2.5/mindi-busybox/loginutils/vlock.c

    r821 r1765  
    11/* vi: set sw=4 ts=4: */
     2
    23/*
    34 * vlock implementation for busybox
     
    1617 * It now works with md5, sha1, etc passwords. */
    1718
    18 #include <stdio.h>
    19 #include <stdlib.h>
     19#include "libbb.h"
    2020#include <sys/vt.h>
    21 #include <signal.h>
    22 #include <string.h>
    23 #include <unistd.h>
    24 #include <fcntl.h>
    25 #include <errno.h>
    26 #include <sys/ioctl.h>
    27 #include <termios.h>
    28 
    29 #include "busybox.h"
    3021
    3122static struct passwd *pw;
     
    3728static void release_vt(int signo)
    3829{
    39     if (!o_lock_all)
    40         ioctl(vfd, VT_RELDISP, 1);
    41     else
    42         ioctl(vfd, VT_RELDISP, 0);
     30    ioctl(vfd, VT_RELDISP, !o_lock_all);
    4331}
    4432
     
    5442}
    5543
     44int vlock_main(int argc, char **argv);
    5645int vlock_main(int argc, char **argv)
    5746{
     
    6049    struct vt_mode vtm;
    6150    struct termios term;
     51    uid_t uid = getuid();
     52
     53    pw = getpwuid(uid);
     54    if (pw == NULL)
     55        bb_error_msg_and_die("unknown uid %d", uid);
    6256
    6357    if (argc > 2) {
     
    6559    }
    6660
    67     o_lock_all = bb_getopt_ulflags (argc, argv, "a");
     61    o_lock_all = getopt32(argv, "a");
    6862
    69     if((pw = getpwuid(getuid())) == NULL) {
    70         bb_error_msg_and_die("Unknown uid %d", getuid());
    71     }
     63    vfd = xopen(CURRENT_TTY, O_RDWR);
    7264
    73     vfd = bb_xopen(CURRENT_TTY, O_RDWR);
    74 
    75     if (ioctl(vfd, VT_GETMODE, &vtm) < 0) {
    76         bb_perror_msg_and_die("VT_GETMODE");
    77     }
     65    xioctl(vfd, VT_GETMODE, &vtm);
    7866
    7967    /* mask a bunch of signals */
     
    118106
    119107    do {
    120         printf("Virtual Console%s locked.\n%s's ", (o_lock_all) ? "s" : "", pw->pw_name);
    121         fflush(stdout);
    122         if (correct_password (pw)) {
     108        printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name);
     109        if (correct_password(pw)) {
    123110            break;
    124111        }
    125112        bb_do_delay(FAIL_DELAY);
    126         puts("Password incorrect.");
     113        puts("Password incorrect");
    127114    } while (1);
    128115    restore_terminal();
    129     return 0;
     116    fflush_stdout_and_exit(0);
    130117}
Note: See TracChangeset for help on using the changeset viewer.