lib-addrchange: Change API to fill up if_index value from netlink msg
[samba.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 = NULL;
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 NTSTATUS init_idmap_child(TALLOC_CTX *mem_ctx)
74 {
75         struct tevent_req *subreq = NULL;
76
77         if (static_idmap_child != NULL) {
78                 DBG_ERR("idmap child already allocated\n");
79                 return NT_STATUS_INTERNAL_ERROR;
80         }
81
82         static_idmap_child = talloc_zero(mem_ctx, struct winbindd_child);
83         if (static_idmap_child == NULL) {
84                 return NT_STATUS_NO_MEMORY;
85         }
86
87         subreq = wb_parent_idmap_setup_send(static_idmap_child,
88                                             global_event_context());
89         if (subreq == NULL) {
90                 /*
91                  * This is only an optimization, so we're free to
92                  * to ignore errors
93                  */
94                 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
95                 return NT_STATUS_NO_MEMORY;
96         }
97         tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
98         DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
99         return NT_STATUS_OK;
100 }
101
102 static void init_idmap_child_done(struct tevent_req *subreq)
103 {
104         const struct wb_parent_idmap_config *cfg = NULL;
105         NTSTATUS status;
106
107         status = wb_parent_idmap_setup_recv(subreq, &cfg);
108         TALLOC_FREE(subreq);
109         if (!NT_STATUS_IS_OK(status)) {
110                 /*
111                  * This is only an optimization, so we're free to
112                  * to ignore errors
113                  */
114                 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
115                         nt_errstr(status));
116                 return;
117         }
118
119         DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
120 }
121
122 struct wb_parent_idmap_setup_state {
123         struct tevent_context *ev;
124         struct wb_parent_idmap_config *cfg;
125         size_t dom_idx;
126 };
127
128 static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
129                                           enum tevent_req_state req_state)
130 {
131         struct wb_parent_idmap_setup_state *state =
132                 tevent_req_data(req,
133                 struct wb_parent_idmap_setup_state);
134
135         if (req_state == TEVENT_REQ_DONE) {
136                 state->cfg = NULL;
137                 return;
138         }
139
140         if (state->cfg == NULL) {
141                 return;
142         }
143
144         state->cfg->num_doms = 0;
145         state->cfg->initialized = false;
146         TALLOC_FREE(state->cfg->doms);
147         state->cfg = NULL;
148 }
149
150 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
151 static bool wb_parent_idmap_setup_scan_config(const char *domname,
152                                               void *private_data);
153 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
154 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
155
156 struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
157                                               struct tevent_context *ev)
158 {
159         struct tevent_req *req = NULL;
160         struct wb_parent_idmap_setup_state *state = NULL;
161         struct tevent_req *subreq = NULL;
162
163         req = tevent_req_create(mem_ctx, &state,
164                                 struct wb_parent_idmap_setup_state);
165         if (req == NULL) {
166                 return NULL;
167         }
168         *state = (struct wb_parent_idmap_setup_state) {
169                 .ev = ev,
170                 .cfg = &static_parent_idmap_config,
171                 .dom_idx = 0,
172         };
173
174         if (state->cfg->initialized) {
175                 tevent_req_done(req);
176                 return tevent_req_post(req, ev);
177         }
178
179         if (state->cfg->queue == NULL) {
180                 state->cfg->queue = tevent_queue_create(NULL,
181                                                 "wb_parent_idmap_config_queue");
182                 if (tevent_req_nomem(state->cfg->queue, req)) {
183                         return tevent_req_post(req, ev);
184                 }
185         }
186
187         subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
188         if (tevent_req_nomem(subreq, req)) {
189                 return tevent_req_post(req, ev);
190         }
191         tevent_req_set_callback(subreq,
192                                 wb_parent_idmap_setup_queue_wait_done,
193                                 req);
194
195         return req;
196 }
197
198 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
199 {
200         struct tevent_req *req =
201                 tevent_req_callback_data(subreq,
202                 struct tevent_req);
203         struct wb_parent_idmap_setup_state *state =
204                 tevent_req_data(req,
205                 struct wb_parent_idmap_setup_state);
206         bool ok;
207
208         /*
209          * Note we don't call TALLOC_FREE(subreq) here in order to block the
210          * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
211          * will destroy it implicitly.
212          */
213         ok = tevent_queue_wait_recv(subreq);
214         if (!ok) {
215                 DBG_ERR("tevent_queue_wait_recv() failed\n");
216                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
217                 return;
218         }
219
220         if (state->cfg->num_doms != 0) {
221                 /*
222                  * If we're not the first one we're done.
223                  */
224                 tevent_req_done(req);
225                 return;
226         }
227
228         /*
229          * From this point we start changing state->cfg,
230          * which is &static_parent_idmap_config,
231          * so we better setup a cleanup function
232          * to undo the changes on failure.
233          */
234         tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
235
236         /*
237          * Put the passdb idmap domain first. We always need to try
238          * there first.
239          */
240         state->cfg->doms = talloc_zero_array(NULL,
241                                              struct wb_parent_idmap_config_dom,
242                                              1);
243         if (tevent_req_nomem(state->cfg->doms, req)) {
244                 return;
245         }
246         state->cfg->doms[0].low_id = 0;
247         state->cfg->doms[0].high_id = UINT_MAX;
248         state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
249                                                  get_global_sam_name());
250         if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
251                 return;
252         }
253         state->cfg->num_doms += 1;
254
255         lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
256         if (!tevent_req_is_in_progress(req)) {
257                 return;
258         }
259
260         wb_parent_idmap_setup_lookupname_next(req);
261 }
262
263 static bool wb_parent_idmap_setup_scan_config(const char *domname,
264                                               void *private_data)
265 {
266         struct tevent_req *req =
267                 talloc_get_type_abort(private_data,
268                 struct tevent_req);
269         struct wb_parent_idmap_setup_state *state =
270                 tevent_req_data(req,
271                 struct wb_parent_idmap_setup_state);
272         struct wb_parent_idmap_config_dom *map = NULL;
273         size_t i;
274         const char *range;
275         unsigned low_id, high_id;
276         int ret;
277
278         range = idmap_config_const_string(domname, "range", NULL);
279         if (range == NULL) {
280                 DBG_DEBUG("No range for domain %s found\n", domname);
281                 return false;
282         }
283
284         ret = sscanf(range, "%u - %u", &low_id, &high_id);
285         if (ret != 2) {
286                 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
287                           range, domname);
288                 return false;
289         }
290
291         if (low_id > high_id) {
292                 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
293                           low_id, high_id, domname);
294                 return false;
295         }
296
297         for (i=0; i<state->cfg->num_doms; i++) {
298                 if (strequal(domname, state->cfg->doms[i].name)) {
299                         map = &state->cfg->doms[i];
300                         break;
301                 }
302         }
303
304         if (map == NULL) {
305                 struct wb_parent_idmap_config_dom *tmp;
306                 char *name;
307
308                 name = talloc_strdup(state, domname);
309                 if (name == NULL) {
310                         DBG_ERR("talloc failed\n");
311                         return false;
312                 }
313
314                 tmp = talloc_realloc(
315                         NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
316                         state->cfg->num_doms+1);
317                 if (tmp == NULL) {
318                         DBG_ERR("talloc failed\n");
319                         return false;
320                 }
321                 state->cfg->doms = tmp;
322
323                 map = &state->cfg->doms[state->cfg->num_doms];
324                 state->cfg->num_doms += 1;
325                 ZERO_STRUCTP(map);
326                 map->name = talloc_move(state->cfg->doms, &name);
327         }
328
329         map->low_id = low_id;
330         map->high_id = high_id;
331
332         return false;
333 }
334
335 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
336 {
337         struct wb_parent_idmap_setup_state *state =
338                 tevent_req_data(req,
339                 struct wb_parent_idmap_setup_state);
340         struct wb_parent_idmap_config_dom *dom =
341                 &state->cfg->doms[state->dom_idx];
342         struct tevent_req *subreq = NULL;
343
344  next_domain:
345         if (state->dom_idx == state->cfg->num_doms) {
346                 /*
347                  * We're done, so start the idmap child
348                  */
349                 setup_child(NULL, static_idmap_child, "log.winbindd", "idmap");
350                 static_parent_idmap_config.initialized = true;
351                 tevent_req_done(req);
352                 return;
353         }
354
355         if (strequal(dom->name, "*")) {
356                 state->dom_idx++;
357                 goto next_domain;
358         }
359
360         subreq = wb_lookupname_send(state,
361                                     state->ev,
362                                     dom->name,
363                                     dom->name,
364                                     "",
365                                     LOOKUP_NAME_NO_NSS);
366         if (tevent_req_nomem(subreq, req)) {
367                 return;
368         }
369         tevent_req_set_callback(subreq,
370                                 wb_parent_idmap_setup_lookupname_done,
371                                 req);
372 }
373
374 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
375 {
376         struct tevent_req *req =
377                 tevent_req_callback_data(subreq,
378                 struct tevent_req);
379         struct wb_parent_idmap_setup_state *state =
380                 tevent_req_data(req,
381                 struct wb_parent_idmap_setup_state);
382         struct wb_parent_idmap_config_dom *dom =
383                 &state->cfg->doms[state->dom_idx];
384         enum lsa_SidType type;
385         NTSTATUS status;
386
387         status = wb_lookupname_recv(subreq, &dom->sid, &type);
388         TALLOC_FREE(subreq);
389         if (!NT_STATUS_IS_OK(status)) {
390                 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
391                         dom->name,
392                         nt_errstr(status));
393
394                 state->dom_idx++;
395                 wb_parent_idmap_setup_lookupname_next(req);
396                 return;
397         }
398
399         if (type != SID_NAME_DOMAIN) {
400                 struct dom_sid_buf buf;
401
402                 DBG_ERR("SID %s for idmap domain name '%s' "
403                         "not a domain SID\n",
404                         dom_sid_str_buf(&dom->sid, &buf),
405                         dom->name);
406
407                 ZERO_STRUCT(dom->sid);
408         }
409
410         state->dom_idx++;
411         wb_parent_idmap_setup_lookupname_next(req);
412
413         return;
414 }
415
416 NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
417                                     const struct wb_parent_idmap_config **_cfg)
418 {
419         const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
420         NTSTATUS status;
421
422         *_cfg = NULL;
423
424         if (tevent_req_is_nterror(req, &status)) {
425                 tevent_req_received(req);
426                 return status;
427         }
428
429         /*
430          * Note state->cfg is already set to NULL by
431          * wb_parent_idmap_setup_cleanup()
432          */
433         *_cfg = cfg;
434         tevent_req_received(req);
435         return NT_STATUS_OK;
436 }