ctdb-tool: Fix "ctdb -Y ifaces" output to have trailing delimiters
[Samba.git] / source3 / winbindd / winbindd_getgroups.c
blobb899bebe17035c191fb5d03bee8b27ebb4d7567f
1 /*
2 Unix SMB/CIFS implementation.
3 async implementation of WINBINDD_GETGROUPS
4 Copyright (C) Volker Lendecke 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
24 struct winbindd_getgroups_state {
25 struct tevent_context *ev;
26 fstring domname;
27 fstring username;
28 struct dom_sid sid;
29 enum lsa_SidType type;
30 int num_sids;
31 struct dom_sid *sids;
32 int num_gids;
33 gid_t *gids;
36 static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq);
37 static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq);
38 static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq);
40 struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
41 struct tevent_context *ev,
42 struct winbindd_cli_state *cli,
43 struct winbindd_request *request)
45 struct tevent_req *req, *subreq;
46 struct winbindd_getgroups_state *state;
47 char *domuser, *mapped_user;
48 NTSTATUS status;
50 req = tevent_req_create(mem_ctx, &state,
51 struct winbindd_getgroups_state);
52 if (req == NULL) {
53 return NULL;
55 state->ev = ev;
57 /* Ensure null termination */
58 request->data.username[sizeof(request->data.username)-1]='\0';
60 DEBUG(3, ("getgroups %s\n", request->data.username));
62 domuser = request->data.username;
64 status = normalize_name_unmap(state, domuser, &mapped_user);
66 if (NT_STATUS_IS_OK(status)
67 || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
68 /* normalize_name_unmapped did something */
69 domuser = mapped_user;
72 if (!parse_domain_user(domuser, state->domname, state->username)) {
73 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
74 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
75 return tevent_req_post(req, ev);
78 subreq = wb_lookupname_send(state, ev, state->domname, state->username,
79 LOOKUP_NAME_NO_NSS);
80 if (tevent_req_nomem(subreq, req)) {
81 return tevent_req_post(req, ev);
83 tevent_req_set_callback(subreq, winbindd_getgroups_lookupname_done,
84 req);
85 return req;
88 static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq)
90 struct tevent_req *req = tevent_req_callback_data(
91 subreq, struct tevent_req);
92 struct winbindd_getgroups_state *state = tevent_req_data(
93 req, struct winbindd_getgroups_state);
94 NTSTATUS status;
96 status = wb_lookupname_recv(subreq, &state->sid, &state->type);
97 TALLOC_FREE(subreq);
98 if (tevent_req_nterror(req, status)) {
99 return;
102 subreq = wb_gettoken_send(state, state->ev, &state->sid);
103 if (tevent_req_nomem(subreq, req)) {
104 return;
106 tevent_req_set_callback(subreq, winbindd_getgroups_gettoken_done, req);
109 static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq)
111 struct tevent_req *req = tevent_req_callback_data(
112 subreq, struct tevent_req);
113 struct winbindd_getgroups_state *state = tevent_req_data(
114 req, struct winbindd_getgroups_state);
115 NTSTATUS status;
117 status = wb_gettoken_recv(subreq, state, &state->num_sids,
118 &state->sids);
119 TALLOC_FREE(subreq);
120 if (tevent_req_nterror(req, status)) {
121 return;
125 * Convert the group SIDs to gids. state->sids[0] contains the user
126 * sid. If the idmap backend uses ID_TYPE_BOTH, we might need the
127 * the id of the user sid in the list of group sids, so map the
128 * complete token.
131 subreq = wb_sids2xids_send(state, state->ev,
132 state->sids, state->num_sids);
133 if (tevent_req_nomem(subreq, req)) {
134 return;
136 tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req);
139 static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq)
141 struct tevent_req *req = tevent_req_callback_data(
142 subreq, struct tevent_req);
143 struct winbindd_getgroups_state *state = tevent_req_data(
144 req, struct winbindd_getgroups_state);
145 NTSTATUS status;
146 struct unixid *xids;
147 int i;
149 xids = talloc_array(state, struct unixid, state->num_sids);
150 if (tevent_req_nomem(xids, req)) {
151 return;
153 for (i=0; i < state->num_sids; i++) {
154 xids[i].type = ID_TYPE_NOT_SPECIFIED;
155 xids[i].id = UINT32_MAX;
158 status = wb_sids2xids_recv(subreq, xids);
159 TALLOC_FREE(subreq);
160 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) ||
161 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
163 status = NT_STATUS_OK;
165 if (tevent_req_nterror(req, status)) {
166 return;
169 state->gids = talloc_array(state, gid_t, state->num_sids);
170 if (tevent_req_nomem(state->gids, req)) {
171 return;
173 state->num_gids = 0;
175 for (i=0; i < state->num_sids; i++) {
176 bool include_gid = false;
177 const char *debug_missing = NULL;
179 switch (xids[i].type) {
180 case ID_TYPE_NOT_SPECIFIED:
181 debug_missing = "not specified";
182 break;
183 case ID_TYPE_UID:
184 if (i != 0) {
185 debug_missing = "uid";
187 break;
188 case ID_TYPE_GID:
189 case ID_TYPE_BOTH:
190 include_gid = true;
191 break;
194 if (!include_gid) {
195 if (debug_missing == NULL) {
196 continue;
199 DEBUG(10, ("WARNING: skipping unix id (%u) for sid %s "
200 "from group list because the idmap type "
201 "is %s. "
202 "This might be a security problem when ACLs "
203 "contain DENY ACEs!\n",
204 (unsigned)xids[i].id,
205 sid_string_tos(&state->sids[i]),
206 debug_missing));
207 continue;
210 state->gids[state->num_gids] = (gid_t)xids[i].id;
211 state->num_gids += 1;
215 * This should not fail, as it does not do any reallocation,
216 * just updating the talloc size.
218 state->gids = talloc_realloc(state, state->gids, gid_t, state->num_gids);
219 if (tevent_req_nomem(state->gids, req)) {
220 return;
223 tevent_req_done(req);
226 NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
227 struct winbindd_response *response)
229 struct winbindd_getgroups_state *state = tevent_req_data(
230 req, struct winbindd_getgroups_state);
231 NTSTATUS status;
233 if (tevent_req_is_nterror(req, &status)) {
234 DEBUG(5, ("Could not convert sid %s: %s\n",
235 sid_string_dbg(&state->sid), nt_errstr(status)));
236 return status;
239 response->data.num_entries = state->num_gids;
241 if (state->num_gids > 0) {
242 response->extra_data.data = talloc_move(response,
243 &state->gids);
244 response->length += state->num_gids * sizeof(gid_t);
246 return NT_STATUS_OK;