diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-14 00:51:05 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-14 00:51:05 +0000 |
commit | 829bbd3b5701f656c94f1cc672faa39946675d13 (patch) | |
tree | dbe6672228a3cb51eb8031ba714bb4abb96decf4 | |
parent | f2b39e088d6ccbf4a540c741059c2f661eebc9ac (diff) | |
download | busybox-w32-829bbd3b5701f656c94f1cc672faa39946675d13.tar.gz busybox-w32-829bbd3b5701f656c94f1cc672faa39946675d13.tar.bz2 busybox-w32-829bbd3b5701f656c94f1cc672faa39946675d13.zip |
*: unify concurrent-safe update of /etc/{passwd,group,[g]shadow}
by Tito (farmatito AT tiscali.it)
function old new delta
update_passwd 743 1171 +428
bb_perror_nomsg - 9 +9
find_main 436 444 +8
passwd_main 1023 1027 +4
nameval 202 206 +4
chpasswd_main 315 319 +4
bb__parsespent 119 117 -2
adduser_main 654 650 -4
addgroup_main 345 341 -4
sv_main 1228 1222 -6
deluser_main 173 160 -13
bb_internal_putpwent 69 - -69
add_user_to_group 231 - -231
del_line_matching 460 31 -429
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 5/6 up/down: 457/-758) Total: -301 bytes
-rw-r--r-- | include/libbb.h | 11 | ||||
-rw-r--r-- | libbb/Kbuild | 3 | ||||
-rw-r--r-- | libbb/update_passwd.c | 163 | ||||
-rw-r--r-- | loginutils/addgroup.c | 75 | ||||
-rw-r--r-- | loginutils/adduser.c | 40 | ||||
-rw-r--r-- | loginutils/chpasswd.c | 5 | ||||
-rw-r--r-- | loginutils/deluser.c | 133 | ||||
-rw-r--r-- | loginutils/passwd.c | 5 |
8 files changed, 208 insertions, 227 deletions
diff --git a/include/libbb.h b/include/libbb.h index 0b94f70fd..1faa9e9fd 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1142,9 +1142,16 @@ extern int obscure(const char *old, const char *newval, const struct passwd *pwd | |||
1142 | * (otherwise we risk having same salt generated) | 1142 | * (otherwise we risk having same salt generated) |
1143 | */ | 1143 | */ |
1144 | extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; | 1144 | extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; |
1145 | |||
1145 | /* Returns number of lines changed, or -1 on error */ | 1146 | /* Returns number of lines changed, or -1 on error */ |
1146 | extern int update_passwd(const char *filename, const char *username, | 1147 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) |
1147 | const char *new_pw) FAST_FUNC; | 1148 | #define update_passwd(filename, username, data, member) \ |
1149 | update_passwd(filename, username, data) | ||
1150 | #endif | ||
1151 | extern int update_passwd(const char *filename, | ||
1152 | const char *username, | ||
1153 | const char *data, | ||
1154 | const char *member) FAST_FUNC; | ||
1148 | 1155 | ||
1149 | int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC; | 1156 | int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC; |
1150 | int index_in_strings(const char *strings, const char *key) FAST_FUNC; | 1157 | int index_in_strings(const char *strings, const char *key) FAST_FUNC; |
diff --git a/libbb/Kbuild b/libbb/Kbuild index 2c8830f99..57d5d21cf 100644 --- a/libbb/Kbuild +++ b/libbb/Kbuild | |||
@@ -120,6 +120,9 @@ lib-y += xrealloc_vector.o | |||
120 | lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o | 120 | lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o |
121 | lib-$(CONFIG_LOSETUP) += loop.o | 121 | lib-$(CONFIG_LOSETUP) += loop.o |
122 | lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o | 122 | lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o |
123 | lib-$(CONFIG_ADDGROUP) += update_passwd.o | ||
124 | lib-$(CONFIG_ADDUSER) += update_passwd.o | ||
125 | lib-$(CONFIG_DELUSER) += update_passwd.o | ||
123 | lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o | 126 | lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o |
124 | lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o | 127 | lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o |
125 | lib-$(CONFIG_CRYPTPW) += pw_encrypt.o | 128 | lib-$(CONFIG_CRYPTPW) += pw_encrypt.o |
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c index 565dd3702..32943482c 100644 --- a/libbb/update_passwd.c +++ b/libbb/update_passwd.c | |||
@@ -8,9 +8,11 @@ | |||
8 | * | 8 | * |
9 | * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org> | 9 | * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org> |
10 | * | 10 | * |
11 | * Modified to be able to add or delete users, groups and users to/from groups | ||
12 | * by Tito Ragusa <farmatito@tiscali.it> | ||
13 | * | ||
11 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | 14 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
12 | */ | 15 | */ |
13 | |||
14 | #include "libbb.h" | 16 | #include "libbb.h" |
15 | 17 | ||
16 | #if ENABLE_SELINUX | 18 | #if ENABLE_SELINUX |
@@ -35,12 +37,44 @@ static void check_selinux_update_passwd(const char *username) | |||
35 | freecon(context); | 37 | freecon(context); |
36 | } | 38 | } |
37 | #else | 39 | #else |
38 | #define check_selinux_update_passwd(username) ((void)0) | 40 | # define check_selinux_update_passwd(username) ((void)0) |
39 | #endif | 41 | #endif |
40 | 42 | ||
41 | int FAST_FUNC update_passwd(const char *filename, const char *username, | 43 | /* |
42 | const char *new_pw) | 44 | 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL) |
45 | only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser | ||
46 | |||
47 | 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL) | ||
48 | only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup | ||
49 | |||
50 | 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER) | ||
51 | only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a' | ||
52 | like in addgroup and member != NULL | ||
53 | |||
54 | 4) delete a user: update_passwd(FILE, USER, NULL, NULL) | ||
55 | |||
56 | 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL) | ||
57 | |||
58 | 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER) | ||
59 | only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL | ||
60 | |||
61 | 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL) | ||
62 | only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd | ||
63 | or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd | ||
64 | |||
65 | This function does not validate the arguments fed to it | ||
66 | so the calling program should take care of that. | ||
67 | |||
68 | Returns number of lines changed, or -1 on error. | ||
69 | */ | ||
70 | int FAST_FUNC update_passwd(const char *filename, | ||
71 | const char *name, | ||
72 | const char *new_passwd, | ||
73 | const char *member) | ||
43 | { | 74 | { |
75 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) | ||
76 | #define member NULL | ||
77 | #endif | ||
44 | struct stat sb; | 78 | struct stat sb; |
45 | struct flock lock; | 79 | struct flock lock; |
46 | FILE *old_fp; | 80 | FILE *old_fp; |
@@ -51,22 +85,25 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
51 | int old_fd; | 85 | int old_fd; |
52 | int new_fd; | 86 | int new_fd; |
53 | int i; | 87 | int i; |
54 | int cnt = 0; | 88 | int changed_lines; |
55 | int ret = -1; /* failure */ | 89 | int ret = -1; /* failure */ |
56 | 90 | ||
57 | filename = xmalloc_follow_symlinks(filename); | 91 | filename = xmalloc_follow_symlinks(filename); |
58 | if (filename == NULL) | 92 | if (filename == NULL) |
59 | return -1; | 93 | return ret; |
60 | 94 | ||
61 | check_selinux_update_passwd(username); | 95 | check_selinux_update_passwd(name); |
62 | 96 | ||
63 | /* New passwd file, "/etc/passwd+" for now */ | 97 | /* New passwd file, "/etc/passwd+" for now */ |
64 | fnamesfx = xasprintf("%s+", filename); | 98 | fnamesfx = xasprintf("%s+", filename); |
65 | sfx_char = &fnamesfx[strlen(fnamesfx)-1]; | 99 | sfx_char = &fnamesfx[strlen(fnamesfx)-1]; |
66 | username = xasprintf("%s:", username); | 100 | name = xasprintf("%s:", name); |
67 | user_len = strlen(username); | 101 | user_len = strlen(name); |
68 | 102 | ||
69 | old_fp = fopen(filename, "r+"); | 103 | if (strstr(filename, "shadow")) |
104 | old_fp = fopen(filename, "r+"); | ||
105 | else | ||
106 | old_fp = fopen_or_warn(filename, "r+"); | ||
70 | if (!old_fp) | 107 | if (!old_fp) |
71 | goto free_mem; | 108 | goto free_mem; |
72 | old_fd = fileno(old_fp); | 109 | old_fd = fileno(old_fp); |
@@ -82,7 +119,7 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
82 | if (errno != EEXIST) break; | 119 | if (errno != EEXIST) break; |
83 | usleep(100000); /* 0.1 sec */ | 120 | usleep(100000); /* 0.1 sec */ |
84 | } while (--i); | 121 | } while (--i); |
85 | bb_perror_msg("cannot create '%s'", fnamesfx); | 122 | bb_perror_msg("can't create '%s'", fnamesfx); |
86 | goto close_old_fp; | 123 | goto close_old_fp; |
87 | 124 | ||
88 | created: | 125 | created: |
@@ -90,8 +127,10 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
90 | fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ | 127 | fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ |
91 | fchown(new_fd, sb.st_uid, sb.st_gid); | 128 | fchown(new_fd, sb.st_uid, sb.st_gid); |
92 | } | 129 | } |
130 | errno = 0; | ||
93 | new_fp = fdopen(new_fd, "w"); | 131 | new_fp = fdopen(new_fd, "w"); |
94 | if (!new_fp) { | 132 | if (!new_fp) { |
133 | bb_perror_nomsg(); | ||
95 | close(new_fd); | 134 | close(new_fd); |
96 | goto unlink_new; | 135 | goto unlink_new; |
97 | } | 136 | } |
@@ -102,7 +141,8 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
102 | i = (unlink(fnamesfx) && errno != ENOENT); | 141 | i = (unlink(fnamesfx) && errno != ENOENT); |
103 | /* Create backup as a hardlink to current */ | 142 | /* Create backup as a hardlink to current */ |
104 | if (i || link(filename, fnamesfx)) | 143 | if (i || link(filename, fnamesfx)) |
105 | bb_perror_msg("warning: cannot create backup copy '%s'", fnamesfx); | 144 | bb_perror_msg("warning: can't create backup copy '%s'", |
145 | fnamesfx); | ||
106 | *sfx_char = '+'; | 146 | *sfx_char = '+'; |
107 | 147 | ||
108 | /* Lock the password file before updating */ | 148 | /* Lock the password file before updating */ |
@@ -111,38 +151,107 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
111 | lock.l_start = 0; | 151 | lock.l_start = 0; |
112 | lock.l_len = 0; | 152 | lock.l_len = 0; |
113 | if (fcntl(old_fd, F_SETLK, &lock) < 0) | 153 | if (fcntl(old_fd, F_SETLK, &lock) < 0) |
114 | bb_perror_msg("warning: cannot lock '%s'", filename); | 154 | bb_perror_msg("warning: can't lock '%s'", filename); |
115 | lock.l_type = F_UNLCK; | 155 | lock.l_type = F_UNLCK; |
116 | 156 | ||
117 | /* Read current password file, write updated /etc/passwd+ */ | 157 | /* Read current password file, write updated /etc/passwd+ */ |
158 | changed_lines = 0; | ||
118 | while (1) { | 159 | while (1) { |
119 | char *line = xmalloc_fgets(old_fp); | 160 | char *cp, *line; |
120 | if (!line) break; /* EOF/error */ | 161 | |
121 | if (strncmp(username, line, user_len) == 0) { | 162 | line = xmalloc_fgetline(old_fp); |
122 | /* we have a match with "username:"... */ | 163 | if (!line) /* EOF/error */ |
123 | const char *cp = line + user_len; | 164 | break; |
124 | /* now cp -> old passwd, skip it: */ | 165 | if (strncmp(name, line, user_len) != 0) { |
125 | cp = strchrnul(cp, ':'); | 166 | fprintf(new_fp, "%s\n", line); |
126 | /* now cp -> ':' after old passwd or -> "" */ | 167 | goto next; |
127 | fprintf(new_fp, "%s%s%s", username, new_pw, cp); | 168 | } |
128 | cnt++; | 169 | |
170 | /* We have a match with "name:"... */ | ||
171 | cp = line + user_len; /* move past name: */ | ||
172 | |||
173 | #if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP | ||
174 | if (member) { | ||
175 | /* It's actually /etc/group+, not /etc/passwd+ */ | ||
176 | if (ENABLE_FEATURE_ADDUSER_TO_GROUP | ||
177 | && applet_name[0] == 'a' | ||
178 | ) { | ||
179 | /* Add user to group */ | ||
180 | fprintf(new_fp, "%s%s%s\n", line, | ||
181 | last_char_is(line, ':') ? "" : ",", | ||
182 | member); | ||
183 | changed_lines++; | ||
184 | } else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP | ||
185 | /* && applet_name[0] == 'd' */ | ||
186 | ) { | ||
187 | /* Delete user from group */ | ||
188 | char *tmp; | ||
189 | const char *fmt = "%s"; | ||
190 | |||
191 | /* find the start of the member list: last ':' */ | ||
192 | cp = strrchr(line, ':'); | ||
193 | /* cut it */ | ||
194 | *cp++ = '\0'; | ||
195 | /* write the cut line name:passwd:gid: | ||
196 | * or name:!:: */ | ||
197 | fprintf(new_fp, "%s:", line); | ||
198 | /* parse the tokens of the member list */ | ||
199 | tmp = cp; | ||
200 | while ((cp = strsep(&tmp, ",")) != NULL) { | ||
201 | if (strcmp(member, cp) != 0) { | ||
202 | fprintf(new_fp, fmt, cp); | ||
203 | fmt = ",%s"; | ||
204 | } else { | ||
205 | /* found member, skip it */ | ||
206 | changed_lines++; | ||
207 | } | ||
208 | } | ||
209 | fprintf(new_fp, "\n"); | ||
210 | } | ||
129 | } else | 211 | } else |
130 | fputs(line, new_fp); | 212 | #endif |
213 | if ((ENABLE_PASSWD && applet_name[0] == 'p') | ||
214 | || (ENABLE_CHPASSWD && applet_name[0] == 'c') | ||
215 | ) { | ||
216 | /* Change passwd */ | ||
217 | cp = strchrnul(cp, ':'); /* move past old passwd */ | ||
218 | /* name: + new_passwd + :rest of line */ | ||
219 | fprintf(new_fp, "%s%s%s\n", name, new_passwd, cp); | ||
220 | changed_lines++; | ||
221 | } /* else delete user or group: skip the line */ | ||
222 | next: | ||
131 | free(line); | 223 | free(line); |
132 | } | 224 | } |
225 | |||
226 | if (changed_lines == 0) { | ||
227 | if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && member) | ||
228 | bb_error_msg("can't find %s in %s", member, filename); | ||
229 | if ((ENABLE_ADDUSER || ENABLE_ADDGROUP) | ||
230 | && applet_name[0] == 'a' && !member | ||
231 | ) { | ||
232 | /* add user or group */ | ||
233 | fprintf(new_fp, "%s%s\n", name, new_passwd); | ||
234 | changed_lines++; | ||
235 | } | ||
236 | } | ||
237 | |||
133 | fcntl(old_fd, F_SETLK, &lock); | 238 | fcntl(old_fd, F_SETLK, &lock); |
134 | 239 | ||
135 | /* We do want all of them to execute, thus | instead of || */ | 240 | /* We do want all of them to execute, thus | instead of || */ |
241 | errno = 0; | ||
136 | if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) | 242 | if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) |
137 | || rename(fnamesfx, filename) | 243 | || rename(fnamesfx, filename) |
138 | ) { | 244 | ) { |
139 | /* At least one of those failed */ | 245 | /* At least one of those failed */ |
246 | bb_perror_nomsg(); | ||
140 | goto unlink_new; | 247 | goto unlink_new; |
141 | } | 248 | } |
142 | ret = cnt; /* whee, success! */ | 249 | /* Success: ret >= 0 */ |
250 | ret = changed_lines; | ||
143 | 251 | ||
144 | unlink_new: | 252 | unlink_new: |
145 | if (ret < 0) unlink(fnamesfx); | 253 | if (ret < 0) |
254 | unlink(fnamesfx); | ||
146 | 255 | ||
147 | close_old_fp: | 256 | close_old_fp: |
148 | fclose(old_fp); | 257 | fclose(old_fp); |
@@ -150,6 +259,6 @@ int FAST_FUNC update_passwd(const char *filename, const char *username, | |||
150 | free_mem: | 259 | free_mem: |
151 | free(fnamesfx); | 260 | free(fnamesfx); |
152 | free((char *)filename); | 261 | free((char *)filename); |
153 | free((char *)username); | 262 | free((char *)name); |
154 | return ret; | 263 | return ret; |
155 | } | 264 | } |
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c index 5032d7b99..5a0cf3fff 100644 --- a/loginutils/addgroup.c +++ b/loginutils/addgroup.c | |||
@@ -9,7 +9,6 @@ | |||
9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | |||
13 | #include "libbb.h" | 12 | #include "libbb.h" |
14 | 13 | ||
15 | static void xgroup_study(struct group *g) | 14 | static void xgroup_study(struct group *g) |
@@ -45,8 +44,8 @@ static void xgroup_study(struct group *g) | |||
45 | /* append a new user to the passwd file */ | 44 | /* append a new user to the passwd file */ |
46 | static void new_group(char *group, gid_t gid) | 45 | static void new_group(char *group, gid_t gid) |
47 | { | 46 | { |
48 | FILE *file; | ||
49 | struct group gr; | 47 | struct group gr; |
48 | char *p; | ||
50 | 49 | ||
51 | /* make sure gid and group haven't already been allocated */ | 50 | /* make sure gid and group haven't already been allocated */ |
52 | gr.gr_gid = gid; | 51 | gr.gr_gid = gid; |
@@ -54,67 +53,17 @@ static void new_group(char *group, gid_t gid) | |||
54 | xgroup_study(&gr); | 53 | xgroup_study(&gr); |
55 | 54 | ||
56 | /* add entry to group */ | 55 | /* add entry to group */ |
57 | file = xfopen(bb_path_group_file, "a"); | 56 | p = xasprintf("x:%u:", gr.gr_gid); |
58 | /* group:passwd:gid:userlist */ | 57 | if (update_passwd(bb_path_group_file, group, p, NULL) < 0) |
59 | fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid); | 58 | exit(EXIT_FAILURE); |
60 | if (ENABLE_FEATURE_CLEAN_UP) | 59 | if (ENABLE_FEATURE_CLEAN_UP) |
61 | fclose(file); | 60 | free(p); |
62 | #if ENABLE_FEATURE_SHADOWPASSWDS | 61 | #if ENABLE_FEATURE_SHADOWPASSWDS |
63 | file = fopen_or_warn(bb_path_gshadow_file, "a"); | 62 | /* Ignore errors: if file is missing we suppose admin doesn't want it */ |
64 | if (file) { | 63 | update_passwd(bb_path_gshadow_file, group, "!::", NULL); |
65 | fprintf(file, "%s:!::\n", group); | ||
66 | if (ENABLE_FEATURE_CLEAN_UP) | ||
67 | fclose(file); | ||
68 | } | ||
69 | #endif | 64 | #endif |
70 | } | 65 | } |
71 | 66 | ||
72 | #if ENABLE_FEATURE_ADDUSER_TO_GROUP | ||
73 | static void add_user_to_group(char **args, | ||
74 | const char *path, | ||
75 | FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) | ||
76 | { | ||
77 | char *line; | ||
78 | int len = strlen(args[1]); | ||
79 | llist_t *plist = NULL; | ||
80 | FILE *group_file; | ||
81 | |||
82 | group_file = fopen_func(path, "r"); | ||
83 | |||
84 | if (!group_file) return; | ||
85 | |||
86 | while ((line = xmalloc_fgetline(group_file)) != NULL) { | ||
87 | /* Find the group */ | ||
88 | if (!strncmp(line, args[1], len) | ||
89 | && line[len] == ':' | ||
90 | ) { | ||
91 | /* Add the new user */ | ||
92 | line = xasprintf("%s%s%s", line, | ||
93 | last_char_is(line, ':') ? "" : ",", | ||
94 | args[0]); | ||
95 | } | ||
96 | llist_add_to_end(&plist, line); | ||
97 | } | ||
98 | |||
99 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
100 | fclose(group_file); | ||
101 | group_file = fopen_func(path, "w"); | ||
102 | while ((line = llist_pop(&plist))) { | ||
103 | if (group_file) | ||
104 | fprintf(group_file, "%s\n", line); | ||
105 | free(line); | ||
106 | } | ||
107 | if (group_file) | ||
108 | fclose(group_file); | ||
109 | } else { | ||
110 | group_file = fopen_func(path, "w"); | ||
111 | if (group_file) | ||
112 | while ((line = llist_pop(&plist))) | ||
113 | fprintf(group_file, "%s\n", line); | ||
114 | } | ||
115 | } | ||
116 | #endif | ||
117 | |||
118 | /* | 67 | /* |
119 | * addgroup will take a login_name as its first parameter. | 68 | * addgroup will take a login_name as its first parameter. |
120 | * | 69 | * |
@@ -166,10 +115,12 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv) | |||
166 | return EXIT_SUCCESS; | 115 | return EXIT_SUCCESS; |
167 | } | 116 | } |
168 | } | 117 | } |
169 | add_user_to_group(argv, bb_path_group_file, xfopen); | 118 | if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) { |
170 | #if ENABLE_FEATURE_SHADOWPASSWDS | 119 | return EXIT_FAILURE; |
171 | add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn); | 120 | } |
172 | #endif | 121 | # if ENABLE_FEATURE_SHADOWPASSWDS |
122 | update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]); | ||
123 | # endif | ||
173 | } else | 124 | } else |
174 | #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ | 125 | #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ |
175 | { | 126 | { |
diff --git a/loginutils/adduser.c b/loginutils/adduser.c index b94bb3aea..d0a870c54 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c | |||
@@ -7,14 +7,12 @@ | |||
7 | * | 7 | * |
8 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | 8 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
9 | */ | 9 | */ |
10 | |||
11 | #include "libbb.h" | 10 | #include "libbb.h" |
12 | 11 | ||
13 | #define OPT_DONT_SET_PASS (1 << 4) | 12 | #define OPT_DONT_SET_PASS (1 << 4) |
14 | #define OPT_SYSTEM_ACCOUNT (1 << 5) | 13 | #define OPT_SYSTEM_ACCOUNT (1 << 5) |
15 | #define OPT_DONT_MAKE_HOME (1 << 6) | 14 | #define OPT_DONT_MAKE_HOME (1 << 6) |
16 | 15 | ||
17 | |||
18 | /* remix */ | 16 | /* remix */ |
19 | /* recoded such that the uid may be passed in *p */ | 17 | /* recoded such that the uid may be passed in *p */ |
20 | static void passwd_study(struct passwd *p) | 18 | static void passwd_study(struct passwd *p) |
@@ -88,10 +86,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) | |||
88 | { | 86 | { |
89 | struct passwd pw; | 87 | struct passwd pw; |
90 | const char *usegroup = NULL; | 88 | const char *usegroup = NULL; |
91 | FILE *file; | 89 | char *p; |
92 | #if ENABLE_FEATURE_SHADOWPASSWDS | ||
93 | int fd; | ||
94 | #endif | ||
95 | 90 | ||
96 | #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS | 91 | #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS |
97 | applet_long_options = adduser_longopts; | 92 | applet_long_options = adduser_longopts; |
@@ -124,32 +119,19 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) | |||
124 | /* make sure everything is kosher and setup uid && maybe gid */ | 119 | /* make sure everything is kosher and setup uid && maybe gid */ |
125 | passwd_study(&pw); | 120 | passwd_study(&pw); |
126 | 121 | ||
127 | /* add to passwd */ | 122 | p = xasprintf("x:%u:%u:%s:%s:%s", pw.pw_uid, pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell); |
128 | file = xfopen(bb_path_passwd_file, "a"); | 123 | if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) { |
129 | //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */ | 124 | return EXIT_FAILURE; |
130 | if (putpwent(&pw, file) != 0) { | ||
131 | bb_perror_nomsg_and_die(); | ||
132 | } | 125 | } |
133 | /* do fclose even if !ENABLE_FEATURE_CLEAN_UP. | 126 | if (ENABLE_FEATURE_CLEAN_UP) |
134 | * We will exec passwd, files must be flushed & closed before that! */ | 127 | free(p); |
135 | fclose(file); | ||
136 | 128 | ||
137 | #if ENABLE_FEATURE_SHADOWPASSWDS | 129 | #if ENABLE_FEATURE_SHADOWPASSWDS |
138 | /* add to shadow if necessary */ | 130 | p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL) / 86400)); /* sp->sp_lstchg */ |
139 | /* fopen(..., "a"); would create shadow file, which is wrong. | 131 | /* Ignore errors: if file is missing we suppose admin doesn't want it */ |
140 | * If shadow file doesn't exist, admin probably does not want it */ | 132 | update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL); |
141 | fd = open_or_warn(bb_path_shadow_file, O_WRONLY | O_APPEND); | 133 | if (ENABLE_FEATURE_CLEAN_UP) |
142 | if (fd >= 0) { | 134 | free(p); |
143 | char *s = xasprintf("%s:!:%u:0:99999:7:::\n", | ||
144 | pw.pw_name, /* username */ | ||
145 | (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */ | ||
146 | /*0,*/ /* sp->sp_min */ | ||
147 | /*99999,*/ /* sp->sp_max */ | ||
148 | /*7*/ /* sp->sp_warn */ | ||
149 | ); | ||
150 | xwrite_str(fd, s); | ||
151 | close(fd); | ||
152 | } | ||
153 | #endif | 135 | #endif |
154 | 136 | ||
155 | /* add to group */ | 137 | /* add to group */ |
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c index c83d1dad7..4bffbe83f 100644 --- a/loginutils/chpasswd.c +++ b/loginutils/chpasswd.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * Written for SLIND (from passwd.c) by Alexander Shishkin <virtuoso@slind.org> | 5 | * Written for SLIND (from passwd.c) by Alexander Shishkin <virtuoso@slind.org> |
6 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 6 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
7 | */ | 7 | */ |
8 | |||
9 | #include "libbb.h" | 8 | #include "libbb.h" |
10 | 9 | ||
11 | #if ENABLE_GETOPT_LONG | 10 | #if ENABLE_GETOPT_LONG |
@@ -53,10 +52,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) | |||
53 | /* This is rather complex: if user is not found in /etc/shadow, | 52 | /* This is rather complex: if user is not found in /etc/shadow, |
54 | * we try to find & change his passwd in /etc/passwd */ | 53 | * we try to find & change his passwd in /etc/passwd */ |
55 | #if ENABLE_FEATURE_SHADOWPASSWDS | 54 | #if ENABLE_FEATURE_SHADOWPASSWDS |
56 | rc = update_passwd(bb_path_shadow_file, name, pass); | 55 | rc = update_passwd(bb_path_shadow_file, name, pass, NULL); |
57 | if (rc == 0) /* no lines updated, no errors detected */ | 56 | if (rc == 0) /* no lines updated, no errors detected */ |
58 | #endif | 57 | #endif |
59 | rc = update_passwd(bb_path_passwd_file, name, pass); | 58 | rc = update_passwd(bb_path_passwd_file, name, pass, NULL); |
60 | /* LOGMODE_BOTH logs to syslog also */ | 59 | /* LOGMODE_BOTH logs to syslog also */ |
61 | logmode = LOGMODE_BOTH; | 60 | logmode = LOGMODE_BOTH; |
62 | if (rc < 0) | 61 | if (rc < 0) |
diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 56253712e..293e324b0 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c | |||
@@ -9,117 +9,48 @@ | |||
9 | * Licensed under GPL version 2, see file LICENSE in this tarball for details. | 9 | * Licensed under GPL version 2, see file LICENSE in this tarball for details. |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | |||
13 | #include "libbb.h" | 12 | #include "libbb.h" |
14 | 13 | ||
15 | /* Status */ | 14 | static int del_line_matching(char **args, const char *filename) |
16 | #define STATUS_OK 0 | ||
17 | #define NAME_NOT_FOUND 1 | ||
18 | #define MEMBER_NOT_FOUND 2 | ||
19 | |||
20 | static void del_line_matching(char **args, | ||
21 | const char *filename, | ||
22 | FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) | ||
23 | { | 15 | { |
24 | FILE *passwd; | 16 | if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) { |
25 | smallint error = NAME_NOT_FOUND; | 17 | return update_passwd(filename, args[2], NULL, args[1]); |
26 | char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1]; | ||
27 | char *line, *del; | ||
28 | char *new = xzalloc(1); | ||
29 | |||
30 | passwd = fopen_func(filename, "r"); | ||
31 | if (passwd) { | ||
32 | while ((line = xmalloc_fgets(passwd))) { | ||
33 | int len = strlen(name); | ||
34 | |||
35 | if (strncmp(line, name, len) == 0 | ||
36 | && line[len] == ':' | ||
37 | ) { | ||
38 | error = STATUS_OK; | ||
39 | if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) { | ||
40 | struct group *gr; | ||
41 | char *p; | ||
42 | if (args[2] | ||
43 | /* There were two args on commandline */ | ||
44 | && (gr = getgrnam(name)) | ||
45 | /* The group was not deleted in the meanwhile */ | ||
46 | && (p = strrchr(line, ':')) | ||
47 | /* We can find a pointer to the last ':' */ | ||
48 | ) { | ||
49 | error = MEMBER_NOT_FOUND; | ||
50 | /* Move past ':' (worst case to '\0') and cut the line */ | ||
51 | p[1] = '\0'; | ||
52 | /* Reuse p */ | ||
53 | for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) { | ||
54 | /* Add all the other group members */ | ||
55 | if (strcmp(args[1], *gr->gr_mem) != 0) { | ||
56 | del = p; | ||
57 | p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem); | ||
58 | free(del); | ||
59 | } else | ||
60 | error = STATUS_OK; | ||
61 | } | ||
62 | /* Recompose the line */ | ||
63 | line = xasprintf("%s%s\n", line, p); | ||
64 | if (ENABLE_FEATURE_CLEAN_UP) free(p); | ||
65 | } else | ||
66 | goto skip; | ||
67 | } | ||
68 | } | ||
69 | del = new; | ||
70 | new = xasprintf("%s%s", new, line); | ||
71 | free(del); | ||
72 | skip: | ||
73 | free(line); | ||
74 | } | ||
75 | |||
76 | if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); | ||
77 | |||
78 | if (error) { | ||
79 | if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) { | ||
80 | /* Set the correct values for error message */ | ||
81 | filename = name; | ||
82 | name = args[1]; | ||
83 | } | ||
84 | bb_error_msg("can't find %s in %s", name, filename); | ||
85 | } else { | ||
86 | passwd = fopen_func(filename, "w"); | ||
87 | if (passwd) { | ||
88 | fputs(new, passwd); | ||
89 | if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); | ||
90 | } | ||
91 | } | ||
92 | } | 18 | } |
93 | free(new); | 19 | return update_passwd(filename, args[1], NULL, NULL); |
94 | } | 20 | } |
95 | 21 | ||
96 | int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 22 | int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
97 | int deluser_main(int argc, char **argv) | 23 | int deluser_main(int argc, char **argv) |
98 | { | 24 | { |
99 | if (argc == 2 | 25 | if (argc != 2 |
100 | || (ENABLE_FEATURE_DEL_USER_FROM_GROUP | 26 | && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP |
101 | && (applet_name[3] == 'g' && argc == 3)) | 27 | || (applet_name[3] != 'g' || argc != 3)) |
102 | ) { | 28 | ) { |
103 | if (geteuid()) | 29 | bb_show_usage(); |
104 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | 30 | } |
105 | 31 | ||
106 | if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) | 32 | if (geteuid()) |
107 | || ENABLE_DELUSER | 33 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
108 | || (ENABLE_DELGROUP && ENABLE_DESKTOP) | 34 | |
35 | if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) | ||
36 | || ENABLE_DELUSER | ||
37 | || (ENABLE_DELGROUP && ENABLE_DESKTOP) | ||
38 | ) { | ||
39 | if (ENABLE_DELUSER | ||
40 | && (!ENABLE_DELGROUP || applet_name[3] == 'u') | ||
109 | ) { | 41 | ) { |
110 | if (ENABLE_DELUSER | 42 | if (del_line_matching(argv, bb_path_passwd_file) < 0) |
111 | && (!ENABLE_DELGROUP || applet_name[3] == 'u') | 43 | return EXIT_FAILURE; |
112 | ) { | 44 | if (ENABLE_FEATURE_SHADOWPASSWDS) { |
113 | del_line_matching(argv, bb_path_passwd_file, xfopen); | 45 | del_line_matching(argv, bb_path_shadow_file); |
114 | if (ENABLE_FEATURE_SHADOWPASSWDS) | 46 | } |
115 | del_line_matching(argv, bb_path_shadow_file, fopen_or_warn); | 47 | } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) |
116 | } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) | 48 | bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); |
117 | bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); | 49 | } |
118 | } | 50 | if (del_line_matching(argv, bb_path_group_file) < 0) |
119 | del_line_matching(argv, bb_path_group_file, xfopen); | 51 | return EXIT_FAILURE; |
120 | if (ENABLE_FEATURE_SHADOWPASSWDS) | 52 | if (ENABLE_FEATURE_SHADOWPASSWDS) { |
121 | del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn); | 53 | del_line_matching(argv, bb_path_gshadow_file); |
122 | return EXIT_SUCCESS; | 54 | } |
123 | } else | 55 | return EXIT_SUCCESS; |
124 | bb_show_usage(); | ||
125 | } | 56 | } |
diff --git a/loginutils/passwd.c b/loginutils/passwd.c index 9ed78c1b7..7b93713b9 100644 --- a/loginutils/passwd.c +++ b/loginutils/passwd.c | |||
@@ -2,7 +2,6 @@ | |||
2 | /* | 2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 | */ | 4 | */ |
5 | |||
6 | #include "libbb.h" | 5 | #include "libbb.h" |
7 | #include <syslog.h> | 6 | #include <syslog.h> |
8 | 7 | ||
@@ -181,12 +180,12 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) | |||
181 | 180 | ||
182 | #if ENABLE_FEATURE_SHADOWPASSWDS | 181 | #if ENABLE_FEATURE_SHADOWPASSWDS |
183 | filename = bb_path_shadow_file; | 182 | filename = bb_path_shadow_file; |
184 | rc = update_passwd(bb_path_shadow_file, name, newp); | 183 | rc = update_passwd(bb_path_shadow_file, name, newp, NULL); |
185 | if (rc == 0) /* no lines updated, no errors detected */ | 184 | if (rc == 0) /* no lines updated, no errors detected */ |
186 | #endif | 185 | #endif |
187 | { | 186 | { |
188 | filename = bb_path_passwd_file; | 187 | filename = bb_path_passwd_file; |
189 | rc = update_passwd(bb_path_passwd_file, name, newp); | 188 | rc = update_passwd(bb_path_passwd_file, name, newp, NULL); |
190 | } | 189 | } |
191 | /* LOGMODE_BOTH */ | 190 | /* LOGMODE_BOTH */ |
192 | if (rc < 0) | 191 | if (rc < 0) |