diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-10-29 19:25:45 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-10-29 19:25:45 +0000 |
commit | 15ca51e3e2a31efc275b616106244d8ec3f8f773 (patch) | |
tree | e54716fcb612a54cfa72564d9ef089eebe92acbd /loginutils/adduser.c | |
parent | 5a28a25b9dd81e0975532458723c4244ff532e58 (diff) | |
download | busybox-w32-15ca51e3e2a31efc275b616106244d8ec3f8f773.tar.gz busybox-w32-15ca51e3e2a31efc275b616106244d8ec3f8f773.tar.bz2 busybox-w32-15ca51e3e2a31efc275b616106244d8ec3f8f773.zip |
appletlib.c: make it actally follow _BB_SUID_ALWAYS rules
adduser: implement -S and code shrink / fix uid selection
*: sanitize getspnam_r use
text data bss dec hex filename
777042 974 9676 787692 c04ec busybox_old
776883 974 9676 787533 c044d busybox_unstripped
Diffstat (limited to 'loginutils/adduser.c')
-rw-r--r-- | loginutils/adduser.c | 196 |
1 files changed, 78 insertions, 118 deletions
diff --git a/loginutils/adduser.c b/loginutils/adduser.c index 5c624285f..e91417ad5 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c | |||
@@ -11,68 +11,47 @@ | |||
11 | #include "libbb.h" | 11 | #include "libbb.h" |
12 | 12 | ||
13 | #define OPT_DONT_SET_PASS (1 << 4) | 13 | #define OPT_DONT_SET_PASS (1 << 4) |
14 | #define OPT_SYSTEM_ACCOUNT (1 << 5) | ||
14 | #define OPT_DONT_MAKE_HOME (1 << 6) | 15 | #define OPT_DONT_MAKE_HOME (1 << 6) |
15 | 16 | ||
16 | 17 | ||
17 | /* remix */ | 18 | /* remix */ |
18 | /* EDR recoded such that the uid may be passed in *p */ | 19 | /* recoded such that the uid may be passed in *p */ |
19 | static int passwd_study(const char *filename, struct passwd *p) | 20 | static void passwd_study(struct passwd *p) |
20 | { | 21 | { |
21 | enum { min = 500, max = 65000 }; | 22 | int max; |
22 | FILE *passwd; | ||
23 | /* We are using reentrant fgetpwent_r() in order to avoid | ||
24 | * pulling in static buffers from libc (think static build here) */ | ||
25 | char buffer[256]; | ||
26 | struct passwd pw; | ||
27 | struct passwd *result; | ||
28 | |||
29 | passwd = xfopen(filename, "r"); | ||
30 | |||
31 | /* EDR if uid is out of bounds, set to min */ | ||
32 | if ((p->pw_uid > max) || (p->pw_uid < min)) | ||
33 | p->pw_uid = min; | ||
34 | |||
35 | /* stuff to do: | ||
36 | * make sure login isn't taken; | ||
37 | * find free uid and gid; | ||
38 | */ | ||
39 | while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) { | ||
40 | if (strcmp(pw.pw_name, p->pw_name) == 0) { | ||
41 | /* return 0; */ | ||
42 | return 1; | ||
43 | } | ||
44 | if ((pw.pw_uid >= p->pw_uid) && (pw.pw_uid < max) | ||
45 | && (pw.pw_uid >= min)) { | ||
46 | p->pw_uid = pw.pw_uid + 1; | ||
47 | } | ||
48 | } | ||
49 | 23 | ||
50 | if (p->pw_gid == 0) { | 24 | if (getpwnam(p->pw_name)) |
51 | /* EDR check for an already existing gid */ | 25 | bb_error_msg_and_die("login '%s' is in use", p->pw_name); |
52 | while (getgrgid(p->pw_uid) != NULL) | ||
53 | p->pw_uid++; | ||
54 | 26 | ||
55 | /* EDR also check for an existing group definition */ | 27 | if (option_mask32 & OPT_SYSTEM_ACCOUNT) { |
56 | if (getgrnam(p->pw_name) != NULL) | 28 | p->pw_uid = 0; |
57 | return 3; | 29 | max = 999; |
30 | } else { | ||
31 | p->pw_uid = 1000; | ||
32 | max = 64999; | ||
33 | } | ||
58 | 34 | ||
59 | /* EDR create new gid always = uid */ | 35 | /* check for a free uid (and maybe gid) */ |
36 | while (getpwuid(p->pw_uid) || (!p->pw_gid && getgrgid(p->pw_uid))) | ||
37 | p->pw_uid++; | ||
38 | |||
39 | if (!p->pw_gid) { | ||
40 | /* new gid = uid */ | ||
60 | p->pw_gid = p->pw_uid; | 41 | p->pw_gid = p->pw_uid; |
42 | if (getgrnam(p->pw_name)) | ||
43 | bb_error_msg_and_die("group name '%s' is in use", p->pw_name); | ||
61 | } | 44 | } |
62 | 45 | ||
63 | /* EDR bounds check */ | 46 | if (p->pw_uid > max) |
64 | if ((p->pw_uid > max) || (p->pw_uid < min)) | 47 | bb_error_msg_and_die("no free uids left"); |
65 | return 2; | ||
66 | |||
67 | /* return 1; */ | ||
68 | return 0; | ||
69 | } | 48 | } |
70 | 49 | ||
71 | static void addgroup_wrapper(struct passwd *p) | 50 | static void addgroup_wrapper(struct passwd *p) |
72 | { | 51 | { |
73 | char *cmd; | 52 | char *cmd; |
74 | 53 | ||
75 | cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name); | 54 | cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name); |
76 | system(cmd); | 55 | system(cmd); |
77 | free(cmd); | 56 | free(cmd); |
78 | } | 57 | } |
@@ -84,33 +63,54 @@ static void passwd_wrapper(const char *login) | |||
84 | static const char prog[] ALIGN1 = "passwd"; | 63 | static const char prog[] ALIGN1 = "passwd"; |
85 | 64 | ||
86 | BB_EXECLP(prog, prog, login, NULL); | 65 | BB_EXECLP(prog, prog, login, NULL); |
87 | bb_error_msg_and_die("failed to execute '%s', you must set the password for '%s' manually", prog, login); | 66 | bb_error_msg_and_die("cannot execute %s, you must set password manually", prog); |
88 | } | 67 | } |
89 | 68 | ||
90 | /* putpwent(3) remix */ | 69 | /* |
91 | static int adduser(struct passwd *p) | 70 | * adduser will take a login_name as its first parameter. |
71 | * home, shell, gecos: | ||
72 | * can be customized via command-line parameters. | ||
73 | */ | ||
74 | int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
75 | int adduser_main(int argc, char **argv) | ||
92 | { | 76 | { |
77 | struct passwd pw; | ||
78 | const char *usegroup = NULL; | ||
93 | FILE *file; | 79 | FILE *file; |
94 | int addgroup = !p->pw_gid; | ||
95 | 80 | ||
96 | /* make sure everything is kosher and setup uid && gid */ | 81 | /* got root? */ |
97 | file = xfopen(bb_path_passwd_file, "a"); | 82 | if (geteuid()) { |
98 | fseek(file, 0, SEEK_END); | 83 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
99 | |||
100 | switch (passwd_study(bb_path_passwd_file, p)) { | ||
101 | case 1: | ||
102 | bb_error_msg_and_die("%s: login already in use", p->pw_name); | ||
103 | case 2: | ||
104 | bb_error_msg_and_die("illegal uid or no uids left"); | ||
105 | case 3: | ||
106 | bb_error_msg_and_die("%s: group name already in use", p->pw_name); | ||
107 | } | 84 | } |
108 | 85 | ||
86 | pw.pw_gecos = (char *)"Linux User,,,"; | ||
87 | pw.pw_shell = (char *)DEFAULT_SHELL; | ||
88 | pw.pw_dir = NULL; | ||
89 | |||
90 | /* exactly one non-option arg */ | ||
91 | opt_complementary = "=1"; | ||
92 | getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); | ||
93 | argv += optind; | ||
94 | |||
95 | /* fill in the passwd struct */ | ||
96 | pw.pw_name = argv[0]; | ||
97 | if (!pw.pw_dir) { | ||
98 | /* create string for $HOME if not specified already */ | ||
99 | pw.pw_dir = xasprintf("/home/%s", argv[0]); | ||
100 | } | ||
101 | pw.pw_passwd = (char *)"x"; | ||
102 | pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ | ||
103 | |||
104 | /* make sure everything is kosher and setup uid && maybe gid */ | ||
105 | passwd_study(&pw); | ||
106 | |||
109 | /* add to passwd */ | 107 | /* add to passwd */ |
110 | if (putpwent(p, file) == -1) { | 108 | file = xfopen(bb_path_passwd_file, "a"); |
109 | //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */ | ||
110 | if (putpwent(&pw, file) != 0) { | ||
111 | bb_perror_nomsg_and_die(); | 111 | bb_perror_nomsg_and_die(); |
112 | } | 112 | } |
113 | /* Do fclose even if !ENABLE_FEATURE_CLEAN_UP. | 113 | /* do fclose even if !ENABLE_FEATURE_CLEAN_UP. |
114 | * We will exec passwd, files must be flushed & closed before that! */ | 114 | * We will exec passwd, files must be flushed & closed before that! */ |
115 | fclose(file); | 115 | fclose(file); |
116 | 116 | ||
@@ -118,13 +118,14 @@ static int adduser(struct passwd *p) | |||
118 | /* add to shadow if necessary */ | 118 | /* add to shadow if necessary */ |
119 | file = fopen_or_warn(bb_path_shadow_file, "a"); | 119 | file = fopen_or_warn(bb_path_shadow_file, "a"); |
120 | if (file) { | 120 | if (file) { |
121 | fseek(file, 0, SEEK_END); | 121 | //fseek(file, 0, SEEK_END); |
122 | fprintf(file, "%s:!:%ld:%d:%d:%d:::\n", | 122 | fprintf(file, "%s:!:%u:0:99999:7:::\n", |
123 | p->pw_name, /* username */ | 123 | pw.pw_name, /* username */ |
124 | time(NULL) / 86400, /* sp->sp_lstchg */ | 124 | (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */ |
125 | 0, /* sp->sp_min */ | 125 | /*0,*/ /* sp->sp_min */ |
126 | 99999, /* sp->sp_max */ | 126 | /*99999,*/ /* sp->sp_max */ |
127 | 7); /* sp->sp_warn */ | 127 | /*7*/ /* sp->sp_warn */ |
128 | ); | ||
128 | fclose(file); | 129 | fclose(file); |
129 | } | 130 | } |
130 | #endif | 131 | #endif |
@@ -132,7 +133,8 @@ static int adduser(struct passwd *p) | |||
132 | /* add to group */ | 133 | /* add to group */ |
133 | /* addgroup should be responsible for dealing w/ gshadow */ | 134 | /* addgroup should be responsible for dealing w/ gshadow */ |
134 | /* if using a pre-existing group, don't create one */ | 135 | /* if using a pre-existing group, don't create one */ |
135 | if (addgroup) addgroup_wrapper(p); | 136 | if (!usegroup) |
137 | addgroup_wrapper(&pw); | ||
136 | 138 | ||
137 | /* Clear the umask for this process so it doesn't | 139 | /* Clear the umask for this process so it doesn't |
138 | * screw up the permissions on the mkdir and chown. */ | 140 | * screw up the permissions on the mkdir and chown. */ |
@@ -141,60 +143,18 @@ static int adduser(struct passwd *p) | |||
141 | /* Set the owner and group so it is owned by the new user, | 143 | /* Set the owner and group so it is owned by the new user, |
142 | then fix up the permissions to 2755. Can't do it before | 144 | then fix up the permissions to 2755. Can't do it before |
143 | since chown will clear the setgid bit */ | 145 | since chown will clear the setgid bit */ |
144 | if (mkdir(p->pw_dir, 0755) | 146 | if (mkdir(pw.pw_dir, 0755) |
145 | || chown(p->pw_dir, p->pw_uid, p->pw_gid) | 147 | || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) |
146 | || chmod(p->pw_dir, 02755)) { | 148 | || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */ |
147 | bb_simple_perror_msg(p->pw_dir); | 149 | ) { |
150 | bb_simple_perror_msg(pw.pw_dir); | ||
148 | } | 151 | } |
149 | } | 152 | } |
150 | 153 | ||
151 | if (!(option_mask32 & OPT_DONT_SET_PASS)) { | 154 | if (!(option_mask32 & OPT_DONT_SET_PASS)) { |
152 | /* interactively set passwd */ | 155 | /* interactively set passwd */ |
153 | passwd_wrapper(p->pw_name); | 156 | passwd_wrapper(pw.pw_name); |
154 | } | 157 | } |
155 | 158 | ||
156 | return 0; | 159 | return 0; |
157 | } | 160 | } |
158 | |||
159 | /* | ||
160 | * adduser will take a login_name as its first parameter. | ||
161 | * | ||
162 | * home | ||
163 | * shell | ||
164 | * gecos | ||
165 | * | ||
166 | * can be customized via command-line parameters. | ||
167 | */ | ||
168 | int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
169 | int adduser_main(int argc, char **argv) | ||
170 | { | ||
171 | struct passwd pw; | ||
172 | const char *usegroup = NULL; | ||
173 | |||
174 | /* got root? */ | ||
175 | if (geteuid()) { | ||
176 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | ||
177 | } | ||
178 | |||
179 | pw.pw_gecos = (char *)"Linux User,,,"; | ||
180 | pw.pw_shell = (char *)DEFAULT_SHELL; | ||
181 | pw.pw_dir = NULL; | ||
182 | |||
183 | /* exactly one non-option arg */ | ||
184 | opt_complementary = "=1"; | ||
185 | getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); | ||
186 | argv += optind; | ||
187 | |||
188 | /* create a passwd struct */ | ||
189 | pw.pw_name = argv[0]; | ||
190 | if (!pw.pw_dir) { | ||
191 | /* create string for $HOME if not specified already */ | ||
192 | pw.pw_dir = xasprintf("/home/%s", argv[0]); | ||
193 | } | ||
194 | pw.pw_passwd = (char *)"x"; | ||
195 | pw.pw_uid = 0; | ||
196 | pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ | ||
197 | |||
198 | /* grand finale */ | ||
199 | return adduser(&pw); | ||
200 | } | ||