s3:winbind: Convert WINBINDD_GETGROUPS to the new API
authorVolker Lendecke <vl@samba.org>
Tue, 4 Aug 2009 20:26:07 +0000 (16:26 -0400)
committerVolker Lendecke <vl@samba.org>
Wed, 5 Aug 2009 07:21:25 +0000 (03:21 -0400)
source3/Makefile.in
source3/winbindd/winbindd.c
source3/winbindd/winbindd_getgroups.c [new file with mode: 0644]
source3/winbindd/winbindd_group.c
source3/winbindd/winbindd_proto.h

index 92ff64fbda547bc8523bcdbf4c07ed68dd489845..650e2081c75c342a5a0357cfd06100ee126bfca9 100644 (file)
@@ -1174,6 +1174,7 @@ WINBINDD_OBJ1 = \
                winbindd/winbindd_getpwuid.o \
                winbindd/winbindd_getsidaliases.o \
                winbindd/winbindd_getuserdomgroups.o \
+               winbindd/winbindd_getgroups.o \
                auth/token_util.o \
                ../nsswitch/libwbclient/wb_reqtrans.o \
                smbd/connection.o
index 1a5e958d38f1558ff1482509126403e7a4edbf5b..348816b39cf2b9663f2a764a650176f2ad7f071c 100644 (file)
@@ -431,7 +431,6 @@ static struct winbindd_dispatch_table {
        { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" },
        { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" },
 
-       { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
        { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" },
 
        /* Group functions */
@@ -533,6 +532,8 @@ static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
          winbindd_getsidaliases_send, winbindd_getsidaliases_recv },
        { WINBINDD_GETUSERDOMGROUPS, "GETUSERDOMGROUPS",
          winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv },
+       { WINBINDD_GETGROUPS, "GETGROUPS",
+         winbindd_getgroups_send, winbindd_getgroups_recv },
 
        { 0, NULL, NULL, NULL }
 };
diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c
new file mode 100644 (file)
index 0000000..9e64656
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+   Unix SMB/CIFS implementation.
+   async implementation of WINBINDD_GETGROUPS
+   Copyright (C) Volker Lendecke 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+struct winbindd_getgroups_state {
+       struct tevent_context *ev;
+       fstring domname;
+       fstring username;
+       struct dom_sid sid;
+       enum lsa_SidType type;
+       int num_sids;
+       struct dom_sid *sids;
+       int next_sid;
+       int num_gids;
+       gid_t *gids;
+};
+
+static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq);
+static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq);
+static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq);
+
+struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct winbindd_request *request)
+{
+       struct tevent_req *req, *subreq;
+       struct winbindd_getgroups_state *state;
+       char *domuser, *mapped_user;
+       struct winbindd_domain *domain;
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct winbindd_getgroups_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+
+       /* Ensure null termination */
+       request->data.username[sizeof(request->data.username)-1]='\0';
+
+       DEBUG(3, ("getgroups %s\n", request->data.username));
+
+       domuser = request->data.username;
+
+       status = normalize_name_unmap(state, domuser, &mapped_user);
+
+       if (NT_STATUS_IS_OK(status)
+           || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
+               /* normalize_name_unmapped did something */
+               domuser = mapped_user;
+       }
+
+       if (!parse_domain_user(domuser, state->domname, state->username)) {
+               DEBUG(5, ("Could not parse domain user: %s\n", domuser));
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return tevent_req_post(req, ev);
+       }
+
+       domain = find_domain_from_name_noinit(state->domname);
+       if (domain == NULL) {
+               /* Retry with DNS name */
+               char *p = strchr(domuser, '@');
+               if (p != NULL) {
+                       domain = find_domain_from_name_noinit(p+1);
+               }
+       }
+       if (domain == NULL) {
+               DEBUG(7, ("could not find domain entry for domain %s\n",
+                         state->domname));
+               tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
+               return tevent_req_post(req, ev);
+       }
+
+       if (lp_winbind_trusted_domains_only() && domain->primary) {
+               DEBUG(7,("winbindd_getgroups: My domain -- "
+                        "rejecting getgroups() for %s\\%s.\n",
+                        state->domname, state->username));
+               tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = wb_lookupname_send(state, ev, state->domname, state->username,
+                                   LOOKUP_NAME_NO_NSS);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, winbindd_getgroups_lookupname_done,
+                               req);
+       return req;
+}
+
+static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct winbindd_getgroups_state *state = tevent_req_data(
+               req, struct winbindd_getgroups_state);
+       NTSTATUS status;
+
+       status = wb_lookupname_recv(subreq, &state->sid, &state->type);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       subreq = wb_gettoken_send(state, state->ev, &state->sid);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, winbindd_getgroups_gettoken_done, req);
+}
+
+static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct winbindd_getgroups_state *state = tevent_req_data(
+               req, struct winbindd_getgroups_state);
+       NTSTATUS status;
+
+       status = wb_gettoken_recv(subreq, state, &state->num_sids,
+                                 &state->sids);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       /*
+        * Convert the group SIDs to gids. state->sids[0] contains the user
+        * sid, so start at index 1.
+        */
+
+       state->gids = talloc_array(state, gid_t, state->num_sids-1);
+       if (tevent_req_nomem(state->gids, req)) {
+               return;
+       }
+       state->num_gids = 0;
+       state->next_sid = 1;
+
+       subreq = wb_sid2gid_send(state, state->ev,
+                                &state->sids[state->next_sid]);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req);
+}
+
+static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct winbindd_getgroups_state *state = tevent_req_data(
+               req, struct winbindd_getgroups_state);
+       NTSTATUS status;
+
+       status = wb_sid2gid_recv(subreq, &state->gids[state->num_gids]);
+       TALLOC_FREE(subreq);
+
+       /*
+        * In case of failure, just continue with the next gid
+        */
+       if (NT_STATUS_IS_OK(status)) {
+               state->num_gids += 1;
+       }
+       state->next_sid += 1;
+
+       if (state->next_sid >= state->num_sids) {
+               tevent_req_done(req);
+               return;
+       }
+
+       subreq = wb_sid2gid_send(state, state->ev,
+                                &state->sids[state->next_sid]);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req);
+}
+
+NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
+                                struct winbindd_response *response)
+{
+       struct winbindd_getgroups_state *state = tevent_req_data(
+               req, struct winbindd_getgroups_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               DEBUG(5, ("Could not convert sid %s: %s\n",
+                         sid_string_dbg(&state->sid), nt_errstr(status)));
+               return status;
+       }
+
+       response->data.num_entries = state->num_gids;
+
+       if (state->num_gids > 0) {
+               response->extra_data.data = talloc_move(response,
+                                                       &state->gids);
+               response->length += state->num_gids * sizeof(gid_t);
+       }
+       return NT_STATUS_OK;
+}
index 12067f553f9825aeab1a07f7e92d16aa9d5f67e6..c1a898d73b244462ffcfede4aac3f1d6e04dc084 100644 (file)
@@ -1559,178 +1559,6 @@ struct getgroups_state {
        size_t num_token_gids;
 };
 
-static void getgroups_usersid_recv(void *private_data, bool success,
-                                  const DOM_SID *sid, enum lsa_SidType type);
-static void getgroups_tokensids_recv(void *private_data, bool success,
-                                    DOM_SID *token_sids, size_t num_token_sids);
-static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid);
-
-void winbindd_getgroups(struct winbindd_cli_state *state)
-{
-       struct getgroups_state *s;
-       char *real_name = NULL;
-       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
-
-       /* Ensure null termination */
-       state->request->data.username
-               [sizeof(state->request->data.username)-1]='\0';
-
-       DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid,
-                 state->request->data.username));
-
-       /* Parse domain and username */
-
-       s = TALLOC_P(state->mem_ctx, struct getgroups_state);
-       if (s == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               request_error(state);
-               return;
-       }
-
-       s->state = state;
-
-       nt_status = normalize_name_unmap(state->mem_ctx,
-                                        state->request->data.username,
-                                        &real_name);
-
-       /* Reset the real_name pointer if we didn't do anything
-          productive in the above call */
-       if (!NT_STATUS_IS_OK(nt_status) &&
-           !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
-       {
-               real_name = state->request->data.username;
-       }
-
-       if (!parse_domain_user_talloc(state->mem_ctx, real_name,
-                                     &s->domname, &s->username)) {
-               DEBUG(5, ("Could not parse domain user: %s\n",
-                         real_name));
-
-               /* error out if we do not have nested group support */
-
-               if ( !lp_winbind_nested_groups() ) {
-                       request_error(state);
-                       return;
-               }
-
-               s->domname = talloc_strdup(state->mem_ctx,
-                                          get_global_sam_name());
-               s->username = talloc_strdup(state->mem_ctx,
-                                           state->request->data.username);
-       }
-
-       /* Get info for the domain (either by short domain name or
-          DNS name in the case of a UPN) */
-
-       s->domain = find_domain_from_name_noinit(s->domname);
-       if (!s->domain) {
-               char *p = strchr(s->username, '@');
-
-               if (p) {
-                       s->domain = find_domain_from_name_noinit(p+1);
-               }
-
-       }
-
-       if (s->domain == NULL) {
-               DEBUG(7, ("could not find domain entry for domain %s\n",
-                         s->domname));
-               request_error(state);
-               return;
-       }
-
-       if ( s->domain->primary && lp_winbind_trusted_domains_only()) {
-               DEBUG(7,("winbindd_getgroups: My domain -- rejecting "
-                        "getgroups() for %s\\%s.\n", s->domname,
-                        s->username));
-               request_error(state);
-               return;
-       }
-
-       /* Get rid and name type from name.  The following costs 1 packet */
-
-       winbindd_lookupname_async(state->mem_ctx,
-                                 s->domname, s->username,
-                                 getgroups_usersid_recv,
-                                 WINBINDD_GETGROUPS, s);
-}
-
-static void getgroups_usersid_recv(void *private_data, bool success,
-                                  const DOM_SID *sid, enum lsa_SidType type)
-{
-       struct getgroups_state *s =
-               (struct getgroups_state *)private_data;
-
-       if ((!success) ||
-           ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) {
-               request_error(s->state);
-               return;
-       }
-
-       sid_copy(&s->user_sid, sid);
-
-       winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid,
-                               getgroups_tokensids_recv, s);
-}
-
-static void getgroups_tokensids_recv(void *private_data, bool success,
-                                    DOM_SID *token_sids, size_t num_token_sids)
-{
-       struct getgroups_state *s =
-               (struct getgroups_state *)private_data;
-
-       /* We need at least the user sid and the primary group in the token,
-        * otherwise it's an error */
-
-       if ((!success) || (num_token_sids < 2)) {
-               request_error(s->state);
-               return;
-       }
-
-       s->token_sids = token_sids;
-       s->num_token_sids = num_token_sids;
-       s->i = 0;
-
-       s->token_gids = NULL;
-       s->num_token_gids = 0;
-
-       getgroups_sid2gid_recv(s, False, 0);
-}
-
-static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid)
-{
-       struct getgroups_state *s =
-               (struct getgroups_state *)private_data;
-
-       if (success) {
-               if (!add_gid_to_array_unique(s->state->mem_ctx, gid,
-                                       &s->token_gids,
-                                       &s->num_token_gids)) {
-                       return;
-               }
-       }
-
-       if (s->i < s->num_token_sids) {
-               const DOM_SID *sid = &s->token_sids[s->i];
-               s->i += 1;
-
-               if (sid_equal(sid, &s->user_sid)) {
-                       getgroups_sid2gid_recv(s, False, 0);
-                       return;
-               }
-
-               winbindd_sid2gid_async(s->state->mem_ctx, sid,
-                                      getgroups_sid2gid_recv, s);
-               return;
-       }
-
-       s->state->response->data.num_entries = s->num_token_gids;
-       if (s->num_token_gids) {
-               s->state->response->extra_data.data = s->token_gids;
-               s->state->response->length += s->num_token_gids * sizeof(gid_t);
-       }
-       request_ok(s->state);
-}
 
 /* Get user supplementary sids. This is equivalent to the
    winbindd_getgroups() function but it involves a SID->SIDs mapping
index df6df12dc38dfc397f7c3e8f56208cdcf053a380..a9a374a53288eeb2f4130cce6abe926b21e00231 100644 (file)
@@ -761,6 +761,11 @@ struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx,
                                    const struct dom_sid *sid);
 NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                          int *num_sids, struct dom_sid **sids);
+struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct winbindd_request *request);
+NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
+                                struct winbindd_response *response);