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