aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-22 21:35:52 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-22 21:35:52 +0000
commitc2931aa2df2ddc6a627f3c40eb1cf5c221067092 (patch)
tree8b4b92c8c5bea933f7ea68302328bd17c0610b4a
parentc8d7109f6036fab6b5993c24fc6514ba0c6a7d3d (diff)
downloadbusybox-w32-c2931aa2df2ddc6a627f3c40eb1cf5c221067092.tar.gz
busybox-w32-c2931aa2df2ddc6a627f3c40eb1cf5c221067092.tar.bz2
busybox-w32-c2931aa2df2ddc6a627f3c40eb1cf5c221067092.zip
adduser/addgroup: support specifying uid/gid, add system
account creation mode. By Tito. function old new delta adduser_main 650 726 +76 addgroup_main 341 402 +61 addgroup_longopts - 16 +16 adduser_longopts 97 103 +6 packed_usage 26161 26163 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/0 up/down: 161/0) Total: 161 bytes
-rw-r--r--include/usage.h2
-rw-r--r--loginutils/Config.in7
-rw-r--r--loginutils/addgroup.c63
-rw-r--r--loginutils/adduser.c82
4 files changed, 112 insertions, 42 deletions
diff --git a/include/usage.h b/include/usage.h
index 9294e892c..7b88a2acc 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -39,6 +39,7 @@
39 "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \ 39 "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \
40 "\nOptions:" \ 40 "\nOptions:" \
41 "\n -g GID Group id" \ 41 "\n -g GID Group id" \
42 "\n -S Create a system group" \
42 43
43#define adduser_trivial_usage \ 44#define adduser_trivial_usage \
44 "[OPTIONS] user_name" 45 "[OPTIONS] user_name"
@@ -52,6 +53,7 @@
52 "\n -S Create a system user" \ 53 "\n -S Create a system user" \
53 "\n -D Do not assign a password" \ 54 "\n -D Do not assign a password" \
54 "\n -H Do not create home directory" \ 55 "\n -H Do not create home directory" \
56 "\n -u UID User id" \
55 57
56#define adjtimex_trivial_usage \ 58#define adjtimex_trivial_usage \
57 "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" 59 "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
diff --git a/loginutils/Config.in b/loginutils/Config.in
index ddd0c8015..9430bfa09 100644
--- a/loginutils/Config.in
+++ b/loginutils/Config.in
@@ -97,6 +97,13 @@ config ADDGROUP
97 help 97 help
98 Utility for creating a new group account. 98 Utility for creating a new group account.
99 99
100config FEATURE_ADDGROUP_LONG_OPTIONS
101 bool "Enable long options"
102 default n
103 depends on ADDGROUP && GETOPT_LONG
104 help
105 Support long options for the addgroup applet.
106
100config FEATURE_ADDUSER_TO_GROUP 107config FEATURE_ADDUSER_TO_GROUP
101 bool "Support for adding users to groups" 108 bool "Support for adding users to groups"
102 default n 109 default n
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c
index 5a0cf3fff..cb839290d 100644
--- a/loginutils/addgroup.c
+++ b/loginutils/addgroup.c
@@ -11,34 +11,50 @@
11 */ 11 */
12#include "libbb.h" 12#include "libbb.h"
13 13
14#define OPT_GID (1 << 0)
15#define OPT_SYSTEM_ACCOUNT (1 << 1)
16
17/* We assume GID_T_MAX == INT_MAX */
14static void xgroup_study(struct group *g) 18static void xgroup_study(struct group *g)
15{ 19{
20 unsigned max = INT_MAX;
21
16 /* Make sure gr_name is unused */ 22 /* Make sure gr_name is unused */
17 if (getgrnam(g->gr_name)) { 23 if (getgrnam(g->gr_name)) {
18 goto error; 24 bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name);
25 /* these format strings are reused in adduser and addgroup */
19 } 26 }
20 27
28 /* if a specific gid is requested, the --system switch and */
29 /* min and max values are overriden, and the range of valid */
30 /* gid values is set to [0, INT_MAX] */
31 if (!(option_mask32 & OPT_GID)) {
32 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
33 g->gr_gid = 100; /* FIRST_SYSTEM_GID */
34 max = 999; /* LAST_SYSTEM_GID */
35 } else {
36 g->gr_gid = 1000; /* FIRST_GID */
37 max = 64999; /* LAST_GID */
38 }
39 }
21 /* Check if the desired gid is free 40 /* Check if the desired gid is free
22 * or find the first free one */ 41 * or find the first free one */
23 while (1) { 42 while (1) {
24 if (!getgrgid(g->gr_gid)) { 43 if (!getgrgid(g->gr_gid)) {
25 return; /* found free group: return */ 44 return; /* found free group: return */
26 } 45 }
27 if (option_mask32) { 46 if (option_mask32 & OPT_GID) {
28 /* -g N, cannot pick gid other than N: error */ 47 /* -g N, cannot pick gid other than N: error */
29 g->gr_name = itoa(g->gr_gid); 48 bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid));
30 goto error; 49 /* this format strings is reused in adduser and addgroup */
31 } 50 }
32 g->gr_gid++; 51 if (g->gr_gid == max) {
33 if (g->gr_gid <= 0) {
34 /* overflowed: error */ 52 /* overflowed: error */
35 bb_error_msg_and_die("no gids left"); 53 bb_error_msg_and_die("no %cids left", 'g');
54 /* this format string is reused in adduser and addgroup */
36 } 55 }
56 g->gr_gid++;
37 } 57 }
38
39 error:
40 /* exit */
41 bb_error_msg_and_die("group %s already exists", g->gr_name);
42} 58}
43 59
44/* append a new user to the passwd file */ 60/* append a new user to the passwd file */
@@ -53,7 +69,7 @@ static void new_group(char *group, gid_t gid)
53 xgroup_study(&gr); 69 xgroup_study(&gr);
54 70
55 /* add entry to group */ 71 /* add entry to group */
56 p = xasprintf("x:%u:", gr.gr_gid); 72 p = xasprintf("x:%u:", (unsigned) gr.gr_gid);
57 if (update_passwd(bb_path_group_file, group, p, NULL) < 0) 73 if (update_passwd(bb_path_group_file, group, p, NULL) < 0)
58 exit(EXIT_FAILURE); 74 exit(EXIT_FAILURE);
59 if (ENABLE_FEATURE_CLEAN_UP) 75 if (ENABLE_FEATURE_CLEAN_UP)
@@ -64,6 +80,13 @@ static void new_group(char *group, gid_t gid)
64#endif 80#endif
65} 81}
66 82
83#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
84static const char addgroup_longopts[] ALIGN1 =
85 "gid\0" Required_argument "g"
86 "system\0" No_argument "S"
87 ;
88#endif
89
67/* 90/*
68 * addgroup will take a login_name as its first parameter. 91 * addgroup will take a login_name as its first parameter.
69 * 92 *
@@ -74,23 +97,23 @@ static void new_group(char *group, gid_t gid)
74int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 97int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
75int addgroup_main(int argc UNUSED_PARAM, char **argv) 98int addgroup_main(int argc UNUSED_PARAM, char **argv)
76{ 99{
77 char *group; 100 unsigned opts;
78 gid_t gid = 0; 101 unsigned gid = 0;
79 102
80 /* need to be root */ 103 /* need to be root */
81 if (geteuid()) { 104 if (geteuid()) {
82 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 105 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
83 } 106 }
84 107#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
108 applet_long_options = addgroup_longopts;
109#endif
85 /* Syntax: 110 /* Syntax:
86 * addgroup group 111 * addgroup group
87 * addgroup -g num group 112 * addgroup -g num group
88 * addgroup user group 113 * addgroup user group
89 * Check for min, max and missing args */ 114 * Check for min, max and missing args */
90 opt_complementary = "-1:?2"; 115 opt_complementary = "-1:?2:g+";
91 if (getopt32(argv, "g:", &group)) { 116 opts = getopt32(argv, "g:S", &gid);
92 gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1);
93 }
94 /* move past the commandline options */ 117 /* move past the commandline options */
95 argv += optind; 118 argv += optind;
96 //argc -= optind; 119 //argc -= optind;
@@ -99,7 +122,7 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv)
99 if (argv[1]) { 122 if (argv[1]) {
100 struct group *gr; 123 struct group *gr;
101 124
102 if (option_mask32) { 125 if (opts & OPT_GID) {
103 /* -g was there, but "addgroup -g num user group" 126 /* -g was there, but "addgroup -g num user group"
104 * is a no-no */ 127 * is a no-no */
105 bb_show_usage(); 128 bb_show_usage();
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
index df4fad694..a399d9e4c 100644
--- a/loginutils/adduser.c
+++ b/loginutils/adduser.c
@@ -9,38 +9,55 @@
9 */ 9 */
10#include "libbb.h" 10#include "libbb.h"
11 11
12/* #define OPT_HOME (1 << 0) */ /* unused */
13/* #define OPT_GECOS (1 << 1) */ /* unused */
14#define OPT_SHELL (1 << 2)
15#define OPT_GID (1 << 3)
12#define OPT_DONT_SET_PASS (1 << 4) 16#define OPT_DONT_SET_PASS (1 << 4)
13#define OPT_SYSTEM_ACCOUNT (1 << 5) 17#define OPT_SYSTEM_ACCOUNT (1 << 5)
14#define OPT_DONT_MAKE_HOME (1 << 6) 18#define OPT_DONT_MAKE_HOME (1 << 6)
19#define OPT_UID (1 << 7)
15 20
21/* We assume UID_T_MAX == INT_MAX */
16/* remix */ 22/* remix */
17/* recoded such that the uid may be passed in *p */ 23/* recoded such that the uid may be passed in *p */
18static void passwd_study(struct passwd *p) 24static void passwd_study(struct passwd *p)
19{ 25{
20 int max; 26 int max = UINT_MAX;
21 27
22 if (getpwnam(p->pw_name)) 28 if (getpwnam(p->pw_name)) {
23 bb_error_msg_and_die("login '%s' is in use", p->pw_name); 29 bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
24 30 /* this format string is reused in adduser and addgroup */
25 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
26 p->pw_uid = 0;
27 max = 999;
28 } else {
29 p->pw_uid = 1000;
30 max = 64999;
31 } 31 }
32 32
33 if (!(option_mask32 & OPT_UID)) {
34 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
35 p->pw_uid = 100; /* FIRST_SYSTEM_UID */
36 max = 999; /* LAST_SYSTEM_UID */
37 } else {
38 p->pw_uid = 1000; /* FIRST_UID */
39 max = 64999; /* LAST_UID */
40 }
41 }
33 /* check for a free uid (and maybe gid) */ 42 /* check for a free uid (and maybe gid) */
34 while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) { 43 while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
44 if (option_mask32 & OPT_UID) {
45 /* -u N, cannot pick uid other than N: error */
46 bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid));
47 /* this format string is reused in adduser and addgroup */
48 }
49 if (p->pw_uid == max) {
50 bb_error_msg_and_die("no %cids left", 'u');
51 }
35 p->pw_uid++; 52 p->pw_uid++;
36 if (p->pw_uid > max)
37 bb_error_msg_and_die("no free uids left");
38 } 53 }
39 54
40 if (p->pw_gid == (gid_t)-1) { 55 if (p->pw_gid == (gid_t)-1) {
41 p->pw_gid = p->pw_uid; /* new gid = uid */ 56 p->pw_gid = p->pw_uid; /* new gid = uid */
42 if (getgrnam(p->pw_name)) 57 if (getgrnam(p->pw_name)) {
43 bb_error_msg_and_die("group name '%s' is in use", p->pw_name); 58 bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name);
59 /* this format string is reused in adduser and addgroup */
60 }
44 } 61 }
45} 62}
46 63
@@ -73,6 +90,7 @@ static const char adduser_longopts[] ALIGN1 =
73 "empty-password\0" No_argument "D" 90 "empty-password\0" No_argument "D"
74 "system\0" No_argument "S" 91 "system\0" No_argument "S"
75 "no-create-home\0" No_argument "H" 92 "no-create-home\0" No_argument "H"
93 "uid\0" Required_argument "u"
76 ; 94 ;
77#endif 95#endif
78 96
@@ -87,6 +105,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
87 struct passwd pw; 105 struct passwd pw;
88 const char *usegroup = NULL; 106 const char *usegroup = NULL;
89 char *p; 107 char *p;
108 unsigned opts;
90 109
91#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS 110#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
92 applet_long_options = adduser_longopts; 111 applet_long_options = adduser_longopts;
@@ -102,8 +121,17 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
102 pw.pw_dir = NULL; 121 pw.pw_dir = NULL;
103 122
104 /* exactly one non-option arg */ 123 /* exactly one non-option arg */
105 opt_complementary = "=1"; 124 /* disable interactive passwd for system accounts */
106 getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); 125 opt_complementary = "=1:SD:u+";
126 if (sizeof(pw.pw_uid) == sizeof(int)) {
127 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
128 } else {
129 unsigned uid;
130 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid);
131 if (opts & OPT_UID) {
132 pw.pw_uid = uid;
133 }
134 }
107 argv += optind; 135 argv += optind;
108 136
109 /* fill in the passwd struct */ 137 /* fill in the passwd struct */
@@ -114,12 +142,22 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
114 pw.pw_dir = xasprintf("/home/%s", argv[0]); 142 pw.pw_dir = xasprintf("/home/%s", argv[0]);
115 } 143 }
116 pw.pw_passwd = (char *)"x"; 144 pw.pw_passwd = (char *)"x";
145 if (opts & OPT_SYSTEM_ACCOUNT) {
146 if (!usegroup) {
147 usegroup = "nogroup";
148 }
149 if (!(opts & OPT_SHELL)) {
150 pw.pw_shell = (char *) "/bin/false";
151 }
152 }
117 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */ 153 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
118 154
119 /* make sure everything is kosher and setup uid && maybe gid */ 155 /* make sure everything is kosher and setup uid && maybe gid */
120 passwd_study(&pw); 156 passwd_study(&pw);
121 157
122 p = xasprintf("x:%u:%u:%s:%s:%s", pw.pw_uid, pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell); 158 p = xasprintf("x:%u:%u:%s:%s:%s",
159 (unsigned) pw.pw_uid, (unsigned) pw.pw_gid,
160 pw.pw_gecos, pw.pw_dir, pw.pw_shell);
123 if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) { 161 if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) {
124 return EXIT_FAILURE; 162 return EXIT_FAILURE;
125 } 163 }
@@ -143,10 +181,10 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
143 /* clear the umask for this process so it doesn't 181 /* clear the umask for this process so it doesn't
144 * screw up the permissions on the mkdir and chown. */ 182 * screw up the permissions on the mkdir and chown. */
145 umask(0); 183 umask(0);
146 if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { 184 if (!(opts & OPT_DONT_MAKE_HOME)) {
147 /* Set the owner and group so it is owned by the new user, 185 /* set the owner and group so it is owned by the new user,
148 then fix up the permissions to 2755. Can't do it before 186 * then fix up the permissions to 2755. Can't do it before
149 since chown will clear the setgid bit */ 187 * since chown will clear the setgid bit */
150 if (mkdir(pw.pw_dir, 0755) 188 if (mkdir(pw.pw_dir, 0755)
151 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) 189 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)
152 || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */ 190 || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */
@@ -155,7 +193,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
155 } 193 }
156 } 194 }
157 195
158 if (!(option_mask32 & OPT_DONT_SET_PASS)) { 196 if (!(opts & OPT_DONT_SET_PASS)) {
159 /* interactively set passwd */ 197 /* interactively set passwd */
160 passwd_wrapper(pw.pw_name); 198 passwd_wrapper(pw.pw_name);
161 } 199 }