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