Skip to content

Commit 6b386b8

Browse files
committed
CA-375277: unixpwd_stubs.c: factor out common code and use enter/leave blocking section where possible
unshadow is not thread safe, but the other ones should be. TODO: double check all C API calls in unixpwd.c with the MT-safe portion of the manpage Signed-off-by: Edwin Török <[email protected]>
1 parent a7cf4ff commit 6b386b8

File tree

1 file changed

+52
-66
lines changed

1 file changed

+52
-66
lines changed

unixpwd/c/unixpwd_stubs.c

+52-66
Original file line numberDiff line numberDiff line change
@@ -20,104 +20,90 @@
2020
#include <caml/fail.h>
2121
#include <caml/callback.h>
2222
#include <caml/memory.h>
23+
#include <caml/threads.h>
24+
#include <caml/unixsupport.h>
2325

2426
#include "unixpwd.h"
2527

26-
27-
CAMLprim value
28-
caml_unixpwd_getpwd(value caml_user)
28+
static CAMLprim value caml_unixpwd_get_(value caml_user, const char *fname, char*(*f)(const char*))
2929
{
3030
CAMLparam1(caml_user);
31-
const char *user;
32-
char *passwd;
31+
char *user;
32+
char *passwd;
33+
int saved_errno;
3334
CAMLlocal1(pw);
3435

35-
user = String_val(caml_user);
36-
passwd = unixpwd_getpwd(user);
37-
if (passwd == NULL && errno != 0)
38-
caml_failwith(strerror(errno));
39-
if (passwd == NULL)
40-
caml_failwith("unspecified error in caml_unixpwd_getpwd()");
36+
user = caml_stat_strdup(String_val(caml_user));
37+
caml_enter_blocking_section();
38+
errno = 0;
39+
passwd = f(user);
40+
saved_errno = errno;
41+
caml_stat_free(user); user = NULL;
42+
caml_leave_blocking_section();
43+
errno = saved_errno;
44+
45+
if (passwd == NULL) /* errno of 0 will be mapped to `EUNKNOWNERR of 0` */
46+
uerror(fname, caml_user);
4147

4248
pw = caml_copy_string(passwd);
4349
free(passwd);
4450
CAMLreturn(pw);
4551
}
4652

4753
CAMLprim value
48-
caml_unixpwd_getspw(value caml_user)
54+
caml_unixpwd_getpwd(value caml_user)
4955
{
50-
CAMLparam1(caml_user);
51-
const char *user;
52-
char *passwd;
53-
CAMLlocal1(pw);
54-
55-
user = String_val(caml_user);
56-
passwd = unixpwd_getspw(user);
57-
if (passwd == NULL && errno != 0)
58-
caml_failwith(strerror(errno));
59-
if (passwd == NULL)
60-
caml_failwith("unspecified error in caml_unixpwd_getspw()");
61-
62-
pw = caml_copy_string(passwd);
63-
free(passwd);
64-
CAMLreturn(pw);
56+
return caml_unixpwd_get_(caml_user, "unixpwd_getpwd", unixpwd_getpwd);
6557
}
6658

67-
59+
CAMLprim value
60+
caml_unixpwd_getspw(value caml_user)
61+
{
62+
return caml_unixpwd_get_(caml_user, "unixpwd_getspw", unixpwd_getspw);
63+
}
6864

6965
CAMLprim value
7066
caml_unixpwd_get(value caml_user)
7167
{
72-
CAMLparam1(caml_user);
73-
const char *user;
74-
char *passwd;
75-
CAMLlocal1(pw);
76-
77-
user = String_val(caml_user);
78-
passwd = unixpwd_get(user);
79-
if (passwd == NULL && errno != 0)
80-
caml_failwith(strerror(errno));
81-
if (passwd == NULL)
82-
caml_failwith("unspecified error in caml_unixpwd_get()");
83-
84-
pw = caml_copy_string(passwd);
85-
free(passwd);
86-
CAMLreturn(pw);
68+
return caml_unixpwd_get_(caml_user, "unixpwd_get", unixpwd_get);
8769
}
8870

89-
CAMLprim value
90-
caml_unixpwd_setpwd(value caml_user, value caml_password)
71+
static CAMLprim value caml_unixpwd_set_(value caml_user, value caml_password, const char *fname, int(*f)(const char*, char*))
9172
{
9273
CAMLparam2(caml_user, caml_password);
93-
const char *user;
94-
char *password;
95-
int rc;
74+
char *user;
75+
char *password;
76+
int saved_errno;
77+
int rc;
9678

97-
user = String_val(caml_user);
79+
user = caml_stat_strdup(String_val(caml_user));
9880
password = caml_stat_strdup(String_val(caml_password));
99-
rc = unixpwd_setpwd(user, password);
81+
caml_enter_blocking_section();
82+
errno = 0;
83+
rc = f(user, password);
84+
saved_errno = errno;
85+
caml_stat_free(user);
10086
caml_stat_free(password);
87+
caml_leave_blocking_section();
88+
errno = saved_errno;
89+
10190
if (rc != 0)
102-
caml_failwith(strerror(rc));
91+
uerror(fname, caml_user); /* only raise with user not pass */
10392
CAMLreturn(Val_unit);
10493
}
10594

10695
CAMLprim value
107-
caml_unixpwd_setspw(value caml_user, value caml_password)
96+
caml_unixpwd_setpwd(value caml_user, value caml_password)
10897
{
109-
CAMLparam2(caml_user, caml_password);
110-
const char *user;
111-
char *password;
112-
int rc;
98+
return caml_unixpwd_set_(caml_user, caml_password, "unix_setpwd",
99+
unixpwd_setpwd);
100+
}
113101

114-
user = String_val(caml_user);
115-
password = caml_stat_strdup(String_val(caml_password));
116-
rc = unixpwd_setspw(user, password);
117-
caml_stat_free(password);
118-
if (rc != 0)
119-
caml_failwith(strerror(rc));
120-
CAMLreturn(Val_unit);
102+
CAMLprim value
103+
caml_unixpwd_setspw(value caml_user, value caml_password)
104+
{
105+
return caml_unixpwd_set_(caml_user, caml_password, "unix_setpwd",
106+
unixpwd_setspw);
121107
}
122108

123109
CAMLprim value
@@ -127,11 +113,11 @@ caml_unixpwd_unshadow(value unused)
127113
char *passwords;
128114
CAMLlocal1(str);
129115

116+
/* NOT thread safe, retain runtime lock for now, it uses setpwent/endpwent,
117+
* this should be replaced by fopen/fpwgetent_r/etc. */
130118
passwords = unixpwd_unshadow();
131-
if (passwords == NULL && errno != 0)
132-
caml_failwith(strerror(errno));
133119
if (passwords == NULL)
134-
caml_failwith("unspecified error in caml_unixpwd_unshadow()");
120+
uerror("unixpwd_unshadow", Nothing);
135121

136122
str = caml_copy_string(passwords);
137123
free(passwords);

0 commit comments

Comments
 (0)