Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : 4 : User credentials handling for Group Managed Service Accounts 5 : 6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2023 7 : 8 : This program is free software; you can redistribute it and/or modify 9 : it under the terms of the GNU General Public License as published by 10 : the Free Software Foundation; either version 3 of the License, or 11 : (at your option) any later version. 12 : 13 : This program is distributed in the hope that it will be useful, 14 : but WITHOUT ANY WARRANTY; without even the implied warranty of 15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 : GNU General Public License for more details. 17 : 18 : You should have received a copy of the GNU General Public License 19 : along with this program. If not, see <http://www.gnu.org/licenses/>. 20 : */ 21 : 22 : #include "includes.h" 23 : #include "librpc/gen_ndr/ndr_gmsa.h" /* for struct MANAGEDPASSWORD_BLOB */ 24 : #include "auth/credentials/credentials.h" 25 : #include "auth/credentials/credentials_internal.h" 26 : #include "lib/util/charset/charset.h" 27 : #include "lib/crypto/gkdi.h" 28 : /* 29 : * All current callers set "for_keytab = true", but if we start using 30 : * this for getting a TGT we need the logic to ignore a very new 31 : * key 32 : */ 33 2 : NTSTATUS cli_credentials_set_gmsa_passwords(struct cli_credentials *creds, 34 : const DATA_BLOB *managed_password_blob, 35 : bool for_keytab, 36 : const char **error_string) 37 : { 38 0 : struct MANAGEDPASSWORD_BLOB managed_password; 39 0 : DATA_BLOB managed_pw_utf16; 40 0 : DATA_BLOB previous_managed_pw_utf16; 41 0 : enum ndr_err_code ndr_err; 42 2 : TALLOC_CTX *frame = talloc_stackframe(); 43 0 : bool only_use_previous_pw; 44 : 45 : /* 46 : * Group Managed Service Accounts are type 47 : * UF_WORKSTATION_TRUST_ACCOUNT and will follow those salting 48 : * rules 49 : */ 50 2 : cli_credentials_set_secure_channel_type(creds, SEC_CHAN_WKSTA); 51 : 52 2 : ndr_err = ndr_pull_struct_blob_all(managed_password_blob, 53 : frame, 54 : &managed_password, 55 : (ndr_pull_flags_fn_t)ndr_pull_MANAGEDPASSWORD_BLOB); 56 2 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 57 0 : *error_string = talloc_asprintf(creds, 58 : "Failed to parse msDS-ManagedPassword " 59 : "as MANAGEDPASSWORD_BLOB"); 60 0 : TALLOC_FREE(frame); 61 0 : return NT_STATUS_ILL_FORMED_PASSWORD; 62 : } 63 : 64 : /* 65 : * We check if this is 'for keytab' as a keytab wants to know 66 : * about a near-future password as it will be on disk for some 67 : * time 68 : */ 69 2 : only_use_previous_pw = 70 2 : managed_password.passwords.query_interval != NULL 71 2 : && *managed_password.passwords.query_interval <= gkdi_max_clock_skew 72 4 : && for_keytab == false; 73 : 74 : /* 75 : * We look at the old password first as we might bail out 76 : * early if the new password is "too fresh" 77 : */ 78 2 : if (managed_password.passwords.previous) { 79 0 : previous_managed_pw_utf16 80 0 : = data_blob_const(managed_password.passwords.previous, 81 0 : utf16_len(managed_password.passwords.previous)); 82 : 83 0 : cli_credentials_set_old_utf16_password(creds, &previous_managed_pw_utf16); 84 : 85 0 : if (only_use_previous_pw) { 86 : /* We are in the 5 mins where we know the next 87 : * password, but it will not be available yet, just 88 : * use the old password for now. 89 : */ 90 0 : cli_credentials_set_utf16_password(creds, &previous_managed_pw_utf16, 91 : CRED_SPECIFIED); 92 : 93 : /* 94 : * We are done, the new password is of no 95 : * interest to us 96 : */ 97 0 : TALLOC_FREE(frame); 98 0 : return NT_STATUS_OK; 99 : } 100 : 101 : } 102 : 103 2 : if (only_use_previous_pw) { 104 0 : *error_string = talloc_asprintf(creds, 105 : "No old password but new password is too new " 106 : "(< 5min) in msDS-ManagedPassword " 107 : "MANAGEDPASSWORD_BLOB"); 108 0 : TALLOC_FREE(frame); 109 0 : return NT_STATUS_ILL_FORMED_PASSWORD; 110 : } 111 : 112 2 : if (managed_password.passwords.current == NULL) { 113 0 : *error_string = talloc_asprintf(creds, 114 : "Failed to find new password in msDS-ManagedPassword " 115 : "MANAGEDPASSWORD_BLOB"); 116 0 : TALLOC_FREE(frame); 117 0 : return NT_STATUS_ILL_FORMED_PASSWORD; 118 : } 119 : 120 0 : managed_pw_utf16 121 2 : = data_blob_const(managed_password.passwords.current, 122 2 : utf16_len(managed_password.passwords.current)); 123 : 124 2 : cli_credentials_set_utf16_password(creds, &managed_pw_utf16, 125 : CRED_SPECIFIED); 126 : 127 2 : TALLOC_FREE(frame); 128 2 : return NT_STATUS_OK; 129 : }