[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / winbindd / winbindd_async.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    
9    The helpers always consist of three functions: 
10
11    * A request setup function that takes the necessary parameters together
12      with a continuation function that is to be called upon completion
13
14    * A private continuation function that is internal only. This is to be
15      called by the lower-level functions in do_async(). Its only task is to
16      properly call the continuation function named above.
17
18    * A worker function that is called inside the appropriate child process.
19
20    This program is free software; you can redistribute it and/or modify
21    it under the terms of the GNU General Public License as published by
22    the Free Software Foundation; either version 3 of the License, or
23    (at your option) any later version.
24    
25    This program is distributed in the hope that it will be useful,
26    but WITHOUT ANY WARRANTY; without even the implied warranty of
27    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28    GNU General Public License for more details.
29    
30    You should have received a copy of the GNU General Public License
31    along with this program.  If not, see <http://www.gnu.org/licenses/>.
32 */
33
34 #include "includes.h"
35 #include "winbindd.h"
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_WINBIND
39
40 struct do_async_state {
41         TALLOC_CTX *mem_ctx;
42         struct winbindd_request request;
43         struct winbindd_response response;
44         void (*cont)(TALLOC_CTX *mem_ctx,
45                      BOOL success,
46                      struct winbindd_response *response,
47                      void *c, void *private_data);
48         void *c, *private_data;
49 };
50
51 static void do_async_recv(void *private_data, BOOL success)
52 {
53         struct do_async_state *state =
54                 talloc_get_type_abort(private_data, struct do_async_state);
55
56         state->cont(state->mem_ctx, success, &state->response,
57                     state->c, state->private_data);
58 }
59
60 static void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
61                      const struct winbindd_request *request,
62                      void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
63                                   struct winbindd_response *response,
64                                   void *c, void *private_data),
65                      void *c, void *private_data)
66 {
67         struct do_async_state *state;
68
69         state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
70         if (state == NULL) {
71                 DEBUG(0, ("talloc failed\n"));
72                 cont(mem_ctx, False, NULL, c, private_data);
73                 return;
74         }
75
76         state->mem_ctx = mem_ctx;
77         state->request = *request;
78         state->request.length = sizeof(state->request);
79         state->cont = cont;
80         state->c = c;
81         state->private_data = private_data;
82
83         async_request(mem_ctx, child, &state->request,
84                       &state->response, do_async_recv, state);
85 }
86
87 void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
88                      const struct winbindd_request *request,
89                      void (*cont)(TALLOC_CTX *mem_ctx, BOOL success,
90                                   struct winbindd_response *response,
91                                   void *c, void *private_data),
92                      void *c, void *private_data)
93 {
94         struct do_async_state *state;
95
96         state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
97         if (state == NULL) {
98                 DEBUG(0, ("talloc failed\n"));
99                 cont(mem_ctx, False, NULL, c, private_data);
100                 return;
101         }
102
103         state->mem_ctx = mem_ctx;
104         state->request = *request;
105         state->request.length = sizeof(state->request);
106         state->cont = cont;
107         state->c = c;
108         state->private_data = private_data;
109
110         async_domain_request(mem_ctx, domain, &state->request,
111                              &state->response, do_async_recv, state);
112 }
113
114 static void winbindd_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
115                                    struct winbindd_response *response,
116                                    void *c, void *private_data)
117 {
118         void (*cont)(void *priv, BOOL succ) = (void (*)(void *, BOOL))c;
119
120         if (!success) {
121                 DEBUG(5, ("Could not trigger idmap_set_mapping\n"));
122                 cont(private_data, False);
123                 return;
124         }
125
126         if (response->result != WINBINDD_OK) {
127                 DEBUG(5, ("idmap_set_mapping returned an error\n"));
128                 cont(private_data, False);
129                 return;
130         }
131
132         cont(private_data, True);
133 }
134
135 void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
136                              void (*cont)(void *private_data, BOOL success),
137                              void *private_data)
138 {
139         struct winbindd_request request;
140         ZERO_STRUCT(request);
141         request.cmd = WINBINDD_DUAL_SET_MAPPING;
142         request.data.dual_idmapset.id = map->xid.id;
143         request.data.dual_idmapset.type = map->xid.type;
144         sid_to_string(request.data.dual_idmapset.sid, map->sid);
145
146         do_async(mem_ctx, idmap_child(), &request, winbindd_set_mapping_recv,
147                  (void *)cont, private_data);
148 }
149
150 enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
151                                             struct winbindd_cli_state *state)
152 {
153         struct id_map map;
154         DOM_SID sid;
155         NTSTATUS result;
156
157         DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
158
159         if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid))
160                 return WINBINDD_ERROR;
161
162         map.sid = &sid;
163         map.xid.id = state->request.data.dual_idmapset.id;
164         map.xid.type = state->request.data.dual_idmapset.type;
165         map.status = ID_MAPPED;
166
167         result = idmap_set_mapping(&map);
168         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
169 }
170
171 static void winbindd_set_hwm_recv(TALLOC_CTX *mem_ctx, BOOL success,
172                                    struct winbindd_response *response,
173                                    void *c, void *private_data)
174 {
175         void (*cont)(void *priv, BOOL succ) = (void (*)(void *, BOOL))c;
176
177         if (!success) {
178                 DEBUG(5, ("Could not trigger idmap_set_hwm\n"));
179                 cont(private_data, False);
180                 return;
181         }
182
183         if (response->result != WINBINDD_OK) {
184                 DEBUG(5, ("idmap_set_hwm returned an error\n"));
185                 cont(private_data, False);
186                 return;
187         }
188
189         cont(private_data, True);
190 }
191
192 void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
193                              void (*cont)(void *private_data, BOOL success),
194                              void *private_data)
195 {
196         struct winbindd_request request;
197         ZERO_STRUCT(request);
198         request.cmd = WINBINDD_DUAL_SET_HWM;
199         request.data.dual_idmapset.id = xid->id;
200         request.data.dual_idmapset.type = xid->type;
201
202         do_async(mem_ctx, idmap_child(), &request, winbindd_set_hwm_recv,
203                  (void *)cont, private_data);
204 }
205
206 enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
207                                             struct winbindd_cli_state *state)
208 {
209         struct unixid xid;
210         NTSTATUS result;
211
212         DEBUG(3, ("[%5lu]: dual_set_hwm\n", (unsigned long)state->pid));
213
214         xid.id = state->request.data.dual_idmapset.id;
215         xid.type = state->request.data.dual_idmapset.type;
216
217         switch (xid.type) {
218         case ID_TYPE_UID:
219                 result = idmap_set_uid_hwm(&xid);
220                 break;
221         case ID_TYPE_GID:
222                 result = idmap_set_gid_hwm(&xid);
223                 break;
224         default:
225                 return WINBINDD_ERROR;
226         }
227         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
228 }
229
230 static void winbindd_sids2xids_recv(TALLOC_CTX *mem_ctx, BOOL success,
231                                struct winbindd_response *response,
232                                void *c, void *private_data)
233 {
234         void (*cont)(void *priv, BOOL succ, void *, int) =
235                 (void (*)(void *, BOOL, void *, int))c;
236
237         if (!success) {
238                 DEBUG(5, ("Could not trigger sids2xids\n"));
239                 cont(private_data, False, NULL, 0);
240                 return;
241         }
242
243         if (response->result != WINBINDD_OK) {
244                 DEBUG(5, ("sids2xids returned an error\n"));
245                 cont(private_data, False, NULL, 0);
246                 return;
247         }
248
249         cont(private_data, True, response->extra_data.data, response->length - sizeof(response));
250 }
251                          
252 void winbindd_sids2xids_async(TALLOC_CTX *mem_ctx, void *sids, int size,
253                          void (*cont)(void *private_data, BOOL success, void *data, int len),
254                          void *private_data)
255 {
256         struct winbindd_request request;
257         ZERO_STRUCT(request);
258         request.cmd = WINBINDD_DUAL_SIDS2XIDS;
259         request.extra_data.data = (char *)sids;
260         request.extra_len = size;
261         do_async(mem_ctx, idmap_child(), &request, winbindd_sids2xids_recv,
262                  (void *)cont, private_data);
263 }
264
265 enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
266                                            struct winbindd_cli_state *state)
267 {
268         DOM_SID *sids;
269         struct unixid *xids;
270         struct id_map **ids;
271         NTSTATUS result;
272         int num, i;
273
274         DEBUG(3, ("[%5lu]: sids to unix ids\n", (unsigned long)state->pid));
275
276         if (state->request.extra_len == 0) {
277                 DEBUG(0, ("Invalid buffer size!\n"));
278                 return WINBINDD_ERROR;
279         }
280
281         sids = (DOM_SID *)state->request.extra_data.data;
282         num = state->request.extra_len / sizeof(DOM_SID);
283
284         ids = TALLOC_ZERO_ARRAY(state->mem_ctx, struct id_map *, num + 1);
285         if ( ! ids) {
286                 DEBUG(0, ("Out of memory!\n"));
287                 return WINBINDD_ERROR;
288         }
289         for (i = 0; i < num; i++) {
290                 ids[i] = TALLOC_P(ids, struct id_map);
291                 if ( ! ids[i]) {
292                         DEBUG(0, ("Out of memory!\n"));
293                         talloc_free(ids);
294                         return WINBINDD_ERROR;
295                 }
296                 ids[i]->sid = &sids[i];
297         }
298
299         result = idmap_sids_to_unixids(ids);
300
301         if (NT_STATUS_IS_OK(result)) {
302
303                 xids = SMB_MALLOC_ARRAY(struct unixid, num);
304                 if ( ! xids) {
305                         DEBUG(0, ("Out of memory!\n"));
306                         talloc_free(ids);
307                         return WINBINDD_ERROR;
308                 }
309                 
310                 for (i = 0; i < num; i++) {
311                         if (ids[i]->status == ID_MAPPED) {
312                                 xids[i].type = ids[i]->xid.type;
313                                 xids[i].id = ids[i]->xid.id;
314                         } else {
315                                 xids[i].type = -1;
316                         }
317                 }
318
319                 state->response.length = sizeof(state->response) + (sizeof(struct unixid) * num);
320                 state->response.extra_data.data = xids;
321
322         } else {
323                 DEBUG (2, ("idmap_sids_to_unixids returned an error: 0x%08x\n", NT_STATUS_V(result)));
324                 talloc_free(ids);
325                 return WINBINDD_ERROR;
326         }
327
328         talloc_free(ids);
329         return WINBINDD_OK;
330 }
331
332 static void winbindd_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
333                                struct winbindd_response *response,
334                                void *c, void *private_data)
335 {
336         void (*cont)(void *priv, BOOL succ, uid_t uid) =
337                 (void (*)(void *, BOOL, uid_t))c;
338
339         if (!success) {
340                 DEBUG(5, ("Could not trigger sid2uid\n"));
341                 cont(private_data, False, 0);
342                 return;
343         }
344
345         if (response->result != WINBINDD_OK) {
346                 DEBUG(5, ("sid2uid returned an error\n"));
347                 cont(private_data, False, 0);
348                 return;
349         }
350
351         cont(private_data, True, response->data.uid);
352 }
353                          
354 void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
355                          void (*cont)(void *private_data, BOOL success, uid_t uid),
356                          void *private_data)
357 {
358         struct winbindd_request request;
359         ZERO_STRUCT(request);
360         request.cmd = WINBINDD_DUAL_SID2UID;
361         sid_to_string(request.data.dual_sid2id.sid, sid);
362         do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv,
363                  (void *)cont, private_data);
364 }
365
366 enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
367                                            struct winbindd_cli_state *state)
368 {
369         DOM_SID sid;
370         NTSTATUS result;
371
372         DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
373                   state->request.data.dual_sid2id.sid));
374
375         if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
376                 DEBUG(1, ("Could not get convert sid %s from string\n",
377                           state->request.data.dual_sid2id.sid));
378                 return WINBINDD_ERROR;
379         }
380
381         /* Find uid for this sid and return it, possibly ask the slow remote idmap */
382
383         result = idmap_sid_to_uid(&sid, &(state->response.data.uid));
384
385         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
386 }
387
388 #if 0   /* not used */
389 static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
390                           struct winbindd_response *response,
391                           void *c, void *private_data);
392
393 void winbindd_uid2name_async(TALLOC_CTX *mem_ctx, uid_t uid,
394                              void (*cont)(void *private_data, BOOL success,
395                                           const char *name),
396                              void *private_data)
397 {
398         struct winbindd_request request;
399         ZERO_STRUCT(request);
400         request.cmd = WINBINDD_DUAL_UID2NAME;
401         request.data.uid = uid;
402         do_async(mem_ctx, idmap_child(), &request, uid2name_recv,
403                  (void *)cont, private_data);
404 }
405 #endif  /* not used */
406
407 enum winbindd_result winbindd_dual_uid2name(struct winbindd_domain *domain,
408                                             struct winbindd_cli_state *state)
409 {
410         struct passwd *pw;
411
412         DEBUG(3, ("[%5lu]: uid2name %lu\n", (unsigned long)state->pid, 
413                   (unsigned long)state->request.data.uid));
414
415         pw = getpwuid(state->request.data.uid);
416         if (pw == NULL) {
417                 DEBUG(5, ("User %lu not found\n",
418                           (unsigned long)state->request.data.uid));
419                 return WINBINDD_ERROR;
420         }
421
422         fstrcpy(state->response.data.name.name, pw->pw_name);
423         return WINBINDD_OK;
424 }
425
426 #if 0   /* not used */
427 static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
428                           struct winbindd_response *response,
429                           void *c, void *private_data)
430 {
431         void (*cont)(void *priv, BOOL succ, const char *name) =
432                 (void (*)(void *, BOOL, const char *))c;
433
434         if (!success) {
435                 DEBUG(5, ("Could not trigger uid2name\n"));
436                 cont(private_data, False, NULL);
437                 return;
438         }
439
440         if (response->result != WINBINDD_OK) {
441                 DEBUG(5, ("uid2name returned an error\n"));
442                 cont(private_data, False, NULL);
443                 return;
444         }
445
446         cont(private_data, True, response->data.name.name);
447 }
448
449 static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
450                           struct winbindd_response *response,
451                           void *c, void *private_data);
452
453 static void winbindd_name2uid_async(TALLOC_CTX *mem_ctx, const char *name,
454                                     void (*cont)(void *private_data, BOOL success,
455                                                  uid_t uid),
456                                     void *private_data)
457 {
458         struct winbindd_request request;
459         ZERO_STRUCT(request);
460         request.cmd = WINBINDD_DUAL_NAME2UID;
461         fstrcpy(request.data.username, name);
462         do_async(mem_ctx, idmap_child(), &request, name2uid_recv,
463                  (void *)cont, private_data);
464 }
465 #endif  /* not used */
466
467 enum winbindd_result winbindd_dual_name2uid(struct winbindd_domain *domain,
468                                             struct winbindd_cli_state *state)
469 {
470         struct passwd *pw;
471
472         /* Ensure null termination */
473         state->request.data.username
474                 [sizeof(state->request.data.username)-1] = '\0';
475
476         DEBUG(3, ("[%5lu]: name2uid %s\n", (unsigned long)state->pid, 
477                   state->request.data.username));
478
479         pw = getpwnam(state->request.data.username);
480         if (pw == NULL) {
481                 return WINBINDD_ERROR;
482         }
483
484         state->response.data.uid = pw->pw_uid;
485         return WINBINDD_OK;
486 }
487
488 #if 0   /* not used */
489 static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
490                           struct winbindd_response *response,
491                           void *c, void *private_data)
492 {
493         void (*cont)(void *priv, BOOL succ, uid_t uid) =
494                 (void (*)(void *, BOOL, uid_t))c;
495
496         if (!success) {
497                 DEBUG(5, ("Could not trigger name2uid\n"));
498                 cont(private_data, False, 0);
499                 return;
500         }
501
502         if (response->result != WINBINDD_OK) {
503                 DEBUG(5, ("name2uid returned an error\n"));
504                 cont(private_data, False, 0);
505                 return;
506         }
507
508         cont(private_data, True, response->data.uid);
509 }
510 #endif  /* not used */
511
512 static void winbindd_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
513                                struct winbindd_response *response,
514                                void *c, void *private_data)
515 {
516         void (*cont)(void *priv, BOOL succ, gid_t gid) =
517                 (void (*)(void *, BOOL, gid_t))c;
518
519         if (!success) {
520                 DEBUG(5, ("Could not trigger sid2gid\n"));
521                 cont(private_data, False, 0);
522                 return;
523         }
524
525         if (response->result != WINBINDD_OK) {
526                 DEBUG(5, ("sid2gid returned an error\n"));
527                 cont(private_data, False, 0);
528                 return;
529         }
530
531         cont(private_data, True, response->data.gid);
532 }
533                          
534 void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
535                          void (*cont)(void *private_data, BOOL success, gid_t gid),
536                          void *private_data)
537 {
538         struct winbindd_request request;
539         ZERO_STRUCT(request);
540         request.cmd = WINBINDD_DUAL_SID2GID;
541         sid_to_string(request.data.dual_sid2id.sid, sid);
542
543         DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n", 
544                 request.data.dual_sid2id.sid));
545
546         do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
547                  (void *)cont, private_data);
548 }
549
550 enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
551                                            struct winbindd_cli_state *state)
552 {
553         DOM_SID sid;
554         NTSTATUS result;
555
556         DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
557                   state->request.data.dual_sid2id.sid));
558
559         if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
560                 DEBUG(1, ("Could not get convert sid %s from string\n",
561                           state->request.data.dual_sid2id.sid));
562                 return WINBINDD_ERROR;
563         }
564
565         /* Find gid for this sid and return it, possibly ask the slow remote idmap */
566
567         result = idmap_sid_to_gid(&sid, &state->response.data.gid);
568         
569         DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n", NT_STATUS_V(result), sid_string_static(&sid), state->response.data.gid));
570
571         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
572 }
573
574 static void gid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
575                           struct winbindd_response *response,
576                           void *c, void *private_data)
577 {
578         void (*cont)(void *priv, BOOL succ, const char *name) =
579                 (void (*)(void *, BOOL, const char *))c;
580
581         if (!success) {
582                 DEBUG(5, ("Could not trigger gid2name\n"));
583                 cont(private_data, False, NULL);
584                 return;
585         }
586
587         if (response->result != WINBINDD_OK) {
588                 DEBUG(5, ("gid2name returned an error\n"));
589                 cont(private_data, False, NULL);
590                 return;
591         }
592
593         cont(private_data, True, response->data.name.name);
594 }
595
596 void winbindd_gid2name_async(TALLOC_CTX *mem_ctx, gid_t gid,
597                              void (*cont)(void *private_data, BOOL success,
598                                           const char *name),
599                              void *private_data)
600 {
601         struct winbindd_request request;
602         ZERO_STRUCT(request);
603         request.cmd = WINBINDD_DUAL_GID2NAME;
604         request.data.gid = gid;
605         do_async(mem_ctx, idmap_child(), &request, gid2name_recv,
606                  (void *)cont, private_data);
607 }
608
609 enum winbindd_result winbindd_dual_gid2name(struct winbindd_domain *domain,
610                                             struct winbindd_cli_state *state)
611 {
612         struct group *gr;
613
614         DEBUG(3, ("[%5lu]: gid2name %lu\n", (unsigned long)state->pid, 
615                   (unsigned long)state->request.data.gid));
616
617         gr = getgrgid(state->request.data.gid);
618         if (gr == NULL)
619                 return WINBINDD_ERROR;
620
621         fstrcpy(state->response.data.name.name, gr->gr_name);
622         return WINBINDD_OK;
623 }
624
625 #if 0   /* not used */
626 static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
627                           struct winbindd_response *response,
628                           void *c, void *private_data);
629
630 static void winbindd_name2gid_async(TALLOC_CTX *mem_ctx, const char *name,
631                                     void (*cont)(void *private_data, BOOL success,
632                                                  gid_t gid),
633                                     void *private_data)
634 {
635         struct winbindd_request request;
636         ZERO_STRUCT(request);
637         request.cmd = WINBINDD_DUAL_NAME2GID;
638         fstrcpy(request.data.groupname, name);
639         do_async(mem_ctx, idmap_child(), &request, name2gid_recv,
640                  (void *)cont, private_data);
641 }
642 #endif  /* not used */
643
644 enum winbindd_result winbindd_dual_name2gid(struct winbindd_domain *domain,
645                                             struct winbindd_cli_state *state)
646 {
647         struct group *gr;
648
649         /* Ensure null termination */
650         state->request.data.groupname
651                 [sizeof(state->request.data.groupname)-1] = '\0';
652
653         DEBUG(3, ("[%5lu]: name2gid %s\n", (unsigned long)state->pid, 
654                   state->request.data.groupname));
655
656         gr = getgrnam(state->request.data.groupname);
657         if (gr == NULL) {
658                 return WINBINDD_ERROR;
659         }
660
661         state->response.data.gid = gr->gr_gid;
662         return WINBINDD_OK;
663 }
664
665 #if 0   /* not used */
666 static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
667                           struct winbindd_response *response,
668                           void *c, void *private_data)
669 {
670         void (*cont)(void *priv, BOOL succ, gid_t gid) =
671                 (void (*)(void *, BOOL, gid_t))c;
672
673         if (!success) {
674                 DEBUG(5, ("Could not trigger name2gid\n"));
675                 cont(private_data, False, 0);
676                 return;
677         }
678
679         if (response->result != WINBINDD_OK) {
680                 DEBUG(5, ("name2gid returned an error\n"));
681                 cont(private_data, False, 0);
682                 return;
683         }
684
685         cont(private_data, True, response->data.gid);
686 }
687 #endif  /* not used */
688
689 struct lookupsid_state {
690         DOM_SID sid;    
691         void *caller_private_data;
692 };
693
694
695 static void lookupsid_recv2(TALLOC_CTX *mem_ctx, BOOL success,
696                            struct winbindd_response *response,
697                            void *c, void *private_data)
698 {
699         void (*cont)(void *priv, BOOL succ, const char *dom_name,
700                      const char *name, enum lsa_SidType type) =
701                 (void (*)(void *, BOOL, const char *, const char *,
702                           enum lsa_SidType))c;
703         struct lookupsid_state *s = talloc_get_type_abort(private_data, 
704                                                           struct lookupsid_state);
705
706         if (!success) {
707                 DEBUG(5, ("Could not trigger lookupsid\n"));
708                 cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
709                 return;
710         }
711
712         if (response->result != WINBINDD_OK) {
713                 DEBUG(5, ("lookupsid (forest root) returned an error\n"));              
714                 cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
715                 return;
716         }
717
718         cont(s->caller_private_data, True, response->data.name.dom_name,
719              response->data.name.name,
720              (enum lsa_SidType)response->data.name.type);
721 }
722
723 static void lookupsid_recv(TALLOC_CTX *mem_ctx, BOOL success,
724                            struct winbindd_response *response,
725                            void *c, void *private_data)
726 {
727         void (*cont)(void *priv, BOOL succ, const char *dom_name,
728                      const char *name, enum lsa_SidType type) =
729                 (void (*)(void *, BOOL, const char *, const char *,
730                           enum lsa_SidType))c;
731         struct lookupsid_state *s = talloc_get_type_abort(private_data, 
732                                                           struct lookupsid_state);
733
734         if (!success) {
735                 DEBUG(5, ("Could not trigger lookupsid\n"));
736                 cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
737                 return;
738         }
739
740         if (response->result != WINBINDD_OK) {
741                 /* Try again using the forest root */
742                 struct winbindd_domain *root_domain = find_root_domain();
743                 struct winbindd_request request;
744                 
745                 if ( !root_domain ) {
746                         DEBUG(5,("lookupsid_recv: unable to determine forest root\n"));
747                         cont(s->caller_private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
748                         return;
749                 }
750
751                 ZERO_STRUCT(request);
752                 request.cmd = WINBINDD_LOOKUPSID;
753                 fstrcpy(request.data.sid, sid_string_static(&s->sid));
754
755                 do_async_domain(mem_ctx, root_domain, &request, lookupsid_recv2,
756                                 (void *)cont, s);
757
758                 return;
759         }
760
761         cont(s->caller_private_data, True, response->data.name.dom_name,
762              response->data.name.name,
763              (enum lsa_SidType)response->data.name.type);
764 }
765
766 void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
767                               void (*cont)(void *private_data, BOOL success,
768                                            const char *dom_name,
769                                            const char *name,
770                                            enum lsa_SidType type),
771                               void *private_data)
772 {
773         struct winbindd_domain *domain;
774         struct winbindd_request request;
775         struct lookupsid_state *s;      
776
777         domain = find_lookup_domain_from_sid(sid);
778         if (domain == NULL) {
779                 DEBUG(5, ("Could not find domain for sid %s\n",
780                           sid_string_static(sid)));
781                 cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
782                 return;
783         }
784
785         ZERO_STRUCT(request);
786         request.cmd = WINBINDD_LOOKUPSID;
787         fstrcpy(request.data.sid, sid_string_static(sid));
788
789         if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupsid_state)) == NULL ) {
790                 DEBUG(0, ("winbindd_lookupsid_async: talloc failed\n"));
791                 cont(private_data, False, NULL, NULL, SID_NAME_UNKNOWN);
792                 return;
793         }
794
795         sid_copy( &s->sid, sid );       
796         s->caller_private_data = private_data;  
797
798         do_async_domain(mem_ctx, domain, &request, lookupsid_recv,
799                         (void *)cont, s);
800 }
801
802 enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
803                                              struct winbindd_cli_state *state)
804 {
805         enum lsa_SidType type;
806         DOM_SID sid;
807         char *name;
808         char *dom_name;
809
810         /* Ensure null termination */
811         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
812
813         DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, 
814                   state->request.data.sid));
815
816         /* Lookup sid from PDC using lsa_lookup_sids() */
817
818         if (!string_to_sid(&sid, state->request.data.sid)) {
819                 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
820                 return WINBINDD_ERROR;
821         }
822
823         /* Lookup the sid */
824
825         if (!winbindd_lookup_name_by_sid(state->mem_ctx, domain, &sid, 
826                                          &dom_name, &name, &type)) 
827         {
828                 TALLOC_FREE(dom_name);
829                 TALLOC_FREE(name);
830                 return WINBINDD_ERROR;
831         }
832
833         fstrcpy(state->response.data.name.dom_name, dom_name);
834         fstrcpy(state->response.data.name.name, name);
835         state->response.data.name.type = type;
836
837         TALLOC_FREE(dom_name);
838         TALLOC_FREE(name);
839         return WINBINDD_OK;
840 }
841
842 /********************************************************************
843  This is the second callback after contacting the forest root
844 ********************************************************************/
845
846 struct lookupname_state {
847         char *dom_name;
848         char *name;
849         void *caller_private_data;
850 };
851
852
853 static void lookupname_recv2(TALLOC_CTX *mem_ctx, BOOL success,
854                             struct winbindd_response *response,
855                             void *c, void *private_data)
856 {
857         void (*cont)(void *priv, BOOL succ, const DOM_SID *sid,
858                      enum lsa_SidType type) =
859                 (void (*)(void *, BOOL, const DOM_SID *, enum lsa_SidType))c;
860         DOM_SID sid;
861         struct lookupname_state *s = talloc_get_type_abort( private_data, 
862                                                             struct lookupname_state );
863         
864
865         if (!success) {
866                 DEBUG(5, ("Could not trigger lookup_name\n"));
867                 cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
868                 return;
869         }
870
871         if (response->result != WINBINDD_OK) {
872                 DEBUG(5, ("lookup_name returned an error\n"));
873                 cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
874                 return;
875         }
876
877         if (!string_to_sid(&sid, response->data.sid.sid)) {
878                 DEBUG(0, ("Could not convert string %s to sid\n",
879                           response->data.sid.sid));
880                 cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
881                 return;
882         }
883
884         cont(s->caller_private_data, True, &sid,
885              (enum lsa_SidType)response->data.sid.type);
886 }
887
888 /********************************************************************
889  This is the first callback after contacting our own domain 
890 ********************************************************************/
891
892 static void lookupname_recv(TALLOC_CTX *mem_ctx, BOOL success,
893                             struct winbindd_response *response,
894                             void *c, void *private_data)
895 {
896         void (*cont)(void *priv, BOOL succ, const DOM_SID *sid,
897                      enum lsa_SidType type) =
898                 (void (*)(void *, BOOL, const DOM_SID *, enum lsa_SidType))c;
899         DOM_SID sid;
900         struct lookupname_state *s = talloc_get_type_abort( private_data, 
901                                                             struct lookupname_state );  
902
903         if (!success) {
904                 DEBUG(5, ("lookupname_recv: lookup_name() failed!\n"));
905                 cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
906                 return;
907         }
908
909         if (response->result != WINBINDD_OK) {
910                 /* Try again using the forest root */
911                 struct winbindd_domain *root_domain = find_root_domain();
912                 struct winbindd_request request;                
913                 
914                 if ( !root_domain ) {
915                         DEBUG(5,("lookupname_recv: unable to determine forest root\n"));
916                         cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
917                         return;
918                 }
919
920                 ZERO_STRUCT(request);
921                 request.cmd = WINBINDD_LOOKUPNAME;
922
923                 fstrcpy( request.data.name.dom_name, s->dom_name );
924                 fstrcpy( request.data.name.name, s->name );             
925
926                 do_async_domain(mem_ctx, root_domain, &request, lookupname_recv2,
927                                 (void *)cont, s);
928
929                 return;
930         }
931
932         if (!string_to_sid(&sid, response->data.sid.sid)) {
933                 DEBUG(0, ("Could not convert string %s to sid\n",
934                           response->data.sid.sid));
935                 cont(s->caller_private_data, False, NULL, SID_NAME_UNKNOWN);
936                 return;
937         }
938
939         cont(s->caller_private_data, True, &sid,
940              (enum lsa_SidType)response->data.sid.type);
941 }
942
943 /********************************************************************
944  The lookup name call first contacts a DC in its own domain
945  and fallbacks to contact a DC in the forest in our domain doesn't
946  know the name.
947 ********************************************************************/
948
949 void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
950                                const char *dom_name, const char *name,
951                                void (*cont)(void *private_data, BOOL success,
952                                             const DOM_SID *sid,
953                                             enum lsa_SidType type),
954                                enum winbindd_cmd orig_cmd,
955                                void *private_data)
956 {
957         struct winbindd_request request;
958         struct winbindd_domain *domain;
959         struct lookupname_state *s;     
960
961         if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
962                 DEBUG(5, ("Could not find domain for name %s\n", dom_name));
963                 cont(private_data, False, NULL, SID_NAME_UNKNOWN);
964                 return;
965         }
966
967         ZERO_STRUCT(request);
968         request.cmd = WINBINDD_LOOKUPNAME;
969         request.original_cmd = orig_cmd;
970         fstrcpy(request.data.name.dom_name, dom_name);
971         fstrcpy(request.data.name.name, name);
972
973         if ( (s = TALLOC_ZERO_P(mem_ctx, struct lookupname_state)) == NULL ) {
974                 DEBUG(0, ("winbindd_lookupname_async: talloc failed\n"));
975                 cont(private_data, False, NULL, SID_NAME_UNKNOWN);
976                 return;
977         }
978
979         s->dom_name = talloc_strdup( s, dom_name );
980         s->name     = talloc_strdup( s, name );
981         s->caller_private_data = private_data;
982
983         do_async_domain(mem_ctx, domain, &request, lookupname_recv,
984                         (void *)cont, s);
985 }
986
987 enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
988                                               struct winbindd_cli_state *state)
989 {
990         enum lsa_SidType type;
991         char *name_domain, *name_user;
992         DOM_SID sid;
993         char *p;
994
995         /* Ensure null termination */
996         state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
997
998         /* Ensure null termination */
999         state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
1000
1001         /* cope with the name being a fully qualified name */
1002         p = strstr(state->request.data.name.name, lp_winbind_separator());
1003         if (p) {
1004                 *p = 0;
1005                 name_domain = state->request.data.name.name;
1006                 name_user = p+1;
1007         } else {
1008                 name_domain = state->request.data.name.dom_name;
1009                 name_user = state->request.data.name.name;
1010         }
1011
1012         DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
1013                   name_domain, lp_winbind_separator(), name_user));
1014
1015         /* Lookup name from DC using lsa_lookup_names() */
1016         if (!winbindd_lookup_sid_by_name(state->mem_ctx, state->request.original_cmd, domain, name_domain,
1017                                          name_user, &sid, &type)) {
1018                 return WINBINDD_ERROR;
1019         }
1020
1021         sid_to_string(state->response.data.sid.sid, &sid);
1022         state->response.data.sid.type = type;
1023
1024         return WINBINDD_OK;
1025 }
1026
1027 BOOL print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
1028                    size_t num_sids, char **result, ssize_t *len)
1029 {
1030         size_t i;
1031         size_t buflen = 0;
1032
1033         *len = 0;
1034         *result = NULL;
1035         for (i=0; i<num_sids; i++) {
1036                 sprintf_append(mem_ctx, result, len, &buflen,
1037                                "%s\n", sid_string_static(&sids[i]));
1038         }
1039
1040         if ((num_sids != 0) && (*result == NULL)) {
1041                 return False;
1042         }
1043
1044         return True;
1045 }
1046
1047 static BOOL parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
1048                           DOM_SID **sids, size_t *num_sids)
1049 {
1050         char *p, *q;
1051
1052         p = sidstr;
1053         if (p == NULL)
1054                 return False;
1055
1056         while (p[0] != '\0') {
1057                 DOM_SID sid;
1058                 q = strchr(p, '\n');
1059                 if (q == NULL) {
1060                         DEBUG(0, ("Got invalid sidstr: %s\n", p));
1061                         return False;
1062                 }
1063                 *q = '\0';
1064                 q += 1;
1065                 if (!string_to_sid(&sid, p)) {
1066                         DEBUG(0, ("Could not parse sid %s\n", p));
1067                         return False;
1068                 }
1069                 if (!add_sid_to_array(mem_ctx, &sid, sids, num_sids)) {
1070                         return False;
1071                 }
1072                 p = q;
1073         }
1074         return True;
1075 }
1076
1077 static BOOL parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
1078                           uint32 **rids, size_t *num_rids)
1079 {
1080         char *p;
1081
1082         p = ridstr;
1083         if (p == NULL)
1084                 return False;
1085
1086         while (p[0] != '\0') {
1087                 uint32 rid;
1088                 char *q;
1089                 rid = strtoul(p, &q, 10);
1090                 if (*q != '\n') {
1091                         DEBUG(0, ("Got invalid ridstr: %s\n", p));
1092                         return False;
1093                 }
1094                 p = q+1;
1095                 ADD_TO_ARRAY(mem_ctx, uint32, rid, rids, num_rids);
1096         }
1097         return True;
1098 }
1099
1100 enum winbindd_result winbindd_dual_lookuprids(struct winbindd_domain *domain,
1101                                               struct winbindd_cli_state *state)
1102 {
1103         uint32 *rids = NULL;
1104         size_t i, buflen, num_rids = 0;
1105         ssize_t len;
1106         DOM_SID domain_sid;
1107         char *domain_name;
1108         char **names;
1109         enum lsa_SidType *types;
1110         NTSTATUS status;
1111         char *result;
1112
1113         DEBUG(10, ("Looking up RIDs for domain %s (%s)\n",
1114                    state->request.domain_name,
1115                    state->request.data.sid));
1116
1117         if (!parse_ridlist(state->mem_ctx, state->request.extra_data.data,
1118                            &rids, &num_rids)) {
1119                 DEBUG(5, ("Could not parse ridlist\n"));
1120                 return WINBINDD_ERROR;
1121         }
1122
1123         if (!string_to_sid(&domain_sid, state->request.data.sid)) {
1124                 DEBUG(5, ("Could not parse domain sid %s\n",
1125                           state->request.data.sid));
1126                 return WINBINDD_ERROR;
1127         }
1128
1129         status = domain->methods->rids_to_names(domain, state->mem_ctx,
1130                                                 &domain_sid, rids, num_rids,
1131                                                 &domain_name,
1132                                                 &names, &types);
1133
1134         if (!NT_STATUS_IS_OK(status) &&
1135             !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1136                 return WINBINDD_ERROR;
1137         }
1138
1139         len = 0;
1140         buflen = 0;
1141         result = NULL;
1142
1143         for (i=0; i<num_rids; i++) {
1144                 sprintf_append(state->mem_ctx, &result, &len, &buflen,
1145                                "%d %s\n", types[i], names[i]);
1146         }
1147
1148         fstrcpy(state->response.data.domain_name, domain_name);
1149
1150         if (result != NULL) {
1151                 state->response.extra_data.data = SMB_STRDUP(result);
1152                 if (!state->response.extra_data.data) {
1153                         return WINBINDD_ERROR;
1154                 }
1155                 state->response.length += len+1;
1156         }
1157
1158         return WINBINDD_OK;
1159 }
1160
1161 static void getsidaliases_recv(TALLOC_CTX *mem_ctx, BOOL success,
1162                                struct winbindd_response *response,
1163                                void *c, void *private_data)
1164 {
1165         void (*cont)(void *priv, BOOL succ,
1166                      DOM_SID *aliases, size_t num_aliases) =
1167                 (void (*)(void *, BOOL, DOM_SID *, size_t))c;
1168         char *aliases_str;
1169         DOM_SID *sids = NULL;
1170         size_t num_sids = 0;
1171
1172         if (!success) {
1173                 DEBUG(5, ("Could not trigger getsidaliases\n"));
1174                 cont(private_data, success, NULL, 0);
1175                 return;
1176         }
1177
1178         if (response->result != WINBINDD_OK) {
1179                 DEBUG(5, ("getsidaliases returned an error\n"));
1180                 cont(private_data, False, NULL, 0);
1181                 return;
1182         }
1183
1184         aliases_str = (char *)response->extra_data.data;
1185
1186         if (aliases_str == NULL) {
1187                 DEBUG(10, ("getsidaliases return 0 SIDs\n"));
1188                 cont(private_data, True, NULL, 0);
1189                 return;
1190         }
1191
1192         if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
1193                 DEBUG(0, ("Could not parse sids\n"));
1194                 cont(private_data, False, NULL, 0);
1195                 return;
1196         }
1197
1198         SAFE_FREE(response->extra_data.data);
1199
1200         cont(private_data, True, sids, num_sids);
1201 }
1202
1203 void winbindd_getsidaliases_async(struct winbindd_domain *domain,
1204                                   TALLOC_CTX *mem_ctx,
1205                                   const DOM_SID *sids, size_t num_sids,
1206                                   void (*cont)(void *private_data,
1207                                                BOOL success,
1208                                                const DOM_SID *aliases,
1209                                                size_t num_aliases),
1210                                   void *private_data)
1211 {
1212         struct winbindd_request request;
1213         char *sidstr = NULL;
1214         ssize_t len;
1215
1216         if (num_sids == 0) {
1217                 cont(private_data, True, NULL, 0);
1218                 return;
1219         }
1220
1221         if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr, &len)) {
1222                 cont(private_data, False, NULL, 0);
1223                 return;
1224         }
1225
1226         ZERO_STRUCT(request);
1227         request.cmd = WINBINDD_DUAL_GETSIDALIASES;
1228         request.extra_len = len;
1229         request.extra_data.data = sidstr;
1230
1231         do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
1232                         (void *)cont, private_data);
1233 }
1234
1235 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
1236                                                  struct winbindd_cli_state *state)
1237 {
1238         DOM_SID *sids = NULL;
1239         size_t num_sids = 0;
1240         char *sidstr = NULL;
1241         ssize_t len;
1242         size_t i;
1243         uint32 num_aliases;
1244         uint32 *alias_rids;
1245         NTSTATUS result;
1246
1247         DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
1248
1249         sidstr = state->request.extra_data.data;
1250         if (sidstr == NULL) {
1251                 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
1252                 if (!sidstr) {
1253                         DEBUG(0, ("Out of memory\n"));
1254                         return WINBINDD_ERROR;
1255                 }
1256         }
1257
1258         DEBUG(10, ("Sidlist: %s\n", sidstr));
1259
1260         if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
1261                 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
1262                 return WINBINDD_ERROR;
1263         }
1264
1265         num_aliases = 0;
1266         alias_rids = NULL;
1267
1268         result = domain->methods->lookup_useraliases(domain,
1269                                                      state->mem_ctx,
1270                                                      num_sids, sids,
1271                                                      &num_aliases,
1272                                                      &alias_rids);
1273
1274         if (!NT_STATUS_IS_OK(result)) {
1275                 DEBUG(3, ("Could not lookup_useraliases: %s\n",
1276                           nt_errstr(result)));
1277                 return WINBINDD_ERROR;
1278         }
1279
1280         num_sids = 0;
1281         sids = NULL;
1282         sidstr = NULL;
1283
1284         DEBUG(10, ("Got %d aliases\n", num_aliases));
1285
1286         for (i=0; i<num_aliases; i++) {
1287                 DOM_SID sid;
1288                 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
1289                 sid_copy(&sid, &domain->sid);
1290                 sid_append_rid(&sid, alias_rids[i]);
1291                 if (!add_sid_to_array(state->mem_ctx, &sid, &sids, &num_sids)) {
1292                         return WINBINDD_ERROR;
1293                 }
1294         }
1295
1296
1297         if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
1298                 DEBUG(0, ("Could not print_sidlist\n"));
1299                 state->response.extra_data.data = NULL;
1300                 return WINBINDD_ERROR;
1301         }
1302
1303         state->response.extra_data.data = NULL;
1304
1305         if (sidstr) {
1306                 state->response.extra_data.data = SMB_STRDUP(sidstr);
1307                 if (!state->response.extra_data.data) {
1308                         DEBUG(0, ("Out of memory\n"));
1309                         return WINBINDD_ERROR;
1310                 }
1311                 DEBUG(10, ("aliases_list: %s\n",
1312                            (char *)state->response.extra_data.data));
1313                 state->response.length += len+1;
1314         }
1315         
1316         return WINBINDD_OK;
1317 }
1318
1319 struct gettoken_state {
1320         TALLOC_CTX *mem_ctx;
1321         DOM_SID user_sid;
1322         struct winbindd_domain *alias_domain;
1323         struct winbindd_domain *local_alias_domain;
1324         struct winbindd_domain *builtin_domain;
1325         DOM_SID *sids;
1326         size_t num_sids;
1327         void (*cont)(void *private_data, BOOL success, DOM_SID *sids, size_t num_sids);
1328         void *private_data;
1329 };
1330
1331 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
1332                                    struct winbindd_response *response,
1333                                    void *c, void *private_data);
1334 static void gettoken_recvaliases(void *private_data, BOOL success,
1335                                  const DOM_SID *aliases,
1336                                  size_t num_aliases);
1337                                  
1338
1339 void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
1340                              void (*cont)(void *private_data, BOOL success,
1341                                           DOM_SID *sids, size_t num_sids),
1342                              void *private_data)
1343 {
1344         struct winbindd_domain *domain;
1345         struct winbindd_request request;
1346         struct gettoken_state *state;
1347
1348         state = TALLOC_ZERO_P(mem_ctx, struct gettoken_state);
1349         if (state == NULL) {
1350                 DEBUG(0, ("talloc failed\n"));
1351                 cont(private_data, False, NULL, 0);
1352                 return;
1353         }
1354
1355         state->mem_ctx = mem_ctx;
1356         sid_copy(&state->user_sid, user_sid);
1357         state->alias_domain = find_our_domain();
1358         state->local_alias_domain = find_domain_from_name( get_global_sam_name() );
1359         state->builtin_domain = find_builtin_domain();
1360         state->cont = cont;
1361         state->private_data = private_data;
1362
1363         domain = find_domain_from_sid_noinit(user_sid);
1364         if (domain == NULL) {
1365                 DEBUG(5, ("Could not find domain from SID %s\n",
1366                           sid_string_static(user_sid)));
1367                 cont(private_data, False, NULL, 0);
1368                 return;
1369         }
1370
1371         ZERO_STRUCT(request);
1372         request.cmd = WINBINDD_GETUSERDOMGROUPS;
1373         fstrcpy(request.data.sid, sid_string_static(user_sid));
1374
1375         do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
1376                         NULL, state);
1377 }
1378
1379 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, BOOL success,
1380                                    struct winbindd_response *response,
1381                                    void *c, void *private_data)
1382 {
1383         struct gettoken_state *state =
1384                 talloc_get_type_abort(private_data, struct gettoken_state);
1385         char *sids_str;
1386         
1387         if (!success) {
1388                 DEBUG(10, ("Could not get domain groups\n"));
1389                 state->cont(state->private_data, False, NULL, 0);
1390                 return;
1391         }
1392
1393         sids_str = (char *)response->extra_data.data;
1394
1395         if (sids_str == NULL) {
1396                 /* This could be normal if we are dealing with a
1397                    local user and local groups */
1398
1399                 if ( !sid_check_is_in_our_domain( &state->user_sid ) ) {
1400                         DEBUG(10, ("Received no domain groups\n"));
1401                         state->cont(state->private_data, True, NULL, 0);
1402                         return;
1403                 }
1404         }
1405
1406         state->sids = NULL;
1407         state->num_sids = 0;
1408
1409         if (!add_sid_to_array(mem_ctx, &state->user_sid, &state->sids,
1410                          &state->num_sids)) {
1411                 DEBUG(0, ("Out of memory\n"));
1412                 state->cont(state->private_data, False, NULL, 0);
1413                 return;
1414         }
1415
1416         if (sids_str && !parse_sidlist(mem_ctx, sids_str, &state->sids,
1417                            &state->num_sids)) {
1418                 DEBUG(0, ("Could not parse sids\n"));
1419                 state->cont(state->private_data, False, NULL, 0);
1420                 return;
1421         }
1422
1423         SAFE_FREE(response->extra_data.data);
1424
1425         if (state->alias_domain == NULL) {
1426                 DEBUG(10, ("Don't expand domain local groups\n"));
1427                 state->cont(state->private_data, True, state->sids,
1428                             state->num_sids);
1429                 return;
1430         }
1431
1432         winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
1433                                      state->sids, state->num_sids,
1434                                      gettoken_recvaliases, state);
1435 }
1436
1437 static void gettoken_recvaliases(void *private_data, BOOL success,
1438                                  const DOM_SID *aliases,
1439                                  size_t num_aliases)
1440 {
1441         struct gettoken_state *state = (struct gettoken_state *)private_data;
1442         size_t i;
1443
1444         if (!success) {
1445                 DEBUG(10, ("Could not receive domain local groups\n"));
1446                 state->cont(state->private_data, False, NULL, 0);
1447                 return;
1448         }
1449
1450         for (i=0; i<num_aliases; i++) {
1451                 if (!add_sid_to_array(state->mem_ctx, &aliases[i],
1452                                  &state->sids, &state->num_sids)) {
1453                         DEBUG(0, ("Out of memory\n"));
1454                         state->cont(state->private_data, False, NULL, 0);
1455                         return;
1456                 }
1457         }
1458
1459         if (state->local_alias_domain != NULL) {
1460                 struct winbindd_domain *local_domain = state->local_alias_domain;
1461                 DEBUG(10, ("Expanding our own local groups\n"));
1462                 state->local_alias_domain = NULL;
1463                 winbindd_getsidaliases_async(local_domain, state->mem_ctx,
1464                                              state->sids, state->num_sids,
1465                                              gettoken_recvaliases, state);
1466                 return;
1467         }
1468
1469         if (state->builtin_domain != NULL) {
1470                 struct winbindd_domain *builtin_domain = state->builtin_domain;
1471                 DEBUG(10, ("Expanding our own BUILTIN groups\n"));
1472                 state->builtin_domain = NULL;
1473                 winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
1474                                              state->sids, state->num_sids,
1475                                              gettoken_recvaliases, state);
1476                 return;
1477         }
1478
1479         state->cont(state->private_data, True, state->sids, state->num_sids);
1480 }
1481
1482 static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
1483                             struct winbindd_response *response,
1484                             void *c, void *private_data)
1485 {
1486         void (*cont)(void *priv, BOOL succ, const char *acct_name,
1487                      const char *full_name, const char *homedir, 
1488                      const char *shell, uint32 gid, uint32 group_rid) =
1489                 (void (*)(void *, BOOL, const char *, const char *,
1490                           const char *, const char *, uint32, uint32))c;
1491
1492         if (!success) {
1493                 DEBUG(5, ("Could not trigger query_user\n"));
1494                 cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
1495                 return;
1496         }
1497
1498         if (response->result != WINBINDD_OK) {
1499                 DEBUG(5, ("query_user returned an error\n"));
1500                 cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
1501                 return;
1502         }
1503
1504         cont(private_data, True, response->data.user_info.acct_name,
1505              response->data.user_info.full_name,
1506              response->data.user_info.homedir,
1507              response->data.user_info.shell,
1508              response->data.user_info.primary_gid,
1509              response->data.user_info.group_rid);
1510 }
1511
1512 void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1513                       const DOM_SID *sid,
1514                       void (*cont)(void *private_data, BOOL success,
1515                                    const char *acct_name,
1516                                    const char *full_name,
1517                                    const char *homedir,
1518                                    const char *shell,
1519                                    gid_t gid,
1520                                    uint32 group_rid),
1521                       void *private_data)
1522 {
1523         struct winbindd_request request;
1524         ZERO_STRUCT(request);
1525         request.cmd = WINBINDD_DUAL_USERINFO;
1526         sid_to_string(request.data.sid, sid);
1527         do_async_domain(mem_ctx, domain, &request, query_user_recv,
1528                         (void *)cont, private_data);
1529 }
1530
1531 /* The following uid2sid/gid2sid functions has been contributed by
1532  * Keith Reynolds <Keith.Reynolds@centrify.com> */
1533
1534 static void winbindd_uid2sid_recv(TALLOC_CTX *mem_ctx, BOOL success,
1535                                   struct winbindd_response *response,
1536                                   void *c, void *private_data)
1537 {
1538         void (*cont)(void *priv, BOOL succ, const char *sid) =
1539                 (void (*)(void *, BOOL, const char *))c;
1540
1541         if (!success) {
1542                 DEBUG(5, ("Could not trigger uid2sid\n"));
1543                 cont(private_data, False, NULL);
1544                 return;
1545         }
1546
1547         if (response->result != WINBINDD_OK) {
1548                 DEBUG(5, ("uid2sid returned an error\n"));
1549                 cont(private_data, False, NULL);
1550                 return;
1551         }
1552
1553         cont(private_data, True, response->data.sid.sid);
1554 }
1555
1556 void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid,
1557                             void (*cont)(void *private_data, BOOL success, const char *sid),
1558                             void *private_data)
1559 {
1560         struct winbindd_request request;
1561
1562         ZERO_STRUCT(request);
1563         request.cmd = WINBINDD_DUAL_UID2SID;
1564         request.data.uid = uid;
1565         do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv,
1566                  (void *)cont, private_data);
1567 }
1568
1569 enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
1570                                            struct winbindd_cli_state *state)
1571 {
1572         DOM_SID sid;
1573         NTSTATUS result;
1574
1575         DEBUG(3,("[%5lu]: uid to sid %lu\n",
1576                  (unsigned long)state->pid,
1577                  (unsigned long) state->request.data.uid));
1578
1579         /* Find sid for this uid and return it, possibly ask the slow remote idmap */
1580         result = idmap_uid_to_sid(&sid, state->request.data.uid);
1581
1582         if (NT_STATUS_IS_OK(result)) {
1583                 sid_to_string(state->response.data.sid.sid, &sid);
1584                 state->response.data.sid.type = SID_NAME_USER;
1585                 return WINBINDD_OK;
1586         }
1587
1588         return WINBINDD_ERROR;
1589 }
1590
1591 static void winbindd_gid2sid_recv(TALLOC_CTX *mem_ctx, BOOL success,
1592                                   struct winbindd_response *response,
1593                                   void *c, void *private_data)
1594 {
1595         void (*cont)(void *priv, BOOL succ, const char *sid) =
1596                 (void (*)(void *, BOOL, const char *))c;
1597
1598         if (!success) {
1599                 DEBUG(5, ("Could not trigger gid2sid\n"));
1600                 cont(private_data, False, NULL);
1601                 return;
1602         }
1603
1604         if (response->result != WINBINDD_OK) {
1605                 DEBUG(5, ("gid2sid returned an error\n"));
1606                 cont(private_data, False, NULL);
1607                 return;
1608         }
1609
1610         cont(private_data, True, response->data.sid.sid);
1611 }
1612
1613 void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid,
1614                             void (*cont)(void *private_data, BOOL success, const char *sid),
1615                             void *private_data)
1616 {
1617         struct winbindd_request request;
1618
1619         ZERO_STRUCT(request);
1620         request.cmd = WINBINDD_DUAL_GID2SID;
1621         request.data.gid = gid;
1622         do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv,
1623                  (void *)cont, private_data);
1624 }
1625
1626 enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
1627                                            struct winbindd_cli_state *state)
1628 {
1629         DOM_SID sid;
1630         NTSTATUS result;
1631
1632         DEBUG(3,("[%5lu]: gid %lu to sid\n",
1633                 (unsigned long)state->pid,
1634                 (unsigned long) state->request.data.gid));
1635
1636         /* Find sid for this gid and return it, possibly ask the slow remote idmap */
1637         result = idmap_gid_to_sid(&sid, state->request.data.gid);
1638
1639         if (NT_STATUS_IS_OK(result)) {
1640                 sid_to_string(state->response.data.sid.sid, &sid);
1641                 DEBUG(10, ("[%5lu]: retrieved sid: %s\n",
1642                            (unsigned long)state->pid,
1643                            state->response.data.sid.sid));
1644                 state->response.data.sid.type = SID_NAME_DOM_GRP;
1645                 return WINBINDD_OK;
1646         }
1647
1648         return WINBINDD_ERROR;
1649 }
1650
1651 static void winbindd_dump_id_maps_recv(TALLOC_CTX *mem_ctx, BOOL success,
1652                                struct winbindd_response *response,
1653                                void *c, void *private_data)
1654 {
1655         void (*cont)(void *priv, BOOL succ) =
1656                 (void (*)(void *, BOOL))c;
1657
1658         if (!success) {
1659                 DEBUG(5, ("Could not trigger a map dump\n"));
1660                 cont(private_data, False);
1661                 return;
1662         }
1663
1664         if (response->result != WINBINDD_OK) {
1665                 DEBUG(5, ("idmap dump maps returned an error\n"));
1666                 cont(private_data, False);
1667                 return;
1668         }
1669
1670         cont(private_data, True);
1671 }
1672                          
1673 void winbindd_dump_maps_async(TALLOC_CTX *mem_ctx, void *data, int size,
1674                          void (*cont)(void *private_data, BOOL success),
1675                          void *private_data)
1676 {
1677         struct winbindd_request request;
1678         ZERO_STRUCT(request);
1679         request.cmd = WINBINDD_DUAL_DUMP_MAPS;
1680         request.extra_data.data = (char *)data;
1681         request.extra_len = size;
1682         do_async(mem_ctx, idmap_child(), &request, winbindd_dump_id_maps_recv,
1683                  (void *)cont, private_data);
1684 }
1685
1686 enum winbindd_result winbindd_dual_dump_maps(struct winbindd_domain *domain,
1687                                            struct winbindd_cli_state *state)
1688 {
1689         DEBUG(3, ("[%5lu]: dual dump maps\n", (unsigned long)state->pid));
1690
1691         idmap_dump_maps((char *)state->request.extra_data.data);
1692
1693         return WINBINDD_OK;
1694 }
1695