2 Unix SMB/CIFS implementation.
3 Main winbindd samba3 server routines
5 Copyright (C) Stefan Metzmacher 2005
6 Copyright (C) Volker Lendecke 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "smbd/service_stream.h"
25 #include "nsswitch/winbind_nss_config.h"
26 #include "nsswitch/winbindd_nss.h"
27 #include "winbind/wb_server.h"
28 #include "winbind/wb_samba3_protocol.h"
29 #include "winbind/wb_async_helpers.h"
30 #include "librpc/gen_ndr/nbt.h"
31 #include "libcli/raw/libcliraw.h"
32 #include "libcli/composite/composite.h"
33 #include "libcli/smb_composite/smb_composite.h"
34 #include "include/version.h"
35 #include "lib/events/events.h"
36 #include "librpc/gen_ndr/ndr_netlogon.h"
38 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
39 struct wbsrv_samba3_call *s3call)
41 if (!NT_STATUS_IS_OK(status)) {
42 struct winbindd_response *resp = &s3call->response;
43 resp->result = WINBINDD_ERROR;
44 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
46 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
48 resp->data.auth.pam_error = nt_status_to_pam(status);
51 status = wbsrv_send_reply(s3call->call);
52 if (!NT_STATUS_IS_OK(status)) {
53 wbsrv_terminate_connection(s3call->call->wbconn,
54 "wbsrv_queue_reply() failed");
58 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
60 s3call->response.result = WINBINDD_OK;
61 s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
65 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
67 s3call->response.result = WINBINDD_OK;
68 s3call->response.data.info.winbind_separator = *lp_winbind_separator();
69 WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
70 SAMBA_VERSION_STRING);
74 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
76 s3call->response.result = WINBINDD_OK;
77 WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
82 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
84 s3call->response.result = WINBINDD_OK;
85 WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
90 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
92 s3call->response.result = WINBINDD_OK;
93 s3call->response.extra_data =
94 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
95 NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
99 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
101 s3call->response.result = WINBINDD_OK;
105 static void checkmachacc_recv_creds(struct composite_context *ctx);
107 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
109 struct composite_context *ctx;
111 DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
113 ctx = wb_cmd_checkmachacc_send(s3call->call);
114 NT_STATUS_HAVE_NO_MEMORY(ctx);
116 ctx->async.fn = checkmachacc_recv_creds;
117 ctx->async.private_data = s3call;
118 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
122 static void checkmachacc_recv_creds(struct composite_context *ctx)
124 struct wbsrv_samba3_call *s3call =
125 talloc_get_type(ctx->async.private_data,
126 struct wbsrv_samba3_call);
129 status = wb_cmd_checkmachacc_recv(ctx);
131 s3call->response.result = WINBINDD_OK;
132 wbsrv_samba3_async_epilogue(status, s3call);
135 static void getdcname_recv_dc(struct composite_context *ctx);
137 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
139 struct composite_context *ctx;
140 struct wbsrv_service *service =
141 s3call->call->wbconn->listen_socket->service;
143 DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
145 ctx = wb_cmd_getdcname_send(service, service->domains,
146 s3call->request.domain_name);
147 NT_STATUS_HAVE_NO_MEMORY(ctx);
149 ctx->async.fn = getdcname_recv_dc;
150 ctx->async.private_data = s3call;
151 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
155 static void getdcname_recv_dc(struct composite_context *ctx)
157 struct wbsrv_samba3_call *s3call =
158 talloc_get_type(ctx->async.private_data,
159 struct wbsrv_samba3_call);
163 status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
164 if (!NT_STATUS_IS_OK(status)) goto done;
166 s3call->response.result = WINBINDD_OK;
167 WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
170 wbsrv_samba3_async_epilogue(status, s3call);
173 static void userdomgroups_recv_groups(struct composite_context *ctx);
175 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
177 struct composite_context *ctx;
180 DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
182 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
184 DEBUG(5, ("Could not parse sid %s\n",
185 s3call->request.data.sid));
186 return NT_STATUS_NO_MEMORY;
189 ctx = wb_cmd_userdomgroups_send(
190 s3call->call->wbconn->listen_socket->service, sid);
191 NT_STATUS_HAVE_NO_MEMORY(ctx);
193 ctx->async.fn = userdomgroups_recv_groups;
194 ctx->async.private_data = s3call;
195 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
199 static void userdomgroups_recv_groups(struct composite_context *ctx)
201 struct wbsrv_samba3_call *s3call =
202 talloc_get_type(ctx->async.private_data,
203 struct wbsrv_samba3_call);
205 struct dom_sid **sids;
209 status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
210 if (!NT_STATUS_IS_OK(status)) goto done;
212 sids_string = talloc_strdup(s3call, "");
213 if (sids_string == NULL) {
214 status = NT_STATUS_NO_MEMORY;
218 for (i=0; i<num_sids; i++) {
219 sids_string = talloc_asprintf_append(
220 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
223 if (sids_string == NULL) {
224 status = NT_STATUS_NO_MEMORY;
228 s3call->response.result = WINBINDD_OK;
229 s3call->response.extra_data = sids_string;
230 s3call->response.length += strlen(sids_string)+1;
231 s3call->response.data.num_entries = num_sids;
234 wbsrv_samba3_async_epilogue(status, s3call);
237 static void usersids_recv_sids(struct composite_context *ctx);
239 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
241 struct composite_context *ctx;
244 DEBUG(5, ("wbsrv_samba3_usersids called\n"));
246 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
248 DEBUG(5, ("Could not parse sid %s\n",
249 s3call->request.data.sid));
250 return NT_STATUS_NO_MEMORY;
253 ctx = wb_cmd_usersids_send(
254 s3call->call->wbconn->listen_socket->service, sid);
255 NT_STATUS_HAVE_NO_MEMORY(ctx);
257 ctx->async.fn = usersids_recv_sids;
258 ctx->async.private_data = s3call;
259 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
263 static void usersids_recv_sids(struct composite_context *ctx)
265 struct wbsrv_samba3_call *s3call =
266 talloc_get_type(ctx->async.private_data,
267 struct wbsrv_samba3_call);
269 struct dom_sid **sids;
273 status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
274 if (!NT_STATUS_IS_OK(status)) goto done;
276 sids_string = talloc_strdup(s3call, "");
277 if (sids_string == NULL) {
278 status = NT_STATUS_NO_MEMORY;
282 for (i=0; i<num_sids; i++) {
283 sids_string = talloc_asprintf_append(
284 sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
285 if (sids_string == NULL) {
286 status = NT_STATUS_NO_MEMORY;
291 s3call->response.result = WINBINDD_OK;
292 s3call->response.extra_data = sids_string;
293 s3call->response.length += strlen(sids_string);
294 s3call->response.data.num_entries = num_sids;
296 /* Hmmmm. Nasty protocol -- who invented the zeros between the
297 * SIDs? Hmmm. Could have been me -- vl */
299 while (*sids_string != '\0') {
300 if ((*sids_string) == '\n') {
307 wbsrv_samba3_async_epilogue(status, s3call);
310 static void lookupname_recv_sid(struct composite_context *ctx);
312 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
314 struct composite_context *ctx;
315 struct wbsrv_service *service =
316 s3call->call->wbconn->listen_socket->service;
318 DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
320 ctx = wb_cmd_lookupname_send(service, service->domains,
321 s3call->request.data.name.dom_name,
322 s3call->request.data.name.name);
323 NT_STATUS_HAVE_NO_MEMORY(ctx);
325 /* setup the callbacks */
326 ctx->async.fn = lookupname_recv_sid;
327 ctx->async.private_data = s3call;
328 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
332 static void lookupname_recv_sid(struct composite_context *ctx)
334 struct wbsrv_samba3_call *s3call =
335 talloc_get_type(ctx->async.private_data,
336 struct wbsrv_samba3_call);
337 struct wb_sid_object *sid;
340 status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
341 if (!NT_STATUS_IS_OK(status)) goto done;
343 s3call->response.result = WINBINDD_OK;
344 s3call->response.data.sid.type = sid->type;
345 WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
346 dom_sid_string(s3call, sid->sid));
349 wbsrv_samba3_async_epilogue(status, s3call);
352 static void lookupsid_recv_name(struct composite_context *ctx);
354 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
356 struct composite_context *ctx;
357 struct wbsrv_service *service =
358 s3call->call->wbconn->listen_socket->service;
361 DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
363 sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
365 DEBUG(5, ("Could not parse sid %s\n",
366 s3call->request.data.sid));
367 return NT_STATUS_NO_MEMORY;
370 ctx = wb_cmd_lookupsid_send(service, service->domains, sid);
371 NT_STATUS_HAVE_NO_MEMORY(ctx);
373 /* setup the callbacks */
374 ctx->async.fn = lookupsid_recv_name;
375 ctx->async.private_data = s3call;
376 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
380 static void lookupsid_recv_name(struct composite_context *ctx)
382 struct wbsrv_samba3_call *s3call =
383 talloc_get_type(ctx->async.private_data,
384 struct wbsrv_samba3_call);
385 struct wb_sid_object *sid;
388 status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
389 if (!NT_STATUS_IS_OK(status)) goto done;
391 s3call->response.result = WINBINDD_OK;
392 s3call->response.data.name.type = sid->type;
393 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
395 WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
398 wbsrv_samba3_async_epilogue(status, s3call);
401 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
403 s3call->response.result = WINBINDD_ERROR;
408 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
409 char **domain, char **user)
411 char *p = strchr(domuser, *lp_winbind_separator());
414 *domain = talloc_strdup(mem_ctx, lp_workgroup());
416 *domain = talloc_strndup(mem_ctx, domuser,
417 PTR_DIFF(p, domuser));
421 *user = talloc_strdup(mem_ctx, domuser);
423 return ((*domain != NULL) && (*user != NULL));
427 static void pam_auth_crap_recv(struct composite_context *ctx);
429 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
431 struct composite_context *ctx;
433 DATA_BLOB chal, nt_resp, lm_resp;
435 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
437 chal.data = s3call->request.data.auth_crap.chal;
438 chal.length = sizeof(s3call->request.data.auth_crap.chal);
439 nt_resp.data = s3call->request.data.auth_crap.nt_resp;
440 nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
441 lm_resp.data = s3call->request.data.auth_crap.lm_resp;
442 lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
444 ctx = wb_cmd_pam_auth_crap_send(
446 s3call->request.data.auth_crap.domain,
447 s3call->request.data.auth_crap.user,
448 s3call->request.data.auth_crap.workstation,
449 chal, nt_resp, lm_resp);
450 NT_STATUS_HAVE_NO_MEMORY(ctx);
452 ctx->async.fn = pam_auth_crap_recv;
453 ctx->async.private_data = s3call;
454 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
458 static void pam_auth_crap_recv(struct composite_context *ctx)
460 struct wbsrv_samba3_call *s3call =
461 talloc_get_type(ctx->async.private_data,
462 struct wbsrv_samba3_call);
463 struct winbindd_response *resp = &s3call->response;
466 struct netr_UserSessionKey user_session_key;
467 struct netr_LMSessionKey lm_key;
469 status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
470 &user_session_key, &lm_key);
471 if (!NT_STATUS_IS_OK(status)) goto done;
473 if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
474 memcpy(s3call->response.data.auth.user_session_key,
475 &user_session_key.key,
476 sizeof(s3call->response.data.auth.user_session_key));
479 if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
480 s3call->response.extra_data = info3.data;
481 s3call->response.length += info3.length;
484 if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
485 memcpy(s3call->response.data.auth.first_8_lm_hash,
487 sizeof(s3call->response.data.auth.first_8_lm_hash));
490 resp->result = WINBINDD_OK;
493 wbsrv_samba3_async_epilogue(status, s3call);
496 static void list_trustdom_recv_doms(struct composite_context *ctx);
498 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
500 struct composite_context *ctx;
501 struct wbsrv_service *service =
502 s3call->call->wbconn->listen_socket->service;
504 DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
506 ctx = wb_cmd_list_trustdoms_send(service);
507 NT_STATUS_HAVE_NO_MEMORY(ctx);
509 ctx->async.fn = list_trustdom_recv_doms;
510 ctx->async.private_data = s3call;
511 s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
515 static void list_trustdom_recv_doms(struct composite_context *ctx)
517 struct wbsrv_samba3_call *s3call =
518 talloc_get_type(ctx->async.private_data,
519 struct wbsrv_samba3_call);
521 struct wb_dom_info **domains;
525 status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
527 if (!NT_STATUS_IS_OK(status)) goto done;
529 result = talloc_strdup(s3call, "");
530 if (result == NULL) {
531 status = NT_STATUS_NO_MEMORY;
535 for (i=0; i<num_domains; i++) {
536 result = talloc_asprintf_append(
537 result, "%s\\%s\\%s",
538 domains[i]->name, domains[i]->name,
539 dom_sid_string(s3call, domains[i]->sid));
542 if (result == NULL) {
543 status = NT_STATUS_NO_MEMORY;
547 s3call->response.result = WINBINDD_OK;
548 if (num_domains > 0) {
549 s3call->response.extra_data = result;
550 s3call->response.length += strlen(result)+1;
554 wbsrv_samba3_async_epilogue(status, s3call);