Skip to content

Commit a26fe47

Browse files
committed
libnss_tcb: Match interfaces with NSS documentation.
According to [1] the interfaces provided are of return-type 'enum nss_status', of which the _nss_database_getXXX_r() interfaces are mandated to take four parameters: a pointer to the result, a pointer to an additional buffer, the size of the buffer supplied, and a pointer to an integer to report error values (errnop). The returned status values are meant to be accompanied by a corresponding error value [2] passed through 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 a26fe47

File tree

2 files changed

+66
-20
lines changed

2 files changed

+66
-20
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 documentation.
4+
According to [1] the interfaces provided are of return-type
5+
'enum nss_status', of which the _nss_database_getXXX_r() interfaces
6+
are mandated to take four parameters: a pointer to the result,
7+
a pointer to an additional buffer, the size of the buffer supplied,
8+
and a pointer to an integer to report error values (errnop). The
9+
returned status values are meant to be accompanied by a corresponding
10+
error value [2] passed through the errnop pointer.
11+
[1] https://www.gnu.org/software/libc/manual/html_node/NSS-Module-Function-Internals.html
12+
[2] https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html
13+
* libs/nss.c (_nss_tcb_setspent): Adapt return-type and use return
14+
values from documented macro.
15+
(_nss_tcb_endspent): Likewise.
16+
(_nss_tcb_getspnam_r): Adapt return-type, change fourth parameter
17+
to be 'int *errnop', use return values from documented macros, and
18+
set proper errno in errnop before returning.
19+
(_nss_tcb_getspent_r): Likewise.
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,

libs/nss.c

Lines changed: 48 additions & 20 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,80 @@ 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;
100100

101101
/* Disallow potentially-malicious user names */
102102
if (!is_valid_username(name)) {
103-
errno = ENOENT;
103+
/* we don't serve an entry here */
104+
*__errnop = ENOENT;
104105
return NSS_STATUS_NOTFOUND;
105106
}
106107

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

114-
retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result);
122+
retval = fgetspent_r(f, __result_buf, __buffer,
123+
__buflen, &__result_buf);
115124
saved_errno = errno;
116125
fclose(f);
117126
errno = saved_errno;
118-
if (!retval)
119-
return NSS_STATUS_SUCCESS;
120127

121-
switch (saved_errno) {
128+
/* real error number is retval from fgetspent_r(),
129+
by NSS spec errnop *MUST NOT* be set to 0 */
130+
if (retval)
131+
*__errnop = retval;
132+
133+
switch (retval) {
122134
case 0:
135+
/* no error, entry found */
123136
return NSS_STATUS_SUCCESS;
124137

125138
case ENOENT:
139+
/* if the file would not exist nor be readable, we would
140+
have already bailed out with ENOENT/NSS_STATUS_UNAVAIL
141+
immediately after the call to tcb_safe_open() */
126142
return NSS_STATUS_NOTFOUND;
127143

144+
case EAGAIN:
145+
/* ressources are temporary not available */
146+
return NSS_STATUS_TRYAGAIN;
147+
128148
case ERANGE:
149+
/* buffer too small */
129150
return NSS_STATUS_TRYAGAIN;
130151

131152
default:
153+
/* something else, e.g. parser error, but we can't help it */
132154
return NSS_STATUS_UNAVAIL;
133155
}
134156
}
135157

136-
int _nss_tcb_getspent_r(struct spwd *__result_buf,
137-
char *__buffer, size_t __buflen, struct spwd **__result)
158+
enum nss_status _nss_tcb_getspent_r(struct spwd *__result_buf,
159+
char *__buffer, size_t __buflen, int *__errnop)
138160
{
139161
struct dirent *result;
140162
off_t currpos;
141163
int retval, saved_errno;
142164

143165
if (!tcbdir) {
144-
errno = ENOENT;
166+
/* tcbdir does not exist */
167+
*__errnop = ENOENT;
145168
return NSS_STATUS_UNAVAIL;
146169
}
147170

@@ -154,21 +177,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154177
closedir(tcbdir);
155178
errno = saved_errno;
156179
tcbdir = NULL;
180+
/* cannot iterate tcbdir */
181+
*__errnop = ENOENT;
157182
return NSS_STATUS_UNAVAIL;
158183
}
159184
if (!result) {
160185
closedir(tcbdir);
161-
errno = ENOENT;
186+
errno = saved_errno;
162187
tcbdir = NULL;
188+
/* we have no more entries in tcbdir */
189+
*__errnop = ENOENT;
163190
return NSS_STATUS_NOTFOUND;
164191
}
165192
errno = saved_errno;
166193
} while (!strcmp(result->d_name, ".") ||
167194
!strcmp(result->d_name, "..") || result->d_name[0] == ':');
168195

169196
retval = _nss_tcb_getspnam_r(result->d_name, __result_buf, __buffer,
170-
__buflen, __result);
197+
__buflen, __errnop);
171198

199+
/* errnop has already been set by _nss_tcb_getspnam_r() */
172200
switch (retval) {
173201
case NSS_STATUS_SUCCESS:
174202
return NSS_STATUS_SUCCESS;

0 commit comments

Comments
 (0)