libwbclient: Fix a few resource leak CIDs
[nivanova/samba-autobuild/.git] / nsswitch / libwbclient / wbc_sid.c
index a2ed5e1d3f3a1455562e0feec7ea5bf3771ce6be..cc71b9e865c9eac21bba0aa5b607a4fd930e0416 100644 (file)
 #include "libwbclient.h"
 #include "../winbind_client.h"
 
+/* 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)
+{
+       uint64_t id_auth;
+       int i, ofs;
+
+       if (!sid) {
+               strlcpy(buf, "(NULL SID)", buflen);
+               return 10;      /* strlen("(NULL SID)") */
+       }
+
+       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);
+       }
+
+       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;
+}
+
 /* Convert a binary SID to a character string */
 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
                      char **sid_string)
 {
-       uint32_t id_auth;
-       int i, ofs, maxlen;
+       char buf[WBC_SID_STRING_BUFLEN];
        char *result;
+       int len;
 
        if (!sid) {
                return WBC_ERR_INVALID_SID;
        }
 
-       maxlen = sid->num_auths * 11 + 25;
+       len = wbcSidToStringBuf(sid, buf, sizeof(buf));
 
-       result = (char *)wbcAllocateMemory(maxlen, 1, NULL);
-       if (result == NULL) {
-               return WBC_ERR_NO_MEMORY;
+       if (len+1 > sizeof(buf)) {
+               return WBC_ERR_INVALID_SID;
        }
 
-       /*
-        * BIG NOTE: this function only does SIDS where the identauth is not
-        * >= ^32 in a range of 2^48.
-        */
-
-       id_auth = sid->id_auth[5] +
-               (sid->id_auth[4] << 8) +
-               (sid->id_auth[3] << 16) +
-               (sid->id_auth[2] << 24);
-
-       ofs = snprintf(result, maxlen, "S-%u-%lu",
-                      (unsigned int)sid->sid_rev_num, (unsigned long)id_auth);
-
-       for (i = 0; i < sid->num_auths; i++) {
-               ofs += snprintf(result + ofs, maxlen - ofs, "-%lu",
-                               (unsigned long)sid->sub_auths[i]);
+       result = (char *)wbcAllocateMemory(len+1, 1, NULL);
+       if (result == NULL) {
+               return WBC_ERR_NO_MEMORY;
        }
+       memcpy(result, buf, len+1);
 
        *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) {
@@ -95,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;
        }
 
@@ -153,10 +180,11 @@ 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;
@@ -179,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);
@@ -195,17 +223,25 @@ 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 wbcLookupSid(const struct wbcDomainSid *sid,
-                   char **pdomain,
-                   char **pname,
-                   enum wbcSidType *pname_type)
+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 *sid_string = NULL;
        char *domain, *name;
 
        if (!sid) {
@@ -217,19 +253,12 @@ wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
        ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       /* dst is already null terminated from the memset above */
-
-       wbc_status = wbcSidToString(sid, &sid_string);
-       if (!WBC_ERROR_IS_OK(wbc_status)) {
-               return wbc_status;
-       }
-
-       strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
-       wbcFreeMemory(sid_string);
+       wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
 
        /* Make request */
 
-       wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSID,
+                                       &request,
                                        &response);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                return wbc_status;
@@ -267,9 +296,216 @@ done:
        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;
+       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<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);
+
+       request.extra_data.data = sidlist;
+       request.extra_len = p - sidlist;
+
+       wbc_status = wbcRequestResponse(ctx, 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; i++) {
+
+               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;
+
+               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;
+       }
+
+       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 (names[i].domain_index >= 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;
+}
+
+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,
@@ -281,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;
@@ -297,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,7 +555,7 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
        request.extra_data.data = ridlist;
        request.extra_len = len;
 
-       wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
+       wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
                                        &request,
                                        &response);
        free(ridlist);
@@ -347,21 +578,21 @@ 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';
@@ -374,7 +605,7 @@ 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;
@@ -396,17 +627,28 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
        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;
@@ -421,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;
@@ -433,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);
@@ -444,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;
@@ -467,12 +706,21 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
  done:
        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)
 {
@@ -485,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;
@@ -511,45 +758,37 @@ 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++) {
-               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';
@@ -560,7 +799,7 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
        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);
@@ -568,11 +807,11 @@ 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);
+       rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
+                                            sizeof(uint32_t), NULL);
        BAIL_ON_PTR_ERROR(sids, wbc_status);
 
        s = (const char *)response.extra_data.data;
@@ -594,18 +833,28 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
        wbc_status = WBC_ERR_SUCCESS;
 
  done:
-       wbcFreeMemory(sid_string);
-       talloc_free(extra_data);
+       free(extra_data);
        winbindd_free_response(&response);
-       talloc_free(rids);
+       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;
@@ -624,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;
@@ -643,35 +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:
        winbindd_free_response(&response);
-       if (users) {
-               talloc_free(users);
-       }
+       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;
@@ -690,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;
@@ -709,59 +987,62 @@ 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:
        winbindd_free_response(&response);
-       if (groups) {
-               talloc_free(groups);
-       }
+       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);
-               BAIL_ON_PTR_ERROR(name, wbc_status);
+               name = wbcStrDup(pwd->pw_gecos);
                wbcFreeMemory(pwd);
+               BAIL_ON_PTR_ERROR(name, wbc_status);
        }
 
        wbc_status = WBC_ERR_SUCCESS;
@@ -779,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) {