s4:winbind Implement logic for getgroups to work
[mat/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 "param/param.h"
27 #include "winbind/wb_helper.h"
28 #include "libcli/composite/composite.h"
29 #include "version.h"
30 #include "librpc/gen_ndr/ndr_netlogon.h"
31 #include "libcli/security/security.h"
32 #include "auth/ntlm/pam_errors.h"
33 #include "auth/credentials/credentials.h"
34 #include "smbd/service_task.h"
35
36 /*
37   support the old Samba3 TXT form of the info3
38  */
39 static NTSTATUS wb_samba3_append_info3_as_txt(TALLOC_CTX *mem_ctx,
40                                               struct wbsrv_samba3_call *s3call,
41                                               DATA_BLOB info3b)
42 {
43         struct netr_SamInfo3 *info3;
44         char *ex;
45         uint32_t i;
46         enum ndr_err_code ndr_err;
47
48         info3 = talloc(mem_ctx, struct netr_SamInfo3);
49         NT_STATUS_HAVE_NO_MEMORY(info3);
50
51         /* The Samba3 protocol has a redundent 4 bytes at the start */
52         info3b.data += 4;
53         info3b.length -= 4;
54
55         ndr_err = ndr_pull_struct_blob(&info3b,
56                                        mem_ctx,
57                                        lp_iconv_convenience(s3call->wbconn->lp_ctx), 
58                                        info3,
59                                        (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3);
60         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
61                 return ndr_map_error2ntstatus(ndr_err);
62         }
63
64         s3call->response.data.auth.info3.logon_time =
65                 nt_time_to_unix(info3->base.last_logon);
66         s3call->response.data.auth.info3.logoff_time =
67                 nt_time_to_unix(info3->base.last_logoff);
68         s3call->response.data.auth.info3.kickoff_time =
69                 nt_time_to_unix(info3->base.acct_expiry);
70         s3call->response.data.auth.info3.pass_last_set_time =
71                 nt_time_to_unix(info3->base.last_password_change);
72         s3call->response.data.auth.info3.pass_can_change_time =
73                 nt_time_to_unix(info3->base.allow_password_change);
74         s3call->response.data.auth.info3.pass_must_change_time =
75                 nt_time_to_unix(info3->base.force_password_change);
76
77         s3call->response.data.auth.info3.logon_count = info3->base.logon_count;
78         s3call->response.data.auth.info3.bad_pw_count = info3->base.bad_password_count;
79
80         s3call->response.data.auth.info3.user_rid = info3->base.rid;
81         s3call->response.data.auth.info3.group_rid = info3->base.primary_gid;
82         fstrcpy(s3call->response.data.auth.info3.dom_sid, dom_sid_string(mem_ctx, info3->base.domain_sid));
83
84         s3call->response.data.auth.info3.num_groups = info3->base.groups.count;
85         s3call->response.data.auth.info3.user_flgs = info3->base.user_flags;
86
87         s3call->response.data.auth.info3.acct_flags = info3->base.acct_flags;
88         s3call->response.data.auth.info3.num_other_sids = info3->sidcount;
89
90         fstrcpy(s3call->response.data.auth.info3.user_name,
91                 info3->base.account_name.string);
92         fstrcpy(s3call->response.data.auth.info3.full_name,
93                 info3->base.full_name.string);
94         fstrcpy(s3call->response.data.auth.info3.logon_script,
95                 info3->base.logon_script.string);
96         fstrcpy(s3call->response.data.auth.info3.profile_path,
97                 info3->base.profile_path.string);
98         fstrcpy(s3call->response.data.auth.info3.home_dir,
99                 info3->base.home_directory.string);
100         fstrcpy(s3call->response.data.auth.info3.dir_drive,
101                 info3->base.home_drive.string);
102
103         fstrcpy(s3call->response.data.auth.info3.logon_srv,
104                 info3->base.logon_server.string);
105         fstrcpy(s3call->response.data.auth.info3.logon_dom,
106                 info3->base.domain.string);
107
108         ex = talloc_strdup(mem_ctx, "");
109         NT_STATUS_HAVE_NO_MEMORY(ex);
110
111         for (i=0; i < info3->base.groups.count; i++) {
112                 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
113                                                    info3->base.groups.rids[i].rid,
114                                                    info3->base.groups.rids[i].attributes);
115                 NT_STATUS_HAVE_NO_MEMORY(ex);
116         }
117
118         for (i=0; i < info3->sidcount; i++) {
119                 char *sid;
120
121                 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
122                 NT_STATUS_HAVE_NO_MEMORY(sid);
123
124                 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
125                                                    sid,
126                                                    info3->sids[i].attributes);
127                 NT_STATUS_HAVE_NO_MEMORY(ex);
128
129                 talloc_free(sid);
130         }
131
132         s3call->response.extra_data.data = ex;
133         s3call->response.length += talloc_get_size(ex);
134
135         return NT_STATUS_OK;
136 }
137
138 /* 
139    Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
140 */
141
142 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
143                                              struct wbsrv_samba3_call *s3call)
144 {
145         struct winbindd_response *resp = &s3call->response;
146         if (!NT_STATUS_IS_OK(status)) {
147                 resp->result = WINBINDD_ERROR;
148         } else {
149                 resp->result = WINBINDD_OK;
150         }
151         
152         WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
153                                 nt_errstr(status));
154         WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
155                                 get_friendly_nt_error_msg(status));
156
157         resp->data.auth.pam_error = nt_status_to_pam(status);
158         resp->data.auth.nt_status = NT_STATUS_V(status);
159
160         wbsrv_samba3_send_reply(s3call);
161 }
162
163 /* 
164    Send of a generic reply to a Samba3 query
165 */
166
167 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
168                                         struct wbsrv_samba3_call *s3call)
169 {
170         struct winbindd_response *resp = &s3call->response;
171         if (NT_STATUS_IS_OK(status)) {
172                 resp->result = WINBINDD_OK;
173         } else {
174                 resp->result = WINBINDD_ERROR;
175         }
176
177         wbsrv_samba3_send_reply(s3call);
178 }
179
180 /* 
181    Boilerplate commands, simple queries without network traffic 
182 */
183
184 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
185 {
186         s3call->response.result                 = WINBINDD_OK;
187         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
188         return NT_STATUS_OK;
189 }
190
191 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
192 {
193         s3call->response.result                 = WINBINDD_OK;
194         s3call->response.data.info.winbind_separator = *lp_winbind_separator(s3call->wbconn->lp_ctx);
195         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
196                                 SAMBA_VERSION_STRING);
197         return NT_STATUS_OK;
198 }
199
200 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
201 {
202         s3call->response.result                 = WINBINDD_OK;
203         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
204                                 lp_workgroup(s3call->wbconn->lp_ctx));
205         return NT_STATUS_OK;
206 }
207
208 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
209 {
210         s3call->response.result                 = WINBINDD_OK;
211         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
212                                 lp_netbios_name(s3call->wbconn->lp_ctx));
213         return NT_STATUS_OK;
214 }
215
216 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
217 {
218         const char *path = s3call->wbconn->listen_socket->service->priv_socket_path;
219         s3call->response.result          = WINBINDD_OK;
220         s3call->response.extra_data.data = discard_const(path);
221
222         s3call->response.length += strlen(path) + 1;
223         return NT_STATUS_OK;
224 }
225
226 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
227 {
228         s3call->response.result                 = WINBINDD_OK;
229         return NT_STATUS_OK;
230 }
231
232 NTSTATUS wbsrv_samba3_domain_info(struct wbsrv_samba3_call *s3call)
233 {
234         DEBUG(5, ("wbsrv_samba3_domain_info called, stub\n"));
235         s3call->response.result = WINBINDD_OK;
236         fstrcpy(s3call->response.data.domain_info.name,
237                 s3call->request.domain_name);
238         fstrcpy(s3call->response.data.domain_info.alt_name,
239                 s3call->request.domain_name);
240         fstrcpy(s3call->response.data.domain_info.sid, "S-1-2-3-4");
241         s3call->response.data.domain_info.native_mode = false;
242         s3call->response.data.domain_info.active_directory = false;
243         s3call->response.data.domain_info.primary = false;
244
245         return NT_STATUS_OK;
246 }
247
248 /* Plaintext authentication 
249    
250    This interface is used by ntlm_auth in it's 'basic' authentication
251    mode, as well as by pam_winbind to authenticate users where we are
252    given a plaintext password.
253 */
254
255 static void check_machacc_recv(struct composite_context *ctx);
256
257 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
258 {
259         NTSTATUS status;
260         struct cli_credentials *creds;
261         struct composite_context *ctx;
262         struct wbsrv_service *service =
263                 s3call->wbconn->listen_socket->service;
264
265         /* Create a credentials structure */
266         creds = cli_credentials_init(s3call);
267         if (creds == NULL) {
268                 return NT_STATUS_NO_MEMORY;
269         }
270
271         cli_credentials_set_conf(creds, service->task->lp_ctx);
272
273         /* Connect the machine account to the credentials */
274         status = cli_credentials_set_machine_account(creds, service->task->lp_ctx);
275         if (!NT_STATUS_IS_OK(status)) {
276                 talloc_free(creds);
277                 return status;
278         }
279
280         ctx = wb_cmd_pam_auth_send(s3call, service, creds);
281
282         if (!ctx) {
283                 talloc_free(creds);
284                 return NT_STATUS_NO_MEMORY;
285         }
286
287         ctx->async.fn = check_machacc_recv;
288         ctx->async.private_data = s3call;
289         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
290         return NT_STATUS_OK;
291 }
292
293 static void check_machacc_recv(struct composite_context *ctx)
294 {
295         struct wbsrv_samba3_call *s3call =
296                 talloc_get_type(ctx->async.private_data,
297                                 struct wbsrv_samba3_call);
298         NTSTATUS status;
299
300         status = wb_cmd_pam_auth_recv(ctx, s3call, NULL, NULL, NULL, NULL);
301
302         if (!NT_STATUS_IS_OK(status)) goto done;
303
304  done:
305         wbsrv_samba3_async_auth_epilogue(status, s3call);
306 }
307
308 /*
309   Find the name of a suitable domain controller, by query on the
310   netlogon pipe to the DC.  
311 */
312
313 static void getdcname_recv_dc(struct composite_context *ctx);
314
315 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
316 {
317         struct composite_context *ctx;
318         struct wbsrv_service *service =
319                 s3call->wbconn->listen_socket->service;
320
321         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
322
323         ctx = wb_cmd_getdcname_send(s3call, service,
324                                     s3call->request.domain_name);
325         NT_STATUS_HAVE_NO_MEMORY(ctx);
326
327         ctx->async.fn = getdcname_recv_dc;
328         ctx->async.private_data = s3call;
329         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
330         return NT_STATUS_OK;
331 }
332
333 static void getdcname_recv_dc(struct composite_context *ctx)
334 {
335         struct wbsrv_samba3_call *s3call =
336                 talloc_get_type(ctx->async.private_data,
337                                 struct wbsrv_samba3_call);
338         const char *dcname;
339         NTSTATUS status;
340
341         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
342         if (!NT_STATUS_IS_OK(status)) goto done;
343
344         s3call->response.result = WINBINDD_OK;
345         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
346
347  done:
348         wbsrv_samba3_async_epilogue(status, s3call);
349 }
350
351 /* 
352    Lookup a user's domain groups
353 */
354
355 static void userdomgroups_recv_groups(struct composite_context *ctx);
356
357 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
358 {
359         struct composite_context *ctx;
360         struct dom_sid *sid;
361
362         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
363
364         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
365         if (sid == NULL) {
366                 DEBUG(5, ("Could not parse sid %s\n",
367                           s3call->request.data.sid));
368                 return NT_STATUS_NO_MEMORY;
369         }
370
371         ctx = wb_cmd_userdomgroups_send(
372                 s3call, s3call->wbconn->listen_socket->service, sid);
373         NT_STATUS_HAVE_NO_MEMORY(ctx);
374
375         ctx->async.fn = userdomgroups_recv_groups;
376         ctx->async.private_data = s3call;
377         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
378         return NT_STATUS_OK;
379 }
380
381 static void userdomgroups_recv_groups(struct composite_context *ctx)
382 {
383         struct wbsrv_samba3_call *s3call =
384                 talloc_get_type(ctx->async.private_data,
385                                 struct wbsrv_samba3_call);
386         int i, num_sids;
387         struct dom_sid **sids;
388         char *sids_string;
389         NTSTATUS status;
390
391         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
392         if (!NT_STATUS_IS_OK(status)) goto done;
393
394         sids_string = talloc_strdup(s3call, "");
395         if (sids_string == NULL) {
396                 status = NT_STATUS_NO_MEMORY;
397                 goto done;
398         }
399
400         for (i=0; i<num_sids; i++) {
401                 sids_string = talloc_asprintf_append_buffer(
402                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
403         }
404
405         if (sids_string == NULL) {
406                 status = NT_STATUS_NO_MEMORY;
407                 goto done;
408         }
409
410         s3call->response.result = WINBINDD_OK;
411         s3call->response.extra_data.data = sids_string;
412         s3call->response.length += strlen(sids_string)+1;
413         s3call->response.data.num_entries = num_sids;
414
415  done:
416         wbsrv_samba3_async_epilogue(status, s3call);
417 }
418
419 /* 
420    Lookup the list of SIDs for a user 
421 */
422 static void usersids_recv_sids(struct composite_context *ctx);
423
424 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
425 {
426         struct composite_context *ctx;
427         struct dom_sid *sid;
428
429         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
430
431         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
432         if (sid == NULL) {
433                 DEBUG(5, ("Could not parse sid %s\n",
434                           s3call->request.data.sid));
435                 return NT_STATUS_NO_MEMORY;
436         }
437
438         ctx = wb_cmd_usersids_send(
439                 s3call, s3call->wbconn->listen_socket->service, sid);
440         NT_STATUS_HAVE_NO_MEMORY(ctx);
441
442         ctx->async.fn = usersids_recv_sids;
443         ctx->async.private_data = s3call;
444         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
445         return NT_STATUS_OK;
446 }
447
448 static void usersids_recv_sids(struct composite_context *ctx)
449 {
450         struct wbsrv_samba3_call *s3call =
451                 talloc_get_type(ctx->async.private_data,
452                                 struct wbsrv_samba3_call);
453         int i, num_sids;
454         struct dom_sid **sids;
455         char *sids_string;
456         NTSTATUS status;
457
458         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
459         if (!NT_STATUS_IS_OK(status)) goto done;
460
461         sids_string = talloc_strdup(s3call, "");
462         if (sids_string == NULL) {
463                 status = NT_STATUS_NO_MEMORY;
464                 goto done;
465         }
466
467         for (i=0; i<num_sids; i++) {
468                 sids_string = talloc_asprintf_append_buffer(
469                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
470                 if (sids_string == NULL) {
471                         status = NT_STATUS_NO_MEMORY;
472                         goto done;
473                 }
474         }
475
476         s3call->response.result = WINBINDD_OK;
477         s3call->response.extra_data.data = sids_string;
478         s3call->response.length += strlen(sids_string);
479         s3call->response.data.num_entries = num_sids;
480
481         /* Hmmmm. Nasty protocol -- who invented the zeros between the
482          * SIDs? Hmmm. Could have been me -- vl */
483
484         while (*sids_string != '\0') {
485                 if ((*sids_string) == '\n') {
486                         *sids_string = '\0';
487                 }
488                 sids_string += 1;
489         }
490
491  done:
492         wbsrv_samba3_async_epilogue(status, s3call);
493 }
494
495 /* 
496    Lookup a DOMAIN\\user style name, and return a SID
497 */
498
499 static void lookupname_recv_sid(struct composite_context *ctx);
500
501 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
502 {
503         struct composite_context *ctx;
504         struct wbsrv_service *service =
505                 s3call->wbconn->listen_socket->service;
506
507         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
508
509         ctx = wb_cmd_lookupname_send(s3call, service,
510                                      s3call->request.data.name.dom_name,
511                                      s3call->request.data.name.name);
512         NT_STATUS_HAVE_NO_MEMORY(ctx);
513
514         /* setup the callbacks */
515         ctx->async.fn = lookupname_recv_sid;
516         ctx->async.private_data = s3call;
517         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
518         return NT_STATUS_OK;
519 }
520
521 static void lookupname_recv_sid(struct composite_context *ctx)
522 {
523         struct wbsrv_samba3_call *s3call =
524                 talloc_get_type(ctx->async.private_data,
525                                 struct wbsrv_samba3_call);
526         struct wb_sid_object *sid;
527         NTSTATUS status;
528
529         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
530         if (!NT_STATUS_IS_OK(status)) goto done;
531
532         s3call->response.result = WINBINDD_OK;
533         s3call->response.data.sid.type = sid->type;
534         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
535                                 dom_sid_string(s3call, sid->sid));
536
537  done:
538         wbsrv_samba3_async_epilogue(status, s3call);
539 }
540
541 /* 
542    Lookup a SID, and return a DOMAIN\\user style name
543 */
544
545 static void lookupsid_recv_name(struct composite_context *ctx);
546
547 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
548 {
549         struct composite_context *ctx;
550         struct wbsrv_service *service =
551                 s3call->wbconn->listen_socket->service;
552         struct dom_sid *sid;
553
554         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
555
556         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
557         if (sid == NULL) {
558                 DEBUG(5, ("Could not parse sid %s\n",
559                           s3call->request.data.sid));
560                 return NT_STATUS_NO_MEMORY;
561         }
562
563         ctx = wb_cmd_lookupsid_send(s3call, service, sid);
564         NT_STATUS_HAVE_NO_MEMORY(ctx);
565
566         /* setup the callbacks */
567         ctx->async.fn = lookupsid_recv_name;
568         ctx->async.private_data = s3call;
569         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
570         return NT_STATUS_OK;
571 }
572
573 static void lookupsid_recv_name(struct composite_context *ctx)
574 {
575         struct wbsrv_samba3_call *s3call =
576                 talloc_get_type(ctx->async.private_data,
577                                 struct wbsrv_samba3_call);
578         struct wb_sid_object *sid;
579         NTSTATUS status;
580
581         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
582         if (!NT_STATUS_IS_OK(status)) goto done;
583
584         s3call->response.result = WINBINDD_OK;
585         s3call->response.data.name.type = sid->type;
586         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
587                                 sid->domain);
588         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
589
590  done:
591         wbsrv_samba3_async_epilogue(status, s3call);
592 }
593
594 /*
595   Challenge-response authentication.  This interface is used by
596   ntlm_auth and the smbd auth subsystem to pass NTLM authentication
597   requests along a common pipe to the domain controller.  
598
599   The return value (in the async reply) may include the 'info3'
600   (effectivly most things you would want to know about the user), or
601   the NT and LM session keys seperated.
602 */
603
604 static void pam_auth_crap_recv(struct composite_context *ctx);
605
606 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
607 {
608         struct composite_context *ctx;
609         struct wbsrv_service *service =
610                 s3call->wbconn->listen_socket->service;
611         DATA_BLOB chal, nt_resp, lm_resp;
612
613         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
614
615         chal.data       = s3call->request.data.auth_crap.chal;
616         chal.length     = sizeof(s3call->request.data.auth_crap.chal);
617         nt_resp.data    = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
618         nt_resp.length  = s3call->request.data.auth_crap.nt_resp_len;
619         lm_resp.data    = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
620         lm_resp.length  = s3call->request.data.auth_crap.lm_resp_len;
621
622         ctx = wb_cmd_pam_auth_crap_send(
623                 s3call, service,
624                 s3call->request.data.auth_crap.logon_parameters,
625                 s3call->request.data.auth_crap.domain,
626                 s3call->request.data.auth_crap.user,
627                 s3call->request.data.auth_crap.workstation,
628                 chal, nt_resp, lm_resp);
629         NT_STATUS_HAVE_NO_MEMORY(ctx);
630
631         ctx->async.fn = pam_auth_crap_recv;
632         ctx->async.private_data = s3call;
633         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
634         return NT_STATUS_OK;
635 }
636
637 static void pam_auth_crap_recv(struct composite_context *ctx)
638 {
639         struct wbsrv_samba3_call *s3call =
640                 talloc_get_type(ctx->async.private_data,
641                                 struct wbsrv_samba3_call);
642         NTSTATUS status;
643         DATA_BLOB info3;
644         struct netr_UserSessionKey user_session_key;
645         struct netr_LMSessionKey lm_key;
646         char *unix_username;
647         
648         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
649                                            &user_session_key, &lm_key, &unix_username);
650         if (!NT_STATUS_IS_OK(status)) goto done;
651
652         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
653                 memcpy(s3call->response.data.auth.user_session_key, 
654                        &user_session_key.key,
655                        sizeof(s3call->response.data.auth.user_session_key));
656         }
657
658         if (s3call->request.flags & WBFLAG_PAM_INFO3_TEXT) {
659                 status = wb_samba3_append_info3_as_txt(ctx, s3call, info3);
660                 if (!NT_STATUS_IS_OK(status)) {
661                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
662                                   nt_errstr(status)));
663                         goto done;
664                 }
665         }
666
667         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
668                 s3call->response.extra_data.data = info3.data;
669                 s3call->response.length += info3.length;
670         }
671
672         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
673                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
674                        lm_key.key,
675                        sizeof(s3call->response.data.auth.first_8_lm_hash));
676         }
677         
678         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
679                 s3call->response.extra_data.data = unix_username;
680                 s3call->response.length += strlen(unix_username)+1;
681         }
682
683  done:
684         wbsrv_samba3_async_auth_epilogue(status, s3call);
685 }
686
687 /* Plaintext authentication 
688    
689    This interface is used by ntlm_auth in it's 'basic' authentication
690    mode, as well as by pam_winbind to authenticate users where we are
691    given a plaintext password.
692 */
693
694 static void pam_auth_recv(struct composite_context *ctx);
695
696 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
697 {
698         struct composite_context *ctx;
699         struct wbsrv_service *service =
700                 s3call->wbconn->listen_socket->service;
701         struct cli_credentials *credentials;
702         char *user, *domain;
703
704         if (!wb_samba3_split_username(s3call, s3call->wbconn->lp_ctx,
705                                  s3call->request.data.auth.user,
706                                  &domain, &user)) {
707                 return NT_STATUS_NO_SUCH_USER;
708         }
709
710         credentials = cli_credentials_init(s3call);
711         if (!credentials) {
712                 return NT_STATUS_NO_MEMORY;
713         }
714         cli_credentials_set_conf(credentials, service->task->lp_ctx);
715         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
716         cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
717
718         cli_credentials_set_password(credentials, s3call->request.data.auth.pass, CRED_SPECIFIED);
719
720         ctx = wb_cmd_pam_auth_send(s3call, service, credentials);
721         NT_STATUS_HAVE_NO_MEMORY(ctx);
722
723         ctx->async.fn = pam_auth_recv;
724         ctx->async.private_data = s3call;
725         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
726         return NT_STATUS_OK;
727 }
728
729 static void pam_auth_recv(struct composite_context *ctx)
730 {
731         struct wbsrv_samba3_call *s3call =
732                 talloc_get_type(ctx->async.private_data,
733                                 struct wbsrv_samba3_call);
734         NTSTATUS status;
735         DATA_BLOB info3;
736         struct netr_UserSessionKey user_session_key;
737         struct netr_LMSessionKey lm_key;
738         char *unix_username;
739
740         status = wb_cmd_pam_auth_recv(ctx, s3call, &info3, 
741                                       &user_session_key, &lm_key, &unix_username);
742
743         if (!NT_STATUS_IS_OK(status)) goto done;
744
745         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
746                 memcpy(s3call->response.data.auth.user_session_key, 
747                        &user_session_key.key,
748                        sizeof(s3call->response.data.auth.user_session_key));
749         }
750
751         if (s3call->request.flags & WBFLAG_PAM_INFO3_TEXT) {
752                 status = wb_samba3_append_info3_as_txt(ctx, s3call, info3);
753                 if (!NT_STATUS_IS_OK(status)) {
754                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
755                                   nt_errstr(status)));
756                         goto done;
757                 }
758         }
759
760         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
761                 s3call->response.extra_data.data = info3.data;
762                 s3call->response.length += info3.length;
763         }
764
765         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
766                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
767                        lm_key.key,
768                        sizeof(s3call->response.data.auth.first_8_lm_hash));
769         }
770         
771         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
772                 s3call->response.extra_data.data = unix_username;
773                 s3call->response.length += strlen(unix_username)+1;
774         }
775         
776
777  done:
778         wbsrv_samba3_async_auth_epilogue(status, s3call);
779 }
780
781 /* 
782    List trusted domains
783 */
784
785 static void list_trustdom_recv_doms(struct composite_context *ctx);
786
787 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
788 {
789         struct composite_context *ctx;
790         struct wbsrv_service *service =
791                 s3call->wbconn->listen_socket->service;
792
793         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
794
795         ctx = wb_cmd_list_trustdoms_send(s3call, service);
796         NT_STATUS_HAVE_NO_MEMORY(ctx);
797
798         ctx->async.fn = list_trustdom_recv_doms;
799         ctx->async.private_data = s3call;
800         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
801         return NT_STATUS_OK;
802 }
803
804 static void list_trustdom_recv_doms(struct composite_context *ctx)
805 {
806         struct wbsrv_samba3_call *s3call =
807                 talloc_get_type(ctx->async.private_data,
808                                 struct wbsrv_samba3_call);
809         int i, num_domains;
810         struct wb_dom_info **domains;
811         NTSTATUS status;
812         char *result;
813
814         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
815                                             &domains);
816         if (!NT_STATUS_IS_OK(status)) goto done;
817
818         result = talloc_strdup(s3call, "");
819         if (result == NULL) {
820                 status = NT_STATUS_NO_MEMORY;
821                 goto done;
822         }
823
824         for (i=0; i<num_domains; i++) {
825                 result = talloc_asprintf_append_buffer(
826                         result, "%s\\%s\\%s",
827                         domains[i]->name, domains[i]->name,
828                         dom_sid_string(s3call, domains[i]->sid));
829         }
830
831         if (result == NULL) {
832                 status = NT_STATUS_NO_MEMORY;
833                 goto done;
834         }
835
836         s3call->response.result = WINBINDD_OK;
837         if (num_domains > 0) {
838                 s3call->response.extra_data.data = result;
839                 s3call->response.length += strlen(result)+1;
840         }
841
842  done:
843         wbsrv_samba3_async_epilogue(status, s3call);
844 }
845
846 /* list groups */
847 static void list_groups_recv(struct composite_context *ctx);
848
849 NTSTATUS wbsrv_samba3_list_groups(struct wbsrv_samba3_call *s3call)
850 {
851         struct composite_context *ctx;
852         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
853
854         DEBUG(5, ("wbsrv_samba4_list_groups called\n"));
855
856         ctx = wb_cmd_list_groups_send(s3call, service,
857                                       s3call->request.domain_name);
858         NT_STATUS_HAVE_NO_MEMORY(ctx);
859
860         ctx->async.fn = list_groups_recv;
861         ctx->async.private_data = s3call;
862         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
863         return NT_STATUS_OK;
864 }
865
866 static void list_groups_recv(struct composite_context *ctx)
867 {
868         struct wbsrv_samba3_call *s3call = talloc_get_type_abort(
869                                                 ctx->async.private_data,
870                                                 struct wbsrv_samba3_call);
871         uint32_t extra_data_len;
872         char *extra_data;
873         NTSTATUS status;
874
875         DEBUG(5, ("list_groups_recv called\n"));
876
877         status = wb_cmd_list_groups_recv(ctx, s3call, &extra_data_len,
878                         &extra_data);
879
880         if (NT_STATUS_IS_OK(status)) {
881                 s3call->response.extra_data.data = extra_data;
882                 s3call->response.length += extra_data_len;
883                 if (extra_data) {
884                         s3call->response.length += 1;
885                 }
886         }
887
888         wbsrv_samba3_async_epilogue(status, s3call);
889 }
890
891 /* List users */
892
893 static void list_users_recv(struct composite_context *ctx);
894
895 NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
896 {
897         struct composite_context *ctx;
898         struct wbsrv_service *service =
899                 s3call->wbconn->listen_socket->service;
900
901         DEBUG(5, ("wbsrv_samba3_list_users called\n"));
902
903         ctx = wb_cmd_list_users_send(s3call, service,
904                         s3call->request.domain_name);
905         NT_STATUS_HAVE_NO_MEMORY(ctx);
906
907         ctx->async.fn = list_users_recv;
908         ctx->async.private_data = s3call;
909         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
910         return NT_STATUS_OK;
911 }
912
913 static void list_users_recv(struct composite_context *ctx)
914 {
915         struct wbsrv_samba3_call *s3call =
916                 talloc_get_type(ctx->async.private_data,
917                                 struct wbsrv_samba3_call);
918         uint32_t extra_data_len;
919         char *extra_data;
920         NTSTATUS status;
921
922         DEBUG(5, ("list_users_recv called\n"));
923
924         status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
925                         &extra_data);
926
927         if (NT_STATUS_IS_OK(status)) {
928                 s3call->response.extra_data.data = extra_data;
929                 s3call->response.length += extra_data_len;
930                 if (extra_data) {
931                         s3call->response.length += 1;
932                 }
933         }
934
935         wbsrv_samba3_async_epilogue(status, s3call);
936 }
937
938 /* NSS calls */
939
940 static void getpwnam_recv(struct composite_context *ctx);
941
942 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
943 {
944         struct composite_context *ctx;
945         struct wbsrv_service *service =
946                 s3call->wbconn->listen_socket->service;
947
948         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
949
950         ctx = wb_cmd_getpwnam_send(s3call, service,
951                         s3call->request.data.username);
952         NT_STATUS_HAVE_NO_MEMORY(ctx);
953
954         ctx->async.fn = getpwnam_recv;
955         ctx->async.private_data = s3call;
956         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
957         return NT_STATUS_OK;
958 }
959
960 static void getpwnam_recv(struct composite_context *ctx)
961 {
962         struct wbsrv_samba3_call *s3call =
963                 talloc_get_type(ctx->async.private_data,
964                                 struct wbsrv_samba3_call);
965         NTSTATUS status;
966         struct winbindd_pw *pw;
967
968         DEBUG(5, ("getpwnam_recv called\n"));
969
970         status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
971         if(NT_STATUS_IS_OK(status))
972                 s3call->response.data.pw = *pw;
973
974         wbsrv_samba3_async_epilogue(status, s3call);
975 }
976
977 static void getpwuid_recv(struct composite_context *ctx);
978
979 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
980 {
981         struct composite_context *ctx;
982         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
983
984         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
985
986         ctx = wb_cmd_getpwuid_send(s3call, service,
987                         s3call->request.data.uid);
988         NT_STATUS_HAVE_NO_MEMORY(ctx);
989
990         ctx->async.fn = getpwuid_recv;
991         ctx->async.private_data = s3call;
992         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
993         return NT_STATUS_OK;
994 }
995
996 static void getpwuid_recv(struct composite_context *ctx)
997 {
998         struct wbsrv_samba3_call *s3call =
999                 talloc_get_type(ctx->async.private_data,
1000                                 struct wbsrv_samba3_call);
1001         NTSTATUS status;
1002         struct winbindd_pw *pw;
1003
1004         DEBUG(5, ("getpwuid_recv called\n"));
1005
1006         status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
1007         if (NT_STATUS_IS_OK(status))
1008                 s3call->response.data.pw = *pw;
1009
1010         wbsrv_samba3_async_epilogue(status, s3call);
1011 }
1012
1013 static void setpwent_recv(struct composite_context *ctx);
1014
1015 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
1016 {
1017         struct composite_context *ctx;
1018         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1019
1020         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
1021
1022         ctx = wb_cmd_setpwent_send(s3call, service);
1023         NT_STATUS_HAVE_NO_MEMORY(ctx);
1024
1025         ctx->async.fn = setpwent_recv;
1026         ctx->async.private_data = s3call;
1027         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1028         return NT_STATUS_OK;
1029 }
1030
1031 static void setpwent_recv(struct composite_context *ctx)
1032 {
1033         struct wbsrv_samba3_call *s3call =
1034                 talloc_get_type(ctx->async.private_data,
1035                                 struct wbsrv_samba3_call);
1036         NTSTATUS status;
1037         struct wbsrv_pwent *pwent;
1038
1039         DEBUG(5, ("setpwent_recv called\n"));
1040
1041         status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
1042         if (NT_STATUS_IS_OK(status)) {
1043                 s3call->wbconn->protocol_private_data = pwent;
1044         }
1045
1046         wbsrv_samba3_async_epilogue(status, s3call);
1047 }
1048
1049 static void getpwent_recv(struct composite_context *ctx);
1050
1051 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
1052 {
1053         struct composite_context *ctx;
1054         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1055         struct wbsrv_pwent *pwent;
1056
1057         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
1058
1059         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
1060
1061         pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
1062                         struct wbsrv_pwent);
1063         NT_STATUS_HAVE_NO_MEMORY(pwent);
1064
1065         ctx = wb_cmd_getpwent_send(s3call, service, pwent,
1066                         s3call->request.data.num_entries);
1067         NT_STATUS_HAVE_NO_MEMORY(ctx);
1068
1069         ctx->async.fn = getpwent_recv;
1070         ctx->async.private_data = s3call;
1071         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1072         return NT_STATUS_OK;
1073 }
1074
1075 static void getpwent_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         struct winbindd_pw *pw;
1082         uint32_t num_users;
1083
1084         DEBUG(5, ("getpwent_recv called\n"));
1085
1086         status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
1087         if (NT_STATUS_IS_OK(status)) {
1088                 uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
1089
1090                 s3call->response.data.num_entries = num_users;
1091                 s3call->response.extra_data.data = pw;
1092                 s3call->response.length += extra_len;
1093         }
1094
1095         wbsrv_samba3_async_epilogue(status, s3call);
1096 }
1097
1098 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
1099 {
1100         struct wbsrv_pwent *pwent =
1101                 talloc_get_type(s3call->wbconn->protocol_private_data,
1102                                 struct wbsrv_pwent);
1103         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
1104
1105         talloc_free(pwent);
1106
1107         s3call->wbconn->protocol_private_data = NULL;
1108         s3call->response.result = WINBINDD_OK;
1109         return NT_STATUS_OK;
1110 }
1111
1112
1113 static void getgrnam_recv(struct composite_context *ctx);
1114
1115 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
1116 {
1117         struct composite_context *ctx;
1118         struct wbsrv_service *service =
1119                 s3call->wbconn->listen_socket->service;
1120
1121         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
1122
1123         ctx = wb_cmd_getgrnam_send(s3call, service,
1124                         s3call->request.data.groupname);
1125         NT_STATUS_HAVE_NO_MEMORY(ctx);
1126
1127         ctx->async.fn = getgrnam_recv;
1128         ctx->async.private_data = s3call;
1129         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1130         return NT_STATUS_OK;
1131 }
1132
1133 static void getgrnam_recv(struct composite_context *ctx)
1134 {
1135         struct wbsrv_samba3_call *s3call =
1136                 talloc_get_type(ctx->async.private_data,
1137                                 struct wbsrv_samba3_call);
1138         NTSTATUS status;
1139         struct winbindd_gr *gr;
1140
1141         DEBUG(5, ("getgrnam_recv called\n"));
1142
1143         status = wb_cmd_getgrnam_recv(ctx, s3call, &gr);
1144         if(NT_STATUS_IS_OK(status))
1145                 s3call->response.data.gr = *gr;
1146
1147         wbsrv_samba3_async_epilogue(status, s3call);
1148 }
1149
1150 static void getgrgid_recv(struct composite_context *ctx);
1151
1152 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
1153 {
1154         struct composite_context *ctx;
1155         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1156
1157         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
1158
1159         ctx = wb_cmd_getgrgid_send(s3call, service,
1160                         s3call->request.data.gid);
1161         NT_STATUS_HAVE_NO_MEMORY(ctx);
1162
1163         ctx->async.fn = getgrgid_recv;
1164         ctx->async.private_data = s3call;
1165         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1166         return NT_STATUS_OK;
1167 }
1168
1169 static void getgrgid_recv(struct composite_context *ctx)
1170 {
1171         struct wbsrv_samba3_call *s3call =
1172                 talloc_get_type(ctx->async.private_data,
1173                                 struct wbsrv_samba3_call);
1174         NTSTATUS status;
1175         struct winbindd_gr *gr;
1176
1177         DEBUG(5, ("getgrgid_recv called\n"));
1178
1179         status = wb_cmd_getgrgid_recv(ctx, s3call, &gr);
1180         if (NT_STATUS_IS_OK(status))
1181                 s3call->response.data.gr = *gr;
1182
1183         wbsrv_samba3_async_epilogue(status, s3call);
1184 }
1185
1186 static void getgroups_recv(struct composite_context *ctx);
1187
1188 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
1189 {
1190         struct composite_context *ctx;
1191         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1192
1193         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
1194         /* S3 code do the same so why not ... */
1195         s3call->request.data.username[sizeof(s3call->request.data.username)-1]='\0';
1196         ctx = wb_cmd_getgroups_send(s3call, service, s3call->request.data.username);
1197         NT_STATUS_HAVE_NO_MEMORY(ctx);
1198
1199         ctx->async.fn = getgroups_recv;
1200         ctx->async.private_data = s3call;
1201         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1202         return NT_STATUS_OK;
1203 }
1204
1205 static void getgroups_recv(struct composite_context *ctx)
1206 {
1207         struct wbsrv_samba3_call *s3call =
1208                 talloc_get_type(ctx->async.private_data,
1209                                 struct wbsrv_samba3_call);
1210         gid_t *gids;
1211         uint32_t num_groups;
1212         NTSTATUS status;
1213         DEBUG(5, ("getgroups_recv called\n"));
1214
1215         status = wb_cmd_getgroups_recv(ctx, s3call, &gids, &num_groups);
1216         if (NT_STATUS_IS_OK(status)) {
1217                 uint32_t extra_len = sizeof(gid_t) * num_groups;
1218
1219                 s3call->response.data.num_entries = num_groups;
1220                 s3call->response.extra_data.data = gids;
1221                 s3call->response.length += extra_len;
1222         } else {
1223                 s3call->response.result = WINBINDD_ERROR;
1224         }
1225
1226         wbsrv_samba3_async_epilogue(status, s3call);
1227 }
1228
1229 static void setgrent_recv(struct composite_context *ctx);
1230
1231 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
1232 {
1233         struct composite_context *ctx;
1234         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1235
1236         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
1237
1238         ctx = wb_cmd_setgrent_send(s3call, service);
1239         NT_STATUS_HAVE_NO_MEMORY(ctx);
1240
1241         ctx->async.fn = setgrent_recv;
1242         ctx->async.private_data = s3call;
1243         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1244         return NT_STATUS_OK;
1245 }
1246
1247 static void setgrent_recv(struct composite_context *ctx)
1248 {
1249         struct wbsrv_samba3_call *s3call =
1250                 talloc_get_type(ctx->async.private_data,
1251                                 struct wbsrv_samba3_call);
1252         NTSTATUS status;
1253         struct wbsrv_grent *grent;
1254
1255         DEBUG(5, ("setpwent_recv called\n"));
1256
1257         status = wb_cmd_setgrent_recv(ctx, s3call->wbconn, &grent);
1258         if (NT_STATUS_IS_OK(status)) {
1259                 s3call->wbconn->protocol_private_data = grent;
1260         }
1261
1262         wbsrv_samba3_async_epilogue(status, s3call);
1263 }
1264
1265 static void getgrent_recv(struct composite_context *ctx);
1266
1267 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
1268 {
1269         struct composite_context *ctx;
1270         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1271         struct wbsrv_grent *grent;
1272
1273         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
1274
1275         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
1276
1277         grent = talloc_get_type(s3call->wbconn->protocol_private_data,
1278                         struct wbsrv_grent);
1279         NT_STATUS_HAVE_NO_MEMORY(grent);
1280
1281         ctx = wb_cmd_getgrent_send(s3call, service, grent,
1282                         s3call->request.data.num_entries);
1283         NT_STATUS_HAVE_NO_MEMORY(ctx);
1284
1285         ctx->async.fn = getgrent_recv;
1286         ctx->async.private_data = s3call;
1287         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1288         return NT_STATUS_OK;
1289 }
1290
1291 static void getgrent_recv(struct composite_context *ctx)
1292 {
1293         struct wbsrv_samba3_call *s3call =
1294                 talloc_get_type(ctx->async.private_data,
1295                                 struct wbsrv_samba3_call);
1296         NTSTATUS status;
1297         struct winbindd_gr *gr;
1298         uint32_t num_groups;
1299
1300         DEBUG(5, ("getgrent_recv called\n"));
1301
1302         status = wb_cmd_getgrent_recv(ctx, s3call, &gr, &num_groups);
1303         if (NT_STATUS_IS_OK(status)) {
1304                 uint32_t extra_len = sizeof(struct winbindd_gr) * num_groups;
1305
1306                 s3call->response.data.num_entries = num_groups;
1307                 s3call->response.extra_data.data = gr;
1308                 s3call->response.length += extra_len;
1309         }
1310
1311         wbsrv_samba3_async_epilogue(status, s3call);
1312 }
1313
1314 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
1315 {
1316         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
1317         s3call->response.result = WINBINDD_OK;
1318         return NT_STATUS_OK;
1319 }
1320
1321 static void sid2uid_recv(struct composite_context *ctx);
1322
1323 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
1324 {
1325         struct composite_context *ctx;
1326         struct wbsrv_service *service =
1327                 s3call->wbconn->listen_socket->service;
1328         struct dom_sid *sid;
1329
1330         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
1331
1332         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
1333         NT_STATUS_HAVE_NO_MEMORY(sid);
1334
1335         ctx = wb_sid2uid_send(s3call, service, sid);
1336         NT_STATUS_HAVE_NO_MEMORY(ctx);
1337
1338         ctx->async.fn = sid2uid_recv;
1339         ctx->async.private_data = s3call;
1340         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1341         return NT_STATUS_OK;
1342
1343 }
1344
1345 static void sid2uid_recv(struct composite_context *ctx)
1346 {
1347         struct wbsrv_samba3_call *s3call =
1348                 talloc_get_type(ctx->async.private_data,
1349                                 struct wbsrv_samba3_call);
1350         NTSTATUS status;
1351
1352         DEBUG(5, ("sid2uid_recv called\n"));
1353
1354         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
1355
1356         wbsrv_samba3_async_epilogue(status, s3call);
1357 }
1358
1359 static void sid2gid_recv(struct composite_context *ctx);
1360
1361 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
1362 {
1363         struct composite_context *ctx;
1364         struct wbsrv_service *service =
1365                 s3call->wbconn->listen_socket->service;
1366         struct dom_sid *sid;
1367
1368         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
1369
1370         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
1371         NT_STATUS_HAVE_NO_MEMORY(sid);
1372
1373         ctx = wb_sid2gid_send(s3call, service, sid);
1374         NT_STATUS_HAVE_NO_MEMORY(ctx);
1375
1376         ctx->async.fn = sid2gid_recv;
1377         ctx->async.private_data = s3call;
1378         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1379         return NT_STATUS_OK;
1380
1381 }
1382
1383 static void sid2gid_recv(struct composite_context *ctx)
1384 {
1385         struct wbsrv_samba3_call *s3call =
1386                 talloc_get_type(ctx->async.private_data,
1387                                 struct wbsrv_samba3_call);
1388         NTSTATUS status;
1389
1390         DEBUG(5, ("sid2gid_recv called\n"));
1391
1392         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
1393
1394         wbsrv_samba3_async_epilogue(status, s3call);
1395 }
1396
1397 static void uid2sid_recv(struct composite_context *ctx);
1398
1399 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1400 {
1401         struct composite_context *ctx;
1402         struct wbsrv_service *service =
1403                 s3call->wbconn->listen_socket->service;
1404
1405         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1406
1407         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
1408         NT_STATUS_HAVE_NO_MEMORY(ctx);
1409
1410         ctx->async.fn = uid2sid_recv;
1411         ctx->async.private_data = s3call;
1412         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1413         return NT_STATUS_OK;
1414
1415 }
1416
1417 static void uid2sid_recv(struct composite_context *ctx)
1418 {
1419         struct wbsrv_samba3_call *s3call =
1420                 talloc_get_type(ctx->async.private_data,
1421                                 struct wbsrv_samba3_call);
1422         NTSTATUS status;
1423         struct dom_sid *sid;
1424         char *sid_str;
1425
1426         DEBUG(5, ("uid2sid_recv called\n"));
1427
1428         status = wb_uid2sid_recv(ctx, s3call, &sid);
1429         if(NT_STATUS_IS_OK(status)) {
1430                 sid_str = dom_sid_string(s3call, sid);
1431
1432                 /* If the conversion failed, bail out with a failure. */
1433                 if (sid_str == NULL)
1434                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1435
1436                 /* But we assume this worked, so we'll set the string. Work
1437                  * done. */
1438                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1439                 s3call->response.data.sid.type = SID_NAME_USER;
1440         }
1441
1442         wbsrv_samba3_async_epilogue(status, s3call);
1443 }
1444
1445 static void gid2sid_recv(struct composite_context *ctx);
1446
1447 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1448 {
1449         struct composite_context *ctx;
1450         struct wbsrv_service *service =
1451                 s3call->wbconn->listen_socket->service;
1452
1453         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1454
1455         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1456         NT_STATUS_HAVE_NO_MEMORY(ctx);
1457
1458         ctx->async.fn = gid2sid_recv;
1459         ctx->async.private_data = s3call;
1460         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1461         return NT_STATUS_OK;
1462
1463 }
1464
1465 static void gid2sid_recv(struct composite_context *ctx)
1466 {
1467         struct wbsrv_samba3_call *s3call =
1468                 talloc_get_type(ctx->async.private_data,
1469                                 struct wbsrv_samba3_call);
1470         NTSTATUS status;
1471         struct dom_sid *sid;
1472         char *sid_str;
1473
1474         DEBUG(5, ("gid2sid_recv called\n"));
1475
1476         status = wb_gid2sid_recv(ctx, s3call, &sid);
1477         if(NT_STATUS_IS_OK(status)) {
1478                 sid_str = dom_sid_string(s3call, sid);
1479
1480                 if (sid_str == NULL)
1481                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1482
1483                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1484                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1485         }
1486
1487         wbsrv_samba3_async_epilogue(status, s3call);
1488 }
1489