diff options
Diffstat (limited to 'src/back-sch-nss.c')
-rw-r--r-- | src/back-sch-nss.c | 246 |
1 files changed, 211 insertions, 35 deletions
diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c index 12ae589..3a21ff6 100644 --- a/src/back-sch-nss.c +++ b/src/back-sch-nss.c @@ -28,9 +28,10 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <dlfcn.h> +#include <errno.h> #include <pwd.h> #include <grp.h> -#include <errno.h> #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H #include <nspr.h> @@ -307,6 +308,144 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd, return entry; } +/* Possible results of lookup using a nss_* function. + * Note: don't include nss.h as its path gets overriden by NSS library */ +enum nss_status +{ + NSS_STATUS_TRYAGAIN = -2, + NSS_STATUS_UNAVAIL, + NSS_STATUS_NOTFOUND, + NSS_STATUS_SUCCESS, + NSS_STATUS_RETURN +}; + +struct nss_ops_ctx { + void *dl_handle; + + enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*setpwent)(void); + enum nss_status (*getpwent_r)(struct passwd *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*endpwent)(void); + + enum nss_status (*getgrnam_r)(const char *name, struct group *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*setgrent)(void); + enum nss_status (*getgrent_r)(struct group *result, + char *buffer, size_t buflen, int *errnop); + enum nss_status (*endgrent)(void); + + enum nss_status (*initgroups_dyn)(const char *user, gid_t group, + long int *start, long int *size, + gid_t **groups, long int limit, + int *errnop); +}; + +void backend_nss_init_context(struct nss_ops_ctx **nss_context) +{ + struct nss_ops_ctx *ctx = NULL; + + if (nss_context == NULL) { + return; + } + + ctx = calloc(1, sizeof(struct nss_ops_ctx)); + + *nss_context = ctx; + if (ctx == NULL) { + return; + } + + ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); + if (ctx->dl_handle == NULL) { + goto fail; + } + + ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); + if (ctx->getpwnam_r == NULL) { + goto fail; + } + + ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); + if (ctx->getpwuid_r == NULL) { + goto fail; + } + + ctx->setpwent = dlsym(ctx->dl_handle, "_nss_sss_setpwent"); + if (ctx->setpwent == NULL) { + goto fail; + } + + ctx->getpwent_r = dlsym(ctx->dl_handle, "_nss_sss_getpwent_r"); + if (ctx->getpwent_r == NULL) { + goto fail; + } + + ctx->endpwent = dlsym(ctx->dl_handle, "_nss_sss_endpwent"); + if (ctx->endpwent == NULL) { + goto fail; + } + + ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); + if (ctx->getgrnam_r == NULL) { + goto fail; + } + + ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); + if (ctx->getgrgid_r == NULL) { + goto fail; + } + + ctx->setgrent = dlsym(ctx->dl_handle, "_nss_sss_setgrent"); + if (ctx->setgrent == NULL) { + goto fail; + } + + ctx->getgrent_r = dlsym(ctx->dl_handle, "_nss_sss_getgrent_r"); + if (ctx->getgrent_r == NULL) { + goto fail; + } + + ctx->endgrent = dlsym(ctx->dl_handle, "_nss_sss_endgrent"); + if (ctx->endgrent == NULL) { + goto fail; + } + + ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); + if (ctx->initgroups_dyn == NULL) { + goto fail; + } + + return; + +fail: + backend_nss_free_context(nss_context); + + return; +} + +void +backend_nss_free_context(struct nss_ops_ctx **nss_context) +{ + if (nss_context == NULL) { + return; + } + + if ((*nss_context)->dl_handle != NULL) { + dlclose((*nss_context)->dl_handle); + } + + free((*nss_context)); + *nss_context = NULL; +} + + + static Slapi_Entry ** backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid, char *container_sdn, @@ -315,25 +454,33 @@ backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid, { struct passwd pwd, *result; Slapi_Entry *entry, **entries; - int rc; + enum nss_status rc; char *buf = NULL; + struct nss_ops_ctx *ctx = NULL; + int lerrno; + + ctx = cbdata->state->nss_context; + if (ctx == NULL) { + return NULL; + } repeat: if (cbdata->nsswitch_buffer == NULL) { return NULL; } if (is_uid) { - rc = getpwuid_r((uid_t) atoll(user_name), &pwd, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &result); + rc = ctx->getpwuid_r((uid_t) atoll(user_name), &pwd, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); } else { - rc = getpwnam_r(user_name, &pwd, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &result); + rc = ctx->getpwnam_r(user_name, &pwd, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); } - if ((result == NULL) || (rc != 0)) { - if (rc == ERANGE) { + + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2); if (buf != NULL) { cbdata->nsswitch_buffer = buf; @@ -437,25 +584,32 @@ backend_retrieve_group_entry_from_nsswitch(char *group_name, bool_t is_gid, { struct group grp, *result; Slapi_Entry *entry, **entries; - int rc; + enum nss_status rc; char *buf = NULL; + struct nss_ops_ctx *ctx = NULL; + int lerrno = 0; + + ctx = cbdata->state->nss_context; + if (ctx == NULL) { + return NULL; + } repeat: if (cbdata->nsswitch_buffer == NULL) { return NULL; } if (is_gid) { - rc = getgrgid_r((gid_t) atoll(group_name), &grp, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &result); + rc = ctx->getgrgid_r((gid_t) atoll(group_name), &grp, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); } else { - rc = getgrnam_r(group_name, &grp, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &result); + rc = ctx->getgrnam_r(group_name, &grp, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); } - if ((result == NULL) || (rc != 0)) { - if (rc == ERANGE) { + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2); if (buf != NULL) { cbdata->nsswitch_buffer = buf; @@ -490,20 +644,27 @@ backend_retrieve_group_entry_from_nsswitch_by_gid(gid_t gid, { struct group grp, *result; Slapi_Entry *entry; - int rc; + enum nss_status rc; char *buf = NULL; + struct nss_ops_ctx *ctx = NULL; + int lerrno = 0; + ctx = cbdata->state->nss_context; + + if (ctx == NULL) { + return NULL; + } repeat: if (cbdata->nsswitch_buffer == NULL) { return NULL; } - rc = getgrgid_r(gid, &grp, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &result); + rc = ctx->getgrgid_r(gid, &grp, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); - if ((result == NULL) || (rc != 0)) { - if (rc == ERANGE) { + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2); if (buf != NULL) { cbdata->nsswitch_buffer = buf; @@ -532,19 +693,28 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn, gid_t *grouplist, *tmp_list; Slapi_Entry **entries, *entry, **tmp; char *buf = NULL; - int rc, ngroups, i, idx; - + int i, idx; + struct nss_ops_ctx *ctx = NULL; + int lerrno = 0; + long int ngroups = 0; + long int start = 0; + enum nss_status rc; + + ctx = cbdata->state->nss_context; + if (ctx == NULL) { + return NULL; + } repeat: if (cbdata->nsswitch_buffer == NULL) { return NULL; } - rc = getpwnam_r(user_name, &pwd, - cbdata->nsswitch_buffer, - cbdata->nsswitch_buffer_len, &pwd_result); + rc = ctx->getpwnam_r(user_name, &pwd, + cbdata->nsswitch_buffer, + cbdata->nsswitch_buffer_len, &lerrno); - if ((pwd_result == NULL) || (rc != 0)) { - if (rc == ERANGE) { + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2); if (buf != NULL) { cbdata->nsswitch_buffer = buf; @@ -559,14 +729,20 @@ repeat: } ngroups = 32; + start = 0; grouplist = malloc(sizeof(gid_t) * ngroups); if (grouplist == NULL) { return NULL; } + grouplist[0] = pwd.pw_gid; + start++; + do { - rc = getgrouplist(user_name, pwd.pw_gid, grouplist, &ngroups); - if (rc < ngroups) { + rc = ctx->initgroups_dyn(user_name, pwd.pw_gid, + &start, &ngroups, &grouplist, + -1, &lerrno); + if ((rc != NSS_STATUS_SUCCESS)) { tmp_list = realloc(grouplist, ngroups * sizeof(gid_t)); if (tmp_list == NULL) { free(grouplist); @@ -574,7 +750,7 @@ repeat: } grouplist = tmp_list; } - } while (rc != ngroups); + } while (rc != NSS_STATUS_SUCCESS); entries = calloc(ngroups + 1, sizeof(entries[0])); if (entries == NULL) { |