s4:libnet Allow 'net password change' to work on expired passwords
authorAndrew Bartlett <abartlet@samba.org>
Thu, 18 Jun 2009 02:33:46 +0000 (12:33 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 18 Jun 2009 03:49:30 +0000 (13:49 +1000)
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
source4/libnet/libnet_join.c
source4/libnet/libnet_passwd.c
source4/libnet/libnet_rpc.c
source4/libnet/libnet_rpc.h
source4/libnet/libnet_samsync.c
source4/libnet/libnet_share.c
source4/libnet/libnet_time.c
source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_connect.c
source4/torture/libnet/libnet_rpc.c

index eb6920d88ef62ac68c68a1ab58d5201e41b28110..43a6a0e10b52f67b42e05409655d0df7fb467bc7 100644 (file)
@@ -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;
index 0a4e357925af13a84bb079ca607138138935719e..81578a1a8859ba007623e65d3f972ba087461e3e 100644 (file)
@@ -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);
index 2c969169373ef955511361bdd524d99d5ba6178f..e558c93d7509e9c19c32fc0834de8d360e8456ad 100644 (file)
@@ -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)) {
index a0d93287a5bfa39eda86868e10ccdc05209c8db6..66e12d0da1464b7cef1f1a67ab42459f163f3f39 100644 (file)
@@ -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 */
index b3e1620c75b28a4d3323360f87fc7e73c3867296..fb2628409f5916e74339d508496b912febcd9584 100644 (file)
@@ -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;
index 4d512d60344be0f6c67184e87c4b43d2401ee53d..1d5e41de0533c56aa002ada147b90ca5116c8b65 100644 (file)
@@ -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);
index 0bf6749a9c1a3162a0aa453c7b82bf3f172dbe0a..e9ad83db36a6b2644b5ddfca52874a8672d18a21 100644 (file)
@@ -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;
index 61a451d3fda661e506d18837653f011cbf50ee16..37648459db9f0bf639e808ffa065afb5c334eb62 100644 (file)
@@ -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;
index 7f573f0e84f81a4f8db321239b80b9751a8f520b..ea92bcc93a4f1233f9d77598ad01ecc6268bd02b 100644 (file)
@@ -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)
 
index 0f9fbe0abc00946947e8d43476780aa1ec925365..1b1f039004ffbdbfa93a75952cc093e33a25b60e 100644 (file)
@@ -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;
index 0bcfcb6a4cd3725d0b03e721ea174ca0bc93f78c..c9ba8755895dbee30132806ab6941b18afcf7ff7 100644 (file)
@@ -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;