FreeRDP
Loading...
Searching...
No Matches
krb5glue_mit.c
1
20#ifndef WITH_KRB5_MIT
21#error "This file must only be included with MIT kerberos"
22#endif
23
24#include <string.h>
25
26#include <winpr/path.h>
27#include <winpr/wlog.h>
28#include <winpr/endian.h>
29#include <winpr/crypto.h>
30#include <winpr/print.h>
31#include <winpr/assert.h>
32#include <errno.h>
33#include "krb5glue.h"
34#include <profile.h>
35
36static char* create_temporary_file(void)
37{
38 BYTE buffer[32];
39 char* hex = nullptr;
40 char* path = nullptr;
41
42 if (winpr_RAND(buffer, sizeof(buffer)) < 0)
43 return nullptr;
44 hex = winpr_BinToHexString(buffer, sizeof(buffer), FALSE);
45 path = GetKnownSubPath(KNOWN_PATH_TEMP, hex);
46 free(hex);
47 return path;
48}
49
50void krb5glue_keys_free(krb5_context ctx, struct krb5glue_keyset* keyset)
51{
52 WINPR_ASSERT(ctx);
53 WINPR_ASSERT(keyset);
54
55 krb5_k_free_key(ctx, keyset->session_key);
56 krb5_k_free_key(ctx, keyset->initiator_key);
57 krb5_k_free_key(ctx, keyset->acceptor_key);
58}
59
60krb5_error_code krb5glue_update_keyset(krb5_context ctx, krb5_auth_context auth_ctx, BOOL acceptor,
61 struct krb5glue_keyset* keyset)
62{
63 WINPR_ASSERT(ctx);
64 WINPR_ASSERT(auth_ctx);
65 WINPR_ASSERT(keyset);
66
67 krb5glue_keys_free(ctx, keyset);
68 krb5_auth_con_getkey_k(ctx, auth_ctx, &keyset->session_key);
69 if (acceptor)
70 {
71 krb5_auth_con_getsendsubkey_k(ctx, auth_ctx, &keyset->acceptor_key);
72 krb5_auth_con_getrecvsubkey_k(ctx, auth_ctx, &keyset->initiator_key);
73 }
74 else
75 {
76 krb5_auth_con_getsendsubkey_k(ctx, auth_ctx, &keyset->initiator_key);
77 krb5_auth_con_getrecvsubkey_k(ctx, auth_ctx, &keyset->acceptor_key);
78 }
79 return 0;
80}
81
82krb5_prompt_type krb5glue_get_prompt_type(krb5_context ctx, krb5_prompt prompts[], int index)
83{
84 WINPR_ASSERT(ctx);
85 WINPR_ASSERT(prompts);
86 WINPR_UNUSED(prompts);
87
88 krb5_prompt_type* types = krb5_get_prompt_types(ctx);
89 return types ? types[index] : 0;
90}
91
92krb5_error_code krb5glue_log_error(krb5_context ctx, krb5_data* msg, const char* tag)
93{
94 krb5_error* error = nullptr;
95 krb5_error_code rv = 0;
96
97 WINPR_ASSERT(ctx);
98 WINPR_ASSERT(msg);
99 WINPR_ASSERT(tag);
100
101 if (!(rv = krb5_rd_error(ctx, msg, &error)))
102 {
103 WLog_ERR(tag, "KRB_ERROR: %s", error->text.data);
104 krb5_free_error(ctx, error);
105 }
106
107 return rv;
108}
109
110BOOL krb5glue_authenticator_validate_chksum(krb5glue_authenticator authenticator, int cksumtype,
111 uint32_t* flags)
112{
113 WINPR_ASSERT(flags);
114
115 if (!authenticator || !authenticator->checksum ||
116 authenticator->checksum->checksum_type != cksumtype || authenticator->checksum->length < 24)
117 return FALSE;
118 *flags = winpr_Data_Get_UINT32((authenticator->checksum->contents + 20));
119 return TRUE;
120}
121
122krb5_error_code krb5glue_get_init_creds(krb5_context ctx, krb5_principal princ, krb5_ccache ccache,
123 krb5_prompter_fct prompter, char* password,
124 SEC_WINPR_KERBEROS_SETTINGS* krb_settings)
125{
126 krb5_error_code rv = 0;
127 krb5_deltat start_time = 0;
128 krb5_get_init_creds_opt* gic_opt = nullptr;
129 krb5_init_creds_context creds_ctx = nullptr;
130 char* tmp_profile_path = create_temporary_file();
131 profile_t profile = nullptr;
132 BOOL is_temp_ctx = FALSE;
133
134 WINPR_ASSERT(ctx);
135
136 rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt);
137 if (rv)
138 goto cleanup;
139
140 krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
141 krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);
142
143 if (krb_settings)
144 {
145 if (krb_settings->startTime)
146 start_time = krb_settings->startTime;
147 if (krb_settings->lifeTime)
148 krb5_get_init_creds_opt_set_tkt_life(gic_opt, krb_settings->lifeTime);
149 if (krb_settings->renewLifeTime)
150 krb5_get_init_creds_opt_set_renew_life(gic_opt, krb_settings->renewLifeTime);
151 if (krb_settings->withPac)
152 {
153 rv = krb5_get_init_creds_opt_set_pac_request(ctx, gic_opt, TRUE);
154 if (rv)
155 goto cleanup;
156 }
157 if (krb_settings->armorCache)
158 {
159 rv = krb5_get_init_creds_opt_set_fast_ccache_name(ctx, gic_opt,
160 krb_settings->armorCache);
161 if (rv)
162 goto cleanup;
163 }
164 if (krb_settings->pkinitX509Identity)
165 {
166 rv = krb5_get_init_creds_opt_set_pa(ctx, gic_opt, "X509_user_identity",
167 krb_settings->pkinitX509Identity);
168 if (rv)
169 goto cleanup;
170 }
171 if (krb_settings->pkinitX509Anchors)
172 {
173 rv = krb5_get_init_creds_opt_set_pa(ctx, gic_opt, "X509_anchors",
174 krb_settings->pkinitX509Anchors);
175 if (rv)
176 goto cleanup;
177 }
178 if (krb_settings->kdcUrl && (strnlen(krb_settings->kdcUrl, 2) > 0))
179 {
180 const char* names[4] = WINPR_C_ARRAY_INIT;
181 char* realm = nullptr;
182 char* kdc_url = nullptr;
183 size_t size = 0;
184
185 if ((rv = krb5_get_profile(ctx, &profile)))
186 goto cleanup;
187
188 rv = ENOMEM;
189 if (winpr_asprintf(&kdc_url, &size, "https://%s/KdcProxy", krb_settings->kdcUrl) <= 0)
190 {
191 free(kdc_url);
192 goto cleanup;
193 }
194
195 realm = calloc(princ->realm.length + 1, 1);
196 if (!realm)
197 {
198 free(kdc_url);
199 goto cleanup;
200 }
201 CopyMemory(realm, princ->realm.data, princ->realm.length);
202
203 names[0] = "realms";
204 names[1] = realm;
205 names[2] = "kdc";
206
207 profile_clear_relation(profile, names);
208 profile_add_relation(profile, names, kdc_url);
209
210 /* Since we know who the KDC is, tell krb5 that its certificate is valid for pkinit */
211 names[2] = "pkinit_kdc_hostname";
212 profile_add_relation(profile, names, krb_settings->kdcUrl);
213
214 free(kdc_url);
215 free(realm);
216
217 long lrv = profile_flush_to_file(profile, tmp_profile_path);
218 if (lrv)
219 goto cleanup;
220
221 profile_abandon(profile);
222 profile = nullptr;
223 lrv = profile_init_path(tmp_profile_path, &profile);
224 if (lrv)
225 goto cleanup;
226
227 rv = krb5_init_context_profile(profile, 0, &ctx);
228 if (rv)
229 goto cleanup;
230 is_temp_ctx = TRUE;
231 }
232 }
233
234 if ((rv = krb5_get_init_creds_opt_set_in_ccache(ctx, gic_opt, ccache)))
235 goto cleanup;
236
237 if ((rv = krb5_get_init_creds_opt_set_out_ccache(ctx, gic_opt, ccache)))
238 goto cleanup;
239
240 if ((rv =
241 krb5_init_creds_init(ctx, princ, prompter, password, start_time, gic_opt, &creds_ctx)))
242 goto cleanup;
243
244 if ((rv = krb5_init_creds_get(ctx, creds_ctx)))
245 goto cleanup;
246
247cleanup:
248 krb5_init_creds_free(ctx, creds_ctx);
249 krb5_get_init_creds_opt_free(ctx, gic_opt);
250 if (is_temp_ctx)
251 krb5_free_context(ctx);
252 profile_abandon(profile);
253 winpr_DeleteFile(tmp_profile_path);
254 free(tmp_profile_path);
255
256 return rv;
257}
258