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