Skip to content

Commit ea61369

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 ea61369

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed

ChangeLog

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
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+
* include/attribute.h (TCB_FALLTHROUGH): New macro.
20+
321
libnss_tcb: Disallow potentially-malicious user names in getspnam(3).
422
IEEE Std 1003.1-2001 allows only the following characters to appear
523
in group- and usernames: letters, digits, underscores, periods,

include/attribute.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@
2626
# define TCB_NONNULL(params)
2727
#endif
2828

29+
#if TCB_GNUC_PREREQ(7,1)
30+
# define TCB_FALLTHROUGH __attribute__((fallthrough));
31+
#else
32+
# define TCB_FALLTHROUGH /* FALLTHRU */
33+
#endif
34+
2935
#endif /* TCB_ATTRIBUTE_H_ */

libs/nss.c

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,32 @@
99
#include <fcntl.h>
1010
#include <dirent.h>
1111

12+
#include "attribute.h"
1213
#include "tcb.h"
1314

1415
static __thread DIR *tcbdir = NULL;
1516

16-
int _nss_tcb_setspent(void)
17+
enum nss_status _nss_tcb_setspent(void)
1718
{
1819
if (!tcbdir) {
1920
tcbdir = opendir(TCB_DIR);
2021
if (!tcbdir)
2122
return NSS_STATUS_UNAVAIL;
2223

23-
return 1;
24+
return NSS_STATUS_SUCCESS;
2425
}
2526

2627
rewinddir(tcbdir);
27-
return 1;
28+
return NSS_STATUS_SUCCESS;
2829
}
2930

30-
int _nss_tcb_endspent(void)
31+
enum nss_status _nss_tcb_endspent(void)
3132
{
3233
if (tcbdir) {
3334
closedir(tcbdir);
3435
tcbdir = NULL;
3536
}
36-
return 1;
37+
return NSS_STATUS_SUCCESS;
3738
}
3839

3940
/******************************************************************************
@@ -91,57 +92,85 @@ static FILE *tcb_safe_open(const char *file, const char *name)
9192
return f;
9293
}
9394

94-
int _nss_tcb_getspnam_r(const char *name, struct spwd *__result_buf,
95-
char *__buffer, size_t __buflen, struct spwd **__result)
95+
enum nss_status _nss_tcb_getspnam_r(const char *name,
96+
struct spwd *__result_buf, char *__buffer, size_t __buflen, int *__errnop)
9697
{
9798
FILE *f;
9899
char *file;
99100
int retval, saved_errno;
101+
struct spwd **result_buf_ptr = NULL;
100102

101103
/* Disallow potentially-malicious user names */
102104
if (!is_valid_username(name)) {
103-
errno = ENOENT;
105+
/* we don't serve an entry here */
106+
*__errnop = ENOENT;
104107
return NSS_STATUS_NOTFOUND;
105108
}
106109

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

114-
retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result);
124+
retval = fgetspent_r(f, __result_buf, __buffer,
125+
__buflen, result_buf_ptr);
115126
saved_errno = errno;
116127
fclose(f);
117128
errno = saved_errno;
118-
if (!retval)
119-
return NSS_STATUS_SUCCESS;
120129

121-
switch (saved_errno) {
130+
/* real error number is retval from fgetspent_r() */
131+
switch (retval) {
122132
case 0:
123-
return NSS_STATUS_SUCCESS;
133+
if (*result_buf_ptr)
134+
return NSS_STATUS_SUCCESS;
135+
136+
/* else: no error, but entry not found;
137+
is properly handled by case ENOENT */
138+
TCB_FALLTHROUGH
124139

125140
case ENOENT:
141+
/* if the file would not exist, we would have already
142+
bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
143+
after the call to tcb_safe_open() */
144+
*__errnop = ENOENT;
126145
return NSS_STATUS_NOTFOUND;
127146

147+
case EAGAIN:
148+
/* ressources are temporary not available */
149+
*__errnop = EAGAIN;
150+
return NSS_STATUS_TRYAGAIN;
151+
128152
case ERANGE:
153+
/* __buffer too small */
154+
*__errnop = ERANGE;
129155
return NSS_STATUS_TRYAGAIN;
130156

131157
default:
158+
/* something serious, but we can't help it */
159+
*__errnop = retval;
132160
return NSS_STATUS_UNAVAIL;
133161
}
134162
}
135163

136-
int _nss_tcb_getspent_r(struct spwd *__result_buf,
137-
char *__buffer, size_t __buflen, struct spwd **__result)
164+
enum nss_status _nss_tcb_getspent_r(struct spwd *__result_buf,
165+
char *__buffer, size_t __buflen, int *__errnop)
138166
{
139167
struct dirent *result;
140168
off_t currpos;
141169
int retval, saved_errno;
142170

143171
if (!tcbdir) {
144-
errno = ENOENT;
172+
/* tcbdir does not exist */
173+
*__errnop = ENOENT;
145174
return NSS_STATUS_UNAVAIL;
146175
}
147176

@@ -154,21 +183,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154183
closedir(tcbdir);
155184
errno = saved_errno;
156185
tcbdir = NULL;
186+
/* cannot iterate tcbdir */
187+
*__errnop = ENOENT;
157188
return NSS_STATUS_UNAVAIL;
158189
}
159190
if (!result) {
160191
closedir(tcbdir);
161-
errno = ENOENT;
192+
errno = saved_errno;
162193
tcbdir = NULL;
194+
/* we have no more entries in tcbdir */
195+
*__errnop = ENOENT;
163196
return NSS_STATUS_NOTFOUND;
164197
}
165198
errno = saved_errno;
166199
} while (!strcmp(result->d_name, ".") ||
167200
!strcmp(result->d_name, "..") || result->d_name[0] == ':');
168201

169202
retval = _nss_tcb_getspnam_r(result->d_name, __result_buf, __buffer,
170-
__buflen, __result);
203+
__buflen, __errnop);
171204

205+
/* __errnop has already been set by _nss_tcb_getspnam_r() */
172206
switch (retval) {
173207
case NSS_STATUS_SUCCESS:
174208
return NSS_STATUS_SUCCESS;

0 commit comments

Comments
 (0)