/src/samba/auth/credentials/credentials_gmsa.c
Line | Count | Source (jump to first uncovered line) |
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 | | 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 | 0 | { |
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 | 0 | 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 | 0 | cli_credentials_set_secure_channel_type(creds, SEC_CHAN_WKSTA); |
51 | |
|
52 | 0 | ndr_err = ndr_pull_struct_blob_all(managed_password_blob, |
53 | 0 | frame, |
54 | 0 | &managed_password, |
55 | 0 | (ndr_pull_flags_fn_t)ndr_pull_MANAGEDPASSWORD_BLOB); |
56 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
57 | 0 | *error_string = talloc_asprintf(creds, |
58 | 0 | "Failed to parse msDS-ManagedPassword " |
59 | 0 | "as MANAGEDPASSWORD_BLOB"); |
60 | 0 | TALLOC_FREE(frame); |
61 | 0 | return NT_STATUS_ILL_FORMED_PASSWORD; |
62 | 0 | } |
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 | 0 | only_use_previous_pw = |
70 | 0 | managed_password.passwords.query_interval != NULL |
71 | 0 | && *managed_password.passwords.query_interval <= gkdi_max_clock_skew |
72 | 0 | && 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 | 0 | 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 | 0 | 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 | 0 | } |
100 | |
|
101 | 0 | } |
102 | | |
103 | 0 | if (only_use_previous_pw) { |
104 | 0 | *error_string = talloc_asprintf(creds, |
105 | 0 | "No old password but new password is too new " |
106 | 0 | "(< 5min) in msDS-ManagedPassword " |
107 | 0 | "MANAGEDPASSWORD_BLOB"); |
108 | 0 | TALLOC_FREE(frame); |
109 | 0 | return NT_STATUS_ILL_FORMED_PASSWORD; |
110 | 0 | } |
111 | | |
112 | 0 | if (managed_password.passwords.current == NULL) { |
113 | 0 | *error_string = talloc_asprintf(creds, |
114 | 0 | "Failed to find new password in msDS-ManagedPassword " |
115 | 0 | "MANAGEDPASSWORD_BLOB"); |
116 | 0 | TALLOC_FREE(frame); |
117 | 0 | return NT_STATUS_ILL_FORMED_PASSWORD; |
118 | 0 | } |
119 | | |
120 | 0 | managed_pw_utf16 |
121 | 0 | = data_blob_const(managed_password.passwords.current, |
122 | 0 | utf16_len(managed_password.passwords.current)); |
123 | |
|
124 | 0 | cli_credentials_set_utf16_password(creds, &managed_pw_utf16, |
125 | 0 | CRED_SPECIFIED); |
126 | |
|
127 | 0 | TALLOC_FREE(frame); |
128 | 0 | return NT_STATUS_OK; |
129 | 0 | } |