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"
29 #include "include/version.h"
30 #include "librpc/gen_ndr/ndr_netlogon.h"
33 Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
36 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
37 struct wbsrv_samba3_call *s3call)
39 struct winbindd_response *resp = &s3call->response;
40 if (!NT_STATUS_IS_OK(status)) {
41 resp->result = WINBINDD_ERROR;
42 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
44 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
45 get_friendly_nt_error_msg(status));
47 resp->result = WINBINDD_OK;
50 resp->data.auth.pam_error = nt_status_to_pam(status);
51 resp->data.auth.nt_status = NT_STATUS_V(status);
53 wbsrv_samba3_send_reply(s3call);
57 Send of a generic reply to a Samba3 query
60 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
61 struct wbsrv_samba3_call *s3call)
63 struct winbindd_response *resp = &s3call->response;
64 if (NT_STATUS_IS_OK(status)) {
65 resp->result = WINBINDD_OK;
67 resp->result = WINBINDD_ERROR;
70 wbsrv_samba3_send_reply(s3call);
74 Boilerplate commands, simple queries without network traffic
77 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
79 s3call->response.result = WINBINDD_OK;
80 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
84 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
86 s3call->response.result = WINBINDD_OK;
87 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
88 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
89 SAMBA_VERSION_STRING);
93 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
95 s3call->response.result = WINBINDD_OK;
96 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
101 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
103 s3call->response.result = WINBINDD_OK;
104 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
109 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
111 s3call->response.result = WINBINDD_OK;
112 s3call->response.extra_data =
113 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
114 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
118 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
120 s3call->response.result = WINBINDD_OK;
126 Validate that we have a working pipe to the domain controller.
127 Return any NT error found in the process
130 static void checkmachacc_recv_creds(struct composite_context *ctx);
132 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
134 struct composite_context *ctx;
136 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
138 ctx = wb_cmd_checkmachacc_send(s3call->call);
139 NT_STATUS_HAVE_NO_MEMORY(ctx);
141 ctx->async.fn = checkmachacc_recv_creds;
142 ctx->async.private_data = s3call;
143 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
147 static void checkmachacc_recv_creds(struct composite_context *ctx)
149 struct wbsrv_samba3_call *s3call =
150 talloc_get_type(ctx->async.private_data,
151 struct wbsrv_samba3_call);
154 status = wb_cmd_checkmachacc_recv(ctx);
156 wbsrv_samba3_async_auth_epilogue(status, s3call);
161 Find the name of a suitable domain controller, by query on the
162 netlogon pipe to the DC.
165 static void getdcname_recv_dc(struct composite_context *ctx);
167 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
169 struct composite_context *ctx;
170 struct wbsrv_service *service =
171 s3call->wbconn->listen_socket->service;
173 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
175 ctx = wb_cmd_getdcname_send(s3call, service,
176 s3call->request.domain_name);
177 NT_STATUS_HAVE_NO_MEMORY(ctx);
179 ctx->async.fn = getdcname_recv_dc;
180 ctx->async.private_data = s3call;
181 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
185 static void getdcname_recv_dc(struct composite_context *ctx)
187 struct wbsrv_samba3_call *s3call =
188 talloc_get_type(ctx->async.private_data,
189 struct wbsrv_samba3_call);
193 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
194 if (!NT_STATUS_IS_OK(status)) goto done;
196 s3call->response.result = WINBINDD_OK;
197 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
200 wbsrv_samba3_async_epilogue(status, s3call);
204 Lookup a user's domain groups
207 static void userdomgroups_recv_groups(struct composite_context *ctx);
209 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
211 struct composite_context *ctx;
214 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
216 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
218 DEBUG(5, ("Could not parse sid %s\n",
219 s3call->request.data.sid));
220 return NT_STATUS_NO_MEMORY;
223 ctx = wb_cmd_userdomgroups_send(
224 s3call, s3call->wbconn->listen_socket->service, sid);
225 NT_STATUS_HAVE_NO_MEMORY(ctx);
227 ctx->async.fn = userdomgroups_recv_groups;
228 ctx->async.private_data = s3call;
229 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
233 static void userdomgroups_recv_groups(struct composite_context *ctx)
235 struct wbsrv_samba3_call *s3call =
236 talloc_get_type(ctx->async.private_data,
237 struct wbsrv_samba3_call);
239 struct dom_sid **sids;
243 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
244 if (!NT_STATUS_IS_OK(status)) goto done;
246 sids_string = talloc_strdup(s3call, "");
247 if (sids_string == NULL) {
248 status = NT_STATUS_NO_MEMORY;
252 for (i=0; i<num_sids; i++) {
253 sids_string = talloc_asprintf_append(
254 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
257 if (sids_string == NULL) {
258 status = NT_STATUS_NO_MEMORY;
262 s3call->response.result = WINBINDD_OK;
263 s3call->response.extra_data = sids_string;
264 s3call->response.length += strlen(sids_string)+1;
265 s3call->response.data.num_entries = num_sids;
268 wbsrv_samba3_async_epilogue(status, s3call);
272 Lookup the list of SIDs for a user
274 static void usersids_recv_sids(struct composite_context *ctx);
276 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
278 struct composite_context *ctx;
281 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
283 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
285 DEBUG(5, ("Could not parse sid %s\n",
286 s3call->request.data.sid));
287 return NT_STATUS_NO_MEMORY;
290 ctx = wb_cmd_usersids_send(
291 s3call, s3call->wbconn->listen_socket->service, sid);
292 NT_STATUS_HAVE_NO_MEMORY(ctx);
294 ctx->async.fn = usersids_recv_sids;
295 ctx->async.private_data = s3call;
296 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
300 static void usersids_recv_sids(struct composite_context *ctx)
302 struct wbsrv_samba3_call *s3call =
303 talloc_get_type(ctx->async.private_data,
304 struct wbsrv_samba3_call);
306 struct dom_sid **sids;
310 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
311 if (!NT_STATUS_IS_OK(status)) goto done;
313 sids_string = talloc_strdup(s3call, "");
314 if (sids_string == NULL) {
315 status = NT_STATUS_NO_MEMORY;
319 for (i=0; i<num_sids; i++) {
320 sids_string = talloc_asprintf_append(
321 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
322 if (sids_string == NULL) {
323 status = NT_STATUS_NO_MEMORY;
328 s3call->response.result = WINBINDD_OK;
329 s3call->response.extra_data = sids_string;
330 s3call->response.length += strlen(sids_string);
331 s3call->response.data.num_entries = num_sids;
333 /* Hmmmm. Nasty protocol -- who invented the zeros between the
334 * SIDs? Hmmm. Could have been me -- vl */
336 while (*sids_string != '\0') {
337 if ((*sids_string) == '\n') {
344 wbsrv_samba3_async_epilogue(status, s3call);
348 Lookup a DOMAIN\\user style name, and return a SID
351 static void lookupname_recv_sid(struct composite_context *ctx);
353 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
355 struct composite_context *ctx;
356 struct wbsrv_service *service =
357 s3call->wbconn->listen_socket->service;
359 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
361 ctx = wb_cmd_lookupname_send(s3call, service,
362 s3call->request.data.name.dom_name,
363 s3call->request.data.name.name);
364 NT_STATUS_HAVE_NO_MEMORY(ctx);
366 /* setup the callbacks */
367 ctx->async.fn = lookupname_recv_sid;
368 ctx->async.private_data = s3call;
369 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
373 static void lookupname_recv_sid(struct composite_context *ctx)
375 struct wbsrv_samba3_call *s3call =
376 talloc_get_type(ctx->async.private_data,
377 struct wbsrv_samba3_call);
378 struct wb_sid_object *sid;
381 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
382 if (!NT_STATUS_IS_OK(status)) goto done;
384 s3call->response.result = WINBINDD_OK;
385 s3call->response.data.sid.type = sid->type;
386 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
387 dom_sid_string(s3call, sid->sid));
390 wbsrv_samba3_async_epilogue(status, s3call);
394 Lookup a SID, and return a DOMAIN\\user style name
397 static void lookupsid_recv_name(struct composite_context *ctx);
399 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
401 struct composite_context *ctx;
402 struct wbsrv_service *service =
403 s3call->wbconn->listen_socket->service;
406 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
408 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
410 DEBUG(5, ("Could not parse sid %s\n",
411 s3call->request.data.sid));
412 return NT_STATUS_NO_MEMORY;
415 ctx = wb_cmd_lookupsid_send(s3call, service, sid);
416 NT_STATUS_HAVE_NO_MEMORY(ctx);
418 /* setup the callbacks */
419 ctx->async.fn = lookupsid_recv_name;
420 ctx->async.private_data = s3call;
421 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
425 static void lookupsid_recv_name(struct composite_context *ctx)
427 struct wbsrv_samba3_call *s3call =
428 talloc_get_type(ctx->async.private_data,
429 struct wbsrv_samba3_call);
430 struct wb_sid_object *sid;
433 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
434 if (!NT_STATUS_IS_OK(status)) goto done;
436 s3call->response.result = WINBINDD_OK;
437 s3call->response.data.name.type = sid->type;
438 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
440 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
443 wbsrv_samba3_async_epilogue(status, s3call);
447 Challenge-response authentication. This interface is used by
448 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
449 requests along a common pipe to the domain controller.
451 The return value (in the async reply) may include the 'info3'
452 (effectivly most things you would want to know about the user), or
453 the NT and LM session keys seperated.
456 static void pam_auth_crap_recv(struct composite_context *ctx);
458 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
460 struct composite_context *ctx;
461 struct wbsrv_service *service =
462 s3call->wbconn->listen_socket->service;
463 DATA_BLOB chal, nt_resp, lm_resp;
465 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
467 chal.data = s3call->request.data.auth_crap.chal;
468 chal.length = sizeof(s3call->request.data.auth_crap.chal);
469 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
470 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
471 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
472 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
474 ctx = wb_cmd_pam_auth_crap_send(
476 s3call->request.data.auth_crap.logon_parameters,
477 s3call->request.data.auth_crap.domain,
478 s3call->request.data.auth_crap.user,
479 s3call->request.data.auth_crap.workstation,
480 chal, nt_resp, lm_resp);
481 NT_STATUS_HAVE_NO_MEMORY(ctx);
483 ctx->async.fn = pam_auth_crap_recv;
484 ctx->async.private_data = s3call;
485 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
489 static void pam_auth_crap_recv(struct composite_context *ctx)
491 struct wbsrv_samba3_call *s3call =
492 talloc_get_type(ctx->async.private_data,
493 struct wbsrv_samba3_call);
496 struct netr_UserSessionKey user_session_key;
497 struct netr_LMSessionKey lm_key;
500 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
501 &user_session_key, &lm_key, &unix_username);
502 if (!NT_STATUS_IS_OK(status)) goto done;
504 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
505 memcpy(s3call->response.data.auth.user_session_key,
506 &user_session_key.key,
507 sizeof(s3call->response.data.auth.user_session_key));
510 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
511 s3call->response.extra_data = info3.data;
512 s3call->response.length += info3.length;
515 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
516 memcpy(s3call->response.data.auth.first_8_lm_hash,
518 sizeof(s3call->response.data.auth.first_8_lm_hash));
521 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
522 s3call->response.extra_data = unix_username;
523 s3call->response.length += strlen(unix_username)+1;
527 wbsrv_samba3_async_auth_epilogue(status, s3call);
530 /* Helper function: Split a domain\\user string into it's parts,
531 * because the client supplies it as one string */
533 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
534 char **domain, char **user)
536 char *p = strchr(domuser, *lp_winbind_separator());
539 *domain = talloc_strdup(mem_ctx, lp_workgroup());
541 *domain = talloc_strndup(mem_ctx, domuser,
542 PTR_DIFF(p, domuser));
546 *user = talloc_strdup(mem_ctx, domuser);
548 return ((*domain != NULL) && (*user != NULL));
551 /* Plaintext authentication
553 This interface is used by ntlm_auth in it's 'basic' authentication
554 mode, as well as by pam_winbind to authenticate users where we are
555 given a plaintext password.
558 static void pam_auth_recv(struct composite_context *ctx);
560 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
562 struct composite_context *ctx;
563 struct wbsrv_service *service =
564 s3call->wbconn->listen_socket->service;
567 if (!samba3_parse_domuser(s3call,
568 s3call->request.data.auth.user,
570 return NT_STATUS_NO_SUCH_USER;
573 ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
574 s3call->request.data.auth.pass);
575 NT_STATUS_HAVE_NO_MEMORY(ctx);
577 ctx->async.fn = pam_auth_recv;
578 ctx->async.private_data = s3call;
579 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
583 static void pam_auth_recv(struct composite_context *ctx)
585 struct wbsrv_samba3_call *s3call =
586 talloc_get_type(ctx->async.private_data,
587 struct wbsrv_samba3_call);
590 status = wb_cmd_pam_auth_recv(ctx);
592 if (!NT_STATUS_IS_OK(status)) goto done;
595 wbsrv_samba3_async_auth_epilogue(status, s3call);
602 static void list_trustdom_recv_doms(struct composite_context *ctx);
604 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
606 struct composite_context *ctx;
607 struct wbsrv_service *service =
608 s3call->wbconn->listen_socket->service;
610 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
612 ctx = wb_cmd_list_trustdoms_send(s3call, service);
613 NT_STATUS_HAVE_NO_MEMORY(ctx);
615 ctx->async.fn = list_trustdom_recv_doms;
616 ctx->async.private_data = s3call;
617 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
621 static void list_trustdom_recv_doms(struct composite_context *ctx)
623 struct wbsrv_samba3_call *s3call =
624 talloc_get_type(ctx->async.private_data,
625 struct wbsrv_samba3_call);
627 struct wb_dom_info **domains;
631 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
633 if (!NT_STATUS_IS_OK(status)) goto done;
635 result = talloc_strdup(s3call, "");
636 if (result == NULL) {
637 status = NT_STATUS_NO_MEMORY;
641 for (i=0; i<num_domains; i++) {
642 result = talloc_asprintf_append(
643 result, "%s\\%s\\%s",
644 domains[i]->name, domains[i]->name,
645 dom_sid_string(s3call, domains[i]->sid));
648 if (result == NULL) {
649 status = NT_STATUS_NO_MEMORY;
653 s3call->response.result = WINBINDD_OK;
654 if (num_domains > 0) {
655 s3call->response.extra_data = result;
656 s3call->response.length += strlen(result)+1;
660 wbsrv_samba3_async_epilogue(status, s3call);