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