lineedit: print prompt and editing operations to stderr
[busybox-git.git] / loginutils / addgroup.c
blob2b5ac755063a768cf8f80819d69ca598fdc1bf40
1 /* vi: set sw=4 ts=4: */
2 /*
3 * addgroup - add groups to /etc/group and /etc/gshadow
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>
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 //config:config ADDGROUP
12 //config: bool "addgroup (8.8 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.
27 //applet:IF_ADDGROUP(APPLET_NOEXEC(addgroup, addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP, addgroup))
29 //kbuild:lib-$(CONFIG_ADDGROUP) += addgroup.o
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"
38 #include "libbb.h"
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
47 #define OPT_GID (1 << 0)
48 #define OPT_SYSTEM_ACCOUNT (1 << 1)
50 static void xgroup_study(struct group *g)
52 unsigned max = CONFIG_LAST_ID;
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 */
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;
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 */
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 */
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 */
87 g->gr_gid++;
91 /* append a new user to the passwd file */
92 static void new_group(char *group, gid_t gid)
94 struct group gr;
95 char *p;
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);
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_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).
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
129 //FIXME: upstream addgroup has no short options! NOT COMPATIBLE!
130 static const char addgroup_longopts[] ALIGN1 =
131 "gid\0" Required_argument "g"
132 "system\0" No_argument "S"
136 * addgroup will take a login_name as its first parameter.
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.
142 int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
143 int addgroup_main(int argc UNUSED_PARAM, char **argv)
145 #if ENABLE_FEATURE_ADDUSER_TO_GROUP
146 unsigned opts;
147 #endif
148 const char *gid = "0";
150 /* need to be root */
151 if (geteuid()) {
152 bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
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
165 /* move past the commandline options */
166 argv += optind;
167 //argc -= optind;
169 #if ENABLE_FEATURE_ADDUSER_TO_GROUP
170 if (argv[1]) {
171 struct group *gr;
173 if (opts & OPT_GID) {
174 /* -g was there, but "addgroup -g num user group"
175 * is a no-no */
176 bb_show_usage();
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;
189 if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) {
190 return EXIT_FAILURE;
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 */
198 die_if_bad_username(argv[0]);
199 new_group(argv[0], xatou_range(gid, 0, CONFIG_LAST_ID));
201 /* Reached only on success */
202 return EXIT_SUCCESS;