summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-14 00:51:05 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-14 00:51:05 +0000
commit829bbd3b5701f656c94f1cc672faa39946675d13 (patch)
treedbe6672228a3cb51eb8031ba714bb4abb96decf4
parentf2b39e088d6ccbf4a540c741059c2f661eebc9ac (diff)
downloadbusybox-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.h11
-rw-r--r--libbb/Kbuild3
-rw-r--r--libbb/update_passwd.c163
-rw-r--r--loginutils/addgroup.c75
-rw-r--r--loginutils/adduser.c40
-rw-r--r--loginutils/chpasswd.c5
-rw-r--r--loginutils/deluser.c133
-rw-r--r--loginutils/passwd.c5
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 */
1144extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; 1144extern 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 */
1146extern 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
1151extern int update_passwd(const char *filename,
1152 const char *username,
1153 const char *data,
1154 const char *member) FAST_FUNC;
1148 1155
1149int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC; 1156int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC;
1150int index_in_strings(const char *strings, const char *key) FAST_FUNC; 1157int 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
120lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o 120lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o
121lib-$(CONFIG_LOSETUP) += loop.o 121lib-$(CONFIG_LOSETUP) += loop.o
122lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o 122lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
123lib-$(CONFIG_ADDGROUP) += update_passwd.o
124lib-$(CONFIG_ADDUSER) += update_passwd.o
125lib-$(CONFIG_DELUSER) += update_passwd.o
123lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o 126lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o
124lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o 127lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
125lib-$(CONFIG_CRYPTPW) += pw_encrypt.o 128lib-$(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
41int 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*/
70int 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
15static void xgroup_study(struct group *g) 14static 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 */
46static void new_group(char *group, gid_t gid) 45static 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
73static 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 */
20static void passwd_study(struct passwd *p) 18static 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 */ 14static 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
20static 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
96int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 22int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
97int deluser_main(int argc, char **argv) 23int 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)