Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source3/libsmb/trusts_util.c

    r740 r988  
    2121#include "includes.h"
    2222#include "../libcli/auth/libcli_auth.h"
    23 #include "../librpc/gen_ndr/ndr_lsa_c.h"
    24 #include "rpc_client/cli_lsarpc.h"
     23#include "../libcli/auth/netlogon_creds_cli.h"
    2524#include "rpc_client/cli_netlogon.h"
    2625#include "rpc_client/cli_pipe.h"
     
    2928#include "passdb.h"
    3029#include "libsmb/libsmb.h"
    31 
    32 /*********************************************************
    33  Change the domain password on the PDC.
    34  Store the password ourselves, but use the supplied password
    35  Caller must have already setup the connection to the NETLOGON pipe
    36 **********************************************************/
    37 
    38 NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
    39                                       const char *domain,
    40                                       const char *account_name,
    41                                       unsigned char orig_trust_passwd_hash[16],
    42                                       enum netr_SchannelType sec_channel_type)
    43 {
    44         unsigned char new_trust_passwd_hash[16];
    45         char *new_trust_passwd;
    46         NTSTATUS nt_status;
    47 
    48         switch (sec_channel_type) {
    49         case SEC_CHAN_WKSTA:
    50         case SEC_CHAN_DOMAIN:
    51                 break;
    52         default:
    53                 return NT_STATUS_NOT_SUPPORTED;
    54         }
    55 
    56         /* Create a random machine account password */
    57         new_trust_passwd = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
    58 
    59         if (new_trust_passwd == NULL) {
    60                 DEBUG(0, ("talloc_strdup failed\n"));
    61                 return NT_STATUS_NO_MEMORY;
    62         }
    63 
    64         E_md4hash(new_trust_passwd, new_trust_passwd_hash);
    65 
    66         nt_status = rpccli_netlogon_set_trust_password(cli, mem_ctx,
    67                                                        account_name,
    68                                                        orig_trust_passwd_hash,
    69                                                        new_trust_passwd,
    70                                                        new_trust_passwd_hash,
    71                                                        sec_channel_type);
    72 
    73         if (NT_STATUS_IS_OK(nt_status)) {
    74                 DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n",
    75                          current_timestring(talloc_tos(), False)));
    76                 /*
    77                  * Return the result of trying to write the new password
    78                  * back into the trust account file.
    79                  */
    80 
    81                 switch (sec_channel_type) {
    82 
    83                 case SEC_CHAN_WKSTA:
    84                         if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
    85                                 nt_status = NT_STATUS_UNSUCCESSFUL;
    86                         }
    87                         break;
    88 
    89                 case SEC_CHAN_DOMAIN: {
    90                         char *pwd;
    91                         struct dom_sid sid;
    92                         time_t pass_last_set_time;
    93 
    94                         /* we need to get the sid first for the
    95                          * pdb_set_trusteddom_pw call */
    96 
    97                         if (!pdb_get_trusteddom_pw(domain, &pwd, &sid, &pass_last_set_time)) {
    98                                 nt_status = NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
    99                         }
    100                         if (!pdb_set_trusteddom_pw(domain, new_trust_passwd, &sid)) {
    101                                 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
    102                         }
    103                         break;
    104                 }
    105                 default:
    106                         break;
    107                 }
    108         }
    109 
    110         return nt_status;
    111 }
     30#include "source3/include/messages.h"
     31#include "source3/include/g_lock.h"
    11232
    11333/*********************************************************
     
    11737**********************************************************/
    11838
    119 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
    120                                            TALLOC_CTX *mem_ctx,
    121                                            const char *domain)
     39struct trust_pw_change_state {
     40        struct g_lock_ctx *g_ctx;
     41        char *g_lock_key;
     42};
     43
     44static int trust_pw_change_state_destructor(struct trust_pw_change_state *state)
    12245{
    123         unsigned char old_trust_passwd_hash[16];
     46        g_lock_unlock(state->g_ctx, state->g_lock_key);
     47        return 0;
     48}
     49
     50NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
     51                         struct messaging_context *msg_ctx,
     52                         struct dcerpc_binding_handle *b,
     53                         const char *domain,
     54                         bool force)
     55{
     56        TALLOC_CTX *frame = talloc_stackframe();
     57        struct trust_pw_change_state *state;
     58        struct cli_credentials *creds = NULL;
     59        const struct samr_Password *current_nt_hash = NULL;
     60        const struct samr_Password *previous_nt_hash = NULL;
    12461        enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
    125         const char *account_name;
    126 
    127         if (!get_trust_pw_hash(domain, old_trust_passwd_hash, &account_name,
    128                                &sec_channel_type)) {
    129                 DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
    130                 return NT_STATUS_UNSUCCESSFUL;
    131         }
    132 
    133         return trust_pw_change_and_store_it(cli, mem_ctx, domain,
    134                                             account_name,
    135                                             old_trust_passwd_hash,
    136                                             sec_channel_type);
     62        time_t pass_last_set_time;
     63        uint32_t old_version = 0;
     64        struct pdb_trusted_domain *td = NULL;
     65        struct timeval g_timeout = { 0, };
     66        int timeout = 0;
     67        struct timeval tv = { 0, };
     68        size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH;
     69        uint8_t new_password_buffer[256 * 2] = { 0, };
     70        char *new_trust_passwd = NULL;
     71        size_t len = 0;
     72        uint32_t new_version = 0;
     73        uint32_t *new_trust_version = NULL;
     74        NTSTATUS status;
     75        bool ok;
     76
     77        state = talloc_zero(frame, struct trust_pw_change_state);
     78        if (state == NULL) {
     79                TALLOC_FREE(frame);
     80                return NT_STATUS_NO_MEMORY;
     81        }
     82
     83        state->g_ctx = g_lock_ctx_init(state, msg_ctx);
     84        if (state->g_ctx == NULL) {
     85                TALLOC_FREE(frame);
     86                return NT_STATUS_NO_MEMORY;
     87        }
     88
     89        state->g_lock_key = talloc_asprintf(state,
     90                                "trust_password_change_%s",
     91                                domain);
     92        if (state->g_lock_key == NULL) {
     93                TALLOC_FREE(frame);
     94                return NT_STATUS_NO_MEMORY;
     95        }
     96
     97        g_timeout = timeval_current_ofs(10, 0);
     98        status = g_lock_lock(state->g_ctx,
     99                             state->g_lock_key,
     100                             G_LOCK_WRITE, g_timeout);
     101        if (!NT_STATUS_IS_OK(status)) {
     102                DEBUG(1, ("could not get g_lock on [%s]!\n",
     103                          state->g_lock_key));
     104                TALLOC_FREE(frame);
     105                return status;
     106        }
     107
     108        talloc_set_destructor(state, trust_pw_change_state_destructor);
     109
     110        status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
     111        if (!NT_STATUS_IS_OK(status)) {
     112                DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n",
     113                          domain, nt_errstr(status)));
     114                TALLOC_FREE(frame);
     115                return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     116        }
     117
     118        current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
     119        if (current_nt_hash == NULL) {
     120                DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
     121                          domain));
     122                TALLOC_FREE(frame);
     123                return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     124        }
     125
     126        old_version = cli_credentials_get_kvno(creds);
     127        pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
     128        sec_channel_type = cli_credentials_get_secure_channel_type(creds);
     129
     130        new_version = old_version + 1;
     131
     132        switch (sec_channel_type) {
     133        case SEC_CHAN_WKSTA:
     134        case SEC_CHAN_BDC:
     135                break;
     136        case SEC_CHAN_DNS_DOMAIN:
     137                /*
     138                 * new_len * 2 = 498 bytes is the largest possible length
     139                 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
     140                 * and a confounder with at least 2 bytes is required.
     141                 *
     142                 * Windows uses new_len = 120 => 240 bytes.
     143                 */
     144                new_len = 120;
     145
     146                /* fall through */
     147        case SEC_CHAN_DOMAIN:
     148                status = pdb_get_trusted_domain(frame, domain, &td);
     149                if (!NT_STATUS_IS_OK(status)) {
     150                        DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n",
     151                                  domain, nt_errstr(status)));
     152                        TALLOC_FREE(frame);
     153                        return status;
     154                }
     155
     156                new_trust_version = &new_version;
     157                break;
     158        default:
     159                TALLOC_FREE(frame);
     160                return NT_STATUS_NOT_SUPPORTED;
     161        }
     162
     163        timeout = lp_machine_password_timeout();
     164        if (timeout == 0) {
     165                if (!force) {
     166                        DEBUG(10,("machine password never expires\n"));
     167                        TALLOC_FREE(frame);
     168                        return NT_STATUS_OK;
     169                }
     170        }
     171
     172        tv.tv_sec = pass_last_set_time;
     173        DEBUG(10, ("password last changed %s\n",
     174                   timeval_string(talloc_tos(), &tv, false)));
     175        tv.tv_sec += timeout;
     176        DEBUGADD(10, ("password valid until %s\n",
     177                      timeval_string(talloc_tos(), &tv, false)));
     178
     179        if (!force && !timeval_expired(&tv)) {
     180                TALLOC_FREE(frame);
     181                return NT_STATUS_OK;
     182        }
     183
     184        /*
     185         * Create a random machine account password
     186         * We create a random buffer and convert that to utf8.
     187         * This is similar to what windows is doing.
     188         */
     189        generate_secret_buffer(new_password_buffer, new_len * 2);
     190        ok = convert_string_talloc(frame,
     191                                   CH_UTF16MUNGED, CH_UTF8,
     192                                   new_password_buffer, new_len * 2,
     193                                   (void *)&new_trust_passwd, &len);
     194        ZERO_STRUCT(new_password_buffer);
     195        if (!ok) {
     196                DEBUG(0, ("convert_string_talloc failed\n"));
     197                TALLOC_FREE(frame);
     198                return NT_STATUS_NO_MEMORY;
     199        }
     200
     201        /*
     202         * We could use cli_credentials_get_old_nt_hash(creds, frame) to
     203         * set previous_nt_hash.
     204         *
     205         * But we want to check if the dc has our current password and only do
     206         * a change if that's the case. So we keep previous_nt_hash = NULL.
     207         *
     208         * TODO:
     209         * If the previous password is the only password in common with the dc,
     210         * we better skip the password change, or use something like
     211         * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
     212         * local secrets before doing the change.
     213         */
     214        status = netlogon_creds_cli_auth(context, b,
     215                                         *current_nt_hash,
     216                                         previous_nt_hash);
     217        if (!NT_STATUS_IS_OK(status)) {
     218                DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n",
     219                          domain, nt_errstr(status)));
     220                TALLOC_FREE(frame);
     221                return status;
     222        }
     223
     224        /*
     225         * Return the result of trying to write the new password
     226         * back into the trust account file.
     227         */
     228
     229        switch (sec_channel_type) {
     230
     231        case SEC_CHAN_WKSTA:
     232        case SEC_CHAN_BDC:
     233                ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type);
     234                if (!ok) {
     235                        DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n",
     236                                  domain));
     237                        TALLOC_FREE(frame);
     238                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
     239                }
     240                break;
     241
     242        case SEC_CHAN_DNS_DOMAIN:
     243        case SEC_CHAN_DOMAIN:
     244                /*
     245                 * we need to get the sid first for the
     246                 * pdb_set_trusteddom_pw call
     247                 */
     248                ok = pdb_set_trusteddom_pw(domain, new_trust_passwd,
     249                                           &td->security_identifier);
     250                if (!ok) {
     251                        DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
     252                                  domain));
     253                        TALLOC_FREE(frame);
     254                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
     255                }
     256                break;
     257
     258        default:
     259                smb_panic("Unsupported secure channel type");
     260                break;
     261        }
     262
     263        DEBUG(1,("%s : %s(%s): Changed password locally\n",
     264                 current_timestring(talloc_tos(), false), __func__, domain));
     265
     266        status = netlogon_creds_cli_ServerPasswordSet(context, b,
     267                                                      new_trust_passwd,
     268                                                      new_trust_version);
     269        if (!NT_STATUS_IS_OK(status)) {
     270                DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n",
     271                         current_timestring(talloc_tos(), false), __func__,
     272                         domain, nt_errstr(status)));
     273                TALLOC_FREE(frame);
     274                return status;
     275        }
     276
     277        DEBUG(1,("%s : %s(%s): Changed password remotely.\n",
     278                 current_timestring(talloc_tos(), false), __func__, domain));
     279
     280        TALLOC_FREE(frame);
     281        return NT_STATUS_OK;
    137282}
    138 
    139 /*********************************************************************
    140  Enumerate the list of trusted domains from a DC
    141 *********************************************************************/
    142 
    143 bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
    144                                      char ***domain_names, uint32 *num_domains,
    145                                      struct dom_sid **sids )
    146 {
    147         struct policy_handle    pol;
    148         NTSTATUS status, result;
    149         fstring         dc_name;
    150         struct sockaddr_storage dc_ss;
    151         uint32          enum_ctx = 0;
    152         struct cli_state *cli = NULL;
    153         struct rpc_pipe_client *lsa_pipe = NULL;
    154         struct lsa_DomainList dom_list;
    155         int i;
    156         struct dcerpc_binding_handle *b = NULL;
    157 
    158         *domain_names = NULL;
    159         *num_domains = 0;
    160         *sids = NULL;
    161 
    162         /* lookup a DC first */
    163 
    164         if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
    165                 DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
    166                         domain));
    167                 return False;
    168         }
    169 
    170         /* setup the anonymous connection */
    171 
    172         status = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC",
    173                 "", "", "", 0, Undefined);
    174         if ( !NT_STATUS_IS_OK(status) )
    175                 goto done;
    176 
    177         /* open the LSARPC_PIPE */
    178 
    179         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
    180                                           &lsa_pipe);
    181         if (!NT_STATUS_IS_OK(status)) {
    182                 goto done;
    183         }
    184 
    185         b = lsa_pipe->binding_handle;
    186 
    187         /* get a handle */
    188 
    189         status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
    190                 LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
    191         if ( !NT_STATUS_IS_OK(status) )
    192                 goto done;
    193 
    194         /* Lookup list of trusted domains */
    195 
    196         status = dcerpc_lsa_EnumTrustDom(b, mem_ctx,
    197                                          &pol,
    198                                          &enum_ctx,
    199                                          &dom_list,
    200                                          (uint32_t)-1,
    201                                          &result);
    202         if ( !NT_STATUS_IS_OK(status) )
    203                 goto done;
    204         if (!NT_STATUS_IS_OK(result)) {
    205                 status = result;
    206                 goto done;
    207         }
    208 
    209         *num_domains = dom_list.count;
    210 
    211         *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
    212         if (!*domain_names) {
    213                 status = NT_STATUS_NO_MEMORY;
    214                 goto done;
    215         }
    216 
    217         *sids = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, *num_domains);
    218         if (!*sids) {
    219                 status = NT_STATUS_NO_MEMORY;
    220                 goto done;
    221         }
    222 
    223         for (i=0; i< *num_domains; i++) {
    224                 (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
    225                 (*sids)[i] = *dom_list.domains[i].sid;
    226         }
    227 
    228 done:
    229         /* cleanup */
    230         if (cli) {
    231                 DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
    232                 cli_shutdown( cli );
    233         }
    234 
    235         return NT_STATUS_IS_OK(status);
    236 }
    237 
    238 NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine)
    239 {
    240         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
    241         struct sockaddr_storage pdc_ss;
    242         fstring dc_name;
    243         struct cli_state *cli = NULL;
    244         struct rpc_pipe_client *netlogon_pipe = NULL;
    245 
    246         DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n",
    247                 domain));
    248 
    249         if (remote_machine == NULL || !strcmp(remote_machine, "*")) {
    250                 /* Use the PDC *only* for this */
    251 
    252                 if ( !get_pdc_ip(domain, &pdc_ss) ) {
    253                         DEBUG(0,("Can't get IP for PDC for domain %s\n", domain));
    254                         goto failed;
    255                 }
    256 
    257                 if ( !name_status_find( domain, 0x1b, 0x20, &pdc_ss, dc_name) )
    258                         goto failed;
    259         } else {
    260                 /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */
    261                 fstrcpy( dc_name, remote_machine );
    262         }
    263 
    264         /* if this next call fails, then give up.  We can't do
    265            password changes on BDC's  --jerry */
    266 
    267         if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname(), dc_name,
    268                                            NULL, 0,
    269                                            "IPC$", "IPC",
    270                                            "", "",
    271                                            "", 0, Undefined))) {
    272                 DEBUG(0,("modify_trust_password: Connection to %s failed!\n", dc_name));
    273                 nt_status = NT_STATUS_UNSUCCESSFUL;
    274                 goto failed;
    275         }
    276 
    277         /*
    278          * Ok - we have an anonymous connection to the IPC$ share.
    279          * Now start the NT Domain stuff :-).
    280          */
    281 
    282         /* Shouldn't we open this with schannel ? JRA. */
    283 
    284         nt_status = cli_rpc_pipe_open_noauth(
    285                 cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe);
    286         if (!NT_STATUS_IS_OK(nt_status)) {
    287                 DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n",
    288                         dc_name, nt_errstr(nt_status)));
    289                 cli_shutdown(cli);
    290                 cli = NULL;
    291                 goto failed;
    292         }
    293 
    294         nt_status = trust_pw_find_change_and_store_it(
    295                 netlogon_pipe, netlogon_pipe, domain);
    296 
    297         cli_shutdown(cli);
    298         cli = NULL;
    299 
    300 failed:
    301         if (!NT_STATUS_IS_OK(nt_status)) {
    302                 DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n",
    303                         current_timestring(talloc_tos(), False), domain));
    304         }
    305         else
    306                 DEBUG(5,("change_trust_account_password: sucess!\n"));
    307 
    308         return nt_status;
    309 }
Note: See TracChangeset for help on using the changeset viewer.