summaryrefslogtreecommitdiff
path: root/source4/winbind/wb_async_helpers.c
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/wb_async_helpers.c
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/wb_async_helpers.c')
-rw-r--r--source4/winbind/wb_async_helpers.c224
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);
+}