56a168ebb0ed65386a4a7bedca61ace7c2bca8ed
[jelmer/samba4-debian.git] / source / 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
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbind/wb_server.h"
25 #include "winbind/wb_async_helpers.h"
26 #include "winbind/wb_helper.h"
27 #include "libcli/composite/composite.h"
28 #include "version.h"
29 #include "librpc/gen_ndr/netlogon.h"
30 #include "libcli/security/security.h"
31 #include "auth/pam_errors.h"
32 #include "param/param.h"
33
34 /* 
35    Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
36 */
37
38 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
39                                              struct wbsrv_samba3_call *s3call)
40 {
41         struct winbindd_response *resp = &s3call->response;
42         if (!NT_STATUS_IS_OK(status)) {
43                 resp->result = WINBINDD_ERROR;
44                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
45                                         nt_errstr(status));
46                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
47                                         get_friendly_nt_error_msg(status));
48         } else {
49                 resp->result = WINBINDD_OK;
50         }
51
52         resp->data.auth.pam_error = nt_status_to_pam(status);
53         resp->data.auth.nt_status = NT_STATUS_V(status);
54
55         wbsrv_samba3_send_reply(s3call);
56 }
57
58 /* 
59    Send of a generic reply to a Samba3 query
60 */
61
62 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
63                                         struct wbsrv_samba3_call *s3call)
64 {
65         struct winbindd_response *resp = &s3call->response;
66         if (NT_STATUS_IS_OK(status)) {
67                 resp->result = WINBINDD_OK;
68         } else {
69                 resp->result = WINBINDD_ERROR;
70         }
71
72         wbsrv_samba3_send_reply(s3call);
73 }
74
75 /* 
76    Boilerplate commands, simple queries without network traffic 
77 */
78
79 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
80 {
81         s3call->response.result                 = WINBINDD_OK;
82         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
83         return NT_STATUS_OK;
84 }
85
86 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
87 {
88         s3call->response.result                 = WINBINDD_OK;
89         s3call->response.data.info.winbind_separator = *lp_winbind_separator();
90         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
91                                 SAMBA_VERSION_STRING);
92         return NT_STATUS_OK;
93 }
94
95 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
96 {
97         s3call->response.result                 = WINBINDD_OK;
98         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
99                                 lp_workgroup());
100         return NT_STATUS_OK;
101 }
102
103 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
104 {
105         s3call->response.result                 = WINBINDD_OK;
106         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
107                                 lp_netbios_name());
108         return NT_STATUS_OK;
109 }
110
111 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
112 {
113         s3call->response.result                 = WINBINDD_OK;
114         s3call->response.extra_data.data =
115                 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
116         NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data.data);
117         return NT_STATUS_OK;
118 }
119
120 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
121 {
122         s3call->response.result                 = WINBINDD_OK;
123         return NT_STATUS_OK;
124 }
125
126 #if 0
127 /* 
128    Validate that we have a working pipe to the domain controller.
129    Return any NT error found in the process
130 */
131
132 static void checkmachacc_recv_creds(struct composite_context *ctx);
133
134 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
135 {
136         struct composite_context *ctx;
137
138         DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
139
140         ctx = wb_cmd_checkmachacc_send(s3call->call);
141         NT_STATUS_HAVE_NO_MEMORY(ctx);
142
143         ctx->async.fn = checkmachacc_recv_creds;
144         ctx->async.private_data = s3call;
145         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
146         return NT_STATUS_OK;
147 }
148         
149 static void checkmachacc_recv_creds(struct composite_context *ctx)
150 {
151         struct wbsrv_samba3_call *s3call =
152                 talloc_get_type(ctx->async.private_data,
153                                 struct wbsrv_samba3_call);
154         NTSTATUS status;
155
156         status = wb_cmd_checkmachacc_recv(ctx);
157
158         wbsrv_samba3_async_auth_epilogue(status, s3call);
159 }
160 #endif
161
162 /*
163   Find the name of a suitable domain controller, by query on the
164   netlogon pipe to the DC.  
165 */
166
167 static void getdcname_recv_dc(struct composite_context *ctx);
168
169 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
170 {
171         struct composite_context *ctx;
172         struct wbsrv_service *service =
173                 s3call->wbconn->listen_socket->service;
174
175         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
176
177         ctx = wb_cmd_getdcname_send(s3call, service,
178                                     s3call->request.domain_name);
179         NT_STATUS_HAVE_NO_MEMORY(ctx);
180
181         ctx->async.fn = getdcname_recv_dc;
182         ctx->async.private_data = s3call;
183         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
184         return NT_STATUS_OK;
185 }
186
187 static void getdcname_recv_dc(struct composite_context *ctx)
188 {
189         struct wbsrv_samba3_call *s3call =
190                 talloc_get_type(ctx->async.private_data,
191                                 struct wbsrv_samba3_call);
192         const char *dcname;
193         NTSTATUS status;
194
195         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
196         if (!NT_STATUS_IS_OK(status)) goto done;
197
198         s3call->response.result = WINBINDD_OK;
199         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
200
201  done:
202         wbsrv_samba3_async_epilogue(status, s3call);
203 }
204
205 /* 
206    Lookup a user's domain groups
207 */
208
209 static void userdomgroups_recv_groups(struct composite_context *ctx);
210
211 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
212 {
213         struct composite_context *ctx;
214         struct dom_sid *sid;
215
216         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
217
218         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
219         if (sid == NULL) {
220                 DEBUG(5, ("Could not parse sid %s\n",
221                           s3call->request.data.sid));
222                 return NT_STATUS_NO_MEMORY;
223         }
224
225         ctx = wb_cmd_userdomgroups_send(
226                 s3call, s3call->wbconn->listen_socket->service, sid);
227         NT_STATUS_HAVE_NO_MEMORY(ctx);
228
229         ctx->async.fn = userdomgroups_recv_groups;
230         ctx->async.private_data = s3call;
231         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
232         return NT_STATUS_OK;
233 }
234
235 static void userdomgroups_recv_groups(struct composite_context *ctx)
236 {
237         struct wbsrv_samba3_call *s3call =
238                 talloc_get_type(ctx->async.private_data,
239                                 struct wbsrv_samba3_call);
240         int i, num_sids;
241         struct dom_sid **sids;
242         char *sids_string;
243         NTSTATUS status;
244
245         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
246         if (!NT_STATUS_IS_OK(status)) goto done;
247
248         sids_string = talloc_strdup(s3call, "");
249         if (sids_string == NULL) {
250                 status = NT_STATUS_NO_MEMORY;
251                 goto done;
252         }
253
254         for (i=0; i<num_sids; i++) {
255                 sids_string = talloc_asprintf_append_buffer(
256                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
257         }
258
259         if (sids_string == NULL) {
260                 status = NT_STATUS_NO_MEMORY;
261                 goto done;
262         }
263
264         s3call->response.result = WINBINDD_OK;
265         s3call->response.extra_data.data = sids_string;
266         s3call->response.length += strlen(sids_string)+1;
267         s3call->response.data.num_entries = num_sids;
268
269  done:
270         wbsrv_samba3_async_epilogue(status, s3call);
271 }
272
273 /* 
274    Lookup the list of SIDs for a user 
275 */
276 static void usersids_recv_sids(struct composite_context *ctx);
277
278 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
279 {
280         struct composite_context *ctx;
281         struct dom_sid *sid;
282
283         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
284
285         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
286         if (sid == NULL) {
287                 DEBUG(5, ("Could not parse sid %s\n",
288                           s3call->request.data.sid));
289                 return NT_STATUS_NO_MEMORY;
290         }
291
292         ctx = wb_cmd_usersids_send(
293                 s3call, s3call->wbconn->listen_socket->service, sid);
294         NT_STATUS_HAVE_NO_MEMORY(ctx);
295
296         ctx->async.fn = usersids_recv_sids;
297         ctx->async.private_data = s3call;
298         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
299         return NT_STATUS_OK;
300 }
301
302 static void usersids_recv_sids(struct composite_context *ctx)
303 {
304         struct wbsrv_samba3_call *s3call =
305                 talloc_get_type(ctx->async.private_data,
306                                 struct wbsrv_samba3_call);
307         int i, num_sids;
308         struct dom_sid **sids;
309         char *sids_string;
310         NTSTATUS status;
311
312         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
313         if (!NT_STATUS_IS_OK(status)) goto done;
314
315         sids_string = talloc_strdup(s3call, "");
316         if (sids_string == NULL) {
317                 status = NT_STATUS_NO_MEMORY;
318                 goto done;
319         }
320
321         for (i=0; i<num_sids; i++) {
322                 sids_string = talloc_asprintf_append_buffer(
323                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
324                 if (sids_string == NULL) {
325                         status = NT_STATUS_NO_MEMORY;
326                         goto done;
327                 }
328         }
329
330         s3call->response.result = WINBINDD_OK;
331         s3call->response.extra_data.data = sids_string;
332         s3call->response.length += strlen(sids_string);
333         s3call->response.data.num_entries = num_sids;
334
335         /* Hmmmm. Nasty protocol -- who invented the zeros between the
336          * SIDs? Hmmm. Could have been me -- vl */
337
338         while (*sids_string != '\0') {
339                 if ((*sids_string) == '\n') {
340                         *sids_string = '\0';
341                 }
342                 sids_string += 1;
343         }
344
345  done:
346         wbsrv_samba3_async_epilogue(status, s3call);
347 }
348
349 /* 
350    Lookup a DOMAIN\\user style name, and return a SID
351 */
352
353 static void lookupname_recv_sid(struct composite_context *ctx);
354
355 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
356 {
357         struct composite_context *ctx;
358         struct wbsrv_service *service =
359                 s3call->wbconn->listen_socket->service;
360
361         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
362
363         ctx = wb_cmd_lookupname_send(s3call, service,
364                                      s3call->request.data.name.dom_name,
365                                      s3call->request.data.name.name);
366         NT_STATUS_HAVE_NO_MEMORY(ctx);
367
368         /* setup the callbacks */
369         ctx->async.fn = lookupname_recv_sid;
370         ctx->async.private_data = s3call;
371         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
372         return NT_STATUS_OK;
373 }
374
375 static void lookupname_recv_sid(struct composite_context *ctx)
376 {
377         struct wbsrv_samba3_call *s3call =
378                 talloc_get_type(ctx->async.private_data,
379                                 struct wbsrv_samba3_call);
380         struct wb_sid_object *sid;
381         NTSTATUS status;
382
383         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
384         if (!NT_STATUS_IS_OK(status)) goto done;
385
386         s3call->response.result = WINBINDD_OK;
387         s3call->response.data.sid.type = sid->type;
388         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
389                                 dom_sid_string(s3call, sid->sid));
390
391  done:
392         wbsrv_samba3_async_epilogue(status, s3call);
393 }
394
395 /* 
396    Lookup a SID, and return a DOMAIN\\user style name
397 */
398
399 static void lookupsid_recv_name(struct composite_context *ctx);
400
401 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
402 {
403         struct composite_context *ctx;
404         struct wbsrv_service *service =
405                 s3call->wbconn->listen_socket->service;
406         struct dom_sid *sid;
407
408         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
409
410         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
411         if (sid == NULL) {
412                 DEBUG(5, ("Could not parse sid %s\n",
413                           s3call->request.data.sid));
414                 return NT_STATUS_NO_MEMORY;
415         }
416
417         ctx = wb_cmd_lookupsid_send(s3call, service, sid);
418         NT_STATUS_HAVE_NO_MEMORY(ctx);
419
420         /* setup the callbacks */
421         ctx->async.fn = lookupsid_recv_name;
422         ctx->async.private_data = s3call;
423         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
424         return NT_STATUS_OK;
425 }
426
427 static void lookupsid_recv_name(struct composite_context *ctx)
428 {
429         struct wbsrv_samba3_call *s3call =
430                 talloc_get_type(ctx->async.private_data,
431                                 struct wbsrv_samba3_call);
432         struct wb_sid_object *sid;
433         NTSTATUS status;
434
435         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
436         if (!NT_STATUS_IS_OK(status)) goto done;
437
438         s3call->response.result = WINBINDD_OK;
439         s3call->response.data.name.type = sid->type;
440         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
441                                 sid->domain);
442         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
443
444  done:
445         wbsrv_samba3_async_epilogue(status, s3call);
446 }
447
448 /*
449   Challenge-response authentication.  This interface is used by
450   ntlm_auth and the smbd auth subsystem to pass NTLM authentication
451   requests along a common pipe to the domain controller.  
452
453   The return value (in the async reply) may include the 'info3'
454   (effectivly most things you would want to know about the user), or
455   the NT and LM session keys seperated.
456 */
457
458 static void pam_auth_crap_recv(struct composite_context *ctx);
459
460 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
461 {
462         struct composite_context *ctx;
463         struct wbsrv_service *service =
464                 s3call->wbconn->listen_socket->service;
465         DATA_BLOB chal, nt_resp, lm_resp;
466
467         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
468
469         chal.data       = s3call->request.data.auth_crap.chal;
470         chal.length     = sizeof(s3call->request.data.auth_crap.chal);
471         nt_resp.data    = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
472         nt_resp.length  = s3call->request.data.auth_crap.nt_resp_len;
473         lm_resp.data    = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
474         lm_resp.length  = s3call->request.data.auth_crap.lm_resp_len;
475
476         ctx = wb_cmd_pam_auth_crap_send(
477                 s3call, service,
478                 s3call->request.data.auth_crap.logon_parameters,
479                 s3call->request.data.auth_crap.domain,
480                 s3call->request.data.auth_crap.user,
481                 s3call->request.data.auth_crap.workstation,
482                 chal, nt_resp, lm_resp);
483         NT_STATUS_HAVE_NO_MEMORY(ctx);
484
485         ctx->async.fn = pam_auth_crap_recv;
486         ctx->async.private_data = s3call;
487         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
488         return NT_STATUS_OK;
489 }
490
491 static void pam_auth_crap_recv(struct composite_context *ctx)
492 {
493         struct wbsrv_samba3_call *s3call =
494                 talloc_get_type(ctx->async.private_data,
495                                 struct wbsrv_samba3_call);
496         NTSTATUS status;
497         DATA_BLOB info3;
498         struct netr_UserSessionKey user_session_key;
499         struct netr_LMSessionKey lm_key;
500         char *unix_username;
501         
502         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
503                                            &user_session_key, &lm_key, &unix_username);
504         if (!NT_STATUS_IS_OK(status)) goto done;
505
506         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
507                 memcpy(s3call->response.data.auth.user_session_key, 
508                        &user_session_key.key,
509                        sizeof(s3call->response.data.auth.user_session_key));
510         }
511
512         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
513                 s3call->response.extra_data.data = info3.data;
514                 s3call->response.length += info3.length;
515         }
516
517         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
518                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
519                        lm_key.key,
520                        sizeof(s3call->response.data.auth.first_8_lm_hash));
521         }
522         
523         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
524                 s3call->response.extra_data.data = unix_username;
525                 s3call->response.length += strlen(unix_username)+1;
526         }
527
528  done:
529         wbsrv_samba3_async_auth_epilogue(status, s3call);
530 }
531
532 /* Plaintext authentication 
533    
534    This interface is used by ntlm_auth in it's 'basic' authentication
535    mode, as well as by pam_winbind to authenticate users where we are
536    given a plaintext password.
537 */
538
539 static void pam_auth_recv(struct composite_context *ctx);
540
541 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
542 {
543         struct composite_context *ctx;
544         struct wbsrv_service *service =
545                 s3call->wbconn->listen_socket->service;
546         char *user, *domain;
547
548         if (!wb_samba3_split_username(s3call,
549                                  s3call->request.data.auth.user,
550                                  &domain, &user)) {
551                 return NT_STATUS_NO_SUCH_USER;
552         }
553
554         ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
555                                    s3call->request.data.auth.pass);
556         NT_STATUS_HAVE_NO_MEMORY(ctx);
557
558         ctx->async.fn = pam_auth_recv;
559         ctx->async.private_data = s3call;
560         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
561         return NT_STATUS_OK;
562 }
563
564 static void pam_auth_recv(struct composite_context *ctx)
565 {
566         struct wbsrv_samba3_call *s3call =
567                 talloc_get_type(ctx->async.private_data,
568                                 struct wbsrv_samba3_call);
569         NTSTATUS status;
570
571         status = wb_cmd_pam_auth_recv(ctx);
572
573         if (!NT_STATUS_IS_OK(status)) goto done;
574
575  done:
576         wbsrv_samba3_async_auth_epilogue(status, s3call);
577 }
578
579 /* 
580    List trusted domains
581 */
582
583 static void list_trustdom_recv_doms(struct composite_context *ctx);
584
585 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
586 {
587         struct composite_context *ctx;
588         struct wbsrv_service *service =
589                 s3call->wbconn->listen_socket->service;
590
591         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
592
593         ctx = wb_cmd_list_trustdoms_send(s3call, service);
594         NT_STATUS_HAVE_NO_MEMORY(ctx);
595
596         ctx->async.fn = list_trustdom_recv_doms;
597         ctx->async.private_data = s3call;
598         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
599         return NT_STATUS_OK;
600 }
601
602 static void list_trustdom_recv_doms(struct composite_context *ctx)
603 {
604         struct wbsrv_samba3_call *s3call =
605                 talloc_get_type(ctx->async.private_data,
606                                 struct wbsrv_samba3_call);
607         int i, num_domains;
608         struct wb_dom_info **domains;
609         NTSTATUS status;
610         char *result;
611
612         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
613                                             &domains);
614         if (!NT_STATUS_IS_OK(status)) goto done;
615
616         result = talloc_strdup(s3call, "");
617         if (result == NULL) {
618                 status = NT_STATUS_NO_MEMORY;
619                 goto done;
620         }
621
622         for (i=0; i<num_domains; i++) {
623                 result = talloc_asprintf_append_buffer(
624                         result, "%s\\%s\\%s",
625                         domains[i]->name, domains[i]->name,
626                         dom_sid_string(s3call, domains[i]->sid));
627         }
628
629         if (result == NULL) {
630                 status = NT_STATUS_NO_MEMORY;
631                 goto done;
632         }
633
634         s3call->response.result = WINBINDD_OK;
635         if (num_domains > 0) {
636                 s3call->response.extra_data.data = result;
637                 s3call->response.length += strlen(result)+1;
638         }
639
640  done:
641         wbsrv_samba3_async_epilogue(status, s3call);
642 }
643
644
645 /* List users */
646
647 static void list_users_recv(struct composite_context *ctx);
648
649 NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
650 {
651         struct composite_context *ctx;
652         struct wbsrv_service *service =
653                 s3call->wbconn->listen_socket->service;
654
655         DEBUG(5, ("wbsrv_samba3_list_users called\n"));
656
657         ctx = wb_cmd_list_users_send(s3call, service,
658                         s3call->request.domain_name);
659         NT_STATUS_HAVE_NO_MEMORY(ctx);
660
661         ctx->async.fn = list_users_recv;
662         ctx->async.private_data = s3call;
663         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
664         return NT_STATUS_OK;
665 }
666
667 static void list_users_recv(struct composite_context *ctx)
668 {
669         struct wbsrv_samba3_call *s3call =
670                 talloc_get_type(ctx->async.private_data,
671                                 struct wbsrv_samba3_call);
672         uint32_t extra_data_len;
673         char *extra_data;
674         NTSTATUS status;
675
676         DEBUG(5, ("list_users_recv called\n"));
677
678         status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
679                         &extra_data);
680
681         if (NT_STATUS_IS_OK(status)) {
682                 s3call->response.extra_data.data = extra_data;
683                 s3call->response.length += extra_data_len;
684         }
685
686         wbsrv_samba3_async_epilogue(status, s3call);
687 }
688
689 /* NSS calls */
690
691 static void getpwnam_recv(struct composite_context *ctx);
692
693 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
694 {
695         struct composite_context *ctx;
696         struct wbsrv_service *service =
697                 s3call->wbconn->listen_socket->service;
698
699         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
700
701         ctx = wb_cmd_getpwnam_send(s3call, service,
702                         s3call->request.data.username);
703         NT_STATUS_HAVE_NO_MEMORY(ctx);
704
705         ctx->async.fn = getpwnam_recv;
706         ctx->async.private_data = s3call;
707         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
708         return NT_STATUS_OK;
709 }
710
711 static void getpwnam_recv(struct composite_context *ctx)
712 {
713         struct wbsrv_samba3_call *s3call =
714                 talloc_get_type(ctx->async.private_data,
715                                 struct wbsrv_samba3_call);
716         NTSTATUS status;
717         struct winbindd_pw *pw;
718
719         DEBUG(5, ("getpwnam_recv called\n"));
720
721         status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
722         if(NT_STATUS_IS_OK(status))
723                 s3call->response.data.pw = *pw;
724
725         wbsrv_samba3_async_epilogue(status, s3call);
726 }
727
728 static void getpwuid_recv(struct composite_context *ctx);
729
730 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
731 {
732         struct composite_context *ctx;
733         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
734
735         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
736
737         ctx = wb_cmd_getpwuid_send(s3call, service,
738                         s3call->request.data.uid);
739         NT_STATUS_HAVE_NO_MEMORY(ctx);
740
741         ctx->async.fn = getpwuid_recv;
742         ctx->async.private_data = s3call;
743         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
744         return NT_STATUS_OK;
745 }
746
747 static void getpwuid_recv(struct composite_context *ctx)
748 {
749         struct wbsrv_samba3_call *s3call =
750                 talloc_get_type(ctx->async.private_data,
751                                 struct wbsrv_samba3_call);
752         NTSTATUS status;
753         struct winbindd_pw *pw;
754
755         DEBUG(5, ("getpwuid_recv called\n"));
756
757         status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
758         if (NT_STATUS_IS_OK(status))
759                 s3call->response.data.pw = *pw;
760
761         wbsrv_samba3_async_epilogue(status, s3call);
762 }
763
764 static void setpwent_recv(struct composite_context *ctx);
765
766 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
767 {
768         struct composite_context *ctx;
769         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
770
771         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
772
773         ctx = wb_cmd_setpwent_send(s3call, service);
774         NT_STATUS_HAVE_NO_MEMORY(ctx);
775
776         ctx->async.fn = setpwent_recv;
777         ctx->async.private_data = s3call;
778         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
779         return NT_STATUS_OK;
780 }
781
782 static void setpwent_recv(struct composite_context *ctx)
783 {
784         struct wbsrv_samba3_call *s3call =
785                 talloc_get_type(ctx->async.private_data,
786                                 struct wbsrv_samba3_call);
787         NTSTATUS status;
788         struct wbsrv_pwent *pwent;
789
790         DEBUG(5, ("setpwent_recv called\n"));
791
792         status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
793         if (NT_STATUS_IS_OK(status)) {
794                 s3call->wbconn->protocol_private_data = pwent;
795         }
796
797         wbsrv_samba3_async_epilogue(status, s3call);
798 }
799
800 static void getpwent_recv(struct composite_context *ctx);
801
802 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
803 {
804         struct composite_context *ctx;
805         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
806         struct wbsrv_pwent *pwent;
807
808         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
809
810         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
811
812         pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
813                         struct wbsrv_pwent);
814         NT_STATUS_HAVE_NO_MEMORY(pwent);
815
816         ctx = wb_cmd_getpwent_send(s3call, service, pwent,
817                         s3call->request.data.num_entries);
818         NT_STATUS_HAVE_NO_MEMORY(ctx);
819
820         ctx->async.fn = getpwent_recv;
821         ctx->async.private_data = s3call;
822         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
823         return NT_STATUS_OK;
824 }
825
826 static void getpwent_recv(struct composite_context *ctx)
827 {
828         struct wbsrv_samba3_call *s3call =
829                 talloc_get_type(ctx->async.private_data,
830                                 struct wbsrv_samba3_call);
831         NTSTATUS status;
832         struct winbindd_pw *pw;
833         uint32_t num_users;
834
835         DEBUG(5, ("getpwent_recv called\n"));
836
837         status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
838         if (NT_STATUS_IS_OK(status)) {
839                 uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
840
841                 s3call->response.data.num_entries = num_users;
842                 s3call->response.extra_data.data = pw;
843                 s3call->response.length += extra_len;
844         }
845
846         wbsrv_samba3_async_epilogue(status, s3call);
847 }
848
849 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
850 {
851         struct wbsrv_pwent *pwent =
852                 talloc_get_type(s3call->wbconn->protocol_private_data,
853                                 struct wbsrv_pwent);
854         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
855
856         talloc_free(pwent);
857
858         s3call->wbconn->protocol_private_data = NULL;
859         s3call->response.result = WINBINDD_OK;
860         return NT_STATUS_OK;
861 }
862
863 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
864 {
865         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
866         s3call->response.result = WINBINDD_ERROR;
867         return NT_STATUS_OK;
868 }
869
870 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
871 {
872         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
873         s3call->response.result = WINBINDD_ERROR;
874         return NT_STATUS_OK;
875 }
876
877 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
878 {
879         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
880         s3call->response.result = WINBINDD_ERROR;
881         return NT_STATUS_OK;
882 }
883
884 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
885 {
886         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
887         s3call->response.result = WINBINDD_OK;
888         return NT_STATUS_OK;
889 }
890
891 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
892 {
893         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
894         s3call->response.result = WINBINDD_ERROR;
895         return NT_STATUS_OK;
896 }
897
898 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
899 {
900         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
901         s3call->response.result = WINBINDD_OK;
902         return NT_STATUS_OK;
903 }
904
905 static void sid2uid_recv(struct composite_context *ctx);
906
907 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
908 {
909         struct composite_context *ctx;
910         struct wbsrv_service *service =
911                 s3call->wbconn->listen_socket->service;
912         struct dom_sid *sid;
913
914         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
915
916         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
917         NT_STATUS_HAVE_NO_MEMORY(sid);
918
919         ctx = wb_sid2uid_send(s3call, service, sid);
920         NT_STATUS_HAVE_NO_MEMORY(ctx);
921
922         ctx->async.fn = sid2uid_recv;
923         ctx->async.private_data = s3call;
924         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
925         return NT_STATUS_OK;
926
927 }
928
929 static void sid2uid_recv(struct composite_context *ctx)
930 {
931         struct wbsrv_samba3_call *s3call =
932                 talloc_get_type(ctx->async.private_data,
933                                 struct wbsrv_samba3_call);
934         NTSTATUS status;
935
936         DEBUG(5, ("sid2uid_recv called\n"));
937
938         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
939
940         wbsrv_samba3_async_epilogue(status, s3call);
941 }
942
943 static void sid2gid_recv(struct composite_context *ctx);
944
945 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
946 {
947         struct composite_context *ctx;
948         struct wbsrv_service *service =
949                 s3call->wbconn->listen_socket->service;
950         struct dom_sid *sid;
951
952         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
953
954         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
955         NT_STATUS_HAVE_NO_MEMORY(sid);
956
957         ctx = wb_sid2gid_send(s3call, service, sid);
958         NT_STATUS_HAVE_NO_MEMORY(ctx);
959
960         ctx->async.fn = sid2gid_recv;
961         ctx->async.private_data = s3call;
962         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
963         return NT_STATUS_OK;
964
965 }
966
967 static void sid2gid_recv(struct composite_context *ctx)
968 {
969         struct wbsrv_samba3_call *s3call =
970                 talloc_get_type(ctx->async.private_data,
971                                 struct wbsrv_samba3_call);
972         NTSTATUS status;
973
974         DEBUG(5, ("sid2gid_recv called\n"));
975
976         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
977
978         wbsrv_samba3_async_epilogue(status, s3call);
979 }
980
981 static void uid2sid_recv(struct composite_context *ctx);
982
983 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
984 {
985         struct composite_context *ctx;
986         struct wbsrv_service *service =
987                 s3call->wbconn->listen_socket->service;
988
989         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
990
991         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
992         NT_STATUS_HAVE_NO_MEMORY(ctx);
993
994         ctx->async.fn = uid2sid_recv;
995         ctx->async.private_data = s3call;
996         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
997         return NT_STATUS_OK;
998
999 }
1000
1001 static void uid2sid_recv(struct composite_context *ctx)
1002 {
1003         struct wbsrv_samba3_call *s3call =
1004                 talloc_get_type(ctx->async.private_data,
1005                                 struct wbsrv_samba3_call);
1006         NTSTATUS status;
1007         struct dom_sid *sid;
1008         char *sid_str;
1009
1010         DEBUG(5, ("uid2sid_recv called\n"));
1011
1012         status = wb_uid2sid_recv(ctx, s3call, &sid);
1013         if(NT_STATUS_IS_OK(status)) {
1014                 sid_str = dom_sid_string(s3call, sid);
1015
1016                 /* If the conversion failed, bail out with a failure. */
1017                 if (sid_str == NULL)
1018                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1019
1020                 /* But we assume this worked, so we'll set the string. Work
1021                  * done. */
1022                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1023                 s3call->response.data.sid.type = SID_NAME_USER;
1024         }
1025
1026         wbsrv_samba3_async_epilogue(status, s3call);
1027 }
1028
1029 static void gid2sid_recv(struct composite_context *ctx);
1030
1031 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1032 {
1033         struct composite_context *ctx;
1034         struct wbsrv_service *service =
1035                 s3call->wbconn->listen_socket->service;
1036
1037         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1038
1039         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1040         NT_STATUS_HAVE_NO_MEMORY(ctx);
1041
1042         ctx->async.fn = gid2sid_recv;
1043         ctx->async.private_data = s3call;
1044         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1045         return NT_STATUS_OK;
1046
1047 }
1048
1049 static void gid2sid_recv(struct composite_context *ctx)
1050 {
1051         struct wbsrv_samba3_call *s3call =
1052                 talloc_get_type(ctx->async.private_data,
1053                                 struct wbsrv_samba3_call);
1054         NTSTATUS status;
1055         struct dom_sid *sid;
1056         char *sid_str;
1057
1058         DEBUG(5, ("gid2sid_recv called\n"));
1059
1060         status = wb_gid2sid_recv(ctx, s3call, &sid);
1061         if(NT_STATUS_IS_OK(status)) {
1062                 sid_str = dom_sid_string(s3call, sid);
1063
1064                 if (sid_str == NULL)
1065                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1066
1067                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1068                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1069         }
1070
1071         wbsrv_samba3_async_epilogue(status, s3call);
1072 }
1073