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/wb_async_helpers.c | |
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/wb_async_helpers.c')
-rw-r--r-- | source4/winbind/wb_async_helpers.c | 224 |
1 files changed, 223 insertions, 1 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); +} |