wb-ndr: implement WINBIND_LOOKUP_LEVEL_SID2DOMGROUPS
[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 static void ndr_child_lookup_rids2names(struct winbindd_domain *domain,
400                                         struct winbindd_cli_state *state,
401                                         struct winbind_lookup *r)
402 {
403         char *domain_name;
404         char **names;
405         enum lsa_SidType *types;
406         NTSTATUS status;
407         uint32_t i;
408         struct winbind_lookup_name_info *n;
409
410         DEBUG(3, ("lookup rids2name domain:%s  num %u\n",
411                   sid_string_dbg(r->in.req.rids.domain_sid),
412                   r->in.req.rids.num_rids));
413
414
415         status = domain->methods->rids_to_names(domain, state->mem_ctx,
416                                                 r->in.req.rids.domain_sid,
417                                                 r->in.req.rids.rids,
418                                                 r->in.req.rids.num_rids,
419                                                 &domain_name,
420                                                 &names, &types);
421
422         if (!NT_STATUS_IS_OK(status) &&
423             !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
424                 DEBUG(1, ("Can't lookup names by rids: %s\n",
425                           nt_errstr(status)));
426                 r->out.result = WINBIND_STATUS_FOOBAR;
427                 return;
428         }
429
430         r->out.rep->name_array.num_names = r->in.req.rids.num_rids;
431         n = talloc_array(r,
432                          struct winbind_lookup_name_info,
433                          r->out.rep->name_array.num_names);
434         if (!n) {
435                 r->out.result = WINBIND_STATUS_NO_MEMORY;
436                 return;
437         }
438         r->out.rep->name_array.names = n;
439
440         for (i=0; i < r->out.rep->name_array.num_names; i++) {
441                 n[i].domain_name        = domain_name;
442                 n[i].account_name       = names[i];
443                 n[i].type               = types[i];
444         }
445
446         r->out.result = WINBIND_STATUS_OK;
447 }
448
449 static void ndr_child_lookup_sid2userinfo(struct winbindd_domain *domain,
450                                           struct winbindd_cli_state *state,
451                                           struct winbind_lookup *r)
452 {
453         NTSTATUS status;
454         WINBIND_USERINFO user_info;
455
456         DEBUG(3, ("lookup sid2userinfo user:%s\n",
457                   sid_string_dbg(r->in.req.sid)));
458
459
460         status = domain->methods->query_user(domain, state->mem_ctx,
461                                              r->in.req.sid, &user_info);
462         if (!NT_STATUS_IS_OK(status)) {
463                 DEBUG(1, ("error getting user info for sid %s: %s\n",
464                           sid_string_dbg(r->in.req.sid), nt_errstr(status)));
465                 r->out.result = WINBIND_STATUS_FOOBAR;
466                 return;
467         }
468
469         r->out.rep->user_info.account           = user_info.acct_name;
470         r->out.rep->user_info.gecos             = user_info.full_name;
471         r->out.rep->user_info.homedir           = user_info.homedir;
472         r->out.rep->user_info.shell             = user_info.shell;
473         r->out.rep->user_info.primary_gid       = user_info.primary_gid;
474
475         if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
476                                 &r->out.rep->user_info.primary_rid)) {
477                 DEBUG(1, ("Could not extract group rid out of %s\n",
478                           sid_string_dbg(&user_info.group_sid)));
479                 r->out.result = WINBIND_STATUS_FOOBAR;
480                 return;
481         }
482
483         r->out.result = WINBIND_STATUS_OK;
484 }
485
486 static void ndr_child_lookup_sid2domgroups(struct winbindd_domain *domain,
487                                            struct winbindd_cli_state *state,
488                                            struct winbind_lookup *r)
489 {
490         NTSTATUS status;
491         struct winbind_lookup_sid_info *a;
492         struct dom_sid *groups;
493         uint32_t i, num_groups;
494
495         DEBUG(3, ("lookup sid2domgroups user:%s\n",
496                   sid_string_dbg(r->in.req.sid)));
497
498         status = domain->methods->lookup_usergroups(domain, state->mem_ctx,
499                                                     r->in.req.sid, &num_groups,
500                                                     &groups);
501         if (!NT_STATUS_IS_OK(status)) {
502                 DEBUG(1, ("error getting user domain groups info for sid %s: %s\n",
503                           sid_string_dbg(r->in.req.sid), nt_errstr(status)));
504                 r->out.result = WINBIND_STATUS_FOOBAR;
505                 return;
506         }
507
508         a = talloc_array(r, struct winbind_lookup_sid_info, num_groups);
509         if (!a) {
510                 r->out.result = WINBIND_STATUS_NO_MEMORY;
511                 return;
512         }
513
514         for (i=0; i < num_groups; i++) {
515                 a[i].sid        = &groups[i];
516                 /* TODO: get this from the backend */
517                 a[i].type       = SID_NAME_DOM_GRP;
518         }
519
520         r->out.rep->sid_array.num_sids          = num_groups;
521         r->out.rep->sid_array.sids              = a;
522
523         r->out.result = WINBIND_STATUS_OK;
524 }
525
526 void winbindd_ndr_domain_child_lookup(struct winbindd_domain *domain,
527                                       struct winbindd_cli_state *state)
528 {
529         struct winbind_lookup *r;
530
531         r = talloc_get_type_abort(state->c.ndr.r,
532                                   struct winbind_lookup);
533
534         switch (*r->in.level) {
535         case WINBIND_LOOKUP_LEVEL_SID2NAME:
536                 ndr_child_lookup_sid2name(domain, state, r);
537                 return;
538
539         case WINBIND_LOOKUP_LEVEL_NAME2SID:
540                 ndr_child_lookup_name2sid(domain, state, r);
541                 return;
542
543         case WINBIND_LOOKUP_LEVEL_RIDS2NAMES:
544                 ndr_child_lookup_rids2names(domain, state, r);
545                 return;
546
547         case WINBIND_LOOKUP_LEVEL_SID2USERINFO:
548                 ndr_child_lookup_sid2userinfo(domain, state, r);
549                 return;
550
551         case WINBIND_LOOKUP_LEVEL_SID2DOMGROUPS:
552                 ndr_child_lookup_sid2domgroups(domain, state, r);
553                 return;
554         }
555
556         r->out.result = WINBIND_STATUS_UNKNOWN_LEVEL;
557         return;
558 }
559
560 /********************************************************************
561  This is the second callback after contacting the forest root
562 ********************************************************************/
563
564 static void winbindd_lookupname_recv2(TALLOC_CTX *mem_ctx, bool success,
565                                       struct winbindd_ndr_call *c,
566                                       void *_private_data,
567                                       void *_cont,
568                                       void *cont_private)
569 {
570         void (*cont)(void *priv, bool succ,
571                      const DOM_SID *sid, enum lsa_SidType type) =
572                 (void (*)(void *, bool, const DOM_SID *,
573                           enum lsa_SidType))_cont;
574         struct winbind_lookup *r =
575                 talloc_get_type_abort(_private_data, struct winbind_lookup);
576
577         if (!success) {
578                 DEBUG(5, ("Could not trigger lookup(name2sid)\n"));
579                 TALLOC_FREE(r);
580                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
581                 return;
582         }
583
584         if (r->out.result != WINBIND_STATUS_OK) {
585                 DEBUG(5,("lookup(name2sid) returned an error:0x%08X\n"
586                          " (root domain)\n", r->out.result));
587                 TALLOC_FREE(r);
588                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
589                 return;
590         }
591
592         cont(cont_private, true,
593              r->out.rep->sid_info.sid,
594              r->out.rep->sid_info.type);
595 }
596
597 /********************************************************************
598  This is the first callback after contacting our own domain
599 ********************************************************************/
600
601 static void winbindd_lookupname_recv1(TALLOC_CTX *mem_ctx, bool success,
602                                       struct winbindd_ndr_call *c,
603                                       void *_private_data,
604                                       void *_cont,
605                                       void *cont_private)
606 {
607         void (*cont)(void *priv, bool succ,
608                      const DOM_SID *sid, enum lsa_SidType type) =
609                 (void (*)(void *, bool, const DOM_SID *,
610                           enum lsa_SidType))_cont;
611         struct winbind_lookup *r =
612                 talloc_get_type_abort(_private_data, struct winbind_lookup);
613
614         if (!success) {
615                 DEBUG(5, ("Could not trigger lookup(name2sid)\n"));
616                 TALLOC_FREE(r);
617                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
618                 return;
619         }
620
621         if (r->out.result != WINBIND_STATUS_OK) {
622                 struct winbindd_domain *root_domain = find_root_domain();
623
624                 if ( !root_domain ) {
625                         DEBUG(5,("lookup(name2sid) returned an error:0x%08X\n"
626                                  " (no root domain as fallback)\n", r->out.result));
627
628                         TALLOC_FREE(r);
629                         cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
630                         return;
631                 }
632                 DEBUG(5,("lookup(name2sid) returned an error:0x%08X"
633                          " (fallback to root domain)\n", r->out.result));
634
635                 do_async_ndr_domain(mem_ctx, root_domain,
636                                     NDR_WINBIND_LOOKUP, r,
637                                     winbindd_lookupname_recv2, r,
638                                     (void *)cont, cont_private);
639                 return;
640         }
641
642         cont(cont_private, true,
643              r->out.rep->sid_info.sid,
644              r->out.rep->sid_info.type);
645 }
646
647 /********************************************************************
648  The lookup name call first contacts a DC in its own domain
649  and fallbacks to contact a DC in the forest in our domain doesn't
650  know the name.
651 ********************************************************************/
652
653 void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
654                                const char *dom_name, const char *name,
655                                void (*cont)(void *private_data, bool success,
656                                             const DOM_SID *sid,
657                                             enum lsa_SidType type),
658                                enum winbindd_cmd orig_cmd,
659                                void *cont_private)
660 {
661         struct winbindd_domain *domain;
662         struct winbind_lookup *r = NULL;
663
664         if ( (domain = find_lookup_domain_from_name(dom_name)) == NULL ) {
665                 DEBUG(5, ("Could not find domain for name '%s'\n", dom_name));
666                 cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
667                 return;
668         }
669
670         r = TALLOC_P(mem_ctx, struct winbind_lookup);
671         if (!r) goto nomem;
672         r->in.level = TALLOC_P(r, enum winbind_lookup_level);
673         if (!r->in.level) goto nomem;
674
675         *r->in.level    = WINBIND_LOOKUP_LEVEL_NAME2SID;
676         r->in.req.name  = talloc_asprintf(r, "%s%s%s",
677                                           dom_name,
678                                           lp_winbind_separator(),
679                                           name);
680         if (!r->in.req.name) goto nomem;
681 /*TODO: pass down orig_cmd */
682         do_async_ndr_domain(mem_ctx, domain,
683                             NDR_WINBIND_LOOKUP, r,
684                             winbindd_lookupname_recv1, r,
685                             (void *)cont, cont_private);
686         return;
687 nomem:
688         TALLOC_FREE(r);
689         cont(cont_private, false, NULL, SID_NAME_UNKNOWN);
690         return;
691 }
692
693 bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
694                    size_t num_sids, char **result, ssize_t *len)
695 {
696         size_t i;
697         size_t buflen = 0;
698
699         *len = 0;
700         *result = NULL;
701         for (i=0; i<num_sids; i++) {
702                 fstring tmp;
703                 sprintf_append(mem_ctx, result, len, &buflen,
704                                "%s\n", sid_to_fstring(tmp, &sids[i]));
705         }
706
707         if ((num_sids != 0) && (*result == NULL)) {
708                 return False;
709         }
710
711         return True;
712 }
713
714 static bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr,
715                           DOM_SID **sids, size_t *num_sids)
716 {
717         char *p, *q;
718
719         p = sidstr;
720         if (p == NULL)
721                 return False;
722
723         while (p[0] != '\0') {
724                 DOM_SID sid;
725                 q = strchr(p, '\n');
726                 if (q == NULL) {
727                         DEBUG(0, ("Got invalid sidstr: %s\n", p));
728                         return False;
729                 }
730                 *q = '\0';
731                 q += 1;
732                 if (!string_to_sid(&sid, p)) {
733                         DEBUG(0, ("Could not parse sid %s\n", p));
734                         return False;
735                 }
736                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
737                                                       num_sids)))
738                 {
739                         return False;
740                 }
741                 p = q;
742         }
743         return True;
744 }
745
746 bool parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
747                    uint32 **rids, size_t *num_rids)
748 {
749         char *p;
750
751         p = ridstr;
752         if (p == NULL)
753                 return False;
754
755         while (p[0] != '\0') {
756                 uint32 rid;
757                 char *q;
758                 rid = strtoul(p, &q, 10);
759                 if (*q != '\n') {
760                         DEBUG(0, ("Got invalid ridstr: %s\n", p));
761                         return False;
762                 }
763                 p = q+1;
764                 ADD_TO_ARRAY(mem_ctx, uint32, rid, rids, num_rids);
765         }
766         return True;
767 }
768
769 static void winbindd_lookup_recv(TALLOC_CTX *mem_ctx, bool success,
770                                  struct winbindd_ndr_call *c,
771                                  void *_r,
772                                  void *_cont,
773                                  void *cont_private)
774 {
775         void (*cont)(void *priv, bool succ, struct winbind_lookup *r) =
776                 (void (*)(void *, bool, struct winbind_lookup*))_cont;
777         struct winbind_lookup *r =
778                 talloc_get_type_abort(_r, struct winbind_lookup);
779
780         if (!success) {
781                 DEBUG(5, ("Could not lookup\n"));
782                 cont(cont_private, false, r);
783                 return;
784         }
785
786         if (r->out.result != WINBIND_STATUS_OK) {
787                 DEBUG(5, ("lookup returned an error:0x%08X\n",
788                         r->out.result));
789                 cont(cont_private, false, r);
790                 return;
791         }
792
793         cont(cont_private, true, r);
794 }
795
796 void winbindd_lookup_async(TALLOC_CTX *mem_ctx,
797                            struct winbindd_domain *domain,
798                            struct winbind_lookup *r,
799                            void (*cont)(void *private_data,
800                                         bool success,
801                                         struct winbind_lookup *r),
802                            void *cont_private)
803 {
804         do_async_ndr_domain(mem_ctx, domain,
805                             NDR_WINBIND_LOOKUP, r,
806                             winbindd_lookup_recv, r,
807                             (void *)cont, cont_private);
808 }
809
810 static void getsidaliases_recv(TALLOC_CTX *mem_ctx, bool success,
811                                struct winbindd_response *response,
812                                void *c, void *private_data)
813 {
814         void (*cont)(void *priv, bool succ,
815                      DOM_SID *aliases, size_t num_aliases) =
816                 (void (*)(void *, bool, DOM_SID *, size_t))c;
817         char *aliases_str;
818         DOM_SID *sids = NULL;
819         size_t num_sids = 0;
820
821         if (!success) {
822                 DEBUG(5, ("Could not trigger getsidaliases\n"));
823                 cont(private_data, success, NULL, 0);
824                 return;
825         }
826
827         if (response->result != WINBINDD_OK) {
828                 DEBUG(5, ("getsidaliases returned an error\n"));
829                 cont(private_data, False, NULL, 0);
830                 return;
831         }
832
833         aliases_str = (char *)response->extra_data.data;
834
835         if (aliases_str == NULL) {
836                 DEBUG(10, ("getsidaliases return 0 SIDs\n"));
837                 cont(private_data, True, NULL, 0);
838                 return;
839         }
840
841         if (!parse_sidlist(mem_ctx, aliases_str, &sids, &num_sids)) {
842                 DEBUG(0, ("Could not parse sids\n"));
843                 cont(private_data, False, NULL, 0);
844                 return;
845         }
846
847         SAFE_FREE(response->extra_data.data);
848
849         cont(private_data, True, sids, num_sids);
850 }
851
852 void winbindd_getsidaliases_async(struct winbindd_domain *domain,
853                                   TALLOC_CTX *mem_ctx,
854                                   const DOM_SID *sids, size_t num_sids,
855                                   void (*cont)(void *private_data,
856                                                bool success,
857                                                const DOM_SID *aliases,
858                                                size_t num_aliases),
859                                   void *private_data)
860 {
861         struct winbindd_request request;
862         char *sidstr = NULL;
863         ssize_t len;
864
865         if (num_sids == 0) {
866                 cont(private_data, True, NULL, 0);
867                 return;
868         }
869
870         if (!print_sidlist(mem_ctx, sids, num_sids, &sidstr, &len)) {
871                 cont(private_data, False, NULL, 0);
872                 return;
873         }
874
875         ZERO_STRUCT(request);
876         request.cmd = WINBINDD_DUAL_GETSIDALIASES;
877         request.extra_len = len;
878         request.extra_data.data = sidstr;
879
880         do_async_domain(mem_ctx, domain, &request, getsidaliases_recv,
881                         (void *)cont, private_data);
882 }
883
884 enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
885                                                  struct winbindd_cli_state *state)
886 {
887         DOM_SID *sids = NULL;
888         size_t num_sids = 0;
889         char *sidstr = NULL;
890         ssize_t len;
891         size_t i;
892         uint32 num_aliases;
893         uint32 *alias_rids;
894         NTSTATUS result;
895
896         DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));
897
898         sidstr = state->request.extra_data.data;
899         if (sidstr == NULL) {
900                 sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
901                 if (!sidstr) {
902                         DEBUG(0, ("Out of memory\n"));
903                         return WINBINDD_ERROR;
904                 }
905         }
906
907         DEBUG(10, ("Sidlist: %s\n", sidstr));
908
909         if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
910                 DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
911                 return WINBINDD_ERROR;
912         }
913
914         num_aliases = 0;
915         alias_rids = NULL;
916
917         result = domain->methods->lookup_useraliases(domain,
918                                                      state->mem_ctx,
919                                                      num_sids, sids,
920                                                      &num_aliases,
921                                                      &alias_rids);
922
923         if (!NT_STATUS_IS_OK(result)) {
924                 DEBUG(3, ("Could not lookup_useraliases: %s\n",
925                           nt_errstr(result)));
926                 return WINBINDD_ERROR;
927         }
928
929         num_sids = 0;
930         sids = NULL;
931         sidstr = NULL;
932
933         DEBUG(10, ("Got %d aliases\n", num_aliases));
934
935         for (i=0; i<num_aliases; i++) {
936                 DOM_SID sid;
937                 DEBUGADD(10, (" rid %d\n", alias_rids[i]));
938                 sid_copy(&sid, &domain->sid);
939                 sid_append_rid(&sid, alias_rids[i]);
940                 result = add_sid_to_array(state->mem_ctx, &sid, &sids,
941                                           &num_sids);
942                 if (!NT_STATUS_IS_OK(result)) {
943                         return WINBINDD_ERROR;
944                 }
945         }
946
947
948         if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
949                 DEBUG(0, ("Could not print_sidlist\n"));
950                 state->response.extra_data.data = NULL;
951                 return WINBINDD_ERROR;
952         }
953
954         state->response.extra_data.data = NULL;
955
956         if (sidstr) {
957                 state->response.extra_data.data = SMB_STRDUP(sidstr);
958                 if (!state->response.extra_data.data) {
959                         DEBUG(0, ("Out of memory\n"));
960                         return WINBINDD_ERROR;
961                 }
962                 DEBUG(10, ("aliases_list: %s\n",
963                            (char *)state->response.extra_data.data));
964                 state->response.length += len+1;
965         }
966         
967         return WINBINDD_OK;
968 }
969
970 struct gettoken_state {
971         TALLOC_CTX *mem_ctx;
972         DOM_SID user_sid;
973         struct winbindd_domain *alias_domain;
974         struct winbindd_domain *local_alias_domain;
975         struct winbindd_domain *builtin_domain;
976         DOM_SID *sids;
977         size_t num_sids;
978         void (*cont)(void *private_data, bool success, DOM_SID *sids, size_t num_sids);
979         void *private_data;
980 };
981
982 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
983                                    struct winbindd_response *response,
984                                    void *c, void *private_data);
985 static void gettoken_recvaliases(void *private_data, bool success,
986                                  const DOM_SID *aliases,
987                                  size_t num_aliases);
988                                  
989
990 void winbindd_gettoken_async(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid,
991                              void (*cont)(void *private_data, bool success,
992                                           DOM_SID *sids, size_t num_sids),
993                              void *private_data)
994 {
995         struct winbindd_domain *domain;
996         struct winbindd_request request;
997         struct gettoken_state *state;
998
999         state = TALLOC_ZERO_P(mem_ctx, struct gettoken_state);
1000         if (state == NULL) {
1001                 DEBUG(0, ("talloc failed\n"));
1002                 cont(private_data, False, NULL, 0);
1003                 return;
1004         }
1005
1006         state->mem_ctx = mem_ctx;
1007         sid_copy(&state->user_sid, user_sid);
1008         state->alias_domain = find_our_domain();
1009         state->local_alias_domain = find_domain_from_name( get_global_sam_name() );
1010         state->builtin_domain = find_builtin_domain();
1011         state->cont = cont;
1012         state->private_data = private_data;
1013
1014         domain = find_domain_from_sid_noinit(user_sid);
1015         if (domain == NULL) {
1016                 DEBUG(5, ("Could not find domain from SID %s\n",
1017                           sid_string_dbg(user_sid)));
1018                 cont(private_data, False, NULL, 0);
1019                 return;
1020         }
1021
1022         ZERO_STRUCT(request);
1023         request.cmd = WINBINDD_GETUSERDOMGROUPS;
1024         sid_to_fstring(request.data.sid, user_sid);
1025
1026         do_async_domain(mem_ctx, domain, &request, gettoken_recvdomgroups,
1027                         NULL, state);
1028 }
1029
1030 static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success,
1031                                    struct winbindd_response *response,
1032                                    void *c, void *private_data)
1033 {
1034         struct gettoken_state *state =
1035                 talloc_get_type_abort(private_data, struct gettoken_state);
1036         char *sids_str;
1037         
1038         if (!success) {
1039                 DEBUG(10, ("Could not get domain groups\n"));
1040                 state->cont(state->private_data, False, NULL, 0);
1041                 return;
1042         }
1043
1044         sids_str = (char *)response->extra_data.data;
1045
1046         if (sids_str == NULL) {
1047                 /* This could be normal if we are dealing with a
1048                    local user and local groups */
1049
1050                 if ( !sid_check_is_in_our_domain( &state->user_sid ) ) {
1051                         DEBUG(10, ("Received no domain groups\n"));
1052                         state->cont(state->private_data, True, NULL, 0);
1053                         return;
1054                 }
1055         }
1056
1057         state->sids = NULL;
1058         state->num_sids = 0;
1059
1060         if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &state->user_sid,
1061                                               &state->sids, &state->num_sids)))
1062         {
1063                 DEBUG(0, ("Out of memory\n"));
1064                 state->cont(state->private_data, False, NULL, 0);
1065                 return;
1066         }
1067
1068         if (sids_str && !parse_sidlist(mem_ctx, sids_str, &state->sids,
1069                            &state->num_sids)) {
1070                 DEBUG(0, ("Could not parse sids\n"));
1071                 state->cont(state->private_data, False, NULL, 0);
1072                 return;
1073         }
1074
1075         SAFE_FREE(response->extra_data.data);
1076
1077         if (state->alias_domain == NULL) {
1078                 DEBUG(10, ("Don't expand domain local groups\n"));
1079                 state->cont(state->private_data, True, state->sids,
1080                             state->num_sids);
1081                 return;
1082         }
1083
1084         winbindd_getsidaliases_async(state->alias_domain, mem_ctx,
1085                                      state->sids, state->num_sids,
1086                                      gettoken_recvaliases, state);
1087 }
1088
1089 static void gettoken_recvaliases(void *private_data, bool success,
1090                                  const DOM_SID *aliases,
1091                                  size_t num_aliases)
1092 {
1093         struct gettoken_state *state = (struct gettoken_state *)private_data;
1094         size_t i;
1095
1096         if (!success) {
1097                 DEBUG(10, ("Could not receive domain local groups\n"));
1098                 state->cont(state->private_data, False, NULL, 0);
1099                 return;
1100         }
1101
1102         for (i=0; i<num_aliases; i++) {
1103                 if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx,
1104                                                       &aliases[i],
1105                                                       &state->sids,
1106                                                       &state->num_sids)))
1107                 {
1108                         DEBUG(0, ("Out of memory\n"));
1109                         state->cont(state->private_data, False, NULL, 0);
1110                         return;
1111                 }
1112         }
1113
1114         if (state->local_alias_domain != NULL) {
1115                 struct winbindd_domain *local_domain = state->local_alias_domain;
1116                 DEBUG(10, ("Expanding our own local groups\n"));
1117                 state->local_alias_domain = NULL;
1118                 winbindd_getsidaliases_async(local_domain, state->mem_ctx,
1119                                              state->sids, state->num_sids,
1120                                              gettoken_recvaliases, state);
1121                 return;
1122         }
1123
1124         if (state->builtin_domain != NULL) {
1125                 struct winbindd_domain *builtin_domain = state->builtin_domain;
1126                 DEBUG(10, ("Expanding our own BUILTIN groups\n"));
1127                 state->builtin_domain = NULL;
1128                 winbindd_getsidaliases_async(builtin_domain, state->mem_ctx,
1129                                              state->sids, state->num_sids,
1130                                              gettoken_recvaliases, state);
1131                 return;
1132         }
1133
1134         state->cont(state->private_data, True, state->sids, state->num_sids);
1135 }
1136
1137 static void query_user_recv(TALLOC_CTX *mem_ctx, bool success,
1138                             struct winbindd_ndr_call *c,
1139                             void *_private_data,
1140                             void *_cont,
1141                             void *cont_private)
1142 {
1143         void (*cont)(void *private_data, bool success,
1144                      const char *acct_name,
1145                      const char *full_name,
1146                      const char *homedir,
1147                      const char *shell,
1148                      gid_t gid,
1149                      uint32 group_rid) =
1150                 (void (*)(void *, bool, const char *, const char *,
1151                         const char *,const char *, gid_t, uint32_t))_cont;
1152         struct winbind_lookup *r =
1153                 talloc_get_type_abort(_private_data, struct winbind_lookup);
1154
1155         if (!success) {
1156                 DEBUG(5, ("Could not trigger lookup(sid2userinfo)\n"));
1157                 TALLOC_FREE(r);
1158                 cont(cont_private, false, NULL, NULL, NULL, NULL, (gid_t)-1, 0);
1159                 return;
1160         }
1161
1162         if (r->out.result != WINBIND_STATUS_OK) {
1163                 DEBUG(5, ("Could not trigger lookup(sid2userinfo): 0x%08X\n",
1164                         r->out.result));
1165                 TALLOC_FREE(r);
1166                 cont(cont_private, false, NULL, NULL, NULL, NULL, (gid_t)-1, 0);
1167                 return;
1168         }
1169
1170         cont(cont_private, true,
1171              r->out.rep->user_info.account,
1172              r->out.rep->user_info.gecos,
1173              r->out.rep->user_info.homedir,
1174              r->out.rep->user_info.shell,
1175              r->out.rep->user_info.primary_gid,
1176              r->out.rep->user_info.primary_rid);
1177 }
1178
1179 void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1180                       const DOM_SID *sid,
1181                       void (*cont)(void *private_data, bool success,
1182                                    const char *acct_name,
1183                                    const char *full_name,
1184                                    const char *homedir,
1185                                    const char *shell,
1186                                    gid_t gid,
1187                                    uint32 group_rid),
1188                       void *private_data)
1189 {
1190         struct winbind_lookup *r = NULL;
1191
1192         r = TALLOC_P(mem_ctx, struct winbind_lookup);
1193         if (!r) goto nomem;
1194         r->in.level = TALLOC_P(r, enum winbind_lookup_level);
1195         if (!r->in.level) goto nomem;
1196
1197         *r->in.level    = WINBIND_LOOKUP_LEVEL_SID2USERINFO;
1198         r->in.req.sid   = sid_dup_talloc(r, sid);
1199         if (!r->in.req.sid) goto nomem;
1200
1201         do_async_ndr_domain(mem_ctx, domain,
1202                             NDR_WINBIND_LOOKUP, r,
1203                             query_user_recv, r,
1204                             (void *)cont, private_data);
1205         return;
1206 nomem:
1207         TALLOC_FREE(r);
1208         cont(private_data, false, NULL, NULL, NULL, NULL, (gid_t)-1, 0);
1209         return;
1210 }