Skip to content

Commit

Permalink
libnss_tcb: Match interfaces with NSS documention.
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
besser82 committed Dec 21, 2024
1 parent b6ce07b commit 20c1bb2
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 21 deletions.
16 changes: 16 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
2024-12-20 Björn Esser <besser82 at fedoraproject.org>

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
* libs/nss.c (_nss_tcb_setspent): Adapt return-type and use return
values from documented macro.
(_nss_tcb_endspent): Likewise.
(_nss_tcb_getspnam_r): Adapt return-type, change fourth parameter
to be 'int *errnop', use return values from documented macros, and
set proper errno in errnop before returning.
(_nss_tcb_getspent_r): Likewise.

libnss_tcb: Disallow potentially-malicious user names in getspnam(3).
IEEE Std 1003.1-2001 allows only the following characters to appear
in group- and usernames: letters, digits, underscores, periods,
Expand Down
66 changes: 45 additions & 21 deletions libs/nss.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@

static __thread DIR *tcbdir = NULL;

int _nss_tcb_setspent(void)
enum nss_status _nss_tcb_setspent(void)
{
if (!tcbdir) {
tcbdir = opendir(TCB_DIR);
if (!tcbdir)
return NSS_STATUS_UNAVAIL;

return 1;
return NSS_STATUS_SUCCESS;
}

rewinddir(tcbdir);
return 1;
return NSS_STATUS_SUCCESS;
}

int _nss_tcb_endspent(void)
enum nss_status _nss_tcb_endspent(void)
{
if (tcbdir) {
closedir(tcbdir);
tcbdir = NULL;
}
return 1;
return NSS_STATUS_SUCCESS;
}

/******************************************************************************
Expand Down Expand Up @@ -91,57 +91,76 @@ static FILE *tcb_safe_open(const char *file, const char *name)
return f;
}

int _nss_tcb_getspnam_r(const char *name, struct spwd *__result_buf,
char *__buffer, size_t __buflen, struct spwd **__result)
enum nss_status _nss_tcb_getspnam_r(const char *name,
struct spwd *__result_buf, char *__buffer, size_t __buflen, int *__errnop)
{
FILE *f;
char *file;
int retval, saved_errno;
struct spwd **result_buf_ptr = NULL;

/* Disallow potentially-malicious user names */
if (!is_valid_username(name)) {
errno = ENOENT;
/* we don't serve an entry here */
*__errnop = ENOENT;
return NSS_STATUS_NOTFOUND;
}

if (asprintf(&file, TCB_FMT, name) < 0)
if (asprintf(&file, TCB_FMT, name) < 0) {
/* retry, as malloc or another resource has failed */
*__errnop = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}

f = tcb_safe_open(file, name);
free(file);
if (!f)
return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
if (!f) {
/* $user/shadow not existing */
*__errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}

retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result);
retval = fgetspent_r(f, __result_buf, __buffer,
__buflen, result_buf_ptr);
saved_errno = errno;
fclose(f);
errno = saved_errno;
if (!retval)
return NSS_STATUS_SUCCESS;

switch (saved_errno) {
case 0:
return NSS_STATUS_SUCCESS;

/* real error number is retval from fgetspent_r() */
*__errnop = retval;
switch (retval) {
case ENOENT:
/* if the file would not exist, we would have already
bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
after the call to tcb_safe_open() */
return NSS_STATUS_NOTFOUND;

case EAGAIN:
/* ressources are temporary not available */
return NSS_STATUS_TRYAGAIN;

case ERANGE:
/* __buffer too small */
return NSS_STATUS_TRYAGAIN;

default:
/* something serious, but we can't help it */
return NSS_STATUS_UNAVAIL;
}
}

int _nss_tcb_getspent_r(struct spwd *__result_buf,
char *__buffer, size_t __buflen, struct spwd **__result)
enum nss_status _nss_tcb_getspent_r(struct spwd *__result_buf,
char *__buffer, size_t __buflen, int *__errnop)
{
struct dirent *result;
off_t currpos;
int retval, saved_errno;

if (!tcbdir) {
errno = ENOENT;
/* tcbdir does not exist */
*__errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}

Expand All @@ -154,21 +173,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
closedir(tcbdir);
errno = saved_errno;
tcbdir = NULL;
/* cannot iterate tcbdir */
*__errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}
if (!result) {
closedir(tcbdir);
errno = ENOENT;
errno = saved_errno;
tcbdir = NULL;
/* we have no more entries in tcbdir */
*__errnop = ENOENT;
return NSS_STATUS_NOTFOUND;
}
errno = saved_errno;
} while (!strcmp(result->d_name, ".") ||
!strcmp(result->d_name, "..") || result->d_name[0] == ':');

retval = _nss_tcb_getspnam_r(result->d_name, __result_buf, __buffer,
__buflen, __result);
__buflen, __errnop);

/* __errnop has already been set by _nss_tcb_getspnam_r() */
switch (retval) {
case NSS_STATUS_SUCCESS:
return NSS_STATUS_SUCCESS;
Expand Down

0 comments on commit 20c1bb2

Please sign in to comment.