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 "nsswitch/winbindd_nss.h"
26 #include "winbind/wb_server.h"
27 #include "winbind/wb_samba3_protocol.h"
28 #include "winbind/wb_async_helpers.h"
29 #include "libcli/composite/composite.h"
30 #include "include/version.h"
31 #include "librpc/gen_ndr/ndr_netlogon.h"
34 Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
37 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
38 struct wbsrv_samba3_call *s3call)
40 struct winbindd_response *resp = &s3call->response;
41 if (!NT_STATUS_IS_OK(status)) {
42 resp->result = WINBINDD_ERROR;
43 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
45 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
46 get_friendly_nt_error_msg(status));
48 resp->result = WINBINDD_OK;
51 resp->data.auth.pam_error = nt_status_to_pam(status);
52 resp->data.auth.nt_status = NT_STATUS_V(status);
54 status = wbsrv_send_reply(s3call->call);
55 if (!NT_STATUS_IS_OK(status)) {
56 wbsrv_terminate_connection(s3call->call->wbconn,
57 "wbsrv_queue_reply() failed");
62 Send of a generic reply to a Samba3 query
65 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
66 struct wbsrv_samba3_call *s3call)
68 struct winbindd_response *resp = &s3call->response;
69 if (NT_STATUS_IS_OK(status)) {
70 resp->result = WINBINDD_OK;
72 resp->result = WINBINDD_ERROR;
75 status = wbsrv_send_reply(s3call->call);
76 if (!NT_STATUS_IS_OK(status)) {
77 wbsrv_terminate_connection(s3call->call->wbconn,
78 "wbsrv_queue_reply() failed");
83 Boilerplate commands, simple queries without network traffic
86 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
88 s3call->response.result = WINBINDD_OK;
89 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
93 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
95 s3call->response.result = WINBINDD_OK;
96 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
97 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
98 SAMBA_VERSION_STRING);
102 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
104 s3call->response.result = WINBINDD_OK;
105 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
110 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
112 s3call->response.result = WINBINDD_OK;
113 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
118 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
120 s3call->response.result = WINBINDD_OK;
121 s3call->response.extra_data =
122 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
123 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
127 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
129 s3call->response.result = WINBINDD_OK;
135 Validate that we have a working pipe to the domain controller.
136 Return any NT error found in the process
139 static void checkmachacc_recv_creds(struct composite_context *ctx);
141 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
143 struct composite_context *ctx;
145 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
147 ctx = wb_cmd_checkmachacc_send(s3call->call);
148 NT_STATUS_HAVE_NO_MEMORY(ctx);
150 ctx->async.fn = checkmachacc_recv_creds;
151 ctx->async.private_data = s3call;
152 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
156 static void checkmachacc_recv_creds(struct composite_context *ctx)
158 struct wbsrv_samba3_call *s3call =
159 talloc_get_type(ctx->async.private_data,
160 struct wbsrv_samba3_call);
163 status = wb_cmd_checkmachacc_recv(ctx);
165 wbsrv_samba3_async_auth_epilogue(status, s3call);
170 Find the name of a suitable domain controller, by query on the
171 netlogon pipe to the DC.
174 static void getdcname_recv_dc(struct composite_context *ctx);
176 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
178 struct composite_context *ctx;
179 struct wbsrv_service *service =
180 s3call->call->wbconn->listen_socket->service;
182 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
184 ctx = wb_cmd_getdcname_send(s3call, service,
185 s3call->request.domain_name);
186 NT_STATUS_HAVE_NO_MEMORY(ctx);
188 ctx->async.fn = getdcname_recv_dc;
189 ctx->async.private_data = s3call;
190 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
194 static void getdcname_recv_dc(struct composite_context *ctx)
196 struct wbsrv_samba3_call *s3call =
197 talloc_get_type(ctx->async.private_data,
198 struct wbsrv_samba3_call);
202 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
203 if (!NT_STATUS_IS_OK(status)) goto done;
205 s3call->response.result = WINBINDD_OK;
206 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
209 wbsrv_samba3_async_epilogue(status, s3call);
213 Lookup a user's domain groups
216 static void userdomgroups_recv_groups(struct composite_context *ctx);
218 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
220 struct composite_context *ctx;
223 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
225 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
227 DEBUG(5, ("Could not parse sid %s\n",
228 s3call->request.data.sid));
229 return NT_STATUS_NO_MEMORY;
232 ctx = wb_cmd_userdomgroups_send(
233 s3call, s3call->call->wbconn->listen_socket->service, sid);
234 NT_STATUS_HAVE_NO_MEMORY(ctx);
236 ctx->async.fn = userdomgroups_recv_groups;
237 ctx->async.private_data = s3call;
238 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
242 static void userdomgroups_recv_groups(struct composite_context *ctx)
244 struct wbsrv_samba3_call *s3call =
245 talloc_get_type(ctx->async.private_data,
246 struct wbsrv_samba3_call);
248 struct dom_sid **sids;
252 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
253 if (!NT_STATUS_IS_OK(status)) goto done;
255 sids_string = talloc_strdup(s3call, "");
256 if (sids_string == NULL) {
257 status = NT_STATUS_NO_MEMORY;
261 for (i=0; i<num_sids; i++) {
262 sids_string = talloc_asprintf_append(
263 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
266 if (sids_string == NULL) {
267 status = NT_STATUS_NO_MEMORY;
271 s3call->response.result = WINBINDD_OK;
272 s3call->response.extra_data = sids_string;
273 s3call->response.length += strlen(sids_string)+1;
274 s3call->response.data.num_entries = num_sids;
277 wbsrv_samba3_async_epilogue(status, s3call);
281 Lookup the list of SIDs for a user
283 static void usersids_recv_sids(struct composite_context *ctx);
285 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
287 struct composite_context *ctx;
290 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
292 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
294 DEBUG(5, ("Could not parse sid %s\n",
295 s3call->request.data.sid));
296 return NT_STATUS_NO_MEMORY;
299 ctx = wb_cmd_usersids_send(
300 s3call, s3call->call->wbconn->listen_socket->service, sid);
301 NT_STATUS_HAVE_NO_MEMORY(ctx);
303 ctx->async.fn = usersids_recv_sids;
304 ctx->async.private_data = s3call;
305 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
309 static void usersids_recv_sids(struct composite_context *ctx)
311 struct wbsrv_samba3_call *s3call =
312 talloc_get_type(ctx->async.private_data,
313 struct wbsrv_samba3_call);
315 struct dom_sid **sids;
319 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
320 if (!NT_STATUS_IS_OK(status)) goto done;
322 sids_string = talloc_strdup(s3call, "");
323 if (sids_string == NULL) {
324 status = NT_STATUS_NO_MEMORY;
328 for (i=0; i<num_sids; i++) {
329 sids_string = talloc_asprintf_append(
330 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
331 if (sids_string == NULL) {
332 status = NT_STATUS_NO_MEMORY;
337 s3call->response.result = WINBINDD_OK;
338 s3call->response.extra_data = sids_string;
339 s3call->response.length += strlen(sids_string);
340 s3call->response.data.num_entries = num_sids;
342 /* Hmmmm. Nasty protocol -- who invented the zeros between the
343 * SIDs? Hmmm. Could have been me -- vl */
345 while (*sids_string != '\0') {
346 if ((*sids_string) == '\n') {
353 wbsrv_samba3_async_epilogue(status, s3call);
357 Lookup a DOMAIN\\user style name, and return a SID
360 static void lookupname_recv_sid(struct composite_context *ctx);
362 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
364 struct composite_context *ctx;
365 struct wbsrv_service *service =
366 s3call->call->wbconn->listen_socket->service;
368 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
370 ctx = wb_cmd_lookupname_send(s3call, service,
371 s3call->request.data.name.dom_name,
372 s3call->request.data.name.name);
373 NT_STATUS_HAVE_NO_MEMORY(ctx);
375 /* setup the callbacks */
376 ctx->async.fn = lookupname_recv_sid;
377 ctx->async.private_data = s3call;
378 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
382 static void lookupname_recv_sid(struct composite_context *ctx)
384 struct wbsrv_samba3_call *s3call =
385 talloc_get_type(ctx->async.private_data,
386 struct wbsrv_samba3_call);
387 struct wb_sid_object *sid;
390 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
391 if (!NT_STATUS_IS_OK(status)) goto done;
393 s3call->response.result = WINBINDD_OK;
394 s3call->response.data.sid.type = sid->type;
395 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
396 dom_sid_string(s3call, sid->sid));
399 wbsrv_samba3_async_epilogue(status, s3call);
403 Lookup a SID, and return a DOMAIN\\user style name
406 static void lookupsid_recv_name(struct composite_context *ctx);
408 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
410 struct composite_context *ctx;
411 struct wbsrv_service *service =
412 s3call->call->wbconn->listen_socket->service;
415 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
417 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
419 DEBUG(5, ("Could not parse sid %s\n",
420 s3call->request.data.sid));
421 return NT_STATUS_NO_MEMORY;
424 ctx = wb_cmd_lookupsid_send(s3call, service, sid);
425 NT_STATUS_HAVE_NO_MEMORY(ctx);
427 /* setup the callbacks */
428 ctx->async.fn = lookupsid_recv_name;
429 ctx->async.private_data = s3call;
430 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
434 static void lookupsid_recv_name(struct composite_context *ctx)
436 struct wbsrv_samba3_call *s3call =
437 talloc_get_type(ctx->async.private_data,
438 struct wbsrv_samba3_call);
439 struct wb_sid_object *sid;
442 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
443 if (!NT_STATUS_IS_OK(status)) goto done;
445 s3call->response.result = WINBINDD_OK;
446 s3call->response.data.name.type = sid->type;
447 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
449 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
452 wbsrv_samba3_async_epilogue(status, s3call);
456 Challenge-response authentication. This interface is used by
457 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
458 requests along a common pipe to the domain controller.
460 The return value (in the async reply) may include the 'info3'
461 (effectivly most things you would want to know about the user), or
462 the NT and LM session keys seperated.
465 static void pam_auth_crap_recv(struct composite_context *ctx);
467 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
469 struct composite_context *ctx;
470 struct wbsrv_service *service =
471 s3call->call->wbconn->listen_socket->service;
472 DATA_BLOB chal, nt_resp, lm_resp;
474 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
476 chal.data = s3call->request.data.auth_crap.chal;
477 chal.length = sizeof(s3call->request.data.auth_crap.chal);
478 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
479 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
480 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
481 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
483 ctx = wb_cmd_pam_auth_crap_send(
485 s3call->request.data.auth_crap.logon_parameters,
486 s3call->request.data.auth_crap.domain,
487 s3call->request.data.auth_crap.user,
488 s3call->request.data.auth_crap.workstation,
489 chal, nt_resp, lm_resp);
490 NT_STATUS_HAVE_NO_MEMORY(ctx);
492 ctx->async.fn = pam_auth_crap_recv;
493 ctx->async.private_data = s3call;
494 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
498 static void pam_auth_crap_recv(struct composite_context *ctx)
500 struct wbsrv_samba3_call *s3call =
501 talloc_get_type(ctx->async.private_data,
502 struct wbsrv_samba3_call);
505 struct netr_UserSessionKey user_session_key;
506 struct netr_LMSessionKey lm_key;
509 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
510 &user_session_key, &lm_key, &unix_username);
511 if (!NT_STATUS_IS_OK(status)) goto done;
513 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
514 memcpy(s3call->response.data.auth.user_session_key,
515 &user_session_key.key,
516 sizeof(s3call->response.data.auth.user_session_key));
519 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
520 s3call->response.extra_data = info3.data;
521 s3call->response.length += info3.length;
524 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
525 memcpy(s3call->response.data.auth.first_8_lm_hash,
527 sizeof(s3call->response.data.auth.first_8_lm_hash));
530 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
531 s3call->response.extra_data = unix_username;
532 s3call->response.length += strlen(unix_username)+1;
536 wbsrv_samba3_async_auth_epilogue(status, s3call);
539 /* Helper function: Split a domain\\user string into it's parts,
540 * because the client supplies it as one string */
542 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
543 char **domain, char **user)
545 char *p = strchr(domuser, *lp_winbind_separator());
548 *domain = talloc_strdup(mem_ctx, lp_workgroup());
550 *domain = talloc_strndup(mem_ctx, domuser,
551 PTR_DIFF(p, domuser));
555 *user = talloc_strdup(mem_ctx, domuser);
557 return ((*domain != NULL) && (*user != NULL));
560 /* Plaintext authentication
562 This interface is used by ntlm_auth in it's 'basic' authentication
563 mode, as well as by pam_winbind to authenticate users where we are
564 given a plaintext password.
567 static void pam_auth_recv(struct composite_context *ctx);
569 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
571 struct composite_context *ctx;
572 struct wbsrv_service *service =
573 s3call->call->wbconn->listen_socket->service;
576 if (!samba3_parse_domuser(s3call,
577 s3call->request.data.auth.user,
579 return NT_STATUS_NO_SUCH_USER;
582 ctx = wb_cmd_pam_auth_send(s3call, service, 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(s3call, 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);