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