From 58e8db912d2213a594714ac29866396098662557 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 18 Jun 2009 12:33:46 +1000 Subject: s4:libnet Allow 'net password change' to work on expired passwords We need to pass down flags to the DCE/RPC layer to allow fallback to anonymous connections, as we can't log in with an expired password. The anonymous connection can then change the password with SAMR. Andrew Bartlett --- source4/libnet/libnet_domain.c | 4 ++++ source4/libnet/libnet_join.c | 2 +- source4/libnet/libnet_passwd.c | 6 +++++- source4/libnet/libnet_rpc.c | 19 +++++++++++++++---- source4/libnet/libnet_rpc.h | 1 + source4/libnet/libnet_samsync.c | 2 +- source4/libnet/libnet_share.c | 6 ++++++ source4/libnet/libnet_time.c | 2 ++ source4/librpc/rpc/dcerpc.h | 2 ++ source4/librpc/rpc/dcerpc_connect.c | 4 ++-- source4/torture/libnet/libnet_rpc.c | 2 ++ 11 files changed, 41 insertions(+), 9 deletions(-) diff --git a/source4/libnet/libnet_domain.c b/source4/libnet/libnet_domain.c index eb6920d88e..43a6a0e10b 100644 --- a/source4/libnet/libnet_domain.c +++ b/source4/libnet/libnet_domain.c @@ -427,6 +427,8 @@ struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx, /* check, if there's lsa pipe opened already, before opening a handle */ if (ctx->lsa.pipe == NULL) { + ZERO_STRUCT(s->rpcconn); + /* attempting to connect a domain controller */ s->rpcconn.level = LIBNET_RPC_CONNECT_DC; s->rpcconn.in.name = talloc_strdup(c, io->in.domain_name); @@ -1179,6 +1181,8 @@ struct composite_context* libnet_DomainList_send(struct libnet_context *ctx, /* check whether samr pipe has already been opened */ if (ctx->samr.pipe == NULL) { + ZERO_STRUCT(s->rpcconn); + /* prepare rpc connect call */ s->rpcconn.level = LIBNET_RPC_CONNECT_SERVER; s->rpcconn.in.name = s->hostname; diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c index 0a4e357925..81578a1a88 100644 --- a/source4/libnet/libnet_join.c +++ b/source4/libnet/libnet_join.c @@ -479,7 +479,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru return NT_STATUS_NO_MEMORY; } - connect_with_info = talloc(tmp_ctx, struct libnet_RpcConnect); + connect_with_info = talloc_zero(tmp_ctx, struct libnet_RpcConnect); if (!connect_with_info) { r->out.error_string = NULL; talloc_free(tmp_ctx); diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index 2c96916937..e558c93d75 100644 --- a/source4/libnet/libnet_passwd.c +++ b/source4/libnet/libnet_passwd.c @@ -53,10 +53,13 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT struct samr_DomInfo1 *dominfo = NULL; struct samr_ChangeReject *reject = NULL; + ZERO_STRUCT(c); + /* prepare connect to the SAMR pipe of the users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &ndr_table_samr; + c.in.dcerpc_flags = DCERPC_ANON_FALLBACK; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); @@ -504,11 +507,12 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX * struct policy_handle u_handle; union libnet_SetPassword r2; + ZERO_STRUCT(c); /* prepare connect to the SAMR pipe of users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &ndr_table_samr; - + /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index a0d93287a5..66e12d0da1 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -106,6 +106,12 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context return c; } + switch (r->level) { + case LIBNET_RPC_CONNECT_SERVER: + case LIBNET_RPC_CONNECT_SERVER_ADDRESS: + b->flags = r->in.dcerpc_flags; + } + if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) { b->target_hostname = talloc_reference(b, r->in.name); if (composite_nomem(b->target_hostname, c)) { @@ -323,6 +329,7 @@ static void continue_lookup_dc(struct composite_context *ctx) s->r2.in.name = talloc_strdup(s, s->connect_name); s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address); s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface; + s->r2.in.dcerpc_flags = s->r.in.dcerpc_flags; /* send rpc connect request to the server */ rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn); @@ -478,14 +485,18 @@ static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_cont s->r = *r; ZERO_STRUCT(s->r.out); + /* proceed to pure rpc connection if the binding string is provided, otherwise try to connect domain controller */ if (r->in.binding == NULL) { - s->rpc_conn.in.name = r->in.name; - s->rpc_conn.level = LIBNET_RPC_CONNECT_DC; + /* Pass on any binding flags (such as anonymous fallback) that have been set */ + s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags; + + s->rpc_conn.in.name = r->in.name; + s->rpc_conn.level = LIBNET_RPC_CONNECT_DC; } else { - s->rpc_conn.in.binding = r->in.binding; - s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING; + s->rpc_conn.in.binding = r->in.binding; + s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING; } /* we need to query information on lsarpc interface first */ diff --git a/source4/libnet/libnet_rpc.h b/source4/libnet/libnet_rpc.h index b3e1620c75..fb2628409f 100644 --- a/source4/libnet/libnet_rpc.h +++ b/source4/libnet/libnet_rpc.h @@ -45,6 +45,7 @@ struct libnet_RpcConnect { const char *address; const char *binding; const struct ndr_interface_table *dcerpc_iface; + int dcerpc_flags; } in; struct { struct dcerpc_pipe *dcerpc_pipe; diff --git a/source4/libnet/libnet_samsync.c b/source4/libnet/libnet_samsync.c index 4d512d6034..1d5e41de05 100644 --- a/source4/libnet/libnet_samsync.c +++ b/source4/libnet/libnet_samsync.c @@ -77,7 +77,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } - c = talloc(samsync_ctx, struct libnet_RpcConnect); + c = talloc_zero(samsync_ctx, struct libnet_RpcConnect); if (!c) { r->out.error_string = NULL; talloc_free(samsync_ctx); diff --git a/source4/libnet/libnet_share.c b/source4/libnet/libnet_share.c index 0bf6749a9c..e9ad83db36 100644 --- a/source4/libnet/libnet_share.c +++ b/source4/libnet/libnet_share.c @@ -37,6 +37,8 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx, struct srvsvc_NetShareCtr501 ctr501; struct srvsvc_NetShareCtr502 ctr502; + ZERO_STRUCT(c); + c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; @@ -121,6 +123,8 @@ NTSTATUS libnet_AddShare(struct libnet_context *ctx, struct srvsvc_NetShareAdd s; union srvsvc_NetShareInfo info; + ZERO_STRUCT(c); + c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; @@ -170,6 +174,8 @@ NTSTATUS libnet_DelShare(struct libnet_context *ctx, struct libnet_RpcConnect c; struct srvsvc_NetShareDel s; + ZERO_STRUCT(c); + c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; diff --git a/source4/libnet/libnet_time.c b/source4/libnet/libnet_time.c index 61a451d3fd..37648459db 100644 --- a/source4/libnet/libnet_time.c +++ b/source4/libnet/libnet_time.c @@ -33,6 +33,8 @@ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX * struct srvsvc_NetRemoteTODInfo *info = NULL; struct tm tm; + ZERO_STRUCT(c); + /* prepare connect to the SRVSVC pipe of a timeserver */ c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->srvsvc.in.server_name; diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 7f573f0e84..ea92bcc93a 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -142,6 +142,8 @@ struct dcerpc_pipe { #define DCERPC_SCHANNEL (1<<9) +#define DCERPC_ANON_FALLBACK (1<<10) + /* use a 128 bit session key */ #define DCERPC_SCHANNEL_128 (1<<12) diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index 0f9fbe0abc..1b1f039004 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -130,10 +130,10 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT * provide proper credentials - user supplied, but allow a * fallback to anonymous if this is an schannel connection * (might be NT4 not allowing machine logins at session - * setup). + * setup) or if asked to do so by the caller (perhaps a SAMR password change?) */ s->conn.in.credentials = s->io.creds; - if (s->io.binding->flags & DCERPC_SCHANNEL) { + if (s->io.binding->flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) { conn->in.fallback_to_anonymous = true; } else { conn->in.fallback_to_anonymous = false; diff --git a/source4/torture/libnet/libnet_rpc.c b/source4/torture/libnet/libnet_rpc.c index 0bcfcb6a4c..c9ba875589 100644 --- a/source4/torture/libnet/libnet_rpc.c +++ b/source4/torture/libnet/libnet_rpc.c @@ -42,6 +42,8 @@ static bool test_connect_service(struct libnet_context *ctx, { NTSTATUS status; struct libnet_RpcConnect connect_r; + ZERO_STRUCT(connect_r); + connect_r.level = level; connect_r.in.binding = binding_string; connect_r.in.name = hostname; -- cgit