r22675: Simo's patch for 0 size allocation. Still need
[sfrench/samba-autobuild/.git] / source / nsswitch / winbindd_async.c
index 93dea6f48cb8b19baf9272d6a85aab0e85ec3766..393479c63d3ec3fd0a5943a8220703b509ea281e 100644 (file)
@@ -256,7 +256,7 @@ void winbindd_sids2xids_async(TALLOC_CTX *mem_ctx, void *sids, int size,
        struct winbindd_request request;
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_DUAL_SIDS2XIDS;
-       request.extra_data.data = sids;
+       request.extra_data.data = (char *)sids;
        request.extra_len = size;
        do_async(mem_ctx, idmap_child(), &request, winbindd_sids2xids_recv,
                 (void *)cont, private_data);
@@ -273,16 +273,21 @@ enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
 
        DEBUG(3, ("[%5lu]: sids to unix ids\n", (unsigned long)state->pid));
 
+       if (state->request.extra_len == 0) {
+               DEBUG(0, ("Invalid buffer size!\n"));
+               return WINBINDD_ERROR;
+       }
+
        sids = (DOM_SID *)state->request.extra_data.data;
        num = state->request.extra_len / sizeof(DOM_SID);
 
-       ids = talloc_zero_array(state->mem_ctx, struct id_map *, num + 1);
+       ids = TALLOC_ZERO_ARRAY(state->mem_ctx, struct id_map *, num + 1);
        if ( ! ids) {
                DEBUG(0, ("Out of memory!\n"));
                return WINBINDD_ERROR;
        }
        for (i = 0; i < num; i++) {
-               ids[i] = talloc(ids, struct id_map);
+               ids[i] = TALLOC_P(ids, struct id_map);
                if ( ! ids[i]) {
                        DEBUG(0, ("Out of memory!\n"));
                        talloc_free(ids);
@@ -303,7 +308,7 @@ enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
                }
                
                for (i = 0; i < num; i++) {
-                       if (ids[i]->mapped) {
+                       if (ids[i]->status == ID_MAPPED) {
                                xids[i].type = ids[i]->xid.type;
                                xids[i].id = ids[i]->xid.id;
                        } else {
@@ -535,7 +540,7 @@ void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
        request.cmd = WINBINDD_DUAL_SID2GID;
        sid_to_string(request.data.dual_sid2id.sid, sid);
 
-       DEBUG(7,("idmap_sid2gid_async: Resolving %s to a gid\n", 
+       DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n", 
                request.data.dual_sid2id.sid));
 
        do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
@@ -772,7 +777,11 @@ enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
        return WINBINDD_OK;
 }
 
-static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
+/********************************************************************
+ This is the second callback after contacting the forest root
+********************************************************************/
+
+static void lookupname_recv2(TALLOC_CTX *mem_ctx, BOOL success,
                            struct winbindd_response *response,
                            void *c, void *private_data)
 {
@@ -804,8 +813,71 @@ static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
             (enum lsa_SidType)response->data.sid.type);
 }
 
-void winbindd_lookupname_async(TALLOC_CTX *mem_ctx, const char *dom_name,
-                              const char *name,
+/********************************************************************
+ This is the first callback after contacting our own domain 
+********************************************************************/
+
+static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
+                           struct winbindd_response *response,
+                           void *c, void *private_data)
+{
+       void (*cont)(void *priv, BOOL succ, const DOM_SID *sid,
+                    enum lsa_SidType type) =
+               (void (*)(void *, BOOL, const DOM_SID *, enum lsa_SidType))c;
+       DOM_SID sid;
+
+       if (!success) {
+               DEBUG(5, ("lookupname_recv: lookup_name() failed!\n"));
+               cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       if (response->result != WINBINDD_OK) {
+               /* Try again using the forest root */
+               struct winbindd_domain *root_domain = find_root_domain();
+               struct winbindd_cli_state *state = (struct winbindd_cli_state*)private_data;            
+               struct winbindd_request request;                
+               char *name_domain, *name_account;
+               
+               if ( !root_domain ) {
+                       DEBUG(5,("lookupname_recv: unable to determine forest root\n"));
+                       cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+                       return;
+               }
+
+               name_domain  = state->request.data.name.dom_name;
+               name_account = state->request.data.name.name;   
+
+               ZERO_STRUCT(request);
+               request.cmd = WINBINDD_LOOKUPNAME;
+               fstrcpy(request.data.name.dom_name, name_domain);
+               fstrcpy(request.data.name.name, name_account);
+
+               do_async_domain(mem_ctx, root_domain, &request, lookupname_recv2,
+                               (void *)cont, private_data);
+
+               return;
+       }
+
+       if (!string_to_sid(&sid, response->data.sid.sid)) {
+               DEBUG(0, ("Could not convert string %s to sid\n",
+                         response->data.sid.sid));
+               cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
+       cont(private_data, True, &sid,
+            (enum lsa_SidType)response->data.sid.type);
+}
+
+/********************************************************************
+ The lookup name call first contacts a DC in its own domain
+ and fallbacks to contact a DC in the forest in our domain doesn't
+ know the name.
+********************************************************************/
+
+void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
+                              const char *dom_name, const char *name,
                               void (*cont)(void *private_data, BOOL success,
                                            const DOM_SID *sid,
                                            enum lsa_SidType type),
@@ -814,9 +886,7 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx, const char *dom_name,
        struct winbindd_request request;
        struct winbindd_domain *domain;
 
-       domain = find_lookup_domain_from_name(dom_name);
-
-       if (domain == NULL) {
+       if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
                DEBUG(5, ("Could not find domain for name %s\n", dom_name));
                cont(private_data, False, NULL, SID_NAME_UNKNOWN);
                return;
@@ -840,10 +910,10 @@ enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
        char *p;
 
        /* Ensure null termination */
-       state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
+       state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
 
        /* Ensure null termination */
-       state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0';
+       state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
 
        /* cope with the name being a fully qualified name */
        p = strstr(state->request.data.name.name, lp_winbind_separator());
@@ -859,7 +929,7 @@ enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
        DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
                  name_domain, lp_winbind_separator(), name_user));
 
-       /* Lookup name from PDC using lsa_lookup_names() */
+       /* Lookup name from DC using lsa_lookup_names() */
        if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, name_domain,
                                         name_user, &sid, &type)) {
                return WINBINDD_ERROR;
@@ -1084,7 +1154,7 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
 {
        DOM_SID *sids = NULL;
        size_t num_sids = 0;
-       char *sidstr;
+       char *sidstr = NULL;
        ssize_t len;
        size_t i;
        uint32 num_aliases;
@@ -1094,8 +1164,13 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
        DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
 
        sidstr = state->request.extra_data.data;
-       if (sidstr == NULL)
+       if (sidstr == NULL) {
                sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
+               if (!sidstr) {
+                       DEBUG(0, ("Out of memory\n"));
+                       return WINBINDD_ERROR;
+               }
+       }
 
        DEBUG(10, ("Sidlist: %s\n", sidstr));
 
@@ -1121,6 +1196,7 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
 
        num_sids = 0;
        sids = NULL;
+       sidstr = NULL;
 
        DEBUG(10, ("Got %d aliases\n", num_aliases));
 
@@ -1135,15 +1211,20 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
        }
 
 
-       if (!print_sidlist(NULL, sids, num_sids, &sidstr, &len)) {
+       if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
                DEBUG(0, ("Could not print_sidlist\n"));
                state->response.extra_data.data = NULL;
                return WINBINDD_ERROR;
        }
 
-       state->response.extra_data.data = sidstr;
+       state->response.extra_data.data = NULL;
 
-       if (state->response.extra_data.data != NULL) {
+       if (sidstr) {
+               state->response.extra_data.data = SMB_STRDUP(sidstr);
+               if (!state->response.extra_data.data) {
+                       DEBUG(0, ("Out of memory\n"));
+                       return WINBINDD_ERROR;
+               }
                DEBUG(10, ("aliases_list: %s\n",
                           (char *)state->response.extra_data.data));
                state->response.length += len+1;
@@ -1321,13 +1402,13 @@ static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
 {
        void (*cont)(void *priv, BOOL succ, const char *acct_name,
                     const char *full_name, const char *homedir, 
-                    const char *shell, uint32 group_rid) =
+                    const char *shell, uint32 gid, uint32 group_rid) =
                (void (*)(void *, BOOL, const char *, const char *,
-                         const char *, const char *, uint32))c;
+                         const char *, const char *, uint32, uint32))c;
 
        if (!success) {
                DEBUG(5, ("Could not trigger query_user\n"));
-               cont(private_data, False, NULL, NULL, NULL, NULL, -1);
+               cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
                return;
        }
 
@@ -1335,6 +1416,7 @@ static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
             response->data.user_info.full_name,
             response->data.user_info.homedir,
             response->data.user_info.shell,
+            response->data.user_info.primary_gid,
             response->data.user_info.group_rid);
 }
 
@@ -1345,6 +1427,7 @@ void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                                   const char *full_name,
                                   const char *homedir,
                                   const char *shell,
+                                  gid_t gid,
                                   uint32 group_rid),
                      void *private_data)
 {
@@ -1505,7 +1588,7 @@ void winbindd_dump_maps_async(TALLOC_CTX *mem_ctx, void *data, int size,
        struct winbindd_request request;
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_DUAL_DUMP_MAPS;
-       request.extra_data.data = data;
+       request.extra_data.data = (char *)data;
        request.extra_len = size;
        do_async(mem_ctx, idmap_child(), &request, winbindd_dump_id_maps_recv,
                 (void *)cont, private_data);