2 Unix SMB/CIFS implementation.
3 Main winbindd samba3 server routines
5 Copyright (C) Stefan Metzmacher 2005
6 Copyright (C) Volker Lendecke 2005
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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.
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.
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.
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"
40 Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
43 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
44 struct wbsrv_samba3_call *s3call)
46 struct winbindd_response *resp = &s3call->response;
47 if (!NT_STATUS_IS_OK(status)) {
48 resp->result = WINBINDD_ERROR;
49 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
51 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
52 get_friendly_nt_error_msg(status));
54 resp->result = WINBINDD_OK;
57 resp->data.auth.pam_error = nt_status_to_pam(status);
58 resp->data.auth.nt_status = NT_STATUS_V(status);
60 status = wbsrv_send_reply(s3call->call);
61 if (!NT_STATUS_IS_OK(status)) {
62 wbsrv_terminate_connection(s3call->call->wbconn,
63 "wbsrv_queue_reply() failed");
68 Send of a generic reply to a Samba3 query
71 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
72 struct wbsrv_samba3_call *s3call)
74 struct winbindd_response *resp = &s3call->response;
75 if (NT_STATUS_IS_OK(status)) {
76 resp->result = WINBINDD_OK;
78 resp->result = WINBINDD_ERROR;
81 status = wbsrv_send_reply(s3call->call);
82 if (!NT_STATUS_IS_OK(status)) {
83 wbsrv_terminate_connection(s3call->call->wbconn,
84 "wbsrv_queue_reply() failed");
89 Boilerplate commands, simple queries without network traffic
92 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
94 s3call->response.result = WINBINDD_OK;
95 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
99 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
101 s3call->response.result = WINBINDD_OK;
102 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
103 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
104 SAMBA_VERSION_STRING);
108 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
110 s3call->response.result = WINBINDD_OK;
111 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
116 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
118 s3call->response.result = WINBINDD_OK;
119 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
124 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
126 s3call->response.result = WINBINDD_OK;
127 s3call->response.extra_data =
128 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
129 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
133 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
135 s3call->response.result = WINBINDD_OK;
140 Validate that we have a working pipe to the domain controller.
141 Return any NT error found in the process
144 static void checkmachacc_recv_creds(struct composite_context *ctx);
146 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
148 struct composite_context *ctx;
150 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
152 ctx = wb_cmd_checkmachacc_send(s3call->call);
153 NT_STATUS_HAVE_NO_MEMORY(ctx);
155 ctx->async.fn = checkmachacc_recv_creds;
156 ctx->async.private_data = s3call;
157 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
161 static void checkmachacc_recv_creds(struct composite_context *ctx)
163 struct wbsrv_samba3_call *s3call =
164 talloc_get_type(ctx->async.private_data,
165 struct wbsrv_samba3_call);
168 status = wb_cmd_checkmachacc_recv(ctx);
170 wbsrv_samba3_async_auth_epilogue(status, s3call);
174 Find the name of a suitable domain controller, by query on the
175 netlogon pipe to the DC.
178 static void getdcname_recv_dc(struct composite_context *ctx);
180 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
182 struct composite_context *ctx;
183 struct wbsrv_service *service =
184 s3call->call->wbconn->listen_socket->service;
186 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
188 ctx = wb_cmd_getdcname_send(service, service->domains,
189 s3call->request.domain_name);
190 NT_STATUS_HAVE_NO_MEMORY(ctx);
192 ctx->async.fn = getdcname_recv_dc;
193 ctx->async.private_data = s3call;
194 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
198 static void getdcname_recv_dc(struct composite_context *ctx)
200 struct wbsrv_samba3_call *s3call =
201 talloc_get_type(ctx->async.private_data,
202 struct wbsrv_samba3_call);
206 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
207 if (!NT_STATUS_IS_OK(status)) goto done;
209 s3call->response.result = WINBINDD_OK;
210 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
213 wbsrv_samba3_async_epilogue(status, s3call);
217 Lookup a user's domain groups
220 static void userdomgroups_recv_groups(struct composite_context *ctx);
222 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
224 struct composite_context *ctx;
227 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
229 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
231 DEBUG(5, ("Could not parse sid %s\n",
232 s3call->request.data.sid));
233 return NT_STATUS_NO_MEMORY;
236 ctx = wb_cmd_userdomgroups_send(
237 s3call->call->wbconn->listen_socket->service, sid);
238 NT_STATUS_HAVE_NO_MEMORY(ctx);
240 ctx->async.fn = userdomgroups_recv_groups;
241 ctx->async.private_data = s3call;
242 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
246 static void userdomgroups_recv_groups(struct composite_context *ctx)
248 struct wbsrv_samba3_call *s3call =
249 talloc_get_type(ctx->async.private_data,
250 struct wbsrv_samba3_call);
252 struct dom_sid **sids;
256 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
257 if (!NT_STATUS_IS_OK(status)) goto done;
259 sids_string = talloc_strdup(s3call, "");
260 if (sids_string == NULL) {
261 status = NT_STATUS_NO_MEMORY;
265 for (i=0; i<num_sids; i++) {
266 sids_string = talloc_asprintf_append(
267 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
270 if (sids_string == NULL) {
271 status = NT_STATUS_NO_MEMORY;
275 s3call->response.result = WINBINDD_OK;
276 s3call->response.extra_data = sids_string;
277 s3call->response.length += strlen(sids_string)+1;
278 s3call->response.data.num_entries = num_sids;
281 wbsrv_samba3_async_epilogue(status, s3call);
285 Lookup the list of SIDs for a user
287 static void usersids_recv_sids(struct composite_context *ctx);
289 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
291 struct composite_context *ctx;
294 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
296 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
298 DEBUG(5, ("Could not parse sid %s\n",
299 s3call->request.data.sid));
300 return NT_STATUS_NO_MEMORY;
303 ctx = wb_cmd_usersids_send(
304 s3call->call->wbconn->listen_socket->service, sid);
305 NT_STATUS_HAVE_NO_MEMORY(ctx);
307 ctx->async.fn = usersids_recv_sids;
308 ctx->async.private_data = s3call;
309 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
313 static void usersids_recv_sids(struct composite_context *ctx)
315 struct wbsrv_samba3_call *s3call =
316 talloc_get_type(ctx->async.private_data,
317 struct wbsrv_samba3_call);
319 struct dom_sid **sids;
323 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
324 if (!NT_STATUS_IS_OK(status)) goto done;
326 sids_string = talloc_strdup(s3call, "");
327 if (sids_string == NULL) {
328 status = NT_STATUS_NO_MEMORY;
332 for (i=0; i<num_sids; i++) {
333 sids_string = talloc_asprintf_append(
334 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
335 if (sids_string == NULL) {
336 status = NT_STATUS_NO_MEMORY;
341 s3call->response.result = WINBINDD_OK;
342 s3call->response.extra_data = sids_string;
343 s3call->response.length += strlen(sids_string);
344 s3call->response.data.num_entries = num_sids;
346 /* Hmmmm. Nasty protocol -- who invented the zeros between the
347 * SIDs? Hmmm. Could have been me -- vl */
349 while (*sids_string != '\0') {
350 if ((*sids_string) == '\n') {
357 wbsrv_samba3_async_epilogue(status, s3call);
361 Lookup a DOMAIN\\user style name, and return a SID
364 static void lookupname_recv_sid(struct composite_context *ctx);
366 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
368 struct composite_context *ctx;
369 struct wbsrv_service *service =
370 s3call->call->wbconn->listen_socket->service;
372 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
374 ctx = wb_cmd_lookupname_send(service, service->domains,
375 s3call->request.data.name.dom_name,
376 s3call->request.data.name.name);
377 NT_STATUS_HAVE_NO_MEMORY(ctx);
379 /* setup the callbacks */
380 ctx->async.fn = lookupname_recv_sid;
381 ctx->async.private_data = s3call;
382 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
386 static void lookupname_recv_sid(struct composite_context *ctx)
388 struct wbsrv_samba3_call *s3call =
389 talloc_get_type(ctx->async.private_data,
390 struct wbsrv_samba3_call);
391 struct wb_sid_object *sid;
394 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
395 if (!NT_STATUS_IS_OK(status)) goto done;
397 s3call->response.result = WINBINDD_OK;
398 s3call->response.data.sid.type = sid->type;
399 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
400 dom_sid_string(s3call, sid->sid));
403 wbsrv_samba3_async_epilogue(status, s3call);
407 Lookup a SID, and return a DOMAIN\\user style name
410 static void lookupsid_recv_name(struct composite_context *ctx);
412 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
414 struct composite_context *ctx;
415 struct wbsrv_service *service =
416 s3call->call->wbconn->listen_socket->service;
419 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
421 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
423 DEBUG(5, ("Could not parse sid %s\n",
424 s3call->request.data.sid));
425 return NT_STATUS_NO_MEMORY;
428 ctx = wb_cmd_lookupsid_send(service, service->domains, sid);
429 NT_STATUS_HAVE_NO_MEMORY(ctx);
431 /* setup the callbacks */
432 ctx->async.fn = lookupsid_recv_name;
433 ctx->async.private_data = s3call;
434 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
438 static void lookupsid_recv_name(struct composite_context *ctx)
440 struct wbsrv_samba3_call *s3call =
441 talloc_get_type(ctx->async.private_data,
442 struct wbsrv_samba3_call);
443 struct wb_sid_object *sid;
446 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
447 if (!NT_STATUS_IS_OK(status)) goto done;
449 s3call->response.result = WINBINDD_OK;
450 s3call->response.data.name.type = sid->type;
451 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
453 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
456 wbsrv_samba3_async_epilogue(status, s3call);
460 Challenge-response authentication. This interface is used by
461 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
462 requests along a common pipe to the domain controller.
464 The return value (in the async reply) may include the 'info3'
465 (effectivly most things you would want to know about the user), or
466 the NT and LM session keys seperated.
469 static void pam_auth_crap_recv(struct composite_context *ctx);
471 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
473 struct composite_context *ctx;
474 DATA_BLOB chal, nt_resp, lm_resp;
476 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
478 chal.data = s3call->request.data.auth_crap.chal;
479 chal.length = sizeof(s3call->request.data.auth_crap.chal);
480 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
481 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
482 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
483 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
485 ctx = wb_cmd_pam_auth_crap_send(
487 s3call->request.data.auth_crap.logon_parameters,
488 s3call->request.data.auth_crap.domain,
489 s3call->request.data.auth_crap.user,
490 s3call->request.data.auth_crap.workstation,
491 chal, nt_resp, lm_resp);
492 NT_STATUS_HAVE_NO_MEMORY(ctx);
494 ctx->async.fn = pam_auth_crap_recv;
495 ctx->async.private_data = s3call;
496 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
500 static void pam_auth_crap_recv(struct composite_context *ctx)
502 struct wbsrv_samba3_call *s3call =
503 talloc_get_type(ctx->async.private_data,
504 struct wbsrv_samba3_call);
507 struct netr_UserSessionKey user_session_key;
508 struct netr_LMSessionKey lm_key;
511 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
512 &user_session_key, &lm_key, &unix_username);
513 if (!NT_STATUS_IS_OK(status)) goto done;
515 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
516 memcpy(s3call->response.data.auth.user_session_key,
517 &user_session_key.key,
518 sizeof(s3call->response.data.auth.user_session_key));
521 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
522 s3call->response.extra_data = info3.data;
523 s3call->response.length += info3.length;
526 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
527 memcpy(s3call->response.data.auth.first_8_lm_hash,
529 sizeof(s3call->response.data.auth.first_8_lm_hash));
532 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
533 s3call->response.extra_data = unix_username;
534 s3call->response.length += strlen(unix_username)+1;
538 wbsrv_samba3_async_auth_epilogue(status, s3call);
541 /* Helper function: Split a domain\\user string into it's parts,
542 * because the client supplies it as one string */
544 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
545 char **domain, char **user)
547 char *p = strchr(domuser, *lp_winbind_separator());
550 *domain = talloc_strdup(mem_ctx, lp_workgroup());
552 *domain = talloc_strndup(mem_ctx, domuser,
553 PTR_DIFF(p, domuser));
557 *user = talloc_strdup(mem_ctx, domuser);
559 return ((*domain != NULL) && (*user != NULL));
562 /* Plaintext authentication
564 This interface is used by ntlm_auth in it's 'basic' authentication
565 mode, as well as by pam_winbind to authenticate users where we are
566 given a plaintext password.
569 static void pam_auth_recv(struct composite_context *ctx);
571 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
573 struct composite_context *ctx;
575 if (!samba3_parse_domuser(s3call,
576 s3call->request.data.auth.user,
578 return NT_STATUS_NO_SUCH_USER;
581 ctx = wb_cmd_pam_auth_send(
582 s3call->call, domain, user,
583 s3call->request.data.auth.pass);
584 NT_STATUS_HAVE_NO_MEMORY(ctx);
586 ctx->async.fn = pam_auth_recv;
587 ctx->async.private_data = s3call;
588 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
592 static void pam_auth_recv(struct composite_context *ctx)
594 struct wbsrv_samba3_call *s3call =
595 talloc_get_type(ctx->async.private_data,
596 struct wbsrv_samba3_call);
599 status = wb_cmd_pam_auth_recv(ctx);
601 if (!NT_STATUS_IS_OK(status)) goto done;
604 wbsrv_samba3_async_auth_epilogue(status, s3call);
611 static void list_trustdom_recv_doms(struct composite_context *ctx);
613 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
615 struct composite_context *ctx;
616 struct wbsrv_service *service =
617 s3call->call->wbconn->listen_socket->service;
619 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
621 ctx = wb_cmd_list_trustdoms_send(service);
622 NT_STATUS_HAVE_NO_MEMORY(ctx);
624 ctx->async.fn = list_trustdom_recv_doms;
625 ctx->async.private_data = s3call;
626 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
630 static void list_trustdom_recv_doms(struct composite_context *ctx)
632 struct wbsrv_samba3_call *s3call =
633 talloc_get_type(ctx->async.private_data,
634 struct wbsrv_samba3_call);
636 struct wb_dom_info **domains;
640 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
642 if (!NT_STATUS_IS_OK(status)) goto done;
644 result = talloc_strdup(s3call, "");
645 if (result == NULL) {
646 status = NT_STATUS_NO_MEMORY;
650 for (i=0; i<num_domains; i++) {
651 result = talloc_asprintf_append(
652 result, "%s\\%s\\%s",
653 domains[i]->name, domains[i]->name,
654 dom_sid_string(s3call, domains[i]->sid));
657 if (result == NULL) {
658 status = NT_STATUS_NO_MEMORY;
662 s3call->response.result = WINBINDD_OK;
663 if (num_domains > 0) {
664 s3call->response.extra_data = result;
665 s3call->response.length += strlen(result)+1;
669 wbsrv_samba3_async_epilogue(status, s3call);