Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/loginutils


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

Location:
branches/stable/mindi-busybox/loginutils
Files:
2 deleted
10 edited
3 copied

Legend:

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

    r902 r1770  
    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/stable/mindi-busybox/loginutils/addgroup.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/adduser.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/deluser.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/getty.c

    r902 r1770  
    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/stable/mindi-busybox/loginutils/login.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/passwd.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/su.c

    r821 r1770  
    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/stable/mindi-busybox/loginutils/sulogin.c

    r902 r1770  
    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/stable/mindi-busybox/loginutils/vlock.c

    r821 r1770  
    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.