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