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_async_helpers.h"
28 #include "libcli/composite/composite.h"
30 #include "librpc/gen_ndr/netlogon.h"
31 #include "librpc/gen_ndr/ndr_security.h"
32 #include "libcli/security/proto.h"
33 #include "auth/pam_errors.h"
36 Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
39 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
40 struct wbsrv_samba3_call *s3call)
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,
47 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
48 get_friendly_nt_error_msg(status));
50 resp->result = WINBINDD_OK;
53 resp->data.auth.pam_error = nt_status_to_pam(status);
54 resp->data.auth.nt_status = NT_STATUS_V(status);
56 wbsrv_samba3_send_reply(s3call);
60 Send of a generic reply to a Samba3 query
63 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
64 struct wbsrv_samba3_call *s3call)
66 struct winbindd_response *resp = &s3call->response;
67 if (NT_STATUS_IS_OK(status)) {
68 resp->result = WINBINDD_OK;
70 resp->result = WINBINDD_ERROR;
73 wbsrv_samba3_send_reply(s3call);
77 Boilerplate commands, simple queries without network traffic
80 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
82 s3call->response.result = WINBINDD_OK;
83 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
87 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
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);
96 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
98 s3call->response.result = WINBINDD_OK;
99 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
104 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
106 s3call->response.result = WINBINDD_OK;
107 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
112 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
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);
121 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
123 s3call->response.result = WINBINDD_OK;
129 Validate that we have a working pipe to the domain controller.
130 Return any NT error found in the process
133 static void checkmachacc_recv_creds(struct composite_context *ctx);
135 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
137 struct composite_context *ctx;
139 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
141 ctx = wb_cmd_checkmachacc_send(s3call->call);
142 NT_STATUS_HAVE_NO_MEMORY(ctx);
144 ctx->async.fn = checkmachacc_recv_creds;
145 ctx->async.private_data = s3call;
146 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
150 static void checkmachacc_recv_creds(struct composite_context *ctx)
152 struct wbsrv_samba3_call *s3call =
153 talloc_get_type(ctx->async.private_data,
154 struct wbsrv_samba3_call);
157 status = wb_cmd_checkmachacc_recv(ctx);
159 wbsrv_samba3_async_auth_epilogue(status, s3call);
164 Find the name of a suitable domain controller, by query on the
165 netlogon pipe to the DC.
168 static void getdcname_recv_dc(struct composite_context *ctx);
170 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
172 struct composite_context *ctx;
173 struct wbsrv_service *service =
174 s3call->wbconn->listen_socket->service;
176 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
178 ctx = wb_cmd_getdcname_send(s3call, service,
179 s3call->request.domain_name);
180 NT_STATUS_HAVE_NO_MEMORY(ctx);
182 ctx->async.fn = getdcname_recv_dc;
183 ctx->async.private_data = s3call;
184 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
188 static void getdcname_recv_dc(struct composite_context *ctx)
190 struct wbsrv_samba3_call *s3call =
191 talloc_get_type(ctx->async.private_data,
192 struct wbsrv_samba3_call);
196 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
197 if (!NT_STATUS_IS_OK(status)) goto done;
199 s3call->response.result = WINBINDD_OK;
200 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
203 wbsrv_samba3_async_epilogue(status, s3call);
207 Lookup a user's domain groups
210 static void userdomgroups_recv_groups(struct composite_context *ctx);
212 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
214 struct composite_context *ctx;
217 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
219 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
221 DEBUG(5, ("Could not parse sid %s\n",
222 s3call->request.data.sid));
223 return NT_STATUS_NO_MEMORY;
226 ctx = wb_cmd_userdomgroups_send(
227 s3call, s3call->wbconn->listen_socket->service, sid);
228 NT_STATUS_HAVE_NO_MEMORY(ctx);
230 ctx->async.fn = userdomgroups_recv_groups;
231 ctx->async.private_data = s3call;
232 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
236 static void userdomgroups_recv_groups(struct composite_context *ctx)
238 struct wbsrv_samba3_call *s3call =
239 talloc_get_type(ctx->async.private_data,
240 struct wbsrv_samba3_call);
242 struct dom_sid **sids;
246 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
247 if (!NT_STATUS_IS_OK(status)) goto done;
249 sids_string = talloc_strdup(s3call, "");
250 if (sids_string == NULL) {
251 status = NT_STATUS_NO_MEMORY;
255 for (i=0; i<num_sids; i++) {
256 sids_string = talloc_asprintf_append(
257 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
260 if (sids_string == NULL) {
261 status = NT_STATUS_NO_MEMORY;
265 s3call->response.result = WINBINDD_OK;
266 s3call->response.extra_data = sids_string;
267 s3call->response.length += strlen(sids_string)+1;
268 s3call->response.data.num_entries = num_sids;
271 wbsrv_samba3_async_epilogue(status, s3call);
275 Lookup the list of SIDs for a user
277 static void usersids_recv_sids(struct composite_context *ctx);
279 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
281 struct composite_context *ctx;
284 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
286 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
288 DEBUG(5, ("Could not parse sid %s\n",
289 s3call->request.data.sid));
290 return NT_STATUS_NO_MEMORY;
293 ctx = wb_cmd_usersids_send(
294 s3call, s3call->wbconn->listen_socket->service, sid);
295 NT_STATUS_HAVE_NO_MEMORY(ctx);
297 ctx->async.fn = usersids_recv_sids;
298 ctx->async.private_data = s3call;
299 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
303 static void usersids_recv_sids(struct composite_context *ctx)
305 struct wbsrv_samba3_call *s3call =
306 talloc_get_type(ctx->async.private_data,
307 struct wbsrv_samba3_call);
309 struct dom_sid **sids;
313 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
314 if (!NT_STATUS_IS_OK(status)) goto done;
316 sids_string = talloc_strdup(s3call, "");
317 if (sids_string == NULL) {
318 status = NT_STATUS_NO_MEMORY;
322 for (i=0; i<num_sids; i++) {
323 sids_string = talloc_asprintf_append(
324 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
325 if (sids_string == NULL) {
326 status = NT_STATUS_NO_MEMORY;
331 s3call->response.result = WINBINDD_OK;
332 s3call->response.extra_data = sids_string;
333 s3call->response.length += strlen(sids_string);
334 s3call->response.data.num_entries = num_sids;
336 /* Hmmmm. Nasty protocol -- who invented the zeros between the
337 * SIDs? Hmmm. Could have been me -- vl */
339 while (*sids_string != '\0') {
340 if ((*sids_string) == '\n') {
347 wbsrv_samba3_async_epilogue(status, s3call);
351 Lookup a DOMAIN\\user style name, and return a SID
354 static void lookupname_recv_sid(struct composite_context *ctx);
356 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
358 struct composite_context *ctx;
359 struct wbsrv_service *service =
360 s3call->wbconn->listen_socket->service;
362 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
364 ctx = wb_cmd_lookupname_send(s3call, service,
365 s3call->request.data.name.dom_name,
366 s3call->request.data.name.name);
367 NT_STATUS_HAVE_NO_MEMORY(ctx);
369 /* setup the callbacks */
370 ctx->async.fn = lookupname_recv_sid;
371 ctx->async.private_data = s3call;
372 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
376 static void lookupname_recv_sid(struct composite_context *ctx)
378 struct wbsrv_samba3_call *s3call =
379 talloc_get_type(ctx->async.private_data,
380 struct wbsrv_samba3_call);
381 struct wb_sid_object *sid;
384 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
385 if (!NT_STATUS_IS_OK(status)) goto done;
387 s3call->response.result = WINBINDD_OK;
388 s3call->response.data.sid.type = sid->type;
389 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
390 dom_sid_string(s3call, sid->sid));
393 wbsrv_samba3_async_epilogue(status, s3call);
397 Lookup a SID, and return a DOMAIN\\user style name
400 static void lookupsid_recv_name(struct composite_context *ctx);
402 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
404 struct composite_context *ctx;
405 struct wbsrv_service *service =
406 s3call->wbconn->listen_socket->service;
409 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
411 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
413 DEBUG(5, ("Could not parse sid %s\n",
414 s3call->request.data.sid));
415 return NT_STATUS_NO_MEMORY;
418 ctx = wb_cmd_lookupsid_send(s3call, service, sid);
419 NT_STATUS_HAVE_NO_MEMORY(ctx);
421 /* setup the callbacks */
422 ctx->async.fn = lookupsid_recv_name;
423 ctx->async.private_data = s3call;
424 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
428 static void lookupsid_recv_name(struct composite_context *ctx)
430 struct wbsrv_samba3_call *s3call =
431 talloc_get_type(ctx->async.private_data,
432 struct wbsrv_samba3_call);
433 struct wb_sid_object *sid;
436 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
437 if (!NT_STATUS_IS_OK(status)) goto done;
439 s3call->response.result = WINBINDD_OK;
440 s3call->response.data.name.type = sid->type;
441 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
443 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
446 wbsrv_samba3_async_epilogue(status, s3call);
450 Challenge-response authentication. This interface is used by
451 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
452 requests along a common pipe to the domain controller.
454 The return value (in the async reply) may include the 'info3'
455 (effectivly most things you would want to know about the user), or
456 the NT and LM session keys seperated.
459 static void pam_auth_crap_recv(struct composite_context *ctx);
461 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
463 struct composite_context *ctx;
464 struct wbsrv_service *service =
465 s3call->wbconn->listen_socket->service;
466 DATA_BLOB chal, nt_resp, lm_resp;
468 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
470 chal.data = s3call->request.data.auth_crap.chal;
471 chal.length = sizeof(s3call->request.data.auth_crap.chal);
472 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
473 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
474 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
475 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
477 ctx = wb_cmd_pam_auth_crap_send(
479 s3call->request.data.auth_crap.logon_parameters,
480 s3call->request.data.auth_crap.domain,
481 s3call->request.data.auth_crap.user,
482 s3call->request.data.auth_crap.workstation,
483 chal, nt_resp, lm_resp);
484 NT_STATUS_HAVE_NO_MEMORY(ctx);
486 ctx->async.fn = pam_auth_crap_recv;
487 ctx->async.private_data = s3call;
488 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
492 static void pam_auth_crap_recv(struct composite_context *ctx)
494 struct wbsrv_samba3_call *s3call =
495 talloc_get_type(ctx->async.private_data,
496 struct wbsrv_samba3_call);
499 struct netr_UserSessionKey user_session_key;
500 struct netr_LMSessionKey lm_key;
503 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
504 &user_session_key, &lm_key, &unix_username);
505 if (!NT_STATUS_IS_OK(status)) goto done;
507 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
508 memcpy(s3call->response.data.auth.user_session_key,
509 &user_session_key.key,
510 sizeof(s3call->response.data.auth.user_session_key));
513 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
514 s3call->response.extra_data = info3.data;
515 s3call->response.length += info3.length;
518 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
519 memcpy(s3call->response.data.auth.first_8_lm_hash,
521 sizeof(s3call->response.data.auth.first_8_lm_hash));
524 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
525 s3call->response.extra_data = unix_username;
526 s3call->response.length += strlen(unix_username)+1;
530 wbsrv_samba3_async_auth_epilogue(status, s3call);
533 /* Helper function: Split a domain\\user string into it's parts,
534 * because the client supplies it as one string */
536 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
537 char **domain, char **user)
539 char *p = strchr(domuser, *lp_winbind_separator());
542 *domain = talloc_strdup(mem_ctx, lp_workgroup());
544 *domain = talloc_strndup(mem_ctx, domuser,
545 PTR_DIFF(p, domuser));
549 *user = talloc_strdup(mem_ctx, domuser);
551 return ((*domain != NULL) && (*user != NULL));
554 /* Plaintext authentication
556 This interface is used by ntlm_auth in it's 'basic' authentication
557 mode, as well as by pam_winbind to authenticate users where we are
558 given a plaintext password.
561 static void pam_auth_recv(struct composite_context *ctx);
563 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
565 struct composite_context *ctx;
566 struct wbsrv_service *service =
567 s3call->wbconn->listen_socket->service;
570 if (!samba3_parse_domuser(s3call,
571 s3call->request.data.auth.user,
573 return NT_STATUS_NO_SUCH_USER;
576 ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
577 s3call->request.data.auth.pass);
578 NT_STATUS_HAVE_NO_MEMORY(ctx);
580 ctx->async.fn = pam_auth_recv;
581 ctx->async.private_data = s3call;
582 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
586 static void pam_auth_recv(struct composite_context *ctx)
588 struct wbsrv_samba3_call *s3call =
589 talloc_get_type(ctx->async.private_data,
590 struct wbsrv_samba3_call);
593 status = wb_cmd_pam_auth_recv(ctx);
595 if (!NT_STATUS_IS_OK(status)) goto done;
598 wbsrv_samba3_async_auth_epilogue(status, s3call);
605 static void list_trustdom_recv_doms(struct composite_context *ctx);
607 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
609 struct composite_context *ctx;
610 struct wbsrv_service *service =
611 s3call->wbconn->listen_socket->service;
613 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
615 ctx = wb_cmd_list_trustdoms_send(s3call, service);
616 NT_STATUS_HAVE_NO_MEMORY(ctx);
618 ctx->async.fn = list_trustdom_recv_doms;
619 ctx->async.private_data = s3call;
620 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
624 static void list_trustdom_recv_doms(struct composite_context *ctx)
626 struct wbsrv_samba3_call *s3call =
627 talloc_get_type(ctx->async.private_data,
628 struct wbsrv_samba3_call);
630 struct wb_dom_info **domains;
634 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
636 if (!NT_STATUS_IS_OK(status)) goto done;
638 result = talloc_strdup(s3call, "");
639 if (result == NULL) {
640 status = NT_STATUS_NO_MEMORY;
644 for (i=0; i<num_domains; i++) {
645 result = talloc_asprintf_append(
646 result, "%s\\%s\\%s",
647 domains[i]->name, domains[i]->name,
648 dom_sid_string(s3call, domains[i]->sid));
651 if (result == NULL) {
652 status = NT_STATUS_NO_MEMORY;
656 s3call->response.result = WINBINDD_OK;
657 if (num_domains > 0) {
658 s3call->response.extra_data = result;
659 s3call->response.length += strlen(result)+1;
663 wbsrv_samba3_async_epilogue(status, s3call);