winbind: avoid using fstrcpy(dcname,...) in _dual_init_connection
[samba.git] / source3 / winbindd / wb_xids2sids.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * async xids2sids
4  * Copyright (C) Volker Lendecke 2015
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 "../libcli/security/security.h"
23 #include "idmap_cache.h"
24 #include "librpc/gen_ndr/ndr_winbind_c.h"
25 #include "librpc/gen_ndr/ndr_netlogon.h"
26 #include "passdb/lookup_sid.h"
27
28 struct wb_xids2sids_dom_map {
29         unsigned low_id;
30         unsigned high_id;
31         const char *name;
32         struct dom_sid sid;
33 };
34
35 /*
36  * Map idmap ranges to domain names, taken from smb.conf. This is
37  * stored in the parent winbind and used to assemble xid2sid calls
38  * into per-idmap-domain chunks.
39  */
40 static struct wb_xids2sids_dom_map *dom_maps;
41
42 static bool wb_xids2sids_add_dom(const char *domname,
43                                  void *private_data)
44 {
45         struct wb_xids2sids_dom_map *map = NULL;
46         size_t num_maps = talloc_array_length(dom_maps);
47         size_t i;
48         const char *range;
49         unsigned low_id, high_id;
50         int ret;
51
52         range = idmap_config_const_string(domname, "range", NULL);
53         if (range == NULL) {
54                 DBG_DEBUG("No range for domain %s found\n", domname);
55                 return false;
56         }
57
58         ret = sscanf(range, "%u - %u", &low_id, &high_id);
59         if (ret != 2) {
60                 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
61                           range, domname);
62                 return false;
63         }
64
65         if (low_id > high_id) {
66                 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
67                           low_id, high_id, domname);
68                 return false;
69         }
70
71         for (i=0; i<num_maps; i++) {
72                 if (strequal(domname, dom_maps[i].name)) {
73                         map = &dom_maps[i];
74                         break;
75                 }
76         }
77
78         if (map == NULL) {
79                 struct wb_xids2sids_dom_map *tmp;
80                 char *name;
81
82                 name = talloc_strdup(talloc_tos(), domname);
83                 if (name == NULL) {
84                         DBG_DEBUG("talloc failed\n");
85                         return false;
86                 }
87
88                 tmp = talloc_realloc(
89                         NULL, dom_maps, struct wb_xids2sids_dom_map,
90                         num_maps+1);
91                 if (tmp == NULL) {
92                         TALLOC_FREE(name);
93                         return false;
94                 }
95                 dom_maps = tmp;
96
97                 map = &dom_maps[num_maps];
98                 ZERO_STRUCTP(map);
99                 map->name = talloc_move(dom_maps, &name);
100         }
101
102         map->low_id = low_id;
103         map->high_id = high_id;
104
105         return false;
106 }
107
108 struct wb_xids2sids_init_dom_maps_state {
109         struct tevent_context *ev;
110         struct tevent_req *req;
111         size_t dom_idx;
112 };
113
114 static void wb_xids2sids_init_dom_maps_lookupname_next(
115         struct wb_xids2sids_init_dom_maps_state *state);
116
117 static void wb_xids2sids_init_dom_maps_lookupname_done(
118         struct tevent_req *subreq);
119
120 static struct tevent_req *wb_xids2sids_init_dom_maps_send(
121         TALLOC_CTX *mem_ctx, struct tevent_context *ev)
122 {
123         struct tevent_req *req = NULL;
124         struct wb_xids2sids_init_dom_maps_state *state = NULL;
125
126         req = tevent_req_create(mem_ctx, &state,
127                                 struct wb_xids2sids_init_dom_maps_state);
128         if (req == NULL) {
129                 return NULL;
130         }
131         *state = (struct wb_xids2sids_init_dom_maps_state) {
132                 .ev = ev,
133                 .req = req,
134                 .dom_idx = 0,
135         };
136
137         if (dom_maps != NULL) {
138                 tevent_req_done(req);
139                 return tevent_req_post(req, ev);
140         }
141         /*
142          * Put the passdb idmap domain first. We always need to try
143          * there first.
144          */
145
146         dom_maps = talloc_zero_array(NULL, struct wb_xids2sids_dom_map, 1);
147         if (tevent_req_nomem(dom_maps, req)) {
148                 return tevent_req_post(req, ev);
149         }
150         dom_maps[0].low_id = 0;
151         dom_maps[0].high_id = UINT_MAX;
152         dom_maps[0].name = talloc_strdup(dom_maps, get_global_sam_name());
153         if (tevent_req_nomem(dom_maps[0].name, req)) {
154                 TALLOC_FREE(dom_maps);
155                 return tevent_req_post(req, ev);
156         }
157
158         lp_scan_idmap_domains(wb_xids2sids_add_dom, NULL);
159
160         wb_xids2sids_init_dom_maps_lookupname_next(state);
161         if (!tevent_req_is_in_progress(req)) {
162                 tevent_req_post(req, ev);
163         }
164         return req;
165 }
166
167 static void wb_xids2sids_init_dom_maps_lookupname_next(
168         struct wb_xids2sids_init_dom_maps_state *state)
169 {
170         struct tevent_req *subreq = NULL;
171
172         if (state->dom_idx == talloc_array_length(dom_maps)) {
173                 tevent_req_done(state->req);
174                 return;
175         }
176
177         if (strequal(dom_maps[state->dom_idx].name, "*")) {
178                 state->dom_idx++;
179                 if (state->dom_idx == talloc_array_length(dom_maps)) {
180                         tevent_req_done(state->req);
181                         return;
182                 }
183         }
184
185         subreq = wb_lookupname_send(state,
186                                     state->ev,
187                                     dom_maps[state->dom_idx].name,
188                                     "",
189                                     LOOKUP_NAME_NO_NSS);
190         if (tevent_req_nomem(subreq, state->req)) {
191                 return;
192         }
193         tevent_req_set_callback(subreq,
194                                 wb_xids2sids_init_dom_maps_lookupname_done,
195                                 state->req);
196 }
197
198 static void wb_xids2sids_init_dom_maps_lookupname_done(
199         struct tevent_req *subreq)
200 {
201         struct tevent_req *req = tevent_req_callback_data(
202                 subreq, struct tevent_req);
203         struct wb_xids2sids_init_dom_maps_state *state = tevent_req_data(
204                 req, struct wb_xids2sids_init_dom_maps_state);
205         enum lsa_SidType type;
206         NTSTATUS status;
207
208         status = wb_lookupname_recv(subreq,
209                                     &dom_maps[state->dom_idx].sid,
210                                     &type);
211         TALLOC_FREE(subreq);
212         if (!NT_STATUS_IS_OK(status)) {
213                 DBG_WARNING("Lookup domain name '%s' failed '%s'\n",
214                             dom_maps[state->dom_idx].name,
215                             nt_errstr(status));
216
217                 state->dom_idx++;
218                 wb_xids2sids_init_dom_maps_lookupname_next(state);
219                 return;
220         }
221
222         if (type != SID_NAME_DOMAIN) {
223                 DBG_WARNING("SID %s for idmap domain name '%s' "
224                             "not a domain SID\n",
225                             sid_string_dbg(&dom_maps[state->dom_idx].sid),
226                             dom_maps[state->dom_idx].name);
227
228                 ZERO_STRUCT(dom_maps[state->dom_idx].sid);
229         }
230
231         state->dom_idx++;
232         wb_xids2sids_init_dom_maps_lookupname_next(state);
233
234         return;
235 }
236
237 static NTSTATUS wb_xids2sids_init_dom_maps_recv(struct tevent_req *req)
238 {
239         return tevent_req_simple_recv_ntstatus(req);
240 }
241
242 struct wb_xids2sids_dom_state {
243         struct tevent_context *ev;
244         struct unixid *all_xids;
245         size_t num_all_xids;
246         struct dom_sid *all_sids;
247         struct wb_xids2sids_dom_map *dom_map;
248         bool tried_dclookup;
249
250         size_t num_dom_xids;
251         struct unixid *dom_xids;
252         struct dom_sid *dom_sids;
253 };
254
255 static void wb_xids2sids_dom_done(struct tevent_req *subreq);
256 static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq);
257
258 static struct tevent_req *wb_xids2sids_dom_send(
259         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
260         struct wb_xids2sids_dom_map *dom_map,
261         struct unixid *xids, size_t num_xids, struct dom_sid *sids)
262 {
263         struct tevent_req *req, *subreq;
264         struct wb_xids2sids_dom_state *state;
265         struct winbindd_child *child;
266         size_t i;
267
268         req = tevent_req_create(mem_ctx, &state,
269                                 struct wb_xids2sids_dom_state);
270         if (req == NULL) {
271                 return NULL;
272         }
273         state->ev = ev;
274         state->all_xids = xids;
275         state->num_all_xids = num_xids;
276         state->all_sids = sids;
277         state->dom_map = dom_map;
278
279         state->dom_xids = talloc_array(state, struct unixid, num_xids);
280         if (tevent_req_nomem(state->dom_xids, req)) {
281                 return tevent_req_post(req, ev);
282         }
283         state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
284         if (tevent_req_nomem(state->dom_sids, req)) {
285                 return tevent_req_post(req, ev);
286         }
287
288         for (i=0; i<num_xids; i++) {
289                 struct unixid id = state->all_xids[i];
290
291                 if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
292                         /* out of range */
293                         continue;
294                 }
295                 if (!is_null_sid(&state->all_sids[i])) {
296                         /* already mapped */
297                         continue;
298                 }
299                 state->dom_xids[state->num_dom_xids++] = id;
300         }
301
302         if (state->num_dom_xids == 0) {
303                 tevent_req_done(req);
304                 return tevent_req_post(req, ev);
305         }
306
307         child = idmap_child();
308         subreq = dcerpc_wbint_UnixIDs2Sids_send(
309                 state, ev, child->binding_handle, dom_map->name, dom_map->sid,
310                 state->num_dom_xids, state->dom_xids, state->dom_sids);
311         if (tevent_req_nomem(subreq, req)) {
312                 return tevent_req_post(req, ev);
313         }
314         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
315         return req;
316 }
317
318 static void wb_xids2sids_dom_done(struct tevent_req *subreq)
319 {
320         struct tevent_req *req = tevent_req_callback_data(
321                 subreq, struct tevent_req);
322         struct wb_xids2sids_dom_state *state = tevent_req_data(
323                 req, struct wb_xids2sids_dom_state);
324         struct wb_xids2sids_dom_map *dom_map = state->dom_map;
325         NTSTATUS status, result;
326         size_t i;
327         size_t dom_sid_idx;
328
329         status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
330         TALLOC_FREE(subreq);
331         if (tevent_req_nterror(req, status)) {
332                 return;
333         }
334
335         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
336             !state->tried_dclookup) {
337
338                 subreq = wb_dsgetdcname_send(
339                         state, state->ev, state->dom_map->name, NULL, NULL,
340                         DS_RETURN_DNS_NAME);
341                 if (tevent_req_nomem(subreq, req)) {
342                         return;
343                 }
344                 tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
345                 return;
346         }
347
348         if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
349             tevent_req_nterror(req, result)) {
350                 return;
351         }
352
353         dom_sid_idx = 0;
354
355         for (i=0; i<state->num_all_xids; i++) {
356                 struct unixid id = state->all_xids[i];
357
358                 if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
359                         /* out of range */
360                         continue;
361                 }
362                 if (!is_null_sid(&state->all_sids[i])) {
363                         /* already mapped */
364                         continue;
365                 }
366
367                 sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
368
369                 /*
370                  * Prime the cache after an xid2sid call. It's
371                  * important that we use state->dom_xids for the xid
372                  * value, not state->all_xids: state->all_xids carries
373                  * what we asked for, e.g. a
374                  * ID_TYPE_UID. state->dom_xids holds something the
375                  * idmap child possibly changed to ID_TYPE_BOTH.
376                  */
377                 idmap_cache_set_sid2unixid(
378                         &state->all_sids[i], &state->dom_xids[dom_sid_idx]);
379
380                 dom_sid_idx += 1;
381         }
382
383         tevent_req_done(req);
384 }
385
386 static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
387 {
388         struct tevent_req *req = tevent_req_callback_data(
389                 subreq, struct tevent_req);
390         struct wb_xids2sids_dom_state *state = tevent_req_data(
391                 req, struct wb_xids2sids_dom_state);
392         struct winbindd_child *child = idmap_child();
393         struct netr_DsRGetDCNameInfo *dcinfo;
394         NTSTATUS status;
395
396         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
397         TALLOC_FREE(subreq);
398         if (tevent_req_nterror(req, status)) {
399                 return;
400         }
401
402         state->tried_dclookup = true;
403
404         status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
405         if (tevent_req_nterror(req, status)) {
406                 return;
407         }
408
409         child = idmap_child();
410         subreq = dcerpc_wbint_UnixIDs2Sids_send(
411                 state, state->ev, child->binding_handle, state->dom_map->name,
412                 state->dom_map->sid, state->num_dom_xids,
413                 state->dom_xids, state->dom_sids);
414         if (tevent_req_nomem(subreq, req)) {
415                 return;
416         }
417         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
418 }
419
420 static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
421 {
422         return tevent_req_simple_recv_ntstatus(req);
423 }
424
425 struct wb_xids2sids_state {
426         struct tevent_context *ev;
427         struct unixid *xids;
428         size_t num_xids;
429         struct dom_sid *sids;
430
431         size_t dom_idx;
432 };
433
434 static void wb_xids2sids_done(struct tevent_req *subreq);
435 static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq);
436
437 struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
438                                      struct tevent_context *ev,
439                                      struct unixid *xids,
440                                      uint32_t num_xids)
441 {
442         struct tevent_req *req, *subreq;
443         struct wb_xids2sids_state *state;
444
445         req = tevent_req_create(mem_ctx, &state,
446                                 struct wb_xids2sids_state);
447         if (req == NULL) {
448                 return NULL;
449         }
450         state->ev = ev;
451         state->xids = xids;
452         state->num_xids = num_xids;
453
454         state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
455         if (tevent_req_nomem(state->sids, req)) {
456                 return tevent_req_post(req, ev);
457         }
458
459         if (winbindd_use_idmap_cache()) {
460                 uint32_t i;
461
462                 for (i=0; i<num_xids; i++) {
463                         struct dom_sid sid;
464                         bool ok, expired;
465
466                         switch (xids[i].type) {
467                             case ID_TYPE_UID:
468                                     ok = idmap_cache_find_uid2sid(
469                                             xids[i].id, &sid, &expired);
470                                     break;
471                             case ID_TYPE_GID:
472                                     ok = idmap_cache_find_gid2sid(
473                                             xids[i].id, &sid, &expired);
474                                     break;
475                             default:
476                                     ok = false;
477                         }
478
479                         if (ok && !expired) {
480                                 sid_copy(&state->sids[i], &sid);
481                         }
482                 }
483         }
484
485         subreq = wb_xids2sids_init_dom_maps_send(
486                 state, state->ev);
487         if (tevent_req_nomem(subreq, req)) {
488                 return tevent_req_post(req, ev);
489         }
490         tevent_req_set_callback(subreq, wb_xids2sids_init_dom_maps_done, req);
491         return req;
492 }
493
494 static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq)
495 {
496         struct tevent_req *req = tevent_req_callback_data(
497                 subreq, struct tevent_req);
498         struct wb_xids2sids_state *state = tevent_req_data(
499                 req, struct wb_xids2sids_state);
500         size_t num_domains;
501         NTSTATUS status;
502
503         status = wb_xids2sids_init_dom_maps_recv(subreq);
504         TALLOC_FREE(subreq);
505         if (tevent_req_nterror(req, status)) {
506                 return;
507         }
508
509         num_domains = talloc_array_length(dom_maps);
510         if (num_domains == 0) {
511                 tevent_req_done(req);
512                 return;
513         }
514
515         subreq = wb_xids2sids_dom_send(
516                 state, state->ev, &dom_maps[state->dom_idx],
517                 state->xids, state->num_xids, state->sids);
518         if (tevent_req_nomem(subreq, req)) {
519                 return;
520         }
521         tevent_req_set_callback(subreq, wb_xids2sids_done, req);
522         return;
523 }
524
525 static void wb_xids2sids_done(struct tevent_req *subreq)
526 {
527         struct tevent_req *req = tevent_req_callback_data(
528                 subreq, struct tevent_req);
529         struct wb_xids2sids_state *state = tevent_req_data(
530                 req, struct wb_xids2sids_state);
531         size_t num_domains = talloc_array_length(dom_maps);
532         NTSTATUS status;
533
534         status = wb_xids2sids_dom_recv(subreq);
535         TALLOC_FREE(subreq);
536         if (tevent_req_nterror(req, status)) {
537                 return;
538         }
539
540         state->dom_idx += 1;
541
542         if (state->dom_idx >= num_domains) {
543                 tevent_req_done(req);
544                 return;
545         }
546
547         subreq = wb_xids2sids_dom_send(
548                 state, state->ev, &dom_maps[state->dom_idx],
549                 state->xids, state->num_xids, state->sids);
550         if (tevent_req_nomem(subreq, req)) {
551                 return;
552         }
553         tevent_req_set_callback(subreq, wb_xids2sids_done, req);
554 }
555
556 NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
557                            struct dom_sid **sids)
558 {
559         struct wb_xids2sids_state *state = tevent_req_data(
560                 req, struct wb_xids2sids_state);
561         NTSTATUS status;
562
563         if (tevent_req_is_nterror(req, &status)) {
564                 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status)));
565                 return status;
566         }
567
568         *sids = talloc_move(mem_ctx, &state->sids);
569         return NT_STATUS_OK;
570 }