s4 winbind: Add implementation for WINBINDD_GETGRNAM
[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         const char *path = s3call->wbconn->listen_socket->service->priv_socket_path;
117         s3call->response.result          = WINBINDD_OK;
118         WBSRV_SAMBA3_SET_STRING(s3call->response.extra_data.data, 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 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
943 {
944         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
945         s3call->response.result = WINBINDD_ERROR;
946         return NT_STATUS_OK;
947 }
948
949 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
950 {
951         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
952         s3call->response.result = WINBINDD_ERROR;
953         return NT_STATUS_OK;
954 }
955
956 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
957 {
958         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
959         s3call->response.result = WINBINDD_OK;
960         return NT_STATUS_OK;
961 }
962
963 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
964 {
965         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
966         s3call->response.result = WINBINDD_ERROR;
967         return NT_STATUS_OK;
968 }
969
970 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
971 {
972         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
973         s3call->response.result = WINBINDD_OK;
974         return NT_STATUS_OK;
975 }
976
977 static void sid2uid_recv(struct composite_context *ctx);
978
979 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
980 {
981         struct composite_context *ctx;
982         struct wbsrv_service *service =
983                 s3call->wbconn->listen_socket->service;
984         struct dom_sid *sid;
985
986         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
987
988         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
989         NT_STATUS_HAVE_NO_MEMORY(sid);
990
991         ctx = wb_sid2uid_send(s3call, service, sid);
992         NT_STATUS_HAVE_NO_MEMORY(ctx);
993
994         ctx->async.fn = sid2uid_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 sid2uid_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
1008         DEBUG(5, ("sid2uid_recv called\n"));
1009
1010         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
1011
1012         wbsrv_samba3_async_epilogue(status, s3call);
1013 }
1014
1015 static void sid2gid_recv(struct composite_context *ctx);
1016
1017 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
1018 {
1019         struct composite_context *ctx;
1020         struct wbsrv_service *service =
1021                 s3call->wbconn->listen_socket->service;
1022         struct dom_sid *sid;
1023
1024         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
1025
1026         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
1027         NT_STATUS_HAVE_NO_MEMORY(sid);
1028
1029         ctx = wb_sid2gid_send(s3call, service, sid);
1030         NT_STATUS_HAVE_NO_MEMORY(ctx);
1031
1032         ctx->async.fn = sid2gid_recv;
1033         ctx->async.private_data = s3call;
1034         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1035         return NT_STATUS_OK;
1036
1037 }
1038
1039 static void sid2gid_recv(struct composite_context *ctx)
1040 {
1041         struct wbsrv_samba3_call *s3call =
1042                 talloc_get_type(ctx->async.private_data,
1043                                 struct wbsrv_samba3_call);
1044         NTSTATUS status;
1045
1046         DEBUG(5, ("sid2gid_recv called\n"));
1047
1048         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
1049
1050         wbsrv_samba3_async_epilogue(status, s3call);
1051 }
1052
1053 static void uid2sid_recv(struct composite_context *ctx);
1054
1055 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1056 {
1057         struct composite_context *ctx;
1058         struct wbsrv_service *service =
1059                 s3call->wbconn->listen_socket->service;
1060
1061         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1062
1063         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
1064         NT_STATUS_HAVE_NO_MEMORY(ctx);
1065
1066         ctx->async.fn = uid2sid_recv;
1067         ctx->async.private_data = s3call;
1068         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1069         return NT_STATUS_OK;
1070
1071 }
1072
1073 static void uid2sid_recv(struct composite_context *ctx)
1074 {
1075         struct wbsrv_samba3_call *s3call =
1076                 talloc_get_type(ctx->async.private_data,
1077                                 struct wbsrv_samba3_call);
1078         NTSTATUS status;
1079         struct dom_sid *sid;
1080         char *sid_str;
1081
1082         DEBUG(5, ("uid2sid_recv called\n"));
1083
1084         status = wb_uid2sid_recv(ctx, s3call, &sid);
1085         if(NT_STATUS_IS_OK(status)) {
1086                 sid_str = dom_sid_string(s3call, sid);
1087
1088                 /* If the conversion failed, bail out with a failure. */
1089                 if (sid_str == NULL)
1090                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1091
1092                 /* But we assume this worked, so we'll set the string. Work
1093                  * done. */
1094                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1095                 s3call->response.data.sid.type = SID_NAME_USER;
1096         }
1097
1098         wbsrv_samba3_async_epilogue(status, s3call);
1099 }
1100
1101 static void gid2sid_recv(struct composite_context *ctx);
1102
1103 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1104 {
1105         struct composite_context *ctx;
1106         struct wbsrv_service *service =
1107                 s3call->wbconn->listen_socket->service;
1108
1109         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1110
1111         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1112         NT_STATUS_HAVE_NO_MEMORY(ctx);
1113
1114         ctx->async.fn = gid2sid_recv;
1115         ctx->async.private_data = s3call;
1116         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1117         return NT_STATUS_OK;
1118
1119 }
1120
1121 static void gid2sid_recv(struct composite_context *ctx)
1122 {
1123         struct wbsrv_samba3_call *s3call =
1124                 talloc_get_type(ctx->async.private_data,
1125                                 struct wbsrv_samba3_call);
1126         NTSTATUS status;
1127         struct dom_sid *sid;
1128         char *sid_str;
1129
1130         DEBUG(5, ("gid2sid_recv called\n"));
1131
1132         status = wb_gid2sid_recv(ctx, s3call, &sid);
1133         if(NT_STATUS_IS_OK(status)) {
1134                 sid_str = dom_sid_string(s3call, sid);
1135
1136                 if (sid_str == NULL)
1137                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1138
1139                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1140                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1141         }
1142
1143         wbsrv_samba3_async_epilogue(status, s3call);
1144 }
1145