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