Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
[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/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         }
724
725         wbsrv_samba3_async_epilogue(status, s3call);
726 }
727
728 /* NSS calls */
729
730 static void getpwnam_recv(struct composite_context *ctx);
731
732 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
733 {
734         struct composite_context *ctx;
735         struct wbsrv_service *service =
736                 s3call->wbconn->listen_socket->service;
737
738         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
739
740         ctx = wb_cmd_getpwnam_send(s3call, service,
741                         s3call->request.data.username);
742         NT_STATUS_HAVE_NO_MEMORY(ctx);
743
744         ctx->async.fn = getpwnam_recv;
745         ctx->async.private_data = s3call;
746         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
747         return NT_STATUS_OK;
748 }
749
750 static void getpwnam_recv(struct composite_context *ctx)
751 {
752         struct wbsrv_samba3_call *s3call =
753                 talloc_get_type(ctx->async.private_data,
754                                 struct wbsrv_samba3_call);
755         NTSTATUS status;
756         struct winbindd_pw *pw;
757
758         DEBUG(5, ("getpwnam_recv called\n"));
759
760         status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
761         if(NT_STATUS_IS_OK(status))
762                 s3call->response.data.pw = *pw;
763
764         wbsrv_samba3_async_epilogue(status, s3call);
765 }
766
767 static void getpwuid_recv(struct composite_context *ctx);
768
769 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
770 {
771         struct composite_context *ctx;
772         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
773
774         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
775
776         ctx = wb_cmd_getpwuid_send(s3call, service,
777                         s3call->request.data.uid);
778         NT_STATUS_HAVE_NO_MEMORY(ctx);
779
780         ctx->async.fn = getpwuid_recv;
781         ctx->async.private_data = s3call;
782         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
783         return NT_STATUS_OK;
784 }
785
786 static void getpwuid_recv(struct composite_context *ctx)
787 {
788         struct wbsrv_samba3_call *s3call =
789                 talloc_get_type(ctx->async.private_data,
790                                 struct wbsrv_samba3_call);
791         NTSTATUS status;
792         struct winbindd_pw *pw;
793
794         DEBUG(5, ("getpwuid_recv called\n"));
795
796         status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
797         if (NT_STATUS_IS_OK(status))
798                 s3call->response.data.pw = *pw;
799
800         wbsrv_samba3_async_epilogue(status, s3call);
801 }
802
803 static void setpwent_recv(struct composite_context *ctx);
804
805 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
806 {
807         struct composite_context *ctx;
808         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
809
810         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
811
812         ctx = wb_cmd_setpwent_send(s3call, service);
813         NT_STATUS_HAVE_NO_MEMORY(ctx);
814
815         ctx->async.fn = setpwent_recv;
816         ctx->async.private_data = s3call;
817         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
818         return NT_STATUS_OK;
819 }
820
821 static void setpwent_recv(struct composite_context *ctx)
822 {
823         struct wbsrv_samba3_call *s3call =
824                 talloc_get_type(ctx->async.private_data,
825                                 struct wbsrv_samba3_call);
826         NTSTATUS status;
827         struct wbsrv_pwent *pwent;
828
829         DEBUG(5, ("setpwent_recv called\n"));
830
831         status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
832         if (NT_STATUS_IS_OK(status)) {
833                 s3call->wbconn->protocol_private_data = pwent;
834         }
835
836         wbsrv_samba3_async_epilogue(status, s3call);
837 }
838
839 static void getpwent_recv(struct composite_context *ctx);
840
841 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
842 {
843         struct composite_context *ctx;
844         struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
845         struct wbsrv_pwent *pwent;
846
847         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
848
849         NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
850
851         pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
852                         struct wbsrv_pwent);
853         NT_STATUS_HAVE_NO_MEMORY(pwent);
854
855         ctx = wb_cmd_getpwent_send(s3call, service, pwent,
856                         s3call->request.data.num_entries);
857         NT_STATUS_HAVE_NO_MEMORY(ctx);
858
859         ctx->async.fn = getpwent_recv;
860         ctx->async.private_data = s3call;
861         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
862         return NT_STATUS_OK;
863 }
864
865 static void getpwent_recv(struct composite_context *ctx)
866 {
867         struct wbsrv_samba3_call *s3call =
868                 talloc_get_type(ctx->async.private_data,
869                                 struct wbsrv_samba3_call);
870         NTSTATUS status;
871         struct winbindd_pw *pw;
872         uint32_t num_users;
873
874         DEBUG(5, ("getpwent_recv called\n"));
875
876         status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
877         if (NT_STATUS_IS_OK(status)) {
878                 uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
879
880                 s3call->response.data.num_entries = num_users;
881                 s3call->response.extra_data.data = pw;
882                 s3call->response.length += extra_len;
883         }
884
885         wbsrv_samba3_async_epilogue(status, s3call);
886 }
887
888 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
889 {
890         struct wbsrv_pwent *pwent =
891                 talloc_get_type(s3call->wbconn->protocol_private_data,
892                                 struct wbsrv_pwent);
893         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
894
895         talloc_free(pwent);
896
897         s3call->wbconn->protocol_private_data = NULL;
898         s3call->response.result = WINBINDD_OK;
899         return NT_STATUS_OK;
900 }
901
902 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
903 {
904         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
905         s3call->response.result = WINBINDD_ERROR;
906         return NT_STATUS_OK;
907 }
908
909 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
910 {
911         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
912         s3call->response.result = WINBINDD_ERROR;
913         return NT_STATUS_OK;
914 }
915
916 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
917 {
918         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
919         s3call->response.result = WINBINDD_ERROR;
920         return NT_STATUS_OK;
921 }
922
923 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
924 {
925         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
926         s3call->response.result = WINBINDD_OK;
927         return NT_STATUS_OK;
928 }
929
930 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
931 {
932         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
933         s3call->response.result = WINBINDD_ERROR;
934         return NT_STATUS_OK;
935 }
936
937 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
938 {
939         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
940         s3call->response.result = WINBINDD_OK;
941         return NT_STATUS_OK;
942 }
943
944 static void sid2uid_recv(struct composite_context *ctx);
945
946 NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
947 {
948         struct composite_context *ctx;
949         struct wbsrv_service *service =
950                 s3call->wbconn->listen_socket->service;
951         struct dom_sid *sid;
952
953         DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
954
955         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
956         NT_STATUS_HAVE_NO_MEMORY(sid);
957
958         ctx = wb_sid2uid_send(s3call, service, sid);
959         NT_STATUS_HAVE_NO_MEMORY(ctx);
960
961         ctx->async.fn = sid2uid_recv;
962         ctx->async.private_data = s3call;
963         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
964         return NT_STATUS_OK;
965
966 }
967
968 static void sid2uid_recv(struct composite_context *ctx)
969 {
970         struct wbsrv_samba3_call *s3call =
971                 talloc_get_type(ctx->async.private_data,
972                                 struct wbsrv_samba3_call);
973         NTSTATUS status;
974
975         DEBUG(5, ("sid2uid_recv called\n"));
976
977         status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
978
979         wbsrv_samba3_async_epilogue(status, s3call);
980 }
981
982 static void sid2gid_recv(struct composite_context *ctx);
983
984 NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
985 {
986         struct composite_context *ctx;
987         struct wbsrv_service *service =
988                 s3call->wbconn->listen_socket->service;
989         struct dom_sid *sid;
990
991         DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
992
993         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
994         NT_STATUS_HAVE_NO_MEMORY(sid);
995
996         ctx = wb_sid2gid_send(s3call, service, sid);
997         NT_STATUS_HAVE_NO_MEMORY(ctx);
998
999         ctx->async.fn = sid2gid_recv;
1000         ctx->async.private_data = s3call;
1001         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1002         return NT_STATUS_OK;
1003
1004 }
1005
1006 static void sid2gid_recv(struct composite_context *ctx)
1007 {
1008         struct wbsrv_samba3_call *s3call =
1009                 talloc_get_type(ctx->async.private_data,
1010                                 struct wbsrv_samba3_call);
1011         NTSTATUS status;
1012
1013         DEBUG(5, ("sid2gid_recv called\n"));
1014
1015         status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
1016
1017         wbsrv_samba3_async_epilogue(status, s3call);
1018 }
1019
1020 static void uid2sid_recv(struct composite_context *ctx);
1021
1022 NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
1023 {
1024         struct composite_context *ctx;
1025         struct wbsrv_service *service =
1026                 s3call->wbconn->listen_socket->service;
1027
1028         DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
1029
1030         ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
1031         NT_STATUS_HAVE_NO_MEMORY(ctx);
1032
1033         ctx->async.fn = uid2sid_recv;
1034         ctx->async.private_data = s3call;
1035         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1036         return NT_STATUS_OK;
1037
1038 }
1039
1040 static void uid2sid_recv(struct composite_context *ctx)
1041 {
1042         struct wbsrv_samba3_call *s3call =
1043                 talloc_get_type(ctx->async.private_data,
1044                                 struct wbsrv_samba3_call);
1045         NTSTATUS status;
1046         struct dom_sid *sid;
1047         char *sid_str;
1048
1049         DEBUG(5, ("uid2sid_recv called\n"));
1050
1051         status = wb_uid2sid_recv(ctx, s3call, &sid);
1052         if(NT_STATUS_IS_OK(status)) {
1053                 sid_str = dom_sid_string(s3call, sid);
1054
1055                 /* If the conversion failed, bail out with a failure. */
1056                 if (sid_str == NULL)
1057                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1058
1059                 /* But we assume this worked, so we'll set the string. Work
1060                  * done. */
1061                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1062                 s3call->response.data.sid.type = SID_NAME_USER;
1063         }
1064
1065         wbsrv_samba3_async_epilogue(status, s3call);
1066 }
1067
1068 static void gid2sid_recv(struct composite_context *ctx);
1069
1070 NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
1071 {
1072         struct composite_context *ctx;
1073         struct wbsrv_service *service =
1074                 s3call->wbconn->listen_socket->service;
1075
1076         DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
1077
1078         ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
1079         NT_STATUS_HAVE_NO_MEMORY(ctx);
1080
1081         ctx->async.fn = gid2sid_recv;
1082         ctx->async.private_data = s3call;
1083         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
1084         return NT_STATUS_OK;
1085
1086 }
1087
1088 static void gid2sid_recv(struct composite_context *ctx)
1089 {
1090         struct wbsrv_samba3_call *s3call =
1091                 talloc_get_type(ctx->async.private_data,
1092                                 struct wbsrv_samba3_call);
1093         NTSTATUS status;
1094         struct dom_sid *sid;
1095         char *sid_str;
1096
1097         DEBUG(5, ("gid2sid_recv called\n"));
1098
1099         status = wb_gid2sid_recv(ctx, s3call, &sid);
1100         if(NT_STATUS_IS_OK(status)) {
1101                 sid_str = dom_sid_string(s3call, sid);
1102
1103                 if (sid_str == NULL)
1104                         wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
1105
1106                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
1107                 s3call->response.data.sid.type = SID_NAME_DOMAIN;
1108         }
1109
1110         wbsrv_samba3_async_epilogue(status, s3call);
1111 }
1112