winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[samba.git] / nsswitch / libwbclient / wbc_sid.c
index 99c9d8e1521fa9cd7c51fcddf5b8a2d4fd8342bf..77445afc5e938e1cb4015e7168a396a9140a13e8 100644 (file)
@@ -4,6 +4,7 @@
    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
 
 #include "replace.h"
 #include "libwbclient.h"
+#include "../winbind_client.h"
 
-
-/* Convert a binary SID to a character string */
-wbcErr wbcSidToString(const struct wbcDomainSid *sid,
-                     char **sid_string)
+/* Convert a sid to a string into a buffer. Return the string
+ * length. If buflen is too small, return the string length that would
+ * result if it was long enough. */
+int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen)
 {
-       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
-       uint32_t id_auth;
-       int i;
-       char *tmp = NULL;
+       uint64_t id_auth;
+       int i, ofs;
 
        if (!sid) {
-               wbc_status = WBC_ERR_INVALID_SID;
-               BAIL_ON_WBC_ERROR(wbc_status);
+               strlcpy(buf, "(NULL SID)", buflen);
+               return 10;      /* strlen("(NULL SID)") */
        }
 
-       id_auth = sid->id_auth[5] +
-               (sid->id_auth[4] << 8) +
-               (sid->id_auth[3] << 16) +
-               (sid->id_auth[2] << 24);
+       id_auth = (uint64_t)sid->id_auth[5] +
+               ((uint64_t)sid->id_auth[4] << 8) +
+               ((uint64_t)sid->id_auth[3] << 16) +
+               ((uint64_t)sid->id_auth[2] << 24) +
+               ((uint64_t)sid->id_auth[1] << 32) +
+               ((uint64_t)sid->id_auth[0] << 40);
+
+       ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
+       if (id_auth >= UINT32_MAX) {
+               ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "0x%llx",
+                               (unsigned long long)id_auth);
+       } else {
+               ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
+                               (unsigned long long)id_auth);
+       }
 
-       tmp = talloc_asprintf(NULL, "S-%d-%d", sid->sid_rev_num, id_auth);
-       BAIL_ON_PTR_ERROR(tmp, wbc_status);
+       for (i = 0; i < sid->num_auths; i++) {
+               ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
+                               (unsigned int)sid->sub_auths[i]);
+       }
+       return ofs;
+}
 
-       for (i=0; i<sid->num_auths; i++) {
-               char *tmp2;
-               tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
-               BAIL_ON_PTR_ERROR(tmp2, wbc_status);
+/* Convert a binary SID to a character string */
+wbcErr wbcSidToString(const struct wbcDomainSid *sid,
+                     char **sid_string)
+{
+       char buf[WBC_SID_STRING_BUFLEN];
+       char *result;
+       int len;
 
-               tmp = tmp2;
+       if (!sid) {
+               return WBC_ERR_INVALID_SID;
        }
 
-       *sid_string = tmp;
-       tmp = NULL;
+       len = wbcSidToStringBuf(sid, buf, sizeof(buf));
 
-       wbc_status = WBC_ERR_SUCCESS;
+       if (len+1 > sizeof(buf)) {
+               return WBC_ERR_INVALID_SID;
+       }
 
-done:
-       talloc_free(tmp);
+       result = (char *)wbcAllocateMemory(len+1, 1, NULL);
+       if (result == NULL) {
+               return WBC_ERR_NO_MEMORY;
+       }
+       memcpy(result, buf, len+1);
 
-       return wbc_status;
+       *sid_string = result;
+       return WBC_ERR_SUCCESS;
 }
 
+#define AUTHORITY_MASK (~(0xffffffffffffULL))
+
 /* Convert a character string to a binary SID */
 wbcErr wbcStringToSid(const char *str,
                      struct wbcDomainSid *sid)
 {
        const char *p;
        char *q;
-       uint32_t x;
+       uint64_t x;
        wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 
        if (!sid) {
@@ -94,45 +120,47 @@ wbcErr wbcStringToSid(const char *str,
        /* Get the SID revision number */
 
        p = str+2;
-       x = (uint32_t)strtol(p, &q, 10);
-       if (x==0 || !q || *q!='-') {
+       x = (uint64_t)strtoul(p, &q, 10);
+       if (x==0 || x > UINT8_MAX || !q || *q!='-') {
                wbc_status = WBC_ERR_INVALID_SID;
                BAIL_ON_WBC_ERROR(wbc_status);
        }
        sid->sid_rev_num = (uint8_t)x;
 
-       /* Next the Identifier Authority.  This is stored in big-endian
-          in a 6 byte array. */
-
+       /*
+        * Next the Identifier Authority.  This is stored big-endian in a
+        * 6 byte array. If the authority value is >= UINT_MAX, then it should
+        * be expressed as a hex value, according to MS-DTYP.
+        */
        p = q+1;
-       x = (uint32_t)strtol(p, &q, 10);
-       if (!q || *q!='-') {
+       x = strtoull(p, &q, 0);
+       if (!q || *q!='-' || (x & AUTHORITY_MASK)) {
                wbc_status = WBC_ERR_INVALID_SID;
                BAIL_ON_WBC_ERROR(wbc_status);
        }
-       sid->id_auth[5] = (x & 0x000000ff);
-       sid->id_auth[4] = (x & 0x0000ff00) >> 8;
-       sid->id_auth[3] = (x & 0x00ff0000) >> 16;
-       sid->id_auth[2] = (x & 0xff000000) >> 24;
-       sid->id_auth[1] = 0;
-       sid->id_auth[0] = 0;
+       sid->id_auth[5] = (x & 0x0000000000ffULL);
+       sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
+       sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
+       sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
+       sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
+       sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
 
        /* now read the the subauthorities */
-
        p = q +1;
        sid->num_auths = 0;
        while (sid->num_auths < WBC_MAXSUBAUTHS) {
-               x=(uint32_t)strtoul(p, &q, 10);
+               x = strtoull(p, &q, 10);
                if (p == q)
                        break;
-               if (q == NULL) {
+               if (x > UINT32_MAX) {
                        wbc_status = WBC_ERR_INVALID_SID;
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
                sid->sub_auths[sid->num_auths++] = x;
 
-               if ((*q!='-') || (*q=='\0'))
+               if (*q != '-') {
                        break;
+               }
                p = q + 1;
        }
 
@@ -150,11 +178,13 @@ done:
 
 }
 
+
 /* Convert a domain and name to SID */
-wbcErr wbcLookupName(const char *domain,
-                    const char *name,
-                    struct wbcDomainSid *sid,
-                    enum wbcSidType *name_type)
+wbcErr wbcCtxLookupName(struct wbcContext *ctx,
+                       const char *domain,
+                       const char *name,
+                       struct wbcDomainSid *sid,
+                       enum wbcSidType *name_type)
 {
        struct winbindd_request request;
        struct winbindd_response response;
@@ -177,7 +207,7 @@ wbcErr wbcLookupName(const char *domain,
        strncpy(request.data.name.name, name,
                sizeof(request.data.name.name)-1);
 
-       wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
                                        &request,
                                        &response);
        BAIL_ON_WBC_ERROR(wbc_status);
@@ -193,97 +223,289 @@ wbcErr wbcLookupName(const char *domain,
        return wbc_status;
 }
 
+wbcErr wbcLookupName(const char *domain,
+                    const char *name,
+                    struct wbcDomainSid *sid,
+                    enum wbcSidType *name_type)
+{
+       return wbcCtxLookupName(NULL, domain, name, sid, name_type);
+}
+
+
 /* Convert a SID to a domain and name */
+wbcErr wbcCtxLookupSid(struct wbcContext *ctx,
+                      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(ctx, 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;
+}
+
 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
                    char **pdomain,
                    char **pname,
                    enum wbcSidType *pname_type)
+{
+       return wbcCtxLookupSid(NULL, sid, pdomain, pname, pname_type);
+}
+
+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 wbcCtxLookupSids(struct wbcContext *ctx,
+                       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;
-       char *sid_string = NULL;
-       char *domain = NULL;
-       char *name = NULL;
-       enum wbcSidType name_type = WBC_SID_NAME_USE_NONE;
+       int buflen, i, extra_len, num_domains, num_names;
+       char *sidlist, *p, *q, *extra_data;
+       struct wbcDomainInfo *domains = NULL;
+       struct wbcTranslatedName *names = NULL;
 
-       if (!sid) {
-               wbc_status = WBC_ERR_INVALID_PARAM;
-               BAIL_ON_WBC_ERROR(wbc_status);
+       buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
+
+       sidlist = (char *)malloc(buflen);
+       if (sidlist == NULL) {
+               return WBC_ERR_NO_MEMORY;
        }
 
-       /* Initialize request */
+       p = sidlist;
+
+       for (i=0; i<num_sids; i++) {
+               int remaining;
+               int len;
+
+               remaining = buflen - (p - sidlist);
+
+               len = wbcSidToStringBuf(&sids[i], p, remaining);
+               if (len > remaining) {
+                       free(sidlist);
+                       return WBC_ERR_UNKNOWN_FAILURE;
+               }
+
+               p += len;
+               *p++ = '\n';
+       }
+       *p++ = '\0';
 
        ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       /* dst is already null terminated from the memset above */
+       request.extra_data.data = sidlist;
+       request.extra_len = p - sidlist;
 
-       wbc_status = wbcSidToString(sid, &sid_string);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSIDS,
+                                       &request, &response);
+       free(sidlist);
+       if (!WBC_ERROR_IS_OK(wbc_status)) {
+               return wbc_status;
+       }
 
-       strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
-       wbcFreeMemory(sid_string);
+       extra_len = response.length - sizeof(struct winbindd_response);
+       extra_data = (char *)response.extra_data.data;
 
-       /* Make request */
+       if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
+               goto wbc_err_invalid;
+       }
 
-       wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID,
-                                          &request,
-                                          &response);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       p = extra_data;
 
-       /* Copy out result */
+       num_domains = strtoul(p, &q, 10);
+       if (*q != '\n') {
+               goto wbc_err_invalid;
+       }
+       p = q+1;
 
-       domain = talloc_strdup(NULL, response.data.name.dom_name);
-       BAIL_ON_PTR_ERROR(domain, wbc_status);
+       domains = (struct wbcDomainInfo *)wbcAllocateMemory(
+               num_domains+1, sizeof(struct wbcDomainInfo),
+               wbcDomainInfosDestructor);
+       if (domains == NULL) {
+               wbc_status = WBC_ERR_NO_MEMORY;
+               goto fail;
+       }
 
-       name = talloc_strdup(NULL, response.data.name.name);
-       BAIL_ON_PTR_ERROR(name, wbc_status);
+       for (i=0; i<num_domains; i++) {
 
-       name_type = (enum wbcSidType)response.data.name.type;
+               q = strchr(p, ' ');
+               if (q == NULL) {
+                       goto wbc_err_invalid;
+               }
+               *q = '\0';
+               wbc_status = wbcStringToSid(p, &domains[i].sid);
+               if (!WBC_ERROR_IS_OK(wbc_status)) {
+                       goto fail;
+               }
+               p = q+1;
 
-       wbc_status = WBC_ERR_SUCCESS;
+               q = strchr(p, '\n');
+               if (q == NULL) {
+                       goto wbc_err_invalid;
+               }
+               *q = '\0';
+               domains[i].short_name = wbcStrDup(p);
+               if (domains[i].short_name == NULL) {
+                       wbc_status = WBC_ERR_NO_MEMORY;
+                       goto fail;
+               }
+               p = q+1;
+       }
 
- done:
-       if (WBC_ERROR_IS_OK(wbc_status)) {
-               if (pdomain != NULL) {
-                       *pdomain = domain;
-               } else {
-                       TALLOC_FREE(domain);
+       num_names = strtoul(p, &q, 10);
+       if (*q != '\n') {
+               goto wbc_err_invalid;
+       }
+       p = q+1;
+
+       if (num_names != num_sids) {
+               goto wbc_err_invalid;
+       }
+
+       names = (struct wbcTranslatedName *)wbcAllocateMemory(
+               num_names+1, sizeof(struct wbcTranslatedName),
+               wbcTranslatedNamesDestructor);
+       if (names == NULL) {
+               wbc_status = WBC_ERR_NO_MEMORY;
+               goto fail;
+       }
+
+       for (i=0; i<num_names; i++) {
+
+               names[i].domain_index = strtoul(p, &q, 10);
+               if (names[i].domain_index < 0) {
+                       goto wbc_err_invalid;
                }
-               if (pname != NULL) {
-                       *pname = name;
-               } else {
-                       TALLOC_FREE(name);
+               if (names[i].domain_index >= num_domains) {
+                       goto wbc_err_invalid;
                }
-               if (pname_type != NULL) {
-                       *pname_type = name_type;
+
+               if (*q != ' ') {
+                       goto wbc_err_invalid;
                }
-       }
-       else {
-#if 0
-               /*
-                * Found by Coverity: In this particular routine we can't end
-                * up here with a non-NULL name. Further up there are just two
-                * exit paths that lead here, neither of which leave an
-                * allocated name. If you add more paths up there, re-activate
-                * this.
-                */
-               if (name != NULL) {
-                       talloc_free(name);
+               p = q+1;
+
+               names[i].type = strtoul(p, &q, 10);
+               if (*q != ' ') {
+                       goto wbc_err_invalid;
                }
-#endif
-               if (domain != NULL) {
-                       talloc_free(domain);
+               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;
 }
 
+wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
+                    struct wbcDomainInfo **pdomains, int *pnum_domains,
+                    struct wbcTranslatedName **pnames)
+{
+       return wbcCtxLookupSids(NULL, sids, num_sids, pdomains,
+                               pnum_domains, pnames);
+}
+
 /* Translate a collection of RIDs within a domain to names */
 
-wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
+wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
                     int num_rids,
                     uint32_t *rids,
                     const char **pp_domain_name,
@@ -295,7 +517,6 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
        char *p;
        struct winbindd_request request;
        struct winbindd_response response;
-       char *sid_string = NULL;
        char *domain_name = NULL;
        const char **names = NULL;
        enum wbcSidType *types = NULL;
@@ -311,11 +532,7 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       wbc_status = wbcSidToString(dom_sid, &sid_string);
-       BAIL_ON_WBC_ERROR(wbc_status);
-
-       strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
-       wbcFreeMemory(sid_string);
+       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
@@ -324,36 +541,34 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
 
        ridbuf_size = (sizeof(char)*11) * num_rids + 1;
 
-       ridlist = talloc_zero_array(NULL, char, ridbuf_size);
+       ridlist = (char *)malloc(ridbuf_size);
        BAIL_ON_PTR_ERROR(ridlist, wbc_status);
 
        len = 0;
-       for (i=0; i<num_rids && (len-1)>0; i++) {
-               char ridstr[12];
-
-               len = strlen(ridlist);
-               p = ridlist + len;
-
-               snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
-               strncat(p, ridstr, ridbuf_size-len-1);
+       for (i=0; i<num_rids; i++) {
+               len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
+                               rids[i]);
        }
+       ridlist[len] = '\0';
+       len += 1;
 
        request.extra_data.data = ridlist;
-       request.extra_len = strlen(ridlist)+1;
+       request.extra_len = len;
 
-       wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
                                        &request,
                                        &response);
-       talloc_free(ridlist);
+       free(ridlist);
        BAIL_ON_WBC_ERROR(wbc_status);
 
-       domain_name = talloc_strdup(NULL, response.data.domain_name);
+       domain_name = wbcStrDup(response.data.domain_name);
        BAIL_ON_PTR_ERROR(domain_name, wbc_status);
 
-       names = talloc_array(NULL, const char*, num_rids);
+       names = wbcAllocateStringArray(num_rids);
        BAIL_ON_PTR_ERROR(names, wbc_status);
 
-       types = talloc_array(NULL, enum wbcSidType, num_rids);
+       types = (enum wbcSidType *)wbcAllocateMemory(
+               num_rids, sizeof(enum wbcSidType), NULL);
        BAIL_ON_PTR_ERROR(types, wbc_status);
 
        p = (char *)response.extra_data.data;
@@ -363,26 +578,26 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
 
                if (*p == '\0') {
                        wbc_status = WBC_ERR_INVALID_RESPONSE;
-                       BAIL_ON_WBC_ERROR(wbc_status);
+                       goto done;
                }
 
                types[i] = (enum wbcSidType)strtoul(p, &q, 10);
 
                if (*q != ' ') {
                        wbc_status = WBC_ERR_INVALID_RESPONSE;
-                       BAIL_ON_WBC_ERROR(wbc_status);
+                       goto done;
                }
 
                p = q+1;
 
                if ((q = strchr(p, '\n')) == NULL) {
                        wbc_status = WBC_ERR_INVALID_RESPONSE;
-                       BAIL_ON_WBC_ERROR(wbc_status);
+                       goto done;
                }
 
                *q = '\0';
 
-               names[i] = talloc_strdup(names, p);
+               names[i] = strdup(p);
                BAIL_ON_PTR_ERROR(names[i], wbc_status);
 
                p = q+1;
@@ -390,15 +605,13 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
 
        if (*p != '\0') {
                wbc_status = WBC_ERR_INVALID_RESPONSE;
-               BAIL_ON_WBC_ERROR(wbc_status);
+               goto done;
        }
 
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       if (response.extra_data.data) {
-               free(response.extra_data.data);
-       }
+       winbindd_free_response(&response);
 
        if (WBC_ERROR_IS_OK(wbc_status)) {
                *pp_domain_name = domain_name;
@@ -406,28 +619,36 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
                *ptypes = types;
        }
        else {
-               if (domain_name)
-                       talloc_free(domain_name);
-               if (names)
-                       talloc_free(names);
-               if (types)
-                       talloc_free(types);
+               wbcFreeMemory(domain_name);
+               wbcFreeMemory(names);
+               wbcFreeMemory(types);
        }
 
        return wbc_status;
 }
 
+wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
+                    int num_rids,
+                    uint32_t *rids,
+                    const char **pp_domain_name,
+                    const char ***pnames,
+                    enum wbcSidType **ptypes)
+{
+       return wbcCtxLookupRids(NULL, dom_sid, num_rids, rids,
+                               pp_domain_name, pnames, ptypes);
+}
+
 /* Get the groups a user belongs to */
-wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
-                        bool domain_groups_only,
-                        uint32_t *num_sids,
-                        struct wbcDomainSid **_sids)
+wbcErr wbcCtxLookupUserSids(struct wbcContext *ctx,
+                           const struct wbcDomainSid *user_sid,
+                           bool domain_groups_only,
+                           uint32_t *num_sids,
+                           struct wbcDomainSid **_sids)
 {
        uint32_t i;
        const char *s;
        struct winbindd_request request;
        struct winbindd_response response;
-       char *sid_string = NULL;
        struct wbcDomainSid *sids = NULL;
        wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
        int cmd;
@@ -442,11 +663,7 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       wbc_status = wbcSidToString(user_sid, &sid_string);
-       BAIL_ON_WBC_ERROR(wbc_status);
-
-       strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
-       wbcFreeMemory(sid_string);
+       wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
 
        if (domain_groups_only) {
                cmd = WINBINDD_GETUSERDOMGROUPS;
@@ -454,7 +671,7 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
                cmd = WINBINDD_GETUSERSIDS;
        }
 
-       wbc_status = wbcRequestResponse(cmd,
+       wbc_status = wbcRequestResponse(ctx, cmd,
                                        &request,
                                        &response);
        BAIL_ON_WBC_ERROR(wbc_status);
@@ -465,8 +682,9 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       sids = talloc_array(NULL, struct wbcDomainSid,
-                           response.data.num_entries);
+       sids = (struct wbcDomainSid *)wbcAllocateMemory(
+               response.data.num_entries, sizeof(struct wbcDomainSid),
+               NULL);
        BAIL_ON_PTR_ERROR(sids, wbc_status);
 
        s = (const char *)response.extra_data.data;
@@ -486,16 +704,23 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       if (response.extra_data.data) {
-               free(response.extra_data.data);
-       }
+       winbindd_free_response(&response);
        if (sids) {
-               talloc_free(sids);
+               wbcFreeMemory(sids);
        }
 
        return wbc_status;
 }
 
+wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
+                        bool domain_groups_only,
+                        uint32_t *num_sids,
+                        struct wbcDomainSid **_sids)
+{
+       return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
+                                   num_sids, _sids);
+}
+
 static inline
 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
 {
@@ -508,18 +733,17 @@ wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
 }
 
 /* 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)
+wbcErr wbcCtxGetSidAliases(struct wbcContext *ctx,
+                          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;
-       char *sid_string = NULL;
-       ssize_t sid_len;
        ssize_t extra_data_len = 0;
        char * extra_data = NULL;
        ssize_t buflen = 0;
@@ -534,57 +758,48 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
 
        if (!dom_sid) {
                wbc_status = WBC_ERR_INVALID_PARAM;
-               BAIL_ON_WBC_ERROR(wbc_status);
+               goto done;
        }
 
-       wbc_status = wbcSidToString(dom_sid, &sid_string);
-       BAIL_ON_WBC_ERROR(wbc_status);
-
-       strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
-       wbcFreeMemory(sid_string);
-       sid_string = NULL;
+       wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
 
-       /* Lets assume each sid is around 54 characters
-        * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
-       buflen = 54 * num_sids;
-       extra_data = talloc_array(NULL, char, buflen);
+       /* 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;
-               BAIL_ON_WBC_ERROR(wbc_status);
+               goto done;
        }
 
        /* Build the sid list */
        for (i=0; i<num_sids; i++) {
-               if (sid_string) {
-                       wbcFreeMemory(sid_string);
-                       sid_string = NULL;
-               }
-               wbc_status = wbcSidToString(&sids[i], &sid_string);
-               BAIL_ON_WBC_ERROR(wbc_status);
+               char sid_str[WBC_SID_STRING_BUFLEN];
+               size_t sid_len;
 
-               sid_len = strlen(sid_string);
+               sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
 
                if (buflen < extra_data_len + sid_len + 2) {
                        buflen *= 2;
-                       extra_data = talloc_realloc(NULL, extra_data,
-                           char, buflen);
+                       extra_data = (char *)realloc(extra_data, buflen);
                        if (!extra_data) {
                                wbc_status = WBC_ERR_NO_MEMORY;
                                BAIL_ON_WBC_ERROR(wbc_status);
                        }
                }
 
-               strncpy(&extra_data[extra_data_len], sid_string,
+               strncpy(&extra_data[extra_data_len], sid_str,
                        buflen - extra_data_len);
                extra_data_len += sid_len;
                extra_data[extra_data_len++] = '\n';
                extra_data[extra_data_len] = '\0';
        }
+       extra_data_len += 1;
 
        request.extra_data.data = extra_data;
        request.extra_len = extra_data_len;
 
-       wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
                                        &request,
                                        &response);
        BAIL_ON_WBC_ERROR(wbc_status);
@@ -592,12 +807,12 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
        if (response.data.num_entries &&
            !response.extra_data.data) {
                wbc_status = WBC_ERR_INVALID_RESPONSE;
-               BAIL_ON_WBC_ERROR(wbc_status);
+               goto done;
        }
 
-       rids = talloc_array(NULL, uint32_t,
-                           response.data.num_entries);
-       BAIL_ON_PTR_ERROR(sids, wbc_status);
+       rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
+                                            sizeof(uint32_t), NULL);
+       BAIL_ON_PTR_ERROR(rids, wbc_status);
 
        s = (const char *)response.extra_data.data;
        for (i = 0; i < response.data.num_entries; i++) {
@@ -618,27 +833,28 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       if (sid_string) {
-               wbcFreeMemory(sid_string);
-       }
-       if (extra_data) {
-               talloc_free(extra_data);
-       }
-       if (response.extra_data.data) {
-               free(response.extra_data.data);
-       }
-       if (rids) {
-               talloc_free(rids);
-       }
-
+       free(extra_data);
+       winbindd_free_response(&response);
+       wbcFreeMemory(rids);
        return wbc_status;
 }
 
+wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
+                       struct wbcDomainSid *sids,
+                       uint32_t num_sids,
+                       uint32_t **alias_rids,
+                       uint32_t *num_alias_rids)
+{
+       return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
+                                  alias_rids, num_alias_rids);
+}
+
 
 /* Lists Users */
-wbcErr wbcListUsers(const char *domain_name,
-                   uint32_t *_num_users,
-                   const char ***_users)
+wbcErr wbcCtxListUsers(struct wbcContext *ctx,
+                      const char *domain_name,
+                      uint32_t *_num_users,
+                      const char ***_users)
 {
        wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
        struct winbindd_request request;
@@ -657,18 +873,31 @@ wbcErr wbcListUsers(const char *domain_name,
                        sizeof(request.domain_name)-1);
        }
 
-       wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
                                        &request,
                                        &response);
        BAIL_ON_WBC_ERROR(wbc_status);
 
+       users = wbcAllocateStringArray(response.data.num_entries);
+       if (users == NULL) {
+               return WBC_ERR_NO_MEMORY;
+       }
+
        /* Look through extra data */
 
        next = (const char *)response.extra_data.data;
        while (next) {
-               const char **tmp;
-               const char *current = next;
-               char *k = strchr(next, ',');
+               const char *current;
+               char *k;
+
+               if (num_users >= 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;
@@ -676,37 +905,38 @@ wbcErr wbcListUsers(const char *domain_name,
                        next = NULL;
                }
 
-               tmp = talloc_realloc(NULL, users,
-                                    const char *,
-                                    num_users+1);
-               BAIL_ON_PTR_ERROR(tmp, wbc_status);
-               users = tmp;
-
-               users[num_users] = talloc_strdup(users, current);
+               users[num_users] = strdup(current);
                BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
-
-               num_users++;
+               num_users += 1;
+       }
+       if (num_users != response.data.num_entries) {
+               wbc_status = WBC_ERR_INVALID_RESPONSE;
+               goto done;
        }
 
-       *_num_users = num_users;
+       *_num_users = response.data.num_entries;
        *_users = users;
        users = NULL;
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       if (response.extra_data.data) {
-               free(response.extra_data.data);
-       }
-       if (users) {
-               talloc_free(users);
-       }
+       winbindd_free_response(&response);
+       wbcFreeMemory(users);
        return wbc_status;
 }
 
+wbcErr wbcListUsers(const char *domain_name,
+                   uint32_t *_num_users,
+                   const char ***_users)
+{
+       return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
+}
+
 /* Lists Groups */
-wbcErr wbcListGroups(const char *domain_name,
-                    uint32_t *_num_groups,
-                    const char ***_groups)
+wbcErr wbcCtxListGroups(struct wbcContext *ctx,
+                       const char *domain_name,
+                       uint32_t *_num_groups,
+                       const char ***_groups)
 {
        wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
        struct winbindd_request request;
@@ -725,18 +955,31 @@ wbcErr wbcListGroups(const char *domain_name,
                        sizeof(request.domain_name)-1);
        }
 
-       wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
+       wbc_status = wbcRequestResponse(ctx, 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 **tmp;
-               const char *current = next;
-               char *k = strchr(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;
@@ -744,59 +987,61 @@ wbcErr wbcListGroups(const char *domain_name,
                        next = NULL;
                }
 
-               tmp = talloc_realloc(NULL, groups,
-                                    const char *,
-                                    num_groups+1);
-               BAIL_ON_PTR_ERROR(tmp, wbc_status);
-               groups = tmp;
-
-               groups[num_groups] = talloc_strdup(groups, current);
+               groups[num_groups] = strdup(current);
                BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
-
-               num_groups++;
+               num_groups += 1;
+       }
+       if (num_groups != response.data.num_entries) {
+               wbc_status = WBC_ERR_INVALID_RESPONSE;
+               goto done;
        }
 
-       *_num_groups = num_groups;
+       *_num_groups = response.data.num_entries;
        *_groups = groups;
        groups = NULL;
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       if (response.extra_data.data) {
-               free(response.extra_data.data);
-       }
-       if (groups) {
-               talloc_free(groups);
-       }
+       winbindd_free_response(&response);
+       wbcFreeMemory(groups);
        return wbc_status;
 }
 
-wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
-                        char **pdomain,
-                        char **pfullname,
-                        enum wbcSidType *pname_type)
+wbcErr wbcListGroups(const char *domain_name,
+                    uint32_t *_num_groups,
+                    const char ***_groups)
+{
+       return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
+}
+
+wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
+                           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);
+       wbc_status = wbcCtxLookupSid(ctx, 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);
+               wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
                BAIL_ON_WBC_ERROR(wbc_status);
 
-               wbc_status = wbcGetpwuid(uid, &pwd);
+               wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
                BAIL_ON_WBC_ERROR(wbc_status);
 
                wbcFreeMemory(name);
 
-               name = talloc_strdup(NULL, pwd->pw_gecos);
+               name = wbcStrDup(pwd->pw_gecos);
+               wbcFreeMemory(pwd);
                BAIL_ON_PTR_ERROR(name, wbc_status);
        }
 
@@ -815,6 +1060,14 @@ wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
        return wbc_status;
 }
 
+wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
+                        char **pdomain,
+                        char **pfullname,
+                        enum wbcSidType *pname_type)
+{
+       return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
+}
+
 const char* wbcSidTypeString(enum wbcSidType type)
 {
        switch (type) {
@@ -828,6 +1081,7 @@ const char* wbcSidTypeString(enum wbcSidType type)
        case WBC_SID_NAME_INVALID:  return "SID_INVALID";
        case WBC_SID_NAME_UNKNOWN:  return "SID_UNKNOWN";
        case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
+       case WBC_SID_NAME_LABEL:    return "SID_LABEL";
        default:                    return "Unknown type";
        }
 }