lib: Remove timeval_set()
[samba.git] / source3 / winbindd / wb_getgrsid.c
1 /*
2    Unix SMB/CIFS implementation.
3    async getgrsid
4    Copyright (C) Volker Lendecke 2009
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "librpc/gen_ndr/ndr_winbind_c.h"
23 #include "../libcli/security/security.h"
24 #include "lib/dbwrap/dbwrap_rbt.h"
25 #include "lib/dbwrap/dbwrap.h"
26
27 struct wb_getgrsid_state {
28         struct tevent_context *ev;
29         struct dom_sid sid;
30         int max_nesting;
31         const char *domname;
32         const char *name;
33         enum lsa_SidType type;
34         gid_t gid;
35         struct db_context *members;
36         uint32_t num_sids;
37         struct dom_sid *sids;
38 };
39
40 static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq);
41 static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq);
42 static void wb_getgrsid_got_members(struct tevent_req *subreq);
43 static void wb_getgrsid_got_alias_members(struct tevent_req *subreq);
44
45 struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
46                                     struct tevent_context *ev,
47                                     const struct dom_sid *group_sid,
48                                     int max_nesting)
49 {
50         struct tevent_req *req, *subreq;
51         struct wb_getgrsid_state *state;
52         struct dom_sid_buf buf;
53
54         req = tevent_req_create(mem_ctx, &state, struct wb_getgrsid_state);
55         if (req == NULL) {
56                 return NULL;
57         }
58
59         D_INFO("WB command getgrsid start.\nLooking up group SID %s.\n", dom_sid_str_buf(group_sid, &buf));
60
61         sid_copy(&state->sid, group_sid);
62         state->ev = ev;
63         state->max_nesting = max_nesting;
64
65         if (dom_sid_in_domain(&global_sid_Unix_Groups, group_sid)) {
66                 /* unmapped Unix groups must be resolved locally */
67                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
68                 return tevent_req_post(req, ev);
69         }
70
71         subreq = wb_lookupsid_send(state, ev, &state->sid);
72         if (tevent_req_nomem(subreq, req)) {
73                 return tevent_req_post(req, ev);
74         }
75         tevent_req_set_callback(subreq, wb_getgrsid_lookupsid_done, req);
76         return req;
77 }
78
79 static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq)
80 {
81         struct tevent_req *req = tevent_req_callback_data(
82                 subreq, struct tevent_req);
83         struct wb_getgrsid_state *state = tevent_req_data(
84                 req, struct wb_getgrsid_state);
85         NTSTATUS status;
86
87         status = wb_lookupsid_recv(subreq, state, &state->type,
88                                    &state->domname, &state->name);
89         TALLOC_FREE(subreq);
90         if (tevent_req_nterror(req, status)) {
91                 return;
92         }
93
94         switch (state->type) {
95         case SID_NAME_DOM_GRP:
96         case SID_NAME_ALIAS:
97         case SID_NAME_WKN_GRP:
98         /*
99          * also treat user-type SIDS (they might map to ID_TYPE_BOTH)
100          */
101         case SID_NAME_USER:
102         case SID_NAME_COMPUTER:
103                 break;
104         default:
105                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
106                 return;
107         }
108
109         subreq = wb_sids2xids_send(state, state->ev, &state->sid, 1);
110         if (tevent_req_nomem(subreq, req)) {
111                 return;
112         }
113         tevent_req_set_callback(subreq, wb_getgrsid_sid2gid_done, req);
114 }
115
116 static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
117 {
118         struct tevent_req *req = tevent_req_callback_data(
119                 subreq, struct tevent_req);
120         struct wb_getgrsid_state *state = tevent_req_data(
121                 req, struct wb_getgrsid_state);
122         NTSTATUS status;
123         struct unixid xids[1];
124
125         status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
126         TALLOC_FREE(subreq);
127         if (tevent_req_nterror(req, status)) {
128                 return;
129         }
130
131         /*
132          * We are filtering further down in sids2xids, but that filtering
133          * depends on the actual type of the sid handed in (as determined
134          * by lookupsids). Here we need to filter for the type of object
135          * actually requested, in this case uid.
136          */
137         if (!(xids[0].type == ID_TYPE_GID || xids[0].type == ID_TYPE_BOTH)) {
138                 tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
139                 return;
140         }
141
142         state->gid = (gid_t)xids[0].id;
143
144         switch (state->type) {
145         case SID_NAME_USER:
146         case SID_NAME_COMPUTER: {
147                 /*
148                  * special treatment for a user sid that is
149                  * mapped to ID_TYPE_BOTH:
150                  * create a group with the sid/xid as only member
151                  */
152                 const char *name;
153
154                 if (xids[0].type != ID_TYPE_BOTH) {
155                         tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
156                         return;
157                 }
158
159                 state->members = db_open_rbt(state);
160                 if (tevent_req_nomem(state->members, req)) {
161                         return;
162                 }
163
164                 name = fill_domain_username_talloc(talloc_tos(),
165                                                    state->domname,
166                                                    state->name,
167                                                    true /* can_assume */);
168                 if (tevent_req_nomem(name, req)) {
169                         return;
170                 }
171
172                 status = add_member_to_db(state->members, &state->sid, name);
173                 if (!NT_STATUS_IS_OK(status)) {
174                         tevent_req_nterror(req, status);
175                         return;
176                 }
177
178                 tevent_req_done(req);
179                 return;
180         }
181         case SID_NAME_ALIAS:
182                 subreq = wb_alias_members_send(state,
183                                                state->ev,
184                                                &state->sid,
185                                                state->type,
186                                                state->max_nesting);
187                 if (tevent_req_nomem(subreq, req)) {
188                         return;
189                 }
190                 /* Decrement the depth based on 'winbind expand groups' */
191                 state->max_nesting--;
192                 tevent_req_set_callback(subreq,
193                                         wb_getgrsid_got_alias_members,
194                                         req);
195                 break;
196         case SID_NAME_DOM_GRP:
197                 subreq = wb_group_members_send(state,
198                                                state->ev,
199                                                &state->sid,
200                                                1,
201                                                &state->type,
202                                                state->max_nesting);
203                 if (tevent_req_nomem(subreq, req)) {
204                         return;
205                 }
206                 tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
207                 break;
208         case SID_NAME_WKN_GRP:
209                 state->members = db_open_rbt(state);
210                 if (tevent_req_nomem(state->members, req)) {
211                         return;
212                 }
213                 tevent_req_done(req);
214                 return;
215         default:
216                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
217                 break;
218         }
219 }
220
221 static void wb_getgrsid_got_alias_members_names(struct tevent_req *subreq)
222 {
223         struct tevent_req *req =
224                 tevent_req_callback_data(subreq, struct tevent_req);
225         struct wb_getgrsid_state *state =
226                 tevent_req_data(req, struct wb_getgrsid_state);
227         struct lsa_RefDomainList *domains = NULL;
228         struct lsa_TransNameArray *names = NULL;
229         NTSTATUS status;
230         uint32_t li;
231         uint32_t num_sids = 0;
232         struct dom_sid *sids = NULL;
233         enum lsa_SidType *types = NULL;
234
235         status = wb_lookupsids_recv(subreq, state, &domains, &names);
236
237         TALLOC_FREE(subreq);
238         if (tevent_req_nterror(req, status)) {
239                 D_WARNING("Failed with %s.\n", nt_errstr(status));
240                 return;
241         }
242
243         if (domains == NULL) {
244                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
245                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
246                 return;
247         }
248
249         if (names == NULL) {
250                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
251                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
252                 return;
253         }
254
255         state->members = db_open_rbt(state);
256         if (tevent_req_nomem(state->members, req)) {
257                 return;
258         }
259
260         for (li = 0; li < state->num_sids; li++) {
261                 struct lsa_TranslatedName *n = &names->names[li];
262
263                 if (n->sid_type == SID_NAME_USER ||
264                     n->sid_type == SID_NAME_COMPUTER) {
265                         const char *name = fill_domain_username_talloc(
266                                 talloc_tos(),
267                                 domains->domains[n->sid_index].name.string,
268                                 n->name.string,
269                                 false /* can_assume */);
270                         if (tevent_req_nomem(name, req)) {
271                                 return;
272                         }
273
274                         status = add_member_to_db(state->members,
275                                                   &state->sids[li],
276                                                   name);
277                         if (!NT_STATUS_IS_OK(status)) {
278                                 tevent_req_nterror(req, status);
279                                 return;
280                         }
281                 } else if (n->sid_type == SID_NAME_DOM_GRP) {
282                         sids = talloc_realloc(talloc_tos(),
283                                               sids,
284                                               struct dom_sid,
285                                               num_sids + 1);
286                         if (tevent_req_nomem(sids, req)) {
287                                 return;
288                         }
289                         sids[num_sids] = state->sids[li];
290                         types = talloc_realloc(talloc_tos(),
291                                                types,
292                                                enum lsa_SidType,
293                                                num_sids + 1);
294                         if (tevent_req_nomem(types, req)) {
295                                 return;
296                         }
297                         types[num_sids] = n->sid_type;
298                         num_sids++;
299                 } else {
300                         struct dom_sid_buf buf;
301                         D_DEBUG("SID %s with sid_type=%d is ignored!\n",
302                                 dom_sid_str_buf(&state->sids[li], &buf),
303                                 n->sid_type);
304                 }
305         }
306
307         TALLOC_FREE(names);
308         TALLOC_FREE(domains);
309
310         if (num_sids == 0) {
311                 tevent_req_done(req);
312                 return;
313         }
314         subreq = wb_group_members_send(state,
315                                        state->ev,
316                                        sids,
317                                        num_sids,
318                                        types,
319                                        state->max_nesting);
320         if (tevent_req_nomem(subreq, req)) {
321                 return;
322         }
323         tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
324 }
325
326 static void wb_getgrsid_got_alias_members(struct tevent_req *subreq)
327 {
328         struct tevent_req *req =
329                 tevent_req_callback_data(subreq, struct tevent_req);
330         struct wb_getgrsid_state *state =
331                 tevent_req_data(req, struct wb_getgrsid_state);
332         NTSTATUS status;
333
334         status = wb_alias_members_recv(subreq,
335                                        state,
336                                        &state->num_sids,
337                                        &state->sids);
338         TALLOC_FREE(subreq);
339         if (tevent_req_nterror(req, status)) {
340                 return;
341         }
342
343         subreq = wb_lookupsids_send(state,
344                                     state->ev,
345                                     state->sids,
346                                     state->num_sids);
347         if (tevent_req_nomem(subreq, req)) {
348                 return;
349         }
350         tevent_req_set_callback(subreq,
351                                 wb_getgrsid_got_alias_members_names,
352                                 req);
353 }
354
355 static void wb_getgrsid_got_members(struct tevent_req *subreq)
356 {
357         struct tevent_req *req = tevent_req_callback_data(
358                 subreq, struct tevent_req);
359         struct wb_getgrsid_state *state = tevent_req_data(
360                 req, struct wb_getgrsid_state);
361         NTSTATUS status;
362         struct db_context *members_prev = state->members;
363
364         status = wb_group_members_recv(subreq, state, &state->members);
365         TALLOC_FREE(subreq);
366         if (tevent_req_nterror(req, status)) {
367                 return;
368         }
369         /*
370          * If we have called wb_alias_members_send(), members_prev
371          * might already contain users that are direct members of alias,
372          * add to them the users from nested groups.
373          */
374         if (members_prev != NULL) {
375                 status = dbwrap_merge_dbs(state->members,
376                                           members_prev,
377                                           TDB_REPLACE);
378                 if (tevent_req_nterror(req, status)) {
379                         return;
380                 }
381         }
382         tevent_req_done(req);
383 }
384
385 NTSTATUS wb_getgrsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
386                           const char **domname, const char **name, gid_t *gid,
387                           struct db_context **members)
388 {
389         struct wb_getgrsid_state *state = tevent_req_data(
390                 req, struct wb_getgrsid_state);
391         NTSTATUS status;
392
393         D_INFO("WB command getgrsid end.\n");
394         if (tevent_req_is_nterror(req, &status)) {
395                 D_WARNING("Failed with %s.\n", nt_errstr(status));
396                 return status;
397         }
398         *domname = talloc_move(mem_ctx, &state->domname);
399         *name = talloc_move(mem_ctx, &state->name);
400         *gid = state->gid;
401         *members = talloc_move(mem_ctx, &state->members);
402         return NT_STATUS_OK;
403 }