wb-ndr: change winbindd_lookupname_async() to use winbind_lookup() TODO!!!
[metze/samba/wb-ndr.git] / source / winbindd / winbindd_async.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Async helpers for blocking functions
5
6    Copyright (C) Volker Lendecke 2005
7    Copyright (C) Gerald Carter 2006
8    
9    The helpers always consist of three functions: 
10
11    * A request setup function that takes the necessary parameters together
12      with a continuation function that is to be called upon completion
13
14    * A private continuation function that is internal only. This is to be
15      called by the lower-level functions in do_async(). Its only task is to
16      properly call the continuation function named above.
17
18    * A worker function that is called inside the appropriate child process.
19
20    This program is free software; you can redistribute it and/or modify
21    it under the terms of the GNU General Public License as published by
22    the Free Software Foundation; either version 3 of the License, or
23    (at your option) any later version.
24    
25    This program is distributed in the hope that it will be useful,
26    but WITHOUT ANY WARRANTY; without even the implied warranty of
27    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28    GNU General Public License for more details.
29    
30    You should have received a copy of the GNU General Public License
31    along with this program.  If not, see <http://www.gnu.org/licenses/>.
32 */
33
34 #include "includes.h"
35 #include "winbindd.h"
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_WINBIND
39
40 struct do_async_state {
41         TALLOC_CTX *mem_ctx;
42         struct winbindd_request request;
43         struct winbindd_response response;
44         void (*cont)(TALLOC_CTX *mem_ctx,
45                      bool success,
46                      struct winbindd_response *response,
47                      void *c, void *private_data);
48         void *c, *private_data;
49 };
50
51 static void do_async_recv(void *private_data, bool success)
52 {
53         struct do_async_state *state =
54                 talloc_get_type_abort(private_data, struct do_async_state);
55
56         state->cont(state->mem_ctx, success, &state->response,
57                     state->c, state->private_data);
58 }
59
60 void do_async(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
61               const struct winbindd_request *request,
62               void (*cont)(TALLOC_CTX *mem_ctx, bool success,
63                            struct winbindd_response *response,
64                            void *c, void *private_data),
65               void *c, void *private_data)
66 {
67         struct do_async_state *state;
68
69         state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
70         if (state == NULL) {
71                 DEBUG(0, ("talloc failed\n"));
72                 cont(mem_ctx, False, NULL, c, private_data);
73                 return;
74         }
75
76         state->mem_ctx = mem_ctx;
77         state->request = *request;
78         state->request.length = sizeof(state->request);
79         state->cont = cont;
80         state->c = c;
81         state->private_data = private_data;
82
83         async_request(mem_ctx, child, &state->request,
84                       &state->response, do_async_recv, state);
85 }
86
87 void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
88                      const struct winbindd_request *request,
89                      void (*cont)(TALLOC_CTX *mem_ctx, bool success,
90                                   struct winbindd_response *response,
91                                   void *c, void *private_data),
92                      void *c, void *private_data)
93 {
94         struct do_async_state *state;
95
96         state = TALLOC_ZERO_P(mem_ctx, struct do_async_state);
97         if (state == NULL) {
98                 DEBUG(0, ("talloc failed\n"));
99                 cont(mem_ctx, False, NULL, c, private_data);
100                 return;
101         }
102
103         state->mem_ctx = mem_ctx;
104         state->request = *request;
105         state->request.length = sizeof(state->request);
106         state->cont = cont;
107         state->c = c;
108         state->private_data = private_data;
109
110         async_domain_request(mem_ctx, domain, &state->request,
111                              &state->response, do_async_recv, state);
112 }
113
114 struct do_async_ndr_state {
115         TALLOC_CTX *mem_ctx;
116         struct winbindd_ndr_call call;
117         void (*cont)(TALLOC_CTX *mem_ctx, bool success,
118                      struct winbindd_ndr_call *call,
119                      void *private_data,
120                      void *caller_cont,
121                      void *caller_private);
122         void *private_data;
123         void *caller_cont;
124         void *caller_private;
125 };
126
127 static void do_async_ndr_recv(void *private_data, bool success)
128 {
129         struct do_async_ndr_state *state =
130                 talloc_get_type_abort(private_data, struct do_async_ndr_state);
131
132         state->cont(state->mem_ctx, success,
133                     &state->call, state->private_data,
134                     state->caller_cont, state->caller_private);
135 }
136
137 void do_async_ndr(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
138                   uint32 opnum, void *r,
139                   void (*cont)(TALLOC_CTX *mem_ctx, bool success,
140                                struct winbindd_ndr_call *call,
141                                void *private_data,
142                                void *caller_cont,
143                                void *caller_private),
144                   void *private_data,
145                   void *caller_cont,
146                   void *caller_private)
147 {
148         struct do_async_ndr_state *state;
149
150         SMB_ASSERT(opnum < ndr_table_winbind_protocol.num_calls);
151
152         state = TALLOC_ZERO_P(mem_ctx, struct do_async_ndr_state);
153         if (state == NULL) {
154                 DEBUG(0, ("talloc failed\n"));
155                 cont(mem_ctx, False, NULL, private_data,
156                      caller_cont, caller_private);
157                 return;
158         }
159
160         state->mem_ctx = mem_ctx;
161         state->call.ndr.call = &ndr_table_winbind_protocol.calls[opnum];
162         state->call.ndr.r = r;
163         state->cont = cont;
164         state->private_data = private_data;
165         state->caller_cont = caller_cont;
166         state->caller_private = caller_private;
167
168         async_ndr_call(mem_ctx, child, &state->call,
169                        do_async_ndr_recv, state);
170 }
171
172 void do_async_ndr_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
173                          uint32 opnum, void *r,
174                          void (*cont)(TALLOC_CTX *mem_ctx, bool success,
175                                       struct winbindd_ndr_call *call,
176                                       void *private_data,
177                                       void *caller_cont,
178                                       void *caller_private),
179                          void *private_data,
180                          void *caller_cont,
181                          void *caller_private)
182 {
183         struct do_async_ndr_state *state;
184
185         SMB_ASSERT(opnum < ndr_table_winbind_protocol.num_calls);
186
187         state = TALLOC_ZERO_P(mem_ctx, struct do_async_ndr_state);
188         if (state == NULL) {
189                 DEBUG(0, ("talloc failed\n"));
190                 cont(mem_ctx, False, NULL, private_data,
191                      caller_cont, caller_private);
192                 return;
193         }
194
195         state->mem_ctx = mem_ctx;
196         state->call.ndr.call = &ndr_table_winbind_protocol.calls[opnum];
197         state->call.ndr.r = r;
198         state->cont = cont;
199         state->private_data = private_data;
200         state->caller_cont = caller_cont;
201         state->caller_private = caller_private;
202
203         async_ndr_domain_call(mem_ctx, domain, &state->call,
204                               do_async_ndr_recv, state);
205 }
206
207 static void winbindd_lookupsid_recv2(TALLOC_CTX *mem_ctx, bool success,
208                                      struct winbindd_ndr_call *c,
209                                      void *_private_data,
210                                      void *_cont,
211                                      void *cont_private)
212 {
213         void (*cont)(void *priv, bool succ, const char *dom_name,
214                      const char *name, enum lsa_SidType type) =
215                 (void (*)(void *, bool, const char *, const char *,
216                           enum lsa_SidType))_cont;
217         struct winbind_lookup *r =
218                 talloc_get_type_abort(_private_data, struct winbind_lookup);
219
220         if (!success) {
221                 DEBUG(5, ("Could not trigger lookup(sid2name)\n"));
222                 TALLOC_FREE(r);
223                 cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
224                 return;
225         }
226
227         if (r->out.result != WINBIND_STATUS_OK) {
228                 DEBUG(5,("lookup(sid2name) returned an error:0x%08X\n"
229                          " (root domain)\n", r->out.result));
230                 TALLOC_FREE(r);
231                 cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
232                 return;
233         }
234
235         cont(cont_private, true,
236              r->out.rep->name_info.domain_name,
237              r->out.rep->name_info.account_name,
238              r->out.rep->name_info.type);
239 }
240
241 static void winbindd_lookupsid_recv1(TALLOC_CTX *mem_ctx, bool success,
242                                      struct winbindd_ndr_call *c,
243                                      void *_private_data,
244                                      void *_cont,
245                                      void *cont_private)
246 {
247         void (*cont)(void *priv, bool succ, const char *dom_name,
248                      const char *name, enum lsa_SidType type) =
249                 (void (*)(void *, bool, const char *, const char *,
250                           enum lsa_SidType))_cont;
251         struct winbind_lookup *r =
252                 talloc_get_type_abort(_private_data, struct winbind_lookup);
253
254         if (!success) {
255                 DEBUG(5, ("Could not trigger lookup(sid2name)\n"));
256                 TALLOC_FREE(r);
257                 cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
258                 return;
259         }
260
261         if (r->out.result != WINBIND_STATUS_OK) {
262                 struct winbindd_domain *root_domain = find_root_domain();
263
264                 if ( !root_domain ) {
265                         DEBUG(5,("lookup(sid2name) returned an error:0x%08X\n"
266                                  " (no root domain as fallback)\n", r->out.result));
267
268                         TALLOC_FREE(r);
269                         cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
270                         return;
271                 }
272                 DEBUG(5,("lookup(sid2name) returned an error:0x%08X"
273                          " (fallback to root domain)\n", r->out.result));
274
275                 do_async_ndr_domain(mem_ctx, root_domain,
276                                     NDR_WINBIND_LOOKUP, r,
277                                     winbindd_lookupsid_recv2, r,
278                                     (void *)cont, cont_private);
279                 return;
280         }
281
282         cont(cont_private, true,
283              r->out.rep->name_info.domain_name,
284              r->out.rep->name_info.account_name,
285              r->out.rep->name_info.type);
286 }
287
288 void winbindd_lookupsid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
289                               void (*cont)(void *private_data, bool success,
290                                            const char *dom_name,
291                                            const char *name,
292                                            enum lsa_SidType type),
293                               void *cont_private)
294 {
295         struct winbindd_domain *domain;
296         struct winbind_lookup *r = NULL;
297
298         domain = find_lookup_domain_from_sid(sid);
299         if (domain == NULL) {
300                 DEBUG(5, ("Could not find domain for sid %s\n",
301                           sid_string_dbg(sid)));
302                 cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
303                 return;
304         }
305
306         r = TALLOC_P(mem_ctx, struct winbind_lookup);
307         if (!r) goto nomem;
308         r->in.level = TALLOC_P(r, enum winbind_lookup_level);
309         if (!r->in.level) goto nomem;
310
311         *r->in.level    = WINBIND_LOOKUP_LEVEL_SID2NAME;
312         r->in.req.sid   = sid_dup_talloc(r, sid);
313         if (!r->in.req.sid) goto nomem;
314
315         do_async_ndr_domain(mem_ctx, domain,
316                             NDR_WINBIND_LOOKUP, r,
317                             winbindd_lookupsid_recv1, r,
318                             (void *)cont, cont_private);
319         return;
320 nomem:
321         TALLOC_FREE(r);
322         cont(cont_private, false, NULL, NULL, SID_NAME_UNKNOWN);
323         return;
324 }
325
326 static void ndr_child_lookup_sid2name(struct winbindd_domain *domain,
327                                       struct winbindd_cli_state *state,
328                                       struct winbind_lookup *r)
329 {
330         bool ok;
331
332         DEBUG(3, ("lookup sid2name %s\n",
333                   sid_string_dbg(r->in.req.sid)));
334
335         /* Lookup the sid */
336
337         ok = winbindd_lookup_name_by_sid(r, domain,
338                                          r->in.req.sid,
339                                          (char **)&r->out.rep->name_info.domain_name,
340                                          (char **)&r->out.rep->name_info.account_name,
341                                          &r->out.rep->name_info.type);
342         if (!ok) {
343                 DEBUG(1, ("Can't lookup name by sid\n"));
344                 r->out.result = WINBIND_STATUS_FOOBAR;
345                 return;
346         }
347
348         r->out.result = WINBIND_STATUS_OK;
349 }
350
351 static void ndr_child_lookup_name2sid(struct winbindd_domain *domain,
352                                       struct winbindd_cli_state *state,
353                                       struct winbind_lookup *r)
354 {
355         bool ok;
356         char *name_domain;
357         char *name_user;
358         char *p;
359
360         DEBUG(3, ("lookup name2sid %s\n",
361                   r->in.req.name));
362
363         name_domain = talloc_strdup(r, r->in.req.name);
364         if (!name_domain) {
365                 r->out.result = WINBIND_STATUS_NO_MEMORY;
366                 return;
367         }
368
369         /* the name must be a fully qualified name */
370         p = strstr(name_domain, lp_winbind_separator());
371         if (!p) {
372                 r->out.result = WINBIND_STATUS_INVALID_PARAMETER;
373                 return;
374         }
375
376         *p = 0;
377         name_user = p+1;
378
379         r->out.rep->sid_info.sid = TALLOC_ZERO_P(r, struct dom_sid);
380         if (!r->out.rep->sid_info.sid) {
381                 r->out.result = WINBIND_STATUS_NO_MEMORY;
382                 return;
383         }
384
385         /* Lookup name from DC using lsa_lookup_names() */
386 /* TODO: */     ok = winbindd_lookup_sid_by_name(state->mem_ctx, WINBINDD_LOOKUPNAME,
387                                          domain, name_domain, name_user,
388                                          r->out.rep->sid_info.sid,
389                                          &r->out.rep->sid_info.type);
390         if (!ok) {
391                 DEBUG(1, ("Can't lookup name by sid\n"));
392                 r->out.result = WINBIND_STATUS_FOOBAR;
393                 return;
394         }
395
396         r->out.result = WINBIND_STATUS_OK;
397 }
398
399 void winbindd_ndr_domain_child_lookup(struct winbindd_domain *domain,
400                                       struct winbindd_cli_state *state)
401 {
402         struct winbind_lookup *r;
403
404         r = talloc_get_type_abort(state->c.ndr.r,
405                                   struct winbind_lookup);
406
407         switch (*r->in.level) {
408         case WINBIND_LOOKUP_LEVEL_SID2NAME:
409                 ndr_child_lookup_sid2name(domain, state, r);
410                 return;
411
412         case WINBIND_LOOKUP_LEVEL_NAME2SID:
413                 ndr_child_lookup_name2sid(domain, state, r);
414                 return;
415         }
416
417         r->out.result = WINBIND_STATUS_UNKNOWN_LEVEL;
418         return;
419 }
420
421 /********************************************************************
422  This is the second callback after contacting the forest root
423 ********************************************************************/
424
425 static void winbindd_lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
426                                       struct winbindd_ndr_call *c,
427                                       void *_private_data,
428                                       void *_cont,
429                                       void *cont_private)
430 {
431         void (*cont)(void *priv, bool succ,
432                      const DOM_SID *sid, enum lsa_SidType type) =
433                 (void (*)(void *, bool, const DOM_SID *,
434                           enum lsa_SidType))_cont;
435         struct winbind_lookup *r =
436                 talloc_get_type_abort(_private_data, struct winbind_lookup);
437
438         if (!success) {
439                 DEBUG(5, ("Could not trigger lookup(name2sid)\n"));
440                 TALLOC_FREE(r);
441                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
442                 return;
443         }
444
445         if (r->out.result != WINBIND_STATUS_OK) {
446                 DEBUG(5,("lookup(name2sid) returned an error:0x%08X\n"
447                          " (root domain)\n", r->out.result));
448                 TALLOC_FREE(r);
449                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
450                 return;
451         }
452
453         cont(cont_private, true,
454              r->out.rep->sid_info.sid,
455              r->out.rep->sid_info.type);
456 }
457
458 /********************************************************************
459  This is the first callback after contacting our own domain
460 ********************************************************************/
461
462 static void winbindd_lookupname_recv1(TALLOC_CTX *mem_ctx, bool success,
463                                       struct winbindd_ndr_call *c,
464                                       void *_private_data,
465                                       void *_cont,
466                                       void *cont_private)
467 {
468         void (*cont)(void *priv, bool succ,
469                      const DOM_SID *sid, enum lsa_SidType type) =
470                 (void (*)(void *, bool, const DOM_SID *,
471                           enum lsa_SidType))_cont;
472         struct winbind_lookup *r =
473                 talloc_get_type_abort(_private_data, struct winbind_lookup);
474
475         if (!success) {
476                 DEBUG(5, ("Could not trigger lookup(name2sid)\n"));
477                 TALLOC_FREE(r);
478                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
479                 return;
480         }
481
482         if (r->out.result != WINBIND_STATUS_OK) {
483                 struct winbindd_domain *root_domain = find_root_domain();
484
485                 if ( !root_domain ) {
486                         DEBUG(5,("lookup(name2sid) returned an error:0x%08X\n"
487                                  " (no root domain as fallback)\n", r->out.result));
488
489                         TALLOC_FREE(r);
490                         cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
491                         return;
492                 }
493                 DEBUG(5,("lookup(name2sid) returned an error:0x%08X"
494                          " (fallback to root domain)\n", r->out.result));
495
496                 do_async_ndr_domain(mem_ctx, root_domain,
497                                     NDR_WINBIND_LOOKUP, r,
498                                     winbindd_lookupname_recv2, r,
499                                     (void *)cont, cont_private);
500                 return;
501         }
502
503         cont(cont_private, true,
504              r->out.rep->sid_info.sid,
505              r->out.rep->sid_info.type);
506 }
507
508 /********************************************************************
509  The lookup name call first contacts a DC in its own domain
510  and fallbacks to contact a DC in the forest in our domain doesn't
511  know the name.
512 ********************************************************************/
513
514 void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
515                                const char *dom_name, const char *name,
516                                void (*cont)(void *private_data, bool success,
517                                             const DOM_SID *sid,
518                                             enum lsa_SidType type),
519                                enum winbindd_cmd orig_cmd,
520                                void *cont_private)
521 {
522         struct winbindd_domain *domain;
523         struct winbind_lookup *r = NULL;
524
525         if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
526                 DEBUG(5, ("Could not find domain for name '%s'\n", dom_name));
527                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
528                 return;
529         }
530
531         r = TALLOC_P(mem_ctx, struct winbind_lookup);
532         if (!r) goto nomem;
533         r->in.level = TALLOC_P(r, enum winbind_lookup_level);
534         if (!r->in.level) goto nomem;
535
536         *r->in.level    = WINBIND_LOOKUP_LEVEL_NAME2SID;
537         r->in.req.name  = talloc_asprintf(r, "%s%s%s",
538                                           dom_name,
539                                           lp_winbind_separator(),
540                                           name);
541         if (!r->in.req.name) goto nomem;
542 /*TODO: pass down orig_cmd */
543         do_async_ndr_domain(mem_ctx, domain,
544                             NDR_WINBIND_LOOKUP, r,
545                             winbindd_lookupname_recv1, r,
546                             (void *)cont, cont_private);
547         return;
548 nomem:
549         TALLOC_FREE(r);
550         cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
551         return;
552 }
553
554 enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
555                                               struct winbindd_cli_state *state)
556 {
557         enum lsa_SidType type;
558         char *name_domain, *name_user;
559         DOM_SID sid;
560         char *p;
561
562         /* Ensure null termination */
563         state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
564
565         /* Ensure null termination */
566         state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
567
568         /* cope with the name being a fully qualified name */
569         p = strstr(state->request.data.name.name, lp_winbind_separator());
570         if (p) {
571                 *p = 0;
572                 name_domain = state->request.data.name.name;
573                 name_user = p+1;
574         } else {
575                 name_domain = state->request.data.name.dom_name;
576                 name_user = state->request.data.name.name;
577         }
578
579         DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
580                   name_domain, lp_winbind_separator(), name_user));
581
582         /* Lookup name from DC using lsa_lookup_names() */
583         if (!winbindd_lookup_sid_by_name(state->mem_ctx, state->request.original_cmd, domain, name_domain,
584                                          name_user, &sid, &type)) {
585                 return WINBINDD_ERROR;
586         }
587
588         sid_to_fstring(state->response.data.sid.sid, &sid);
589         state->response.data.sid.type = type;
590
591         return WINBINDD_OK;
592 }
593
594 bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
595                    size_t num_sids, char **result, ssize_t *len)
596 {
597         size_t i;
598         size_t buflen = 0;
599
600         *len = 0;
601         *result = NULL;
602         for (i=0; i<num_sids; i++) {
603                 fstring tmp;
604                 sprintf_append(mem_ctx, result, len, &buflen,
605                                "%s\n", sid_to_fstring(tmp, &sids[i]));
606         }
607
608         if ((num_sids != 0) && (*result == NULL)) {
609                 return False;
610         }
611
612         return True;
613 }
614
615 static bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
616                           DOM_SID **sids, size_t *num_sids)
617 {
618         char *p, *q;
619
620         p = sidstr;
621         if (p == NULL)
622                 return False;
623
624         while (p[0] != '\0') {
625                 DOM_SID sid;
626                 q = strchr(p, '\n');
627                 if (q == NULL) {
628                         DEBUG(0, ("Got invalid sidstr: %s\n", p));
629                         return False;
630                 }
631                 *q = '\0';
632                 q += 1;
633                 if (!string_to_sid(&sid, p)) {
634                         DEBUG(0, ("Could not parse sid %s\n", p));
635                         return False;
636                 }
637                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
638                                                       num_sids)))
639                 {
640                         return False;
641                 }
642                 p = q;
643         }
644         return True;
645 }
646
647 static bool parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
648                           uint32 **rids, size_t *num_rids)
649 {
650         char *p;
651
652         p = ridstr;
653         if (p == NULL)
654                 return False;
655
656         while (p[0] != '\0') {
657                 uint32 rid;
658                 char *q;
659                 rid = strtoul(p, &q, 10);
660                 if (*q != '\n') {
661                         DEBUG(0, ("Got invalid ridstr: %s\n", p));
662                         return False;
663                 }
664                 p = q+1;
665                 ADD_TO_ARRAY(mem_ctx, uint32, rid, rids, num_rids);
666         }
667         return True;
668 }
669
670 enum winbindd_result winbindd_dual_lookuprids(struct winbindd_domain *domain,
671                                               struct winbindd_cli_state *state)
672 {
673         uint32 *rids = NULL;
674         size_t i, buflen, num_rids = 0;
675         ssize_t len;
676         DOM_SID domain_sid;
677         char *domain_name;
678         char **names;
679         enum lsa_SidType *types;
680         NTSTATUS status;
681         char *result;
682
683         DEBUG(10, ("Looking up RIDs for domain %s (%s)\n",
684                    state->request.domain_name,
685                    state->request.data.sid));
686
687         if (!parse_ridlist(state->mem_ctx, state->request.extra_data.data,
688                            &rids, &num_rids)) {
689                 DEBUG(5, ("Could not parse ridlist\n"));
690                 return WINBINDD_ERROR;
691         }
692
693         if (!string_to_sid(&domain_sid, state->request.data.sid)) {
694                 DEBUG(5, ("Could not parse domain sid %s\n",
695                           state->request.data.sid));
696                 return WINBINDD_ERROR;
697         }
698
699         status = domain->methods->rids_to_names(domain, state->mem_ctx,
700                                                 &domain_sid, rids, num_rids,
701                                                 &domain_name,
702                                                 &names, &types);
703
704         if (!NT_STATUS_IS_OK(status) &&
705             !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
706                 return WINBINDD_ERROR;
707         }
708
709         len = 0;
710         buflen = 0;
711         result = NULL;
712
713         for (i=0; i<num_rids; i++) {
714                 sprintf_append(state->mem_ctx, &result, &len, &buflen,
715                                "%d %s\n", types[i], names[i]);
716         }
717
718         fstrcpy(state->response.data.domain_name, domain_name);
719
720         if (result != NULL) {
721                 state->response.extra_data.data = SMB_STRDUP(result);
722                 if (!state->response.extra_data.data) {
723                         return WINBINDD_ERROR;
724                 }
725                 state->response.length += len+1;
726         }
727
728         return WINBINDD_OK;
729 }
730
731 static void getsidaliases_recv(TALLOC_CTX *mem_ctx, bool success,
732                                struct winbindd_response *response,
733                                void *c, void *private_data)
734 {
735         void (*cont)(void *priv, bool succ,
736                      DOM_SID *aliases, size_t num_aliases) =
737                 (void (*)(void *, bool, DOM_SID *, size_t))c;
738         char *aliases_str;
739         DOM_SID *sids = NULL;
740         size_t num_sids = 0;
741
742         if (!success) {
743                 DEBUG(5, ("Could not trigger getsidaliases\n"));
744                 cont(private_data, success, NULL, 0);
745                 return;
746         }
747
748         if (response->result != WINBINDD_OK) {
749                 DEBUG(5, ("getsidaliases returned an error\n"));
750                 cont(private_data, False, NULL, 0);
751                 return;
752         }
753
754         aliases_str = (char *)response->extra_data.data;
755
756         if (aliases_str == NULL) {
757                 DEBUG(10, ("getsidaliases return 0 SIDs\n"));
758                 cont(private_data, True, NULL, 0);
759                 return;
760         }
761
762         if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
763                 DEBUG(0, ("Could not parse sids\n"));
764                 cont(private_data, False, NULL, 0);
765                 return;
766         }
767
768         SAFE_FREE(response->extra_data.data);
769
770         cont(private_data, True, sids, num_sids);
771 }
772
773 void winbindd_getsidaliases_async(struct winbindd_domain *domain,
774                                   TALLOC_CTX *mem_ctx,
775                                   const DOM_SID *sids, size_t num_sids,
776                                   void (*cont)(void *private_data,
777                                                bool success,
778                                                const DOM_SID *aliases,
779                                                size_t num_aliases),
780                                   void *private_data)
781 {
782         struct winbindd_request request;
783         char *sidstr = NULL;
784         ssize_t len;
785
786         if (num_sids == 0) {
787                 cont(private_data, True, NULL, 0);
788                 return;
789         }
790
791         if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr, &len)) {
792                 cont(private_data, False, NULL, 0);
793                 return;
794         }
795
796         ZERO_STRUCT(request);
797         request.cmd = WINBINDD_DUAL_GETSIDALIASES;
798         request.extra_len = len;
799         request.extra_data.data = sidstr;
800
801         do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
802                         (void *)cont, private_data);
803 }
804
805 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
806                                                  struct winbindd_cli_state *state)
807 {
808         DOM_SID *sids = NULL;
809         size_t num_sids = 0;
810         char *sidstr = NULL;
811         ssize_t len;
812         size_t i;
813         uint32 num_aliases;
814         uint32 *alias_rids;
815         NTSTATUS result;
816
817         DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
818
819         sidstr = state->request.extra_data.data;
820         if (sidstr == NULL) {
821                 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
822                 if (!sidstr) {
823                         DEBUG(0, ("Out of memory\n"));
824                         return WINBINDD_ERROR;
825                 }
826         }
827
828         DEBUG(10, ("Sidlist: %s\n", sidstr));
829
830         if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
831                 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
832                 return WINBINDD_ERROR;
833         }
834
835         num_aliases = 0;
836         alias_rids = NULL;
837
838         result = domain->methods->lookup_useraliases(domain,
839                                                      state->mem_ctx,
840                                                      num_sids, sids,
841                                                      &num_aliases,
842                                                      &alias_rids);
843
844         if (!NT_STATUS_IS_OK(result)) {
845                 DEBUG(3, ("Could not lookup_useraliases: %s\n",
846                           nt_errstr(result)));
847                 return WINBINDD_ERROR;
848         }
849
850         num_sids = 0;
851         sids = NULL;
852         sidstr = NULL;
853
854         DEBUG(10, ("Got %d aliases\n", num_aliases));
855
856         for (i=0; i<num_aliases; i++) {
857                 DOM_SID sid;
858                 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
859                 sid_copy(&sid, &domain->sid);
860                 sid_append_rid(&sid, alias_rids[i]);
861                 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
862                                           &num_sids);
863                 if (!NT_STATUS_IS_OK(result)) {
864                         return WINBINDD_ERROR;
865                 }
866         }
867
868
869         if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
870                 DEBUG(0, ("Could not print_sidlist\n"));
871                 state->response.extra_data.data = NULL;
872                 return WINBINDD_ERROR;
873         }
874
875         state->response.extra_data.data = NULL;
876
877         if (sidstr) {
878                 state->response.extra_data.data = SMB_STRDUP(sidstr);
879                 if (!state->response.extra_data.data) {
880                         DEBUG(0, ("Out of memory\n"));
881                         return WINBINDD_ERROR;
882                 }
883                 DEBUG(10, ("aliases_list: %s\n",
884                            (char *)state->response.extra_data.data));
885                 state->response.length += len+1;
886         }
887         
888         return WINBINDD_OK;
889 }
890
891 struct gettoken_state {
892         TALLOC_CTX *mem_ctx;
893         DOM_SID user_sid;
894         struct winbindd_domain *alias_domain;
895         struct winbindd_domain *local_alias_domain;
896         struct winbindd_domain *builtin_domain;
897         DOM_SID *sids;
898         size_t num_sids;
899         void (*cont)(void *private_data, bool success, DOM_SID *sids, size_t num_sids);
900         void *private_data;
901 };
902
903 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
904                                    struct winbindd_response *response,
905                                    void *c, void *private_data);
906 static void gettoken_recvaliases(void *private_data, bool success,
907                                  const DOM_SID *aliases,
908                                  size_t num_aliases);
909                                  
910
911 void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
912                              void (*cont)(void *private_data, bool success,
913                                           DOM_SID *sids, size_t num_sids),
914                              void *private_data)
915 {
916         struct winbindd_domain *domain;
917         struct winbindd_request request;
918         struct gettoken_state *state;
919
920         state = TALLOC_ZERO_P(mem_ctx, struct gettoken_state);
921         if (state == NULL) {
922                 DEBUG(0, ("talloc failed\n"));
923                 cont(private_data, False, NULL, 0);
924                 return;
925         }
926
927         state->mem_ctx = mem_ctx;
928         sid_copy(&state->user_sid, user_sid);
929         state->alias_domain = find_our_domain();
930         state->local_alias_domain = find_domain_from_name( get_global_sam_name() );
931         state->builtin_domain = find_builtin_domain();
932         state->cont = cont;
933         state->private_data = private_data;
934
935         domain = find_domain_from_sid_noinit(user_sid);
936         if (domain == NULL) {
937                 DEBUG(5, ("Could not find domain from SID %s\n",
938                           sid_string_dbg(user_sid)));
939                 cont(private_data, False, NULL, 0);
940                 return;
941         }
942
943         ZERO_STRUCT(request);
944         request.cmd = WINBINDD_GETUSERDOMGROUPS;
945         sid_to_fstring(request.data.sid, user_sid);
946
947         do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
948                         NULL, state);
949 }
950
951 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
952                                    struct winbindd_response *response,
953                                    void *c, void *private_data)
954 {
955         struct gettoken_state *state =
956                 talloc_get_type_abort(private_data, struct gettoken_state);
957         char *sids_str;
958         
959         if (!success) {
960                 DEBUG(10, ("Could not get domain groups\n"));
961                 state->cont(state->private_data, False, NULL, 0);
962                 return;
963         }
964
965         sids_str = (char *)response->extra_data.data;
966
967         if (sids_str == NULL) {
968                 /* This could be normal if we are dealing with a
969                    local user and local groups */
970
971                 if ( !sid_check_is_in_our_domain( &state->user_sid ) ) {
972                         DEBUG(10, ("Received no domain groups\n"));
973                         state->cont(state->private_data, True, NULL, 0);
974                         return;
975                 }
976         }
977
978         state->sids = NULL;
979         state->num_sids = 0;
980
981         if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &state->user_sid,
982                                               &state->sids, &state->num_sids)))
983         {
984                 DEBUG(0, ("Out of memory\n"));
985                 state->cont(state->private_data, False, NULL, 0);
986                 return;
987         }
988
989         if (sids_str && !parse_sidlist(mem_ctx, sids_str, &state->sids,
990                            &state->num_sids)) {
991                 DEBUG(0, ("Could not parse sids\n"));
992                 state->cont(state->private_data, False, NULL, 0);
993                 return;
994         }
995
996         SAFE_FREE(response->extra_data.data);
997
998         if (state->alias_domain == NULL) {
999                 DEBUG(10, ("Don't expand domain local groups\n"));
1000                 state->cont(state->private_data, True, state->sids,
1001                             state->num_sids);
1002                 return;
1003         }
1004
1005         winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
1006                                      state->sids, state->num_sids,
1007                                      gettoken_recvaliases, state);
1008 }
1009
1010 static void gettoken_recvaliases(void *private_data, bool success,
1011                                  const DOM_SID *aliases,
1012                                  size_t num_aliases)
1013 {
1014         struct gettoken_state *state = (struct gettoken_state *)private_data;
1015         size_t i;
1016
1017         if (!success) {
1018                 DEBUG(10, ("Could not receive domain local groups\n"));
1019                 state->cont(state->private_data, False, NULL, 0);
1020                 return;
1021         }
1022
1023         for (i=0; i<num_aliases; i++) {
1024                 if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx,
1025                                                       &aliases[i],
1026                                                       &state->sids,
1027                                                       &state->num_sids)))
1028                 {
1029                         DEBUG(0, ("Out of memory\n"));
1030                         state->cont(state->private_data, False, NULL, 0);
1031                         return;
1032                 }
1033         }
1034
1035         if (state->local_alias_domain != NULL) {
1036                 struct winbindd_domain *local_domain = state->local_alias_domain;
1037                 DEBUG(10, ("Expanding our own local groups\n"));
1038                 state->local_alias_domain = NULL;
1039                 winbindd_getsidaliases_async(local_domain, state->mem_ctx,
1040                                              state->sids, state->num_sids,
1041                                              gettoken_recvaliases, state);
1042                 return;
1043         }
1044
1045         if (state->builtin_domain != NULL) {
1046                 struct winbindd_domain *builtin_domain = state->builtin_domain;
1047                 DEBUG(10, ("Expanding our own BUILTIN groups\n"));
1048                 state->builtin_domain = NULL;
1049                 winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
1050                                              state->sids, state->num_sids,
1051                                              gettoken_recvaliases, state);
1052                 return;
1053         }
1054
1055         state->cont(state->private_data, True, state->sids, state->num_sids);
1056 }
1057
1058 static void query_user_recv(TALLOC_CTX *mem_ctx, bool success,
1059                             struct winbindd_response *response,
1060                             void *c, void *private_data)
1061 {
1062         void (*cont)(void *priv, bool succ, const char *acct_name,
1063                      const char *full_name, const char *homedir, 
1064                      const char *shell, uint32 gid, uint32 group_rid) =
1065                 (void (*)(void *, bool, const char *, const char *,
1066                           const char *, const char *, uint32, uint32))c;
1067
1068         if (!success) {
1069                 DEBUG(5, ("Could not trigger query_user\n"));
1070                 cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
1071                 return;
1072         }
1073
1074         if (response->result != WINBINDD_OK) {
1075                 DEBUG(5, ("query_user returned an error\n"));
1076                 cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
1077                 return;
1078         }
1079
1080         cont(private_data, True, response->data.user_info.acct_name,
1081              response->data.user_info.full_name,
1082              response->data.user_info.homedir,
1083              response->data.user_info.shell,
1084              response->data.user_info.primary_gid,
1085              response->data.user_info.group_rid);
1086 }
1087
1088 void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1089                       const DOM_SID *sid,
1090                       void (*cont)(void *private_data, bool success,
1091                                    const char *acct_name,
1092                                    const char *full_name,
1093                                    const char *homedir,
1094                                    const char *shell,
1095                                    gid_t gid,
1096                                    uint32 group_rid),
1097                       void *private_data)
1098 {
1099         struct winbindd_request request;
1100         ZERO_STRUCT(request);
1101         request.cmd = WINBINDD_DUAL_USERINFO;
1102         sid_to_fstring(request.data.sid, sid);
1103         do_async_domain(mem_ctx, domain, &request, query_user_recv,
1104                         (void *)cont, private_data);
1105 }