r991: Allow winbindd to use the domain trust account password
authorGerald Carter <jerry@samba.org>
Thu, 3 Jun 2004 18:00:22 +0000 (18:00 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:51:53 +0000 (10:51 -0500)
for setting up an schannel connection.  This solves the problem
of a Samba DC running winbind, trusting a native mode AD domain,
and needing to enumerate AD users via wbinfo -u.
(This used to be commit e9f109d1b38e0b0adec9b7e9a907f90a79d297ea)

source3/auth/auth_util.c
source3/include/rpc_dce.h
source3/include/rpc_netlogon.h
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_cm.c
source3/rpc_client/cli_netlogon.c
source3/rpc_client/cli_pipe.c
source3/rpc_parse/parse_net.c
source3/rpc_server/srv_netlog.c
source3/rpc_server/srv_netlog_nt.c

index 9a03e7fe13cf1e8f02a09a4a24b6c6474201c1e5..e6cc0fe5b30d05c878ec5ddc4b68f0fbcd667ef1 100644 (file)
@@ -1425,8 +1425,10 @@ BOOL is_trusted_domain(const char* dom_name)
 
        /* if we are a DC, then check for a direct trust relationships */
 
-       if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
+       if ( IS_DC ) {
                become_root();
+               DEBUG (5,("is_trusted_domain: Checking for domain trust with [%s]\n",
+                       dom_name ));
                ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct);
                unbecome_root();
                SAFE_FREE(pass);
index 0df903109db27b54fd5b42bc6193251c259eae80..57b1184bd96a537ea0049e702960bcefbe3b22e4 100644 (file)
@@ -71,7 +71,8 @@ enum RPC_PKT_TYPE
    to NT4.  Actually, anything other than 1ff would seem to do... */
 #define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
  
-#define NETLOGON_NEG_SCHANNEL    0x40000000
+#define NETLOGON_NEG_SCHANNEL                  0x40000000
+#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT      0x2010b000
 
 enum netsec_direction
 {
index a5b93b0238a3479428907ba562f1538f7361bd6e..ad30cfbafb1544d72a09dab572ef1f30ef36cdcd 100644 (file)
 #define SAM_DATABASE_BUILTIN   0x01 /* BUILTIN users and groups */
 #define SAM_DATABASE_PRIVS     0x02 /* Privileges */
 
+#define NETLOGON_CONTROL_REDISCOVER            0x5
+#define NETLOGON_CONTROL_TC_QUERY              0x6
+#define NETLOGON_CONTROL_TRANSPORT_NOTIFY      0x7
+#define NETLOGON_CONTROL_SET_DBFLAG            0xfffe
+
 #if 0
 /* I think this is correct - it's what gets parsed on the wire. JRA. */
 /* NET_USER_INFO_2 */
@@ -204,7 +209,7 @@ typedef struct netlogon_2_info
        uint32  flags;            /* 0x0 - undocumented */
        uint32  pdc_status;       /* 0x0 - undocumented */
        uint32  ptr_trusted_dc_name; /* pointer to trusted domain controller name */
-       uint32  tc_status;           /* 0x051f - ERROR_NO_LOGON_SERVERS */
+       uint32  tc_status;           
        UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */
 
 } NETLOGON_INFO_2;
@@ -255,6 +260,26 @@ typedef struct net_r_logon_ctrl_info
        NTSTATUS status;
 } NET_R_LOGON_CTRL;
 
+
+typedef struct ctrl_data_info_5
+{
+       uint32          function_code;
+       
+       uint32          ptr_domain;
+       UNISTR2         domain;
+       
+} CTRL_DATA_INFO_5;
+
+typedef struct ctrl_data_info_6
+{
+       uint32          function_code;
+       
+       uint32          ptr_domain;
+       UNISTR2         domain;
+       
+} CTRL_DATA_INFO_6;
+
+
 /********************************************************
  Logon Control2 Query
 
@@ -266,13 +291,16 @@ typedef struct net_r_logon_ctrl_info
 /* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */
 typedef struct net_q_logon_ctrl2_info
 {
-       uint32       ptr;             /* undocumented buffer pointer */
-       UNISTR2      uni_server_name; /* server name, starting with two '\'s */
+       uint32          ptr;             /* undocumented buffer pointer */
+       UNISTR2         uni_server_name; /* server name, starting with two '\'s */
+       
+       uint32          function_code; 
+       uint32          query_level;   
+       union {
+               CTRL_DATA_INFO_5 info5;
+               CTRL_DATA_INFO_6 info6;;
+       } info;
        
-       uint32       function_code; /* 0x1 */
-       uint32       query_level;   /* 0x1, 0x3 */
-       uint32       switch_value;  /* 0x1 */
-
 } NET_Q_LOGON_CTRL2;
 
 /*******************************************************
index 877fa2d995c15d4f940c94495e56884b4766db4f..bbd98a620f6b8317e94464464156eec86f168004 100644 (file)
@@ -363,6 +363,12 @@ static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
        if ( NT_STATUS_IS_OK(status) )
                goto done;      
 
+       /* important! make sure that we know if this is a native 
+          mode domain or not */
+
+       if ( !domain->initialized )
+               set_dc_type_and_flags( domain );
+
        status = domain->backend->sequence_number(domain, &domain->sequence_number);
 
        if (!NT_STATUS_IS_OK(status)) {
index eda962088d468c22d081a4a13b7f18774d946a3b..04f87fc1a2fa59ce5144199bd027bdbae40337ee 100644 (file)
@@ -117,21 +117,40 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
 /*
   setup for schannel on any pipes opened on this connection
 */
-static NTSTATUS setup_schannel(struct cli_state *cli)
+static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
 {
        NTSTATUS ret;
        uchar trust_password[16];
        uint32 sec_channel_type;
+       DOM_SID sid;
+       time_t lct;
 
-       if (!secrets_fetch_trust_account_password(lp_workgroup(),
-                                                 trust_password,
-                                                 NULL, &sec_channel_type)) {
-               return NT_STATUS_UNSUCCESSFUL;
+       /* use the domain trust password if we're on a DC 
+          and this is not our domain */
+       
+       if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
+               char *pass = NULL;
+               
+               if ( !secrets_fetch_trusted_domain_password( domain, 
+                       &pass, &sid, &lct) )
+               {
+                       return NT_STATUS_UNSUCCESSFUL;
+               }       
+
+               sec_channel_type = SEC_CHAN_DOMAIN;
+               E_md4hash(pass, trust_password);
+               SAFE_FREE( pass );
+               
+       } else {
+               if (!secrets_fetch_trust_account_password(lp_workgroup(),
+                       trust_password, NULL, &sec_channel_type)) 
+               {
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
        }
 
        ret = cli_nt_setup_netsec(cli, sec_channel_type, 
-                                 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, 
-                                 trust_password);
+               AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
 
        return ret;
 }
@@ -216,7 +235,8 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
        /* Initialise SMB connection */
        fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
 
-/* grab stored passwords */
+       /* grab stored passwords */
+       
        machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
        
        if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
@@ -335,9 +355,13 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
        /* try and use schannel if possible, but continue anyway if it
           failed. This allows existing setups to continue working,
           while solving the win2003 '100 user' limit for systems that
-          are joined properly */
-       if (NT_STATUS_IS_OK(result) && (domain->primary)) {
-               NTSTATUS status = setup_schannel(new_conn->cli);
+          are joined properly.
+       
+          Only do this for our own domain or perhaps a trusted domain
+          if we are on a Samba DC */
+
+       if (NT_STATUS_IS_OK(result) && (domain->primary || IS_DC) ) {
+               NTSTATUS status = setup_schannel( new_conn->cli, domain->name );
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("schannel refused - continuing without schannel (%s)\n", 
                                 nt_errstr(status)));
index f6d88a195016dc84fa89282319c9fed1f98c7581..02d2611d88cd30cde8b5b858fb86ddfeb670bd21 100644 (file)
@@ -91,18 +91,25 @@ NTSTATUS cli_net_auth2(struct cli_state *cli,
         NET_Q_AUTH_2 q;
         NET_R_AUTH_2 r;
         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       fstring machine_acct;
 
         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
 
+       if ( sec_chan == SEC_CHAN_DOMAIN )
+               fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
+       else
+               fstrcpy( machine_acct, cli->mach_acct );
+       
         /* create and send a MSRPC command with api NET_AUTH2 */
 
         DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
-                 cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(),
+                 cli->srv_name_slash, machine_acct, sec_chan, global_myname(),
                  credstr(cli->clnt_cred.challenge.data), *neg_flags));
 
         /* store the parameters */
-        init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct, 
+
+        init_q_auth_2(&q, cli->srv_name_slash, machine_acct, 
                       sec_chan, global_myname(), &cli->clnt_cred.challenge, 
                       *neg_flags);
 
index b24dbb7d25d58841acde4456aa8e8acad289578b..9e2d5aa4a756db7e18534ce7b7ae0d3dcd8449cd 100644 (file)
@@ -1621,9 +1621,6 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       if (lp_client_schannel() != False)
-               neg_flags |= NETLOGON_NEG_SCHANNEL;
-
        neg_flags |= NETLOGON_NEG_SCHANNEL;
 
        result = cli_nt_setup_creds(cli, sec_chan, trust_password,
index 36d55c7bf675d20793e7c88ffcb96501657a944c..b42b9b2a8b41cba99cca0e2924a55d29d7ba4fcc 100644 (file)
@@ -182,6 +182,50 @@ static BOOL net_io_netinfo_2(const char *desc, NETLOGON_INFO_2 *info, prs_struct
        return True;
 }
 
+static BOOL net_io_ctrl_data_info_5(const char *desc, CTRL_DATA_INFO_5 *info, prs_struct *ps, int depth)
+{
+       if (info == NULL)
+               return False;
+               
+       prs_debug(ps, depth, desc, "net_io_ctrl_data_info_5");
+       depth++;
+       
+       if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
+               return False;
+       
+       if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
+               return False;
+               
+       if ( info->ptr_domain ) {
+               if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
+                       return False;
+       }
+               
+       return True;
+}
+
+static BOOL net_io_ctrl_data_info_6(const char *desc, CTRL_DATA_INFO_6 *info, prs_struct *ps, int depth)
+{
+       if (info == NULL)
+               return False;
+               
+       prs_debug(ps, depth, desc, "net_io_ctrl_data_info_6");
+       depth++;
+       
+       if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
+               return False;
+       
+       if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
+               return False;
+               
+       if ( info->ptr_domain ) {
+               if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
+                       return False;
+       }
+               
+       return True;
+}
+
 /*******************************************************************
  Reads or writes an NET_Q_LOGON_CTRL2 structure.
 ********************************************************************/
@@ -210,9 +254,23 @@ BOOL net_io_q_logon_ctrl2(const char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *
                return False;
        if(!prs_uint32("query_level  ", ps, depth, &q_l->query_level))
                return False;
-       if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value))
-               return False;
+       switch ( q_l->function_code ) {
+               case NETLOGON_CONTROL_REDISCOVER:
+                       if ( !net_io_ctrl_data_info_5( "ctrl_data_info5", &q_l->info.info5, ps, depth) ) 
+                               return False;
+                       break;
+                       
+               case NETLOGON_CONTROL_TC_QUERY:
+                       if ( !net_io_ctrl_data_info_6( "ctrl_data_info6", &q_l->info.info6, ps, depth) ) 
+                               return False;
+                       break;
 
+               default:
+                       DEBUG(0,("net_io_q_logon_ctrl2: unknown function_code [%d]\n",
+                               q_l->function_code));
+                       return False;
+       }
+       
        return True;
 }
 
@@ -227,7 +285,6 @@ void init_net_q_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, const char *srv_name,
 
        q_l->function_code = 0x01;
        q_l->query_level = query_level;
-       q_l->switch_value  = 0x01;
 
        init_unistr2(&q_l->uni_server_name, srv_name, UNI_STR_TERMINATE);
 }
@@ -241,9 +298,7 @@ void init_net_r_logon_ctrl2(NET_R_LOGON_CTRL2 *r_l, uint32 query_level,
                            uint32 logon_attempts, uint32 tc_status, 
                            const char *trusted_domain_name)
 {
-       DEBUG(5,("init_r_logon_ctrl2\n"));
-
-       r_l->switch_value  = query_level; /* should only be 0x1 */
+       r_l->switch_value  = query_level; 
 
        switch (query_level) {
        case 1:
index f06a2002e3c37bc372798cfc453721d0a4a2ed59..705b629732a5f729e1fe10a92063f029ed757899 100644 (file)
@@ -227,8 +227,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
        ZERO_STRUCT(q_u);
        ZERO_STRUCT(r_u);
 
-       DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
-
        /* grab the lsa trusted domain list query... */
        if(!net_io_q_trust_dom("", &q_u, data, 0)) {
                DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n"));
@@ -244,8 +242,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
                return False;
        }
 
-       DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
-
        return True;
 }
 
@@ -263,7 +259,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
        ZERO_STRUCT(q_u);
        ZERO_STRUCT(r_u);
 
-       DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
 
        /* grab the lsa netlogon ctrl2 query... */
        if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) {
@@ -278,8 +273,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
                return False;
        }
 
-       DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
-
        return True;
 }
 
@@ -297,8 +290,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
        ZERO_STRUCT(q_u);
        ZERO_STRUCT(r_u);
 
-       DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__));
-
        /* grab the lsa netlogon ctrl query... */
        if(!net_io_q_logon_ctrl("", &q_u, data, 0)) {
                DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n"));
@@ -312,8 +303,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
                return False;
        }
 
-       DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
-
        return True;
 }
 
index be8eda82c9023b9b193607420847f0a462a95e39..264b7a74a7994715b7f90547b9eae98a95643eb7 100644 (file)
@@ -47,6 +47,7 @@ static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
 
 #define ERROR_NO_SUCH_DOMAIN   0x54b
 #define ERROR_NO_LOGON_SERVERS 0x51f
+#define NO_ERROR               0x0
 
 /*************************************************************************
  net_reply_logon_ctrl:
@@ -104,25 +105,67 @@ NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_C
         uint32 flags = 0x0;
         uint32 pdc_connection_status = 0x0;
         uint32 logon_attempts = 0x0;
-        uint32 tc_status = ERROR_NO_LOGON_SERVERS;
-        const char *trusted_domain = "test_domain";
+        uint32 tc_status;
+       fstring servername, domain, dc_name, dc_name2;
+       struct in_addr dc_ip;
 
-        DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n",
-                  q_u->function_code, q_u->query_level, q_u->switch_value));
+       /* this should be \\global_myname() */
+       unistr2_to_ascii(servername, &q_u->uni_server_name, sizeof(servername));
 
-       DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
-
-
-       /* set up the Logon Control2 response */
-       init_net_r_logon_ctrl2(r_u, q_u->query_level,
-                              flags, pdc_connection_status, logon_attempts,
-                              tc_status, trusted_domain);
+       r_u->status = NT_STATUS_OK;
+       
+       tc_status = ERROR_NO_SUCH_DOMAIN;
+       fstrcpy( dc_name, "" );
+       
+       switch ( q_u->function_code ) {
+               case NETLOGON_CONTROL_TC_QUERY:
+                       unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
+                               
+                       if ( !is_trusted_domain( domain ) )
+                               break;
+                               
+                       if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
+                               tc_status = ERROR_NO_LOGON_SERVERS;
+                               break;
+                       }
+
+                       fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
+                               
+                       tc_status = NO_ERROR;
+                       
+                       break;
+                       
+               case NETLOGON_CONTROL_REDISCOVER:
+                       unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
+                               
+                       if ( !is_trusted_domain( domain ) )
+                               break;
+                               
+                       if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
+                               tc_status = ERROR_NO_LOGON_SERVERS;
+                               break;
+                       }
+
+                       fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
+                               
+                       tc_status = NO_ERROR;
+                       
+                       break;
+                       
+               default:
+                       /* no idea what this should be */
+                       DEBUG(0,("_net_logon_ctrl2: unimplemented function level [%d]\n",
+                               q_u->function_code));
+       }
+       
+       /* prepare the response */
+       
+       init_net_r_logon_ctrl2( r_u, q_u->query_level, flags, 
+               pdc_connection_status, logon_attempts, tc_status, dc_name );
 
         if (lp_server_role() == ROLE_DOMAIN_BDC)
                 send_sync_message();
 
-       DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
-
        return r_u->status;
 }