-
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?
Conversation
Last one for v1.3, promissed! |
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.
I've made some comments based on skimming of the code, but also I need to review the spec and we need to review and cleanup our previous errno
logic. This may be overly complicated with us separately maintaining errno
and *__errnop
.
Was the spec always this way or are we breaking compatibility with some legacy glibc?
|
||
if (asprintf(&file, TCB_FMT, name) < 0) | ||
if (asprintf(&file, TCB_FMT, name) < 0) { | ||
*__errnop = EAGAIN; |
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
, because asprintf
may set perhaps ENOMEM
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, as NSS_STATUS_TRYAGAIN
with errnop EAGAIN
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
only ERANGE
has a special meaning, and everything else is as good as EAGAIN
. The implementation agrees with the documentation, there is some special handling for ERANGE
, but besides that all errno
values are equal. In fact, __nss_getent_r
returns EAGAIN
in case of NSS_STATUS_TRYAGAIN
regardless of errno
value.
libs/nss.c
Outdated
|
||
switch (saved_errno) { | ||
case 0: | ||
if (!*result_buf_ptr) { | ||
*__errnop = ENOENT; |
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.
Maybe EINVAL
here? But is it a good idea to check for improper usage like that? It's typical for libc function to just crash when called with a NULL pointer where that is not allowed.
libs/nss.c
Outdated
{ | ||
struct dirent *result; | ||
off_t currpos; | ||
int retval, saved_errno; | ||
|
||
if (!tcbdir) { | ||
tcbdir = opendir(TCB_DIR); | ||
if (!tcbdir) | ||
if (!tcbdir) { | ||
*__errnop = ENOENT; |
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.
Maybe *__errnop = errno;
.
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.
NSS_STATUS_UNAVAIL
with ENOENT
means "A necessary input file cannot be found.", which is the case here; tcbdir cannot be opened.
@@ -115,11 +142,13 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf, | |||
closedir(tcbdir); | |||
errno = saved_errno; | |||
tcbdir = NULL; | |||
*__errnop = ENOENT; |
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.
I am not sure that our previous errno
logic here was right, so maybe ENOENT
is right here.
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Given that in practice __errnop
== &errno
, assigning different values to errno
and *__errnop
doesn't make sense.
The spec for the function prototype is unchanged since glibc-2.0.98 (~Oct 1998); the See: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=c66dbe00b9c98bb9d1fc10c9007fdcfb98a59b73 |
89c5d74
to
ea61369
Compare
ea61369
to
20c1bb2
Compare
@solardiz I would be nice, if you could another look here; this rebase should address most of your previous comments. |
Thanks. I will, but not right now. I want to take a look at the specs and hear from @ldv-alt his thoughts on whether we should continue setting |
20c1bb2
to
b2ca446
Compare
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]>
b2ca446
to
a26fe47
Compare
I've checked the current glibc implementation of nss_files, and for me it looks like it's not quite consistent wrt setting That is, we could make nss_tcb behavior wrt setting |
OK, and what's your preference? Off the top of my head, our options may be:
|
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; | ||
} |
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 original logic seems to be correct: ENOENT
means that the shadow file doesn't exist, in that case NSS_STATUS_NOTFOUND
(The requested entry is not available) should be returned. If the shadow file is not available for other reasons, than NSS_STATUS_UNAVAIL
should be returned.
retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result); | ||
retval = fgetspent_r(f, __result_buf, __buffer, | ||
__buflen, &__result_buf); |
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.
Just to make sure, this is a bug fix: when fgetspent_r
returns a nonzero value, it writes NULL
at the address specified by its last argument. Before this change, that address used to be &errno
.
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) { |
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.
This is correct, the error code returned by fgetspent_r
is currently either ENOENT
or EAGAIN
, it doesn't necessarily have to match the value of errno
.
errno = ENOENT; | ||
errno = saved_errno; | ||
tcbdir = NULL; | ||
/* we have no more entries in tcbdir */ | ||
*__errnop = ENOENT; |
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.
Likewise.
I think first of all we should update the function prototypes and fix the bug of passing After that we could fix other inconsistencies, keeping in the mind that in practice |
So maybe 3 separate commits (fix bug, fix prototypes, start to use the passed BTW, why the two underscores? I think that's inappropriate. |
I concur, identifiers with two leading underscores belong to the reserved namespace, it's not correct to introduce them here. |
LGTM. |
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