Skip to content

Commit b2ca446

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 b2ca446

File tree

2 files changed

+62
-21
lines changed

2 files changed

+62
-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 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: 44 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,75 @@ 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 */
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;
118127
if (!retval)
119128
return NSS_STATUS_SUCCESS;
120129

121-
switch (saved_errno) {
122-
case 0:
123-
return NSS_STATUS_SUCCESS;
124-
130+
/* real error number is retval from fgetspent_r() */
131+
*__errnop = retval;
132+
switch (retval) {
125133
case ENOENT:
134+
/* if the file would not exist, we would have already
135+
bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
136+
after the call to tcb_safe_open() */
126137
return NSS_STATUS_NOTFOUND;
127138

139+
case EAGAIN:
140+
/* ressources are temporary not available */
141+
return NSS_STATUS_TRYAGAIN;
142+
128143
case ERANGE:
144+
/* __buffer too small */
129145
return NSS_STATUS_TRYAGAIN;
130146

131147
default:
148+
/* something serious, but we can't help it */
132149
return NSS_STATUS_UNAVAIL;
133150
}
134151
}
135152

136-
int _nss_tcb_getspent_r(struct spwd *__result_buf,
137-
char *__buffer, size_t __buflen, struct spwd **__result)
153+
enum nss_status _nss_tcb_getspent_r(struct spwd *__result_buf,
154+
char *__buffer, size_t __buflen, int *__errnop)
138155
{
139156
struct dirent *result;
140157
off_t currpos;
141158
int retval, saved_errno;
142159

143160
if (!tcbdir) {
144-
errno = ENOENT;
161+
/* tcbdir does not exist */
162+
*__errnop = ENOENT;
145163
return NSS_STATUS_UNAVAIL;
146164
}
147165

@@ -154,21 +172,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154172
closedir(tcbdir);
155173
errno = saved_errno;
156174
tcbdir = NULL;
175+
/* cannot iterate tcbdir */
176+
*__errnop = ENOENT;
157177
return NSS_STATUS_UNAVAIL;
158178
}
159179
if (!result) {
160180
closedir(tcbdir);
161-
errno = ENOENT;
181+
errno = saved_errno;
162182
tcbdir = NULL;
183+
/* we have no more entries in tcbdir */
184+
*__errnop = ENOENT;
163185
return NSS_STATUS_NOTFOUND;
164186
}
165187
errno = saved_errno;
166188
} while (!strcmp(result->d_name, ".") ||
167189
!strcmp(result->d_name, "..") || result->d_name[0] == ':');
168190

169191
retval = _nss_tcb_getspnam_r(result->d_name, __result_buf, __buffer,
170-
__buflen, __result);
192+
__buflen, __errnop);
171193

194+
/* __errnop has already been set by _nss_tcb_getspnam_r() */
172195
switch (retval) {
173196
case NSS_STATUS_SUCCESS:
174197
return NSS_STATUS_SUCCESS;

0 commit comments

Comments
 (0)