1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 #include "k5-int.h"
6 #include "cleanup.h"
7 #include "auth_con.h"
8
9 #include <stddef.h> /* NULL */
10 #include <stdlib.h> /* malloc */
11 #include <errno.h> /* ENOMEM */
12
13 /*-------------------- decrypt_credencdata --------------------*/
14
15 /*
16 * decrypt the enc_part of a krb5_cred
17 */
18 /*ARGSUSED*/
19 static krb5_error_code
decrypt_credencdata(krb5_context context,krb5_cred * pcred,krb5_keyblock * pkeyblock,krb5_cred_enc_part * pcredenc)20 decrypt_credencdata(krb5_context context, krb5_cred *pcred, krb5_keyblock *pkeyblock, krb5_cred_enc_part *pcredenc)
21 {
22 krb5_cred_enc_part * ppart = NULL;
23 krb5_error_code retval;
24 krb5_data scratch;
25
26 scratch.length = pcred->enc_part.ciphertext.length;
27 if (!(scratch.data = (char *)malloc(scratch.length)))
28 return ENOMEM;
29
30 if (pkeyblock != NULL) {
31 if ((retval = krb5_c_decrypt(context, pkeyblock,
32 KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
33 &pcred->enc_part, &scratch)))
34 goto cleanup;
35 } else {
36 /* Solaris Kerberos */
37 (void) memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
38 }
39
40 /* now decode the decrypted stuff */
41 if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
42 goto cleanup;
43
44 *pcredenc = *ppart;
45 retval = 0;
46
47 cleanup:
48 if (ppart != NULL) {
49 memset(ppart, 0, sizeof(*ppart));
50 krb5_xfree(ppart);
51 }
52 /* Solaris Kerberos */
53 (void) memset(scratch.data, 0, scratch.length);
54 krb5_xfree(scratch.data);
55
56 return retval;
57 }
58 /*----------------------- krb5_rd_cred_basic -----------------------*/
59
60 static krb5_error_code
krb5_rd_cred_basic(krb5_context context,krb5_data * pcreddata,krb5_keyblock * pkeyblock,krb5_replay_data * replaydata,krb5_creds *** pppcreds)61 krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata, krb5_keyblock *pkeyblock, krb5_replay_data *replaydata, krb5_creds ***pppcreds)
62 {
63 krb5_error_code retval;
64 krb5_cred * pcred;
65 krb5_int32 ncreds;
66 krb5_int32 i = 0;
67 krb5_cred_enc_part encpart;
68
69 /* decode cred message */
70 if ((retval = decode_krb5_cred(pcreddata, &pcred)))
71 return retval;
72
73 /* Solaris Kerberos */
74 (void) memset(&encpart, 0, sizeof(encpart));
75
76 if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
77 goto cleanup_cred;
78
79
80 replaydata->timestamp = encpart.timestamp;
81 replaydata->usec = encpart.usec;
82 replaydata->seq = encpart.nonce;
83
84 /*
85 * Allocate the list of creds. The memory is allocated so that
86 * krb5_free_tgt_creds can be used to free the list.
87 */
88 for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
89
90 if ((*pppcreds =
91 (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
92 (ncreds + 1)))) == NULL) {
93 retval = ENOMEM;
94 goto cleanup_cred;
95 }
96 (*pppcreds)[0] = NULL;
97
98 /*
99 * For each credential, create a strcture in the list of
100 * credentials and copy the information.
101 */
102 while (i < ncreds) {
103 krb5_cred_info * pinfo;
104 krb5_creds * pcur;
105 krb5_data * pdata;
106
107 if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
108 retval = ENOMEM;
109 goto cleanup;
110 }
111
112 (*pppcreds)[i] = pcur;
113 (*pppcreds)[i+1] = 0;
114 pinfo = encpart.ticket_info[i++];
115 /* Solaris Kerberos */
116 (void) memset(pcur, 0, sizeof(krb5_creds));
117
118 if ((retval = krb5_copy_principal(context, pinfo->client,
119 &pcur->client)))
120 goto cleanup;
121
122 if ((retval = krb5_copy_principal(context, pinfo->server,
123 &pcur->server)))
124 goto cleanup;
125
126 if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
127 &pcur->keyblock)))
128 goto cleanup;
129
130 if ((retval = krb5_copy_addresses(context, pinfo->caddrs,
131 &pcur->addresses)))
132 goto cleanup;
133
134 if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
135 goto cleanup;
136
137 pcur->ticket = *pdata;
138 krb5_xfree(pdata);
139
140
141 pcur->is_skey = FALSE;
142 pcur->magic = KV5M_CREDS;
143 pcur->times = pinfo->times;
144 pcur->ticket_flags = pinfo->flags;
145 pcur->authdata = NULL; /* not used */
146 /* Solaris Kerberos */
147 (void) memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
148 }
149
150 /*
151 * NULL terminate the list
152 */
153 (*pppcreds)[i] = NULL;
154
155 cleanup:
156 if (retval)
157 krb5_free_tgt_creds(context, *pppcreds);
158
159 cleanup_cred:
160 krb5_free_cred(context, pcred);
161 krb5_free_cred_enc_part(context, &encpart);
162
163 return retval;
164 }
165
166 /*----------------------- krb5_rd_cred -----------------------*/
167
168
169 /*
170 * This functions takes as input an KRB_CRED message, validates it, and
171 * outputs the nonce and an array of the forwarded credentials.
172 */
173 krb5_error_code KRB5_CALLCONV
krb5_rd_cred(krb5_context context,krb5_auth_context auth_context,krb5_data * pcreddata,krb5_creds *** pppcreds,krb5_replay_data * outdata)174 krb5_rd_cred(krb5_context context, krb5_auth_context auth_context, krb5_data *pcreddata, krb5_creds ***pppcreds, krb5_replay_data *outdata)
175 {
176 krb5_error_code retval;
177 krb5_keyblock * keyblock;
178 krb5_replay_data replaydata;
179
180 /* Get keyblock */
181 if ((keyblock = auth_context->recv_subkey) == NULL)
182 keyblock = auth_context->keyblock;
183
184 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
185 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
186 (outdata == NULL))
187 /* Need a better error */
188 return KRB5_RC_REQUIRED;
189
190 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
191 (auth_context->rcache == NULL))
192 return KRB5_RC_REQUIRED;
193
194
195 /*
196 * If decrypting with the first keyblock we try fails, perhaps the
197 * credentials are stored in the session key so try decrypting with
198 * that.
199 */
200 if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock,
201 &replaydata, pppcreds))) {
202 if ((retval = krb5_rd_cred_basic(context, pcreddata,
203 auth_context->keyblock,
204 &replaydata, pppcreds))) {
205 return retval;
206 }
207 }
208
209 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
210 krb5_donot_replay replay;
211
212 if ((retval = krb5int_check_clockskew(context, replaydata.timestamp)))
213 goto error;
214
215 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
216 "_forw", &replay.client)))
217 goto error;
218
219 replay.server = ""; /* XXX */
220 replay.cusec = replaydata.usec;
221 replay.ctime = replaydata.timestamp;
222 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
223 krb5_xfree(replay.client);
224 goto error;
225 }
226 krb5_xfree(replay.client);
227 }
228
229 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
230 if (auth_context->remote_seq_number != replaydata.seq) {
231 retval = KRB5KRB_AP_ERR_BADORDER;
232 goto error;
233 }
234 auth_context->remote_seq_number++;
235 }
236
237 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
238 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
239 outdata->timestamp = replaydata.timestamp;
240 outdata->usec = replaydata.usec;
241 outdata->seq = replaydata.seq;
242 }
243
244 error:;
245 if (retval) {
246 krb5_free_tgt_creds(context, *pppcreds);
247 *pppcreds = NULL;
248 }
249 return retval;
250 }
251
252