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