Skip to content

Commit f5a1c50

Browse files
committed
unixpwd: fix reentrance of unixpwd_setpwd() and unixpwd_setspw()
- prefer fgetpwent_r() over getpwent_r() to avoid ETC_PASSWD FILE to be shared against threads - prefer fgetspent_r() over getspent_r() to avoid ETC_SPASSWD FILE to be shared against threads - while here, unlink(2) tmp_name on error in unixpwd_setpwd() to avoid leaving temporary file on error Signed-off-by: Sebastien Marie <[email protected]>
1 parent 7cc153f commit f5a1c50

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

unixpwd/c/unixpwd.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ unixpwd_setpwd(const char *user, char *password)
8686
*pw;
8787
char buf[BUFLEN];
8888
int tmp;
89-
FILE *tmp_file;
89+
FILE *tmp_file,
90+
*passwd_file;
9091
char tmp_name[PATH_MAX];
9192
struct stat statbuf;
9293
int rc;
@@ -96,18 +97,28 @@ unixpwd_setpwd(const char *user, char *password)
9697
tmp = mkstemp(tmp_name);
9798
if (tmp == -1)
9899
return errno;
99-
if (stat(ETC_PASSWD, &statbuf) != 0
100+
101+
passwd_file = fopen(ETC_PASSWD, "rbe");
102+
if (passwd_file == NULL) {
103+
rc = errno;
104+
close(tmp);
105+
unlink(tmp_name);
106+
return rc;
107+
}
108+
109+
if (fstat(fileno(passwd_file), &statbuf) != 0
100110
|| fchown(tmp, statbuf.st_uid, statbuf.st_gid) != 0
101111
|| fchmod(tmp, statbuf.st_mode) != 0
102112
|| (tmp_file = fdopen(tmp, "w")) == NULL) {
103113
rc = errno ? errno : EPERM;
114+
fclose(passwd_file);
104115
close(tmp);
116+
unlink(tmp_name);
105117
return rc;
106118
}
107119

108-
setpwent();
109120
while (1) {
110-
rc = getpwent_r(&pwd, buf, BUFLEN, &pw);
121+
rc = fgetpwent_r(passwd_file, &pwd, buf, BUFLEN, &pw);
111122
if (rc != 0 || !pw)
112123
break;
113124
if (!strcmp(user, pw->pw_name)) {
@@ -116,8 +127,8 @@ unixpwd_setpwd(const char *user, char *password)
116127
}
117128
putpwent(pw, tmp_file);
118129
}
119-
endpwent();
120130

131+
fclose(passwd_file);
121132
fclose(tmp_file);
122133
if (rc != ENOENT) {
123134
unlink(tmp_name);
@@ -144,7 +155,8 @@ unixpwd_setspw(const char *user, char *password)
144155
*sp;
145156
char buf[BUFLEN];
146157
int tmp;
147-
FILE *tmp_file = NULL;
158+
FILE *tmp_file = NULL,
159+
*spasswd_file;
148160
char tmp_name[PATH_MAX];
149161
struct stat statbuf;
150162
int rc;
@@ -154,26 +166,36 @@ unixpwd_setspw(const char *user, char *password)
154166
tmp = mkstemp(tmp_name);
155167
if (tmp == -1)
156168
return errno;
157-
if (stat(ETC_SPASSWD, &statbuf) != 0
169+
170+
spasswd_file = fopen(ETC_SPASSWD, "rbe");
171+
if (spasswd_file == NULL) {
172+
rc = errno;
173+
close(tmp);
174+
unlink(tmp_name);
175+
return rc;
176+
}
177+
178+
if (fstat(fileno(spasswd_file), &statbuf) != 0
158179
|| fchown(tmp, statbuf.st_uid, statbuf.st_gid) != 0
159180
|| fchmod(tmp, statbuf.st_mode) != 0
160181
|| (tmp_file = fdopen(tmp, "w")) == NULL) {
161182
rc = errno ? errno : EPERM;
183+
fclose(spasswd_file);
162184
close(tmp);
163185
unlink(tmp_name);
164186
return rc;
165187
}
166188
if (lckpwdf() != 0) {
189+
fclose(spasswd_file);
167190
if (tmp_file)
168191
fclose(tmp_file);
169192
close(tmp);
170193
unlink(tmp_name);
171194
return ENOLCK;
172195
}
173196

174-
setspent();
175197
while (1) {
176-
rc = getspent_r(&spw, buf, BUFLEN, &sp);
198+
rc = fgetspent_r(spasswd_file, &spw, buf, BUFLEN, &sp);
177199
if (rc != 0 || !sp)
178200
break;
179201
if (!strcmp(user, sp->sp_namp)) {
@@ -182,8 +204,8 @@ unixpwd_setspw(const char *user, char *password)
182204
}
183205
putspent(sp, tmp_file);
184206
}
185-
endspent();
186207

208+
fclose(spasswd_file);
187209
fclose(tmp_file);
188210
if (rc != ENOENT) {
189211
ulckpwdf();

0 commit comments

Comments
 (0)