Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (8 years ago)
Author:
bruno
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/loginutils/adduser.c

    r1765 r2725  
    66 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
    77 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    10 
    1110#include "libbb.h"
    1211
     12#if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
     13#error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
     14#endif
     15
     16/* #define OPT_HOME           (1 << 0) */ /* unused */
     17/* #define OPT_GECOS          (1 << 1) */ /* unused */
     18#define OPT_SHELL          (1 << 2)
     19#define OPT_GID            (1 << 3)
    1320#define OPT_DONT_SET_PASS  (1 << 4)
     21#define OPT_SYSTEM_ACCOUNT (1 << 5)
    1422#define OPT_DONT_MAKE_HOME (1 << 6)
    15 
    16 
     23#define OPT_UID            (1 << 7)
     24
     25/* We assume UID_T_MAX == INT_MAX */
    1726/* remix */
    18 /* EDR recoded such that the uid may be passed in *p */
    19 static int passwd_study(const char *filename, struct passwd *p)
    20 {
    21     enum { min = 500, max = 65000 };
    22     FILE *passwd;
    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");
    30 
    31     /* EDR if uid is out of bounds, set to min */
    32     if ((p->pw_uid > max) || (p->pw_uid < min))
    33         p->pw_uid = min;
    34 
    35     /* stuff to do:
    36      * make sure login isn't taken;
    37      * find free uid and gid;
    38      */
    39     while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) {
    40         if (strcmp(pw.pw_name, p->pw_name) == 0) {
    41             /* return 0; */
    42             return 1;
    43         }
    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;
    47         }
    48     }
    49 
    50     if (p->pw_gid == 0) {
    51         /* EDR check for an already existing gid */
    52         while (getgrgid(p->pw_uid) != NULL)
    53             p->pw_uid++;
    54 
    55         /* EDR also check for an existing group definition */
    56         if (getgrnam(p->pw_name) != NULL)
    57             return 3;
    58 
    59         /* EDR create new gid always = uid */
    60         p->pw_gid = p->pw_uid;
    61     }
    62 
    63     /* EDR bounds check */
    64     if ((p->pw_uid > max) || (p->pw_uid < min))
    65         return 2;
    66 
    67     /* return 1; */
    68     return 0;
    69 }
    70 
    71 static void addgroup_wrapper(struct passwd *p)
     27/* recoded such that the uid may be passed in *p */
     28static void passwd_study(struct passwd *p)
     29{
     30    int max = UINT_MAX;
     31
     32    if (getpwnam(p->pw_name)) {
     33        bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
     34        /* this format string is reused in adduser and addgroup */
     35    }
     36
     37    if (!(option_mask32 & OPT_UID)) {
     38        if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
     39            p->pw_uid = CONFIG_FIRST_SYSTEM_ID;
     40            max = CONFIG_LAST_SYSTEM_ID;
     41        } else {
     42            p->pw_uid = CONFIG_LAST_SYSTEM_ID + 1;
     43            max = 64999;
     44        }
     45    }
     46    /* check for a free uid (and maybe gid) */
     47    while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
     48        if (option_mask32 & OPT_UID) {
     49            /* -u N, cannot pick uid other than N: error */
     50            bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid));
     51            /* this format string is reused in adduser and addgroup */
     52        }
     53        if (p->pw_uid == max) {
     54            bb_error_msg_and_die("no %cids left", 'u');
     55        }
     56        p->pw_uid++;
     57    }
     58
     59    if (p->pw_gid == (gid_t)-1) {
     60        p->pw_gid = p->pw_uid; /* new gid = uid */
     61        if (getgrnam(p->pw_name)) {
     62            bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name);
     63            /* this format string is reused in adduser and addgroup */
     64        }
     65    }
     66}
     67
     68static void addgroup_wrapper(struct passwd *p, const char *group_name)
    7269{
    7370    char *cmd;
    7471
    75     cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
     72    if (group_name) /* Add user to existing group */
     73        cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name);
     74    else    /* Add user to his own group with the first free gid found in passwd_study */
     75        cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
     76    /* Warning: to be compatible with external addgroup programs we should use --gid instead */
    7677    system(cmd);
    7778    free(cmd);
    7879}
    7980
    80 static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
     81static void passwd_wrapper(const char *login) NORETURN;
    8182
    8283static void passwd_wrapper(const char *login)
    8384{
    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);
    88 }
    89 
    90 /* putpwent(3) remix */
    91 static int adduser(struct passwd *p)
    92 {
    93     FILE *file;
    94     int addgroup = !p->pw_gid;
    95 
    96     /* make sure everything is kosher and setup uid && gid */
    97     file = xfopen(bb_path_passwd_file, "a");
    98     fseek(file, 0, SEEK_END);
    99 
    100     switch (passwd_study(bb_path_passwd_file, p)) {
    101         case 1:
    102             bb_error_msg_and_die("%s: login already in use", p->pw_name);
    103         case 2:
    104             bb_error_msg_and_die("illegal uid or no uids left");
    105         case 3:
    106             bb_error_msg_and_die("%s: group name already in use", p->pw_name);
    107     }
    108 
    109     /* add to passwd */
    110     if (putpwent(p, file) == -1) {
    111         bb_perror_nomsg_and_die();
    112     }
    113     /* Do fclose even if !ENABLE_FEATURE_CLEAN_UP.
    114      * We will exec passwd, files must be flushed & closed before that! */
    115     fclose(file);
    116 
    117 #if ENABLE_FEATURE_SHADOWPASSWDS
    118     /* add to shadow if necessary */
    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     }
    130 #endif
    131 
    132     /* add to group */
    133     /* addgroup should be responsible for dealing w/ gshadow */
    134     /* if using a pre-existing group, don't create one */
    135     if (addgroup) addgroup_wrapper(p);
    136 
    137     /* Clear the umask for this process so it doesn't
    138      * screw up the permissions on the mkdir and chown. */
    139     umask(0);
    140     if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
    141         /* Set the owner and group so it is owned by the new user,
    142            then fix up the permissions to 2755. Can't do it before
    143            since chown will clear the setgid bit */
    144         if (mkdir(p->pw_dir, 0755)
    145         || chown(p->pw_dir, p->pw_uid, p->pw_gid)
    146         || chmod(p->pw_dir, 02755)) {
    147             bb_perror_msg("%s", p->pw_dir);
    148         }
    149     }
    150 
    151     if (!(option_mask32 & OPT_DONT_SET_PASS)) {
    152         /* interactively set passwd */
    153         passwd_wrapper(p->pw_name);
    154     }
    155 
    156     return 0;
    157 }
     85    BB_EXECLP("passwd", "passwd", login, NULL);
     86    bb_error_msg_and_die("can't execute passwd, you must set password manually");
     87}
     88
     89#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
     90static const char adduser_longopts[] ALIGN1 =
     91        "home\0"                Required_argument "h"
     92        "gecos\0"               Required_argument "g"
     93        "shell\0"               Required_argument "s"
     94        "ingroup\0"             Required_argument "G"
     95        "disabled-password\0"   No_argument       "D"
     96        "empty-password\0"      No_argument       "D"
     97        "system\0"              No_argument       "S"
     98        "no-create-home\0"      No_argument       "H"
     99        "uid\0"                 Required_argument "u"
     100        ;
     101#endif
    158102
    159103/*
    160104 * adduser will take a login_name as its first parameter.
    161  *
    162  * home
    163  * shell
    164  * gecos
    165  *
     105 * home, shell, gecos:
    166106 * can be customized via command-line parameters.
    167107 */
    168 int adduser_main(int argc, char **argv);
    169 int adduser_main(int argc, char **argv)
     108int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     109int adduser_main(int argc UNUSED_PARAM, char **argv)
    170110{
    171111    struct passwd pw;
    172112    const char *usegroup = NULL;
     113    char *p;
     114    unsigned opts;
     115
     116#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
     117    applet_long_options = adduser_longopts;
     118#endif
    173119
    174120    /* got root? */
     
    182128
    183129    /* 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);
     130    /* disable interactive passwd for system accounts */
     131    opt_complementary = "=1:SD:u+";
     132    if (sizeof(pw.pw_uid) == sizeof(int)) {
     133        opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
     134    } else {
     135        unsigned uid;
     136        opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid);
     137        if (opts & OPT_UID) {
     138            pw.pw_uid = uid;
     139        }
     140    }
    186141    argv += optind;
    187142
    188     /* create a passwd struct */
     143    /* fill in the passwd struct */
    189144    pw.pw_name = argv[0];
     145    die_if_bad_username(pw.pw_name);
    190146    if (!pw.pw_dir) {
    191147        /* create string for $HOME if not specified already */
     
    193149    }
    194150    pw.pw_passwd = (char *)"x";
    195     pw.pw_uid = 0;
    196     pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */
    197 
    198     /* grand finale */
    199     return adduser(&pw);
    200 }
     151    if (opts & OPT_SYSTEM_ACCOUNT) {
     152        if (!usegroup) {
     153            usegroup = "nogroup";
     154        }
     155        if (!(opts & OPT_SHELL)) {
     156            pw.pw_shell = (char *) "/bin/false";
     157        }
     158    }
     159    pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
     160
     161    /* make sure everything is kosher and setup uid && maybe gid */
     162    passwd_study(&pw);
     163
     164    p = xasprintf("x:%u:%u:%s:%s:%s",
     165            (unsigned) pw.pw_uid, (unsigned) pw.pw_gid,
     166            pw.pw_gecos, pw.pw_dir, pw.pw_shell);
     167    if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) {
     168        return EXIT_FAILURE;
     169    }
     170    if (ENABLE_FEATURE_CLEAN_UP)
     171        free(p);
     172
     173#if ENABLE_FEATURE_SHADOWPASSWDS
     174    /* /etc/shadow fields:
     175     * 1. username
     176     * 2. encrypted password
     177     * 3. last password change (unix date (unix time/24*60*60))
     178     * 4. minimum days required between password changes
     179     * 5. maximum days password is valid
     180     * 6. days before password is to expire that user is warned
     181     * 7. days after password expires that account is disabled
     182     * 8. unix date when login expires (i.e. when it may no longer be used)
     183     */
     184    /* fields:     2 3  4 5     6 78 */
     185    p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL)) / (24*60*60));
     186    /* ignore errors: if file is missing we suppose admin doesn't want it */
     187    update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL);
     188    if (ENABLE_FEATURE_CLEAN_UP)
     189        free(p);
     190#endif
     191
     192    /* add to group */
     193    addgroup_wrapper(&pw, usegroup);
     194
     195    /* clear the umask for this process so it doesn't
     196     * screw up the permissions on the mkdir and chown. */
     197    umask(0);
     198    if (!(opts & OPT_DONT_MAKE_HOME)) {
     199        /* set the owner and group so it is owned by the new user,
     200         * then fix up the permissions to 2755. Can't do it before
     201         * since chown will clear the setgid bit */
     202        int mkdir_err = mkdir(pw.pw_dir, 0755);
     203        if (mkdir_err == 0) {
     204            /* New home. Copy /etc/skel to it */
     205            const char *args[] = {
     206                "chown", "-R",
     207                xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid),
     208                pw.pw_dir, NULL
     209            };
     210            /* Be silent on any errors (like: no /etc/skel) */
     211            logmode = LOGMODE_NONE;
     212            copy_file("/etc/skel", pw.pw_dir, FILEUTILS_RECUR);
     213            logmode = LOGMODE_STDIO;
     214            chown_main(4, (char**)args);
     215        }
     216        if ((mkdir_err != 0 && errno != EEXIST)
     217         || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) != 0
     218         || chmod(pw.pw_dir, 02755) != 0 /* set setgid bit on homedir */
     219        ) {
     220            bb_simple_perror_msg(pw.pw_dir);
     221        }
     222    }
     223
     224    if (!(opts & OPT_DONT_SET_PASS)) {
     225        /* interactively set passwd */
     226        passwd_wrapper(pw.pw_name);
     227    }
     228
     229    return EXIT_SUCCESS;
     230}
Note: See TracChangeset for help on using the changeset viewer.