diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
commit | 74aa0bc6779af38018a03fd2cf4419fe85917904 (patch) | |
tree | 9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/sss_client/subid | |
parent | Initial commit. (diff) | |
download | sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip |
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/sss_client/subid')
-rw-r--r-- | src/sss_client/subid/sss_subid.c | 222 | ||||
-rw-r--r-- | src/sss_client/subid/sss_subid.exports | 12 |
2 files changed, 234 insertions, 0 deletions
diff --git a/src/sss_client/subid/sss_subid.c b/src/sss_client/subid/sss_subid.c new file mode 100644 index 0000000..f1fbe34 --- /dev/null +++ b/src/sss_client/subid/sss_subid.c @@ -0,0 +1,222 @@ +/* + Copyright (C) 2021 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <string.h> +#include <shadow/subid.h> +#include "sss_cli.h" + +/* This shadow-utils plugin contains partial SSSD implementation + * of `subid_nss_ops` API as described in + * https://github.com/shadow-maint/shadow/blob/d4b6d1549b2af48ce3cb6ff78d9892095fb8fdd9/lib/prototypes.h#L271 + */ + +/* Find all subid ranges delegated to a user. + * + * Usage in shadow-utils: + * libsubid: get_sub?id_ranges() -> list_owner_ranges() + * + * SUBID_RANGES Reply: + * + * 0-3: 32bit unsigned number of UID results + * 4-7: 32bit unsigned number of GID results + * For each result (sub-uid ranges first): + * 0-3: 32bit number with "start" id + * 4-7: 32bit number with "count" (range size) + */ +enum subid_status shadow_subid_list_owner_ranges(const char *user, + enum subid_type id_type, + struct subid_range **ranges, + int *count) +{ + size_t user_len; + enum sss_status ret; + uint8_t *repbuf = NULL; + size_t index = 0; + size_t replen; + int errnop; + struct sss_cli_req_data rd; + uint32_t num_results = 0; + uint32_t val; + + if ( !user || !ranges || !count || + ((id_type != ID_TYPE_UID) && (id_type != ID_TYPE_GID)) ) { + return SUBID_STATUS_ERROR; + } + + ret = sss_strnlen(user, SSS_NAME_MAX, &user_len); + if (ret != 0) { + return SUBID_STATUS_UNKNOWN_USER; + } + rd.len = user_len + 1; + rd.data = user; + + sss_nss_lock(); + /* Anticipated workflow will always request both + * sub-uid and sub-gid ranges anyway. + * So don't bother with dedicated commands - + * just request everything in one shot. + * The second request will get data from the cache. + */ + ret = sss_cli_make_request_with_checks(SSS_NSS_GET_SUBID_RANGES, &rd, + SSS_CLI_SOCKET_TIMEOUT, + &repbuf, &replen, &errnop, + SSS_NSS_SOCKET_NAME); + sss_nss_unlock(); + + if ( (ret != SSS_STATUS_SUCCESS) || (errnop != EOK) + /* response must contain at least the "payload header" */ + || (replen < 2*sizeof(uint32_t)) + /* and even number of 'uint32_t' */ + || (replen % (2*sizeof(uint32_t)) != 0) ) { + free(repbuf); + if (ret == SSS_STATUS_UNAVAIL) { + return SUBID_STATUS_ERROR_CONN; + } + return SUBID_STATUS_ERROR; + } + + SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); + if (num_results > (replen/sizeof(uint32_t) - 2)/2) { + free(repbuf); + return SUBID_STATUS_ERROR; + } + + if (id_type == ID_TYPE_UID) { + index = 2 * sizeof(uint32_t); + } else { + index = (2 + 2*num_results) * sizeof(uint32_t); + SAFEALIGN_COPY_UINT32(&num_results, repbuf + sizeof(uint32_t), NULL); + if (num_results > ((replen - index)/sizeof(uint32_t)/2)) { + free(repbuf); + return SUBID_STATUS_ERROR; + } + } + if (num_results == 0) { + /* TODO: how to distinguish "user not found" vs "user doesn't have ranges defined" here? + * Options: + * - special "fake" entry in the cache + * - provide 'nss_protocol_done_fn' to 'nss_getby_name' to avoid "ENOENT -> "empty packet" logic + * - add custom error code for this case and handle in generic 'nss_protocol_done' + * + * Note: at the moment this is not important, since shadow-utils doesn't use return code internally + * and returns -1 from libsubid on any error anyway. + */ + free(repbuf); + return SUBID_STATUS_UNKNOWN_USER; + } + + *count = num_results; + if (*count < 0) { + free(repbuf); + return SUBID_STATUS_ERROR; + } + + *ranges = malloc(num_results * sizeof(struct subid_range)); + if (!*ranges) { + free(repbuf); + return SUBID_STATUS_ERROR; + } + + for (uint32_t c = 0; c < num_results; ++c) { + SAFEALIGN_COPY_UINT32(&val, repbuf + index, &index); + (*ranges)[c].start = val; + SAFEALIGN_COPY_UINT32(&val, repbuf + index, &index); + (*ranges)[c].count = val; + } + free(repbuf); + + return SUBID_STATUS_SUCCESS; +} + +/* Does a user own a given subid range? + * + * Usage in shadow-utils: + * newuidmap/user busy : have_sub_uids() -> has_range() + */ +enum subid_status shadow_subid_has_range(const char *owner, + unsigned long start, + unsigned long count, + enum subid_type id_type, + bool *result) +{ + enum subid_status ret; + struct subid_range *range; + int amount; + unsigned long end = start + count; + + if (!result || (end < start)) { + return SUBID_STATUS_ERROR; + } + + if (count == 0) { + *result = true; + return SUBID_STATUS_SUCCESS; + } + + /* Anticipated workflow is the following: + * + * 1) Podman figures out ranges available for a user: + * libsubid::get_subid_ranges() -> ... -> list_owner_ranges() + * + * 2) Podman maps available ranges: + * newuidmap -> have_sub_uids() -> has_range() + * At this point all ranges are available in a cache from step (1) + * so it doesn't make sense to try "smart" LDAP searches (even if possible) + * Let's just reuse list_owner_ranges() and do a check. + * + * It might have some sense to do a check at responder's side (i.e. without + * fetching all ranges), but range is just a couple of numbers (and FreeIPA + * only supports a single range per user anyway), so this optimization + * wouldn't save much traffic anyway, but would introduce new + * `sss_cli_command`/responder handler. + */ + + ret = shadow_subid_list_owner_ranges(owner, id_type, &range, &amount); + if (ret != SUBID_STATUS_SUCCESS) { + return ret; + } + + *result = false; + + for (int i = 0; i < amount; ++i) { + if ((range[i].start <= start) && + (range[i].start + range[i].count >= end)) { + *result = true; + } + /* TODO: handle coverage via multiple ranges (once IPA supports this) */ + } + + free(range); + return ret; +} + +/* Find uids who own a given subid. + * + * Usage in shadow-utils: + * libsubid: get_sub?id_owners() -> find_subid_owners() + */ +enum subid_status shadow_subid_find_subid_owners(unsigned long subid, + enum subid_type id_type, + uid_t **uids, + int *count) +{ + /* Not yet implemented. + * Currently there are no users of this function. + */ + return SUBID_STATUS_ERROR; +} diff --git a/src/sss_client/subid/sss_subid.exports b/src/sss_client/subid/sss_subid.exports new file mode 100644 index 0000000..87c073b --- /dev/null +++ b/src/sss_client/subid/sss_subid.exports @@ -0,0 +1,12 @@ +EXPORTED { + + # public functions + global: + shadow_subid_has_range; + shadow_subid_list_owner_ranges; + shadow_subid_find_subid_owners; + + # everything else is local + local: + *; +}; |