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