Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/loginutils


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
Location:
branches/3.2/mindi-busybox/loginutils
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/loginutils/Config.src

    r2725 r3232  
    182182    select FEATURE_SYSLOG
    183183    help
    184       getty lets you log in on a tty, it is normally invoked by init.
     184      getty lets you log in on a tty. It is normally invoked by init.
     185
     186      Note that you can save a few bytes by disabling it and
     187      using login applet directly.
     188      If you need to reset tty attributes before calling login,
     189      this script approximates getty:
     190
     191      exec </dev/$1 >/dev/$1 2>&1 || exit 1
     192      reset
     193      stty sane; stty ispeed 38400; stty ospeed 38400
     194      printf "%s login: " "`hostname`"
     195      read -r login
     196      exec /bin/login "$login"
    185197
    186198config LOGIN
     
    193205      Note that Busybox binary must be setuid root for this applet to
    194206      work properly.
     207
     208config LOGIN_SESSION_AS_CHILD
     209    bool "Run logged in session in a child process"
     210    default y if PAM
     211    depends on LOGIN
     212    help
     213      Run the logged in session in a child process.  This allows
     214      login to clean up things such as utmp entries or PAM sessions
     215      when the login session is complete.  If you use PAM, you
     216      almost always would want this to be set to Y, else PAM session
     217      will not be cleaned up.
    195218
    196219config PAM
     
    261284      and uses this information to update a group of existing users.
    262285
     286config FEATURE_DEFAULT_PASSWD_ALGO
     287    string "Default password encryption method (passwd -a, cryptpw -m parameter)"
     288    default "des"
     289    depends on PASSWD || CRYPTPW
     290    help
     291      Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512".
     292
    263293config SU
    264294    bool "su"
  • branches/3.2/mindi-busybox/loginutils/add-remove-shell.c

    r2725 r3232  
    99 */
    1010
    11 //applet:IF_ADD_SHELL(   APPLET_ODDNAME(add-shell   , add_remove_shell, _BB_DIR_USR_BIN, _BB_SUID_DROP, add_shell   ))
    12 //applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, _BB_DIR_USR_BIN, _BB_SUID_DROP, remove_shell))
     11//applet:IF_ADD_SHELL(   APPLET_ODDNAME(add-shell   , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell   ))
     12//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell))
    1313
    1414//kbuild:lib-$(CONFIG_ADD_SHELL)    += add-remove-shell.o
  • branches/3.2/mindi-busybox/loginutils/addgroup.c

    r2725 r3232  
    1010 *
    1111 */
     12
     13//usage:#define addgroup_trivial_usage
     14//usage:       "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP"
     15//usage:#define addgroup_full_usage "\n\n"
     16//usage:       "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n"
     17//usage:     "\n    -g GID  Group id"
     18//usage:     "\n    -S  Create a system group"
     19
    1220#include "libbb.h"
    1321
  • branches/3.2/mindi-busybox/loginutils/adduser.c

    r2725 r3232  
    88 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
     10
     11//usage:#define adduser_trivial_usage
     12//usage:       "[OPTIONS] USER [GROUP]"
     13//usage:#define adduser_full_usage "\n\n"
     14//usage:       "Create new user, or add USER to GROUP\n"
     15//usage:     "\n    -h DIR      Home directory"
     16//usage:     "\n    -g GECOS    GECOS field"
     17//usage:     "\n    -s SHELL    Login shell"
     18//usage:     "\n    -G GRP      Add user to existing group"
     19//usage:     "\n    -S      Create a system user"
     20//usage:     "\n    -D      Don't assign a password"
     21//usage:     "\n    -H      Don't create home directory"
     22//usage:     "\n    -u UID      User id"
     23
    1024#include "libbb.h"
    1125
     
    5367        if (p->pw_uid == max) {
    5468            bb_error_msg_and_die("no %cids left", 'u');
     69            /* this format string is reused in adduser and addgroup */
    5570        }
    5671        p->pw_uid++;
     
    6681}
    6782
    68 static void addgroup_wrapper(struct passwd *p, const char *group_name)
    69 {
    70     char *cmd;
    71 
    72     if (group_name) /* Add user to existing group */
    73         cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name);
    74     else    /* Add user to his own group with the first free gid found in passwd_study */
    75         cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
    76     /* Warning: to be compatible with external addgroup programs we should use --gid instead */
    77     system(cmd);
    78     free(cmd);
    79 }
    80 
    81 static void passwd_wrapper(const char *login) NORETURN;
    82 
    83 static void passwd_wrapper(const char *login)
    84 {
    85     BB_EXECLP("passwd", "passwd", login, NULL);
     83static int addgroup_wrapper(struct passwd *p, const char *group_name)
     84{
     85    char *argv[6];
     86
     87    argv[0] = (char*)"addgroup";
     88    if (group_name) {
     89        /* Add user to existing group */
     90        argv[1] = (char*)"--";
     91        argv[2] = p->pw_name;
     92        argv[3] = (char*)group_name;
     93        argv[4] = NULL;
     94    } else {
     95        /* Add user to his own group with the first free gid
     96         * found in passwd_study.
     97         */
     98#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS || !ENABLE_ADDGROUP
     99        /* We try to use --gid, not -g, because "standard" addgroup
     100         * has no short option -g, it has only long --gid.
     101         */
     102        argv[1] = (char*)"--gid";
     103#else
     104        /* Breaks if system in fact does NOT use busybox addgroup */
     105        argv[1] = (char*)"-g";
     106#endif
     107        argv[2] = utoa(p->pw_gid);
     108        argv[3] = (char*)"--";
     109        argv[4] = p->pw_name;
     110        argv[5] = NULL;
     111    }
     112
     113    return spawn_and_wait(argv);
     114}
     115
     116static void passwd_wrapper(const char *login_name) NORETURN;
     117
     118static void passwd_wrapper(const char *login_name)
     119{
     120    BB_EXECLP("passwd", "passwd", "--", login_name, NULL);
    86121    bb_error_msg_and_die("can't execute passwd, you must set password manually");
    87122}
     
    124159
    125160    pw.pw_gecos = (char *)"Linux User,,,";
    126     pw.pw_shell = (char *)DEFAULT_SHELL;
     161    /* We assume that newly created users "inherit" root's shell setting */
     162    pw.pw_shell = (char *)get_shell_name();
    127163    pw.pw_dir = NULL;
    128164
    129     /* exactly one non-option arg */
     165    /* at most two non-option args */
    130166    /* disable interactive passwd for system accounts */
    131     opt_complementary = "=1:SD:u+";
     167    opt_complementary = "?2:SD:u+";
    132168    if (sizeof(pw.pw_uid) == sizeof(int)) {
    133169        opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
     
    140176    }
    141177    argv += optind;
     178    pw.pw_name = argv[0];
     179
     180    if (!opts && argv[1]) {
     181        /* if called with two non-option arguments, adduser
     182         * will add an existing user to an existing group.
     183         */
     184        return addgroup_wrapper(&pw, argv[1]);
     185    }
    142186
    143187    /* fill in the passwd struct */
    144     pw.pw_name = argv[0];
    145188    die_if_bad_username(pw.pw_name);
    146189    if (!pw.pw_dir) {
     
    170213    if (ENABLE_FEATURE_CLEAN_UP)
    171214        free(p);
    172 
    173215#if ENABLE_FEATURE_SHADOWPASSWDS
    174216    /* /etc/shadow fields:
     
    204246            /* New home. Copy /etc/skel to it */
    205247            const char *args[] = {
    206                 "chown", "-R",
     248                "chown",
     249                "-R",
    207250                xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid),
    208                 pw.pw_dir, NULL
     251                pw.pw_dir,
     252                NULL
    209253            };
    210254            /* Be silent on any errors (like: no /etc/skel) */
  • branches/3.2/mindi-busybox/loginutils/chpasswd.c

    r2725 r3232  
    77 */
    88#include "libbb.h"
     9
     10//usage:#define chpasswd_trivial_usage
     11//usage:    IF_LONG_OPTS("[--md5|--encrypted]") IF_NOT_LONG_OPTS("[-m|-e]")
     12//usage:#define chpasswd_full_usage "\n\n"
     13//usage:       "Read user:password from stdin and update /etc/passwd\n"
     14//usage:    IF_LONG_OPTS(
     15//usage:     "\n    -e,--encrypted  Supplied passwords are in encrypted form"
     16//usage:     "\n    -m,--md5    Use MD5 encryption instead of DES"
     17//usage:    )
     18//usage:    IF_NOT_LONG_OPTS(
     19//usage:     "\n    -e  Supplied passwords are in encrypted form"
     20//usage:     "\n    -m  Use MD5 encryption instead of DES"
     21//usage:    )
     22
     23//TODO: implement -c ALGO
    924
    1025#if ENABLE_LONG_OPTS
     
    2136int chpasswd_main(int argc UNUSED_PARAM, char **argv)
    2237{
    23     char *name, *pass;
    24     char salt[sizeof("$N$XXXXXXXX")];
    25     int opt, rc;
    26     int rnd = rnd; /* we *want* it to be non-initialized! */
     38    char *name;
     39    int opt;
    2740
    28     if (getuid())
     41    if (getuid() != 0)
    2942        bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    3043
     
    3447
    3548    while ((name = xmalloc_fgetline(stdin)) != NULL) {
     49        char *free_me;
     50        char *pass;
     51        int rc;
     52
    3653        pass = strchr(name, ':');
    3754        if (!pass)
     
    4158        xuname2uid(name); /* dies if there is no such user */
    4259
     60        free_me = NULL;
    4361        if (!(opt & OPT_ENC)) {
    44             rnd = crypt_make_salt(salt, 1, rnd);
     62            char salt[sizeof("$N$XXXXXXXX")];
     63
     64            crypt_make_salt(salt, 1);
    4565            if (opt & OPT_MD5) {
    46                 strcpy(salt, "$1$");
    47                 rnd = crypt_make_salt(salt + 3, 4, rnd);
     66                salt[0] = '$';
     67                salt[1] = '1';
     68                salt[2] = '$';
     69                crypt_make_salt(salt + 3, 4);
    4870            }
    49             pass = pw_encrypt(pass, salt, 0);
     71            free_me = pass = pw_encrypt(pass, salt, 0);
    5072        }
    5173
     
    5476#if ENABLE_FEATURE_SHADOWPASSWDS
    5577        rc = update_passwd(bb_path_shadow_file, name, pass, NULL);
    56         if (rc == 0) /* no lines updated, no errors detected */
     78        if (rc > 0) /* password in /etc/shadow was updated */
     79            pass = (char*)"x";
     80        if (rc >= 0)
     81            /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
    5782#endif
    5883            rc = update_passwd(bb_path_passwd_file, name, pass, NULL);
     
    6590        logmode = LOGMODE_STDIO;
    6691        free(name);
    67         if (!(opt & OPT_ENC))
    68             free(pass);
     92        free(free_me);
    6993    }
    7094    return EXIT_SUCCESS;
  • branches/3.2/mindi-busybox/loginutils/cryptpw.c

    r2725 r3232  
    1010 * Licensed under GPLv2, see file LICENSE in this source tree.
    1111 */
     12
     13//usage:#define cryptpw_trivial_usage
     14//usage:       "[OPTIONS] [PASSWORD] [SALT]"
     15/* We do support -s, we just don't mention it */
     16//usage:#define cryptpw_full_usage "\n\n"
     17//usage:       "Crypt PASSWORD using crypt(3)\n"
     18//usage:    IF_LONG_OPTS(
     19//usage:     "\n    -P,--password-fd=N  Read password from fd N"
     20/* //usage:  "\n    -s,--stdin      Use stdin; like -P0" */
     21//usage:     "\n    -m,--method=TYPE    Encryption method"
     22//usage:     "\n    -S,--salt=SALT"
     23//usage:    )
     24//usage:    IF_NOT_LONG_OPTS(
     25//usage:     "\n    -P N    Read password from fd N"
     26/* //usage:  "\n    -s  Use stdin; like -P0" */
     27//usage:     "\n    -m TYPE Encryption method TYPE"
     28//usage:     "\n    -S SALT"
     29//usage:    )
     30
     31/* mkpasswd is an alias to cryptpw */
     32//usage:#define mkpasswd_trivial_usage
     33//usage:       "[OPTIONS] [PASSWORD] [SALT]"
     34/* We do support -s, we just don't mention it */
     35//usage:#define mkpasswd_full_usage "\n\n"
     36//usage:       "Crypt PASSWORD using crypt(3)\n"
     37//usage:    IF_LONG_OPTS(
     38//usage:     "\n    -P,--password-fd=N  Read password from fd N"
     39/* //usage:  "\n    -s,--stdin      Use stdin; like -P0" */
     40//usage:     "\n    -m,--method=TYPE    Encryption method"
     41//usage:     "\n    -S,--salt=SALT"
     42//usage:    )
     43//usage:    IF_NOT_LONG_OPTS(
     44//usage:     "\n    -P N    Read password from fd N"
     45/* //usage:  "\n    -s  Use stdin; like -P0" */
     46//usage:     "\n    -m TYPE Encryption method TYPE"
     47//usage:     "\n    -S SALT"
     48//usage:    )
    1249
    1350#include "libbb.h"
     
    5491int cryptpw_main(int argc UNUSED_PARAM, char **argv)
    5592{
    56     /* $N$ + sha_salt_16_bytes + NUL */
    57     char salt[3 + 16 + 1];
     93    char salt[MAX_PW_SALT_LEN];
    5894    char *salt_ptr;
    5995    const char *opt_m, *opt_S;
    60     int len;
    6196    int fd;
    6297
     
    71106#endif
    72107    fd = STDIN_FILENO;
    73     opt_m = "d";
     108    opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
    74109    opt_S = NULL;
    75110    /* at most two non-option arguments; -P NUM */
     
    83118        opt_S = argv[1];
    84119
    85     len = 2/2;
    86     salt_ptr = salt;
    87     if (opt_m[0] != 'd') { /* not des */
    88         len = 8/2; /* so far assuming md5 */
    89         *salt_ptr++ = '$';
    90         *salt_ptr++ = '1';
    91         *salt_ptr++ = '$';
    92 #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
    93         if (opt_m[0] == 's') { /* sha */
    94             salt[1] = '5' + (strcmp(opt_m, "sha512") == 0);
    95             len = 16/2;
    96         }
    97 #endif
    98     }
     120    salt_ptr = crypt_make_pw_salt(salt, opt_m);
    99121    if (opt_S)
    100         safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3);
    101     else
    102         crypt_make_salt(salt_ptr, len, 0);
     122        safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1));
    103123
    104124    xmove_fd(fd, STDIN_FILENO);
  • branches/3.2/mindi-busybox/loginutils/deluser.c

    r2725 r3232  
    1010 *
    1111 */
     12
     13//usage:#define deluser_trivial_usage
     14//usage:       "USER"
     15//usage:#define deluser_full_usage "\n\n"
     16//usage:       "Delete USER from the system"
     17
     18//usage:#define delgroup_trivial_usage
     19//usage:    IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
     20//usage:#define delgroup_full_usage "\n\n"
     21//usage:       "Delete group GROUP from the system"
     22//usage:    IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")
     23
    1224#include "libbb.h"
    1325
  • branches/3.2/mindi-busybox/loginutils/getty.c

    r2725 r3232  
    11/* vi: set sw=4 ts=4: */
    2 /* agetty.c - another getty program for Linux. By W. Z. Venema 1989
     2/*
     3 * Based on agetty - another getty program for Linux. By W. Z. Venema 1989
    34 * 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.
     5 * This program is freely distributable.
    66 *
    77 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
    88 *
    99 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
    10  * - added Native Language Support
     10 * - Added Native Language Support
    1111 *
    1212 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
    13  * - enable hardware flow control before displaying /etc/issue
     13 * - Enabled hardware flow control before displaying /etc/issue
     14 *
     15 * 2011-01 Venys Vlasenko
     16 * - Removed parity detection code. It can't work reliably:
     17 * if all chars received have bit 7 cleared and odd (or even) parity,
     18 * it is impossible to determine whether other side is 8-bit,no-parity
     19 * or 7-bit,odd(even)-parity. It also interferes with non-ASCII usernames.
     20 * - From now on, we assume that parity is correctly set.
    1421 *
    1522 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     
    1825#include "libbb.h"
    1926#include <syslog.h>
    20 
    21 #if ENABLE_FEATURE_UTMP
    22 # include <utmp.h> /* LOGIN_PROCESS */
    23 #endif
    24 
    2527#ifndef IUCLC
    2628# define IUCLC 0
    2729#endif
    2830
    29 /*
    30  * Some heuristics to find out what environment we are in: if it is not
    31  * System V, assume it is SunOS 4.
    32  */
    33 #ifdef LOGIN_PROCESS                    /* defined in System V utmp.h */
    34 #include <sys/utsname.h>
    35 #else /* if !sysV style, wtmp/utmp code is off */
    36 #undef ENABLE_FEATURE_UTMP
    37 #undef ENABLE_FEATURE_WTMP
    38 #define ENABLE_FEATURE_UTMP 0
    39 #define ENABLE_FEATURE_WTMP 0
    40 #endif  /* LOGIN_PROCESS */
     31#ifndef LOGIN_PROCESS
     32# undef ENABLE_FEATURE_UTMP
     33# undef ENABLE_FEATURE_WTMP
     34# define ENABLE_FEATURE_UTMP 0
     35# define ENABLE_FEATURE_WTMP 0
     36#endif
     37
     38
     39/* The following is used for understandable diagnostics */
     40#ifdef DEBUGGING
     41static FILE *dbf;
     42# define DEBUGTERM "/dev/ttyp0"
     43# define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0)
     44#else
     45# define debug(...) ((void)0)
     46#endif
     47
    4148
    4249/*
     
    4754 * and for line editing at the same time.
    4855 */
    49 
    50 /* I doubt there are systems which still need this */
    51 #undef HANDLE_ALLCAPS
    52 #undef ANCIENT_BS_KILL_CHARS
    53 
     56#undef  _PATH_LOGIN
    5457#define _PATH_LOGIN "/bin/login"
    5558
    56 /* If ISSUE is not defined, getty will never display the contents of the
     59/* Displayed before the login prompt.
     60 * If ISSUE is not defined, getty will never display the contents of the
    5761 * /etc/issue file. You will not want to spit out large "issue" files at the
    5862 * wrong baud rate.
    5963 */
    60 #define ISSUE "/etc/issue"              /* displayed before the login prompt */
    61 
    62 /* Some shorthands for control characters. */
    63 #define CTL(x)          ((x) ^ 0100)    /* Assumes ASCII dialect */
    64 #define CR              CTL('M')        /* carriage return */
    65 #define NL              CTL('J')        /* line feed */
    66 #define BS              CTL('H')        /* back space */
    67 #define DEL             CTL('?')        /* delete */
    68 
    69 /* Defaults for line-editing etc. characters; you may want to change this. */
    70 #define DEF_ERASE       DEL             /* default erase character */
    71 #define DEF_INTR        CTL('C')        /* default interrupt character */
    72 #define DEF_QUIT        CTL('\\')       /* default quit char */
    73 #define DEF_KILL        CTL('U')        /* default kill char */
    74 #define DEF_EOF         CTL('D')        /* default EOF char */
    75 #define DEF_EOL         '\n'
    76 #define DEF_SWITCH      0               /* default switch char */
     64#define ISSUE "/etc/issue"
     65
     66/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */
     67#define CTL(x)          ((x) ^ 0100)
    7768
    7869/*
    79  * When multiple baud rates are specified on the command line, the first one
    80  * we will try is the first one specified.
     70 * When multiple baud rates are specified on the command line,
     71 * the first one we will try is the first one specified.
    8172 */
    8273#define MAX_SPEED       10              /* max. nr. of baud rates */
    8374
    84 /* Storage for command-line options. */
    85 struct options {
    86     int flags;                      /* toggle switches, see below */
    87     unsigned timeout;               /* time-out period */
     75struct globals {
     76    unsigned timeout;
    8877    const char *login;              /* login program */
    89     const char *tty;                /* name of tty */
    90     const char *initstring;         /* modem init string */
     78    const char *fakehost;
     79    const char *tty_name;
     80    char *initstring;               /* modem init string */
    9181    const char *issue;              /* alternative issue file */
    9282    int numspeed;                   /* number of baud rates to try */
    9383    int speeds[MAX_SPEED];          /* baud rates to be tried */
     84    unsigned char eol;              /* end-of-line char seen (CR or NL) */
     85    struct termios tty_attrs;
     86    char line_buf[128];
    9487};
    9588
    96 /* Storage for things detected while the login name was read. */
    97 struct chardata {
    98     unsigned char erase;    /* erase character */
    99     unsigned char kill;     /* kill character */
    100     unsigned char eol;      /* end-of-line character */
    101     unsigned char parity;   /* what parity did we see */
    102     /* (parity & 1): saw odd parity char with 7th bit set */
    103     /* (parity & 2): saw even parity char with 7th bit set */
    104     /* parity == 0: probably 7-bit, space parity? */
    105     /* parity == 1: probably 7-bit, odd parity? */
    106     /* parity == 2: probably 7-bit, even parity? */
    107     /* parity == 3: definitely 8 bit, no parity! */
    108     /* Hmm... with any value of "parity" 8 bit, no parity is possible */
    109 #ifdef HANDLE_ALLCAPS
    110     unsigned char capslock; /* upper case without lower case */
    111 #endif
    112 };
    113 
    114 
    115 /* Initial values for the above. */
    116 static const struct chardata init_chardata = {
    117     DEF_ERASE,                              /* default erase character */
    118     DEF_KILL,                               /* default kill character */
    119     13,                                     /* default eol char */
    120     0,                                      /* space parity */
    121 #ifdef HANDLE_ALLCAPS
    122     0,                                      /* no capslock */
    123 #endif
    124 };
     89#define G (*ptr_to_globals)
     90#define INIT_G() do { \
     91    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     92} while (0)
     93
     94//usage:#define getty_trivial_usage
     95//usage:       "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]"
     96//usage:#define getty_full_usage "\n\n"
     97//usage:       "Open TTY, prompt for login name, then invoke /bin/login\n"
     98//usage:     "\n    -h      Enable hardware RTS/CTS flow control"
     99//usage:     "\n    -L      Set CLOCAL (ignore Carrier Detect state)"
     100//usage:     "\n    -m      Get baud rate from modem's CONNECT status message"
     101//usage:     "\n    -n      Don't prompt for login name"
     102//usage:     "\n    -w      Wait for CR or LF before sending /etc/issue"
     103//usage:     "\n    -i      Don't display /etc/issue"
     104//usage:     "\n    -f ISSUE_FILE   Display ISSUE_FILE instead of /etc/issue"
     105//usage:     "\n    -l LOGIN    Invoke LOGIN instead of /bin/login"
     106//usage:     "\n    -t SEC      Terminate after SEC if no login name is read"
     107//usage:     "\n    -I INITSTR  Send INITSTR before anything else"
     108//usage:     "\n    -H HOST     Log HOST into the utmp file as the hostname"
     109//usage:     "\n"
     110//usage:     "\nBAUD_RATE of 0 leaves it unchanged"
    125111
    126112static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
    127 #define F_INITSTRING    (1 << 0)        /* -I initstring is set */
    128 #define F_LOCAL         (1 << 1)        /* -L force local */
    129 #define F_FAKEHOST      (1 << 2)        /* -H fake hostname */
    130 #define F_CUSTISSUE     (1 << 3)        /* -f give alternative issue file */
    131 #define F_RTSCTS        (1 << 4)        /* -h enable RTS/CTS flow control */
    132 #define F_ISSUE         (1 << 5)        /* -i display /etc/issue */
    133 #define F_LOGIN         (1 << 6)        /* -l non-default login program */
    134 #define F_PARSE         (1 << 7)        /* -m process modem status messages */
    135 #define F_TIMEOUT       (1 << 8)        /* -t time out */
    136 #define F_WAITCRLF      (1 << 9)        /* -w wait for CR or LF */
    137 #define F_NOPROMPT      (1 << 10)       /* -n don't ask for login name */
    138 
    139 
    140 #define line_buf bb_common_bufsiz1
    141 
    142 /* The following is used for understandable diagnostics. */
    143 #ifdef DEBUGGING
    144 static FILE *dbf;
    145 #define DEBUGTERM "/dev/ttyp0"
    146 #define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0)
    147 #else
    148 #define debug(...) ((void)0)
    149 #endif
    150 
    151 
    152 /* bcode - convert speed string to speed code; return <= 0 on failure */
     113#define F_INITSTRING    (1 << 0)   /* -I */
     114#define F_LOCAL         (1 << 1)   /* -L */
     115#define F_FAKEHOST      (1 << 2)   /* -H */
     116#define F_CUSTISSUE     (1 << 3)   /* -f */
     117#define F_RTSCTS        (1 << 4)   /* -h */
     118#define F_NOISSUE       (1 << 5)   /* -i */
     119#define F_LOGIN         (1 << 6)   /* -l */
     120#define F_PARSE         (1 << 7)   /* -m */
     121#define F_TIMEOUT       (1 << 8)   /* -t */
     122#define F_WAITCRLF      (1 << 9)   /* -w */
     123#define F_NOPROMPT      (1 << 10)  /* -n */
     124
     125
     126/* convert speed string to speed code; return <= 0 on failure */
    153127static int bcode(const char *s)
    154128{
     
    159133}
    160134
    161 /* parse_speeds - parse alternate baud rates */
    162 static void parse_speeds(struct options *op, char *arg)
     135/* parse alternate baud rates */
     136static void parse_speeds(char *arg)
    163137{
    164138    char *cp;
     
    167141    debug("entered parse_speeds\n");
    168142    while ((cp = strsep(&arg, ",")) != NULL) {
    169         op->speeds[op->numspeed] = bcode(cp);
    170         if (op->speeds[op->numspeed] < 0)
     143        G.speeds[G.numspeed] = bcode(cp);
     144        if (G.speeds[G.numspeed] < 0)
    171145            bb_error_msg_and_die("bad speed: %s", cp);
    172146        /* note: arg "0" turns into speed B0 */
    173         op->numspeed++;
    174         if (op->numspeed > MAX_SPEED)
     147        G.numspeed++;
     148        if (G.numspeed > MAX_SPEED)
    175149            bb_error_msg_and_die("too many alternate speeds");
    176150    }
     
    178152}
    179153
    180 /* parse_args - parse command-line arguments */
    181 static void parse_args(char **argv, struct options *op, char **fakehost_p)
     154/* parse command-line arguments */
     155static void parse_args(char **argv)
    182156{
    183157    char *ts;
     158    int flags;
    184159
    185160    opt_complementary = "-2:t+"; /* at least 2 args; -t N */
    186     op->flags = getopt32(argv, opt_string,
    187         &(op->initstring), fakehost_p, &(op->issue),
    188         &(op->login), &op->timeout);
     161    flags = getopt32(argv, opt_string,
     162        &G.initstring, &G.fakehost, &G.issue,
     163        &G.login, &G.timeout
     164    );
     165    if (flags & F_INITSTRING) {
     166        G.initstring = xstrdup(G.initstring);
     167        /* decode \ddd octal codes into chars */
     168        strcpy_and_process_escape_sequences(G.initstring, G.initstring);
     169    }
    189170    argv += optind;
    190     if (op->flags & F_INITSTRING) {
    191         op->initstring = xstrdup(op->initstring);
    192         /* decode \ddd octal codes into chars */
    193         strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring);
    194     }
    195     op->flags ^= F_ISSUE;           /* invert flag "show /etc/issue" */
    196171    debug("after getopt\n");
    197172
    198     /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
    199     op->tty = argv[0];      /* tty name */
    200     ts = argv[1];           /* baud rate(s) */
     173    /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
     174    G.tty_name = argv[0];
     175    ts = argv[1];            /* baud rate(s) */
    201176    if (isdigit(argv[0][0])) {
    202         /* a number first, assume it's a speed (BSD style) */
    203         op->tty = ts;   /* tty name is in argv[1] */
    204         ts = argv[0];   /* baud rate(s) */
    205     }
    206     parse_speeds(op, ts);
    207     applet_name = xasprintf("getty: %s", op->tty);
     177        /* A number first, assume it's a speed (BSD style) */
     178        G.tty_name = ts; /* tty name is in argv[1] */
     179        ts = argv[0];    /* baud rate(s) */
     180    }
     181    parse_speeds(ts);
    208182
    209183    if (argv[2])
     
    213187}
    214188
    215 /* open_tty - set up tty as standard { input, output, error } */
    216 static void open_tty(const char *tty)
    217 {
    218     /* Set up new standard input, unless we are given an already opened port. */
    219     if (NOT_LONE_DASH(tty)) {
    220 //      struct stat st;
    221 //      int cur_dir_fd;
    222 //      int fd;
    223 
    224         /* Sanity checks... */
    225 //      cur_dir_fd = xopen(".", O_DIRECTORY | O_NONBLOCK);
    226 //      xchdir("/dev");
    227 //      xstat(tty, &st);
    228 //      if (!S_ISCHR(st.st_mode))
    229 //          bb_error_msg_and_die("not a character device");
    230 
    231         if (tty[0] != '/')
    232             tty = xasprintf("/dev/%s", tty); /* will leak it */
    233 
    234         /* Open the tty as standard input. */
     189/* set up tty as standard input, output, error */
     190static void open_tty(void)
     191{
     192    /* Set up new standard input, unless we are given an already opened port */
     193    if (NOT_LONE_DASH(G.tty_name)) {
     194        if (G.tty_name[0] != '/')
     195            G.tty_name = xasprintf("/dev/%s", G.tty_name); /* will leak it */
     196
     197        /* Open the tty as standard input */
    235198        debug("open(2)\n");
    236199        close(0);
    237         /*fd =*/ xopen(tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */
    238 
    239 //      /* Restore current directory */
    240 //      fchdir(cur_dir_fd);
    241 
    242         /* Open the tty as standard input, continued */
    243 //      xmove_fd(fd, 0);
    244 //      /* fd is >= cur_dir_fd, and cur_dir_fd gets closed too here: */
    245 //      while (fd > 2)
    246 //          close(fd--);
    247 
    248         /* Set proper protections and ownership. */
     200        xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */
     201
     202        /* Set proper protections and ownership */
    249203        fchown(0, 0, 0);        /* 0:0 */
    250204        fchmod(0, 0620);        /* crw--w---- */
    251205    } else {
     206        char *n;
    252207        /*
    253          * Standard input should already be connected to an open port. Make
    254          * sure it is open for read/write.
     208         * Standard input should already be connected to an open port.
     209         * Make sure it is open for read/write.
    255210         */
    256         if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR)
     211        if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR)
    257212            bb_error_msg_and_die("stdin is not open for read/write");
    258     }
    259 }
    260 
    261 /* termios_init - initialize termios settings */
    262 static void termios_init(struct termios *tp, int speed, struct options *op)
    263 {
    264     speed_t ispeed, ospeed;
    265     /*
    266      * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
     213
     214        /* Try to get real tty name instead of "-" */
     215        n = xmalloc_ttyname(0);
     216        if (n)
     217            G.tty_name = n;
     218    }
     219    applet_name = xasprintf("getty: %s", skip_dev_pfx(G.tty_name));
     220}
     221
     222static void set_tty_attrs(void)
     223{
     224    if (tcsetattr_stdin_TCSANOW(&G.tty_attrs) < 0)
     225        bb_perror_msg_and_die("tcsetattr");
     226}
     227
     228/* We manipulate tty_attrs this way:
     229 * - first, we read existing tty_attrs
     230 * - init_tty_attrs modifies some parts and sets it
     231 * - auto_baud and/or BREAK processing can set different speed and set tty attrs
     232 * - finalize_tty_attrs again modifies some parts and sets tty attrs before
     233 *   execing login
     234 */
     235static void init_tty_attrs(int speed)
     236{
     237    /* Try to drain output buffer, with 5 sec timeout.
     238     * Added on request from users of ~600 baud serial interface
     239     * with biggish buffer on a 90MHz CPU.
     240     * They were losing hundreds of bytes of buffered output
     241     * on tcflush.
     242     */
     243    signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo);
     244    alarm(5);
     245    tcdrain(STDIN_FILENO);
     246    alarm(0);
     247
     248    /* Flush input and output queues, important for modems! */
     249    tcflush(STDIN_FILENO, TCIOFLUSH);
     250
     251    /* Set speed if it wasn't specified as "0" on command line */
     252    if (speed != B0)
     253        cfsetspeed(&G.tty_attrs, speed);
     254
     255    /* Initial settings: 8-bit characters, raw mode, blocking i/o.
    267256     * Special characters are set after we have read the login name; all
    268      * reads will be done in raw mode anyway. Errors will be dealt with
    269      * later on.
    270      */
    271     /* flush input and output queues, important for modems! */
    272     tcflush(0, TCIOFLUSH);
    273     ispeed = ospeed = speed;
    274     if (speed == B0) {
    275         /* Speed was specified as "0" on command line.
    276          * Just leave it unchanged */
    277         ispeed = cfgetispeed(tp);
    278         ospeed = cfgetospeed(tp);
    279     }
    280     tp->c_cflag = CS8 | HUPCL | CREAD;
    281     if (op->flags & F_LOCAL)
    282         tp->c_cflag |= CLOCAL;
    283     cfsetispeed(tp, ispeed);
    284     cfsetospeed(tp, ospeed);
    285 
    286     tp->c_iflag = tp->c_lflag = 0;
    287     tp->c_oflag = OPOST | ONLCR;
    288     tp->c_cc[VMIN] = 1;
    289     tp->c_cc[VTIME] = 0;
     257     * reads will be done in raw mode anyway.
     258     */
     259    /* Clear all bits except: */
     260    G.tty_attrs.c_cflag &= (0
     261        /* 2 stop bits (1 otherwise)
     262         * Enable parity bit (both on input and output)
     263         * Odd parity (else even)
     264         */
     265        | CSTOPB | PARENB | PARODD
     266#ifdef CMSPAR
     267        | CMSPAR  /* mark or space parity */
     268#endif
     269#ifdef CBAUD
     270        | CBAUD   /* (output) baud rate */
     271#endif
     272#ifdef CBAUDEX
     273        | CBAUDEX /* (output) baud rate */
     274#endif
     275#ifdef CIBAUD
     276        | CIBAUD   /* input baud rate */
     277#endif
     278    );
     279    /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */
     280    G.tty_attrs.c_cflag |= CS8 | HUPCL | CREAD;
     281    if (option_mask32 & F_LOCAL) {
     282        /* ignore Carrier Detect pin:
     283         * opens don't block when CD is low,
     284         * losing CD doesn't hang up processes whose ctty is this tty
     285         */
     286        G.tty_attrs.c_cflag |= CLOCAL;
     287    }
     288#ifdef CRTSCTS
     289    if (option_mask32 & F_RTSCTS)
     290        G.tty_attrs.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */
     291#endif
     292    G.tty_attrs.c_iflag = 0;
     293    G.tty_attrs.c_lflag = 0;
     294    /* non-raw output; add CR to each NL */
     295    G.tty_attrs.c_oflag = OPOST | ONLCR;
     296
     297    /* reads would block only if < 1 char is available */
     298    G.tty_attrs.c_cc[VMIN] = 1;
     299    /* no timeout (reads block forever) */
     300    G.tty_attrs.c_cc[VTIME] = 0;
    290301#ifdef __linux__
    291     tp->c_line = 0;
    292 #endif
    293 
    294     /* Optionally enable hardware flow control */
    295 #ifdef CRTSCTS
    296     if (op->flags & F_RTSCTS)
    297         tp->c_cflag |= CRTSCTS;
    298 #endif
    299 
    300     tcsetattr_stdin_TCSANOW(tp);
     302    G.tty_attrs.c_line = 0;
     303#endif
     304
     305    set_tty_attrs();
    301306
    302307    debug("term_io 2\n");
    303308}
    304309
    305 /* auto_baud - extract baud rate from modem status message */
    306 static void auto_baud(char *buf, unsigned size_buf, struct termios *tp)
    307 {
    308     int speed;
    309     int vmin;
    310     unsigned iflag;
    311     char *bp;
     310static void finalize_tty_attrs(void)
     311{
     312    /* software flow control on output (stop sending if XOFF is recvd);
     313     * and on input (send XOFF when buffer is full)
     314     */
     315    G.tty_attrs.c_iflag |= IXON | IXOFF;
     316    if (G.eol == '\r') {
     317        G.tty_attrs.c_iflag |= ICRNL; /* map CR on input to NL */
     318    }
     319    /* Other bits in c_iflag:
     320     * IXANY   Any recvd char enables output (any char is also a XON)
     321     * INPCK   Enable parity check
     322     * IGNPAR  Ignore parity errors (drop bad bytes)
     323     * PARMRK  Mark parity errors with 0xff, 0x00 prefix
     324     *         (else bad byte is received as 0x00)
     325     * ISTRIP  Strip parity bit
     326     * IGNBRK  Ignore break condition
     327     * BRKINT  Send SIGINT on break - maybe set this?
     328     * INLCR   Map NL to CR
     329     * IGNCR   Ignore CR
     330     * ICRNL   Map CR to NL
     331     * IUCLC   Map uppercase to lowercase
     332     * IMAXBEL Echo BEL on input line too long
     333     * IUTF8   Appears to affect tty's idea of char widths,
     334     *         observed to improve backspacing through Unicode chars
     335     */
     336
     337    /* line buffered input (NL or EOL or EOF chars end a line);
     338     * recognize INT/QUIT/SUSP chars;
     339     * echo input chars;
     340     * echo BS-SP-BS on erase character;
     341     * echo kill char specially, not as ^c (ECHOKE controls how exactly);
     342     * erase all input via BS-SP-BS on kill char (else go to next line)
     343     */
     344    G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
     345    /* Other bits in c_lflag:
     346     * XCASE   Map uppercase to \lowercase [tried, doesn't work]
     347     * ECHONL  Echo NL even if ECHO is not set
     348     * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
     349     * ECHOPRT On erase, echo erased chars
     350     *         [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
     351     * NOFLSH  Don't flush input buffer after interrupt or quit chars
     352     * IEXTEN  Enable extended functions (??)
     353     *         [glibc says it enables c_cc[LNEXT] "enter literal char"
     354     *         and c_cc[VDISCARD] "toggle discard buffered output" chars]
     355     * FLUSHO  Output being flushed (c_cc[VDISCARD] is in effect)
     356     * PENDIN  Retype pending input at next read or input char
     357     *         (c_cc[VREPRINT] is being processed)
     358     * TOSTOP  Send SIGTTOU for background output
     359     *         (why "stty sane" unsets this bit?)
     360     */
     361
     362    G.tty_attrs.c_cc[VINTR] = CTL('C');
     363    G.tty_attrs.c_cc[VQUIT] = CTL('\\');
     364    G.tty_attrs.c_cc[VEOF] = CTL('D');
     365    G.tty_attrs.c_cc[VEOL] = '\n';
     366#ifdef VSWTC
     367    G.tty_attrs.c_cc[VSWTC] = 0;
     368#endif
     369#ifdef VSWTCH
     370    G.tty_attrs.c_cc[VSWTCH] = 0;
     371#endif
     372    G.tty_attrs.c_cc[VKILL] = CTL('U');
     373    /* Other control chars:
     374     * VEOL2
     375     * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname
     376     * VREPRINT - reprint current input buffer
     377     * VLNEXT, VDISCARD, VSTATUS
     378     * VSUSP, VDSUSP - send (delayed) SIGTSTP
     379     * VSTART, VSTOP - chars used for IXON/IXOFF
     380     */
     381
     382    set_tty_attrs();
     383
     384    /* Now the newline character should be properly written */
     385    full_write(STDOUT_FILENO, "\n", 1);
     386}
     387
     388/* extract baud rate from modem status message */
     389static void auto_baud(void)
     390{
    312391    int nread;
    313392
     
    327406     */
    328407
    329     /*
    330      * Use 7-bit characters, don't block if input queue is empty. Errors will
    331      * be dealt with later on.
    332      */
    333     iflag = tp->c_iflag;
    334     tp->c_iflag |= ISTRIP;          /* enable 8th-bit stripping */
    335     vmin = tp->c_cc[VMIN];
    336     tp->c_cc[VMIN] = 0;             /* don't block if queue empty */
    337     tcsetattr_stdin_TCSANOW(tp);
     408    G.tty_attrs.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */
     409    set_tty_attrs();
    338410
    339411    /*
     
    342414     */
    343415    sleep(1);
    344     nread = safe_read(STDIN_FILENO, buf, size_buf - 1);
     416    nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1);
    345417    if (nread > 0) {
    346         buf[nread] = '\0';
    347         for (bp = buf; bp < buf + nread; bp++) {
     418        int speed;
     419        char *bp;
     420        G.line_buf[nread] = '\0';
     421        for (bp = G.line_buf; bp < G.line_buf + nread; bp++) {
    348422            if (isdigit(*bp)) {
    349423                speed = bcode(bp);
    350424                if (speed > 0)
    351                     cfsetspeed(tp, speed);
     425                    cfsetspeed(&G.tty_attrs, speed);
    352426                break;
    353427            }
     
    355429    }
    356430
    357     /* Restore terminal settings. Errors will be dealt with later on. */
    358     tp->c_iflag = iflag;
    359     tp->c_cc[VMIN] = vmin;
    360     tcsetattr_stdin_TCSANOW(tp);
    361 }
    362 
    363 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
    364 static void do_prompt(struct options *op)
    365 {
     431    /* Restore terminal settings */
     432    G.tty_attrs.c_cc[VMIN] = 1; /* restore to value set by init_tty_attrs */
     433    set_tty_attrs();
     434}
     435
     436/* get user name, establish parity, speed, erase, kill, eol;
     437 * return NULL on BREAK, logname on success
     438 */
     439static char *get_logname(void)
     440{
     441    char *bp;
     442    char c;
     443
     444    /* Flush pending input (esp. after parsing or switching the baud rate) */
     445    usleep(100*1000); /* 0.1 sec */
     446    tcflush(STDIN_FILENO, TCIFLUSH);
     447
     448    /* Prompt for and read a login name */
     449    do {
     450        /* Write issue file and prompt */
    366451#ifdef ISSUE
    367     print_login_issue(op->issue, op->tty);
    368 #endif
    369     print_login_prompt();
    370 }
    371 
    372 #ifdef HANDLE_ALLCAPS
    373 /* all_is_upcase - string contains upper case without lower case */
    374 /* returns 1 if true, 0 if false */
    375 static int all_is_upcase(const char *s)
    376 {
    377     while (*s)
    378         if (islower(*s++))
    379             return 0;
    380     return 1;
    381 }
    382 #endif
    383 
    384 /* get_logname - get user name, establish parity, speed, erase, kill, eol;
    385  * return NULL on BREAK, logname on success */
    386 static char *get_logname(char *logname, unsigned size_logname,
    387         struct options *op, struct chardata *cp)
    388 {
    389     char *bp;
    390     char c;                         /* input character, full eight bits */
    391     char ascval;                    /* low 7 bits of input character */
    392     int bits;                       /* # of "1" bits per character */
    393     int mask;                       /* mask with 1 bit up */
    394     static const char erase[][3] = {/* backspace-space-backspace */
    395         "\010\040\010",                 /* space parity */
    396         "\010\040\010",                 /* odd parity */
    397         "\210\240\210",                 /* even parity */
    398         "\010\040\010",                 /* 8 bit no parity */
    399     };
    400 
    401     /* NB: *cp is pre-initialized with init_chardata */
    402 
    403     /* Flush pending input (esp. after parsing or switching the baud rate). */
    404     sleep(1);
    405     tcflush(0, TCIOFLUSH);
    406 
    407     /* Prompt for and read a login name. */
    408     logname[0] = '\0';
    409     while (!logname[0]) {
    410         /* Write issue file and prompt, with "parity" bit == 0. */
    411         do_prompt(op);
    412 
    413         /* Read name, watch for break, parity, erase, kill, end-of-line. */
    414         bp = logname;
    415         cp->eol = '\0';
    416         while (cp->eol == '\0') {
    417 
    418             /* Do not report trivial EINTR/EIO errors. */
     452        if (!(option_mask32 & F_NOISSUE))
     453            print_login_issue(G.issue, G.tty_name);
     454#endif
     455        print_login_prompt();
     456
     457        /* Read name, watch for break, erase, kill, end-of-line */
     458        bp = G.line_buf;
     459        while (1) {
     460            /* Do not report trivial EINTR/EIO errors */
    419461            errno = EINTR; /* make read of 0 bytes be silent too */
    420462            if (read(STDIN_FILENO, &c, 1) < 1) {
     463                finalize_tty_attrs();
    421464                if (errno == EINTR || errno == EIO)
    422465                    exit(EXIT_SUCCESS);
     
    424467            }
    425468
    426             /* BREAK. If we have speeds to try,
    427              * return NULL (will switch speeds and return here) */
    428             if (c == '\0' && op->numspeed > 1)
    429                 return NULL;
    430 
    431             /* Do parity bit handling. */
    432             if (!(op->flags & F_LOCAL) && (c & 0x80)) {       /* "parity" bit on? */
    433                 bits = 1;
    434                 mask = 1;
    435                 while (mask & 0x7f) {
    436                     if (mask & c)
    437                         bits++; /* count "1" bits */
    438                     mask <<= 1;
    439                 }
    440                 /* ... |= 2 - even, 1 - odd */
    441                 cp->parity |= 2 - (bits & 1);
    442             }
    443 
    444             /* Do erase, kill and end-of-line processing. */
    445             ascval = c & 0x7f;
    446             switch (ascval) {
    447             case CR:
    448             case NL:
    449                 *bp = '\0';             /* terminate logname */
    450                 cp->eol = ascval;       /* set end-of-line char */
    451                 break;
    452             case BS:
    453             case DEL:
    454 #ifdef ANCIENT_BS_KILL_CHARS
    455             case '#':
    456 #endif
    457                 cp->erase = ascval;     /* set erase character */
    458                 if (bp > logname) {
    459                     full_write(STDOUT_FILENO, erase[cp->parity], 3);
     469            switch (c) {
     470            case '\r':
     471            case '\n':
     472                *bp = '\0';
     473                G.eol = c;
     474                goto got_logname;
     475            case CTL('H'):
     476            case 0x7f:
     477                G.tty_attrs.c_cc[VERASE] = c;
     478                if (bp > G.line_buf) {
     479                    full_write(STDOUT_FILENO, "\010 \010", 3);
    460480                    bp--;
    461481                }
    462482                break;
    463483            case CTL('U'):
    464 #ifdef ANCIENT_BS_KILL_CHARS
    465             case '@':
    466 #endif
    467                 cp->kill = ascval;      /* set kill character */
    468                 while (bp > logname) {
    469                     full_write(STDOUT_FILENO, erase[cp->parity], 3);
     484                while (bp > G.line_buf) {
     485                    full_write(STDOUT_FILENO, "\010 \010", 3);
    470486                    bp--;
    471487                }
    472488                break;
     489            case CTL('C'):
    473490            case CTL('D'):
     491                finalize_tty_attrs();
    474492                exit(EXIT_SUCCESS);
     493            case '\0':
     494                /* BREAK. If we have speeds to try,
     495                 * return NULL (will switch speeds and return here) */
     496                if (G.numspeed > 1)
     497                    return NULL;
     498                /* fall through and ignore it */
    475499            default:
    476                 if (ascval < ' ') {
     500                if ((unsigned char)c < ' ') {
    477501                    /* ignore garbage characters */
    478                 } else if ((int)(bp - logname) >= size_logname - 1) {
    479                     bb_error_msg_and_die("input overrun");
    480                 } else {
    481                     full_write(STDOUT_FILENO, &c, 1); /* echo the character */
    482                     *bp++ = ascval; /* and store it */
     502                } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) {
     503                    /* echo and store the character */
     504                    full_write(STDOUT_FILENO, &c, 1);
     505                    *bp++ = c;
    483506                }
    484507                break;
    485508            }
    486         }
    487     }
    488     /* Handle names with upper case and no lower case. */
    489 
    490 #ifdef HANDLE_ALLCAPS
    491     cp->capslock = all_is_upcase(logname);
    492     if (cp->capslock) {
    493         for (bp = logname; *bp; bp++)
    494             if (isupper(*bp))
    495                 *bp = tolower(*bp);     /* map name to lower case */
    496     }
    497 #endif
    498     return logname;
    499 }
    500 
    501 /* termios_final - set the final tty mode bits */
    502 static void termios_final(struct options *op, struct termios *tp, struct chardata *cp)
    503 {
    504     /* General terminal-independent stuff. */
    505     tp->c_iflag |= IXON | IXOFF;    /* 2-way flow control */
    506     tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
    507     /* no longer| ECHOCTL | ECHOPRT */
    508     tp->c_oflag |= OPOST;
    509     /* tp->c_cflag = 0; */
    510     tp->c_cc[VINTR] = DEF_INTR;     /* default interrupt */
    511     tp->c_cc[VQUIT] = DEF_QUIT;     /* default quit */
    512     tp->c_cc[VEOF] = DEF_EOF;       /* default EOF character */
    513     tp->c_cc[VEOL] = DEF_EOL;
    514 #ifdef VSWTC
    515     tp->c_cc[VSWTC] = DEF_SWITCH;   /* default switch character */
    516 #endif
    517 
    518     /* Account for special characters seen in input. */
    519     if (cp->eol == CR) {
    520         tp->c_iflag |= ICRNL;   /* map CR in input to NL */
    521         tp->c_oflag |= ONLCR;   /* map NL in output to CR-NL */
    522     }
    523     tp->c_cc[VERASE] = cp->erase;   /* set erase character */
    524     tp->c_cc[VKILL] = cp->kill;     /* set kill character */
    525 
    526     /* Account for the presence or absence of parity bits in input. */
    527     switch (cp->parity) {
    528     case 0:                                 /* space (always 0) parity */
    529 // I bet most people go here - they use only 7-bit chars in usernames....
    530         break;
    531     case 1:                                 /* odd parity */
    532         tp->c_cflag |= PARODD;
    533         /* FALLTHROUGH */
    534     case 2:                                 /* even parity */
    535         tp->c_cflag |= PARENB;
    536         tp->c_iflag |= INPCK | ISTRIP;
    537         /* FALLTHROUGH */
    538     case (1 | 2):                           /* no parity bit */
    539         tp->c_cflag &= ~CSIZE;
    540         tp->c_cflag |= CS7;
    541 // FIXME: wtf? case 3: we saw both even and odd 8-bit bytes -
    542 // it's probably some umlauts etc, but definitely NOT 7-bit!!!
    543 // Entire parity detection madness here just begs for deletion...
    544         break;
    545     }
    546 
    547     /* Account for upper case without lower case. */
    548 #ifdef HANDLE_ALLCAPS
    549     if (cp->capslock) {
    550         tp->c_iflag |= IUCLC;
    551         tp->c_lflag |= XCASE;
    552         tp->c_oflag |= OLCUC;
    553     }
    554 #endif
    555     /* Optionally enable hardware flow control */
    556 #ifdef CRTSCTS
    557     if (op->flags & F_RTSCTS)
    558         tp->c_cflag |= CRTSCTS;
    559 #endif
    560 
    561     /* Finally, make the new settings effective */
    562     if (tcsetattr_stdin_TCSANOW(tp) < 0)
    563         bb_perror_msg_and_die("tcsetattr");
     509        } /* end of get char loop */
     510 got_logname: ;
     511    } while (G.line_buf[0] == '\0');  /* while logname is empty */
     512
     513    return G.line_buf;
     514}
     515
     516static void alarm_handler(int sig UNUSED_PARAM)
     517{
     518    finalize_tty_attrs();
     519    _exit(EXIT_SUCCESS);
    564520}
    565521
     
    568524{
    569525    int n;
    570     pid_t pid;
    571     char *fakehost = NULL;          /* Fake hostname for ut_host */
    572     char *logname;                  /* login name, given to /bin/login */
    573     /* Merging these into "struct local" may _seem_ to reduce
    574      * parameter passing, but today's gcc will inline
    575      * statics which are called once anyway, so don't do that */
    576     struct chardata chardata;       /* set by get_logname() */
    577     struct termios termios;         /* terminal mode bits */
    578     struct options options;
    579 
    580     chardata = init_chardata;
    581 
    582     memset(&options, 0, sizeof(options));
    583     options.login = _PATH_LOGIN;    /* default login program */
    584     options.tty = "tty1";           /* default tty line */
    585     options.initstring = "";        /* modem init string */
     526    pid_t pid, tsid;
     527    char *logname;
     528
     529    INIT_G();
     530    G.login = _PATH_LOGIN;    /* default login program */
    586531#ifdef ISSUE
    587     options.issue = ISSUE;          /* default issue file */
    588 #endif
    589 
    590     /* Parse command-line arguments. */
    591     parse_args(argv, &options, &fakehost);
    592 
    593     logmode = LOGMODE_NONE;
    594 
    595     /* Create new session, lose controlling tty, if any */
    596     /* docs/ctty.htm says:
    597      * "This is allowed only when the current process
    598      *  is not a process group leader" - is this a problem? */
    599     setsid();
    600     /* close stdio, and stray descriptors, just in case */
     532    G.issue = ISSUE;          /* default issue file */
     533#endif
     534    G.eol = '\r';
     535
     536    /* Parse command-line arguments */
     537    parse_args(argv);
     538
     539    /* Create new session and pgrp, lose controlling tty */
     540    pid = setsid();  /* this also gives us our pid :) */
     541    if (pid < 0) {
     542        int fd;
     543        /* :(
     544         * docs/ctty.htm says:
     545         * "This is allowed only when the current process
     546         *  is not a process group leader".
     547         * Thus, setsid() will fail if we _already_ are
     548         * a session leader - which is quite possible for getty!
     549         */
     550        pid = getpid();
     551        if (getsid(0) != pid) {
     552            //for debugging:
     553            //bb_perror_msg_and_die("setsid failed:"
     554            //  " pid %d ppid %d"
     555            //  " sid %d pgid %d",
     556            //  pid, getppid(),
     557            //  getsid(0), getpgid(0));
     558            bb_perror_msg_and_die("setsid");
     559        }
     560        /* Looks like we are already a session leader.
     561         * In this case (setsid failed) we may still have ctty,
     562         * and it may be different from tty we need to control!
     563         * If we still have ctty, on Linux ioctl(TIOCSCTTY)
     564         * (which we are going to use a bit later) always fails -
     565         * even if we try to take ctty which is already ours!
     566         * Try to drop old ctty now to prevent that.
     567         * Use O_NONBLOCK: old ctty may be a serial line.
     568         */
     569        fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
     570        if (fd >= 0) {
     571            /* TIOCNOTTY sends SIGHUP to the foreground
     572             * process group - which may include us!
     573             * Make sure to not die on it:
     574             */
     575            sighandler_t old = signal(SIGHUP, SIG_IGN);
     576            ioctl(fd, TIOCNOTTY);
     577            close(fd);
     578            signal(SIGHUP, old);
     579        }
     580    }
     581
     582    /* Close stdio, and stray descriptors, just in case */
    601583    n = xopen(bb_dev_null, O_RDWR);
    602584    /* dup2(n, 0); - no, we need to handle "getty - 9600" too */
     
    622604
    623605    /* Open the tty as standard input, if it is not "-" */
    624     /* If it's not "-" and not taken yet, it will become our ctty */
    625606    debug("calling open_tty\n");
    626     open_tty(options.tty);
    627     ndelay_off(0);
     607    open_tty();
     608    ndelay_off(STDIN_FILENO);
    628609    debug("duping\n");
    629     xdup2(0, 1);
    630     xdup2(0, 2);
     610    xdup2(STDIN_FILENO, 1);
     611    xdup2(STDIN_FILENO, 2);
     612
     613    /* Steal ctty if we don't have it yet */
     614    tsid = tcgetsid(STDIN_FILENO);
     615    if (tsid < 0 || pid != tsid) {
     616        if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) < 0)
     617            bb_perror_msg_and_die("TIOCSCTTY");
     618    }
     619
     620#ifdef __linux__
     621    /* Make ourself a foreground process group within our session */
     622    if (tcsetpgrp(STDIN_FILENO, pid) < 0)
     623        bb_perror_msg_and_die("tcsetpgrp");
     624#endif
    631625
    632626    /*
     
    638632     * 5 seconds seems to be a good value.
    639633     */
    640     if (tcgetattr(0, &termios) < 0)
     634    if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0)
    641635        bb_perror_msg_and_die("tcgetattr");
    642636
    643     pid = getpid();
    644 #ifdef __linux__
    645 // FIXME: do we need this? Otherwise "-" case seems to be broken...
    646     // /* Forcibly make fd 0 our controlling tty, even if another session
    647     //  * has it as a ctty. (Another session loses ctty). */
    648     // ioctl(0, TIOCSCTTY, (void*)1);
    649     /* Make ourself a foreground process group within our session */
    650     tcsetpgrp(0, pid);
    651 #endif
    652 
    653637    /* Update the utmp file. This tty is ours now! */
    654     update_utmp(pid, LOGIN_PROCESS, options.tty, "LOGIN", fakehost);
    655 
    656     /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
    657     debug("calling termios_init\n");
    658     termios_init(&termios, options.speeds[0], &options);
     638    update_utmp(pid, LOGIN_PROCESS, G.tty_name, "LOGIN", G.fakehost);
     639
     640    /* Initialize tty attrs (raw mode, eight-bit, blocking i/o) */
     641    debug("calling init_tty_attrs\n");
     642    init_tty_attrs(G.speeds[0]);
    659643
    660644    /* Write the modem init string and DON'T flush the buffers */
    661     if (options.flags & F_INITSTRING) {
     645    if (option_mask32 & F_INITSTRING) {
    662646        debug("writing init string\n");
    663         full_write1_str(options.initstring);
     647        full_write1_str(G.initstring);
    664648    }
    665649
    666650    /* Optionally detect the baud rate from the modem status message */
    667651    debug("before autobaud\n");
    668     if (options.flags & F_PARSE)
    669         auto_baud(line_buf, sizeof(line_buf), &termios);
     652    if (option_mask32 & F_PARSE)
     653        auto_baud();
    670654
    671655    /* Set the optional timer */
    672     alarm(options.timeout); /* if 0, alarm is not set */
     656    signal(SIGALRM, alarm_handler);
     657    alarm(G.timeout); /* if 0, alarm is not set */
    673658
    674659    /* Optionally wait for CR or LF before writing /etc/issue */
    675     if (options.flags & F_WAITCRLF) {
     660    if (option_mask32 & F_WAITCRLF) {
    676661        char ch;
    677 
    678662        debug("waiting for cr-lf\n");
    679663        while (safe_read(STDIN_FILENO, &ch, 1) == 1) {
    680664            debug("read %x\n", (unsigned char)ch);
    681             ch &= 0x7f;                     /* strip "parity bit" */
    682665            if (ch == '\n' || ch == '\r')
    683666                break;
     
    686669
    687670    logname = NULL;
    688     if (!(options.flags & F_NOPROMPT)) {
    689         /* NB:termios_init already set line speed
    690          * to options.speeds[0] */
     671    if (!(option_mask32 & F_NOPROMPT)) {
     672        /* NB: init_tty_attrs already set line speed
     673         * to G.speeds[0] */
    691674        int baud_index = 0;
    692675
    693676        while (1) {
    694             /* Read the login name. */
     677            /* Read the login name */
    695678            debug("reading login name\n");
    696             logname = get_logname(line_buf, sizeof(line_buf),
    697                     &options, &chardata);
     679            logname = get_logname();
    698680            if (logname)
    699681                break;
    700             /* we are here only if options.numspeed > 1 */
    701             baud_index = (baud_index + 1) % options.numspeed;
    702             cfsetispeed(&termios, options.speeds[baud_index]);
    703             cfsetospeed(&termios, options.speeds[baud_index]);
    704             tcsetattr_stdin_TCSANOW(&termios);
     682            /* We are here only if G.numspeed > 1 */
     683            baud_index = (baud_index + 1) % G.numspeed;
     684            cfsetspeed(&G.tty_attrs, G.speeds[baud_index]);
     685            set_tty_attrs();
    705686        }
    706687    }
    707688
    708     /* Disable timer. */
     689    /* Disable timer */
    709690    alarm(0);
    710691
    711     /* Finalize the termios settings. */
    712     termios_final(&options, &termios, &chardata);
    713 
    714     /* Now the newline character should be properly written. */
    715     full_write(STDOUT_FILENO, "\n", 1);
    716 
    717     /* Let the login program take care of password validation. */
     692    finalize_tty_attrs();
     693
     694    /* Let the login program take care of password validation */
    718695    /* We use PATH because we trust that root doesn't set "bad" PATH,
    719      * and getty is not suid-root applet. */
     696     * and getty is not suid-root applet */
    720697    /* With -n, logname == NULL, and login will ask for username instead */
    721     BB_EXECLP(options.login, options.login, "--", logname, NULL);
    722     bb_error_msg_and_die("can't execute '%s'", options.login);
    723 }
     698    BB_EXECLP(G.login, G.login, "--", logname, NULL);
     699    bb_error_msg_and_die("can't execute '%s'", G.login);
     700}
  • branches/3.2/mindi-busybox/loginutils/login.c

    r2725 r3232  
    33 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
     5
     6//usage:#define login_trivial_usage
     7//usage:       "[-p] [-h HOST] [[-f] USER]"
     8//usage:#define login_full_usage "\n\n"
     9//usage:       "Begin a new session on the system\n"
     10//usage:     "\n    -f  Don't authenticate (user already authenticated)"
     11//usage:     "\n    -h  Name of the remote host"
     12//usage:     "\n    -p  Preserve environment"
     13
    514#include "libbb.h"
    615#include <syslog.h>
    7 #if ENABLE_FEATURE_UTMP
    8 # include <utmp.h> /* USER_PROCESS */
    9 #endif
    1016#include <sys/resource.h>
    1117
     
    3238    TIMEOUT = 60,
    3339    EMPTY_USERNAME_COUNT = 10,
    34     USERNAME_SIZE = 32,
     40    /* Some users found 32 chars limit to be too low: */
     41    USERNAME_SIZE = 64,
    3542    TTYNAME_SIZE = 32,
    3643};
    3744
    38 static char* short_tty;
     45struct globals {
     46    struct termios tty_attrs;
     47} FIX_ALIASING;
     48#define G (*(struct globals*)&bb_common_bufsiz1)
     49#define INIT_G() do { } while (0)
     50
    3951
    4052#if ENABLE_FEATURE_NOLOGIN
     
    6981
    7082#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
    71 static int check_securetty(void)
     83static int check_securetty(const char *short_tty)
    7284{
    7385    char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */
     
    8496}
    8597#else
    86 static ALWAYS_INLINE int check_securetty(void) { return 1; }
     98static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; }
    8799#endif
    88100
     
    137149#endif
    138150
     151#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM
     152static void login_pam_end(pam_handle_t *pamh)
     153{
     154    int pamret;
     155
     156    pamret = pam_setcred(pamh, PAM_DELETE_CRED);
     157    if (pamret != PAM_SUCCESS) {
     158        bb_error_msg("pam_%s failed: %s (%d)", "setcred",
     159            pam_strerror(pamh, pamret), pamret);
     160    }
     161    pamret = pam_close_session(pamh, 0);
     162    if (pamret != PAM_SUCCESS) {
     163        bb_error_msg("pam_%s failed: %s (%d)", "close_session",
     164            pam_strerror(pamh, pamret), pamret);
     165    }
     166    pamret = pam_end(pamh, pamret);
     167    if (pamret != PAM_SUCCESS) {
     168        bb_error_msg("pam_%s failed: %s (%d)", "end",
     169            pam_strerror(pamh, pamret), pamret);
     170    }
     171}
     172#endif /* ENABLE_PAM */
     173
    139174static void get_username_or_die(char *buf, int size_buf)
    140175{
     
    180215static void alarm_handler(int sig UNUSED_PARAM)
    181216{
    182     /* This is the escape hatch!  Poor serial line users and the like
     217    /* This is the escape hatch! Poor serial line users and the like
    183218     * arrive here when their connection is broken.
    184219     * We don't want to block here */
    185     ndelay_on(1);
    186     printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
     220    ndelay_on(STDOUT_FILENO);
     221    /* Test for correct attr restoring:
     222     * run "getty 0 -" from a shell, enter bogus username, stop at
     223     * password prompt, let it time out. Without the tcsetattr below,
     224     * when you are back at shell prompt, echo will be still off.
     225     */
     226    tcsetattr_stdin_TCSANOW(&G.tty_attrs);
     227    printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT);
    187228    fflush_all();
    188229    /* unix API is brain damaged regarding O_NONBLOCK,
    189230     * we should undo it, or else we can affect other processes */
    190     ndelay_off(1);
     231    ndelay_off(STDOUT_FILENO);
    191232    _exit(EXIT_SUCCESS);
    192233}
     
    202243    char *fromhost;
    203244    char username[USERNAME_SIZE];
    204     const char *shell;
    205245    int run_by_root;
    206246    unsigned opt;
     
    210250    char *opt_user = opt_user; /* for compiler */
    211251    char *full_tty;
     252    char *short_tty;
    212253    IF_SELINUX(security_context_t user_sid = NULL;)
    213254#if ENABLE_PAM
     
    218259    struct passwd pwdstruct;
    219260    char pwdbuf[256];
    220 #endif
    221 
    222     username[0] = '\0';
    223     signal(SIGALRM, alarm_handler);
    224     alarm(TIMEOUT);
     261    char **pamenv;
     262#endif
     263#if ENABLE_LOGIN_SESSION_AS_CHILD
     264    pid_t child_pid;
     265#endif
     266
     267    INIT_G();
    225268
    226269    /* More of suid paranoia if called by non-root: */
     
    234277    bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
    235278
     279    username[0] = '\0';
    236280    opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
    237281    if (opt & LOGIN_OPT_f) {
     
    244288        safe_strncpy(username, argv[0], sizeof(username));
    245289
    246     /* Let's find out and memorize our tty */
    247     if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO))
     290    /* Save tty attributes - and by doing it, check that it's indeed a tty */
     291    if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0
     292     || !isatty(STDOUT_FILENO)
     293     /*|| !isatty(STDERR_FILENO) - no, guess some people might want to redirect this */
     294    ) {
    248295        return EXIT_FAILURE;  /* Must be a terminal */
     296    }
     297
     298    /* We install timeout handler only _after_ we saved G.tty_attrs */
     299    signal(SIGALRM, alarm_handler);
     300    alarm(TIMEOUT);
     301
     302    /* Find out and memorize our tty name */
    249303    full_tty = xmalloc_ttyname(STDIN_FILENO);
    250304    if (!full_tty)
     
    282336            goto pam_auth_failed;
    283337        }
    284         pamret = pam_authenticate(pamh, 0);
    285         if (pamret != PAM_SUCCESS) {
    286             failed_msg = "authenticate";
    287             goto pam_auth_failed;
    288             /* TODO: or just "goto auth_failed"
    289              * since user seems to enter wrong password
    290              * (in this case pamret == 7)
    291              */
     338        /* set RHOST */
     339        if (opt_host) {
     340            pamret = pam_set_item(pamh, PAM_RHOST, opt_host);
     341            if (pamret != PAM_SUCCESS) {
     342                failed_msg = "set_item(RHOST)";
     343                goto pam_auth_failed;
     344            }
     345        }
     346        if (!(opt & LOGIN_OPT_f)) {
     347            pamret = pam_authenticate(pamh, 0);
     348            if (pamret != PAM_SUCCESS) {
     349                failed_msg = "authenticate";
     350                goto pam_auth_failed;
     351                /* TODO: or just "goto auth_failed"
     352                 * since user seems to enter wrong password
     353                 * (in this case pamret == 7)
     354                 */
     355            }
    292356        }
    293357        /* check that the account is healthy */
     
    346410            break; /* -f USER: success without asking passwd */
    347411
    348         if (pw->pw_uid == 0 && !check_securetty())
     412        if (pw->pw_uid == 0 && !check_securetty(short_tty))
    349413            goto auth_failed;
    350414
     
    353417            break;
    354418 fake_it:
    355         /* authorization takes place here */
     419        /* Password reading and authorization takes place here.
     420         * Note that reads (in no-echo mode) trash tty attributes.
     421         * If we get interrupted by SIGALRM, we need to restore attrs.
     422         */
    356423        if (correct_password(pw))
    357424            break;
     
    359426 auth_failed:
    360427        opt &= ~LOGIN_OPT_f;
    361         bb_do_delay(FAIL_DELAY);
     428        bb_do_delay(LOGIN_FAIL_DELAY);
    362429        /* TODO: doesn't sound like correct English phrase to me */
    363430        puts("Login incorrect");
     
    380447        die_if_nologin();
    381448
    382     IF_SELINUX(initselinux(username, full_tty, &user_sid));
     449#if ENABLE_LOGIN_SESSION_AS_CHILD
     450    child_pid = vfork();
     451    if (child_pid != 0) {
     452        if (child_pid < 0)
     453            bb_perror_msg("vfork");
     454        else {
     455            if (safe_waitpid(child_pid, NULL, 0) == -1)
     456                bb_perror_msg("waitpid");
     457            update_utmp(child_pid, DEAD_PROCESS, NULL, NULL, NULL);
     458        }
     459        IF_PAM(login_pam_end(pamh);)
     460        return 0;
     461    }
     462#endif
     463
     464    IF_SELINUX(initselinux(username, full_tty, &user_sid);)
    383465
    384466    /* Try these, but don't complain if they fail.
     
    394476
    395477    change_identity(pw);
    396     shell = pw->pw_shell;
    397     if (!shell || !shell[0])
    398         shell = DEFAULT_SHELL;
    399     setup_environment(shell,
     478    setup_environment(pw->pw_shell,
    400479            (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV,
    401480            pw);
     481
     482#if ENABLE_PAM
     483    /* Modules such as pam_env will setup the PAM environment,
     484     * which should be copied into the new environment. */
     485    pamenv = pam_getenvlist(pamh);
     486    if (pamenv) while (*pamenv) {
     487        putenv(*pamenv);
     488        pamenv++;
     489    }
     490#endif
    402491
    403492    motd();
     
    435524
    436525    /* Exec login shell with no additional parameters */
    437     run_shell(shell, 1, NULL, NULL);
     526    run_shell(pw->pw_shell, 1, NULL, NULL);
    438527
    439528    /* return EXIT_FAILURE; - not reached */
  • branches/3.2/mindi-busybox/loginutils/passwd.c

    r2725 r3232  
    33 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
     5
     6//usage:#define passwd_trivial_usage
     7//usage:       "[OPTIONS] [USER]"
     8//usage:#define passwd_full_usage "\n\n"
     9//usage:       "Change USER's password (default: current user)"
     10//usage:     "\n"
     11//usage:     "\n    -a ALG  Encryption method"
     12//usage:     "\n    -d  Set password to ''"
     13//usage:     "\n    -l  Lock (disable) account"
     14//usage:     "\n    -u  Unlock (enable) account"
     15
    516#include "libbb.h"
    617#include <syslog.h>
     18#include <sys/resource.h> /* setrlimit */
    719
    820static void nuke_str(char *str)
     
    1123}
    1224
    13 static char* new_password(const struct passwd *pw, uid_t myuid, int algo)
     25static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
    1426{
    15     char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
     27    char salt[MAX_PW_SALT_LEN];
    1628    char *orig = (char*)"";
    1729    char *newp = NULL;
     
    1931    char *ret = NULL; /* failure so far */
    2032
    21     if (myuid && pw->pw_passwd[0]) {
     33    if (myuid != 0 && pw->pw_passwd[0]) {
    2234        char *encrypted;
    2335
     
    2739        encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
    2840        if (strcmp(encrypted, pw->pw_passwd) != 0) {
    29             syslog(LOG_WARNING, "incorrect password for %s",
    30                 pw->pw_name);
    31             bb_do_delay(FAIL_DELAY);
     41            syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
     42            bb_do_delay(LOGIN_FAIL_DELAY);
    3243            puts("Incorrect password");
    3344            goto err_ret;
    3445        }
    35         if (ENABLE_FEATURE_CLEAN_UP) free(encrypted);
     46        if (ENABLE_FEATURE_CLEAN_UP)
     47            free(encrypted);
    3648    }
    3749    orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
     
    4153    newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
    4254    if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
    43      && obscure(orig, newp, pw) && myuid)
     55     && obscure(orig, newp, pw)
     56     && myuid != 0
     57    ) {
    4458        goto err_ret; /* non-root is not allowed to have weak passwd */
     59    }
    4560
    4661    cp = bb_ask_stdin("Retype password: ");
    4762    if (!cp)
    4863        goto err_ret;
    49     if (strcmp(cp, newp)) {
     64    if (strcmp(cp, newp) != 0) {
    5065        puts("Passwords don't match");
    5166        goto err_ret;
    5267    }
    5368
    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     }
     69    crypt_make_pw_salt(salt, algo);
     70
    5971    /* pw_encrypt returns malloced str */
    6072    ret = pw_encrypt(newp, salt, 1);
     
    6476    nuke_str(orig);
    6577    if (ENABLE_FEATURE_CLEAN_UP) free(orig);
     78
    6679    nuke_str(newp);
    6780    if (ENABLE_FEATURE_CLEAN_UP) free(newp);
     81
    6882    nuke_str(cp);
    6983    return ret;
     
    7488{
    7589    enum {
    76         OPT_algo = 0x1, /* -a - password algorithm */
    77         OPT_lock = 0x2, /* -l - lock account */
    78         OPT_unlock = 0x4, /* -u - unlock account */
    79         OPT_delete = 0x8, /* -d - delete password */
    80         OPT_lud = 0xe,
    81         STATE_ALGO_md5 = 0x10,
    82         //STATE_ALGO_des = 0x20, not needed yet
     90        OPT_algo   = (1 << 0), /* -a - password algorithm */
     91        OPT_lock   = (1 << 1), /* -l - lock account */
     92        OPT_unlock = (1 << 2), /* -u - unlock account */
     93        OPT_delete = (1 << 3), /* -d - delete password */
     94        OPT_lud    = OPT_lock | OPT_unlock | OPT_delete,
    8395    };
    8496    unsigned opt;
    8597    int rc;
    86     const char *opt_a = "";
     98    const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
    8799    const char *filename;
    88100    char *myname;
     
    105117    argv += optind;
    106118
    107     if (strcasecmp(opt_a, "des") != 0) /* -a */
    108         opt |= STATE_ALGO_md5;
    109     //else
    110     //  opt |= STATE_ALGO_des;
    111119    myuid = getuid();
    112120    /* -l, -u, -d require root priv and username argument */
    113     if ((opt & OPT_lud) && (myuid || !argv[0]))
     121    if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
    114122        bb_show_usage();
    115123
     
    119127
    120128    pw = xgetpwnam(name);
    121     if (myuid && pw->pw_uid != myuid) {
     129    if (myuid != 0 && pw->pw_uid != myuid) {
    122130        /* LOGMODE_BOTH */
    123131        bb_error_msg_and_die("%s can't change password for %s", myname, name);
     
    153161    c = pw->pw_passwd[0] - '!';
    154162    if (!(opt & OPT_lud)) {
    155         if (myuid && !c) { /* passwd starts with '!' */
     163        if (myuid != 0 && !c) { /* passwd starts with '!' */
    156164            /* LOGMODE_BOTH */
    157165            bb_error_msg_and_die("can't change "
     
    159167        }
    160168        printf("Changing password for %s\n", name);
    161         newp = new_password(pw, myuid, opt & STATE_ALGO_md5);
     169        newp = new_password(pw, myuid, opt_a);
    162170        if (!newp) {
    163171            logmode = LOGMODE_STDIO;
     
    165173        }
    166174    } else if (opt & OPT_lock) {
    167         if (!c) goto skip; /* passwd starts with '!' */
     175        if (!c)
     176            goto skip; /* passwd starts with '!' */
    168177        newp = xasprintf("!%s", pw->pw_passwd);
    169178    } else if (opt & OPT_unlock) {
    170         if (c) goto skip; /* not '!' */
     179        if (c)
     180            goto skip; /* not '!' */
    171181        /* pw->pw_passwd points to static storage,
    172182         * strdup'ing to avoid nasty surprizes */
    173183        newp = xstrdup(&pw->pw_passwd[1]);
    174184    } else if (opt & OPT_delete) {
    175         //newp = xstrdup("");
    176185        newp = (char*)"";
    177186    }
     
    190199    filename = bb_path_shadow_file;
    191200    rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
    192     if (rc == 0) /* no lines updated, no errors detected */
     201    if (rc > 0)
     202        /* password in /etc/shadow was updated */
     203        newp = (char*) "x";
     204    if (rc >= 0)
     205        /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
    193206#endif
    194207    {
     
    198211    /* LOGMODE_BOTH */
    199212    if (rc < 0)
    200         bb_error_msg_and_die("can't update password file %s",
    201                 filename);
     213        bb_error_msg_and_die("can't update password file %s", filename);
    202214    bb_info_msg("Password for %s changed by %s", name, myname);
    203215
    204     //if (ENABLE_FEATURE_CLEAN_UP) free(newp);
     216    /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
    205217 skip:
    206218    if (!newp) {
     
    208220            name, (opt & OPT_unlock) ? "un" : "");
    209221    }
    210     if (ENABLE_FEATURE_CLEAN_UP) free(myname);
     222
     223    if (ENABLE_FEATURE_CLEAN_UP)
     224        free(myname);
    211225    return 0;
    212226}
  • branches/3.2/mindi-busybox/loginutils/su.c

    r2725 r3232  
    88#include "libbb.h"
    99#include <syslog.h>
     10
     11//usage:#define su_trivial_usage
     12//usage:       "[OPTIONS] [-] [USER]"
     13//usage:#define su_full_usage "\n\n"
     14//usage:       "Run shell under USER (by default, root)\n"
     15//usage:     "\n    -,-l    Clear environment, run shell as login shell"
     16//usage:     "\n    -p,-m   Do not set new $HOME, $SHELL, $USER, $LOGNAME"
     17//usage:     "\n    -c CMD  Command to pass to 'sh -c'"
     18//usage:     "\n    -s SH   Shell to use instead of user's default"
    1019
    1120#if ENABLE_FEATURE_SU_CHECKS_SHELLS
     
    4352    uid_t cur_uid = getuid();
    4453    const char *tty;
     54#if ENABLE_FEATURE_UTMP
    4555    char user_buf[64];
     56#endif
    4657    const char *old_user;
    4758
     
    103114    }
    104115
    105     /* Make sure pw->pw_shell is non-NULL.  It may be NULL when NEW_USER
    106      * is a username that is retrieved via NIS (YP), that doesn't have
    107      * a default shell listed.  */
    108     if (!pw->pw_shell || !pw->pw_shell[0])
    109         pw->pw_shell = (char *)DEFAULT_SHELL;
    110 
    111116#if ENABLE_FEATURE_SU_CHECKS_SHELLS
    112     if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) {
     117    if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) {
    113118        /* The user being su'd to has a nonstandard shell, and so is
    114119         * probably a uucp account or has restricted access.  Don't
     
    116121         * shell.  */
    117122        bb_error_msg("using restricted shell");
    118         opt_shell = NULL;
     123        opt_shell = NULL; /* ignore -s PROG */
    119124    }
    120125    /* else: user can run whatever he wants via "su -s PROG USER".
     
    127132    setup_environment(opt_shell,
    128133            ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV)
    129             + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV),
     134            + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV)
     135            + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR),
    130136            pw);
    131137    IF_SELINUX(set_current_security_context(NULL);)
  • branches/3.2/mindi-busybox/loginutils/sulogin.c

    r2725 r3232  
    55 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    66 */
     7
     8//usage:#define sulogin_trivial_usage
     9//usage:       "[-t N] [TTY]"
     10//usage:#define sulogin_full_usage "\n\n"
     11//usage:       "Single user login\n"
     12//usage:     "\n    -t N    Timeout"
    713
    814#include "libbb.h"
     
    8995            break;
    9096        }
    91         bb_do_delay(FAIL_DELAY);
    92         bb_error_msg("login incorrect");
     97        bb_do_delay(LOGIN_FAIL_DELAY);
     98        bb_info_msg("Login incorrect");
    9399    }
    94100    memset(cp, 0, strlen(cp));
  • branches/3.2/mindi-busybox/loginutils/vlock.c

    r2725 r3232  
    1515/* Fixed by Erik Andersen to do passwords the tinylogin way...
    1616 * It now works with md5, sha1, etc passwords. */
     17
     18//usage:#define vlock_trivial_usage
     19//usage:       "[-a]"
     20//usage:#define vlock_full_usage "\n\n"
     21//usage:       "Lock a virtual terminal. A password is required to unlock.\n"
     22//usage:     "\n    -a  Lock all VTs"
    1723
    1824#include "libbb.h"
     
    94100    tcsetattr_stdin_TCSANOW(&term);
    95101
    96     do {
     102    while (1) {
    97103        printf("Virtual console%s locked by %s.\n",
    98                 option_mask32 /*o_lock_all*/ ? "s" : "",
    99                 pw->pw_name);
     104                /* "s" if -a, else "": */ "s" + !option_mask32,
     105                pw->pw_name
     106        );
    100107        if (correct_password(pw)) {
    101108            break;
    102109        }
    103         bb_do_delay(FAIL_DELAY);
    104         puts("Password incorrect");
    105     } while (1);
     110        bb_do_delay(LOGIN_FAIL_DELAY);
     111        puts("Incorrect password");
     112    }
    106113
    107114#ifdef __linux__
Note: See TracChangeset for help on using the changeset viewer.