From 745338dceac40ecb4230ee518e850dc5d3cef6a5 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 9 May 2014 16:07:54 +0200 Subject: libwbclient-sssd: implement basic functions --- nsswitch/libwbclient/wbc_idmap_sssd.c | 138 +++++++- nsswitch/libwbclient/wbc_pwd_sssd.c | 575 +++++++++++++++++++++++++++++++++- nsswitch/libwbclient/wbc_sid_sssd.c | 171 +++++++++- nsswitch/libwbclient/wbc_util_sssd.c | 63 +++- nsswitch/libwbclient/wbclient_sssd.c | 2 + 5 files changed, 927 insertions(+), 22 deletions(-) diff --git a/nsswitch/libwbclient/wbc_idmap_sssd.c b/nsswitch/libwbclient/wbc_idmap_sssd.c index d1ef7f59ca1..25fb88eb18b 100644 --- a/nsswitch/libwbclient/wbc_idmap_sssd.c +++ b/nsswitch/libwbclient/wbc_idmap_sssd.c @@ -20,6 +20,7 @@ */ /* Required Headers */ +#include #include "replace.h" #include "libwbclient.h" @@ -29,13 +30,57 @@ /* Convert a Windows SID to a Unix uid, allocating an uid if needed */ wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid) { - WBC_SSSD_NOT_IMPLEMENTED; + int ret; + char *sid_str; + uint32_t id; + enum sss_id_type type; + wbcErr wbc_status; + + wbc_status = wbcSidToString(sid, &sid_str); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + ret = sss_nss_getidbysid(sid_str, &id, &type); + wbcFreeMemory(sid_str); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + if (type != SSS_ID_TYPE_UID && type != SSS_ID_TYPE_BOTH) { + return WBC_ERR_UNKNOWN_GROUP; + } + + *puid = (uid_t) id; + + return WBC_ERR_SUCCESS; } /* Convert a Unix uid to a Windows SID, allocating a SID if needed */ wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid) { - WBC_SSSD_NOT_IMPLEMENTED; + int ret; + char *str_sid; + enum sss_id_type type; + wbcErr wbc_status; + + ret = sss_nss_getsidbyid(uid, &str_sid, &type); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + if (type != SSS_ID_TYPE_UID && type != SSS_ID_TYPE_BOTH) { + free(str_sid); + return WBC_ERR_UNKNOWN_USER; + } + + wbc_status = wbcStringToSid(str_sid, sid); + free(str_sid); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + return WBC_ERR_SUCCESS; } /** @brief Convert a Windows SID to a Unix gid, allocating a gid if needed @@ -49,24 +94,70 @@ wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid) wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid) { - WBC_SSSD_NOT_IMPLEMENTED; + int ret; + char *sid_str; + uint32_t id; + enum sss_id_type type; + wbcErr wbc_status; + + wbc_status = wbcSidToString(sid, &sid_str); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + ret = sss_nss_getidbysid(sid_str, &id, &type); + wbcFreeMemory(sid_str); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + if (type != SSS_ID_TYPE_GID && type != SSS_ID_TYPE_BOTH) { + return WBC_ERR_UNKNOWN_GROUP; + } + + *pgid = (gid_t) id; + + return WBC_ERR_SUCCESS; } /* Convert a Unix gid to a Windows SID, allocating a SID if needed */ wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid) { - WBC_SSSD_NOT_IMPLEMENTED; + int ret; + char *str_sid; + enum sss_id_type type; + wbcErr wbc_status; + + ret = sss_nss_getsidbyid(gid, &str_sid, &type); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + if (type != SSS_ID_TYPE_GID && type != SSS_ID_TYPE_BOTH) { + free(str_sid); + return WBC_ERR_UNKNOWN_USER; + } + + wbc_status = wbcStringToSid(str_sid, sid); + free(str_sid); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + return WBC_ERR_SUCCESS; } /* Obtain a new uid from Winbind */ wbcErr wbcAllocateUid(uid_t *puid) { + /* Not supported by SSSD */ WBC_SSSD_NOT_IMPLEMENTED; } /* Obtain a new gid from Winbind */ wbcErr wbcAllocateGid(gid_t *pgid) { + /* Not supported by SSSD */ WBC_SSSD_NOT_IMPLEMENTED; } @@ -74,5 +165,42 @@ wbcErr wbcAllocateGid(gid_t *pgid) wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids, struct wbcUnixId *ids) { - WBC_SSSD_NOT_IMPLEMENTED; + int ret; + char *sid_str; + uint32_t id; + enum sss_id_type type; + size_t c; + wbcErr wbc_status; + + for (c = 0; c < num_sids; c++) { + wbc_status = wbcSidToString(&sids[c], &sid_str); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + ret = sss_nss_getidbysid(sid_str, &id, &type); + wbcFreeMemory(sid_str); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + switch (type) { + case SSS_ID_TYPE_UID: + ids[c].type = WBC_ID_TYPE_UID; + ids[c].id.uid = (uid_t) id; + break; + case SSS_ID_TYPE_GID: + ids[c].type = WBC_ID_TYPE_GID; + ids[c].id.gid = (gid_t) id; + break; + case SSS_ID_TYPE_BOTH: + ids[c].type = WBC_ID_TYPE_BOTH; + ids[c].id.uid = (uid_t) id; + break; + default: + ids[c].type = WBC_ID_TYPE_NOT_SPECIFIED; + } + } + + return WBC_ERR_SUCCESS; } 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; } diff --git a/nsswitch/libwbclient/wbc_sid_sssd.c b/nsswitch/libwbclient/wbc_sid_sssd.c index 4826f295fb7..28d181c5664 100644 --- a/nsswitch/libwbclient/wbc_sid_sssd.c +++ b/nsswitch/libwbclient/wbc_sid_sssd.c @@ -21,18 +21,69 @@ /* Required Headers */ +#include + #include "replace.h" #include "libwbclient.h" #include "../winbind_client.h" #include "wbc_sssd_internal.h" +static int sss_id_type_to_wbcSidType(enum sss_id_type sss_type, + enum wbcSidType *name_type) +{ + switch (sss_type) { + case SSS_ID_TYPE_NOT_SPECIFIED: + *name_type = WBC_SID_NAME_USE_NONE; + break; + case SSS_ID_TYPE_UID: + case SSS_ID_TYPE_BOTH: + *name_type = WBC_SID_NAME_USER; + break; + case SSS_ID_TYPE_GID: + *name_type = WBC_SID_NAME_DOM_GRP; + break; + default: + return EINVAL; + } + + return 0; +}; + /* Convert a domain and name to SID */ wbcErr wbcLookupName(const char *domain, const char *name, struct wbcDomainSid *sid, enum wbcSidType *name_type) { - WBC_SSSD_NOT_IMPLEMENTED; + char *fq_name = NULL; + char *str_sid; + enum sss_id_type type; + int ret; + wbcErr wbc_status; + + ret = asprintf(&fq_name, "%s@%s", name, domain); + if (ret == -1) { + return WBC_ERR_NO_MEMORY; + } + + ret = sss_nss_getsidbyname(fq_name, &str_sid, &type); + free(fq_name); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + ret = sss_id_type_to_wbcSidType(type, name_type); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + wbc_status = wbcStringToSid(str_sid, sid); + free(str_sid); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + return WBC_ERR_SUCCESS; } @@ -42,7 +93,55 @@ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, char **pname, enum wbcSidType *pname_type) { - WBC_SSSD_NOT_IMPLEMENTED; + char *str_sid; + char *fq_name = NULL; + enum sss_id_type type; + int ret; + char *p; + wbcErr wbc_status; + + wbc_status = wbcSidToString(sid, &str_sid); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + ret = sss_nss_getnamebysid(str_sid, &fq_name, &type); + wbcFreeMemory(str_sid); + if (ret != 0) { + return WBC_ERR_UNKNOWN_FAILURE; + } + + ret = sss_id_type_to_wbcSidType(type, pname_type); + if (ret != 0) { + wbc_status = WBC_ERR_UNKNOWN_FAILURE; + goto done; + } + + /* FIXME: it would be nice to have a sss_nss_getnamebysid() call which + * return name and domain separately. */ + p = strchr(fq_name, '@'); + if (p == NULL) { + wbc_status = WBC_ERR_UNKNOWN_FAILURE; + goto done; + } + + *p = '\0'; + *pname = wbcStrDup(fq_name); + if (*pname == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + *pdomain = wbcStrDup(p + 1); + if (*pdomain == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + wbc_status = WBC_ERR_SUCCESS; +done: + free(fq_name); + return wbc_status; } wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids, @@ -61,7 +160,73 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, const char ***pnames, enum wbcSidType **ptypes) { - WBC_SSSD_NOT_IMPLEMENTED; + struct wbcDomainSid obj_sid; + size_t c; + wbcErr err; + char *domain; + char *name; + enum wbcSidType type; + const char **names = NULL; + enum wbcSidType *types = NULL; + + memset(&obj_sid, 0, sizeof(obj_sid)); + + obj_sid.sid_rev_num = dom_sid->sid_rev_num; + obj_sid.num_auths = dom_sid->num_auths + 1; + for (c = 0; c < 6; c++) { + obj_sid.id_auth[c] = dom_sid->id_auth[c]; + } + for (c = 0; c < WBC_MAXSUBAUTHS; c++) { + obj_sid.sub_auths[c] = dom_sid->sub_auths[c]; + } + + names = wbcAllocateStringArray(num_rids + 1); + if (names == NULL) { + err = WBC_ERR_NO_MEMORY; + goto done; + } + + types = wbcAllocateMemory(num_rids + 1, sizeof(enum wbcSidType), NULL); + if (types == NULL) { + err = WBC_ERR_NO_MEMORY; + goto done; + } + + for (c = 0; c < num_rids; c++) { + obj_sid.sub_auths[obj_sid.num_auths - 1] = rids[c]; + + err = wbcLookupSid(&obj_sid, &domain, &name, &type); + if (err != WBC_ERR_SUCCESS) { + goto done; + } + + names[c] = strdup(name); + wbcFreeMemory(name); + if (names[c] == NULL) { + err = WBC_ERR_NO_MEMORY; + goto done; + } + types[c] = type; + + if (c == 0) { + *pp_domain_name = domain; + } else { + wbcFreeMemory(domain); + } + } + + *pnames = names; + *ptypes = types; + + err = WBC_ERR_SUCCESS; + +done: + if (err != WBC_ERR_SUCCESS) { + wbcFreeMemory(types); + wbcFreeMemory(names); + } + + return err; } /* Get the groups a user belongs to */ diff --git a/nsswitch/libwbclient/wbc_util_sssd.c b/nsswitch/libwbclient/wbc_util_sssd.c index d1049e239b3..50edc072bc3 100644 --- a/nsswitch/libwbclient/wbc_util_sssd.c +++ b/nsswitch/libwbclient/wbc_util_sssd.c @@ -25,13 +25,26 @@ #include "../winbind_client.h" #include "wbc_sssd_internal.h" +/* For WINBIND_INTERFACE_VERSION */ +#include "../winbind_struct_protocol.h" + /** @brief Ping winbindd to see if the daemon is running * * @return #wbcErr **/ wbcErr wbcPing(void) { - WBC_SSSD_NOT_IMPLEMENTED; + /* TODO: add real check */ + return WBC_ERR_SUCCESS; +} + +static void wbcInterfaceDetailsDestructor(void *ptr) +{ + struct wbcInterfaceDetails *i = (struct wbcInterfaceDetails *)ptr; + free(i->winbind_version); + free(i->netbios_name); + free(i->netbios_domain); + free(i->dns_domain); } /** @@ -44,7 +57,51 @@ wbcErr wbcPing(void) wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) { - WBC_SSSD_NOT_IMPLEMENTED; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcInterfaceDetails *info; + info = (struct wbcInterfaceDetails *)wbcAllocateMemory( + 1, sizeof(struct wbcInterfaceDetails), + wbcInterfaceDetailsDestructor); + if (info == NULL) { + return WBC_ERR_NO_MEMORY; + } + + /* TODO: currently this call just returns a suitable winbind_separator + * for wbinfo. */ + + info->interface_version = WINBIND_INTERFACE_VERSION; + info->winbind_version = strdup("libwbclient for SSSD"); + if (info->winbind_version == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + info->winbind_separator = '\\'; + + info->netbios_name = strdup("-not available-"); + if (info->netbios_name == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + info->netbios_domain = strdup("-not available-"); + if (info->netbios_domain == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + info->dns_domain = strdup("-not available-"); + if (info->dns_domain == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto done; + } + + *_details = info; + info = NULL; + wbc_status = WBC_ERR_SUCCESS; +done: + wbcFreeMemory(info); + return wbc_status; } /** @brief Lookup the current status of a trusted domain, sync wrapper @@ -70,12 +127,14 @@ wbcErr wbcDcInfo(const char *domain, size_t *num_dcs, /* Resolve a NetbiosName via WINS */ wbcErr wbcResolveWinsByName(const char *name, char **ip) { + /* SSSD does not support WINS */ WBC_SSSD_NOT_IMPLEMENTED; } /* Resolve an IP address via WINS into a NetbiosName */ wbcErr wbcResolveWinsByIP(const char *ip, char **name) { + /* SSSD does not support WINS */ WBC_SSSD_NOT_IMPLEMENTED; } diff --git a/nsswitch/libwbclient/wbclient_sssd.c b/nsswitch/libwbclient/wbclient_sssd.c index 2c975f5bcfe..256eac8ad7c 100644 --- a/nsswitch/libwbclient/wbclient_sssd.c +++ b/nsswitch/libwbclient/wbclient_sssd.c @@ -28,6 +28,7 @@ wbcErr wbcRequestResponse(int cmd, struct winbindd_request *request, struct winbindd_response *response) { + /* Helper to make API check happy */ WBC_SSSD_NOT_IMPLEMENTED; } @@ -35,5 +36,6 @@ wbcErr wbcRequestResponsePriv(int cmd, struct winbindd_request *request, struct winbindd_response *response) { + /* Helper to make API check happy */ WBC_SSSD_NOT_IMPLEMENTED; } -- cgit