Changeset 988 for vendor/current/source3/libsmb/trusts_util.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
-
vendor/current/source3/libsmb/trusts_util.c (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/libsmb/trusts_util.c
r740 r988 21 21 #include "includes.h" 22 22 #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" 25 24 #include "rpc_client/cli_netlogon.h" 26 25 #include "rpc_client/cli_pipe.h" … … 29 28 #include "passdb.h" 30 29 #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" 112 32 113 33 /********************************************************* … … 117 37 **********************************************************/ 118 38 119 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli, 120 TALLOC_CTX *mem_ctx, 121 const char *domain) 39 struct trust_pw_change_state { 40 struct g_lock_ctx *g_ctx; 41 char *g_lock_key; 42 }; 43 44 static int trust_pw_change_state_destructor(struct trust_pw_change_state *state) 122 45 { 123 unsigned char old_trust_passwd_hash[16]; 46 g_lock_unlock(state->g_ctx, state->g_lock_key); 47 return 0; 48 } 49 50 NTSTATUS 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; 124 61 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; 137 282 } 138 139 /*********************************************************************140 Enumerate the list of trusted domains from a DC141 *********************************************************************/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 do265 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 else306 DEBUG(5,("change_trust_account_password: sucess!\n"));307 308 return nt_status;309 }
Note:
See TracChangeset
for help on using the changeset viewer.
