r11411: Add to Samba4 the Samba3 patch I just posted for machine account
[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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "smbd/service_stream.h"
26 #include "nsswitch/winbind_nss_config.h"
27 #include "nsswitch/winbindd_nss.h"
28 #include "winbind/wb_server.h"
29 #include "winbind/wb_samba3_protocol.h"
30 #include "winbind/wb_async_helpers.h"
31 #include "librpc/gen_ndr/nbt.h"
32 #include "libcli/raw/libcliraw.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "include/version.h"
36 #include "lib/events/events.h"
37 #include "librpc/gen_ndr/ndr_netlogon.h"
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         status = wbsrv_send_reply(s3call->call);
57         if (!NT_STATUS_IS_OK(status)) {
58                 wbsrv_terminate_connection(s3call->call->wbconn,
59                                            "wbsrv_queue_reply() failed");
60         }
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         status = wbsrv_send_reply(s3call->call);
74         if (!NT_STATUS_IS_OK(status)) {
75                 wbsrv_terminate_connection(s3call->call->wbconn,
76                                            "wbsrv_queue_reply() failed");
77         }
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 =
116                 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
117         NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_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 static void checkmachacc_recv_creds(struct composite_context *ctx);
128
129 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
130 {
131         struct composite_context *ctx;
132
133         DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
134
135         ctx = wb_cmd_checkmachacc_send(s3call->call);
136         NT_STATUS_HAVE_NO_MEMORY(ctx);
137
138         ctx->async.fn = checkmachacc_recv_creds;
139         ctx->async.private_data = s3call;
140         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
141         return NT_STATUS_OK;
142 }
143         
144 static void checkmachacc_recv_creds(struct composite_context *ctx)
145 {
146         struct wbsrv_samba3_call *s3call =
147                 talloc_get_type(ctx->async.private_data,
148                                 struct wbsrv_samba3_call);
149         NTSTATUS status;
150
151         status = wb_cmd_checkmachacc_recv(ctx);
152
153         wbsrv_samba3_async_auth_epilogue(status, s3call);
154 }
155
156 static void getdcname_recv_dc(struct composite_context *ctx);
157
158 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
159 {
160         struct composite_context *ctx;
161         struct wbsrv_service *service =
162                 s3call->call->wbconn->listen_socket->service;
163
164         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
165
166         ctx = wb_cmd_getdcname_send(service, service->domains,
167                                     s3call->request.domain_name);
168         NT_STATUS_HAVE_NO_MEMORY(ctx);
169
170         ctx->async.fn = getdcname_recv_dc;
171         ctx->async.private_data = s3call;
172         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
173         return NT_STATUS_OK;
174 }
175
176 static void getdcname_recv_dc(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         const char *dcname;
182         NTSTATUS status;
183
184         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
185         if (!NT_STATUS_IS_OK(status)) goto done;
186
187         s3call->response.result = WINBINDD_OK;
188         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
189
190  done:
191         wbsrv_samba3_async_epilogue(status, s3call);
192 }
193
194 static void userdomgroups_recv_groups(struct composite_context *ctx);
195
196 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
197 {
198         struct composite_context *ctx;
199         struct dom_sid *sid;
200
201         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
202
203         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
204         if (sid == NULL) {
205                 DEBUG(5, ("Could not parse sid %s\n",
206                           s3call->request.data.sid));
207                 return NT_STATUS_NO_MEMORY;
208         }
209
210         ctx = wb_cmd_userdomgroups_send(
211                 s3call->call->wbconn->listen_socket->service, sid);
212         NT_STATUS_HAVE_NO_MEMORY(ctx);
213
214         ctx->async.fn = userdomgroups_recv_groups;
215         ctx->async.private_data = s3call;
216         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
217         return NT_STATUS_OK;
218 }
219
220 static void userdomgroups_recv_groups(struct composite_context *ctx)
221 {
222         struct wbsrv_samba3_call *s3call =
223                 talloc_get_type(ctx->async.private_data,
224                                 struct wbsrv_samba3_call);
225         int i, num_sids;
226         struct dom_sid **sids;
227         char *sids_string;
228         NTSTATUS status;
229
230         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
231         if (!NT_STATUS_IS_OK(status)) goto done;
232
233         sids_string = talloc_strdup(s3call, "");
234         if (sids_string == NULL) {
235                 status = NT_STATUS_NO_MEMORY;
236                 goto done;
237         }
238
239         for (i=0; i<num_sids; i++) {
240                 sids_string = talloc_asprintf_append(
241                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
242         }
243
244         if (sids_string == NULL) {
245                 status = NT_STATUS_NO_MEMORY;
246                 goto done;
247         }
248
249         s3call->response.result = WINBINDD_OK;
250         s3call->response.extra_data = sids_string;
251         s3call->response.length += strlen(sids_string)+1;
252         s3call->response.data.num_entries = num_sids;
253
254  done:
255         wbsrv_samba3_async_epilogue(status, s3call);
256 }
257
258 static void usersids_recv_sids(struct composite_context *ctx);
259
260 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
261 {
262         struct composite_context *ctx;
263         struct dom_sid *sid;
264
265         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
266
267         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
268         if (sid == NULL) {
269                 DEBUG(5, ("Could not parse sid %s\n",
270                           s3call->request.data.sid));
271                 return NT_STATUS_NO_MEMORY;
272         }
273
274         ctx = wb_cmd_usersids_send(
275                 s3call->call->wbconn->listen_socket->service, sid);
276         NT_STATUS_HAVE_NO_MEMORY(ctx);
277
278         ctx->async.fn = usersids_recv_sids;
279         ctx->async.private_data = s3call;
280         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
281         return NT_STATUS_OK;
282 }
283
284 static void usersids_recv_sids(struct composite_context *ctx)
285 {
286         struct wbsrv_samba3_call *s3call =
287                 talloc_get_type(ctx->async.private_data,
288                                 struct wbsrv_samba3_call);
289         int i, num_sids;
290         struct dom_sid **sids;
291         char *sids_string;
292         NTSTATUS status;
293
294         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
295         if (!NT_STATUS_IS_OK(status)) goto done;
296
297         sids_string = talloc_strdup(s3call, "");
298         if (sids_string == NULL) {
299                 status = NT_STATUS_NO_MEMORY;
300                 goto done;
301         }
302
303         for (i=0; i<num_sids; i++) {
304                 sids_string = talloc_asprintf_append(
305                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
306                 if (sids_string == NULL) {
307                         status = NT_STATUS_NO_MEMORY;
308                         goto done;
309                 }
310         }
311
312         s3call->response.result = WINBINDD_OK;
313         s3call->response.extra_data = sids_string;
314         s3call->response.length += strlen(sids_string);
315         s3call->response.data.num_entries = num_sids;
316
317         /* Hmmmm. Nasty protocol -- who invented the zeros between the
318          * SIDs? Hmmm. Could have been me -- vl */
319
320         while (*sids_string != '\0') {
321                 if ((*sids_string) == '\n') {
322                         *sids_string = '\0';
323                 }
324                 sids_string += 1;
325         }
326
327  done:
328         wbsrv_samba3_async_epilogue(status, s3call);
329 }
330
331 static void lookupname_recv_sid(struct composite_context *ctx);
332
333 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
334 {
335         struct composite_context *ctx;
336         struct wbsrv_service *service =
337                 s3call->call->wbconn->listen_socket->service;
338
339         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
340
341         ctx = wb_cmd_lookupname_send(service, service->domains,
342                                      s3call->request.data.name.dom_name,
343                                      s3call->request.data.name.name);
344         NT_STATUS_HAVE_NO_MEMORY(ctx);
345
346         /* setup the callbacks */
347         ctx->async.fn = lookupname_recv_sid;
348         ctx->async.private_data = s3call;
349         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
350         return NT_STATUS_OK;
351 }
352
353 static void lookupname_recv_sid(struct composite_context *ctx)
354 {
355         struct wbsrv_samba3_call *s3call =
356                 talloc_get_type(ctx->async.private_data,
357                                 struct wbsrv_samba3_call);
358         struct wb_sid_object *sid;
359         NTSTATUS status;
360
361         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
362         if (!NT_STATUS_IS_OK(status)) goto done;
363
364         s3call->response.result = WINBINDD_OK;
365         s3call->response.data.sid.type = sid->type;
366         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
367                                 dom_sid_string(s3call, sid->sid));
368
369  done:
370         wbsrv_samba3_async_epilogue(status, s3call);
371 }
372
373 static void lookupsid_recv_name(struct composite_context *ctx);
374
375 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
376 {
377         struct composite_context *ctx;
378         struct wbsrv_service *service =
379                 s3call->call->wbconn->listen_socket->service;
380         struct dom_sid *sid;
381
382         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
383
384         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
385         if (sid == NULL) {
386                 DEBUG(5, ("Could not parse sid %s\n",
387                           s3call->request.data.sid));
388                 return NT_STATUS_NO_MEMORY;
389         }
390
391         ctx = wb_cmd_lookupsid_send(service, service->domains, sid);
392         NT_STATUS_HAVE_NO_MEMORY(ctx);
393
394         /* setup the callbacks */
395         ctx->async.fn = lookupsid_recv_name;
396         ctx->async.private_data = s3call;
397         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
398         return NT_STATUS_OK;
399 }
400
401 static void lookupsid_recv_name(struct composite_context *ctx)
402 {
403         struct wbsrv_samba3_call *s3call =
404                 talloc_get_type(ctx->async.private_data,
405                                 struct wbsrv_samba3_call);
406         struct wb_sid_object *sid;
407         NTSTATUS status;
408
409         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
410         if (!NT_STATUS_IS_OK(status)) goto done;
411
412         s3call->response.result = WINBINDD_OK;
413         s3call->response.data.name.type = sid->type;
414         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
415                                 sid->domain);
416         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
417
418  done:
419         wbsrv_samba3_async_epilogue(status, s3call);
420 }
421
422 static void pam_auth_crap_recv(struct composite_context *ctx);
423
424 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
425 {
426         struct composite_context *ctx;
427         DATA_BLOB chal, nt_resp, lm_resp;
428
429         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
430
431         chal.data       = s3call->request.data.auth_crap.chal;
432         chal.length     = sizeof(s3call->request.data.auth_crap.chal);
433         nt_resp.data    = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
434         nt_resp.length  = s3call->request.data.auth_crap.nt_resp_len;
435         lm_resp.data    = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
436         lm_resp.length  = s3call->request.data.auth_crap.lm_resp_len;
437
438         ctx = wb_cmd_pam_auth_crap_send(
439                 s3call->call, 
440                 s3call->request.data.auth_crap.logon_parameters,
441                 s3call->request.data.auth_crap.domain,
442                 s3call->request.data.auth_crap.user,
443                 s3call->request.data.auth_crap.workstation,
444                 chal, nt_resp, lm_resp);
445         NT_STATUS_HAVE_NO_MEMORY(ctx);
446
447         ctx->async.fn = pam_auth_crap_recv;
448         ctx->async.private_data = s3call;
449         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
450         return NT_STATUS_OK;
451 }
452
453 static void pam_auth_crap_recv(struct composite_context *ctx)
454 {
455         struct wbsrv_samba3_call *s3call =
456                 talloc_get_type(ctx->async.private_data,
457                                 struct wbsrv_samba3_call);
458         NTSTATUS status;
459         DATA_BLOB info3;
460         struct netr_UserSessionKey user_session_key;
461         struct netr_LMSessionKey lm_key;
462         char *unix_username;
463         
464         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
465                                            &user_session_key, &lm_key, &unix_username);
466         if (!NT_STATUS_IS_OK(status)) goto done;
467
468         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
469                 memcpy(s3call->response.data.auth.user_session_key, 
470                        &user_session_key.key,
471                        sizeof(s3call->response.data.auth.user_session_key));
472         }
473
474         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
475                 s3call->response.extra_data = info3.data;
476                 s3call->response.length += info3.length;
477         }
478
479         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
480                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
481                        lm_key.key,
482                        sizeof(s3call->response.data.auth.first_8_lm_hash));
483         }
484         
485         if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
486                 s3call->response.extra_data = unix_username;
487                 s3call->response.length += strlen(unix_username)+1;
488         }
489
490  done:
491         wbsrv_samba3_async_auth_epilogue(status, s3call);
492 }
493
494 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
495                                  char **domain, char **user)
496 {
497         char *p = strchr(domuser, *lp_winbind_separator());
498
499         if (p == NULL) {
500                 *domain = talloc_strdup(mem_ctx, lp_workgroup());
501         } else {
502                 *domain = talloc_strndup(mem_ctx, domuser,
503                                          PTR_DIFF(p, domuser));
504                 domuser = p+1;
505         }
506
507         *user = talloc_strdup(mem_ctx, domuser);
508
509         return ((*domain != NULL) && (*user != NULL));
510 }
511
512 static void pam_auth_recv(struct composite_context *ctx);
513
514 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
515 {
516         struct composite_context *ctx;
517         char *user, *domain;
518         if (!samba3_parse_domuser(s3call, 
519                                  s3call->request.data.auth.user,
520                                  &domain, &user)) {
521                 return NT_STATUS_NO_SUCH_USER;
522         }
523
524         ctx = wb_cmd_pam_auth_send(
525                 s3call->call, domain, user,
526                 s3call->request.data.auth.pass);
527         NT_STATUS_HAVE_NO_MEMORY(ctx);
528
529         ctx->async.fn = pam_auth_recv;
530         ctx->async.private_data = s3call;
531         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
532         return NT_STATUS_OK;
533 }
534
535 static void pam_auth_recv(struct composite_context *ctx)
536 {
537         struct wbsrv_samba3_call *s3call =
538                 talloc_get_type(ctx->async.private_data,
539                                 struct wbsrv_samba3_call);
540         NTSTATUS status;
541
542         status = wb_cmd_pam_auth_recv(ctx);
543
544         if (!NT_STATUS_IS_OK(status)) goto done;
545
546  done:
547         wbsrv_samba3_async_auth_epilogue(status, s3call);
548 }
549
550 static void list_trustdom_recv_doms(struct composite_context *ctx);
551
552 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
553 {
554         struct composite_context *ctx;
555         struct wbsrv_service *service =
556                 s3call->call->wbconn->listen_socket->service;
557
558         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
559
560         ctx = wb_cmd_list_trustdoms_send(service);
561         NT_STATUS_HAVE_NO_MEMORY(ctx);
562
563         ctx->async.fn = list_trustdom_recv_doms;
564         ctx->async.private_data = s3call;
565         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
566         return NT_STATUS_OK;
567 }
568
569 static void list_trustdom_recv_doms(struct composite_context *ctx)
570 {
571         struct wbsrv_samba3_call *s3call =
572                 talloc_get_type(ctx->async.private_data,
573                                 struct wbsrv_samba3_call);
574         int i, num_domains;
575         struct wb_dom_info **domains;
576         NTSTATUS status;
577         char *result;
578
579         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
580                                             &domains);
581         if (!NT_STATUS_IS_OK(status)) goto done;
582
583         result = talloc_strdup(s3call, "");
584         if (result == NULL) {
585                 status = NT_STATUS_NO_MEMORY;
586                 goto done;
587         }
588
589         for (i=0; i<num_domains; i++) {
590                 result = talloc_asprintf_append(
591                         result, "%s\\%s\\%s",
592                         domains[i]->name, domains[i]->name,
593                         dom_sid_string(s3call, domains[i]->sid));
594         }
595
596         if (result == NULL) {
597                 status = NT_STATUS_NO_MEMORY;
598                 goto done;
599         }
600
601         s3call->response.result = WINBINDD_OK;
602         if (num_domains > 0) {
603                 s3call->response.extra_data = result;
604                 s3call->response.length += strlen(result)+1;
605         }
606
607  done:
608         wbsrv_samba3_async_epilogue(status, s3call);
609 }