s4-winbind: Add support for the WINBINDD_LIST_GROUPS command.
[kai/samba.git] / source4 / winbind / wb_samba3_cmd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main winbindd samba3 server routines
4
5    Copyright (C) Stefan Metzmacher      2005
6    Copyright (C) Volker Lendecke        2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
8    Copyright (C) Kai Blin               2009
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "winbind/wb_server.h"
26 #include "winbind/wb_async_helpers.h"
27 #include "param/param.h"
28 #include "winbind/wb_helper.h"
29 #include "libcli/composite/composite.h"
30 #include "version.h"
31 #include "librpc/gen_ndr/netlogon.h"
32 #include "libcli/security/security.h"
33 #include "auth/ntlm/pam_errors.h"
34 #include "auth/credentials/credentials.h"
35 #include "smbd/service_task.h"
36
37 /* 
38    Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
39 */
40
41 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
42                                              struct wbsrv_samba3_call *s3call)
43 {
44         struct winbindd_response *resp = &s3call->response;
45         if (!NT_STATUS_IS_OK(status)) {
46                 resp->result = WINBINDD_ERROR;
47         } else {
48                 resp->result = WINBINDD_OK;
49         }
50         
51         WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
52                                 nt_errstr(status));
53         WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
54                                 get_friendly_nt_error_msg(status));
55
56         resp->data.auth.pam_error = nt_status_to_pam(status);
57         resp->data.auth.nt_status = NT_STATUS_V(status);
58
59         wbsrv_samba3_send_reply(s3call);
60 }
61
62 /* 
63    Send of a generic reply to a Samba3 query
64 */
65
66 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
67                                         struct wbsrv_samba3_call *s3call)
68 {
69         struct winbindd_response *resp = &s3call->response;
70         if (NT_STATUS_IS_OK(status)) {
71                 resp->result = WINBINDD_OK;
72         } else {
73                 resp->result = WINBINDD_ERROR;
74         }
75
76         wbsrv_samba3_send_reply(s3call);
77 }
78
79 /* 
80    Boilerplate commands, simple queries without network traffic 
81 */
82
83 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
84 {
85         s3call->response.result                 = WINBINDD_OK;
86         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
87         return NT_STATUS_OK;
88 }
89
90 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
91 {
92         s3call->response.result                 = WINBINDD_OK;
93         s3call->response.data.info.winbind_separator = *lp_winbind_separator(s3call->wbconn->lp_ctx);
94         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
95                                 SAMBA_VERSION_STRING);
96         return NT_STATUS_OK;
97 }
98
99 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
100 {
101         s3call->response.result                 = WINBINDD_OK;
102         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
103                                 lp_workgroup(s3call->wbconn->lp_ctx));
104         return NT_STATUS_OK;
105 }
106
107 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
108 {
109         s3call->response.result                 = WINBINDD_OK;
110         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
111                                 lp_netbios_name(s3call->wbconn->lp_ctx));
112         return NT_STATUS_OK;
113 }
114
115 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
116 {
117         const char *path = s3call->wbconn->listen_socket->service->priv_socket_path;
118         s3call->response.result          = WINBINDD_OK;
119         s3call->response.extra_data.data = discard_const(path);
120
121         s3call->response.length += strlen(path) + 1;
122         return NT_STATUS_OK;
123 }
124
125 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
126 {
127         s3call->response.result                 = WINBINDD_OK;
128         return NT_STATUS_OK;
129 }
130
131 /* Plaintext authentication 
132    
133    This interface is used by ntlm_auth in it's 'basic' authentication
134    mode, as well as by pam_winbind to authenticate users where we are
135    given a plaintext password.
136 */
137
138 static void check_machacc_recv(struct composite_context *ctx);
139
140 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
141 {
142         NTSTATUS status;
143         struct cli_credentials *creds;
144         struct composite_context *ctx;
145         struct wbsrv_service *service =
146                 s3call->wbconn->listen_socket->service;
147
148         /* Create a credentials structure */
149         creds = cli_credentials_init(s3call);
150         if (creds == NULL) {
151                 return NT_STATUS_NO_MEMORY;
152         }
153
154         cli_credentials_set_conf(creds, service->task->lp_ctx);
155
156         /* Connect the machine account to the credentials */
157         status = cli_credentials_set_machine_account(creds, service->task->lp_ctx);
158         if (!NT_STATUS_IS_OK(status)) {
159                 talloc_free(creds);
160                 return status;
161         }
162
163         ctx = wb_cmd_pam_auth_send(s3call, service, creds);
164
165         if (!ctx) {
166                 talloc_free(creds);
167                 return NT_STATUS_NO_MEMORY;
168         }
169
170         ctx->async.fn = check_machacc_recv;
171         ctx->async.private_data = s3call;
172         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
173         return NT_STATUS_OK;
174 }
175
176 static void check_machacc_recv(struct composite_context *ctx)
177 {
178         struct wbsrv_samba3_call *s3call =
179                 talloc_get_type(ctx->async.private_data,
180                                 struct wbsrv_samba3_call);
181         NTSTATUS status;
182
183         status = wb_cmd_pam_auth_recv(ctx);
184
185         if (!NT_STATUS_IS_OK(status)) goto done;
186
187  done:
188         wbsrv_samba3_async_auth_epilogue(status, s3call);
189 }
190
191 /*
192   Find the name of a suitable domain controller, by query on the
193   netlogon pipe to the DC.  
194 */
195
196 static void getdcname_recv_dc(struct composite_context *ctx);
197
198 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
199 {
200         struct composite_context *ctx;
201         struct wbsrv_service *service =
202                 s3call->wbconn->listen_socket->service;
203
204         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
205
206         ctx = wb_cmd_getdcname_send(s3call, service,
207                                     s3call->request.domain_name);
208         NT_STATUS_HAVE_NO_MEMORY(ctx);
209
210         ctx->async.fn = getdcname_recv_dc;
211         ctx->async.private_data = s3call;
212         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
213         return NT_STATUS_OK;
214 }
215
216 static void getdcname_recv_dc(struct composite_context *ctx)
217 {
218         struct wbsrv_samba3_call *s3call =
219                 talloc_get_type(ctx->async.private_data,
220                                 struct wbsrv_samba3_call);
221         const char *dcname;
222         NTSTATUS status;
223
224         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
225         if (!NT_STATUS_IS_OK(status)) goto done;
226
227         s3call->response.result = WINBINDD_OK;
228         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
229
230  done:
231         wbsrv_samba3_async_epilogue(status, s3call);
232 }
233
234 /* 
235    Lookup a user's domain groups
236 */
237
238 static void userdomgroups_recv_groups(struct composite_context *ctx);
239
240 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
241 {
242         struct composite_context *ctx;
243         struct dom_sid *sid;
244
245         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
246
247         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
248         if (sid == NULL) {
249                 DEBUG(5, ("Could not parse sid %s\n",
250                           s3call->request.data.sid));
251                 return NT_STATUS_NO_MEMORY;
252         }
253
254         ctx = wb_cmd_userdomgroups_send(
255                 s3call, s3call->wbconn->listen_socket->service, sid);
256         NT_STATUS_HAVE_NO_MEMORY(ctx);
257
258         ctx->async.fn = userdomgroups_recv_groups;
259         ctx->async.private_data = s3call;
260         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
261         return NT_STATUS_OK;
262 }
263
264 static void userdomgroups_recv_groups(struct composite_context *ctx)
265 {
266         struct wbsrv_samba3_call *s3call =
267                 talloc_get_type(ctx->async.private_data,
268                                 struct wbsrv_samba3_call);
269         int i, num_sids;
270         struct dom_sid **sids;
271         char *sids_string;
272         NTSTATUS status;
273
274         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
275         if (!NT_STATUS_IS_OK(status)) goto done;
276
277         sids_string = talloc_strdup(s3call, "");
278         if (sids_string == NULL) {
279                 status = NT_STATUS_NO_MEMORY;
280                 goto done;
281         }
282
283         for (i=0; i<num_sids; i++) {
284                 sids_string = talloc_asprintf_append_buffer(
285                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
286         }
287
288         if (sids_string == NULL) {
289                 status = NT_STATUS_NO_MEMORY;
290                 goto done;
291         }
292
293         s3call->response.result = WINBINDD_OK;
294         s3call->response.extra_data.data = sids_string;
295         s3call->response.length += strlen(sids_string)+1;
296         s3call->response.data.num_entries = num_sids;
297
298  done:
299         wbsrv_samba3_async_epilogue(status, s3call);
300 }
301
302 /* 
303    Lookup the list of SIDs for a user 
304 */
305 static void usersids_recv_sids(struct composite_context *ctx);
306
307 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
308 {
309         struct composite_context *ctx;
310         struct dom_sid *sid;
311
312         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
313
314         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
315         if (sid == NULL) {
316                 DEBUG(5, ("Could not parse sid %s\n",
317                           s3call->request.data.sid));
318                 return NT_STATUS_NO_MEMORY;
319         }
320
321         ctx = wb_cmd_usersids_send(
322                 s3call, s3call->wbconn->listen_socket->service, sid);
323         NT_STATUS_HAVE_NO_MEMORY(ctx);
324
325         ctx->async.fn = usersids_recv_sids;
326         ctx->async.private_data = s3call;
327         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
328         return NT_STATUS_OK;
329 }
330
331 static void usersids_recv_sids(struct composite_context *ctx)
332 {
333         struct wbsrv_samba3_call *s3call =
334                 talloc_get_type(ctx->async.private_data,
335                                 struct wbsrv_samba3_call);
336         int i, num_sids;
337         struct dom_sid **sids;
338         char *sids_string;
339         NTSTATUS status;
340
341         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
342         if (!NT_STATUS_IS_OK(status)) goto done;
343
344         sids_string = talloc_strdup(s3call, "");
345         if (sids_string == NULL) {
346                 status = NT_STATUS_NO_MEMORY;
347                 goto done;
348         }
349
350         for (i=0; i<num_sids; i++) {
351                 sids_string = talloc_asprintf_append_buffer(
352                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
353                 if (sids_string == NULL) {
354                         status = NT_STATUS_NO_MEMORY;
355                         goto done;
356                 }
357         }
358
359         s3call->response.result = WINBINDD_OK;
360         s3call->response.extra_data.data = sids_string;
361         s3call->response.length += strlen(sids_string);
362         s3call->response.data.num_entries = num_sids;
363
364         /* Hmmmm. Nasty protocol -- who invented the zeros between the
365          * SIDs? Hmmm. Could have been me -- vl */
366
367         while (*sids_string != '\0') {
368                 if ((*sids_string) == '\n') {
369                         *sids_string = '\0';
370                 }
371                 sids_string += 1;
372         }
373
374  done:
375         wbsrv_samba3_async_epilogue(status, s3call);
376 }
377
378 /* 
379    Lookup a DOMAIN\\user style name, and return a SID
380 */
381
382 static void lookupname_recv_sid(struct composite_context *ctx);
383
384 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
385 {
386         struct composite_context *ctx;
387         struct wbsrv_service *service =
388                 s3call->wbconn->listen_socket->service;
389
390         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
391
392         ctx = wb_cmd_lookupname_send(s3call, service,
393                                      s3call->request.data.name.dom_name,
394                                      s3call->request.data.name.name);
395         NT_STATUS_HAVE_NO_MEMORY(ctx);
396
397         /* setup the callbacks */
398         ctx->async.fn = lookupname_recv_sid;
399         ctx->async.private_data = s3call;
400         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
401         return NT_STATUS_OK;
402 }
403
404 static void lookupname_recv_sid(struct composite_context *ctx)
405 {
406         struct wbsrv_samba3_call *s3call =
407                 talloc_get_type(ctx->async.private_data,
408                                 struct wbsrv_samba3_call);
409         struct wb_sid_object *sid;
410         NTSTATUS status;
411
412         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
413         if (!NT_STATUS_IS_OK(status)) goto done;
414
415         s3call->response.result = WINBINDD_OK;
416         s3call->response.data.sid.type = sid->type;
417         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
418                                 dom_sid_string(s3call, sid->sid));
419
420  done:
421         wbsrv_samba3_async_epilogue(status, s3call);
422 }
423
424 /* 
425    Lookup a SID, and return a DOMAIN\\user style name
426 */
427
428 static void lookupsid_recv_name(struct composite_context *ctx);
429
430 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
431 {
432         struct composite_context *ctx;
433         struct wbsrv_service *service =
434                 s3call->wbconn->listen_socket->service;
435         struct dom_sid *sid;
436
437         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
438
439         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
440         if (sid == NULL) {
441                 DEBUG(5, ("Could not parse sid %s\n",
442                           s3call->request.data.sid));
443                 return NT_STATUS_NO_MEMORY;
444         }
445
446         ctx = wb_cmd_lookupsid_send(s3call, service, sid);
447         NT_STATUS_HAVE_NO_MEMORY(ctx);
448
449         /* setup the callbacks */
450         ctx->async.fn = lookupsid_recv_name;
451         ctx->async.private_data = s3call;
452         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
453         return NT_STATUS_OK;
454 }
455
456 static void lookupsid_recv_name(struct composite_context *ctx)
457 {
458         struct wbsrv_samba3_call *s3call =
459                 talloc_get_type(ctx->async.private_data,
460                                 struct wbsrv_samba3_call);
461         struct wb_sid_object *sid;
462         NTSTATUS status;
463
464         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
465         if (!NT_STATUS_IS_OK(status)) goto done;
466
467         s3call->response.result = WINBINDD_OK;
468         s3call->response.data.name.type = sid->type;
469         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
470                                 sid->domain);
471         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
472
473  done:
474         wbsrv_samba3_async_epilogue(status, s3call);
475 }
476
477 /*
478   Challenge-response authentication.  This interface is used by
479   ntlm_auth and the smbd auth subsystem to pass NTLM authentication
480   requests along a common pipe to the domain controller.  
481
482   The return value (in the async reply) may include the 'info3'
483   (effectivly most things you would want to know about the user), or
484   the NT and LM session keys seperated.
485 */
486
487 static void pam_auth_crap_recv(struct composite_context *ctx);
488
489 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
490 {
491         struct composite_context *ctx;
492         struct wbsrv_service *service =
493                 s3call->wbconn->listen_socket->service;
494         DATA_BLOB chal, nt_resp, lm_resp;
495
496         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
497
498         chal.data       = s3call->request.data.auth_crap.chal;
499         chal.length     = sizeof(s3call->request.data.auth_crap.chal);
500         nt_resp.data    = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
501         nt_resp.length  = s3call->request.data.auth_crap.nt_resp_len;
502         lm_resp.data    = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
503         lm_resp.length  = s3call->request.data.auth_crap.lm_resp_len;
504
505         ctx = wb_cmd_pam_auth_crap_send(
506                 s3call, service,
507                 s3call->request.data.auth_crap.logon_parameters,
508                 s3call->request.data.auth_crap.domain,
509                 s3call->request.data.auth_crap.user,
510                 s3call->request.data.auth_crap.workstation,
511                 chal, nt_resp, lm_resp);
512         NT_STATUS_HAVE_NO_MEMORY(ctx);
513
514         ctx->async.fn = pam_auth_crap_recv;
515         ctx->async.private_data = s3call;
516         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
517         return NT_STATUS_OK;
518 }
519
520 static void pam_auth_crap_recv(struct composite_context *ctx)
521 {
522         struct wbsrv_samba3_call *s3call =
523                 talloc_get_type(ctx->async.private_data,
524                                 struct wbsrv_samba3_call);
525         NTSTATUS status;
526         DATA_BLOB info3;
527         struct netr_UserSessionKey user_session_key;
528         struct netr_LMSessionKey lm_key;
529         char *unix_username;
530         
531         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
532                                            &user_session_key, &lm_key, &unix_username);
533         if (!NT_STATUS_IS_OK(status)) goto done;
534
535         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
536                 memcpy(s3call->response.data.auth.user_session_key, 
537                        &user_session_key.key,
538                        sizeof(s3call->response.data.auth.user_session_key));
539         }
540
541         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
542                 s3call->response.extra_data.data = info3.data;
543                 s3call->response.length += info3.length;
544         }
545
546         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
547                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
548                        lm_key.key,
549                        sizeof(s3call->response.data.auth.first_8_lm_hash));
550         }
551         
552         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
553                 s3call->response.extra_data.data = unix_username;
554                 s3call->response.length += strlen(unix_username)+1;
555         }
556
557  done:
558         wbsrv_samba3_async_auth_epilogue(status, s3call);
559 }
560
561 /* Plaintext authentication 
562    
563    This interface is used by ntlm_auth in it's 'basic' authentication
564    mode, as well as by pam_winbind to authenticate users where we are
565    given a plaintext password.
566 */
567
568 static void pam_auth_recv(struct composite_context *ctx);
569
570 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
571 {
572         struct composite_context *ctx;
573         struct wbsrv_service *service =
574                 s3call->wbconn->listen_socket->service;
575         struct cli_credentials *credentials;
576         char *user, *domain;
577
578         if (!wb_samba3_split_username(s3call, s3call->wbconn->lp_ctx,
579                                  s3call->request.data.auth.user,
580                                  &domain, &user)) {
581                 return NT_STATUS_NO_SUCH_USER;
582         }
583
584         credentials = cli_credentials_init(s3call);
585         if (!credentials) {
586                 return NT_STATUS_NO_MEMORY;
587         }
588         cli_credentials_set_conf(credentials, service->task->lp_ctx);
589         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
590         cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
591
592         cli_credentials_set_password(credentials, s3call->request.data.auth.pass, CRED_SPECIFIED);
593
594         ctx = wb_cmd_pam_auth_send(s3call, service, credentials);
595         NT_STATUS_HAVE_NO_MEMORY(ctx);
596
597         ctx->async.fn = pam_auth_recv;
598         ctx->async.private_data = s3call;
599         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
600         return NT_STATUS_OK;
601 }
602
603 static void pam_auth_recv(struct composite_context *ctx)
604 {
605         struct wbsrv_samba3_call *s3call =
606                 talloc_get_type(ctx->async.private_data,
607                                 struct wbsrv_samba3_call);
608         NTSTATUS status;
609
610         status = wb_cmd_pam_auth_recv(ctx);
611
612         if (!NT_STATUS_IS_OK(status)) goto done;
613
614  done:
615         wbsrv_samba3_async_auth_epilogue(status, s3call);
616 }
617
618 /* 
619    List trusted domains
620 */
621
622 static void list_trustdom_recv_doms(struct composite_context *ctx);
623
624 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
625 {
626         struct composite_context *ctx;
627         struct wbsrv_service *service =
628                 s3call->wbconn->listen_socket->service;
629
630         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
631
632         ctx = wb_cmd_list_trustdoms_send(s3call, service);
633         NT_STATUS_HAVE_NO_MEMORY(ctx);
634
635         ctx->async.fn = list_trustdom_recv_doms;
636         ctx->async.private_data = s3call;
637         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
638         return NT_STATUS_OK;
639 }
640
641 static void list_trustdom_recv_doms(struct composite_context *ctx)
642 {
643         struct wbsrv_samba3_call *s3call =
644                 talloc_get_type(ctx->async.private_data,
645                                 struct wbsrv_samba3_call);
646         int i, num_domains;
647         struct wb_dom_info **domains;
648         NTSTATUS status;
649         char *result;
650
651         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
652                                             &domains);
653         if (!NT_STATUS_IS_OK(status)) goto done;
654
655         result = talloc_strdup(s3call, "");
656         if (result == NULL) {
657                 status = NT_STATUS_NO_MEMORY;
658                 goto done;
659         }
660
661         for (i=0; i<num_domains; i++) {
662                 result = talloc_asprintf_append_buffer(
663                         result, "%s\\%s\\%s",
664                         domains[i]->name, domains[i]->name,
665                         dom_sid_string(s3call, domains[i]->sid));
666         }
667
668         if (result == NULL) {
669                 status = NT_STATUS_NO_MEMORY;
670                 goto done;
671         }
672
673         s3call->response.result = WINBINDD_OK;
674         if (num_domains > 0) {
675                 s3call->response.extra_data.data = result;
676                 s3call->response.length += strlen(result)+1;
677         }
678
679  done:
680         wbsrv_samba3_async_epilogue(status, s3call);
681 }
682
683 /* list groups */
684 static void list_groups_recv(struct composite_context *ctx);
685
686 NTSTATUS wbsrv_samba3_list_groups(struct wbsrv_samba3_call *s3call)
687 {
688         struct composite_context *ctx;
689         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
690
691         DEBUG(5, ("wbsrv_samba4_list_groups called\n"));
692
693         ctx = wb_cmd_list_groups_send(s3call, service,
694                                       s3call->request.domain_name);
695         NT_STATUS_HAVE_NO_MEMORY(ctx);
696
697         ctx->async.fn = list_groups_recv;
698         ctx->async.private_data = s3call;
699         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
700         return NT_STATUS_OK;
701 }
702
703 static void list_groups_recv(struct composite_context *ctx)
704 {
705         struct wbsrv_samba3_call *s3call = talloc_get_type_abort(
706                                                 ctx->async.private_data,
707                                                 struct wbsrv_samba3_call);
708         uint32_t extra_data_len;
709         char *extra_data;
710         NTSTATUS status;
711
712         DEBUG(5, ("list_groups_recv called\n"));
713
714         status = wb_cmd_list_groups_recv(ctx, s3call, &extra_data_len,
715                         &extra_data);
716
717         if (NT_STATUS_IS_OK(status)) {
718                 s3call->response.extra_data.data = extra_data;
719                 s3call->response.length += extra_data_len;
720                 if (extra_data) {
721                         s3call->response.length += 1;
722                 }
723         }
724
725         wbsrv_samba3_async_epilogue(status, s3call);
726 }
727
728 /* List users */
729
730 static void list_users_recv(struct composite_context *ctx);
731
732 NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
733 {
734         struct composite_context *ctx;
735         struct wbsrv_service *service =
736                 s3call->wbconn->listen_socket->service;
737
738         DEBUG(5, ("wbsrv_samba3_list_users called\n"));
739
740         ctx = wb_cmd_list_users_send(s3call, service,
741                         s3call->request.domain_name);
742         NT_STATUS_HAVE_NO_MEMORY(ctx);
743
744         ctx->async.fn = list_users_recv;
745         ctx->async.private_data = s3call;
746         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
747         return NT_STATUS_OK;
748 }
749
750 static void list_users_recv(struct composite_context *ctx)
751 {
752         struct wbsrv_samba3_call *s3call =
753                 talloc_get_type(ctx->async.private_data,
754                                 struct wbsrv_samba3_call);
755         uint32_t extra_data_len;
756         char *extra_data;
757         NTSTATUS status;
758
759         DEBUG(5, ("list_users_recv called\n"));
760
761         status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
762                         &extra_data);
763
764         if (NT_STATUS_IS_OK(status)) {
765                 s3call->response.extra_data.data = extra_data;
766                 s3call->response.length += extra_data_len;
767                 if (extra_data) {
768                         s3call->response.length += 1;
769                 }
770         }
771
772         wbsrv_samba3_async_epilogue(status, s3call);
773 }
774
775 /* NSS calls */
776
777 static void getpwnam_recv(struct composite_context *ctx);
778
779 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
780 {
781         struct composite_context *ctx;
782         struct wbsrv_service *service =
783                 s3call->wbconn->listen_socket->service;
784
785         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
786
787         ctx = wb_cmd_getpwnam_send(s3call, service,
788                         s3call->request.data.username);
789         NT_STATUS_HAVE_NO_MEMORY(ctx);
790
791         ctx->async.fn = getpwnam_recv;
792         ctx->async.private_data = s3call;
793         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
794         return NT_STATUS_OK;
795 }
796
797 static void getpwnam_recv(struct composite_context *ctx)
798 {
799         struct wbsrv_samba3_call *s3call =
800                 talloc_get_type(ctx->async.private_data,
801                                 struct wbsrv_samba3_call);
802         NTSTATUS status;
803         struct winbindd_pw *pw;
804
805         DEBUG(5, ("getpwnam_recv called\n"));
806
807         status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
808         if(NT_STATUS_IS_OK(status))
809                 s3call->response.data.pw = *pw;
810
811         wbsrv_samba3_async_epilogue(status, s3call);
812 }
813
814 static void getpwuid_recv(struct composite_context *ctx);
815
816 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
817 {
818         struct composite_context *ctx;
819         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
820
821         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
822
823         ctx = wb_cmd_getpwuid_send(s3call, service,
824                         s3call->request.data.uid);
825         NT_STATUS_HAVE_NO_MEMORY(ctx);
826
827         ctx->async.fn = getpwuid_recv;
828         ctx->async.private_data = s3call;
829         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
830         return NT_STATUS_OK;
831 }
832
833 static void getpwuid_recv(struct composite_context *ctx)
834 {
835         struct wbsrv_samba3_call *s3call =
836                 talloc_get_type(ctx->async.private_data,
837                                 struct wbsrv_samba3_call);
838         NTSTATUS status;
839         struct winbindd_pw *pw;
840
841         DEBUG(5, ("getpwuid_recv called\n"));
842
843         status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
844         if (NT_STATUS_IS_OK(status))
845                 s3call->response.data.pw = *pw;
846
847         wbsrv_samba3_async_epilogue(status, s3call);
848 }
849
850 static void setpwent_recv(struct composite_context *ctx);
851
852 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
853 {
854         struct composite_context *ctx;
855         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
856
857         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
858
859         ctx = wb_cmd_setpwent_send(s3call, service);
860         NT_STATUS_HAVE_NO_MEMORY(ctx);
861
862         ctx->async.fn = setpwent_recv;
863         ctx->async.private_data = s3call;
864         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
865         return NT_STATUS_OK;
866 }
867
868 static void setpwent_recv(struct composite_context *ctx)
869 {
870         struct wbsrv_samba3_call *s3call =
871                 talloc_get_type(ctx->async.private_data,
872                                 struct wbsrv_samba3_call);
873         NTSTATUS status;
874         struct wbsrv_pwent *pwent;
875
876         DEBUG(5, ("setpwent_recv called\n"));
877
878         status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
879         if (NT_STATUS_IS_OK(status)) {
880                 s3call->wbconn->protocol_private_data = pwent;
881         }
882
883         wbsrv_samba3_async_epilogue(status, s3call);
884 }
885
886 static void getpwent_recv(struct composite_context *ctx);
887
888 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
889 {
890         struct composite_context *ctx;
891         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
892         struct wbsrv_pwent *pwent;
893
894         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
895
896         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
897
898         pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
899                         struct wbsrv_pwent);
900         NT_STATUS_HAVE_NO_MEMORY(pwent);
901
902         ctx = wb_cmd_getpwent_send(s3call, service, pwent,
903                         s3call->request.data.num_entries);
904         NT_STATUS_HAVE_NO_MEMORY(ctx);
905
906         ctx->async.fn = getpwent_recv;
907         ctx->async.private_data = s3call;
908         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
909         return NT_STATUS_OK;
910 }
911
912 static void getpwent_recv(struct composite_context *ctx)
913 {
914         struct wbsrv_samba3_call *s3call =
915                 talloc_get_type(ctx->async.private_data,
916                                 struct wbsrv_samba3_call);
917         NTSTATUS status;
918         struct winbindd_pw *pw;
919         uint32_t num_users;
920
921         DEBUG(5, ("getpwent_recv called\n"));
922
923         status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
924         if (NT_STATUS_IS_OK(status)) {
925                 uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
926
927                 s3call->response.data.num_entries = num_users;
928                 s3call->response.extra_data.data = pw;
929                 s3call->response.length += extra_len;
930         }
931
932         wbsrv_samba3_async_epilogue(status, s3call);
933 }
934
935 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
936 {
937         struct wbsrv_pwent *pwent =
938                 talloc_get_type(s3call->wbconn->protocol_private_data,
939                                 struct wbsrv_pwent);
940         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
941
942         talloc_free(pwent);
943
944         s3call->wbconn->protocol_private_data = NULL;
945         s3call->response.result = WINBINDD_OK;
946         return NT_STATUS_OK;
947 }
948
949
950 static void getgrnam_recv(struct composite_context *ctx);
951
952 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
953 {
954         struct composite_context *ctx;
955         struct wbsrv_service *service =
956                 s3call->wbconn->listen_socket->service;
957
958         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
959
960         ctx = wb_cmd_getgrnam_send(s3call, service,
961                         s3call->request.data.groupname);
962         NT_STATUS_HAVE_NO_MEMORY(ctx);
963
964         ctx->async.fn = getgrnam_recv;
965         ctx->async.private_data = s3call;
966         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
967         return NT_STATUS_OK;
968 }
969
970 static void getgrnam_recv(struct composite_context *ctx)
971 {
972         struct wbsrv_samba3_call *s3call =
973                 talloc_get_type(ctx->async.private_data,
974                                 struct wbsrv_samba3_call);
975         NTSTATUS status;
976         struct winbindd_gr *gr;
977
978         DEBUG(5, ("getgrnam_recv called\n"));
979
980         status = wb_cmd_getgrnam_recv(ctx, s3call, &gr);
981         if(NT_STATUS_IS_OK(status))
982                 s3call->response.data.gr = *gr;
983
984         wbsrv_samba3_async_epilogue(status, s3call);
985 }
986
987 static void getgrgid_recv(struct composite_context *ctx);
988
989 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
990 {
991         struct composite_context *ctx;
992         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
993
994         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
995
996         ctx = wb_cmd_getgrgid_send(s3call, service,
997                         s3call->request.data.gid);
998         NT_STATUS_HAVE_NO_MEMORY(ctx);
999
1000         ctx->async.fn = getgrgid_recv;
1001         ctx->async.private_data = s3call;
1002         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1003         return NT_STATUS_OK;
1004 }
1005
1006 static void getgrgid_recv(struct composite_context *ctx)
1007 {
1008         struct wbsrv_samba3_call *s3call =
1009                 talloc_get_type(ctx->async.private_data,
1010                                 struct wbsrv_samba3_call);
1011         NTSTATUS status;
1012         struct winbindd_gr *gr;
1013
1014         DEBUG(5, ("getgrgid_recv called\n"));
1015
1016         status = wb_cmd_getgrgid_recv(ctx, s3call, &gr);
1017         if (NT_STATUS_IS_OK(status))
1018                 s3call->response.data.gr = *gr;
1019
1020         wbsrv_samba3_async_epilogue(status, s3call);
1021 }
1022
1023 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
1024 {
1025         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
1026         s3call->response.result = WINBINDD_ERROR;
1027         return NT_STATUS_OK;
1028 }
1029
1030 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
1031 {
1032         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
1033         s3call->response.result = WINBINDD_OK;
1034         return NT_STATUS_OK;
1035 }
1036
1037 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
1038 {
1039         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
1040         s3call->response.result = WINBINDD_ERROR;
1041         return NT_STATUS_OK;
1042 }
1043
1044 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
1045 {
1046         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
1047         s3call->response.result = WINBINDD_OK;
1048         return NT_STATUS_OK;
1049 }
1050
1051 static void sid2uid_recv(struct composite_context *ctx);
1052
1053 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
1054 {
1055         struct composite_context *ctx;
1056         struct wbsrv_service *service =
1057                 s3call->wbconn->listen_socket->service;
1058         struct dom_sid *sid;
1059
1060         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
1061
1062         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
1063         NT_STATUS_HAVE_NO_MEMORY(sid);
1064
1065         ctx = wb_sid2uid_send(s3call, service, sid);
1066         NT_STATUS_HAVE_NO_MEMORY(ctx);
1067
1068         ctx->async.fn = sid2uid_recv;
1069         ctx->async.private_data = s3call;
1070         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1071         return NT_STATUS_OK;
1072
1073 }
1074
1075 static void sid2uid_recv(struct composite_context *ctx)
1076 {
1077         struct wbsrv_samba3_call *s3call =
1078                 talloc_get_type(ctx->async.private_data,
1079                                 struct wbsrv_samba3_call);
1080         NTSTATUS status;
1081
1082         DEBUG(5, ("sid2uid_recv called\n"));
1083
1084         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
1085
1086         wbsrv_samba3_async_epilogue(status, s3call);
1087 }
1088
1089 static void sid2gid_recv(struct composite_context *ctx);
1090
1091 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
1092 {
1093         struct composite_context *ctx;
1094         struct wbsrv_service *service =
1095                 s3call->wbconn->listen_socket->service;
1096         struct dom_sid *sid;
1097
1098         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
1099
1100         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
1101         NT_STATUS_HAVE_NO_MEMORY(sid);
1102
1103         ctx = wb_sid2gid_send(s3call, service, sid);
1104         NT_STATUS_HAVE_NO_MEMORY(ctx);
1105
1106         ctx->async.fn = sid2gid_recv;
1107         ctx->async.private_data = s3call;
1108         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1109         return NT_STATUS_OK;
1110
1111 }
1112
1113 static void sid2gid_recv(struct composite_context *ctx)
1114 {
1115         struct wbsrv_samba3_call *s3call =
1116                 talloc_get_type(ctx->async.private_data,
1117                                 struct wbsrv_samba3_call);
1118         NTSTATUS status;
1119
1120         DEBUG(5, ("sid2gid_recv called\n"));
1121
1122         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
1123
1124         wbsrv_samba3_async_epilogue(status, s3call);
1125 }
1126
1127 static void uid2sid_recv(struct composite_context *ctx);
1128
1129 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1130 {
1131         struct composite_context *ctx;
1132         struct wbsrv_service *service =
1133                 s3call->wbconn->listen_socket->service;
1134
1135         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1136
1137         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
1138         NT_STATUS_HAVE_NO_MEMORY(ctx);
1139
1140         ctx->async.fn = uid2sid_recv;
1141         ctx->async.private_data = s3call;
1142         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1143         return NT_STATUS_OK;
1144
1145 }
1146
1147 static void uid2sid_recv(struct composite_context *ctx)
1148 {
1149         struct wbsrv_samba3_call *s3call =
1150                 talloc_get_type(ctx->async.private_data,
1151                                 struct wbsrv_samba3_call);
1152         NTSTATUS status;
1153         struct dom_sid *sid;
1154         char *sid_str;
1155
1156         DEBUG(5, ("uid2sid_recv called\n"));
1157
1158         status = wb_uid2sid_recv(ctx, s3call, &sid);
1159         if(NT_STATUS_IS_OK(status)) {
1160                 sid_str = dom_sid_string(s3call, sid);
1161
1162                 /* If the conversion failed, bail out with a failure. */
1163                 if (sid_str == NULL)
1164                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1165
1166                 /* But we assume this worked, so we'll set the string. Work
1167                  * done. */
1168                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1169                 s3call->response.data.sid.type = SID_NAME_USER;
1170         }
1171
1172         wbsrv_samba3_async_epilogue(status, s3call);
1173 }
1174
1175 static void gid2sid_recv(struct composite_context *ctx);
1176
1177 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1178 {
1179         struct composite_context *ctx;
1180         struct wbsrv_service *service =
1181                 s3call->wbconn->listen_socket->service;
1182
1183         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1184
1185         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1186         NT_STATUS_HAVE_NO_MEMORY(ctx);
1187
1188         ctx->async.fn = gid2sid_recv;
1189         ctx->async.private_data = s3call;
1190         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1191         return NT_STATUS_OK;
1192
1193 }
1194
1195 static void gid2sid_recv(struct composite_context *ctx)
1196 {
1197         struct wbsrv_samba3_call *s3call =
1198                 talloc_get_type(ctx->async.private_data,
1199                                 struct wbsrv_samba3_call);
1200         NTSTATUS status;
1201         struct dom_sid *sid;
1202         char *sid_str;
1203
1204         DEBUG(5, ("gid2sid_recv called\n"));
1205
1206         status = wb_gid2sid_recv(ctx, s3call, &sid);
1207         if(NT_STATUS_IS_OK(status)) {
1208                 sid_str = dom_sid_string(s3call, sid);
1209
1210                 if (sid_str == NULL)
1211                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1212
1213                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1214                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1215         }
1216
1217         wbsrv_samba3_async_epilogue(status, s3call);
1218 }
1219