Update 4.2 Roadmap file
[mat/samba.git] / source4 / winbind / wb_samba3_cmd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main winbindd samba3 server routines
4
5    Copyright (C) Stefan Metzmacher      2005
6    Copyright (C) Volker Lendecke        2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
8    Copyright (C) Kai Blin               2009
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "winbind/wb_server.h"
26 #include "param/param.h"
27 #include "winbind/wb_helper.h"
28 #include "libcli/composite/composite.h"
29 #include "version.h"
30 #include "librpc/gen_ndr/ndr_netlogon.h"
31 #include "libcli/security/security.h"
32 #include "../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         if (s3call->request->flags & WBFLAG_PAM_AUTH_PAC) {
644                 DEBUG(3, ("PAC validation not supported in this winbind implementation\n"));
645                 return NT_STATUS_INVALID_PARAMETER;
646         }
647
648         chal.data       = s3call->request->data.auth_crap.chal;
649         chal.length     = sizeof(s3call->request->data.auth_crap.chal);
650         nt_resp.data    = (uint8_t *)s3call->request->data.auth_crap.nt_resp;
651         nt_resp.length  = s3call->request->data.auth_crap.nt_resp_len;
652         lm_resp.data    = (uint8_t *)s3call->request->data.auth_crap.lm_resp;
653         lm_resp.length  = s3call->request->data.auth_crap.lm_resp_len;
654
655         ctx = wb_cmd_pam_auth_crap_send(
656                 s3call, service,
657                 s3call->request->data.auth_crap.logon_parameters,
658                 s3call->request->data.auth_crap.domain,
659                 s3call->request->data.auth_crap.user,
660                 s3call->request->data.auth_crap.workstation,
661                 chal, nt_resp, lm_resp);
662         NT_STATUS_HAVE_NO_MEMORY(ctx);
663
664         ctx->async.fn = pam_auth_crap_recv;
665         ctx->async.private_data = s3call;
666         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
667         return NT_STATUS_OK;
668 }
669
670 static void pam_auth_crap_recv(struct composite_context *ctx)
671 {
672         struct wbsrv_samba3_call *s3call =
673                 talloc_get_type(ctx->async.private_data,
674                                 struct wbsrv_samba3_call);
675         NTSTATUS status;
676         DATA_BLOB info3;
677         struct netr_UserSessionKey user_session_key;
678         struct netr_LMSessionKey lm_key;
679         char *unix_username;
680         
681         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
682                                            &user_session_key, &lm_key, &unix_username);
683         if (!NT_STATUS_IS_OK(status)) goto done;
684
685         if (s3call->request->flags & WBFLAG_PAM_USER_SESSION_KEY) {
686                 memcpy(s3call->response->data.auth.user_session_key,
687                        &user_session_key.key,
688                        sizeof(s3call->response->data.auth.user_session_key));
689         }
690
691         if (s3call->request->flags & WBFLAG_PAM_INFO3_TEXT) {
692                 status = wb_samba3_append_info3_as_txt(ctx, s3call, info3);
693                 if (!NT_STATUS_IS_OK(status)) {
694                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
695                                   nt_errstr(status)));
696                         goto done;
697                 }
698         }
699
700         if (s3call->request->flags & WBFLAG_PAM_INFO3_NDR) {
701                 s3call->response->extra_data.data = info3.data;
702                 s3call->response->length += info3.length;
703         }
704
705         if (s3call->request->flags & WBFLAG_PAM_LMKEY) {
706                 memcpy(s3call->response->data.auth.first_8_lm_hash,
707                        lm_key.key,
708                        sizeof(s3call->response->data.auth.first_8_lm_hash));
709         }
710         
711         if (s3call->request->flags & WBFLAG_PAM_UNIX_NAME) {
712                 WBSRV_SAMBA3_SET_STRING(s3call->response->data.auth.unix_username,unix_username);
713         }
714
715  done:
716         wbsrv_samba3_async_auth_epilogue(status, s3call);
717 }
718
719 /* Plaintext authentication 
720    
721    This interface is used by ntlm_auth in it's 'basic' authentication
722    mode, as well as by pam_winbind to authenticate users where we are
723    given a plaintext password.
724 */
725
726 static void pam_auth_recv(struct composite_context *ctx);
727
728 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
729 {
730         struct composite_context *ctx;
731         struct wbsrv_service *service =
732                 s3call->wbconn->listen_socket->service;
733         struct cli_credentials *credentials;
734         char *user, *domain;
735
736         if (!wb_samba3_split_username(s3call, s3call->wbconn->lp_ctx,
737                                  s3call->request->data.auth.user,
738                                  &domain, &user)) {
739                 return NT_STATUS_NO_SUCH_USER;
740         }
741
742         credentials = cli_credentials_init(s3call);
743         if (!credentials) {
744                 return NT_STATUS_NO_MEMORY;
745         }
746         cli_credentials_set_conf(credentials, service->task->lp_ctx);
747         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
748         cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
749
750         cli_credentials_set_password(credentials, s3call->request->data.auth.pass, CRED_SPECIFIED);
751
752         ctx = wb_cmd_pam_auth_send(s3call, service, credentials);
753         NT_STATUS_HAVE_NO_MEMORY(ctx);
754
755         ctx->async.fn = pam_auth_recv;
756         ctx->async.private_data = s3call;
757         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
758         return NT_STATUS_OK;
759 }
760
761 static void pam_auth_recv(struct composite_context *ctx)
762 {
763         struct wbsrv_samba3_call *s3call =
764                 talloc_get_type(ctx->async.private_data,
765                                 struct wbsrv_samba3_call);
766         NTSTATUS status;
767         DATA_BLOB info3;
768         struct netr_UserSessionKey user_session_key;
769         struct netr_LMSessionKey lm_key;
770         char *unix_username;
771
772         status = wb_cmd_pam_auth_recv(ctx, s3call, &info3, 
773                                       &user_session_key, &lm_key, &unix_username);
774
775         if (!NT_STATUS_IS_OK(status)) goto done;
776
777         if (s3call->request->flags & WBFLAG_PAM_USER_SESSION_KEY) {
778                 memcpy(s3call->response->data.auth.user_session_key,
779                        &user_session_key.key,
780                        sizeof(s3call->response->data.auth.user_session_key));
781         }
782
783         if (s3call->request->flags & WBFLAG_PAM_INFO3_TEXT) {
784                 status = wb_samba3_append_info3_as_txt(ctx, s3call, info3);
785                 if (!NT_STATUS_IS_OK(status)) {
786                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
787                                   nt_errstr(status)));
788                         goto done;
789                 }
790         }
791
792         if (s3call->request->flags & WBFLAG_PAM_INFO3_NDR) {
793                 s3call->response->extra_data.data = info3.data;
794                 s3call->response->length += info3.length;
795         }
796
797         if (s3call->request->flags & WBFLAG_PAM_LMKEY) {
798                 memcpy(s3call->response->data.auth.first_8_lm_hash,
799                        lm_key.key,
800                        sizeof(s3call->response->data.auth.first_8_lm_hash));
801         }
802         
803         if (s3call->request->flags & WBFLAG_PAM_UNIX_NAME) {
804                 WBSRV_SAMBA3_SET_STRING(s3call->response->data.auth.unix_username,unix_username);
805         }
806         
807
808  done:
809         wbsrv_samba3_async_auth_epilogue(status, s3call);
810 }
811
812 /* 
813    List trusted domains
814 */
815
816 static void list_trustdom_recv_doms(struct composite_context *ctx);
817
818 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
819 {
820         struct composite_context *ctx;
821         struct wbsrv_service *service =
822                 s3call->wbconn->listen_socket->service;
823
824         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
825
826         ctx = wb_cmd_list_trustdoms_send(s3call, service);
827         NT_STATUS_HAVE_NO_MEMORY(ctx);
828
829         ctx->async.fn = list_trustdom_recv_doms;
830         ctx->async.private_data = s3call;
831         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
832         return NT_STATUS_OK;
833 }
834
835 static void list_trustdom_recv_doms(struct composite_context *ctx)
836 {
837         struct wbsrv_samba3_call *s3call =
838                 talloc_get_type(ctx->async.private_data,
839                                 struct wbsrv_samba3_call);
840         uint32_t i, num_domains;
841         struct wb_dom_info **domains;
842         NTSTATUS status;
843         char *result;
844
845         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
846                                             &domains);
847         if (!NT_STATUS_IS_OK(status)) goto done;
848
849         result = talloc_strdup(s3call, "");
850         if (result == NULL) {
851                 status = NT_STATUS_NO_MEMORY;
852                 goto done;
853         }
854
855         for (i=0; i<num_domains; i++) {
856                 result = talloc_asprintf_append_buffer(
857                         result, "%s\\%s\\%s",
858                         domains[i]->name, domains[i]->name,
859                         dom_sid_string(s3call, domains[i]->sid));
860         }
861
862         if (result == NULL) {
863                 status = NT_STATUS_NO_MEMORY;
864                 goto done;
865         }
866
867         s3call->response->result = WINBINDD_OK;
868         if (num_domains > 0) {
869                 s3call->response->extra_data.data = result;
870                 s3call->response->length += strlen(result)+1;
871                 s3call->response->data.num_entries = num_domains;
872         }
873
874  done:
875         wbsrv_samba3_async_epilogue(status, s3call);
876 }
877
878 /* list groups */
879 static void list_groups_recv(struct composite_context *ctx);
880
881 NTSTATUS wbsrv_samba3_list_groups(struct wbsrv_samba3_call *s3call)
882 {
883         struct composite_context *ctx;
884         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
885
886         DEBUG(5, ("wbsrv_samba4_list_groups called\n"));
887
888         ctx = wb_cmd_list_groups_send(s3call, service,
889                                       s3call->request->domain_name);
890         NT_STATUS_HAVE_NO_MEMORY(ctx);
891
892         ctx->async.fn = list_groups_recv;
893         ctx->async.private_data = s3call;
894         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
895         return NT_STATUS_OK;
896 }
897
898 static void list_groups_recv(struct composite_context *ctx)
899 {
900         struct wbsrv_samba3_call *s3call = talloc_get_type_abort(
901                                                 ctx->async.private_data,
902                                                 struct wbsrv_samba3_call);
903         uint32_t extra_data_len;
904         char *extra_data;
905         uint32_t num_groups;
906         NTSTATUS status;
907
908         DEBUG(5, ("list_groups_recv called\n"));
909
910         status = wb_cmd_list_groups_recv(ctx, s3call, &extra_data_len,
911                         &extra_data, &num_groups);
912
913         if (NT_STATUS_IS_OK(status)) {
914                 s3call->response->extra_data.data = extra_data;
915                 s3call->response->length += extra_data_len;
916                 if (extra_data) {
917                         s3call->response->length += 1;
918                         s3call->response->data.num_entries = num_groups;
919                 }
920         }
921
922         wbsrv_samba3_async_epilogue(status, s3call);
923 }
924
925 /* List users */
926
927 static void list_users_recv(struct composite_context *ctx);
928
929 NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
930 {
931         struct composite_context *ctx;
932         struct wbsrv_service *service =
933                 s3call->wbconn->listen_socket->service;
934
935         DEBUG(5, ("wbsrv_samba3_list_users called\n"));
936
937         ctx = wb_cmd_list_users_send(s3call, service,
938                         s3call->request->domain_name);
939         NT_STATUS_HAVE_NO_MEMORY(ctx);
940
941         ctx->async.fn = list_users_recv;
942         ctx->async.private_data = s3call;
943         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
944         return NT_STATUS_OK;
945 }
946
947 static void list_users_recv(struct composite_context *ctx)
948 {
949         struct wbsrv_samba3_call *s3call =
950                 talloc_get_type(ctx->async.private_data,
951                                 struct wbsrv_samba3_call);
952         uint32_t extra_data_len;
953         char *extra_data;
954         uint32_t num_users;
955         NTSTATUS status;
956
957         DEBUG(5, ("list_users_recv called\n"));
958
959         status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
960                         &extra_data, &num_users);
961
962         if (NT_STATUS_IS_OK(status)) {
963                 s3call->response->extra_data.data = extra_data;
964                 s3call->response->length += extra_data_len;
965                 if (extra_data) {
966                         s3call->response->length += 1;
967                         s3call->response->data.num_entries = num_users;
968                 }
969         }
970
971         wbsrv_samba3_async_epilogue(status, s3call);
972 }
973
974 /* NSS calls */
975
976 static void getpwnam_recv(struct composite_context *ctx);
977
978 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
979 {
980         struct composite_context *ctx;
981         struct wbsrv_service *service =
982                 s3call->wbconn->listen_socket->service;
983
984         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
985
986         ctx = wb_cmd_getpwnam_send(s3call, service,
987                         s3call->request->data.username);
988         NT_STATUS_HAVE_NO_MEMORY(ctx);
989
990         ctx->async.fn = getpwnam_recv;
991         ctx->async.private_data = s3call;
992         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
993         return NT_STATUS_OK;
994 }
995
996 static void getpwnam_recv(struct composite_context *ctx)
997 {
998         struct wbsrv_samba3_call *s3call =
999                 talloc_get_type(ctx->async.private_data,
1000                                 struct wbsrv_samba3_call);
1001         NTSTATUS status;
1002         struct winbindd_pw *pw;
1003
1004         DEBUG(5, ("getpwnam_recv called\n"));
1005
1006         status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
1007         if(NT_STATUS_IS_OK(status))
1008                 s3call->response->data.pw = *pw;
1009
1010         wbsrv_samba3_async_epilogue(status, s3call);
1011 }
1012
1013 static void getpwuid_recv(struct composite_context *ctx);
1014
1015 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
1016 {
1017         struct composite_context *ctx;
1018         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1019
1020         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
1021
1022         ctx = wb_cmd_getpwuid_send(s3call, service,
1023                         s3call->request->data.uid);
1024         NT_STATUS_HAVE_NO_MEMORY(ctx);
1025
1026         ctx->async.fn = getpwuid_recv;
1027         ctx->async.private_data = s3call;
1028         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1029         return NT_STATUS_OK;
1030 }
1031
1032 static void getpwuid_recv(struct composite_context *ctx)
1033 {
1034         struct wbsrv_samba3_call *s3call =
1035                 talloc_get_type(ctx->async.private_data,
1036                                 struct wbsrv_samba3_call);
1037         NTSTATUS status;
1038         struct winbindd_pw *pw;
1039
1040         DEBUG(5, ("getpwuid_recv called\n"));
1041
1042         status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
1043         if (NT_STATUS_IS_OK(status))
1044                 s3call->response->data.pw = *pw;
1045
1046         wbsrv_samba3_async_epilogue(status, s3call);
1047 }
1048
1049 static void setpwent_recv(struct composite_context *ctx);
1050
1051 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
1052 {
1053         struct composite_context *ctx;
1054         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1055
1056         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
1057
1058         ctx = wb_cmd_setpwent_send(s3call, service);
1059         NT_STATUS_HAVE_NO_MEMORY(ctx);
1060
1061         ctx->async.fn = setpwent_recv;
1062         ctx->async.private_data = s3call;
1063         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1064         return NT_STATUS_OK;
1065 }
1066
1067 static void setpwent_recv(struct composite_context *ctx)
1068 {
1069         struct wbsrv_samba3_call *s3call =
1070                 talloc_get_type(ctx->async.private_data,
1071                                 struct wbsrv_samba3_call);
1072         NTSTATUS status;
1073         struct wbsrv_pwent *pwent;
1074
1075         DEBUG(5, ("setpwent_recv called\n"));
1076
1077         status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
1078         if (NT_STATUS_IS_OK(status)) {
1079                 s3call->wbconn->protocol_private_data = pwent;
1080         }
1081
1082         wbsrv_samba3_async_epilogue(status, s3call);
1083 }
1084
1085 static void getpwent_recv(struct composite_context *ctx);
1086
1087 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
1088 {
1089         struct composite_context *ctx;
1090         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1091         struct wbsrv_pwent *pwent;
1092
1093         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
1094
1095         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
1096
1097         pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
1098                         struct wbsrv_pwent);
1099         NT_STATUS_HAVE_NO_MEMORY(pwent);
1100
1101         ctx = wb_cmd_getpwent_send(s3call, service, pwent,
1102                         s3call->request->data.num_entries);
1103         NT_STATUS_HAVE_NO_MEMORY(ctx);
1104
1105         ctx->async.fn = getpwent_recv;
1106         ctx->async.private_data = s3call;
1107         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1108         return NT_STATUS_OK;
1109 }
1110
1111 static void getpwent_recv(struct composite_context *ctx)
1112 {
1113         struct wbsrv_samba3_call *s3call =
1114                 talloc_get_type(ctx->async.private_data,
1115                                 struct wbsrv_samba3_call);
1116         NTSTATUS status;
1117         struct winbindd_pw *pw;
1118         uint32_t num_users;
1119
1120         DEBUG(5, ("getpwent_recv called\n"));
1121
1122         status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
1123         if (NT_STATUS_IS_OK(status)) {
1124                 uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
1125
1126                 s3call->response->data.num_entries = num_users;
1127                 s3call->response->extra_data.data = pw;
1128                 s3call->response->length += extra_len;
1129         }
1130
1131         wbsrv_samba3_async_epilogue(status, s3call);
1132 }
1133
1134 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
1135 {
1136         struct wbsrv_pwent *pwent =
1137                 talloc_get_type(s3call->wbconn->protocol_private_data,
1138                                 struct wbsrv_pwent);
1139         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
1140
1141         talloc_free(pwent);
1142
1143         s3call->wbconn->protocol_private_data = NULL;
1144         s3call->response->result = WINBINDD_OK;
1145         return NT_STATUS_OK;
1146 }
1147
1148
1149 static void getgrnam_recv(struct composite_context *ctx);
1150
1151 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
1152 {
1153         struct composite_context *ctx;
1154         struct wbsrv_service *service =
1155                 s3call->wbconn->listen_socket->service;
1156
1157         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
1158
1159         ctx = wb_cmd_getgrnam_send(s3call, service,
1160                         s3call->request->data.groupname);
1161         NT_STATUS_HAVE_NO_MEMORY(ctx);
1162
1163         ctx->async.fn = getgrnam_recv;
1164         ctx->async.private_data = s3call;
1165         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1166         return NT_STATUS_OK;
1167 }
1168
1169 static void getgrnam_recv(struct composite_context *ctx)
1170 {
1171         struct wbsrv_samba3_call *s3call =
1172                 talloc_get_type(ctx->async.private_data,
1173                                 struct wbsrv_samba3_call);
1174         NTSTATUS status;
1175         struct winbindd_gr *gr;
1176
1177         DEBUG(5, ("getgrnam_recv called\n"));
1178
1179         status = wb_cmd_getgrnam_recv(ctx, s3call, &gr);
1180         if(NT_STATUS_IS_OK(status))
1181                 s3call->response->data.gr = *gr;
1182
1183         wbsrv_samba3_async_epilogue(status, s3call);
1184 }
1185
1186 static void getgrgid_recv(struct composite_context *ctx);
1187
1188 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
1189 {
1190         struct composite_context *ctx;
1191         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1192
1193         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
1194
1195         ctx = wb_cmd_getgrgid_send(s3call, service,
1196                         s3call->request->data.gid);
1197         NT_STATUS_HAVE_NO_MEMORY(ctx);
1198
1199         ctx->async.fn = getgrgid_recv;
1200         ctx->async.private_data = s3call;
1201         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1202         return NT_STATUS_OK;
1203 }
1204
1205 static void getgrgid_recv(struct composite_context *ctx)
1206 {
1207         struct wbsrv_samba3_call *s3call =
1208                 talloc_get_type(ctx->async.private_data,
1209                                 struct wbsrv_samba3_call);
1210         NTSTATUS status;
1211         struct winbindd_gr *gr;
1212
1213         DEBUG(5, ("getgrgid_recv called\n"));
1214
1215         status = wb_cmd_getgrgid_recv(ctx, s3call, &gr);
1216         if (NT_STATUS_IS_OK(status))
1217                 s3call->response->data.gr = *gr;
1218
1219         wbsrv_samba3_async_epilogue(status, s3call);
1220 }
1221
1222 static void getgroups_recv(struct composite_context *ctx);
1223
1224 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
1225 {
1226         struct composite_context *ctx;
1227         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1228
1229         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
1230         /* S3 code do the same so why not ... */
1231         s3call->request->data.username[sizeof(s3call->request->data.username)-1]='\0';
1232         ctx = wb_cmd_getgroups_send(s3call, service, s3call->request->data.username);
1233         NT_STATUS_HAVE_NO_MEMORY(ctx);
1234
1235         ctx->async.fn = getgroups_recv;
1236         ctx->async.private_data = s3call;
1237         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1238         return NT_STATUS_OK;
1239 }
1240
1241 static void getgroups_recv(struct composite_context *ctx)
1242 {
1243         struct wbsrv_samba3_call *s3call =
1244                 talloc_get_type(ctx->async.private_data,
1245                                 struct wbsrv_samba3_call);
1246         gid_t *gids;
1247         uint32_t num_groups;
1248         NTSTATUS status;
1249         DEBUG(5, ("getgroups_recv called\n"));
1250
1251         status = wb_cmd_getgroups_recv(ctx, s3call, &gids, &num_groups);
1252         if (NT_STATUS_IS_OK(status)) {
1253                 uint32_t extra_len = sizeof(gid_t) * num_groups;
1254
1255                 s3call->response->data.num_entries = num_groups;
1256                 s3call->response->extra_data.data = gids;
1257                 s3call->response->length += extra_len;
1258         } else {
1259                 s3call->response->result = WINBINDD_ERROR;
1260         }
1261
1262         wbsrv_samba3_async_epilogue(status, s3call);
1263 }
1264
1265 static void setgrent_recv(struct composite_context *ctx);
1266
1267 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
1268 {
1269         struct composite_context *ctx;
1270         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1271
1272         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
1273
1274         ctx = wb_cmd_setgrent_send(s3call, service);
1275         NT_STATUS_HAVE_NO_MEMORY(ctx);
1276
1277         ctx->async.fn = setgrent_recv;
1278         ctx->async.private_data = s3call;
1279         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1280         return NT_STATUS_OK;
1281 }
1282
1283 static void setgrent_recv(struct composite_context *ctx)
1284 {
1285         struct wbsrv_samba3_call *s3call =
1286                 talloc_get_type(ctx->async.private_data,
1287                                 struct wbsrv_samba3_call);
1288         NTSTATUS status;
1289         struct wbsrv_grent *grent;
1290
1291         DEBUG(5, ("setpwent_recv called\n"));
1292
1293         status = wb_cmd_setgrent_recv(ctx, s3call->wbconn, &grent);
1294         if (NT_STATUS_IS_OK(status)) {
1295                 s3call->wbconn->protocol_private_data = grent;
1296         }
1297
1298         wbsrv_samba3_async_epilogue(status, s3call);
1299 }
1300
1301 static void getgrent_recv(struct composite_context *ctx);
1302
1303 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
1304 {
1305         struct composite_context *ctx;
1306         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
1307         struct wbsrv_grent *grent;
1308
1309         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
1310
1311         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
1312
1313         grent = talloc_get_type(s3call->wbconn->protocol_private_data,
1314                         struct wbsrv_grent);
1315         NT_STATUS_HAVE_NO_MEMORY(grent);
1316
1317         ctx = wb_cmd_getgrent_send(s3call, service, grent,
1318                         s3call->request->data.num_entries);
1319         NT_STATUS_HAVE_NO_MEMORY(ctx);
1320
1321         ctx->async.fn = getgrent_recv;
1322         ctx->async.private_data = s3call;
1323         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1324         return NT_STATUS_OK;
1325 }
1326
1327 static void getgrent_recv(struct composite_context *ctx)
1328 {
1329         struct wbsrv_samba3_call *s3call =
1330                 talloc_get_type(ctx->async.private_data,
1331                                 struct wbsrv_samba3_call);
1332         NTSTATUS status;
1333         struct winbindd_gr *gr;
1334         uint32_t num_groups;
1335
1336         DEBUG(5, ("getgrent_recv called\n"));
1337
1338         status = wb_cmd_getgrent_recv(ctx, s3call, &gr, &num_groups);
1339         if (NT_STATUS_IS_OK(status)) {
1340                 uint32_t extra_len = sizeof(struct winbindd_gr) * num_groups;
1341
1342                 s3call->response->data.num_entries = num_groups;
1343                 s3call->response->extra_data.data = gr;
1344                 s3call->response->length += extra_len;
1345         }
1346
1347         wbsrv_samba3_async_epilogue(status, s3call);
1348 }
1349
1350 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
1351 {
1352         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
1353         s3call->response->result = WINBINDD_OK;
1354         return NT_STATUS_OK;
1355 }
1356
1357 static void sid2uid_recv(struct composite_context *ctx);
1358
1359 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
1360 {
1361         struct composite_context *ctx;
1362         struct wbsrv_service *service =
1363                 s3call->wbconn->listen_socket->service;
1364         struct dom_sid *sid;
1365
1366         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
1367
1368         sid = dom_sid_parse_talloc(s3call, s3call->request->data.sid);
1369         NT_STATUS_HAVE_NO_MEMORY(sid);
1370
1371         ctx = wb_sid2uid_send(s3call, service, sid);
1372         NT_STATUS_HAVE_NO_MEMORY(ctx);
1373
1374         ctx->async.fn = sid2uid_recv;
1375         ctx->async.private_data = s3call;
1376         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1377         return NT_STATUS_OK;
1378
1379 }
1380
1381 static void sid2uid_recv(struct composite_context *ctx)
1382 {
1383         struct wbsrv_samba3_call *s3call =
1384                 talloc_get_type(ctx->async.private_data,
1385                                 struct wbsrv_samba3_call);
1386         NTSTATUS status;
1387
1388         DEBUG(5, ("sid2uid_recv called\n"));
1389
1390         status = wb_sid2uid_recv(ctx, &s3call->response->data.uid);
1391
1392         wbsrv_samba3_async_epilogue(status, s3call);
1393 }
1394
1395 static void sid2gid_recv(struct composite_context *ctx);
1396
1397 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
1398 {
1399         struct composite_context *ctx;
1400         struct wbsrv_service *service =
1401                 s3call->wbconn->listen_socket->service;
1402         struct dom_sid *sid;
1403
1404         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
1405
1406         sid = dom_sid_parse_talloc(s3call, s3call->request->data.sid);
1407         NT_STATUS_HAVE_NO_MEMORY(sid);
1408
1409         ctx = wb_sid2gid_send(s3call, service, sid);
1410         NT_STATUS_HAVE_NO_MEMORY(ctx);
1411
1412         ctx->async.fn = sid2gid_recv;
1413         ctx->async.private_data = s3call;
1414         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1415         return NT_STATUS_OK;
1416
1417 }
1418
1419 static void sid2gid_recv(struct composite_context *ctx)
1420 {
1421         struct wbsrv_samba3_call *s3call =
1422                 talloc_get_type(ctx->async.private_data,
1423                                 struct wbsrv_samba3_call);
1424         NTSTATUS status;
1425
1426         DEBUG(5, ("sid2gid_recv called\n"));
1427
1428         status = wb_sid2gid_recv(ctx, &s3call->response->data.gid);
1429
1430         wbsrv_samba3_async_epilogue(status, s3call);
1431 }
1432
1433 static void uid2sid_recv(struct composite_context *ctx);
1434
1435 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1436 {
1437         struct composite_context *ctx;
1438         struct wbsrv_service *service =
1439                 s3call->wbconn->listen_socket->service;
1440
1441         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1442
1443         ctx = wb_uid2sid_send(s3call, service, s3call->request->data.uid);
1444         NT_STATUS_HAVE_NO_MEMORY(ctx);
1445
1446         ctx->async.fn = uid2sid_recv;
1447         ctx->async.private_data = s3call;
1448         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1449         return NT_STATUS_OK;
1450
1451 }
1452
1453 static void uid2sid_recv(struct composite_context *ctx)
1454 {
1455         struct wbsrv_samba3_call *s3call =
1456                 talloc_get_type(ctx->async.private_data,
1457                                 struct wbsrv_samba3_call);
1458         NTSTATUS status;
1459         struct dom_sid *sid;
1460         char *sid_str;
1461
1462         DEBUG(5, ("uid2sid_recv called\n"));
1463
1464         status = wb_uid2sid_recv(ctx, s3call, &sid);
1465         if(NT_STATUS_IS_OK(status)) {
1466                 sid_str = dom_sid_string(s3call, sid);
1467
1468                 /* If the conversion failed, bail out with a failure. */
1469                 if (sid_str == NULL)
1470                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1471
1472                 /* But we assume this worked, so we'll set the string. Work
1473                  * done. */
1474                 WBSRV_SAMBA3_SET_STRING(s3call->response->data.sid.sid, sid_str);
1475                 s3call->response->data.sid.type = SID_NAME_USER;
1476         }
1477
1478         wbsrv_samba3_async_epilogue(status, s3call);
1479 }
1480
1481 static void gid2sid_recv(struct composite_context *ctx);
1482
1483 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1484 {
1485         struct composite_context *ctx;
1486         struct wbsrv_service *service =
1487                 s3call->wbconn->listen_socket->service;
1488
1489         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1490
1491         ctx = wb_gid2sid_send(s3call, service, s3call->request->data.gid);
1492         NT_STATUS_HAVE_NO_MEMORY(ctx);
1493
1494         ctx->async.fn = gid2sid_recv;
1495         ctx->async.private_data = s3call;
1496         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1497         return NT_STATUS_OK;
1498
1499 }
1500
1501 static void gid2sid_recv(struct composite_context *ctx)
1502 {
1503         struct wbsrv_samba3_call *s3call =
1504                 talloc_get_type(ctx->async.private_data,
1505                                 struct wbsrv_samba3_call);
1506         NTSTATUS status;
1507         struct dom_sid *sid;
1508         char *sid_str;
1509
1510         DEBUG(5, ("gid2sid_recv called\n"));
1511
1512         status = wb_gid2sid_recv(ctx, s3call, &sid);
1513         if(NT_STATUS_IS_OK(status)) {
1514                 sid_str = dom_sid_string(s3call, sid);
1515
1516                 if (sid_str == NULL)
1517                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1518
1519                 WBSRV_SAMBA3_SET_STRING(s3call->response->data.sid.sid, sid_str);
1520                 s3call->response->data.sid.type = SID_NAME_DOMAIN;
1521         }
1522
1523         wbsrv_samba3_async_epilogue(status, s3call);
1524 }
1525
1526 static void sids2xids_recv(struct composite_context *ctx)
1527 {
1528         struct wbsrv_samba3_call *s3call =
1529                 talloc_get_type(ctx->async.private_data,
1530                                 struct wbsrv_samba3_call);
1531         NTSTATUS status;
1532         struct id_map *ids;
1533         unsigned i, count;
1534         struct winbindd_response *resp = s3call->response;
1535
1536         DEBUG(5, ("sids2xids_recv called\n"));
1537
1538         status = wb_sids2xids_recv(ctx, &ids, &count);
1539         if (!NT_STATUS_IS_OK(status)) {
1540                 goto done;
1541         }
1542
1543         /* fill in extra_data with the list of IDs. Each is prefixed
1544          * by 'U' or 'G' for user and group, and followed by a
1545          * newline */
1546         resp->extra_data.data = talloc_strdup(resp, "");
1547         if (resp->extra_data.data == NULL) {
1548                 status = NT_STATUS_NO_MEMORY;
1549                 goto done;
1550         }
1551
1552         for (i=0; i<count; i++) {
1553                 char type_char = '*';
1554                 if (ids[i].status != ID_MAPPED) {
1555                         resp->extra_data.data = talloc_asprintf_append_buffer(resp->extra_data.data, "\n");
1556                         if (resp->extra_data.data == NULL) {
1557                                 status = NT_STATUS_NO_MEMORY;
1558                                 goto done;
1559                         }
1560                         continue;
1561                 }
1562                 switch (ids[i].xid.type) {
1563                 case ID_TYPE_UID:
1564                         type_char = 'U';
1565                         break;
1566                 case ID_TYPE_GID:
1567                         type_char = 'G';
1568                         break;
1569                 case ID_TYPE_BOTH:
1570                         type_char = 'B';
1571                         break;
1572                 case ID_TYPE_NOT_SPECIFIED:
1573                         type_char = 'N';
1574                         break;
1575                 }
1576                 resp->extra_data.data = talloc_asprintf_append_buffer(resp->extra_data.data, "%c%u\n",
1577                                                                       type_char, (unsigned)ids[i].xid.id);
1578                 if (resp->extra_data.data == NULL) {
1579                         status = NT_STATUS_NO_MEMORY;
1580                         goto done;
1581                 }
1582         }
1583         resp->length += strlen(resp->extra_data.data) + 1;
1584
1585 done:
1586         wbsrv_samba3_async_epilogue(status, s3call);
1587 }
1588
1589
1590 NTSTATUS wbsrv_samba3_sids2xids(struct wbsrv_samba3_call *s3call)
1591 {
1592         struct composite_context *ctx;
1593         struct wbsrv_service *service =
1594                 s3call->wbconn->listen_socket->service;
1595         struct id_map *ids = NULL;
1596         unsigned count = 0;
1597         char *saveptr = NULL;
1598         char *sidstr;
1599
1600         DEBUG(5, ("wbsrv_samba3_sids2xids called\n"));
1601
1602         for (sidstr = strtok_r(s3call->request->extra_data.data, "\n", &saveptr);
1603              sidstr;
1604              sidstr = strtok_r(NULL, "\n", &saveptr)) {
1605                 count += 1;
1606                 ids = talloc_realloc(s3call, ids, struct id_map, count);
1607                 NT_STATUS_HAVE_NO_MEMORY(ids);
1608                 ids[count-1].sid = dom_sid_parse_talloc(ids, sidstr);
1609                 NT_STATUS_HAVE_NO_MEMORY(ids->sid);
1610         }
1611
1612         ctx = wb_sids2xids_send(s3call, service, count, ids);
1613         NT_STATUS_HAVE_NO_MEMORY(ctx);
1614
1615         ctx->async.fn = sids2xids_recv;
1616         ctx->async.private_data = s3call;
1617         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1618         return NT_STATUS_OK;
1619 }