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