r20593: Kill annoying warning.
[Samba.git] / source / winbind / wb_samba3_cmd.c
blob7989bec17223e2e2190bcad3c25548ebffe0cfa4
1 /*
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.
24 #include "includes.h"
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 "version.h"
30 #include "librpc/gen_ndr/netlogon.h"
31 #include "libcli/security/security.h"
32 #include "auth/pam_errors.h"
34 /*
35 Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
38 static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
39 struct wbsrv_samba3_call *s3call)
41 struct winbindd_response *resp = &s3call->response;
42 if (!NT_STATUS_IS_OK(status)) {
43 resp->result = WINBINDD_ERROR;
44 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
45 nt_errstr(status));
46 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
47 get_friendly_nt_error_msg(status));
48 } else {
49 resp->result = WINBINDD_OK;
52 resp->data.auth.pam_error = nt_status_to_pam(status);
53 resp->data.auth.nt_status = NT_STATUS_V(status);
55 wbsrv_samba3_send_reply(s3call);
58 /*
59 Send of a generic reply to a Samba3 query
62 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
63 struct wbsrv_samba3_call *s3call)
65 struct winbindd_response *resp = &s3call->response;
66 if (NT_STATUS_IS_OK(status)) {
67 resp->result = WINBINDD_OK;
68 } else {
69 resp->result = WINBINDD_ERROR;
72 wbsrv_samba3_send_reply(s3call);
75 /*
76 Boilerplate commands, simple queries without network traffic
79 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
81 s3call->response.result = WINBINDD_OK;
82 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
83 return NT_STATUS_OK;
86 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
88 s3call->response.result = WINBINDD_OK;
89 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
90 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
91 SAMBA_VERSION_STRING);
92 return NT_STATUS_OK;
95 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
97 s3call->response.result = WINBINDD_OK;
98 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
99 lp_workgroup());
100 return NT_STATUS_OK;
103 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
105 s3call->response.result = WINBINDD_OK;
106 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
107 lp_netbios_name());
108 return NT_STATUS_OK;
111 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
113 s3call->response.result = WINBINDD_OK;
114 s3call->response.extra_data =
115 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
116 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
117 return NT_STATUS_OK;
120 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
122 s3call->response.result = WINBINDD_OK;
123 return NT_STATUS_OK;
126 #if 0
128 Validate that we have a working pipe to the domain controller.
129 Return any NT error found in the process
132 static void checkmachacc_recv_creds(struct composite_context *ctx);
134 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
136 struct composite_context *ctx;
138 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
140 ctx = wb_cmd_checkmachacc_send(s3call->call);
141 NT_STATUS_HAVE_NO_MEMORY(ctx);
143 ctx->async.fn = checkmachacc_recv_creds;
144 ctx->async.private_data = s3call;
145 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
146 return NT_STATUS_OK;
149 static void checkmachacc_recv_creds(struct composite_context *ctx)
151 struct wbsrv_samba3_call *s3call =
152 talloc_get_type(ctx->async.private_data,
153 struct wbsrv_samba3_call);
154 NTSTATUS status;
156 status = wb_cmd_checkmachacc_recv(ctx);
158 wbsrv_samba3_async_auth_epilogue(status, s3call);
160 #endif
163 Find the name of a suitable domain controller, by query on the
164 netlogon pipe to the DC.
167 static void getdcname_recv_dc(struct composite_context *ctx);
169 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
171 struct composite_context *ctx;
172 struct wbsrv_service *service =
173 s3call->wbconn->listen_socket->service;
175 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
177 ctx = wb_cmd_getdcname_send(s3call, service,
178 s3call->request.domain_name);
179 NT_STATUS_HAVE_NO_MEMORY(ctx);
181 ctx->async.fn = getdcname_recv_dc;
182 ctx->async.private_data = s3call;
183 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
184 return NT_STATUS_OK;
187 static void getdcname_recv_dc(struct composite_context *ctx)
189 struct wbsrv_samba3_call *s3call =
190 talloc_get_type(ctx->async.private_data,
191 struct wbsrv_samba3_call);
192 const char *dcname;
193 NTSTATUS status;
195 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
196 if (!NT_STATUS_IS_OK(status)) goto done;
198 s3call->response.result = WINBINDD_OK;
199 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
201 done:
202 wbsrv_samba3_async_epilogue(status, s3call);
206 Lookup a user's domain groups
209 static void userdomgroups_recv_groups(struct composite_context *ctx);
211 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
213 struct composite_context *ctx;
214 struct dom_sid *sid;
216 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
218 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
219 if (sid == NULL) {
220 DEBUG(5, ("Could not parse sid %s\n",
221 s3call->request.data.sid));
222 return NT_STATUS_NO_MEMORY;
225 ctx = wb_cmd_userdomgroups_send(
226 s3call, s3call->wbconn->listen_socket->service, sid);
227 NT_STATUS_HAVE_NO_MEMORY(ctx);
229 ctx->async.fn = userdomgroups_recv_groups;
230 ctx->async.private_data = s3call;
231 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
232 return NT_STATUS_OK;
235 static void userdomgroups_recv_groups(struct composite_context *ctx)
237 struct wbsrv_samba3_call *s3call =
238 talloc_get_type(ctx->async.private_data,
239 struct wbsrv_samba3_call);
240 int i, num_sids;
241 struct dom_sid **sids;
242 char *sids_string;
243 NTSTATUS status;
245 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
246 if (!NT_STATUS_IS_OK(status)) goto done;
248 sids_string = talloc_strdup(s3call, "");
249 if (sids_string == NULL) {
250 status = NT_STATUS_NO_MEMORY;
251 goto done;
254 for (i=0; i<num_sids; i++) {
255 sids_string = talloc_asprintf_append(
256 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
259 if (sids_string == NULL) {
260 status = NT_STATUS_NO_MEMORY;
261 goto done;
264 s3call->response.result = WINBINDD_OK;
265 s3call->response.extra_data = sids_string;
266 s3call->response.length += strlen(sids_string)+1;
267 s3call->response.data.num_entries = num_sids;
269 done:
270 wbsrv_samba3_async_epilogue(status, s3call);
274 Lookup the list of SIDs for a user
276 static void usersids_recv_sids(struct composite_context *ctx);
278 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
280 struct composite_context *ctx;
281 struct dom_sid *sid;
283 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
285 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
286 if (sid == NULL) {
287 DEBUG(5, ("Could not parse sid %s\n",
288 s3call->request.data.sid));
289 return NT_STATUS_NO_MEMORY;
292 ctx = wb_cmd_usersids_send(
293 s3call, s3call->wbconn->listen_socket->service, sid);
294 NT_STATUS_HAVE_NO_MEMORY(ctx);
296 ctx->async.fn = usersids_recv_sids;
297 ctx->async.private_data = s3call;
298 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
299 return NT_STATUS_OK;
302 static void usersids_recv_sids(struct composite_context *ctx)
304 struct wbsrv_samba3_call *s3call =
305 talloc_get_type(ctx->async.private_data,
306 struct wbsrv_samba3_call);
307 int i, num_sids;
308 struct dom_sid **sids;
309 char *sids_string;
310 NTSTATUS status;
312 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
313 if (!NT_STATUS_IS_OK(status)) goto done;
315 sids_string = talloc_strdup(s3call, "");
316 if (sids_string == NULL) {
317 status = NT_STATUS_NO_MEMORY;
318 goto done;
321 for (i=0; i<num_sids; i++) {
322 sids_string = talloc_asprintf_append(
323 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
324 if (sids_string == NULL) {
325 status = NT_STATUS_NO_MEMORY;
326 goto done;
330 s3call->response.result = WINBINDD_OK;
331 s3call->response.extra_data = sids_string;
332 s3call->response.length += strlen(sids_string);
333 s3call->response.data.num_entries = num_sids;
335 /* Hmmmm. Nasty protocol -- who invented the zeros between the
336 * SIDs? Hmmm. Could have been me -- vl */
338 while (*sids_string != '\0') {
339 if ((*sids_string) == '\n') {
340 *sids_string = '\0';
342 sids_string += 1;
345 done:
346 wbsrv_samba3_async_epilogue(status, s3call);
350 Lookup a DOMAIN\\user style name, and return a SID
353 static void lookupname_recv_sid(struct composite_context *ctx);
355 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
357 struct composite_context *ctx;
358 struct wbsrv_service *service =
359 s3call->wbconn->listen_socket->service;
361 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
363 ctx = wb_cmd_lookupname_send(s3call, service,
364 s3call->request.data.name.dom_name,
365 s3call->request.data.name.name);
366 NT_STATUS_HAVE_NO_MEMORY(ctx);
368 /* setup the callbacks */
369 ctx->async.fn = lookupname_recv_sid;
370 ctx->async.private_data = s3call;
371 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
372 return NT_STATUS_OK;
375 static void lookupname_recv_sid(struct composite_context *ctx)
377 struct wbsrv_samba3_call *s3call =
378 talloc_get_type(ctx->async.private_data,
379 struct wbsrv_samba3_call);
380 struct wb_sid_object *sid;
381 NTSTATUS status;
383 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
384 if (!NT_STATUS_IS_OK(status)) goto done;
386 s3call->response.result = WINBINDD_OK;
387 s3call->response.data.sid.type = sid->type;
388 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
389 dom_sid_string(s3call, sid->sid));
391 done:
392 wbsrv_samba3_async_epilogue(status, s3call);
396 Lookup a SID, and return a DOMAIN\\user style name
399 static void lookupsid_recv_name(struct composite_context *ctx);
401 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
403 struct composite_context *ctx;
404 struct wbsrv_service *service =
405 s3call->wbconn->listen_socket->service;
406 struct dom_sid *sid;
408 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
410 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
411 if (sid == NULL) {
412 DEBUG(5, ("Could not parse sid %s\n",
413 s3call->request.data.sid));
414 return NT_STATUS_NO_MEMORY;
417 ctx = wb_cmd_lookupsid_send(s3call, service, sid);
418 NT_STATUS_HAVE_NO_MEMORY(ctx);
420 /* setup the callbacks */
421 ctx->async.fn = lookupsid_recv_name;
422 ctx->async.private_data = s3call;
423 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
424 return NT_STATUS_OK;
427 static void lookupsid_recv_name(struct composite_context *ctx)
429 struct wbsrv_samba3_call *s3call =
430 talloc_get_type(ctx->async.private_data,
431 struct wbsrv_samba3_call);
432 struct wb_sid_object *sid;
433 NTSTATUS status;
435 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
436 if (!NT_STATUS_IS_OK(status)) goto done;
438 s3call->response.result = WINBINDD_OK;
439 s3call->response.data.name.type = sid->type;
440 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
441 sid->domain);
442 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
444 done:
445 wbsrv_samba3_async_epilogue(status, s3call);
449 Challenge-response authentication. This interface is used by
450 ntlm_auth and the smbd auth subsystem to pass NTLM authentication
451 requests along a common pipe to the domain controller.
453 The return value (in the async reply) may include the 'info3'
454 (effectivly most things you would want to know about the user), or
455 the NT and LM session keys seperated.
458 static void pam_auth_crap_recv(struct composite_context *ctx);
460 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
462 struct composite_context *ctx;
463 struct wbsrv_service *service =
464 s3call->wbconn->listen_socket->service;
465 DATA_BLOB chal, nt_resp, lm_resp;
467 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
469 chal.data = s3call->request.data.auth_crap.chal;
470 chal.length = sizeof(s3call->request.data.auth_crap.chal);
471 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
472 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
473 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
474 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
476 ctx = wb_cmd_pam_auth_crap_send(
477 s3call, service,
478 s3call->request.data.auth_crap.logon_parameters,
479 s3call->request.data.auth_crap.domain,
480 s3call->request.data.auth_crap.user,
481 s3call->request.data.auth_crap.workstation,
482 chal, nt_resp, lm_resp);
483 NT_STATUS_HAVE_NO_MEMORY(ctx);
485 ctx->async.fn = pam_auth_crap_recv;
486 ctx->async.private_data = s3call;
487 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
488 return NT_STATUS_OK;
491 static void pam_auth_crap_recv(struct composite_context *ctx)
493 struct wbsrv_samba3_call *s3call =
494 talloc_get_type(ctx->async.private_data,
495 struct wbsrv_samba3_call);
496 NTSTATUS status;
497 DATA_BLOB info3;
498 struct netr_UserSessionKey user_session_key;
499 struct netr_LMSessionKey lm_key;
500 char *unix_username;
502 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
503 &user_session_key, &lm_key, &unix_username);
504 if (!NT_STATUS_IS_OK(status)) goto done;
506 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
507 memcpy(s3call->response.data.auth.user_session_key,
508 &user_session_key.key,
509 sizeof(s3call->response.data.auth.user_session_key));
512 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
513 s3call->response.extra_data = info3.data;
514 s3call->response.length += info3.length;
517 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
518 memcpy(s3call->response.data.auth.first_8_lm_hash,
519 lm_key.key,
520 sizeof(s3call->response.data.auth.first_8_lm_hash));
523 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
524 s3call->response.extra_data = unix_username;
525 s3call->response.length += strlen(unix_username)+1;
528 done:
529 wbsrv_samba3_async_auth_epilogue(status, s3call);
532 /* Helper function: Split a domain\\user string into it's parts,
533 * because the client supplies it as one string */
535 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
536 char **domain, char **user)
538 char *p = strchr(domuser, *lp_winbind_separator());
540 if (p == NULL) {
541 *domain = talloc_strdup(mem_ctx, lp_workgroup());
542 } else {
543 *domain = talloc_strndup(mem_ctx, domuser,
544 PTR_DIFF(p, domuser));
545 domuser = p+1;
548 *user = talloc_strdup(mem_ctx, domuser);
550 return ((*domain != NULL) && (*user != NULL));
553 /* Plaintext authentication
555 This interface is used by ntlm_auth in it's 'basic' authentication
556 mode, as well as by pam_winbind to authenticate users where we are
557 given a plaintext password.
560 static void pam_auth_recv(struct composite_context *ctx);
562 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
564 struct composite_context *ctx;
565 struct wbsrv_service *service =
566 s3call->wbconn->listen_socket->service;
567 char *user, *domain;
569 if (!samba3_parse_domuser(s3call,
570 s3call->request.data.auth.user,
571 &domain, &user)) {
572 return NT_STATUS_NO_SUCH_USER;
575 ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
576 s3call->request.data.auth.pass);
577 NT_STATUS_HAVE_NO_MEMORY(ctx);
579 ctx->async.fn = pam_auth_recv;
580 ctx->async.private_data = s3call;
581 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
582 return NT_STATUS_OK;
585 static void pam_auth_recv(struct composite_context *ctx)
587 struct wbsrv_samba3_call *s3call =
588 talloc_get_type(ctx->async.private_data,
589 struct wbsrv_samba3_call);
590 NTSTATUS status;
592 status = wb_cmd_pam_auth_recv(ctx);
594 if (!NT_STATUS_IS_OK(status)) goto done;
596 done:
597 wbsrv_samba3_async_auth_epilogue(status, s3call);
601 List trusted domains
604 static void list_trustdom_recv_doms(struct composite_context *ctx);
606 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
608 struct composite_context *ctx;
609 struct wbsrv_service *service =
610 s3call->wbconn->listen_socket->service;
612 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
614 ctx = wb_cmd_list_trustdoms_send(s3call, service);
615 NT_STATUS_HAVE_NO_MEMORY(ctx);
617 ctx->async.fn = list_trustdom_recv_doms;
618 ctx->async.private_data = s3call;
619 s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
620 return NT_STATUS_OK;
623 static void list_trustdom_recv_doms(struct composite_context *ctx)
625 struct wbsrv_samba3_call *s3call =
626 talloc_get_type(ctx->async.private_data,
627 struct wbsrv_samba3_call);
628 int i, num_domains;
629 struct wb_dom_info **domains;
630 NTSTATUS status;
631 char *result;
633 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
634 &domains);
635 if (!NT_STATUS_IS_OK(status)) goto done;
637 result = talloc_strdup(s3call, "");
638 if (result == NULL) {
639 status = NT_STATUS_NO_MEMORY;
640 goto done;
643 for (i=0; i<num_domains; i++) {
644 result = talloc_asprintf_append(
645 result, "%s\\%s\\%s",
646 domains[i]->name, domains[i]->name,
647 dom_sid_string(s3call, domains[i]->sid));
650 if (result == NULL) {
651 status = NT_STATUS_NO_MEMORY;
652 goto done;
655 s3call->response.result = WINBINDD_OK;
656 if (num_domains > 0) {
657 s3call->response.extra_data = result;
658 s3call->response.length += strlen(result)+1;
661 done:
662 wbsrv_samba3_async_epilogue(status, s3call);