FreeRDP
krb5glue_heimdal.c
1 
20 #ifndef WITH_KRB5_HEIMDAL
21 #error "This file must ony be included with HEIMDAL kerberos"
22 #endif
23 
24 #include <winpr/endian.h>
25 #include <winpr/wlog.h>
26 #include <winpr/assert.h>
27 #include "krb5glue.h"
28 
29 void krb5glue_keys_free(krb5_context ctx, struct krb5glue_keyset* keyset)
30 {
31  if (!ctx || !keyset)
32  return;
33  if (keyset->session_key)
34  krb5_crypto_destroy(ctx, keyset->session_key);
35  if (keyset->initiator_key)
36  krb5_crypto_destroy(ctx, keyset->initiator_key);
37  if (keyset->acceptor_key)
38  krb5_crypto_destroy(ctx, keyset->acceptor_key);
39 }
40 
41 krb5_error_code krb5glue_update_keyset(krb5_context ctx, krb5_auth_context auth_ctx, BOOL acceptor,
42  struct krb5glue_keyset* keyset)
43 {
44  krb5_keyblock* keyblock = NULL;
45  krb5_error_code rv = 0;
46 
47  WINPR_ASSERT(ctx);
48  WINPR_ASSERT(auth_ctx);
49  WINPR_ASSERT(keyset);
50 
51  krb5glue_keys_free(ctx, keyset);
52 
53  if (!(rv = krb5_auth_con_getkey(ctx, auth_ctx, &keyblock)))
54  {
55  krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->session_key);
56  krb5_free_keyblock(ctx, keyblock);
57  keyblock = NULL;
58  }
59 
60  if (acceptor)
61  rv = krb5_auth_con_getremotesubkey(ctx, auth_ctx, &keyblock);
62  else
63  rv = krb5_auth_con_getlocalsubkey(ctx, auth_ctx, &keyblock);
64 
65  if (!rv && keyblock)
66  {
67  krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->initiator_key);
68  krb5_free_keyblock(ctx, keyblock);
69  keyblock = NULL;
70  }
71 
72  if (acceptor)
73  rv = krb5_auth_con_getlocalsubkey(ctx, auth_ctx, &keyblock);
74  else
75  rv = krb5_auth_con_getremotesubkey(ctx, auth_ctx, &keyblock);
76 
77  if (!rv && keyblock)
78  {
79  krb5_crypto_init(ctx, keyblock, ENCTYPE_NULL, &keyset->acceptor_key);
80  krb5_free_keyblock(ctx, keyblock);
81  }
82 
83  return rv;
84 }
85 
86 krb5_error_code krb5glue_verify_checksum_iov(krb5_context ctx, krb5glue_key key, unsigned usage,
87  krb5_crypto_iov* iov, unsigned int iov_size,
88  krb5_boolean* is_valid)
89 {
90  krb5_error_code rv = 0;
91 
92  WINPR_ASSERT(ctx);
93  WINPR_ASSERT(key);
94  WINPR_ASSERT(is_valid);
95 
96  rv = krb5_verify_checksum_iov(ctx, key, usage, iov, iov_size, NULL);
97  *is_valid = (rv == 0);
98  return rv;
99 }
100 
101 krb5_error_code krb5glue_crypto_length(krb5_context ctx, krb5glue_key key, int type,
102  unsigned int* size)
103 {
104  krb5_error_code rv = 0;
105  size_t s = 0;
106 
107  WINPR_ASSERT(ctx);
108  WINPR_ASSERT(key);
109  WINPR_ASSERT(size);
110 
111  rv = krb5_crypto_length(ctx, key, type, &s);
112  *size = (UINT)s;
113  return rv;
114 }
115 
116 krb5_error_code krb5glue_log_error(krb5_context ctx, krb5_data* msg, const char* tag)
117 {
118  krb5_error error = { 0 };
119  krb5_error_code rv = 0;
120 
121  WINPR_ASSERT(ctx);
122  WINPR_ASSERT(msg);
123  WINPR_ASSERT(tag);
124 
125  if (!(rv = krb5_rd_error(ctx, msg, &error)))
126  {
127  WLog_ERR(tag, "KRB_ERROR: %" PRIx32, error.error_code);
128  krb5_free_error_contents(ctx, &error);
129  }
130  return rv;
131 }
132 
133 BOOL krb5glue_authenticator_validate_chksum(krb5glue_authenticator authenticator, int cksumtype,
134  uint32_t* flags)
135 {
136  WINPR_ASSERT(flags);
137 
138  if (!authenticator || !authenticator->cksum || authenticator->cksum->cksumtype != cksumtype ||
139  authenticator->cksum->checksum.length < 24)
140  return FALSE;
141 
142  const BYTE* data = authenticator->cksum->checksum.data;
143  Data_Read_UINT32((data + 20), (*flags));
144  return TRUE;
145 }
146 
147 krb5_error_code krb5glue_get_init_creds(krb5_context ctx, krb5_principal princ, krb5_ccache ccache,
148  krb5_prompter_fct prompter, char* password,
149  SEC_WINPR_KERBEROS_SETTINGS* krb_settings)
150 {
151  krb5_error_code rv = 0;
152  krb5_deltat start_time = 0;
153  krb5_get_init_creds_opt* gic_opt = NULL;
154  krb5_init_creds_context creds_ctx = NULL;
155  krb5_creds creds = { 0 };
156 
157  WINPR_ASSERT(ctx);
158 
159  do
160  {
161  if ((rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt)) != 0)
162  break;
163 
164  krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
165  krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);
166 
167  if (krb_settings)
168  {
169  if (krb_settings->startTime)
170  start_time = krb_settings->startTime;
171  if (krb_settings->lifeTime)
172  krb5_get_init_creds_opt_set_tkt_life(gic_opt, krb_settings->lifeTime);
173  if (krb_settings->renewLifeTime)
174  krb5_get_init_creds_opt_set_renew_life(gic_opt, krb_settings->renewLifeTime);
175  if (krb_settings->withPac)
176  krb5_get_init_creds_opt_set_pac_request(ctx, gic_opt, TRUE);
177  if (krb_settings->pkinitX509Anchors || krb_settings->pkinitX509Identity)
178  {
179  if ((rv = krb5_get_init_creds_opt_set_pkinit(
180  ctx, gic_opt, princ, krb_settings->pkinitX509Identity,
181  krb_settings->pkinitX509Anchors, NULL, NULL, 0, prompter, password,
182  password)) != 0)
183  break;
184  }
185  }
186 
187  if ((rv = krb5_init_creds_init(ctx, princ, prompter, password, start_time, gic_opt,
188  &creds_ctx)) != 0)
189  break;
190  if ((rv = krb5_init_creds_set_password(ctx, creds_ctx, password)) != 0)
191  break;
192  if (krb_settings && krb_settings->armorCache)
193  {
194  krb5_ccache armor_cc = NULL;
195  if ((rv = krb5_cc_resolve(ctx, krb_settings->armorCache, &armor_cc)) != 0)
196  break;
197  if ((rv = krb5_init_creds_set_fast_ccache(ctx, creds_ctx, armor_cc)) != 0)
198  break;
199  krb5_cc_close(ctx, armor_cc);
200  }
201  if ((rv = krb5_init_creds_get(ctx, creds_ctx)) != 0)
202  break;
203  if ((rv = krb5_init_creds_get_creds(ctx, creds_ctx, &creds)) != 0)
204  break;
205  if ((rv = krb5_cc_store_cred(ctx, ccache, &creds)) != 0)
206  break;
207  } while (0);
208 
209  krb5_free_cred_contents(ctx, &creds);
210  krb5_init_creds_free(ctx, creds_ctx);
211  krb5_get_init_creds_opt_free(ctx, gic_opt);
212 
213  return rv;
214 }
215