r23792: convert Samba4 to GPLv3
[ira/wip.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 "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
34 /* 
35    Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
36 */
37
38 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
39                                              struct wbsrv_samba3_call *s3call)
40 {
41         struct winbindd_response *resp = &s3call->response;
42         if (!NT_STATUS_IS_OK(status)) {
43                 resp->result = WINBINDD_ERROR;
44                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
45                                         nt_errstr(status));
46                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
47                                         get_friendly_nt_error_msg(status));
48         } else {
49                 resp->result = WINBINDD_OK;
50         }
51
52         resp->data.auth.pam_error = nt_status_to_pam(status);
53         resp->data.auth.nt_status = NT_STATUS_V(status);
54
55         wbsrv_samba3_send_reply(s3call);
56 }
57
58 /* 
59    Send of a generic reply to a Samba3 query
60 */
61
62 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
63                                         struct wbsrv_samba3_call *s3call)
64 {
65         struct winbindd_response *resp = &s3call->response;
66         if (NT_STATUS_IS_OK(status)) {
67                 resp->result = WINBINDD_OK;
68         } else {
69                 resp->result = WINBINDD_ERROR;
70         }
71
72         wbsrv_samba3_send_reply(s3call);
73 }
74
75 /* 
76    Boilerplate commands, simple queries without network traffic 
77 */
78
79 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
80 {
81         s3call->response.result                 = WINBINDD_OK;
82         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
83         return NT_STATUS_OK;
84 }
85
86 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
87 {
88         s3call->response.result                 = WINBINDD_OK;
89         s3call->response.data.info.winbind_separator = *lp_winbind_separator();
90         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
91                                 SAMBA_VERSION_STRING);
92         return NT_STATUS_OK;
93 }
94
95 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
96 {
97         s3call->response.result                 = WINBINDD_OK;
98         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
99                                 lp_workgroup());
100         return NT_STATUS_OK;
101 }
102
103 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
104 {
105         s3call->response.result                 = WINBINDD_OK;
106         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
107                                 lp_netbios_name());
108         return NT_STATUS_OK;
109 }
110
111 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
112 {
113         s3call->response.result                 = WINBINDD_OK;
114         s3call->response.extra_data.data =
115                 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
116         NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data.data);
117         return NT_STATUS_OK;
118 }
119
120 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
121 {
122         s3call->response.result                 = WINBINDD_OK;
123         return NT_STATUS_OK;
124 }
125
126 #if 0
127 /* 
128    Validate that we have a working pipe to the domain controller.
129    Return any NT error found in the process
130 */
131
132 static void checkmachacc_recv_creds(struct composite_context *ctx);
133
134 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
135 {
136         struct composite_context *ctx;
137
138         DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
139
140         ctx = wb_cmd_checkmachacc_send(s3call->call);
141         NT_STATUS_HAVE_NO_MEMORY(ctx);
142
143         ctx->async.fn = checkmachacc_recv_creds;
144         ctx->async.private_data = s3call;
145         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
146         return NT_STATUS_OK;
147 }
148         
149 static void checkmachacc_recv_creds(struct composite_context *ctx)
150 {
151         struct wbsrv_samba3_call *s3call =
152                 talloc_get_type(ctx->async.private_data,
153                                 struct wbsrv_samba3_call);
154         NTSTATUS status;
155
156         status = wb_cmd_checkmachacc_recv(ctx);
157
158         wbsrv_samba3_async_auth_epilogue(status, s3call);
159 }
160 #endif
161
162 /*
163   Find the name of a suitable domain controller, by query on the
164   netlogon pipe to the DC.  
165 */
166
167 static void getdcname_recv_dc(struct composite_context *ctx);
168
169 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
170 {
171         struct composite_context *ctx;
172         struct wbsrv_service *service =
173                 s3call->wbconn->listen_socket->service;
174
175         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
176
177         ctx = wb_cmd_getdcname_send(s3call, service,
178                                     s3call->request.domain_name);
179         NT_STATUS_HAVE_NO_MEMORY(ctx);
180
181         ctx->async.fn = getdcname_recv_dc;
182         ctx->async.private_data = s3call;
183         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
184         return NT_STATUS_OK;
185 }
186
187 static void getdcname_recv_dc(struct composite_context *ctx)
188 {
189         struct wbsrv_samba3_call *s3call =
190                 talloc_get_type(ctx->async.private_data,
191                                 struct wbsrv_samba3_call);
192         const char *dcname;
193         NTSTATUS status;
194
195         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
196         if (!NT_STATUS_IS_OK(status)) goto done;
197
198         s3call->response.result = WINBINDD_OK;
199         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
200
201  done:
202         wbsrv_samba3_async_epilogue(status, s3call);
203 }
204
205 /* 
206    Lookup a user's domain groups
207 */
208
209 static void userdomgroups_recv_groups(struct composite_context *ctx);
210
211 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
212 {
213         struct composite_context *ctx;
214         struct dom_sid *sid;
215
216         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
217
218         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
219         if (sid == NULL) {
220                 DEBUG(5, ("Could not parse sid %s\n",
221                           s3call->request.data.sid));
222                 return NT_STATUS_NO_MEMORY;
223         }
224
225         ctx = wb_cmd_userdomgroups_send(
226                 s3call, s3call->wbconn->listen_socket->service, sid);
227         NT_STATUS_HAVE_NO_MEMORY(ctx);
228
229         ctx->async.fn = userdomgroups_recv_groups;
230         ctx->async.private_data = s3call;
231         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
232         return NT_STATUS_OK;
233 }
234
235 static void userdomgroups_recv_groups(struct composite_context *ctx)
236 {
237         struct wbsrv_samba3_call *s3call =
238                 talloc_get_type(ctx->async.private_data,
239                                 struct wbsrv_samba3_call);
240         int i, num_sids;
241         struct dom_sid **sids;
242         char *sids_string;
243         NTSTATUS status;
244
245         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
246         if (!NT_STATUS_IS_OK(status)) goto done;
247
248         sids_string = talloc_strdup(s3call, "");
249         if (sids_string == NULL) {
250                 status = NT_STATUS_NO_MEMORY;
251                 goto done;
252         }
253
254         for (i=0; i<num_sids; i++) {
255                 sids_string = talloc_asprintf_append(
256                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
257         }
258
259         if (sids_string == NULL) {
260                 status = NT_STATUS_NO_MEMORY;
261                 goto done;
262         }
263
264         s3call->response.result = WINBINDD_OK;
265         s3call->response.extra_data.data = sids_string;
266         s3call->response.length += strlen(sids_string)+1;
267         s3call->response.data.num_entries = num_sids;
268
269  done:
270         wbsrv_samba3_async_epilogue(status, s3call);
271 }
272
273 /* 
274    Lookup the list of SIDs for a user 
275 */
276 static void usersids_recv_sids(struct composite_context *ctx);
277
278 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
279 {
280         struct composite_context *ctx;
281         struct dom_sid *sid;
282
283         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
284
285         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
286         if (sid == NULL) {
287                 DEBUG(5, ("Could not parse sid %s\n",
288                           s3call->request.data.sid));
289                 return NT_STATUS_NO_MEMORY;
290         }
291
292         ctx = wb_cmd_usersids_send(
293                 s3call, s3call->wbconn->listen_socket->service, sid);
294         NT_STATUS_HAVE_NO_MEMORY(ctx);
295
296         ctx->async.fn = usersids_recv_sids;
297         ctx->async.private_data = s3call;
298         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
299         return NT_STATUS_OK;
300 }
301
302 static void usersids_recv_sids(struct composite_context *ctx)
303 {
304         struct wbsrv_samba3_call *s3call =
305                 talloc_get_type(ctx->async.private_data,
306                                 struct wbsrv_samba3_call);
307         int i, num_sids;
308         struct dom_sid **sids;
309         char *sids_string;
310         NTSTATUS status;
311
312         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
313         if (!NT_STATUS_IS_OK(status)) goto done;
314
315         sids_string = talloc_strdup(s3call, "");
316         if (sids_string == NULL) {
317                 status = NT_STATUS_NO_MEMORY;
318                 goto done;
319         }
320
321         for (i=0; i<num_sids; i++) {
322                 sids_string = talloc_asprintf_append(
323                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
324                 if (sids_string == NULL) {
325                         status = NT_STATUS_NO_MEMORY;
326                         goto done;
327                 }
328         }
329
330         s3call->response.result = WINBINDD_OK;
331         s3call->response.extra_data.data = sids_string;
332         s3call->response.length += strlen(sids_string);
333         s3call->response.data.num_entries = num_sids;
334
335         /* Hmmmm. Nasty protocol -- who invented the zeros between the
336          * SIDs? Hmmm. Could have been me -- vl */
337
338         while (*sids_string != '\0') {
339                 if ((*sids_string) == '\n') {
340                         *sids_string = '\0';
341                 }
342                 sids_string += 1;
343         }
344
345  done:
346         wbsrv_samba3_async_epilogue(status, s3call);
347 }
348
349 /* 
350    Lookup a DOMAIN\\user style name, and return a SID
351 */
352
353 static void lookupname_recv_sid(struct composite_context *ctx);
354
355 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
356 {
357         struct composite_context *ctx;
358         struct wbsrv_service *service =
359                 s3call->wbconn->listen_socket->service;
360
361         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
362
363         ctx = wb_cmd_lookupname_send(s3call, service,
364                                      s3call->request.data.name.dom_name,
365                                      s3call->request.data.name.name);
366         NT_STATUS_HAVE_NO_MEMORY(ctx);
367
368         /* setup the callbacks */
369         ctx->async.fn = lookupname_recv_sid;
370         ctx->async.private_data = s3call;
371         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
372         return NT_STATUS_OK;
373 }
374
375 static void lookupname_recv_sid(struct composite_context *ctx)
376 {
377         struct wbsrv_samba3_call *s3call =
378                 talloc_get_type(ctx->async.private_data,
379                                 struct wbsrv_samba3_call);
380         struct wb_sid_object *sid;
381         NTSTATUS status;
382
383         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
384         if (!NT_STATUS_IS_OK(status)) goto done;
385
386         s3call->response.result = WINBINDD_OK;
387         s3call->response.data.sid.type = sid->type;
388         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
389                                 dom_sid_string(s3call, sid->sid));
390
391  done:
392         wbsrv_samba3_async_epilogue(status, s3call);
393 }
394
395 /* 
396    Lookup a SID, and return a DOMAIN\\user style name
397 */
398
399 static void lookupsid_recv_name(struct composite_context *ctx);
400
401 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
402 {
403         struct composite_context *ctx;
404         struct wbsrv_service *service =
405                 s3call->wbconn->listen_socket->service;
406         struct dom_sid *sid;
407
408         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
409
410         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
411         if (sid == NULL) {
412                 DEBUG(5, ("Could not parse sid %s\n",
413                           s3call->request.data.sid));
414                 return NT_STATUS_NO_MEMORY;
415         }
416
417         ctx = wb_cmd_lookupsid_send(s3call, service, sid);
418         NT_STATUS_HAVE_NO_MEMORY(ctx);
419
420         /* setup the callbacks */
421         ctx->async.fn = lookupsid_recv_name;
422         ctx->async.private_data = s3call;
423         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
424         return NT_STATUS_OK;
425 }
426
427 static void lookupsid_recv_name(struct composite_context *ctx)
428 {
429         struct wbsrv_samba3_call *s3call =
430                 talloc_get_type(ctx->async.private_data,
431                                 struct wbsrv_samba3_call);
432         struct wb_sid_object *sid;
433         NTSTATUS status;
434
435         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
436         if (!NT_STATUS_IS_OK(status)) goto done;
437
438         s3call->response.result = WINBINDD_OK;
439         s3call->response.data.name.type = sid->type;
440         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
441                                 sid->domain);
442         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
443
444  done:
445         wbsrv_samba3_async_epilogue(status, s3call);
446 }
447
448 /*
449   Challenge-response authentication.  This interface is used by
450   ntlm_auth and the smbd auth subsystem to pass NTLM authentication
451   requests along a common pipe to the domain controller.  
452
453   The return value (in the async reply) may include the 'info3'
454   (effectivly most things you would want to know about the user), or
455   the NT and LM session keys seperated.
456 */
457
458 static void pam_auth_crap_recv(struct composite_context *ctx);
459
460 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
461 {
462         struct composite_context *ctx;
463         struct wbsrv_service *service =
464                 s3call->wbconn->listen_socket->service;
465         DATA_BLOB chal, nt_resp, lm_resp;
466
467         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
468
469         chal.data       = s3call->request.data.auth_crap.chal;
470         chal.length     = sizeof(s3call->request.data.auth_crap.chal);
471         nt_resp.data    = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
472         nt_resp.length  = s3call->request.data.auth_crap.nt_resp_len;
473         lm_resp.data    = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
474         lm_resp.length  = s3call->request.data.auth_crap.lm_resp_len;
475
476         ctx = wb_cmd_pam_auth_crap_send(
477                 s3call, service,
478                 s3call->request.data.auth_crap.logon_parameters,
479                 s3call->request.data.auth_crap.domain,
480                 s3call->request.data.auth_crap.user,
481                 s3call->request.data.auth_crap.workstation,
482                 chal, nt_resp, lm_resp);
483         NT_STATUS_HAVE_NO_MEMORY(ctx);
484
485         ctx->async.fn = pam_auth_crap_recv;
486         ctx->async.private_data = s3call;
487         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
488         return NT_STATUS_OK;
489 }
490
491 static void pam_auth_crap_recv(struct composite_context *ctx)
492 {
493         struct wbsrv_samba3_call *s3call =
494                 talloc_get_type(ctx->async.private_data,
495                                 struct wbsrv_samba3_call);
496         NTSTATUS status;
497         DATA_BLOB info3;
498         struct netr_UserSessionKey user_session_key;
499         struct netr_LMSessionKey lm_key;
500         char *unix_username;
501         
502         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
503                                            &user_session_key, &lm_key, &unix_username);
504         if (!NT_STATUS_IS_OK(status)) goto done;
505
506         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
507                 memcpy(s3call->response.data.auth.user_session_key, 
508                        &user_session_key.key,
509                        sizeof(s3call->response.data.auth.user_session_key));
510         }
511
512         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
513                 s3call->response.extra_data.data = info3.data;
514                 s3call->response.length += info3.length;
515         }
516
517         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
518                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
519                        lm_key.key,
520                        sizeof(s3call->response.data.auth.first_8_lm_hash));
521         }
522         
523         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
524                 s3call->response.extra_data.data = unix_username;
525                 s3call->response.length += strlen(unix_username)+1;
526         }
527
528  done:
529         wbsrv_samba3_async_auth_epilogue(status, s3call);
530 }
531
532 /* Helper function: Split a domain\\user string into it's parts,
533  * because the client supplies it as one string */
534
535 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
536                                  char **domain, char **user)
537 {
538         char *p = strchr(domuser, *lp_winbind_separator());
539
540         if (p == NULL) {
541                 *domain = talloc_strdup(mem_ctx, lp_workgroup());
542         } else {
543                 *domain = talloc_strndup(mem_ctx, domuser,
544                                          PTR_DIFF(p, domuser));
545                 domuser = p+1;
546         }
547
548         *user = talloc_strdup(mem_ctx, domuser);
549
550         return ((*domain != NULL) && (*user != NULL));
551 }
552
553 /* Plaintext authentication 
554    
555    This interface is used by ntlm_auth in it's 'basic' authentication
556    mode, as well as by pam_winbind to authenticate users where we are
557    given a plaintext password.
558 */
559
560 static void pam_auth_recv(struct composite_context *ctx);
561
562 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
563 {
564         struct composite_context *ctx;
565         struct wbsrv_service *service =
566                 s3call->wbconn->listen_socket->service;
567         char *user, *domain;
568
569         if (!samba3_parse_domuser(s3call, 
570                                  s3call->request.data.auth.user,
571                                  &domain, &user)) {
572                 return NT_STATUS_NO_SUCH_USER;
573         }
574
575         ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
576                                    s3call->request.data.auth.pass);
577         NT_STATUS_HAVE_NO_MEMORY(ctx);
578
579         ctx->async.fn = pam_auth_recv;
580         ctx->async.private_data = s3call;
581         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
582         return NT_STATUS_OK;
583 }
584
585 static void pam_auth_recv(struct composite_context *ctx)
586 {
587         struct wbsrv_samba3_call *s3call =
588                 talloc_get_type(ctx->async.private_data,
589                                 struct wbsrv_samba3_call);
590         NTSTATUS status;
591
592         status = wb_cmd_pam_auth_recv(ctx);
593
594         if (!NT_STATUS_IS_OK(status)) goto done;
595
596  done:
597         wbsrv_samba3_async_auth_epilogue(status, s3call);
598 }
599
600 /* 
601    List trusted domains
602 */
603
604 static void list_trustdom_recv_doms(struct composite_context *ctx);
605
606 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
607 {
608         struct composite_context *ctx;
609         struct wbsrv_service *service =
610                 s3call->wbconn->listen_socket->service;
611
612         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
613
614         ctx = wb_cmd_list_trustdoms_send(s3call, service);
615         NT_STATUS_HAVE_NO_MEMORY(ctx);
616
617         ctx->async.fn = list_trustdom_recv_doms;
618         ctx->async.private_data = s3call;
619         s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
620         return NT_STATUS_OK;
621 }
622
623 static void list_trustdom_recv_doms(struct composite_context *ctx)
624 {
625         struct wbsrv_samba3_call *s3call =
626                 talloc_get_type(ctx->async.private_data,
627                                 struct wbsrv_samba3_call);
628         int i, num_domains;
629         struct wb_dom_info **domains;
630         NTSTATUS status;
631         char *result;
632
633         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
634                                             &domains);
635         if (!NT_STATUS_IS_OK(status)) goto done;
636
637         result = talloc_strdup(s3call, "");
638         if (result == NULL) {
639                 status = NT_STATUS_NO_MEMORY;
640                 goto done;
641         }
642
643         for (i=0; i<num_domains; i++) {
644                 result = talloc_asprintf_append(
645                         result, "%s\\%s\\%s",
646                         domains[i]->name, domains[i]->name,
647                         dom_sid_string(s3call, domains[i]->sid));
648         }
649
650         if (result == NULL) {
651                 status = NT_STATUS_NO_MEMORY;
652                 goto done;
653         }
654
655         s3call->response.result = WINBINDD_OK;
656         if (num_domains > 0) {
657                 s3call->response.extra_data.data = result;
658                 s3call->response.length += strlen(result)+1;
659         }
660
661  done:
662         wbsrv_samba3_async_epilogue(status, s3call);
663 }
664
665 /* NSS calls */
666
667 NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
668 {
669         DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
670         s3call->response.result = WINBINDD_ERROR;
671         return NT_STATUS_OK;
672 }
673
674 NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
675 {
676         DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
677         s3call->response.result = WINBINDD_ERROR;
678         return NT_STATUS_OK;
679 }
680
681 NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
682 {
683         DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
684         s3call->response.result = WINBINDD_OK;
685         return NT_STATUS_OK;
686 }
687
688 NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
689 {
690         DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
691         s3call->response.result = WINBINDD_ERROR;
692         return NT_STATUS_OK;
693 }
694
695 NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
696 {
697         DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
698         s3call->response.result = WINBINDD_OK;
699         return NT_STATUS_OK;
700 }
701
702 NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
703 {
704         DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
705         s3call->response.result = WINBINDD_ERROR;
706         return NT_STATUS_OK;
707 }
708
709 NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
710 {
711         DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
712         s3call->response.result = WINBINDD_ERROR;
713         return NT_STATUS_OK;
714 }
715
716 NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
717 {
718         DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
719         s3call->response.result = WINBINDD_ERROR;
720         return NT_STATUS_OK;
721 }
722
723 NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
724 {
725         DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
726         s3call->response.result = WINBINDD_OK;
727         return NT_STATUS_OK;
728 }
729
730 NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
731 {
732         DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
733         s3call->response.result = WINBINDD_ERROR;
734         return NT_STATUS_OK;
735 }
736
737 NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
738 {
739         DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
740         s3call->response.result = WINBINDD_OK;
741         return NT_STATUS_OK;
742 }