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 wbsrv_samba3_send_reply(s3call);
58 Send of a generic reply to a Samba3 query
61 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
62 struct wbsrv_samba3_call *s3call)
64 struct winbindd_response *resp = &s3call->response;
65 if (NT_STATUS_IS_OK(status)) {
66 resp->result = WINBINDD_OK;
68 resp->result = WINBINDD_ERROR;
71 wbsrv_samba3_send_reply(s3call);
75 Boilerplate commands, simple queries without network traffic
78 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
80 s3call->response.result = WINBINDD_OK;
81 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
85 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
87 s3call->response.result = WINBINDD_OK;
88 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
89 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
90 SAMBA_VERSION_STRING);
94 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
96 s3call->response.result = WINBINDD_OK;
97 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
102 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
104 s3call->response.result = WINBINDD_OK;
105 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
110 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
112 s3call->response.result = WINBINDD_OK;
113 s3call->response.extra_data =
114 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
115 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
119 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
121 s3call->response.result = WINBINDD_OK;
127 Validate that we have a working pipe to the domain controller.
128 Return any NT error found in the process
131 static void checkmachacc_recv_creds(struct composite_context *ctx);
133 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
135 struct composite_context *ctx;
137 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
139 ctx = wb_cmd_checkmachacc_send(s3call->call);
140 NT_STATUS_HAVE_NO_MEMORY(ctx);
142 ctx->async.fn = checkmachacc_recv_creds;
143 ctx->async.private_data = s3call;
144 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
148 static void checkmachacc_recv_creds(struct composite_context *ctx)
150 struct wbsrv_samba3_call *s3call =
151 talloc_get_type(ctx->async.private_data,
152 struct wbsrv_samba3_call);
155 status = wb_cmd_checkmachacc_recv(ctx);
157 wbsrv_samba3_async_auth_epilogue(status, s3call);
162 Find the name of a suitable domain controller, by query on the
163 netlogon pipe to the DC.
166 static void getdcname_recv_dc(struct composite_context *ctx);
168 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
170 struct composite_context *ctx;
171 struct wbsrv_service *service =
172 s3call->wbconn->listen_socket->service;
174 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
176 ctx = wb_cmd_getdcname_send(s3call, service,
177 s3call->request.domain_name);
178 NT_STATUS_HAVE_NO_MEMORY(ctx);
180 ctx->async.fn = getdcname_recv_dc;
181 ctx->async.private_data = s3call;
182 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
186 static void getdcname_recv_dc(struct composite_context *ctx)
188 struct wbsrv_samba3_call *s3call =
189 talloc_get_type(ctx->async.private_data,
190 struct wbsrv_samba3_call);
194 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
195 if (!NT_STATUS_IS_OK(status)) goto done;
197 s3call->response.result = WINBINDD_OK;
198 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
201 wbsrv_samba3_async_epilogue(status, s3call);
205 Lookup a user's domain groups
208 static void userdomgroups_recv_groups(struct composite_context *ctx);
210 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
212 struct composite_context *ctx;
215 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
217 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
219 DEBUG(5, ("Could not parse sid %s\n",
220 s3call->request.data.sid));
221 return NT_STATUS_NO_MEMORY;
224 ctx = wb_cmd_userdomgroups_send(
225 s3call, s3call->wbconn->listen_socket->service, sid);
226 NT_STATUS_HAVE_NO_MEMORY(ctx);
228 ctx->async.fn = userdomgroups_recv_groups;
229 ctx->async.private_data = s3call;
230 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
234 static void userdomgroups_recv_groups(struct composite_context *ctx)
236 struct wbsrv_samba3_call *s3call =
237 talloc_get_type(ctx->async.private_data,
238 struct wbsrv_samba3_call);
240 struct dom_sid **sids;
244 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
245 if (!NT_STATUS_IS_OK(status)) goto done;
247 sids_string = talloc_strdup(s3call, "");
248 if (sids_string == NULL) {
249 status = NT_STATUS_NO_MEMORY;
253 for (i=0; i<num_sids; i++) {
254 sids_string = talloc_asprintf_append(
255 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
258 if (sids_string == NULL) {
259 status = NT_STATUS_NO_MEMORY;
263 s3call->response.result = WINBINDD_OK;
264 s3call->response.extra_data = sids_string;
265 s3call->response.length += strlen(sids_string)+1;
266 s3call->response.data.num_entries = num_sids;
269 wbsrv_samba3_async_epilogue(status, s3call);
273 Lookup the list of SIDs for a user
275 static void usersids_recv_sids(struct composite_context *ctx);
277 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
279 struct composite_context *ctx;
282 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
284 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
286 DEBUG(5, ("Could not parse sid %s\n",
287 s3call->request.data.sid));
288 return NT_STATUS_NO_MEMORY;
291 ctx = wb_cmd_usersids_send(
292 s3call, s3call->wbconn->listen_socket->service, sid);
293 NT_STATUS_HAVE_NO_MEMORY(ctx);
295 ctx->async.fn = usersids_recv_sids;
296 ctx->async.private_data = s3call;
297 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
301 static void usersids_recv_sids(struct composite_context *ctx)
303 struct wbsrv_samba3_call *s3call =
304 talloc_get_type(ctx->async.private_data,
305 struct wbsrv_samba3_call);
307 struct dom_sid **sids;
311 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
312 if (!NT_STATUS_IS_OK(status)) goto done;
314 sids_string = talloc_strdup(s3call, "");
315 if (sids_string == NULL) {
316 status = NT_STATUS_NO_MEMORY;
320 for (i=0; i<num_sids; i++) {
321 sids_string = talloc_asprintf_append(
322 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
323 if (sids_string == NULL) {
324 status = NT_STATUS_NO_MEMORY;
329 s3call->response.result = WINBINDD_OK;
330 s3call->response.extra_data = sids_string;
331 s3call->response.length += strlen(sids_string);
332 s3call->response.data.num_entries = num_sids;
334 /* Hmmmm. Nasty protocol -- who invented the zeros between the
335 * SIDs? Hmmm. Could have been me -- vl */
337 while (*sids_string != '\0') {
338 if ((*sids_string) == '\n') {
345 wbsrv_samba3_async_epilogue(status, s3call);
349 Lookup a DOMAIN\\user style name, and return a SID
352 static void lookupname_recv_sid(struct composite_context *ctx);
354 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
356 struct composite_context *ctx;
357 struct wbsrv_service *service =
358 s3call->wbconn->listen_socket->service;
360 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
362 ctx = wb_cmd_lookupname_send(s3call, service,
363 s3call->request.data.name.dom_name,
364 s3call->request.data.name.name);
365 NT_STATUS_HAVE_NO_MEMORY(ctx);
367 /* setup the callbacks */
368 ctx->async.fn = lookupname_recv_sid;
369 ctx->async.private_data = s3call;
370 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
374 static void lookupname_recv_sid(struct composite_context *ctx)
376 struct wbsrv_samba3_call *s3call =
377 talloc_get_type(ctx->async.private_data,
378 struct wbsrv_samba3_call);
379 struct wb_sid_object *sid;
382 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
383 if (!NT_STATUS_IS_OK(status)) goto done;
385 s3call->response.result = WINBINDD_OK;
386 s3call->response.data.sid.type = sid->type;
387 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
388 dom_sid_string(s3call, sid->sid));
391 wbsrv_samba3_async_epilogue(status, s3call);
395 Lookup a SID, and return a DOMAIN\\user style name
398 static void lookupsid_recv_name(struct composite_context *ctx);
400 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
402 struct composite_context *ctx;
403 struct wbsrv_service *service =
404 s3call->wbconn->listen_socket->service;
407 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
409 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
411 DEBUG(5, ("Could not parse sid %s\n",
412 s3call->request.data.sid));
413 return NT_STATUS_NO_MEMORY;
416 ctx = wb_cmd_lookupsid_send(s3call, service, sid);
417 NT_STATUS_HAVE_NO_MEMORY(ctx);
419 /* setup the callbacks */
420 ctx->async.fn = lookupsid_recv_name;
421 ctx->async.private_data = s3call;
422 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
426 static void lookupsid_recv_name(struct composite_context *ctx)
428 struct wbsrv_samba3_call *s3call =
429 talloc_get_type(ctx->async.private_data,
430 struct wbsrv_samba3_call);
431 struct wb_sid_object *sid;
434 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
435 if (!NT_STATUS_IS_OK(status)) goto done;
437 s3call->response.result = WINBINDD_OK;
438 s3call->response.data.name.type = sid->type;
439 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
441 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
444 wbsrv_samba3_async_epilogue(status, s3call);
448 Challenge-response authentication. This interface is used by
449 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
450 requests along a common pipe to the domain controller.
452 The return value (in the async reply) may include the 'info3'
453 (effectivly most things you would want to know about the user), or
454 the NT and LM session keys seperated.
457 static void pam_auth_crap_recv(struct composite_context *ctx);
459 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
461 struct composite_context *ctx;
462 struct wbsrv_service *service =
463 s3call->wbconn->listen_socket->service;
464 DATA_BLOB chal, nt_resp, lm_resp;
466 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
468 chal.data = s3call->request.data.auth_crap.chal;
469 chal.length = sizeof(s3call->request.data.auth_crap.chal);
470 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
471 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
472 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
473 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
475 ctx = wb_cmd_pam_auth_crap_send(
477 s3call->request.data.auth_crap.logon_parameters,
478 s3call->request.data.auth_crap.domain,
479 s3call->request.data.auth_crap.user,
480 s3call->request.data.auth_crap.workstation,
481 chal, nt_resp, lm_resp);
482 NT_STATUS_HAVE_NO_MEMORY(ctx);
484 ctx->async.fn = pam_auth_crap_recv;
485 ctx->async.private_data = s3call;
486 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
490 static void pam_auth_crap_recv(struct composite_context *ctx)
492 struct wbsrv_samba3_call *s3call =
493 talloc_get_type(ctx->async.private_data,
494 struct wbsrv_samba3_call);
497 struct netr_UserSessionKey user_session_key;
498 struct netr_LMSessionKey lm_key;
501 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
502 &user_session_key, &lm_key, &unix_username);
503 if (!NT_STATUS_IS_OK(status)) goto done;
505 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
506 memcpy(s3call->response.data.auth.user_session_key,
507 &user_session_key.key,
508 sizeof(s3call->response.data.auth.user_session_key));
511 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
512 s3call->response.extra_data = info3.data;
513 s3call->response.length += info3.length;
516 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
517 memcpy(s3call->response.data.auth.first_8_lm_hash,
519 sizeof(s3call->response.data.auth.first_8_lm_hash));
522 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
523 s3call->response.extra_data = unix_username;
524 s3call->response.length += strlen(unix_username)+1;
528 wbsrv_samba3_async_auth_epilogue(status, s3call);
531 /* Helper function: Split a domain\\user string into it's parts,
532 * because the client supplies it as one string */
534 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
535 char **domain, char **user)
537 char *p = strchr(domuser, *lp_winbind_separator());
540 *domain = talloc_strdup(mem_ctx, lp_workgroup());
542 *domain = talloc_strndup(mem_ctx, domuser,
543 PTR_DIFF(p, domuser));
547 *user = talloc_strdup(mem_ctx, domuser);
549 return ((*domain != NULL) && (*user != NULL));
552 /* Plaintext authentication
554 This interface is used by ntlm_auth in it's 'basic' authentication
555 mode, as well as by pam_winbind to authenticate users where we are
556 given a plaintext password.
559 static void pam_auth_recv(struct composite_context *ctx);
561 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
563 struct composite_context *ctx;
564 struct wbsrv_service *service =
565 s3call->wbconn->listen_socket->service;
568 if (!samba3_parse_domuser(s3call,
569 s3call->request.data.auth.user,
571 return NT_STATUS_NO_SUCH_USER;
574 ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
575 s3call->request.data.auth.pass);
576 NT_STATUS_HAVE_NO_MEMORY(ctx);
578 ctx->async.fn = pam_auth_recv;
579 ctx->async.private_data = s3call;
580 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
584 static void pam_auth_recv(struct composite_context *ctx)
586 struct wbsrv_samba3_call *s3call =
587 talloc_get_type(ctx->async.private_data,
588 struct wbsrv_samba3_call);
591 status = wb_cmd_pam_auth_recv(ctx);
593 if (!NT_STATUS_IS_OK(status)) goto done;
596 wbsrv_samba3_async_auth_epilogue(status, s3call);
603 static void list_trustdom_recv_doms(struct composite_context *ctx);
605 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
607 struct composite_context *ctx;
608 struct wbsrv_service *service =
609 s3call->wbconn->listen_socket->service;
611 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
613 ctx = wb_cmd_list_trustdoms_send(s3call, service);
614 NT_STATUS_HAVE_NO_MEMORY(ctx);
616 ctx->async.fn = list_trustdom_recv_doms;
617 ctx->async.private_data = s3call;
618 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
622 static void list_trustdom_recv_doms(struct composite_context *ctx)
624 struct wbsrv_samba3_call *s3call =
625 talloc_get_type(ctx->async.private_data,
626 struct wbsrv_samba3_call);
628 struct wb_dom_info **domains;
632 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
634 if (!NT_STATUS_IS_OK(status)) goto done;
636 result = talloc_strdup(s3call, "");
637 if (result == NULL) {
638 status = NT_STATUS_NO_MEMORY;
642 for (i=0; i<num_domains; i++) {
643 result = talloc_asprintf_append(
644 result, "%s\\%s\\%s",
645 domains[i]->name, domains[i]->name,
646 dom_sid_string(s3call, domains[i]->sid));
649 if (result == NULL) {
650 status = NT_STATUS_NO_MEMORY;
654 s3call->response.result = WINBINDD_OK;
655 if (num_domains > 0) {
656 s3call->response.extra_data = result;
657 s3call->response.length += strlen(result)+1;
661 wbsrv_samba3_async_epilogue(status, s3call);