diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-22 21:35:52 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-22 21:35:52 +0000 |
commit | c2931aa2df2ddc6a627f3c40eb1cf5c221067092 (patch) | |
tree | 8b4b92c8c5bea933f7ea68302328bd17c0610b4a | |
parent | c8d7109f6036fab6b5993c24fc6514ba0c6a7d3d (diff) | |
download | busybox-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.h | 2 | ||||
-rw-r--r-- | loginutils/Config.in | 7 | ||||
-rw-r--r-- | loginutils/addgroup.c | 63 | ||||
-rw-r--r-- | loginutils/adduser.c | 82 |
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 | ||
100 | config 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 | |||
100 | config FEATURE_ADDUSER_TO_GROUP | 107 | config 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 */ | ||
14 | static void xgroup_study(struct group *g) | 18 | static 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 | ||
84 | static 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) | |||
74 | int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 97 | int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
75 | int addgroup_main(int argc UNUSED_PARAM, char **argv) | 98 | int 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 */ |
18 | static void passwd_study(struct passwd *p) | 24 | static 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 | } |