summaryrefslogtreecommitdiffstats
path: root/nsswitch/libwbclient/wbc_pwd_sssd.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsswitch/libwbclient/wbc_pwd_sssd.c')
-rw-r--r--nsswitch/libwbclient/wbc_pwd_sssd.c575
1 files changed, 563 insertions, 12 deletions
diff --git a/nsswitch/libwbclient/wbc_pwd_sssd.c b/nsswitch/libwbclient/wbc_pwd_sssd.c
index 164166090e1..b44c8c3eb95 100644
--- a/nsswitch/libwbclient/wbc_pwd_sssd.c
+++ b/nsswitch/libwbclient/wbc_pwd_sssd.c
@@ -25,75 +25,586 @@
#include "../winbind_client.h"
#include "wbc_sssd_internal.h"
+#define DEFAULT_BUFSIZE 4096
+#define MAX_BUFSIZE (1024*1204)
+
+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);
+};
+
+struct nss_ops_ctx *ctx = NULL;
+
+static bool open_libnss_sss(void)
+{
+ ctx = calloc(1, sizeof(struct nss_ops_ctx));
+ if (ctx == NULL) {
+ return false;
+ }
+
+ 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 true;
+
+fail:
+ if (ctx->dl_handle != NULL) {
+ dlclose(ctx->dl_handle);
+ }
+
+ free(ctx);
+ ctx = NULL;
+
+ return false;
+}
+
+static void wbcPasswdDestructor(void *ptr)
+{
+ struct passwd *pw = (struct passwd *)ptr;
+ free(pw->pw_name);
+ free(pw->pw_passwd);
+ free(pw->pw_gecos);
+ free(pw->pw_shell);
+ free(pw->pw_dir);
+}
+
+static wbcErr copy_pwd(struct passwd *in, struct passwd **out)
+{
+ struct passwd *pw;
+
+ pw = (struct passwd *)wbcAllocateMemory(1, sizeof(struct passwd),
+ wbcPasswdDestructor);
+ if (pw == NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ pw->pw_name = strdup(in->pw_name);
+ if (pw->pw_name == NULL) {
+ goto fail;
+ }
+
+ pw->pw_passwd = strdup(in->pw_passwd);
+ if (pw->pw_passwd == NULL) {
+ goto fail;
+ }
+
+ pw->pw_uid = in->pw_uid;
+ pw->pw_gid = in->pw_gid;
+
+ pw->pw_gecos = strdup(in->pw_gecos);
+ if (pw->pw_gecos == NULL) {
+ goto fail;
+ }
+
+ pw->pw_shell = strdup(in->pw_shell);
+ if (pw->pw_shell == NULL) {
+ goto fail;
+ }
+
+ pw->pw_dir = strdup(in->pw_dir);
+ if (pw->pw_dir == NULL) {
+ goto fail;
+ }
+
+ *out = pw;
+ return WBC_ERR_SUCCESS;
+fail:
+ wbcFreeMemory(pw);
+
+ return WBC_ERR_NO_MEMORY;
+}
+
+static wbcErr nss_to_wbc(enum nss_status status)
+{
+ wbcErr wbc_status;
+
+ switch (status) {
+ case NSS_STATUS_SUCCESS:
+ wbc_status = WBC_ERR_SUCCESS;
+ break;
+ case NSS_STATUS_NOTFOUND:
+ wbc_status = WBC_ERR_UNKNOWN_USER;
+ break;
+ default:
+ wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+ }
+
+ return wbc_status;
+}
+
/* Fill in a struct passwd* for a domain user based on username */
wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct passwd lpwd = {0};
+ enum nss_status status;
+ char *buffer = NULL;
+ size_t buflen;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (name == NULL || pwd == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ buflen = DEFAULT_BUFSIZE;
+ buffer = malloc(buflen);
+ if (buffer == NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ status = ctx->getpwnam_r(name, &lpwd, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_pwd(&lpwd, pwd);
+ }
+
+ free(buffer);
+
+ return wbc_status;
}
/* Fill in a struct passwd* for a domain user based on uid */
wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct passwd lpwd = {0};
+ enum nss_status status;
+ char *buffer = NULL;
+ size_t buflen;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (pwd == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ buflen = DEFAULT_BUFSIZE;
+ buffer = malloc(buflen);
+ if (buffer == NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ status = ctx->getpwuid_r(uid, &lpwd, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_pwd(&lpwd, pwd);
+ }
+
+ free(buffer);
+
+ return wbc_status;
}
/* Fill in a struct passwd* for a domain user based on sid */
wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ wbcErr wbc_status;
+ uid_t uid;
+
+ wbc_status = wbcSidToUid(sid, &uid);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return wbc_status;
+ }
+
+ wbc_status = wbcGetpwuid(uid, pwd);
+
+ return wbc_status;
+
+}
+
+static void wbcGroupDestructor(void *ptr)
+{
+ struct group *gr = (struct group *)ptr;
+ size_t c;
+
+ free(gr->gr_name);
+ free(gr->gr_passwd);
+
+ /* if the array was partly created this can be NULL */
+ if (gr->gr_mem == NULL) {
+ return;
+ }
+
+ for (c=0; gr->gr_mem[c] != NULL; c++) {
+ free(gr->gr_mem[c]);
+ }
+ free(gr->gr_mem);
}
+static wbcErr copy_grp(struct group *in, struct group **out)
+{
+ struct group *gr;
+ size_t members;
+ size_t c;
+
+ gr = (struct group *)wbcAllocateMemory(1, sizeof(struct group),
+ wbcGroupDestructor);
+ if (gr == NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ gr->gr_name = strdup(in->gr_name);
+ if (gr->gr_name == NULL) {
+ goto fail;
+ }
+
+ gr->gr_passwd = strdup(in->gr_passwd);
+ if (gr->gr_passwd == NULL) {
+ goto fail;
+ }
+
+ gr->gr_gid = in->gr_gid;
+
+ for (members = 0; in->gr_mem[members] != NULL; members++);
+
+ if (members > 0) {
+ gr->gr_mem = (char **)calloc(members+1, sizeof(char *));
+ if (gr->gr_mem == NULL) {
+ goto fail;
+ }
+
+ for (c = 0; c < members; c++) {
+ gr->gr_mem[c] = strdup(in->gr_mem[c]);
+ if (gr->gr_mem[c] == NULL) {
+ goto fail;
+ }
+ }
+ }
+
+ *out = gr;
+ return WBC_ERR_SUCCESS;
+fail:
+ wbcFreeMemory(gr);
+
+ return WBC_ERR_NO_MEMORY;
+}
/* Fill in a struct passwd* for a domain user based on username */
wbcErr wbcGetgrnam(const char *name, struct group **grp)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct group lgrp;
+ enum nss_status status;
+ char *newbuffer = NULL;
+ char *buffer = NULL;
+ size_t buflen = 0;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (name == NULL || grp == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ do {
+ if (buflen == 0) {
+ buflen = DEFAULT_BUFSIZE;
+ } else {
+ buflen *= 2;
+ }
+ newbuffer = realloc(buffer, buflen);
+ if (newbuffer == NULL) {
+ free(buffer);
+ return WBC_ERR_NO_MEMORY;
+ }
+ buffer = newbuffer;
+
+ memset(grp, 0, sizeof(struct group));
+ status = ctx->getgrnam_r(name, &lgrp, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_grp(&lgrp, grp);
+ }
+ } while (status == NSS_STATUS_TRYAGAIN && nss_errno == ERANGE \
+ && buflen < MAX_BUFSIZE);
+
+ free(buffer);
+
+ return wbc_status;
}
/* Fill in a struct passwd* for a domain user based on uid */
wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct group lgrp;
+ enum nss_status status;
+ char *newbuffer = NULL;
+ char *buffer = NULL;
+ size_t buflen = 0;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (grp == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ do {
+ if (buflen == 0) {
+ buflen = DEFAULT_BUFSIZE;
+ } else {
+ buflen *= 2;
+ }
+ newbuffer = realloc(buffer, buflen);
+ if (newbuffer == NULL) {
+ free(buffer);
+ return WBC_ERR_NO_MEMORY;
+ }
+ buffer = newbuffer;
+
+ memset(grp, 0, sizeof(struct group));
+ status = ctx->getgrgid_r(gid, &lgrp, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_grp(&lgrp, grp);
+ }
+ } while (status == NSS_STATUS_TRYAGAIN && nss_errno == ERANGE \
+ && buflen < MAX_BUFSIZE);
+
+ free(buffer);
+
+ return wbc_status;
}
/* Reset the passwd iterator */
wbcErr wbcSetpwent(void)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ enum nss_status status;
+ wbcErr wbc_status;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ status = ctx->setpwent();
+ wbc_status = nss_to_wbc(status);
+
+ return wbc_status;
}
/* Close the passwd iterator */
wbcErr wbcEndpwent(void)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ enum nss_status status;
+ wbcErr wbc_status;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ status = ctx->endpwent();
+ wbc_status = nss_to_wbc(status);
+
+ return wbc_status;
}
/* Return the next struct passwd* entry from the pwent iterator */
wbcErr wbcGetpwent(struct passwd **pwd)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct passwd lpwd = {0};
+ enum nss_status status;
+ char *buffer = NULL;
+ size_t buflen;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (pwd == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ buflen = DEFAULT_BUFSIZE;
+ buffer = malloc(buflen);
+ if (buffer == NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ status = ctx->getpwent_r(&lpwd, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_pwd(&lpwd, pwd);
+ }
+
+ free(buffer);
+
+ return wbc_status;
}
/* Reset the group iterator */
wbcErr wbcSetgrent(void)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ enum nss_status status;
+ wbcErr wbc_status;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ status = ctx->setgrent();
+ wbc_status = nss_to_wbc(status);
+
+ return wbc_status;
}
/* Close the group iterator */
wbcErr wbcEndgrent(void)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ enum nss_status status;
+ wbcErr wbc_status;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ status = ctx->endgrent();
+ wbc_status = nss_to_wbc(status);
+
+ return wbc_status;
}
/* Return the next struct group* entry from the pwent iterator */
wbcErr wbcGetgrent(struct group **grp)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ struct group lgrp;
+ enum nss_status status;
+ char *newbuffer = NULL;
+ char *buffer = NULL;
+ size_t buflen = 0;
+ wbcErr wbc_status;
+ int nss_errno;
+
+ if (ctx == NULL && !open_libnss_sss()) {
+ return WBC_ERR_NSS_ERROR;
+ }
+
+ if (grp == NULL) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ do {
+ if (buflen == 0) {
+ buflen = DEFAULT_BUFSIZE;
+ } else {
+ buflen *= 2;
+ }
+ newbuffer = realloc(buffer, buflen);
+ if (newbuffer == NULL) {
+ free(buffer);
+ return WBC_ERR_NO_MEMORY;
+ }
+ buffer = newbuffer;
+
+ memset(grp, 0, sizeof(struct group));
+ status = ctx->getgrent_r(&lgrp, buffer, buflen, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (WBC_ERROR_IS_OK(wbc_status)) {
+ wbc_status = copy_grp(&lgrp, grp);
+ }
+ } while (status == NSS_STATUS_TRYAGAIN && nss_errno == ERANGE \
+ && buflen < MAX_BUFSIZE);
+
+ free(buffer);
+
+ return wbc_status;
}
/* Return the next struct group* entry from the pwent iterator */
wbcErr wbcGetgrlist(struct group **grp)
{
+ /* Not used anywhere */
WBC_SSSD_NOT_IMPLEMENTED;
}
@@ -102,5 +613,45 @@ wbcErr wbcGetGroups(const char *account,
uint32_t *num_groups,
gid_t **_groups)
{
- WBC_SSSD_NOT_IMPLEMENTED;
+ wbcErr wbc_status;
+ enum nss_status status;
+ struct passwd *pwd;
+ long int gr_size = 0;
+ long int start = 0;
+ gid_t *gids = NULL;
+ int nss_errno;
+
+ wbc_status = wbcGetpwnam(account, &pwd);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ return wbc_status;
+ }
+
+ gr_size = DEFAULT_BUFSIZE;
+ gids = calloc(gr_size, sizeof(gid_t));
+ if (gids == NULL) {
+ wbc_status = WBC_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ /* nss modules may skip the primary group when we pass it in so always
+ * add it in advance */
+ gids[0] = pwd->pw_gid;
+ start++;
+
+ status = ctx->initgroups_dyn(pwd->pw_name, pwd->pw_gid, &start,
+ &gr_size, &gids, -1, &nss_errno);
+ wbc_status = nss_to_wbc(status);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ goto done;
+ }
+
+ *_groups = gids;
+ *num_groups = start;
+
+ wbc_status = WBC_ERR_SUCCESS;
+
+done:
+ wbcFreeMemory(pwd);
+
+ return wbc_status;
}