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