busybox/loginutils/addgroup.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * addgroup - add groups to /etc/group and /etc/gshadow
   4 *
   5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
   6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
   7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
   8 *
   9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10 */
  11//config:config ADDGROUP
  12//config:       bool "addgroup (8.6 kb)"
  13//config:       default y
  14//config:       select LONG_OPTS
  15//config:       help
  16//config:       Utility for creating a new group account.
  17//config:
  18//config:config FEATURE_ADDUSER_TO_GROUP
  19//config:       bool "Support adding users to groups"
  20//config:       default y
  21//config:       depends on ADDGROUP
  22//config:       help
  23//config:       If called with two non-option arguments,
  24//config:       addgroup will add an existing user to an
  25//config:       existing group.
  26
  27//applet:IF_ADDGROUP(APPLET_NOEXEC(addgroup, addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP, addgroup))
  28
  29//kbuild:lib-$(CONFIG_ADDGROUP) += addgroup.o
  30
  31//usage:#define addgroup_trivial_usage
  32//usage:       "[-g GID] [-S] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP"
  33//usage:#define addgroup_full_usage "\n\n"
  34//usage:       "Add a group" IF_FEATURE_ADDUSER_TO_GROUP(" or add a user to a group") "\n"
  35//usage:     "\n        -g GID  Group id"
  36//usage:     "\n        -S      Create a system group"
  37
  38#include "libbb.h"
  39
  40#if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
  41#error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
  42#endif
  43#if CONFIG_LAST_ID < CONFIG_LAST_SYSTEM_ID
  44#error Bad LAST_ID or LAST_SYSTEM_ID in .config
  45#endif
  46
  47#define OPT_GID                       (1 << 0)
  48#define OPT_SYSTEM_ACCOUNT            (1 << 1)
  49
  50static void xgroup_study(struct group *g)
  51{
  52        unsigned max = CONFIG_LAST_ID;
  53
  54        /* Make sure gr_name is unused */
  55        if (getgrnam(g->gr_name)) {
  56                bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name);
  57                /* these format strings are reused in adduser and addgroup */
  58        }
  59
  60        /* if a specific gid is requested, the --system switch and */
  61        /* min and max values are overridden, and the range of valid */
  62        /* gid values is set to [0, INT_MAX] */
  63        if (!(option_mask32 & OPT_GID)) {
  64                if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
  65                        g->gr_gid = CONFIG_FIRST_SYSTEM_ID;
  66                        max = CONFIG_LAST_SYSTEM_ID;
  67                } else {
  68                        g->gr_gid = CONFIG_LAST_SYSTEM_ID + 1;
  69                }
  70        }
  71        /* Check if the desired gid is free
  72         * or find the first free one */
  73        while (1) {
  74                if (!getgrgid(g->gr_gid)) {
  75                        return; /* found free group: return */
  76                }
  77                if (option_mask32 & OPT_GID) {
  78                        /* -g N, cannot pick gid other than N: error */
  79                        bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid));
  80                        /* this format strings is reused in adduser and addgroup */
  81                }
  82                if (g->gr_gid == max) {
  83                        /* overflowed: error */
  84                        bb_error_msg_and_die("no %cids left", 'g');
  85                        /* this format string is reused in adduser and addgroup */
  86                }
  87                g->gr_gid++;
  88        }
  89}
  90
  91/* append a new user to the passwd file */
  92static void new_group(char *group, gid_t gid)
  93{
  94        struct group gr;
  95        char *p;
  96
  97        /* make sure gid and group haven't already been allocated */
  98        gr.gr_gid = gid;
  99        gr.gr_name = group;
 100        xgroup_study(&gr);
 101
 102        /* add entry to group */
 103        p = xasprintf("x:%u:", (unsigned) gr.gr_gid);
 104        if (update_passwd(bb_path_group_file, group, p, NULL) < 0)
 105                exit(EXIT_FAILURE);
 106        if (ENABLE_FEATURE_CLEAN_UP)
 107                free(p);
 108#if ENABLE_FEATURE_SHADOWPASSWDS
 109        /* /etc/gshadow fields:
 110         * 1. Group name.
 111         * 2. Encrypted password.
 112         *    If set, non-members of the group can join the group
 113         *    by typing the password for that group using the newgrp command.
 114         *    If the value is of this field ! then no user is allowed
 115         *    to access the group using the newgrp command. A value of !!
 116         *    is treated the same as a value of ! only it indicates
 117         *    that a password has never been set before. If the value is null,
 118         *    only group members can log into the group.
 119         * 3. Group administrators (comma delimited list).
 120         *    Group members listed here can add or remove group members
 121         *    using the gpasswd command.
 122         * 4. Group members (comma delimited list).
 123         */
 124        /* Ignore errors: if file is missing we assume admin doesn't want it */
 125        update_passwd(bb_path_gshadow_file, group, "!::", NULL);
 126#endif
 127}
 128
 129//FIXME: upstream addgroup has no short options! NOT COMPATIBLE!
 130static const char addgroup_longopts[] ALIGN1 =
 131                "gid\0"                 Required_argument "g"
 132                "system\0"              No_argument       "S"
 133                ;
 134
 135/*
 136 * addgroup will take a login_name as its first parameter.
 137 *
 138 * gid can be customized via command-line parameters.
 139 * If called with two non-option arguments, addgroup
 140 * will add an existing user to an existing group.
 141 */
 142int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 143int addgroup_main(int argc UNUSED_PARAM, char **argv)
 144{
 145#if ENABLE_FEATURE_ADDUSER_TO_GROUP
 146        unsigned opts;
 147#endif
 148        const char *gid = "0";
 149
 150        /* need to be root */
 151        if (geteuid()) {
 152                bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
 153        }
 154        /* Syntax:
 155         *  addgroup group
 156         *  addgroup --gid num group
 157         *  addgroup user group
 158         * Check for min, max and missing args */
 159#if ENABLE_FEATURE_ADDUSER_TO_GROUP
 160        opts =
 161#endif
 162        getopt32long(argv, "^" "g:S" "\0" "-1:?2", addgroup_longopts,
 163                                &gid
 164        );
 165        /* move past the commandline options */
 166        argv += optind;
 167        //argc -= optind;
 168
 169#if ENABLE_FEATURE_ADDUSER_TO_GROUP
 170        if (argv[1]) {
 171                struct group *gr;
 172
 173                if (opts & OPT_GID) {
 174                        /* -g was there, but "addgroup -g num user group"
 175                         * is a no-no */
 176                        bb_show_usage();
 177                }
 178
 179                /* check if group and user exist */
 180                xuname2uid(argv[0]); /* unknown user: exit */
 181                gr = xgetgrnam(argv[1]); /* unknown group: exit */
 182                /* check if user is already in this group */
 183                for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
 184                        if (strcmp(argv[0], *(gr->gr_mem)) == 0) {
 185                                /* user is already in group: do nothing */
 186                                return EXIT_SUCCESS;
 187                        }
 188                }
 189                if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) {
 190                        return EXIT_FAILURE;
 191                }
 192# if ENABLE_FEATURE_SHADOWPASSWDS
 193                update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]);
 194# endif
 195        } else
 196#endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
 197        {
 198                die_if_bad_username(argv[0]);
 199                new_group(argv[0], xatou_range(gid, 0, CONFIG_LAST_ID));
 200        }
 201        /* Reached only on success */
 202        return EXIT_SUCCESS;
 203}
 204