summaryrefslogtreecommitdiff
path: root/source4/winbind
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2005-10-03 13:46:11 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:39:18 -0500
commite5c6a3e36147103e87d1c55173f4b54ba6134904 (patch)
treeb50938eff14034f7b6db53caf76dd2cd9e8cd10c /source4/winbind
parent28bc38de2ab3a408702cd7d6b69d6549a1fea71a (diff)
downloadsamba-e5c6a3e36147103e87d1c55173f4b54ba6134904.tar.gz
samba-e5c6a3e36147103e87d1c55173f4b54ba6134904.tar.bz2
samba-e5c6a3e36147103e87d1c55173f4b54ba6134904.zip
r10683: Samba3's wbinfo -t should give the correct answer now.
Tridge, if you have time, you might want to look at the segfault I was still seeing. Now I store the handle to the netlogon pipe in the global winbind state and free it on the next entry into check_machacc. The problem seems to be that talloc_free()ing a pipe struct from within a callback function on that pipe is not possible. I think I can live with that, but it has been not really obvious. To reproduce the segfault you might want to look at putting a talloc_free(state->getcreds->out.netlogon) into wbsrv_samba3_check_machacc_receive_creds. This is called from a dcerpc callback function. In particular if the check failed it would be nice if I could delete the pipe directly and not post a different event to some winbind queue. I tried to delete the pipe from a timed event triggered immediately, but this also fails because the inner loop seems to hit the same event again, calling it twice. Volker (This used to be commit 5436d7764812bb632ba865e633005ed07923b57f)
Diffstat (limited to 'source4/winbind')
-rw-r--r--source4/winbind/wb_async_helpers.c224
-rw-r--r--source4/winbind/wb_async_helpers.h10
-rw-r--r--source4/winbind/wb_samba3_cmd.c177
-rw-r--r--source4/winbind/wb_server.h1
4 files changed, 363 insertions, 49 deletions
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
index a802f0e45e..7d7d2b6929 100644
--- a/source4/winbind/wb_async_helpers.c
+++ b/source4/winbind/wb_async_helpers.c
@@ -30,6 +30,10 @@
#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/irpc.h"
#include "librpc/gen_ndr/ndr_irpc.h"
+#include "libcli/raw/libcliraw.h"
+#include "librpc/rpc/dcerpc_composite.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "libcli/auth/credentials.h"
struct finddcs_state {
struct wb_finddcs *io;
@@ -164,7 +168,6 @@ struct composite_context *wb_finddcs_send(struct wb_finddcs *io,
state = talloc(c, struct finddcs_state);
if (state == NULL) goto failed;
-
state->io = io;
make_nbt_name(&name, io->in.domain, 0x1c);
@@ -204,3 +207,222 @@ NTSTATUS wb_finddcs(struct wb_finddcs *io, TALLOC_CTX *mem_ctx,
struct composite_context *c = wb_finddcs_send(io, ev);
return wb_finddcs_recv(c, mem_ctx);
}
+
+struct get_schannel_creds_state {
+ struct composite_context *ctx;
+ struct dcerpc_pipe *p;
+ struct wb_get_schannel_creds *io;
+ struct netr_ServerReqChallenge *r;
+
+ struct creds_CredentialState creds_state;
+ struct netr_Credential netr_cred;
+ uint32_t negotiate_flags;
+ struct netr_ServerAuthenticate2 *a;
+};
+
+static void get_schannel_creds_recv_auth(struct rpc_request *req);
+static void get_schannel_creds_recv_chal(struct rpc_request *req);
+static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
+
+struct composite_context *wb_get_schannel_creds_send(struct wb_get_schannel_creds *io,
+ struct event_context *ev)
+{
+ struct composite_context *result, *ctx;
+ struct get_schannel_creds_state *state;
+
+ result = talloc_zero(NULL, struct composite_context);
+ if (result == NULL) goto failed;
+ result->state = COMPOSITE_STATE_IN_PROGRESS;
+ result->event_ctx = ev;
+
+ state = talloc(result, struct get_schannel_creds_state);
+ if (state == NULL) goto failed;
+ result->private_data = state;
+
+ state->io = io;
+
+ state->p = dcerpc_pipe_init(state, ev);
+ if (state->p == NULL) goto failed;
+
+ ctx = dcerpc_pipe_open_smb_send(state->p->conn, state->io->in.tree,
+ "\\netlogon");
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = get_schannel_creds_recv_pipe;
+ ctx->async.private_data = state;
+ state->ctx = result;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void get_schannel_creds_recv_pipe(struct composite_context *ctx)
+{
+ struct get_schannel_creds_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct get_schannel_creds_state);
+ struct rpc_request *req;
+
+ state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+
+ state->ctx->status = dcerpc_bind_auth_none(state->p,
+ DCERPC_NETLOGON_UUID,
+ DCERPC_NETLOGON_VERSION);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+
+ state->r = talloc(state, struct netr_ServerReqChallenge);
+ if (state->r == NULL) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ state->r->in.computer_name =
+ cli_credentials_get_workstation(state->io->in.creds);
+ state->r->in.server_name =
+ talloc_asprintf(state->r, "\\\\%s",
+ dcerpc_server_name(state->p));
+ state->r->in.credentials = talloc(state->r, struct netr_Credential);
+ state->r->out.credentials = talloc(state->r, struct netr_Credential);
+
+ if ((state->r->in.server_name == NULL) ||
+ (state->r->in.credentials == NULL) ||
+ (state->r->out.credentials == NULL)) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ generate_random_buffer(state->r->in.credentials->data,
+ sizeof(state->r->in.credentials->data));
+
+ req = dcerpc_netr_ServerReqChallenge_send(state->p, state, state->r);
+ if (req == NULL) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req->async.callback = get_schannel_creds_recv_chal;
+ req->async.private = state;
+ return;
+
+ done:
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ state->ctx->state = COMPOSITE_STATE_ERROR;
+ }
+ if ((state->ctx->state >= COMPOSITE_STATE_DONE) &&
+ (state->ctx->async.fn != NULL)) {
+ state->ctx->async.fn(state->ctx);
+ }
+}
+
+static void get_schannel_creds_recv_chal(struct rpc_request *req)
+{
+ struct get_schannel_creds_state *state =
+ talloc_get_type(req->async.private,
+ struct get_schannel_creds_state);
+ const struct samr_Password *mach_pwd;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+ state->ctx->status = state->r->out.result;
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+
+ mach_pwd = cli_credentials_get_nt_hash(state->io->in.creds, state);
+ if (mach_pwd == NULL) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ state->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
+
+ creds_client_init(&state->creds_state, state->r->in.credentials,
+ state->r->out.credentials, mach_pwd,
+ &state->netr_cred, state->negotiate_flags);
+
+ state->a = talloc(state, struct netr_ServerAuthenticate2);
+ if (state->a == NULL) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ state->a->in.server_name =
+ talloc_reference(state->a, state->r->in.server_name);
+ state->a->in.account_name =
+ cli_credentials_get_username(state->io->in.creds);
+ state->a->in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(state->io->in.creds);
+ state->a->in.computer_name =
+ cli_credentials_get_workstation(state->io->in.creds);
+ state->a->in.negotiate_flags = &state->negotiate_flags;
+ state->a->out.negotiate_flags = &state->negotiate_flags;
+ state->a->in.credentials = &state->netr_cred;
+ state->a->out.credentials = &state->netr_cred;
+
+ req = dcerpc_netr_ServerAuthenticate2_send(state->p, state, state->a);
+ if (req == NULL) {
+ state->ctx->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req->async.callback = get_schannel_creds_recv_auth;
+ req->async.private = state;
+ return;
+
+ state->io->out.netlogon = state->p;
+ state->ctx->state = COMPOSITE_STATE_DONE;
+
+ done:
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ state->ctx->state = COMPOSITE_STATE_ERROR;
+ }
+ if ((state->ctx->state >= COMPOSITE_STATE_DONE) &&
+ (state->ctx->async.fn != NULL)) {
+ state->ctx->async.fn(state->ctx);
+ }
+}
+
+static void get_schannel_creds_recv_auth(struct rpc_request *req)
+{
+ struct get_schannel_creds_state *state =
+ talloc_get_type(req->async.private,
+ struct get_schannel_creds_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ DEBUG(5, ("result: %s\n", nt_errstr(state->ctx->status)));
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+ state->ctx->status = state->a->out.result;
+ DEBUG(5, ("result: %s\n", nt_errstr(state->ctx->status)));
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
+
+ state->ctx->state = COMPOSITE_STATE_DONE;
+
+ done:
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ state->ctx->state = COMPOSITE_STATE_ERROR;
+ }
+ if ((state->ctx->state >= COMPOSITE_STATE_DONE) &&
+ (state->ctx->async.fn != NULL)) {
+ state->ctx->async.fn(state->ctx);
+ }
+}
+
+NTSTATUS wb_get_schannel_creds_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status = composite_wait(c);
+ struct get_schannel_creds_state *state =
+ talloc_get_type(c->private_data,
+ struct get_schannel_creds_state);
+ state->io->out.netlogon = talloc_steal(mem_ctx, state->p);
+ talloc_free(c);
+ return status;
+}
+
+NTSTATUS wb_get_schannel_creds(struct wb_get_schannel_creds *io,
+ TALLOC_CTX *mem_ctx,
+ struct event_context *ev)
+{
+ struct composite_context *c = wb_get_schannel_creds_send(io, ev);
+ return wb_get_schannel_creds_recv(c, mem_ctx);
+}
diff --git a/source4/winbind/wb_async_helpers.h b/source4/winbind/wb_async_helpers.h
index 6c4f1d84a8..b37a66e972 100644
--- a/source4/winbind/wb_async_helpers.h
+++ b/source4/winbind/wb_async_helpers.h
@@ -34,3 +34,13 @@ struct wb_finddcs {
} *dcs;
} out;
};
+
+struct wb_get_schannel_creds {
+ struct {
+ struct cli_credentials *creds;
+ struct smbcli_tree *tree;
+ } in;
+ struct {
+ struct dcerpc_pipe *netlogon;
+ } out;
+};
diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c
index 7b3cd79cf4..570a166532 100644
--- a/source4/winbind/wb_samba3_cmd.c
+++ b/source4/winbind/wb_samba3_cmd.c
@@ -32,6 +32,8 @@
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
#include "include/version.h"
+#include "librpc/rpc/dcerpc_composite.h"
+#include "lib/events/events.h"
NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
{
@@ -77,46 +79,53 @@ NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
return NT_STATUS_OK;
}
+#define null_no_memory_done(x) do { \
+ if ((x) == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } \
+ } while (0)
+
struct check_machacc_state {
struct wb_finddcs *io;
struct smb_composite_connect *conn;
+ struct wb_get_schannel_creds *getcreds;
};
-static void wbsrv_samba3_check_machacc_receive_tree(struct composite_context *action)
+static void wbsrv_samba3_check_machacc_receive_creds(struct composite_context *action);
+static void wbsrv_samba3_check_machacc_receive_tree(struct composite_context *action);
+static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *action);
+
+NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
{
- struct wbsrv_samba3_call *s3call =
- talloc_get_type(action->async.private_data,
- struct wbsrv_samba3_call);
- struct check_machacc_state *state =
- talloc_get_type(s3call->private_data,
- struct check_machacc_state);
- NTSTATUS status;
+ struct composite_context *resolve_req;
+ struct check_machacc_state *state;
+ struct wbsrv_service *service =
+ s3call->call->wbconn->listen_socket->service;
- status = smb_composite_connect_recv(action, state);
- WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
- nt_errstr(status));
- WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
- nt_errstr(status));
- s3call->response.data.auth.pam_error = nt_status_to_pam(status);
+ DEBUG(5, ("check_machacc called\n"));
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5, ("Connect failed: %s\n", nt_errstr(status)));
- goto done;
+ if (service->netlogon != NULL) {
+ talloc_free(service->netlogon);
}
- s3call->response.result = WINBINDD_OK;
-
- done:
- if (!NT_STATUS_IS_OK(status)) {
- s3call->response.result = WINBINDD_ERROR;
- }
+ state = talloc(s3call, struct check_machacc_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
- status = wbsrv_send_reply(s3call->call);
- if (!NT_STATUS_IS_OK(status)) {
- wbsrv_terminate_connection(s3call->call->wbconn,
- "wbsrv_queue_reply() failed");
- return;
- }
+ state->io = talloc(s3call, struct wb_finddcs);
+ NT_STATUS_HAVE_NO_MEMORY(state->io);
+ s3call->private_data = state;
+
+ state->io->in.msg_ctx = s3call->call->wbconn->conn->msg_ctx;
+ state->io->in.domain = lp_workgroup();
+
+ resolve_req = wb_finddcs_send(state->io, s3call->call->event_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(resolve_req);
+
+ /* setup the callbacks */
+ resolve_req->async.fn = wbsrv_samba3_check_machacc_receive_dcs;
+ resolve_req->async.private_data = s3call;
+
+ /* tell the caller we reply later */
+ s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
}
static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *action)
@@ -188,31 +197,103 @@ static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *act
}
}
-NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
+static void wbsrv_samba3_check_machacc_receive_tree(struct composite_context *action)
{
- struct composite_context *resolve_req;
- struct check_machacc_state *state;
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(action->async.private_data,
+ struct wbsrv_samba3_call);
+ struct check_machacc_state *state =
+ talloc_get_type(s3call->private_data,
+ struct check_machacc_state);
+ struct composite_context *ctx;
+ NTSTATUS status;
+ struct cli_credentials *creds;
- DEBUG(5, ("check_machacc called\n"));
+ status = smb_composite_connect_recv(action, state);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Connect failed: %s\n", nt_errstr(status)));
+ goto done;
+ }
- state = talloc(s3call, struct check_machacc_state);
- NT_STATUS_HAVE_NO_MEMORY(state);
+ state->getcreds = talloc(state, struct wb_get_schannel_creds);
+ null_no_memory_done(state->getcreds);
- state->io = talloc(s3call, struct wb_finddcs);
- NT_STATUS_HAVE_NO_MEMORY(state->io);
- s3call->private_data = state;
+ creds = cli_credentials_init(state);
+ null_no_memory_done(creds);
+ cli_credentials_set_conf(creds);
+ status = cli_credentials_set_machine_account(creds);
+ if (!NT_STATUS_IS_OK(status)) goto done;
- state->io->in.msg_ctx = s3call->call->wbconn->conn->msg_ctx;
- state->io->in.domain = lp_workgroup();
+ state->getcreds->in.tree = state->conn->out.tree;
+ state->getcreds->in.creds = creds;
- resolve_req = wb_finddcs_send(state->io, s3call->call->event_ctx);
- NT_STATUS_HAVE_NO_MEMORY(resolve_req);
+ ctx = wb_get_schannel_creds_send(state->getcreds,
+ s3call->call->event_ctx);
+ null_no_memory_done(ctx);
- /* setup the callbacks */
- resolve_req->async.fn = wbsrv_samba3_check_machacc_receive_dcs;
- resolve_req->async.private_data = s3call;
+ ctx->async.fn = wbsrv_samba3_check_machacc_receive_creds;
+ ctx->async.private_data = s3call;
- /* tell the caller we reply later */
- s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
- return NT_STATUS_OK;
+ return;
+
+ done:
+ s3call->response.result = WINBINDD_OK;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ s3call->response.result = WINBINDD_ERROR;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
+ nt_errstr(status));
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
+ nt_errstr(status));
+ s3call->response.data.auth.pam_error = nt_status_to_pam(status);
+
+ }
+
+ status = wbsrv_send_reply(s3call->call);
+ if (!NT_STATUS_IS_OK(status)) {
+ wbsrv_terminate_connection(s3call->call->wbconn,
+ "wbsrv_queue_reply() failed");
+ return;
+ }
+}
+
+static void wbsrv_samba3_check_machacc_receive_creds(struct composite_context *action)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(action->async.private_data,
+ struct wbsrv_samba3_call);
+ struct check_machacc_state *state =
+ talloc_get_type(s3call->private_data,
+ struct check_machacc_state);
+ struct wbsrv_service *service =
+ s3call->call->wbconn->listen_socket->service;
+
+ NTSTATUS status;
+
+ status = wb_get_schannel_creds_recv(action, service);
+ service->netlogon = state->getcreds->out.netlogon;
+
+ talloc_unlink(state, state->conn->out.tree); /* The pipe owns it now */
+ state->conn->out.tree = NULL;
+
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ s3call->response.result = WINBINDD_OK;
+ done:
+ if (!NT_STATUS_IS_OK(status)) {
+ s3call->response.result = WINBINDD_ERROR;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
+ nt_errstr(status));
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
+ nt_errstr(status));
+ s3call->response.data.auth.pam_error = nt_status_to_pam(status);
+
+ }
+
+ status = wbsrv_send_reply(s3call->call);
+ if (!NT_STATUS_IS_OK(status)) {
+ wbsrv_terminate_connection(s3call->call->wbconn,
+ "wbsrv_queue_reply() failed");
+ return;
+ }
}
diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h
index 0c00394f7d..3838354d52 100644
--- a/source4/winbind/wb_server.h
+++ b/source4/winbind/wb_server.h
@@ -32,6 +32,7 @@
/* this struct stores global data for the winbind task */
struct wbsrv_service {
struct task_server *task;
+ struct dcerpc_pipe *netlogon;
};
/*