Make WINBINDD_LIST_GROUPS handler asynchronous.
[samba.git] / source3 / winbindd / winbindd_async.c
index 611ca03001c692094eadb73452c67c0d72ecb8ba..635bc6b244f0aa0edb8f09d017a6af31dec42e22 100644 (file)
@@ -175,7 +175,7 @@ static void lookupsid_recv(TALLOC_CTX *mem_ctx, bool success,
 
                ZERO_STRUCT(request);
                request.cmd = WINBINDD_LOOKUPSID;
-               fstrcpy(request.data.sid, sid_string_static(&s->sid));
+               sid_to_fstring(request.data.sid, &s->sid);
 
                do_async_domain(mem_ctx, root_domain, &request, lookupsid_recv2,
                                (void *)cont, s);
@@ -202,14 +202,14 @@ void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
        domain = find_lookup_domain_from_sid(sid);
        if (domain == NULL) {
                DEBUG(5, ("Could not find domain for sid %s\n",
-                         sid_string_static(sid)));
+                         sid_string_dbg(sid)));
                cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
                return;
        }
 
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_LOOKUPSID;
-       fstrcpy(request.data.sid, sid_string_static(sid));
+       sid_to_fstring(request.data.sid, sid);
 
        if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupsid_state)) == NULL ) {
                DEBUG(0, ("winbindd_lookupsid_async: talloc failed\n"));
@@ -283,9 +283,8 @@ static void lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
                     enum lsa_SidType type) =
                (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
        DOM_SID sid;
-       struct lookupname_state *s = talloc_get_type_abort( private_data, 
+       struct lookupname_state *s = talloc_get_type_abort( private_data,
                                                            struct lookupname_state );
-       
 
        if (!success) {
                DEBUG(5, ("Could not trigger lookup_name\n"));
@@ -311,7 +310,7 @@ static void lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
 }
 
 /********************************************************************
- This is the first callback after contacting our own domain 
+ This is the first callback after contacting our own domain
 ********************************************************************/
 
 static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
@@ -322,7 +321,7 @@ static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
                     enum lsa_SidType type) =
                (void (*)(void *, bool, const DOM_SID *, enum lsa_SidType))c;
        DOM_SID sid;
-       struct lookupname_state *s = talloc_get_type_abort( private_data, 
+       struct lookupname_state *s = talloc_get_type_abort( private_data,
                                                            struct lookupname_state );  
 
        if (!success) {
@@ -334,8 +333,8 @@ static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
        if (response->result != WINBINDD_OK) {
                /* Try again using the forest root */
                struct winbindd_domain *root_domain = find_root_domain();
-               struct winbindd_request request;                
-               
+               struct winbindd_request request;
+
                if ( !root_domain ) {
                        DEBUG(5,("lookupname_recv: unable to determine forest root\n"));
                        cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
@@ -346,7 +345,7 @@ static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success,
                request.cmd = WINBINDD_LOOKUPNAME;
 
                fstrcpy( request.data.name.dom_name, s->dom_name );
-               fstrcpy( request.data.name.name, s->name );             
+               fstrcpy( request.data.name.name, s->name );
 
                do_async_domain(mem_ctx, root_domain, &request, lookupname_recv2,
                                (void *)cont, s);
@@ -381,10 +380,10 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
 {
        struct winbindd_request request;
        struct winbindd_domain *domain;
-       struct lookupname_state *s;     
+       struct lookupname_state *s;
 
        if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
-               DEBUG(5, ("Could not find domain for name %s\n", dom_name));
+               DEBUG(5, ("Could not find domain for name '%s'\n", dom_name));
                cont(private_data, False, NULL, SID_NAME_UNKNOWN);
                return;
        }
@@ -403,6 +402,11 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
 
        s->dom_name = talloc_strdup( s, dom_name );
        s->name     = talloc_strdup( s, name );
+       if (!s->dom_name || !s->name) {
+               cont(private_data, False, NULL, SID_NAME_UNKNOWN);
+               return;
+       }
+
        s->caller_private_data = private_data;
 
        do_async_domain(mem_ctx, domain, &request, lookupname_recv,
@@ -443,12 +447,103 @@ enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
                return WINBINDD_ERROR;
        }
 
-       sid_to_string(state->response.data.sid.sid, &sid);
+       sid_to_fstring(state->response.data.sid.sid, &sid);
        state->response.data.sid.type = type;
 
        return WINBINDD_OK;
 }
 
+/* This is the first callback after enumerating groups from a domain */
+static void listgroups_recv(TALLOC_CTX *mem_ctx, bool success,
+                           struct winbindd_response *response,
+                           void *c, void *private_data)
+{
+       void (*cont)(void *priv, bool succ, fstring dom_name, char *data) =
+               (void (*)(void *, bool, fstring, char*))c;
+
+       if (!success || response->result != WINBINDD_OK) {
+               DEBUG(5, ("list_groups() failed!\n"));
+               cont(private_data, False, response->data.name.dom_name, NULL);
+               return;
+       }
+
+       cont(private_data, True, response->data.name.dom_name,
+            response->extra_data.data);
+
+       SAFE_FREE(response->extra_data.data);
+}
+
+/* Request the name of all groups in a single domain */
+void winbindd_listgroups_async(TALLOC_CTX *mem_ctx,
+                              struct winbindd_domain *domain,
+                              void (*cont)(void *private_data, bool success,
+                                    fstring dom_name, char* extra_data),
+                              void *private_data)
+{
+       struct winbindd_request request;
+
+       ZERO_STRUCT(request);
+       request.cmd = WINBINDD_LIST_GROUPS;
+
+       do_async_domain(mem_ctx, domain, &request, listgroups_recv,
+                       (void *)cont, private_data);
+}
+
+enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain,
+                                               struct winbindd_cli_state *state)
+{
+       struct getent_state groups = {};
+       char *extra_data = NULL;
+       unsigned int extra_data_len = 0, i;
+
+       /* Must copy domain into response first for bookeeping in parent */
+       fstrcpy(state->response.data.name.dom_name, domain->name);
+       fstrcpy(groups.domain_name, domain->name);
+
+       /* Get list of sam groups */
+       if (!get_sam_group_entries(&groups)) {
+               /* this domain is empty or in an error state */
+               return WINBINDD_ERROR;
+       }
+
+       /* Allocate some memory for extra data.  Note that we limit
+          account names to sizeof(fstring) = 256 characters.
+          +1 for the ',' between group names */
+       extra_data = (char *)SMB_REALLOC(extra_data,
+               (sizeof(fstring) + 1) * groups.num_sam_entries);
+
+       if (!extra_data) {
+               DEBUG(0,("failed to enlarge buffer!\n"));
+               SAFE_FREE(groups.sam_entries);
+               return WINBINDD_ERROR;
+       }
+
+       /* Pack group list into extra data fields */
+       for (i = 0; i < groups.num_sam_entries; i++) {
+               char *group_name = ((struct acct_info *)
+                                   groups.sam_entries)[i].acct_name;
+               fstring name;
+
+               fill_domain_username(name, domain->name, group_name, True);
+               /* Append to extra data */
+               memcpy(&extra_data[extra_data_len], name, strlen(name));
+               extra_data_len += strlen(name);
+               extra_data[extra_data_len++] = ',';
+       }
+
+       SAFE_FREE(groups.sam_entries);
+
+       /* Assign extra_data fields in response structure */
+       if (extra_data) {
+               /* remove trailing ',' */
+               extra_data[extra_data_len - 1] = '\0';
+               state->response.extra_data.data = extra_data;
+               state->response.length += extra_data_len;
+       }
+
+       return WINBINDD_OK;
+}
+
 bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
                   size_t num_sids, char **result, ssize_t *len)
 {
@@ -458,8 +553,9 @@ bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
        *len = 0;
        *result = NULL;
        for (i=0; i<num_sids; i++) {
+               fstring tmp;
                sprintf_append(mem_ctx, result, len, &buflen,
-                              "%s\n", sid_string_static(&sids[i]));
+                              "%s\n", sid_to_fstring(tmp, &sids[i]));
        }
 
        if ((num_sids != 0) && (*result == NULL)) {
@@ -491,7 +587,9 @@ static bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
                        DEBUG(0, ("Could not parse sid %s\n", p));
                        return False;
                }
-               if (!add_sid_to_array(mem_ctx, &sid, sids, num_sids)) {
+               if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
+                                                     num_sids)))
+               {
                        return False;
                }
                p = q;
@@ -713,7 +811,9 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
                DEBUGADD(10, (" rid %d\n", alias_rids[i]));
                sid_copy(&sid, &domain->sid);
                sid_append_rid(&sid, alias_rids[i]);
-               if (!add_sid_to_array(state->mem_ctx, &sid, &sids, &num_sids)) {
+               result = add_sid_to_array(state->mem_ctx, &sid, &sids,
+                                         &num_sids);
+               if (!NT_STATUS_IS_OK(result)) {
                        return WINBINDD_ERROR;
                }
        }
@@ -788,14 +888,14 @@ void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
        domain = find_domain_from_sid_noinit(user_sid);
        if (domain == NULL) {
                DEBUG(5, ("Could not find domain from SID %s\n",
-                         sid_string_static(user_sid)));
+                         sid_string_dbg(user_sid)));
                cont(private_data, False, NULL, 0);
                return;
        }
 
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_GETUSERDOMGROUPS;
-       fstrcpy(request.data.sid, sid_string_static(user_sid));
+       sid_to_fstring(request.data.sid, user_sid);
 
        do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
                        NULL, state);
@@ -831,8 +931,9 @@ static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
        state->sids = NULL;
        state->num_sids = 0;
 
-       if (!add_sid_to_array(mem_ctx, &state->user_sid, &state->sids,
-                        &state->num_sids)) {
+       if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &state->user_sid,
+                                             &state->sids, &state->num_sids)))
+       {
                DEBUG(0, ("Out of memory\n"));
                state->cont(state->private_data, False, NULL, 0);
                return;
@@ -873,8 +974,11 @@ static void gettoken_recvaliases(void *private_data, bool success,
        }
 
        for (i=0; i<num_aliases; i++) {
-               if (!add_sid_to_array(state->mem_ctx, &aliases[i],
-                                &state->sids, &state->num_sids)) {
+               if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx,
+                                                     &aliases[i],
+                                                     &state->sids,
+                                                     &state->num_sids)))
+               {
                        DEBUG(0, ("Out of memory\n"));
                        state->cont(state->private_data, False, NULL, 0);
                        return;
@@ -948,7 +1052,7 @@ void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
        struct winbindd_request request;
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_DUAL_USERINFO;
-       sid_to_string(request.data.sid, sid);
+       sid_to_fstring(request.data.sid, sid);
        do_async_domain(mem_ctx, domain, &request, query_user_recv,
                        (void *)cont, private_data);
 }