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