Fix missing symbols issues when building with shared libraries.
[kai/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 = 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 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
905 {
906         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
907         s3call->response.result = WINBINDD_ERROR;
908         return NT_STATUS_OK;
909 }
910
911 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
912 {
913         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
914         s3call->response.result = WINBINDD_ERROR;
915         return NT_STATUS_OK;
916 }
917
918 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
919 {
920         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
921         s3call->response.result = WINBINDD_ERROR;
922         return NT_STATUS_OK;
923 }
924
925 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
926 {
927         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
928         s3call->response.result = WINBINDD_OK;
929         return NT_STATUS_OK;
930 }
931
932 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
933 {
934         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
935         s3call->response.result = WINBINDD_ERROR;
936         return NT_STATUS_OK;
937 }
938
939 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
940 {
941         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
942         s3call->response.result = WINBINDD_OK;
943         return NT_STATUS_OK;
944 }
945
946 static void sid2uid_recv(struct composite_context *ctx);
947
948 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
949 {
950         struct composite_context *ctx;
951         struct wbsrv_service *service =
952                 s3call->wbconn->listen_socket->service;
953         struct dom_sid *sid;
954
955         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
956
957         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
958         NT_STATUS_HAVE_NO_MEMORY(sid);
959
960         ctx = wb_sid2uid_send(s3call, service, sid);
961         NT_STATUS_HAVE_NO_MEMORY(ctx);
962
963         ctx->async.fn = sid2uid_recv;
964         ctx->async.private_data = s3call;
965         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
966         return NT_STATUS_OK;
967
968 }
969
970 static void sid2uid_recv(struct composite_context *ctx)
971 {
972         struct wbsrv_samba3_call *s3call =
973                 talloc_get_type(ctx->async.private_data,
974                                 struct wbsrv_samba3_call);
975         NTSTATUS status;
976
977         DEBUG(5, ("sid2uid_recv called\n"));
978
979         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
980
981         wbsrv_samba3_async_epilogue(status, s3call);
982 }
983
984 static void sid2gid_recv(struct composite_context *ctx);
985
986 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
987 {
988         struct composite_context *ctx;
989         struct wbsrv_service *service =
990                 s3call->wbconn->listen_socket->service;
991         struct dom_sid *sid;
992
993         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
994
995         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
996         NT_STATUS_HAVE_NO_MEMORY(sid);
997
998         ctx = wb_sid2gid_send(s3call, service, sid);
999         NT_STATUS_HAVE_NO_MEMORY(ctx);
1000
1001         ctx->async.fn = sid2gid_recv;
1002         ctx->async.private_data = s3call;
1003         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1004         return NT_STATUS_OK;
1005
1006 }
1007
1008 static void sid2gid_recv(struct composite_context *ctx)
1009 {
1010         struct wbsrv_samba3_call *s3call =
1011                 talloc_get_type(ctx->async.private_data,
1012                                 struct wbsrv_samba3_call);
1013         NTSTATUS status;
1014
1015         DEBUG(5, ("sid2gid_recv called\n"));
1016
1017         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
1018
1019         wbsrv_samba3_async_epilogue(status, s3call);
1020 }
1021
1022 static void uid2sid_recv(struct composite_context *ctx);
1023
1024 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1025 {
1026         struct composite_context *ctx;
1027         struct wbsrv_service *service =
1028                 s3call->wbconn->listen_socket->service;
1029
1030         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1031
1032         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
1033         NT_STATUS_HAVE_NO_MEMORY(ctx);
1034
1035         ctx->async.fn = uid2sid_recv;
1036         ctx->async.private_data = s3call;
1037         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1038         return NT_STATUS_OK;
1039
1040 }
1041
1042 static void uid2sid_recv(struct composite_context *ctx)
1043 {
1044         struct wbsrv_samba3_call *s3call =
1045                 talloc_get_type(ctx->async.private_data,
1046                                 struct wbsrv_samba3_call);
1047         NTSTATUS status;
1048         struct dom_sid *sid;
1049         char *sid_str;
1050
1051         DEBUG(5, ("uid2sid_recv called\n"));
1052
1053         status = wb_uid2sid_recv(ctx, s3call, &sid);
1054         if(NT_STATUS_IS_OK(status)) {
1055                 sid_str = dom_sid_string(s3call, sid);
1056
1057                 /* If the conversion failed, bail out with a failure. */
1058                 if (sid_str == NULL)
1059                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1060
1061                 /* But we assume this worked, so we'll set the string. Work
1062                  * done. */
1063                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1064                 s3call->response.data.sid.type = SID_NAME_USER;
1065         }
1066
1067         wbsrv_samba3_async_epilogue(status, s3call);
1068 }
1069
1070 static void gid2sid_recv(struct composite_context *ctx);
1071
1072 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1073 {
1074         struct composite_context *ctx;
1075         struct wbsrv_service *service =
1076                 s3call->wbconn->listen_socket->service;
1077
1078         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1079
1080         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1081         NT_STATUS_HAVE_NO_MEMORY(ctx);
1082
1083         ctx->async.fn = gid2sid_recv;
1084         ctx->async.private_data = s3call;
1085         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1086         return NT_STATUS_OK;
1087
1088 }
1089
1090 static void gid2sid_recv(struct composite_context *ctx)
1091 {
1092         struct wbsrv_samba3_call *s3call =
1093                 talloc_get_type(ctx->async.private_data,
1094                                 struct wbsrv_samba3_call);
1095         NTSTATUS status;
1096         struct dom_sid *sid;
1097         char *sid_str;
1098
1099         DEBUG(5, ("gid2sid_recv called\n"));
1100
1101         status = wb_gid2sid_recv(ctx, s3call, &sid);
1102         if(NT_STATUS_IS_OK(status)) {
1103                 sid_str = dom_sid_string(s3call, sid);
1104
1105                 if (sid_str == NULL)
1106                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1107
1108                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1109                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1110         }
1111
1112         wbsrv_samba3_async_epilogue(status, s3call);
1113 }
1114