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 "smbd/service_stream.h"
26 #include "nsswitch/winbind_nss_config.h"
27 #include "nsswitch/winbindd_nss.h"
28 #include "winbind/wb_server.h"
29 #include "winbind/wb_samba3_protocol.h"
30 #include "winbind/wb_async_helpers.h"
31 #include "librpc/gen_ndr/nbt.h"
32 #include "libcli/raw/libcliraw.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "include/version.h"
36 #include "lib/events/events.h"
37 #include "librpc/gen_ndr/ndr_netlogon.h"
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 status = wbsrv_send_reply(s3call->call);
57 if (!NT_STATUS_IS_OK(status)) {
58 wbsrv_terminate_connection(s3call->call->wbconn,
59 "wbsrv_queue_reply() failed");
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 status = wbsrv_send_reply(s3call->call);
74 if (!NT_STATUS_IS_OK(status)) {
75 wbsrv_terminate_connection(s3call->call->wbconn,
76 "wbsrv_queue_reply() failed");
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;
127 static void checkmachacc_recv_creds(struct composite_context *ctx);
129 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
131 struct composite_context *ctx;
133 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
135 ctx = wb_cmd_checkmachacc_send(s3call->call);
136 NT_STATUS_HAVE_NO_MEMORY(ctx);
138 ctx->async.fn = checkmachacc_recv_creds;
139 ctx->async.private_data = s3call;
140 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
144 static void checkmachacc_recv_creds(struct composite_context *ctx)
146 struct wbsrv_samba3_call *s3call =
147 talloc_get_type(ctx->async.private_data,
148 struct wbsrv_samba3_call);
151 status = wb_cmd_checkmachacc_recv(ctx);
153 wbsrv_samba3_async_auth_epilogue(status, s3call);
156 static void getdcname_recv_dc(struct composite_context *ctx);
158 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
160 struct composite_context *ctx;
161 struct wbsrv_service *service =
162 s3call->call->wbconn->listen_socket->service;
164 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
166 ctx = wb_cmd_getdcname_send(service, service->domains,
167 s3call->request.domain_name);
168 NT_STATUS_HAVE_NO_MEMORY(ctx);
170 ctx->async.fn = getdcname_recv_dc;
171 ctx->async.private_data = s3call;
172 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
176 static void getdcname_recv_dc(struct composite_context *ctx)
178 struct wbsrv_samba3_call *s3call =
179 talloc_get_type(ctx->async.private_data,
180 struct wbsrv_samba3_call);
184 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
185 if (!NT_STATUS_IS_OK(status)) goto done;
187 s3call->response.result = WINBINDD_OK;
188 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
191 wbsrv_samba3_async_epilogue(status, s3call);
194 static void userdomgroups_recv_groups(struct composite_context *ctx);
196 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
198 struct composite_context *ctx;
201 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
203 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
205 DEBUG(5, ("Could not parse sid %s\n",
206 s3call->request.data.sid));
207 return NT_STATUS_NO_MEMORY;
210 ctx = wb_cmd_userdomgroups_send(
211 s3call->call->wbconn->listen_socket->service, sid);
212 NT_STATUS_HAVE_NO_MEMORY(ctx);
214 ctx->async.fn = userdomgroups_recv_groups;
215 ctx->async.private_data = s3call;
216 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
220 static void userdomgroups_recv_groups(struct composite_context *ctx)
222 struct wbsrv_samba3_call *s3call =
223 talloc_get_type(ctx->async.private_data,
224 struct wbsrv_samba3_call);
226 struct dom_sid **sids;
230 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
231 if (!NT_STATUS_IS_OK(status)) goto done;
233 sids_string = talloc_strdup(s3call, "");
234 if (sids_string == NULL) {
235 status = NT_STATUS_NO_MEMORY;
239 for (i=0; i<num_sids; i++) {
240 sids_string = talloc_asprintf_append(
241 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
244 if (sids_string == NULL) {
245 status = NT_STATUS_NO_MEMORY;
249 s3call->response.result = WINBINDD_OK;
250 s3call->response.extra_data = sids_string;
251 s3call->response.length += strlen(sids_string)+1;
252 s3call->response.data.num_entries = num_sids;
255 wbsrv_samba3_async_epilogue(status, s3call);
258 static void usersids_recv_sids(struct composite_context *ctx);
260 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
262 struct composite_context *ctx;
265 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
267 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
269 DEBUG(5, ("Could not parse sid %s\n",
270 s3call->request.data.sid));
271 return NT_STATUS_NO_MEMORY;
274 ctx = wb_cmd_usersids_send(
275 s3call->call->wbconn->listen_socket->service, sid);
276 NT_STATUS_HAVE_NO_MEMORY(ctx);
278 ctx->async.fn = usersids_recv_sids;
279 ctx->async.private_data = s3call;
280 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
284 static void usersids_recv_sids(struct composite_context *ctx)
286 struct wbsrv_samba3_call *s3call =
287 talloc_get_type(ctx->async.private_data,
288 struct wbsrv_samba3_call);
290 struct dom_sid **sids;
294 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
295 if (!NT_STATUS_IS_OK(status)) goto done;
297 sids_string = talloc_strdup(s3call, "");
298 if (sids_string == NULL) {
299 status = NT_STATUS_NO_MEMORY;
303 for (i=0; i<num_sids; i++) {
304 sids_string = talloc_asprintf_append(
305 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
306 if (sids_string == NULL) {
307 status = NT_STATUS_NO_MEMORY;
312 s3call->response.result = WINBINDD_OK;
313 s3call->response.extra_data = sids_string;
314 s3call->response.length += strlen(sids_string);
315 s3call->response.data.num_entries = num_sids;
317 /* Hmmmm. Nasty protocol -- who invented the zeros between the
318 * SIDs? Hmmm. Could have been me -- vl */
320 while (*sids_string != '\0') {
321 if ((*sids_string) == '\n') {
328 wbsrv_samba3_async_epilogue(status, s3call);
331 static void lookupname_recv_sid(struct composite_context *ctx);
333 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
335 struct composite_context *ctx;
336 struct wbsrv_service *service =
337 s3call->call->wbconn->listen_socket->service;
339 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
341 ctx = wb_cmd_lookupname_send(service, service->domains,
342 s3call->request.data.name.dom_name,
343 s3call->request.data.name.name);
344 NT_STATUS_HAVE_NO_MEMORY(ctx);
346 /* setup the callbacks */
347 ctx->async.fn = lookupname_recv_sid;
348 ctx->async.private_data = s3call;
349 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
353 static void lookupname_recv_sid(struct composite_context *ctx)
355 struct wbsrv_samba3_call *s3call =
356 talloc_get_type(ctx->async.private_data,
357 struct wbsrv_samba3_call);
358 struct wb_sid_object *sid;
361 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
362 if (!NT_STATUS_IS_OK(status)) goto done;
364 s3call->response.result = WINBINDD_OK;
365 s3call->response.data.sid.type = sid->type;
366 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
367 dom_sid_string(s3call, sid->sid));
370 wbsrv_samba3_async_epilogue(status, s3call);
373 static void lookupsid_recv_name(struct composite_context *ctx);
375 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
377 struct composite_context *ctx;
378 struct wbsrv_service *service =
379 s3call->call->wbconn->listen_socket->service;
382 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
384 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
386 DEBUG(5, ("Could not parse sid %s\n",
387 s3call->request.data.sid));
388 return NT_STATUS_NO_MEMORY;
391 ctx = wb_cmd_lookupsid_send(service, service->domains, sid);
392 NT_STATUS_HAVE_NO_MEMORY(ctx);
394 /* setup the callbacks */
395 ctx->async.fn = lookupsid_recv_name;
396 ctx->async.private_data = s3call;
397 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
401 static void lookupsid_recv_name(struct composite_context *ctx)
403 struct wbsrv_samba3_call *s3call =
404 talloc_get_type(ctx->async.private_data,
405 struct wbsrv_samba3_call);
406 struct wb_sid_object *sid;
409 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
410 if (!NT_STATUS_IS_OK(status)) goto done;
412 s3call->response.result = WINBINDD_OK;
413 s3call->response.data.name.type = sid->type;
414 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
416 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
419 wbsrv_samba3_async_epilogue(status, s3call);
422 static void pam_auth_crap_recv(struct composite_context *ctx);
424 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
426 struct composite_context *ctx;
427 DATA_BLOB chal, nt_resp, lm_resp;
429 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
431 chal.data = s3call->request.data.auth_crap.chal;
432 chal.length = sizeof(s3call->request.data.auth_crap.chal);
433 nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
434 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
435 lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
436 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
438 ctx = wb_cmd_pam_auth_crap_send(
440 s3call->request.data.auth_crap.logon_parameters,
441 s3call->request.data.auth_crap.domain,
442 s3call->request.data.auth_crap.user,
443 s3call->request.data.auth_crap.workstation,
444 chal, nt_resp, lm_resp);
445 NT_STATUS_HAVE_NO_MEMORY(ctx);
447 ctx->async.fn = pam_auth_crap_recv;
448 ctx->async.private_data = s3call;
449 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
453 static void pam_auth_crap_recv(struct composite_context *ctx)
455 struct wbsrv_samba3_call *s3call =
456 talloc_get_type(ctx->async.private_data,
457 struct wbsrv_samba3_call);
460 struct netr_UserSessionKey user_session_key;
461 struct netr_LMSessionKey lm_key;
464 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
465 &user_session_key, &lm_key, &unix_username);
466 if (!NT_STATUS_IS_OK(status)) goto done;
468 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
469 memcpy(s3call->response.data.auth.user_session_key,
470 &user_session_key.key,
471 sizeof(s3call->response.data.auth.user_session_key));
474 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
475 s3call->response.extra_data = info3.data;
476 s3call->response.length += info3.length;
479 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
480 memcpy(s3call->response.data.auth.first_8_lm_hash,
482 sizeof(s3call->response.data.auth.first_8_lm_hash));
485 if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
486 s3call->response.extra_data = unix_username;
487 s3call->response.length += strlen(unix_username)+1;
491 wbsrv_samba3_async_auth_epilogue(status, s3call);
494 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
495 char **domain, char **user)
497 char *p = strchr(domuser, *lp_winbind_separator());
500 *domain = talloc_strdup(mem_ctx, lp_workgroup());
502 *domain = talloc_strndup(mem_ctx, domuser,
503 PTR_DIFF(p, domuser));
507 *user = talloc_strdup(mem_ctx, domuser);
509 return ((*domain != NULL) && (*user != NULL));
512 static void pam_auth_recv(struct composite_context *ctx);
514 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
516 struct composite_context *ctx;
518 if (!samba3_parse_domuser(s3call,
519 s3call->request.data.auth.user,
521 return NT_STATUS_NO_SUCH_USER;
524 ctx = wb_cmd_pam_auth_send(
525 s3call->call, domain, user,
526 s3call->request.data.auth.pass);
527 NT_STATUS_HAVE_NO_MEMORY(ctx);
529 ctx->async.fn = pam_auth_recv;
530 ctx->async.private_data = s3call;
531 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
535 static void pam_auth_recv(struct composite_context *ctx)
537 struct wbsrv_samba3_call *s3call =
538 talloc_get_type(ctx->async.private_data,
539 struct wbsrv_samba3_call);
542 status = wb_cmd_pam_auth_recv(ctx);
544 if (!NT_STATUS_IS_OK(status)) goto done;
547 wbsrv_samba3_async_auth_epilogue(status, s3call);
550 static void list_trustdom_recv_doms(struct composite_context *ctx);
552 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
554 struct composite_context *ctx;
555 struct wbsrv_service *service =
556 s3call->call->wbconn->listen_socket->service;
558 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
560 ctx = wb_cmd_list_trustdoms_send(service);
561 NT_STATUS_HAVE_NO_MEMORY(ctx);
563 ctx->async.fn = list_trustdom_recv_doms;
564 ctx->async.private_data = s3call;
565 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
569 static void list_trustdom_recv_doms(struct composite_context *ctx)
571 struct wbsrv_samba3_call *s3call =
572 talloc_get_type(ctx->async.private_data,
573 struct wbsrv_samba3_call);
575 struct wb_dom_info **domains;
579 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
581 if (!NT_STATUS_IS_OK(status)) goto done;
583 result = talloc_strdup(s3call, "");
584 if (result == NULL) {
585 status = NT_STATUS_NO_MEMORY;
589 for (i=0; i<num_domains; i++) {
590 result = talloc_asprintf_append(
591 result, "%s\\%s\\%s",
592 domains[i]->name, domains[i]->name,
593 dom_sid_string(s3call, domains[i]->sid));
596 if (result == NULL) {
597 status = NT_STATUS_NO_MEMORY;
601 s3call->response.result = WINBINDD_OK;
602 if (num_domains > 0) {
603 s3call->response.extra_data = result;
604 s3call->response.length += strlen(result)+1;
608 wbsrv_samba3_async_epilogue(status, s3call);