/* Unix SMB/CIFS implementation. Winbind client API Copyright (C) Gerald (Jerry) Carter 2007 Copyright (C) Volker Lendecke 2010 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* Required Headers */ #include "replace.h" #include "libwbclient.h" #include "../winbind_client.h" /* Convert a domain and name to SID */ wbcErr wbcLookupName(const char *domain, const char *name, struct wbcDomainSid *sid, enum wbcSidType *name_type) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!sid || !name_type) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); /* dst is already null terminated from the memset above */ strncpy(request.data.name.dom_name, domain, sizeof(request.data.name.dom_name)-1); strncpy(request.data.name.name, name, sizeof(request.data.name.name)-1); wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = wbcStringToSid(response.data.sid.sid, sid); BAIL_ON_WBC_ERROR(wbc_status); *name_type = (enum wbcSidType)response.data.sid.type; wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; } /* Convert a SID to a domain and name */ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, char **pdomain, char **pname, enum wbcSidType *pname_type) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *domain, *name; if (!sid) { return WBC_ERR_INVALID_PARAM; } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); /* Make request */ wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request, &response); if (!WBC_ERROR_IS_OK(wbc_status)) { return wbc_status; } /* Copy out result */ wbc_status = WBC_ERR_NO_MEMORY; domain = NULL; name = NULL; domain = wbcStrDup(response.data.name.dom_name); if (domain == NULL) { goto done; } name = wbcStrDup(response.data.name.name); if (name == NULL) { goto done; } if (pdomain != NULL) { *pdomain = domain; domain = NULL; } if (pname != NULL) { *pname = name; name = NULL; } if (pname_type != NULL) { *pname_type = (enum wbcSidType)response.data.name.type; } wbc_status = WBC_ERR_SUCCESS; done: wbcFreeMemory(name); wbcFreeMemory(domain); return wbc_status; } static void wbcDomainInfosDestructor(void *ptr) { struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr; while (i->short_name != NULL) { wbcFreeMemory(i->short_name); wbcFreeMemory(i->dns_name); i += 1; } } static void wbcTranslatedNamesDestructor(void *ptr) { struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr; while (n->name != NULL) { wbcFreeMemory(n->name); n += 1; } } wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids, struct wbcDomainInfo **pdomains, int *pnum_domains, struct wbcTranslatedName **pnames) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int buflen, i, extra_len, num_domains, num_names; char *sidlist, *p, *q, *extra_data; struct wbcDomainInfo *domains = NULL; struct wbcTranslatedName *names = NULL; buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1; sidlist = (char *)malloc(buflen); if (sidlist == NULL) { return WBC_ERR_NO_MEMORY; } p = sidlist; for (i=0; i remaining) { free(sidlist); return WBC_ERR_UNKNOWN_FAILURE; } p += len; *p++ = '\n'; } *p++ = '\0'; ZERO_STRUCT(request); ZERO_STRUCT(response); request.extra_data.data = sidlist; request.extra_len = p - sidlist; wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSIDS, &request, &response); free(sidlist); if (!WBC_ERROR_IS_OK(wbc_status)) { return wbc_status; } extra_len = response.length - sizeof(struct winbindd_response); extra_data = (char *)response.extra_data.data; if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) { goto wbc_err_invalid; } p = extra_data; num_domains = strtoul(p, &q, 10); if (*q != '\n') { goto wbc_err_invalid; } p = q+1; domains = (struct wbcDomainInfo *)wbcAllocateMemory( num_domains+1, sizeof(struct wbcDomainInfo), wbcDomainInfosDestructor); if (domains == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } for (i=0; i= num_domains) { goto wbc_err_invalid; } if (*q != ' ') { goto wbc_err_invalid; } p = q+1; names[i].type = strtoul(p, &q, 10); if (*q != ' ') { goto wbc_err_invalid; } p = q+1; q = strchr(p, '\n'); if (q == NULL) { goto wbc_err_invalid; } *q = '\0'; names[i].name = wbcStrDup(p); if (names[i].name == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } p = q+1; } if (*p != '\0') { goto wbc_err_invalid; } *pdomains = domains; *pnames = names; winbindd_free_response(&response); return WBC_ERR_SUCCESS; wbc_err_invalid: wbc_status = WBC_ERR_INVALID_RESPONSE; fail: winbindd_free_response(&response); wbcFreeMemory(domains); wbcFreeMemory(names); return wbc_status; } /* Translate a collection of RIDs within a domain to names */ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, int num_rids, uint32_t *rids, const char **pp_domain_name, const char ***pnames, enum wbcSidType **ptypes) { size_t i, len, ridbuf_size; char *ridlist; char *p; struct winbindd_request request; struct winbindd_response response; char *domain_name = NULL; const char **names = NULL; enum wbcSidType *types = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!dom_sid || (num_rids == 0)) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); /* Even if all the Rids were of maximum 32bit values, we would only have 11 bytes per rid in the final array ("4294967296" + \n). Add one more byte for the terminating '\0' */ ridbuf_size = (sizeof(char)*11) * num_rids + 1; ridlist = (char *)malloc(ridbuf_size); BAIL_ON_PTR_ERROR(ridlist, wbc_status); len = 0; for (i=0; inum_auths < 1) { return WBC_ERR_INVALID_RESPONSE; } *rid = sid->sub_auths[sid->num_auths - 1]; return WBC_ERR_SUCCESS; } /* Get alias membership for sids */ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, struct wbcDomainSid *sids, uint32_t num_sids, uint32_t **alias_rids, uint32_t *num_alias_rids) { uint32_t i; const char *s; struct winbindd_request request; struct winbindd_response response; ssize_t extra_data_len = 0; char * extra_data = NULL; ssize_t buflen = 0; struct wbcDomainSid sid; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; uint32_t * rids = NULL; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!dom_sid) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); /* Lets assume each sid is around 57 characters * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */ buflen = 57 * num_sids; extra_data = (char *)malloc(buflen); if (!extra_data) { wbc_status = WBC_ERR_NO_MEMORY; goto done; } /* Build the sid list */ for (i=0; i= response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } current = next; k = strchr(next, ','); if (k) { k[0] = '\0'; next = k+1; } else { next = NULL; } users[num_users] = strdup(current); BAIL_ON_PTR_ERROR(users[num_users], wbc_status); num_users += 1; } if (num_users != response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } *_num_users = response.data.num_entries; *_users = users; users = NULL; wbc_status = WBC_ERR_SUCCESS; done: winbindd_free_response(&response); wbcFreeMemory(users); return wbc_status; } /* Lists Groups */ wbcErr wbcListGroups(const char *domain_name, uint32_t *_num_groups, const char ***_groups) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; uint32_t num_groups = 0; const char **groups = NULL; const char *next; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (domain_name) { strncpy(request.domain_name, domain_name, sizeof(request.domain_name)-1); } wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); groups = wbcAllocateStringArray(response.data.num_entries); if (groups == NULL) { return WBC_ERR_NO_MEMORY; } /* Look through extra data */ next = (const char *)response.extra_data.data; while (next) { const char *current; char *k; if (num_groups >= response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } current = next; k = strchr(next, ','); if (k) { k[0] = '\0'; next = k+1; } else { next = NULL; } groups[num_groups] = strdup(current); BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status); num_groups += 1; } if (num_groups != response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } *_num_groups = response.data.num_entries; *_groups = groups; groups = NULL; wbc_status = WBC_ERR_SUCCESS; done: winbindd_free_response(&response); wbcFreeMemory(groups); return wbc_status; } wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid, char **pdomain, char **pfullname, enum wbcSidType *pname_type) { wbcErr wbc_status; char *domain = NULL; char *name = NULL; enum wbcSidType name_type; wbc_status = wbcLookupSid(sid, &domain, &name, &name_type); BAIL_ON_WBC_ERROR(wbc_status); if (name_type == WBC_SID_NAME_USER) { uid_t uid; struct passwd *pwd; wbc_status = wbcSidToUid(sid, &uid); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = wbcGetpwuid(uid, &pwd); BAIL_ON_WBC_ERROR(wbc_status); wbcFreeMemory(name); name = wbcStrDup(pwd->pw_gecos); wbcFreeMemory(pwd); BAIL_ON_PTR_ERROR(name, wbc_status); } wbc_status = WBC_ERR_SUCCESS; done: if (WBC_ERROR_IS_OK(wbc_status)) { *pdomain = domain; *pfullname = name; *pname_type = name_type; } else { wbcFreeMemory(domain); wbcFreeMemory(name); } return wbc_status; }