-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
libnss_tcb: Match interfaces with NSS documentation. #31
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
} | ||
|
||
/****************************************************************************** | ||
|
@@ -91,57 +91,80 @@ 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; | ||
|
||
/* 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 nor readable */ | ||
*__errnop = ENOENT; | ||
return NSS_STATUS_UNAVAIL; | ||
} | ||
Comment on lines
-111
to
+120
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original logic seems to be correct: |
||
|
||
retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result); | ||
retval = fgetspent_r(f, __result_buf, __buffer, | ||
__buflen, &__result_buf); | ||
Comment on lines
-114
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to make sure, this is a bug fix: when |
||
saved_errno = errno; | ||
fclose(f); | ||
errno = saved_errno; | ||
if (!retval) | ||
return NSS_STATUS_SUCCESS; | ||
|
||
switch (saved_errno) { | ||
/* real error number is retval from fgetspent_r(), | ||
by NSS spec errnop *MUST NOT* be set to 0 */ | ||
if (retval) | ||
*__errnop = retval; | ||
|
||
switch (retval) { | ||
Comment on lines
-121
to
+133
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is correct, the error code returned by |
||
case 0: | ||
/* no error, entry found */ | ||
return NSS_STATUS_SUCCESS; | ||
|
||
case ENOENT: | ||
/* if the file would not exist nor be readable, 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 else, e.g. parser error, 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; | ||
} | ||
|
||
|
@@ -154,21 +177,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf, | |
closedir(tcbdir); | ||
errno = saved_errno; | ||
tcbdir = NULL; | ||
/* cannot iterate tcbdir */ | ||
*__errnop = ENOENT; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure that our previous There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, as we cannot iterate over tcbdir for unknown reasons, so we should indicate "A necessary input file cannot be found." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that in practice |
||
return NSS_STATUS_UNAVAIL; | ||
} | ||
if (!result) { | ||
closedir(tcbdir); | ||
errno = ENOENT; | ||
errno = saved_errno; | ||
tcbdir = NULL; | ||
/* we have no more entries in tcbdir */ | ||
*__errnop = ENOENT; | ||
Comment on lines
-161
to
+189
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise. |
||
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; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should maybe be
*__errnop = errno
, becauseasprintf
may set perhapsENOMEM
and it'd be right.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the specs
EAGAIN
looks correct to me, asNSS_STATUS_TRYAGAIN
with errnopEAGAIN
means: "One of the functions used ran temporarily out of resources or a service is currently not available."There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation says that in case of
NSS_STATUS_TRYAGAIN
onlyERANGE
has a special meaning, and everything else is as good asEAGAIN
. The implementation agrees with the documentation, there is some special handling forERANGE
, but besides that allerrno
values are equal. In fact,__nss_getent_r
returnsEAGAIN
in case ofNSS_STATUS_TRYAGAIN
regardless oferrno
value.