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