-
Notifications
You must be signed in to change notification settings - Fork 274
subid: Support multiple subid NSS modules #1562
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
Open
YiPrograms
wants to merge
20
commits into
shadow-maint:master
Choose a base branch
from
YiPrograms:multiple-subid-nss
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
f98304f
lib/nss.c: seperate nss lib open and check logic
YiPrograms 3b65abb
lib/nss.c, lib/prototypes.h: linked list for nss_ops
YiPrograms 25ebd69
lib/nss.c: parse multiple subid databases from nsswitch.conf
YiPrograms 4376b03
lib/nss.c: free subid NSS database list on exit
YiPrograms 5c96c85
lib/nss.c, lib/prototypes.h: remove old NSS handle defs
YiPrograms 1b8aeaf
lib/nss.c: update comments and formatting
YiPrograms 1861699
lib/subordinateio.c: want_subuid/gid_file: check for files in nss db …
YiPrograms c56db79
lib/subordinateio.c: restrict subid mutations to files as first source
YiPrograms 23d79a9
lib/subordinateio.c: have_sub_uids/gids: multi-provider lookup
YiPrograms c3a81ba
lib/subordinateio.c: have_range: fix check for sub_uid/gid_open()
YiPrograms 529d41c
lib/subordinateio.c: refactor list_owner_ranges to list_local_owner_r…
YiPrograms 4d8d60a
lib/subordinateio.c: list_owner_ranges: multi-database range listing
YiPrograms 2cb6cbd
lib/subordinateio.c: refactor find_subid_owners to find_local_subid_o…
YiPrograms 2a36cc2
lib/subordinateio.c: find_subid_owners: multi-database owner search
YiPrograms b526c5a
lib/subordinateio.c: free_subid_pointer: use standard free
YiPrograms 90fa9b8
tests/libsubid/04_nss: Improve mock implementation
YiPrograms 4dfa195
tests/libsubid/04_nss: Update and extend test_nss
YiPrograms 3d4cfa9
tests/libsubid/04_nss: Extend range tests to multiple NSS providers
YiPrograms 768ad6f
man/subuid.5, man/subgid.5: document multiple subid delegation support
YiPrograms ec8afae
tests/libsubid/04_nss: add tests for range listing
YiPrograms File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,37 +25,113 @@ | |
|
|
||
| // NSS plugin handling for subids | ||
| // If nsswitch has a line like | ||
| // subid: sssd | ||
| // then sssd will be consulted for subids. Unlike normal NSS dbs, | ||
| // only one db is supported at a time. That's open to debate, but | ||
| // the subids are a pretty limited resource, and local files seem | ||
| // bound to step on any other allocations leading to insecure | ||
| // conditions. | ||
| // subid: sss | ||
| // then the sss module (libsubid_sss.so) will be consulted for subids. | ||
| // If nsswitch has a line specifying multiple databases, like: | ||
| // subid: sss files | ||
| // then databases will be consulted in the specified order. The search | ||
| // stops as soon as the user is found in a database, even if no subids | ||
| // are defined there. For example, if 'sss' knows the user but provides | ||
| // no subids, 'files' will not be consulted. | ||
| // | ||
| // While multiple databases are now supported, the subids are a pretty | ||
| // limited resource. Mixing local files with network allocations | ||
| // (like sssd) requires careful management. Misconfigurations would | ||
| // lead to overlapping ID mappings. Use with caution. | ||
|
|
||
| static atomic_flag nss_init_started; | ||
| static atomic_bool nss_init_completed; | ||
|
|
||
| static struct subid_nss_ops *subid_nss; | ||
| static struct subid_nss_db *subid_nss_db_head; | ||
|
|
||
| bool nss_is_initialized() { | ||
| bool | ||
| nss_is_initialized(void) { | ||
| return atomic_load(&nss_init_completed); | ||
| } | ||
|
|
||
| static void nss_exit(void) { | ||
| if (nss_is_initialized() && subid_nss) { | ||
| dlclose(subid_nss->handle); | ||
| free(subid_nss); | ||
| subid_nss = NULL; | ||
| static void | ||
| nss_exit(void) { | ||
| struct subid_nss_db *current; | ||
| struct subid_nss_db *next; | ||
|
|
||
| if (nss_is_initialized() && subid_nss_db_head) { | ||
| current = subid_nss_db_head; | ||
| while (current) { | ||
| next = current->next; | ||
| if (current->ops) { | ||
| dlclose(current->ops->handle); | ||
| free(current->ops); | ||
| } | ||
| free(current); | ||
| current = next; | ||
| } | ||
|
|
||
| subid_nss_db_head = NULL; | ||
| } | ||
| } | ||
|
|
||
| static struct subid_nss_ops * | ||
| open_and_check_nss_module(const char *libname) { | ||
| void *h; | ||
| struct subid_nss_ops *nss_ops; | ||
|
|
||
| h = dlopen(libname, RTLD_LAZY); | ||
| if (!h) { | ||
| fprintf(log_get_logfd(), "Error opening %s: %s\n", libname, dlerror()); | ||
| fprintf(log_get_logfd(), "Using files\n"); | ||
| return NULL; | ||
| } | ||
|
|
||
| nss_ops = malloc_T(1, struct subid_nss_ops); | ||
| if (!nss_ops) { | ||
| fprintf(log_get_logfd(), "Failed to allocate memory for subid NSS module %s\n", libname); | ||
| dlclose(h); | ||
| return NULL; | ||
| } | ||
|
|
||
| nss_ops->has_range = dlsym(h, "shadow_subid_has_range"); | ||
| if (!nss_ops->has_range) { | ||
| fprintf(log_get_logfd(), "%s did not provide @has_range@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| nss_ops->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); | ||
| if (!nss_ops->list_owner_ranges) { | ||
| fprintf(log_get_logfd(), "%s did not provide @list_owner_ranges@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| nss_ops->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); | ||
| if (!nss_ops->find_subid_owners) { | ||
| fprintf(log_get_logfd(), "%s did not provide @find_subid_owners@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| nss_ops->free = dlsym(h, "shadow_subid_free"); | ||
| if (!nss_ops->free) { | ||
| fprintf(log_get_logfd(), "%s did not provide @free@\n", libname); | ||
| goto close_lib; | ||
| } | ||
|
|
||
| nss_ops->handle = h; | ||
| return nss_ops; | ||
|
|
||
| close_lib: | ||
| dlclose(h); | ||
| free(nss_ops); | ||
| return NULL; | ||
| } | ||
|
|
||
| // nsswitch_path is an argument only to support testing. | ||
| void | ||
| nss_init(const char *nsswitch_path) { | ||
| char *line = NULL, *p; | ||
| char libname[64]; | ||
| FILE *nssfp = NULL; | ||
| void *h; | ||
| size_t len = 0; | ||
| char libname[64]; | ||
| char *line = NULL; | ||
| char *p; | ||
| char *token; | ||
| FILE *nssfp = NULL; | ||
| size_t len = 0; | ||
| const char *delimiters = " \t\n"; | ||
| struct subid_nss_db *new_db; | ||
| struct subid_nss_db **tail = &subid_nss_db_head; | ||
| struct subid_nss_ops *ops; | ||
|
|
||
| if (atomic_flag_test_and_set(&nss_init_started)) { | ||
| // Another thread has started nss_init, wait for it to complete | ||
|
|
@@ -68,7 +144,7 @@ nss_init(const char *nsswitch_path) { | |
| nsswitch_path = NSSWITCH; | ||
|
|
||
| // read nsswitch.conf to check for a line like: | ||
| // subid: files | ||
| // subid: sss files | ||
| nssfp = fopen(nsswitch_path, "r"); | ||
| if (!nssfp) { | ||
| if (errno != ENOENT) | ||
|
|
@@ -86,66 +162,61 @@ nss_init(const char *nsswitch_path) { | |
| if (!strcaseprefix(line, "subid:")) | ||
| continue; | ||
| p = &line[6]; | ||
| p = stpspn(p, " \t\n"); | ||
| p = stpspn(p, delimiters); | ||
| if (!streq(p, "")) | ||
| break; | ||
| p = NULL; | ||
| } | ||
|
|
||
| if (p == NULL) { | ||
| goto null_subid; | ||
| // Use NULL to indicate the built-in "files" database | ||
| subid_nss_db_head = NULL; | ||
| goto done; | ||
| } | ||
| if (stpsep(p, " \t\n") == NULL) { | ||
| fprintf(log_get_logfd(), "No usable subid NSS module found, using files\n"); | ||
| // subid_nss has to be null here, but to ease reviews: | ||
| goto null_subid; | ||
| } | ||
| if (streq(p, "files")) { | ||
| goto null_subid; | ||
| } | ||
| if (strlen(p) > 50) { | ||
| fprintf(log_get_logfd(), "Subid NSS module name too long (longer than 50 characters): %s\n", p); | ||
| fprintf(log_get_logfd(), "Using files\n"); | ||
| goto null_subid; | ||
| } | ||
| stprintf_a(libname, "libsubid_%s.so", p); | ||
| h = dlopen(libname, RTLD_LAZY); | ||
| if (!h) { | ||
|
Comment on lines
-111
to
-112
Collaborator
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.
|
||
| fprintf(log_get_logfd(), "Error opening %s: %s\n", libname, dlerror()); | ||
| fprintf(log_get_logfd(), "Using files\n"); | ||
|
YiPrograms marked this conversation as resolved.
|
||
| goto null_subid; | ||
| } | ||
| subid_nss = malloc_T(1, struct subid_nss_ops); | ||
| if (!subid_nss) { | ||
| goto close_lib; | ||
| } | ||
| subid_nss->has_range = dlsym(h, "shadow_subid_has_range"); | ||
| if (!subid_nss->has_range) { | ||
| fprintf(log_get_logfd(), "%s did not provide @has_range@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| subid_nss->list_owner_ranges = dlsym(h, "shadow_subid_list_owner_ranges"); | ||
| if (!subid_nss->list_owner_ranges) { | ||
| fprintf(log_get_logfd(), "%s did not provide @list_owner_ranges@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| subid_nss->find_subid_owners = dlsym(h, "shadow_subid_find_subid_owners"); | ||
| if (!subid_nss->find_subid_owners) { | ||
| fprintf(log_get_logfd(), "%s did not provide @find_subid_owners@\n", libname); | ||
| goto close_lib; | ||
| } | ||
| subid_nss->free = dlsym(h, "shadow_subid_free"); | ||
| if (!subid_nss->free) { | ||
| fprintf(log_get_logfd(), "%s did not provide @subid_free@\n", libname); | ||
| goto close_lib; | ||
|
|
||
| while (NULL != (token = strsep(&p, delimiters))) { | ||
| if (*token == '\0') { | ||
| continue; | ||
| } | ||
|
|
||
| if (streq(token, "files")) { | ||
| // Use NULL to indicate the built-in "files" database | ||
| ops = NULL; | ||
| } else { | ||
| if (stprintf_a(libname, "libsubid_%s.so", token) == -1) { | ||
| fprintf(log_get_logfd(), "Subid NSS module name too long: %s\n", token); | ||
| continue; | ||
| } | ||
|
|
||
| ops = open_and_check_nss_module(libname); | ||
| if (!ops) { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| new_db = malloc_T(1, struct subid_nss_db); | ||
| if (!new_db) { | ||
| if (ops) { | ||
| dlclose(ops->handle); | ||
| free(ops); | ||
| ops = NULL; | ||
| } | ||
|
|
||
| fprintf(log_get_logfd(), "Failed to allocate memory for subid NSS module %s, skipping\n", token); | ||
| continue; | ||
| } | ||
|
|
||
| new_db->ops = ops; | ||
| new_db->next = NULL; | ||
| *tail = new_db; | ||
| tail = &new_db->next; | ||
| } | ||
| subid_nss->handle = h; | ||
| goto done; | ||
|
|
||
| close_lib: | ||
| dlclose(h); | ||
| free(subid_nss); | ||
| null_subid: | ||
| subid_nss = NULL; | ||
| if (subid_nss_db_head == NULL) { | ||
| // No vaild NSS database loaded, using "files" only. | ||
| // NULL indicates the built-in "files" database, so we can continue, but log a warning. | ||
| fprintf(log_get_logfd(), "No usable subid NSS module found, using files\n"); | ||
| } | ||
|
|
||
| done: | ||
| atomic_store(&nss_init_completed, true); | ||
|
|
@@ -156,7 +227,8 @@ nss_init(const char *nsswitch_path) { | |
| } | ||
| } | ||
|
|
||
| struct subid_nss_ops *get_subid_nss_handle() { | ||
| struct subid_nss_db * | ||
| get_subid_nss_db(void) { | ||
| nss_init(NULL); | ||
| return subid_nss; | ||
| return subid_nss_db_head; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -228,6 +228,11 @@ extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void); | |
| extern void nss_init(const char *nsswitch_path); | ||
| extern bool nss_is_initialized(void); | ||
|
|
||
| struct subid_nss_db { | ||
| struct subid_nss_ops *ops; | ||
| struct subid_nss_db *next; | ||
| }; | ||
|
|
||
|
Comment on lines
+231
to
+235
Collaborator
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. Should we have a linked list? Or is an array simpler? |
||
| struct subid_nss_ops { | ||
| /* | ||
| * nss_has_range: does a user own a given subid range | ||
|
|
@@ -289,7 +294,7 @@ struct subid_nss_ops { | |
| void *handle; | ||
| }; | ||
|
|
||
| extern struct subid_nss_ops *get_subid_nss_handle(void); | ||
| extern struct subid_nss_db *get_subid_nss_db(void); | ||
|
|
||
|
|
||
| /* pam_pass_non_interactive.c */ | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Why did you change from two spaces of inter-sentence space to just one???