Skip to content

Commit 89c5d74

Browse files
committed
libnss_tcb: Match interfaces with NSS documention.
According to [1] the interfaces provided should be of return-type 'enum nss_status', and take 'int *errnop' as the fourth (and last) parameter. Additionally the returned status values should be accompanied by a corresponding ERRNO value [2] passed by the errnop pointer. [1] https://www.gnu.org/software/libc/manual/html_node/NSS-Module-Function-Internals.html [2] https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html Signed-off-by: Björn Esser <[email protected]>
1 parent b6ce07b commit 89c5d74

File tree

2 files changed

+70
-21
lines changed

2 files changed

+70
-21
lines changed

ChangeLog

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
2024-12-20 Björn Esser <besser82 at fedoraproject.org>
22

3+
libnss_tcb: Match interfaces with NSS documention.
4+
According to [1] the interfaces provided should be of return-type
5+
'enum nss_status', and take 'int *errnop' as the fourth (and last)
6+
parameter. Additionally the returned status values should be
7+
accompanied by a corresponding ERRNO value [2] passed by the errnop
8+
pointer.
9+
[1] https://www.gnu.org/software/libc/manual/html_node/NSS-Module-Function-Internals.html
10+
[2] https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html
11+
* libs/nss.c (_nss_tcb_setspent): Adapt return-type and use return
12+
values from documented macro.
13+
(_nss_tcb_endspent): Likewise.
14+
(_nss_tcb_getspnam_r): Adapt return-type, change fourth parameter
15+
to be 'int *errnop', use return values from documented macro, and
16+
set proper errno in errnop before returning. Also check the pointer
17+
to result buffer, set by fgetspent_r(3), to be non-NULL.
18+
(_nss_tcb_getspent_r): Likewise.
19+
320
libnss_tcb: Disallow potentially-malicious user names in getspnam(3).
421
IEEE Std 1003.1-2001 allows only the following characters to appear
522
in group- and usernames: letters, digits, underscores, periods,

libs/nss.c

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,27 @@
1313

1414
static __thread DIR *tcbdir = NULL;
1515

16-
int _nss_tcb_setspent(void)
16+
enum nss_status _nss_tcb_setspent(void)
1717
{
1818
if (!tcbdir) {
1919
tcbdir = opendir(TCB_DIR);
2020
if (!tcbdir)
2121
return NSS_STATUS_UNAVAIL;
2222

23-
return 1;
23+
return NSS_STATUS_SUCCESS;
2424
}
2525

2626
rewinddir(tcbdir);
27-
return 1;
27+
return NSS_STATUS_SUCCESS;
2828
}
2929

30-
int _nss_tcb_endspent(void)
30+
enum nss_status _nss_tcb_endspent(void)
3131
{
3232
if (tcbdir) {
3333
closedir(tcbdir);
3434
tcbdir = NULL;
3535
}
36-
return 1;
36+
return NSS_STATUS_SUCCESS;
3737
}
3838

3939
/******************************************************************************
@@ -91,57 +91,84 @@ static FILE *tcb_safe_open(const char *file, const char *name)
9191
return f;
9292
}
9393

94-
int _nss_tcb_getspnam_r(const char *name, struct spwd *__result_buf,
95-
char *__buffer, size_t __buflen, struct spwd **__result)
94+
enum nss_status _nss_tcb_getspnam_r(const char *name,
95+
struct spwd *__result_buf, char *__buffer, size_t __buflen, int *__errnop)
9696
{
9797
FILE *f;
9898
char *file;
9999
int retval, saved_errno;
100+
struct spwd **result_buf_ptr = NULL;
100101

101102
/* Disallow potentially-malicious user names */
102103
if (!is_valid_username(name)) {
103-
errno = ENOENT;
104+
/* we don't serve an entry here */
105+
*__errnop = ENOENT;
104106
return NSS_STATUS_NOTFOUND;
105107
}
106108

107-
if (asprintf(&file, TCB_FMT, name) < 0)
109+
if (asprintf(&file, TCB_FMT, name) < 0) {
110+
/* retry, as malloc or another resource has failed */
111+
*__errnop = EAGAIN;
108112
return NSS_STATUS_TRYAGAIN;
113+
}
114+
109115
f = tcb_safe_open(file, name);
110116
free(file);
111-
if (!f)
112-
return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
117+
if (!f) {
118+
/* $user/shadow not existing */
119+
*__errnop = ENOENT;
120+
return NSS_STATUS_UNAVAIL;
121+
}
113122

114-
retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result);
123+
retval = fgetspent_r(f, __result_buf, __buffer,
124+
__buflen, result_buf_ptr);
115125
saved_errno = errno;
116126
fclose(f);
117127
errno = saved_errno;
118-
if (!retval)
119-
return NSS_STATUS_SUCCESS;
120128

121-
switch (saved_errno) {
129+
/* real error number is retval from fgetspent_r() */
130+
switch (retval) {
122131
case 0:
123-
return NSS_STATUS_SUCCESS;
132+
if (*result_buf_ptr)
133+
return NSS_STATUS_SUCCESS;
134+
135+
/* else: no error, but entry not found;
136+
handled by fall-through to case ENOENT */
124137

125138
case ENOENT:
139+
/* if the file would not exist, we would have already
140+
bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
141+
after the call to tcb_safe_open() */
142+
*__errnop = ENOENT;
126143
return NSS_STATUS_NOTFOUND;
127144

145+
case EAGAIN:
146+
/* ressources are temporary not available */
147+
*__errnop = EAGAIN;
148+
return NSS_STATUS_TRYAGAIN;
149+
128150
case ERANGE:
151+
/* __buffer too small */
152+
*__errnop = ERANGE;
129153
return NSS_STATUS_TRYAGAIN;
130154

131155
default:
156+
/* something serious, but we can't help it */
157+
*__errnop = retval;
132158
return NSS_STATUS_UNAVAIL;
133159
}
134160
}
135161

136-
int _nss_tcb_getspent_r(struct spwd *__result_buf,
137-
char *__buffer, size_t __buflen, struct spwd **__result)
162+
enum nss_status _nss_tcb_getspent_r(struct spwd *__result_buf,
163+
char *__buffer, size_t __buflen, int *__errnop)
138164
{
139165
struct dirent *result;
140166
off_t currpos;
141167
int retval, saved_errno;
142168

143169
if (!tcbdir) {
144-
errno = ENOENT;
170+
/* tcbdir does not exist */
171+
*__errnop = ENOENT;
145172
return NSS_STATUS_UNAVAIL;
146173
}
147174

@@ -154,21 +181,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154181
closedir(tcbdir);
155182
errno = saved_errno;
156183
tcbdir = NULL;
184+
/* cannot iterate tcbdir */
185+
*__errnop = ENOENT;
157186
return NSS_STATUS_UNAVAIL;
158187
}
159188
if (!result) {
160189
closedir(tcbdir);
161-
errno = ENOENT;
190+
errno = saved_errno;
162191
tcbdir = NULL;
192+
/* we have no more entries in tcbdir */
193+
*__errnop = ENOENT;
163194
return NSS_STATUS_NOTFOUND;
164195
}
165196
errno = saved_errno;
166197
} while (!strcmp(result->d_name, ".") ||
167198
!strcmp(result->d_name, "..") || result->d_name[0] == ':');
168199

169200
retval = _nss_tcb_getspnam_r(result->d_name, __result_buf, __buffer,
170-
__buflen, __result);
201+
__buflen, __errnop);
171202

203+
/* __errnop has already been set by _nss_tcb_getspnam_r() */
172204
switch (retval) {
173205
case NSS_STATUS_SUCCESS:
174206
return NSS_STATUS_SUCCESS;

0 commit comments

Comments
 (0)