75f7d37d86d0ad940f2c8454d9fcd35067de8c1a
[metze/samba-autobuild/.git] / source3 / winbindd / winbindd_idmap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Async helpers for blocking functions
5
6    Copyright (C) Volker Lendecke 2005
7    Copyright (C) Gerald Carter 2006
8    Copyright (C) Simo Sorce 2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "winbindd.h"
26 #include "../libcli/security/security.h"
27 #include "passdb/lookup_sid.h"
28 #include "lib/global_contexts.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_WINBIND
32
33 static struct winbindd_child static_idmap_child;
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 xids2sids/sids2xids calls
38  * into per-idmap-domain chunks.
39  */
40 static struct wb_parent_idmap_config static_parent_idmap_config;
41
42 struct winbindd_child *idmap_child(void)
43 {
44         return &static_idmap_child;
45 }
46
47 bool is_idmap_child(const struct winbindd_child *child)
48 {
49         if (child == &static_idmap_child) {
50                 return true;
51         }
52
53         return false;
54 }
55
56 pid_t idmap_child_pid(void)
57 {
58         return static_idmap_child.pid;
59 }
60
61 struct dcerpc_binding_handle *idmap_child_handle(void)
62 {
63         /*
64          * The caller needs to use wb_parent_idmap_setup_send/recv
65          * before talking to the idmap child!
66          */
67         SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
68         return static_idmap_child.binding_handle;
69 }
70
71 static void init_idmap_child_done(struct tevent_req *subreq);
72
73 void init_idmap_child(void)
74 {
75         struct tevent_req *subreq = NULL;
76
77         subreq = wb_parent_idmap_setup_send(global_event_context(),
78                                             global_event_context());
79         if (subreq == NULL) {
80                 /*
81                  * This is only an optimization, so we're free to
82                  * to ignore errors
83                  */
84                 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
85                 return;
86         }
87         tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
88         DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
89 }
90
91 static void init_idmap_child_done(struct tevent_req *subreq)
92 {
93         const struct wb_parent_idmap_config *cfg = NULL;
94         NTSTATUS status;
95
96         status = wb_parent_idmap_setup_recv(subreq, &cfg);
97         TALLOC_FREE(subreq);
98         if (!NT_STATUS_IS_OK(status)) {
99                 /*
100                  * This is only an optimization, so we're free to
101                  * to ignore errors
102                  */
103                 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
104                         nt_errstr(status));
105                 return;
106         }
107
108         DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
109 }
110
111 struct wb_parent_idmap_setup_state {
112         struct tevent_context *ev;
113         struct wb_parent_idmap_config *cfg;
114         size_t dom_idx;
115 };
116
117 static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
118                                           enum tevent_req_state req_state)
119 {
120         struct wb_parent_idmap_setup_state *state =
121                 tevent_req_data(req,
122                 struct wb_parent_idmap_setup_state);
123
124         if (req_state == TEVENT_REQ_DONE) {
125                 state->cfg = NULL;
126                 return;
127         }
128
129         if (state->cfg == NULL) {
130                 return;
131         }
132
133         state->cfg->num_doms = 0;
134         state->cfg->initialized = false;
135         TALLOC_FREE(state->cfg->doms);
136         state->cfg = NULL;
137 }
138
139 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
140 static bool wb_parent_idmap_setup_scan_config(const char *domname,
141                                               void *private_data);
142 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
143 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
144
145 struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
146                                               struct tevent_context *ev)
147 {
148         struct tevent_req *req = NULL;
149         struct wb_parent_idmap_setup_state *state = NULL;
150         struct tevent_req *subreq = NULL;
151
152         req = tevent_req_create(mem_ctx, &state,
153                                 struct wb_parent_idmap_setup_state);
154         if (req == NULL) {
155                 return NULL;
156         }
157         *state = (struct wb_parent_idmap_setup_state) {
158                 .ev = ev,
159                 .cfg = &static_parent_idmap_config,
160                 .dom_idx = 0,
161         };
162
163         if (state->cfg->initialized) {
164                 tevent_req_done(req);
165                 return tevent_req_post(req, ev);
166         }
167
168         if (state->cfg->queue == NULL) {
169                 state->cfg->queue = tevent_queue_create(NULL,
170                                                 "wb_parent_idmap_config_queue");
171                 if (tevent_req_nomem(state->cfg->queue, req)) {
172                         return tevent_req_post(req, ev);
173                 }
174         }
175
176         subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
177         if (tevent_req_nomem(subreq, req)) {
178                 return tevent_req_post(req, ev);
179         }
180         tevent_req_set_callback(subreq,
181                                 wb_parent_idmap_setup_queue_wait_done,
182                                 req);
183
184         return req;
185 }
186
187 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
188 {
189         struct tevent_req *req =
190                 tevent_req_callback_data(subreq,
191                 struct tevent_req);
192         struct wb_parent_idmap_setup_state *state =
193                 tevent_req_data(req,
194                 struct wb_parent_idmap_setup_state);
195         bool ok;
196
197         /*
198          * Note we don't call TALLOC_FREE(subreq) here in order to block the
199          * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
200          * will destroy it implicitly.
201          */
202         ok = tevent_queue_wait_recv(subreq);
203         if (!ok) {
204                 DBG_ERR("tevent_queue_wait_recv() failed\n");
205                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
206                 return;
207         }
208
209         if (state->cfg->num_doms != 0) {
210                 /*
211                  * If we're not the first one we're done.
212                  */
213                 tevent_req_done(req);
214                 return;
215         }
216
217         /*
218          * From this point we start changing state->cfg,
219          * which is &static_parent_idmap_config,
220          * so we better setup a cleanup function
221          * to undo the changes on failure.
222          */
223         tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
224
225         /*
226          * Put the passdb idmap domain first. We always need to try
227          * there first.
228          */
229         state->cfg->doms = talloc_zero_array(NULL,
230                                              struct wb_parent_idmap_config_dom,
231                                              1);
232         if (tevent_req_nomem(state->cfg->doms, req)) {
233                 return;
234         }
235         state->cfg->doms[0].low_id = 0;
236         state->cfg->doms[0].high_id = UINT_MAX;
237         state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
238                                                  get_global_sam_name());
239         if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
240                 return;
241         }
242         state->cfg->num_doms += 1;
243
244         lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
245         if (!tevent_req_is_in_progress(req)) {
246                 return;
247         }
248
249         wb_parent_idmap_setup_lookupname_next(req);
250 }
251
252 static bool wb_parent_idmap_setup_scan_config(const char *domname,
253                                               void *private_data)
254 {
255         struct tevent_req *req =
256                 talloc_get_type_abort(private_data,
257                 struct tevent_req);
258         struct wb_parent_idmap_setup_state *state =
259                 tevent_req_data(req,
260                 struct wb_parent_idmap_setup_state);
261         struct wb_parent_idmap_config_dom *map = NULL;
262         size_t i;
263         const char *range;
264         unsigned low_id, high_id;
265         int ret;
266
267         range = idmap_config_const_string(domname, "range", NULL);
268         if (range == NULL) {
269                 DBG_DEBUG("No range for domain %s found\n", domname);
270                 return false;
271         }
272
273         ret = sscanf(range, "%u - %u", &low_id, &high_id);
274         if (ret != 2) {
275                 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
276                           range, domname);
277                 return false;
278         }
279
280         if (low_id > high_id) {
281                 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
282                           low_id, high_id, domname);
283                 return false;
284         }
285
286         for (i=0; i<state->cfg->num_doms; i++) {
287                 if (strequal(domname, state->cfg->doms[i].name)) {
288                         map = &state->cfg->doms[i];
289                         break;
290                 }
291         }
292
293         if (map == NULL) {
294                 struct wb_parent_idmap_config_dom *tmp;
295                 char *name;
296
297                 name = talloc_strdup(state, domname);
298                 if (name == NULL) {
299                         DBG_ERR("talloc failed\n");
300                         return false;
301                 }
302
303                 tmp = talloc_realloc(
304                         NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
305                         state->cfg->num_doms+1);
306                 if (tmp == NULL) {
307                         DBG_ERR("talloc failed\n");
308                         return false;
309                 }
310                 state->cfg->doms = tmp;
311
312                 map = &state->cfg->doms[state->cfg->num_doms];
313                 state->cfg->num_doms += 1;
314                 ZERO_STRUCTP(map);
315                 map->name = talloc_move(state->cfg->doms, &name);
316         }
317
318         map->low_id = low_id;
319         map->high_id = high_id;
320
321         return false;
322 }
323
324 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
325 {
326         struct wb_parent_idmap_setup_state *state =
327                 tevent_req_data(req,
328                 struct wb_parent_idmap_setup_state);
329         struct wb_parent_idmap_config_dom *dom =
330                 &state->cfg->doms[state->dom_idx];
331         struct tevent_req *subreq = NULL;
332
333  next_domain:
334         if (state->dom_idx == state->cfg->num_doms) {
335                 /*
336                  * We're done, so start the idmap child
337                  */
338                 setup_child(NULL, &static_idmap_child, "log.winbindd", "idmap");
339                 static_parent_idmap_config.initialized = true;
340                 tevent_req_done(req);
341                 return;
342         }
343
344         if (strequal(dom->name, "*")) {
345                 state->dom_idx++;
346                 goto next_domain;
347         }
348
349         subreq = wb_lookupname_send(state,
350                                     state->ev,
351                                     dom->name,
352                                     dom->name,
353                                     "",
354                                     LOOKUP_NAME_NO_NSS);
355         if (tevent_req_nomem(subreq, req)) {
356                 return;
357         }
358         tevent_req_set_callback(subreq,
359                                 wb_parent_idmap_setup_lookupname_done,
360                                 req);
361 }
362
363 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
364 {
365         struct tevent_req *req =
366                 tevent_req_callback_data(subreq,
367                 struct tevent_req);
368         struct wb_parent_idmap_setup_state *state =
369                 tevent_req_data(req,
370                 struct wb_parent_idmap_setup_state);
371         struct wb_parent_idmap_config_dom *dom =
372                 &state->cfg->doms[state->dom_idx];
373         enum lsa_SidType type;
374         NTSTATUS status;
375
376         status = wb_lookupname_recv(subreq, &dom->sid, &type);
377         TALLOC_FREE(subreq);
378         if (!NT_STATUS_IS_OK(status)) {
379                 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
380                         dom->name,
381                         nt_errstr(status));
382
383                 state->dom_idx++;
384                 wb_parent_idmap_setup_lookupname_next(req);
385                 return;
386         }
387
388         if (type != SID_NAME_DOMAIN) {
389                 struct dom_sid_buf buf;
390
391                 DBG_ERR("SID %s for idmap domain name '%s' "
392                         "not a domain SID\n",
393                         dom_sid_str_buf(&dom->sid, &buf),
394                         dom->name);
395
396                 ZERO_STRUCT(dom->sid);
397         }
398
399         state->dom_idx++;
400         wb_parent_idmap_setup_lookupname_next(req);
401
402         return;
403 }
404
405 NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
406                                     const struct wb_parent_idmap_config **_cfg)
407 {
408         const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
409         NTSTATUS status;
410
411         *_cfg = NULL;
412
413         if (tevent_req_is_nterror(req, &status)) {
414                 tevent_req_received(req);
415                 return status;
416         }
417
418         /*
419          * Note state->cfg is already set to NULL by
420          * wb_parent_idmap_setup_cleanup()
421          */
422         *_cfg = cfg;
423         tevent_req_received(req);
424         return NT_STATUS_OK;
425 }