diff options
author | Volker Lendecke <vlendec@samba.org> | 2005-10-03 13:46:11 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:39:18 -0500 |
commit | e5c6a3e36147103e87d1c55173f4b54ba6134904 (patch) | |
tree | b50938eff14034f7b6db53caf76dd2cd9e8cd10c /source4/winbind | |
parent | 28bc38de2ab3a408702cd7d6b69d6549a1fea71a (diff) | |
download | samba-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.c | 224 | ||||
-rw-r--r-- | source4/winbind/wb_async_helpers.h | 10 | ||||
-rw-r--r-- | source4/winbind/wb_samba3_cmd.c | 177 | ||||
-rw-r--r-- | source4/winbind/wb_server.h | 1 |
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; }; /* |