s3:winbind: Fix bug 5626
[sfrench/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    The helpers always consist of three functions:
11
12    * A request setup function that takes the necessary parameters together
13      with a continuation function that is to be called upon completion
14
15    * A private continuation function that is internal only. This is to be
16      called by the lower-level functions in do_async(). Its only task is to
17      properly call the continuation function named above.
18
19    * A worker function that is called inside the appropriate child process.
20
21    This program is free software; you can redistribute it and/or modify
22    it under the terms of the GNU General Public License as published by
23    the Free Software Foundation; either version 3 of the License, or
24    (at your option) any later version.
25
26    This program is distributed in the hope that it will be useful,
27    but WITHOUT ANY WARRANTY; without even the implied warranty of
28    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29    GNU General Public License for more details.
30
31    You should have received a copy of the GNU General Public License
32    along with this program.  If not, see <http://www.gnu.org/licenses/>.
33 */
34
35 #include "includes.h"
36 #include "winbindd.h"
37
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_WINBIND
40
41 static struct winbindd_child static_idmap_child;
42
43 struct winbindd_child *idmap_child(void)
44 {
45         return &static_idmap_child;
46 }
47
48 static void winbindd_set_mapping_recv(TALLOC_CTX *mem_ctx, bool success,
49                                    struct winbindd_response *response,
50                                    void *c, void *private_data)
51 {
52         void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c;
53
54         if (!success) {
55                 DEBUG(5, ("Could not trigger idmap_set_mapping\n"));
56                 cont(private_data, False);
57                 return;
58         }
59
60         if (response->result != WINBINDD_OK) {
61                 DEBUG(5, ("idmap_set_mapping returned an error\n"));
62                 cont(private_data, False);
63                 return;
64         }
65
66         cont(private_data, True);
67 }
68
69 void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
70                              void (*cont)(void *private_data, bool success),
71                              void *private_data)
72 {
73         struct winbindd_request request;
74         ZERO_STRUCT(request);
75         request.cmd = WINBINDD_DUAL_SET_MAPPING;
76         request.data.dual_idmapset.id = map->xid.id;
77         request.data.dual_idmapset.type = map->xid.type;
78         sid_to_fstring(request.data.dual_idmapset.sid, map->sid);
79
80         do_async(mem_ctx, idmap_child(), &request, winbindd_set_mapping_recv,
81                  (void *)cont, private_data);
82 }
83
84 enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
85                                             struct winbindd_cli_state *state)
86 {
87         struct id_map map;
88         DOM_SID sid;
89         NTSTATUS result;
90
91         DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
92
93         if (!string_to_sid(&sid, state->request->data.dual_idmapset.sid))
94                 return WINBINDD_ERROR;
95
96         map.sid = &sid;
97         map.xid.id = state->request->data.dual_idmapset.id;
98         map.xid.type = state->request->data.dual_idmapset.type;
99         map.status = ID_MAPPED;
100
101         result = idmap_set_mapping(&map);
102         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
103 }
104
105 static void winbindd_remove_mapping_recv(TALLOC_CTX *mem_ctx, bool success,
106                                    struct winbindd_response *response,
107                                    void *c, void *private_data)
108 {
109         void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c;
110
111         if (!success) {
112                 DEBUG(5, ("Could not trigger idmap_remove_mapping\n"));
113                 cont(private_data, False);
114                 return;
115         }
116
117         if (response->result != WINBINDD_OK) {
118                 DEBUG(5, ("idmap_remove_mapping returned an error\n"));
119                 cont(private_data, False);
120                 return;
121         }
122
123         cont(private_data, True);
124 }
125
126 void winbindd_remove_mapping_async(TALLOC_CTX *mem_ctx,
127                              const struct id_map *map,
128                              void (*cont)(void *private_data, bool success),
129                              void *private_data)
130 {
131         struct winbindd_request request;
132         ZERO_STRUCT(request);
133         request.cmd = WINBINDD_DUAL_REMOVE_MAPPING;
134         request.data.dual_idmapset.id = map->xid.id;
135         request.data.dual_idmapset.type = map->xid.type;
136         sid_to_fstring(request.data.dual_idmapset.sid, map->sid);
137
138         do_async(mem_ctx, idmap_child(), &request, winbindd_remove_mapping_recv,
139                  (void *)cont, private_data);
140 }
141
142 enum winbindd_result winbindd_dual_remove_mapping(
143                                             struct winbindd_domain *domain,
144                                             struct winbindd_cli_state *state)
145 {
146         struct id_map map;
147         DOM_SID sid;
148         NTSTATUS result;
149
150         DEBUG(3, ("[%5lu]: dual_idmapremove\n", (unsigned long)state->pid));
151
152         if (!string_to_sid(&sid, state->request->data.dual_idmapset.sid))
153                 return WINBINDD_ERROR;
154
155         map.sid = &sid;
156         map.xid.id = state->request->data.dual_idmapset.id;
157         map.xid.type = state->request->data.dual_idmapset.type;
158         map.status = ID_MAPPED;
159
160         result = idmap_remove_mapping(&map);
161         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
162 }
163
164 static void winbindd_set_hwm_recv(TALLOC_CTX *mem_ctx, bool success,
165                                    struct winbindd_response *response,
166                                    void *c, void *private_data)
167 {
168         void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c;
169
170         if (!success) {
171                 DEBUG(5, ("Could not trigger idmap_set_hwm\n"));
172                 cont(private_data, False);
173                 return;
174         }
175
176         if (response->result != WINBINDD_OK) {
177                 DEBUG(5, ("idmap_set_hwm returned an error\n"));
178                 cont(private_data, False);
179                 return;
180         }
181
182         cont(private_data, True);
183 }
184
185 void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
186                              void (*cont)(void *private_data, bool success),
187                              void *private_data)
188 {
189         struct winbindd_request request;
190         ZERO_STRUCT(request);
191         request.cmd = WINBINDD_DUAL_SET_HWM;
192         request.data.dual_idmapset.id = xid->id;
193         request.data.dual_idmapset.type = xid->type;
194
195         do_async(mem_ctx, idmap_child(), &request, winbindd_set_hwm_recv,
196                  (void *)cont, private_data);
197 }
198
199 enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
200                                             struct winbindd_cli_state *state)
201 {
202         struct unixid xid;
203         NTSTATUS result;
204
205         DEBUG(3, ("[%5lu]: dual_set_hwm\n", (unsigned long)state->pid));
206
207         xid.id = state->request->data.dual_idmapset.id;
208         xid.type = state->request->data.dual_idmapset.type;
209
210         switch (xid.type) {
211         case ID_TYPE_UID:
212                 result = idmap_set_uid_hwm(&xid);
213                 break;
214         case ID_TYPE_GID:
215                 result = idmap_set_gid_hwm(&xid);
216                 break;
217         default:
218                 return WINBINDD_ERROR;
219         }
220         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
221 }
222
223 static void winbindd_sid2uid_recv(TALLOC_CTX *mem_ctx, bool success,
224                                struct winbindd_response *response,
225                                void *c, void *private_data)
226 {
227         void (*cont)(void *priv, bool succ, uid_t uid) =
228                 (void (*)(void *, bool, uid_t))c;
229
230         if (!success) {
231                 DEBUG(5, ("Could not trigger sid2uid\n"));
232                 cont(private_data, False, 0);
233                 return;
234         }
235
236         if (response->result != WINBINDD_OK) {
237                 DEBUG(5, ("sid2uid returned an error\n"));
238                 cont(private_data, False, 0);
239                 return;
240         }
241
242         cont(private_data, True, response->data.uid);
243 }
244
245 void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
246                          void (*cont)(void *private_data, bool success, uid_t uid),
247                          void *private_data)
248 {
249         struct winbindd_request request;
250         struct winbindd_domain *domain;
251
252         ZERO_STRUCT(request);
253         request.cmd = WINBINDD_DUAL_SID2UID;
254
255         domain = find_domain_from_sid(sid);
256
257         if (domain != NULL) {
258                 DEBUG(10, ("winbindd_sid2uid_async found domain %s, "
259                            "have_idmap_config = %d\n", domain->name,
260                            (int)domain->have_idmap_config));
261
262         }
263         else {
264                 DEBUG(10, ("winbindd_sid2uid_async did not find a domain for "
265                            "%s\n", sid_string_dbg(sid)));
266         }
267
268         if ((domain != NULL) && (domain->have_idmap_config)) {
269                 fstrcpy(request.domain_name, domain->name);
270         }
271
272         sid_to_fstring(request.data.dual_sid2id.sid, sid);
273         do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv,
274                  (void *)cont, private_data);
275 }
276
277 enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
278                                            struct winbindd_cli_state *state)
279 {
280         DOM_SID sid;
281         NTSTATUS result;
282
283         DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
284                   state->request->data.dual_sid2id.sid));
285
286         if (!string_to_sid(&sid, state->request->data.dual_sid2id.sid)) {
287                 DEBUG(1, ("Could not get convert sid %s from string\n",
288                           state->request->data.dual_sid2id.sid));
289                 return WINBINDD_ERROR;
290         }
291
292         result = idmap_sid_to_uid(state->request->domain_name, &sid,
293                                   &state->response->data.uid);
294
295         DEBUG(10, ("winbindd_dual_sid2uid: 0x%08x - %s - %u\n",
296                    NT_STATUS_V(result), sid_string_dbg(&sid),
297                    (unsigned int)state->response->data.uid));
298
299         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
300 }
301
302 static void winbindd_sid2gid_recv(TALLOC_CTX *mem_ctx, bool success,
303                                struct winbindd_response *response,
304                                void *c, void *private_data)
305 {
306         void (*cont)(void *priv, bool succ, gid_t gid) =
307                 (void (*)(void *, bool, gid_t))c;
308
309         if (!success) {
310                 DEBUG(5, ("Could not trigger sid2gid\n"));
311                 cont(private_data, False, 0);
312                 return;
313         }
314
315         if (response->result != WINBINDD_OK) {
316                 DEBUG(5, ("sid2gid returned an error\n"));
317                 cont(private_data, False, 0);
318                 return;
319         }
320
321         cont(private_data, True, response->data.gid);
322 }
323
324 void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
325                          void (*cont)(void *private_data, bool success, gid_t gid),
326                          void *private_data)
327 {
328         struct winbindd_request request;
329         struct winbindd_domain *domain;
330
331         ZERO_STRUCT(request);
332         request.cmd = WINBINDD_DUAL_SID2GID;
333
334         domain = find_domain_from_sid(sid);
335         if ((domain != NULL) && (domain->have_idmap_config)) {
336                 fstrcpy(request.domain_name, domain->name);
337         }
338
339         sid_to_fstring(request.data.dual_sid2id.sid, sid);
340
341         DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n",
342                 request.data.dual_sid2id.sid));
343
344         do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
345                  (void *)cont, private_data);
346 }
347
348 enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
349                                            struct winbindd_cli_state *state)
350 {
351         DOM_SID sid;
352         NTSTATUS result;
353
354         DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
355                   state->request->data.dual_sid2id.sid));
356
357         if (!string_to_sid(&sid, state->request->data.dual_sid2id.sid)) {
358                 DEBUG(1, ("Could not get convert sid %s from string\n",
359                           state->request->data.dual_sid2id.sid));
360                 return WINBINDD_ERROR;
361         }
362
363         /* Find gid for this sid and return it, possibly ask the slow remote idmap */
364
365         result = idmap_sid_to_gid(state->request->domain_name, &sid,
366                                   &state->response->data.gid);
367
368         DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n",
369                    NT_STATUS_V(result), sid_string_dbg(&sid),
370                    (unsigned int)state->response->data.gid));
371
372         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
373 }
374
375 /* The following uid2sid/gid2sid functions has been contributed by
376  * Keith Reynolds <Keith.Reynolds@centrify.com> */
377
378 static void winbindd_uid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
379                                   struct winbindd_response *response,
380                                   void *c, void *private_data)
381 {
382         void (*cont)(void *priv, bool succ, const char *sid) =
383                 (void (*)(void *, bool, const char *))c;
384
385         if (!success) {
386                 DEBUG(5, ("Could not trigger uid2sid\n"));
387                 cont(private_data, False, NULL);
388                 return;
389         }
390
391         if (response->result != WINBINDD_OK) {
392                 DEBUG(5, ("uid2sid returned an error\n"));
393                 cont(private_data, False, NULL);
394                 return;
395         }
396
397         cont(private_data, True, response->data.sid.sid);
398 }
399
400 void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
401                             void (*cont)(void *private_data, bool success, const char *sid),
402                             void *private_data)
403 {
404         struct winbindd_domain *domain;
405         struct winbindd_request request;
406
407         ZERO_STRUCT(request);
408         request.cmd = WINBINDD_DUAL_UID2SID;
409         request.data.uid = uid;
410
411         for (domain = domain_list(); domain != NULL; domain = domain->next) {
412                 if (domain->have_idmap_config
413                     && (uid >= domain->id_range_low)
414                     && (uid <= domain->id_range_high)) {
415                         fstrcpy(request.domain_name, domain->name);
416                 }
417         }
418
419         do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv,
420                  (void *)cont, private_data);
421 }
422
423 enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
424                                            struct winbindd_cli_state *state)
425 {
426         DOM_SID sid;
427         NTSTATUS result;
428
429         DEBUG(3,("[%5lu]: uid to sid %lu\n",
430                  (unsigned long)state->pid,
431                  (unsigned long) state->request->data.uid));
432
433         /* Find sid for this uid and return it, possibly ask the slow remote idmap */
434         result = idmap_uid_to_sid(state->request->domain_name, &sid,
435                                   state->request->data.uid);
436
437         if (NT_STATUS_IS_OK(result)) {
438                 sid_to_fstring(state->response->data.sid.sid, &sid);
439                 state->response->data.sid.type = SID_NAME_USER;
440                 return WINBINDD_OK;
441         }
442
443         return WINBINDD_ERROR;
444 }
445
446 static void winbindd_gid2sid_recv(TALLOC_CTX *mem_ctx, bool success,
447                                   struct winbindd_response *response,
448                                   void *c, void *private_data)
449 {
450         void (*cont)(void *priv, bool succ, const char *sid) =
451                 (void (*)(void *, bool, const char *))c;
452
453         if (!success) {
454                 DEBUG(5, ("Could not trigger gid2sid\n"));
455                 cont(private_data, False, NULL);
456                 return;
457         }
458
459         if (response->result != WINBINDD_OK) {
460                 DEBUG(5, ("gid2sid returned an error\n"));
461                 cont(private_data, False, NULL);
462                 return;
463         }
464
465         cont(private_data, True, response->data.sid.sid);
466 }
467
468 void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
469                             void (*cont)(void *private_data, bool success, const char *sid),
470                             void *private_data)
471 {
472         struct winbindd_domain *domain;
473         struct winbindd_request request;
474
475         ZERO_STRUCT(request);
476         request.cmd = WINBINDD_DUAL_GID2SID;
477         request.data.gid = gid;
478
479         for (domain = domain_list(); domain != NULL; domain = domain->next) {
480                 if (domain->have_idmap_config
481                     && (gid >= domain->id_range_low)
482                     && (gid <= domain->id_range_high)) {
483                         fstrcpy(request.domain_name, domain->name);
484                 }
485         }
486
487         do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv,
488                  (void *)cont, private_data);
489 }
490
491 enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
492                                            struct winbindd_cli_state *state)
493 {
494         DOM_SID sid;
495         NTSTATUS result;
496
497         DEBUG(3,("[%5lu]: gid %lu to sid\n",
498                 (unsigned long)state->pid,
499                 (unsigned long) state->request->data.gid));
500
501         /* Find sid for this gid and return it, possibly ask the slow remote idmap */
502         result = idmap_gid_to_sid(state->request->domain_name, &sid,
503                                   state->request->data.gid);
504
505         if (NT_STATUS_IS_OK(result)) {
506                 sid_to_fstring(state->response->data.sid.sid, &sid);
507                 DEBUG(10, ("[%5lu]: retrieved sid: %s\n",
508                            (unsigned long)state->pid,
509                            state->response->data.sid.sid));
510                 state->response->data.sid.type = SID_NAME_DOM_GRP;
511                 return WINBINDD_OK;
512         }
513
514         return WINBINDD_ERROR;
515 }
516
517 static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = {
518         {
519                 .name           = "PING",
520                 .struct_cmd     = WINBINDD_PING,
521                 .struct_fn      = winbindd_dual_ping,
522         },{
523                 .name           = "DUAL_SID2UID",
524                 .struct_cmd     = WINBINDD_DUAL_SID2UID,
525                 .struct_fn      = winbindd_dual_sid2uid,
526         },{
527                 .name           = "DUAL_SID2GID",
528                 .struct_cmd     = WINBINDD_DUAL_SID2GID,
529                 .struct_fn      = winbindd_dual_sid2gid,
530         },{
531                 .name           = "DUAL_UID2SID",
532                 .struct_cmd     = WINBINDD_DUAL_UID2SID,
533                 .struct_fn      = winbindd_dual_uid2sid,
534         },{
535                 .name           = "DUAL_GID2SID",
536                 .struct_cmd     = WINBINDD_DUAL_GID2SID,
537                 .struct_fn      = winbindd_dual_gid2sid,
538         },{
539                 .name           = "DUAL_SET_MAPPING",
540                 .struct_cmd     = WINBINDD_DUAL_SET_MAPPING,
541                 .struct_fn      = winbindd_dual_set_mapping,
542         },{
543                 .name           = "DUAL_REMOVE_MAPPING",
544                 .struct_cmd     = WINBINDD_DUAL_REMOVE_MAPPING,
545                 .struct_fn      = winbindd_dual_remove_mapping,
546         },{
547                 .name           = "DUAL_SET_HWMS",
548                 .struct_cmd     = WINBINDD_DUAL_SET_HWM,
549                 .struct_fn      = winbindd_dual_set_hwm,
550         },{
551                 .name           = "NDRCMD",
552                 .struct_cmd     = WINBINDD_DUAL_NDRCMD,
553                 .struct_fn      = winbindd_dual_ndrcmd,
554         },{
555                 .name           = NULL,
556         }
557 };
558
559 void init_idmap_child(void)
560 {
561         setup_child(NULL, &static_idmap_child,
562                     idmap_dispatch_table,
563                     "log.winbindd", "idmap");
564 }