Skip to content
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

Subids: support nsswitch #321

Merged
merged 6 commits into from
Apr 17, 2021
Merged

Subids: support nsswitch #321

merged 6 commits into from
Apr 17, 2021

Conversation

hallyn
Copy link
Member

@hallyn hallyn commented Apr 9, 2021

When starting any operation to do with subuid delegation, check
nsswitch for a module to use. If none is specified, then use
the traditional /etc/subuid and /etc/subgid files.

Currently only one module is supported, and there is no fallback
to the files on errors. Several possibilities could be considered:

  1. in case of connection error, fall back to files
  2. in case of unknown user, also fall back to files

etc...

When non-files nss module is used, functions to edit the range
are not supported. It may make sense to support it, but it also
may make sense to require another tool to be used.

libsubordinateio also uses the nss_ helpers. This is how for instance
lxc could easily be converted to supporting nsswitch.

Add a set of test cases, including a dummy libsubid_zzz module. This
hardcodes values such that:

'ubuntu' gets 200000 - 300000
'user1' gets 100000 - 165536
'error' emulates an nss module error
'unknown' emulates a user unknown to the nss module
'conn' emulates a connection error ot the nss module

@hallyn hallyn force-pushed the 2021-04-08/nss branch 5 times, most recently from 8a640f6 to b9c48ff Compare April 9, 2021 04:39
lib/nss.c Outdated Show resolved Hide resolved
lib/nss.c Outdated Show resolved Hide resolved
libsubid/subid.h Outdated Show resolved Hide resolved
libsubid/subid.h Outdated Show resolved Hide resolved
libsubid/subid.h Outdated Show resolved Hide resolved
lib/nss.c Outdated Show resolved Hide resolved
libsubid/subid.h Outdated Show resolved Hide resolved
@hallyn
Copy link
Member Author

hallyn commented Apr 9, 2021

I'll address your feedback with appended patches (which I will squash in before merging) soon, but probably not today.

@alexey-tikhonov
Copy link

Hi @hallyn,

thank you for opening PR.

Please see few inline comments.

Besides that I think this PR should update libsubid/api.c as well: currently get_sub?id_ranges() and get_sub?id_owners() unconditionally call sub_?id_open(), sub_?id_close(), etc. I think this is at least redundant and might even cause issues (for example, if network source is configured and /etc/sub?id files are inaccessible for some reason).

It's even more prominent with grant/free_sub?id_range(): besides the same issue with unconditional execution of sub_?id_open/lock/unlock/close(), it operates on files directly, bypassing sub_?id_add/remove(). I think those function should return EOPNOTSUPP promptly in case nsswitch plugin configured.

Additionally, could you please clarify, if const char *owner means:

  • "username",
  • text representation of "UID"
  • or both [should be] supported
    in subid_nss_ops and in libsubid/api.h?

lib/nss.c Outdated Show resolved Hide resolved
Issue shadow-maint#297 reported seeing

*** Warning: Linking the shared library libsubid.la against the
*** static library ../libmisc/libmisc.a is not portable!

which commit b5fb1b3 was supposed
to fix.  But a few commits later it's back.  So try to fix it
in the way the bug reporter suggested.  This broke builds some
other ways, namely a few missing library specifications, so add
those.

Signed-off-by: Serge Hallyn <[email protected]>
@hallyn hallyn force-pushed the 2021-04-08/nss branch 3 times, most recently from f3d619a to 7615cad Compare April 12, 2021 04:51
@rhatdan
Copy link

rhatdan commented Apr 12, 2021

Thanks @hallyn This looks good.

@hallyn
Copy link
Member Author

hallyn commented Apr 12, 2021

I probably need to have configure.ac look for yacc+libtool (per my .travis.yaml update), then depending on the open thread it should be ready.

lib/prototypes.h Outdated Show resolved Hide resolved
lib/nss.c Outdated Show resolved Hide resolved
@alexey-tikhonov
Copy link

Hi @hallyn,

thanks for an update. Good progress.

In the comments to

(*find_subid_owners)(unsigned long id, uid_t **uids, enum subid_type id_type, int *count);

'owner' is described instead of 'id'.
And I still think order of arguments is weird - don't you think it makes sense to move id_type before uids? Currently input arg fits between output arguments.

And what do you think about #321 (comment) ?
Namely:

  • libsubid/api.c does some files operations unconditionally
  • what are the expectations towards meaning of "owner" (UID/username/both) in subid_nss_ops and in libsubid/api.h?

@hallyn
Copy link
Member Author

hallyn commented Apr 13, 2021

In the comments to

(*find_subid_owners)(unsigned long id, uid_t **uids, enum subid_type id_type, int *count);

'owner' is described instead of 'id'.
And I still think order of arguments is weird - don't you think it makes sense to move id_type before uids? Currently input arg fits between output arguments.

Yes, id_type before the output value uids makes sense. Sorry - if you've mentioned this before, I don't remember it.

@hallyn
Copy link
Member Author

hallyn commented Apr 15, 2021

Yeah, I can rename those. I also was going to actually comment the api.h functions :) But maybe as a separate commit since technically that's libsubid, and nss support is a core shadow feature.

@hallyn
Copy link
Member Author

hallyn commented Apr 15, 2021

BTW I do notice that it's a bit inconsistent that find_subid_owners returns uids while the others take a char *username.

I'm loath to change that though - since we can have more than one name per uid, it seems sensible

@hallyn
Copy link
Member Author

hallyn commented Apr 16, 2021

@ikerexxe

Straight to the point, I fear that one of the names of the header for exposing the library is not correct. I see api.h and subid.h as the header names. api.h can be a sensible name for shadow-utils repository, but once you include the file in a distribution you don't know what you are handling as there are lots of packages providing APIs. Would you mind merging those two files into subid.h? Another option would be to rename both files, something like subid_api.h and subid_data.h. This is the approach that I have taken so far in Fedora.

I've merged them into subid.h. Since you're already massaging the files in your package, can you verify that the way I have it will work for you?

If so, then I'll merge.

hallyn added 5 commits April 16, 2021 21:02
Closes shadow-maint#154

When starting any operation to do with subuid delegation, check
nsswitch for a module to use.  If none is specified, then use
the traditional /etc/subuid and /etc/subgid files.

Currently only one module is supported, and there is no fallback
to the files on errors.  Several possibilities could be considered:

1. in case of connection error, fall back to files
2. in case of unknown user, also fall back to files

etc...

When non-files nss module is used, functions to edit the range
are not supported.  It may make sense to support it, but it also
may make sense to require another tool to be used.

libsubordinateio also uses the nss_ helpers.  This is how for instance
lxc could easily be converted to supporting nsswitch.

Add a set of test cases, including a dummy libsubid_zzz module.  This
hardcodes values such that:

'ubuntu' gets 200000 - 300000
'user1' gets 100000 - 165536
'error' emulates an nss module error
'unknown' emulates a user unknown to the nss module
'conn' emulates a connection error ot the nss module

Changes to libsubid:

Change the list_owner_ranges api: return a count instead of making the array
null terminated.

This is a breaking change, so bump the libsubid abi major number.

Rename free_subuid_range and free_subgid_range to ungrant_subuid_range,
because otherwise it's confusing with free_subid_ranges which frees
    memory.

Run libsubid tests in jenkins

Switch argument order in find_subid_owners

Move the db locking into subordinateio.c

Signed-off-by: Serge Hallyn <[email protected]>
Move libsubid/api.h into libsubid/subid.h, and document the api in subid.h

Signed-off-by: Serge Hallyn <[email protected]>
with out also doing '-'

Signed-off-by: Serge Hallyn <[email protected]>
Otherwise our su -p uses bash if that is what root was
configured to use, and then fails to read /root/ for
.bash_profile.  This caused an unexpected error message
in /tmp/err, failing the test.

Signed-off-by: Serge Hallyn <[email protected]>
HOME has to start as /root since we are testing
that su didn't change it.

Signed-off-by: Serge Hallyn <[email protected]>
@hallyn hallyn merged commit b30e961 into shadow-maint:master Apr 17, 2021
@alexey-tikhonov
Copy link

Thank you, @hallyn.

@hallyn
Copy link
Member Author

hallyn commented Apr 19, 2021

@alexey-tikhonov @giuseppe @AkihiroSuda @ikerexxe @rhatdan

Thanks for all your helpful comments.

@ikerexxe
Copy link
Collaborator

@hallyn thanks to you for your work.

I've merged them into subid.h. Since you're already massaging the files in your package, can you verify that the way I have it will work for you?

Yes, that's perfectly fine.

@alexey-tikhonov
Copy link

Hi,

not sure if this is a best place, but I'd like to discuss one thing.

Currently subuid.h::get_subuid_ranges() -> list_owner_ranges() -> get_subid_nss_handle() -> nss_init() -> fprintf(stderr, ...)

That's ok for new?idmap to print to stderr, but I'm not so sure about libsubid...

@hallyn , what do you think?

@hallyn
Copy link
Member Author

hallyn commented Apr 26, 2021

Hi,

not sure if this is a best place, but I'd like to discuss one thing.

Currently subuid.h::get_subuid_ranges() -> list_owner_ranges() -> get_subid_nss_handle() -> nss_init() -> fprintf(stderr, ...)

That's ok for new?idmap to print to stderr, but I'm not so sure about libsubid...

@hallyn , what do you think?

Thanks, good point. We shouldn't do that. Do you mind opening a new issue for that? If so (if you mind :) I'll open one later.

@giuseppe
Copy link
Contributor

one potential issue I've found is that subid.h is not installed:

$ make install DESTDIR=$(pwd)/dest >/dev/null && find dest -name subid.h
libtool: warning: remember to run 'libtool --finish /lib'
$

@alexey-tikhonov
Copy link

Hi @hallyn ,

looking at the usage of has_any_range()/has_range() in existing code, I have following questions:

  1. newusers: sub_uid_assigned() -> nsswitch::has_any_range(), so if network source is configured in nsswitch.conf then newusers consults network source instead of /etc/subid, and this doesn't make much sense, imo
    And this is the only use of has_any_range() I've found. Do we need this function in a plugin at all if only local user manipulation tools use it?

  2. useradd: sub_uid_add() -> !files => -EOPNOTSUPP. Again, if network source is configured in nsswitch.conf then useradd will fail to update /etc/subuid

@alexey-tikhonov
Copy link

Btw, if we suppose that a given subid can be used by multiple users (uids), then probably usage of has_range() in user_busy.c became wrong now (subrange doesn't identify owner anymore).

@alexey-tikhonov
Copy link

alexey-tikhonov commented May 3, 2021

Another one question about get_sub?id_ranges()/list_owner_ranges(): do we really need owner field in struct subordinate_range? Or do we expect those functions to populate this field?
Since those functions do a lookup for a specified owner, this field will clearly be the same in all ranges (and must match in arg). Feels like useless strcpy()'s...

UPD: it seems grant/ungrant rely on this field.
But doing actual implementation of list_owner_ranges(), it feels excessive to allocate every range and then strdup owner (and do a proper cleanup if any of those fails) instead of single allocation of an array of structs with 2 ints...

@hallyn
Copy link
Member Author

hallyn commented May 4, 2021

So maybe we should have something like:

struct subordinate_id_range {
unsigned long start;
unsigned long count;
};

struct subordinate_delegated {
const char *owner;
struct subordinate_id_range range;
};

? Although simply saying that it's ok to leave the subordinate_range->owner
NULL when those functions return would be ok with me too. That might become an
issue for users who want to do several calls for different users, combine the
results, and then parse the collection. But even they may not want to do all
that freeing later.

So if you like we can add a comment in these function descriptions saying
that owner may be returned as NULL.

@hallyn
Copy link
Member Author

hallyn commented May 4, 2021

one potential issue I've found is that subid.h is not installed:

$ make install DESTDIR=$(pwd)/dest >/dev/null && find dest -name subid.h
libtool: warning: remember to run 'libtool --finish /lib'
$

Should be fixed with #330

@hallyn
Copy link
Member Author

hallyn commented May 4, 2021

Hi @hallyn ,

looking at the usage of has_any_range()/has_range() in existing code, I have following questions:

1. newusers: sub_uid_assigned() -> nsswitch::has_any_range(), so if network source is configured in `nsswitch.conf` then `newusers` consults network source instead of /etc/subid, and this doesn't make much sense, imo
   And this is the only use of `has_any_range()` I've found. Do we need this function in a plugin at all if only local user manipulation tools use it?

2. useradd: sub_uid_add() -> !files => -EOPNOTSUPP. Again, if network source is configured in `nsswitch.conf` then `useradd` will fail to update /etc/subuid

Would you mind creating a new issue for these as well? It'll be very hard to track conversation in this issue.

I don't mind dropping has_any_range(), I think I thought something like lxc-usernsexec could use it, but it can just as well just ask for the ranges and get back -ENOENT.

For the second, I think you're saying that useradd should ignore the failure to add subids?

@alexey-tikhonov
Copy link

alexey-tikhonov commented May 4, 2021

  1. newusers: sub_uid_assigned() -> nsswitch::has_any_range(), so if network source is configured in nsswitch.conf then newusers consults network source instead of /etc/subid, and this doesn't make much sense, imo
    And this is the only use of has_any_range() I've found. Do we need this function in a plugin at all if only local user manipulation tools use it?

  2. useradd: sub_uid_add() -> !files => -EOPNOTSUPP. Again, if network source is configured in nsswitch.conf then useradd will fail to update /etc/subuid

Would you mind creating a new issue for these as well? It'll be very hard to track conversation in this issue.

Ok: #331. Just wasn't sure if you see this as an issue.

I don't mind dropping has_any_range(), I think I thought something like lxc-usernsexec could use it, but it can just as well just ask for the ranges and get back -ENOENT.

SUBID_STATUS_SUCCESS && (*count == 0), to be precise.

For the second, I think you're saying that useradd should ignore the failure to add subids?

No, I meant a little bit different thing.
What is our general approach to a case: "nsswitch has network source configured" and "local user manipulation are being done"?
I think local tools, that add/modify local users, should work with /etc/ even if "network source" is enabled in nsswitch?

@alexey-tikhonov
Copy link

struct subordinate_id_range {
unsigned long start;
unsigned long count;
};

struct subordinate_delegated {
const char *owner;
struct subordinate_id_range range;
};

? Although simply saying that it's ok to leave the subordinate_range->owner
NULL when those functions return would be ok with me too. That might become an
issue for users who want to do several calls for different users, combine the
results, and then parse the collection. But even they may not want to do all
that freeing later.

So if you like we can add a comment in these function descriptions saying
that owner may be returned as NULL.

I think my preference would be a solution with two structs (this is very similar to what I have in SSSD's plugin now).
This would allow list_owner_ranges() to work with subordinate_id_range ** (instead of subordinate_delegated ***) - single malloc instead of (1 + count * 2) malloc's...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants