drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / third_party / heimdal / lib / krb5 / mk_cred.c
blob41e858f8058834ba0ab9b096878fd854dc9b897d
1 /*
2 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
36 #define CHECKED_ALLOC(dst) do { \
37 if ((ALLOC(dst, 1)) == NULL) { \
38 ret = krb5_enomem(context); \
39 goto out; \
40 } \
41 } while (0)
43 #define CHECKED_COPY(cp_func, dst, src) do { \
44 if (cp_func(src, dst)) { \
45 ret = krb5_enomem(context); \
46 goto out; \
47 } \
48 } while (0)
49 #define CHECKED_COPY_PPC2KCI(cp_func, dst, src) \
50 CHECKED_COPY(cp_func, krb_cred_info->dst, &ppcreds[i]->src)
52 #define CHECKED_ALLOC_ASSIGN(dst, src) do { \
53 if ((ALLOC(dst, 1)) == NULL) { \
54 ret = krb5_enomem(context); \
55 goto out; \
56 } else \
57 *dst = src; \
58 } while (0)
59 #define CHECKED_ALLOC_ASSIGN_PPC2KCI(dst, src) \
60 CHECKED_ALLOC_ASSIGN(krb_cred_info->dst, ppcreds[i]->src)
62 #define CHECKED_ALLOC_COPY(cp_func, dst, src) do { \
63 if ((ALLOC(dst, 1)) == NULL || cp_func(src, dst)) { \
64 ret = krb5_enomem(context); \
65 goto out; \
66 } \
67 } while (0)
68 #define CHECKED_ALLOC_COPY_PPC2KCI(cp_func, dst, src) \
69 CHECKED_ALLOC_COPY(cp_func, krb_cred_info->dst, &ppcreds[i]->src)
71 /**
72 * Make a KRB-CRED PDU with N credentials.
74 * @param context A kerberos 5 context.
75 * @param auth_context The auth context with the key to encrypt the out_data.
76 * @param ppcreds A null-terminated array of credentials to forward.
77 * @param ppdata The output KRB-CRED (to be freed by caller).
78 * @param replay_data (unused).
80 * @return Return an error code or 0.
82 * @ingroup krb5_credential
85 /* ARGSUSED */
86 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
87 krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context,
88 krb5_creds **ppcreds, krb5_data **ppdata,
89 krb5_replay_data *replay_data)
91 krb5_error_code ret;
92 krb5_data out_data;
94 ret = _krb5_mk_ncred(context, auth_context, ppcreds, &out_data,
95 replay_data);
96 if (ret == 0) {
98 * MIT allocates the return structure for no good reason. We do
99 * likewise as, in this case, incompatibility is the greater evil.
101 *ppdata = calloc(1, sizeof(**ppdata));
102 if (*ppdata) {
103 **ppdata = out_data;
104 } else {
105 krb5_data_free(&out_data);
106 ret = krb5_enomem(context);
110 return ret;
113 /* ARGSUSED */
114 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
115 _krb5_mk_ncred(krb5_context context,
116 krb5_auth_context auth_context,
117 krb5_creds **ppcreds,
118 krb5_data *out_data,
119 krb5_replay_data *replay_data)
121 krb5_error_code ret;
122 EncKrbCredPart enc_krb_cred_part;
123 KrbCredInfo *krb_cred_info;
124 krb5_crypto crypto;
125 KRB_CRED cred;
126 unsigned char *buf = NULL;
127 size_t ncreds, i;
128 size_t buf_size;
129 size_t len;
132 * The ownership of 'buf' is re-assigned to a containing structure
133 * multiple times. We enforce an invariant, either buf is non-zero
134 * and we own it, or buf is zero and it is freed or some structure
135 * owns any storage previously allocated as 'buf'.
137 #define CHOWN_BUF(x, buf) do { (x) = (buf); (buf) = 0; } while (0)
138 #define DISOWN_BUF(buf) do { free(buf); (buf) = 0; } while (0)
140 for (ncreds = 0; ppcreds[ncreds]; ncreds++)
143 memset (&cred, 0, sizeof(cred));
144 memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part));
145 cred.pvno = 5;
146 cred.msg_type = krb_cred;
147 ALLOC_SEQ(&cred.tickets, ncreds);
148 if (cred.tickets.val == NULL) {
149 ret = krb5_enomem(context);
150 goto out;
152 ALLOC_SEQ(&enc_krb_cred_part.ticket_info, ncreds);
153 if (enc_krb_cred_part.ticket_info.val == NULL) {
154 ret = krb5_enomem(context);
155 goto out;
158 for (i = 0; i < ncreds; i++) {
159 ret = decode_Ticket(ppcreds[i]->ticket.data,
160 ppcreds[i]->ticket.length,
161 &cred.tickets.val[i],
162 &len);/* don't care about len */
163 if (ret)
164 goto out;
166 /* fill ticket_info.val[i] */
167 krb_cred_info = &enc_krb_cred_part.ticket_info.val[i];
169 CHECKED_COPY(copy_EncryptionKey,
170 &krb_cred_info->key, &ppcreds[i]->session);
171 CHECKED_ALLOC_COPY_PPC2KCI(copy_Realm, prealm, client->realm);
172 CHECKED_ALLOC_COPY_PPC2KCI(copy_PrincipalName, pname, client->name);
173 CHECKED_ALLOC_ASSIGN_PPC2KCI(flags, flags.b);
174 CHECKED_ALLOC_ASSIGN_PPC2KCI(authtime, times.authtime);
175 CHECKED_ALLOC_ASSIGN_PPC2KCI(starttime, times.starttime);
176 CHECKED_ALLOC_ASSIGN_PPC2KCI(endtime, times.endtime);
177 CHECKED_ALLOC_ASSIGN_PPC2KCI(renew_till, times.renew_till);
178 CHECKED_ALLOC_COPY_PPC2KCI(copy_Realm, srealm, server->realm);
179 CHECKED_ALLOC_COPY_PPC2KCI(copy_PrincipalName, sname, server->name);
180 CHECKED_ALLOC_COPY_PPC2KCI(copy_HostAddresses, caddr, addresses);
183 if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
184 krb5_timestamp sec;
185 int32_t usec;
187 krb5_us_timeofday (context, &sec, &usec);
189 CHECKED_ALLOC_ASSIGN(enc_krb_cred_part.timestamp, sec);
190 CHECKED_ALLOC_ASSIGN(enc_krb_cred_part.usec, usec);
191 } else {
192 enc_krb_cred_part.timestamp = NULL;
193 enc_krb_cred_part.usec = NULL;
194 /* XXX Er, shouldn't we set the seq nums?? */
197 /* XXX: Is this needed? */
198 if (auth_context->local_address && auth_context->local_port) {
199 ret = krb5_make_addrport(context,
200 &enc_krb_cred_part.s_address,
201 auth_context->local_address,
202 auth_context->local_port);
203 if (ret)
204 goto out;
207 /* XXX: Is this needed? */
208 if (auth_context->remote_address) {
209 if (auth_context->remote_port) {
211 * XXX: Should we be checking "no-addresses" for
212 * the receiving realm?
214 ret = krb5_make_addrport(context,
215 &enc_krb_cred_part.r_address,
216 auth_context->remote_address,
217 auth_context->remote_port);
218 if (ret)
219 goto out;
220 } else {
222 * XXX Ugly, make krb5_make_addrport() handle missing port
223 * number (i.e., port == 0), then remove this else.
225 CHECKED_ALLOC(enc_krb_cred_part.r_address);
226 ret = krb5_copy_address(context, auth_context->remote_address,
227 enc_krb_cred_part.r_address);
228 if (ret)
229 goto out;
233 /* encode EncKrbCredPart */
234 ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size,
235 &enc_krb_cred_part, &len, ret);
236 if (ret)
237 goto out;
240 * Some older of the MIT gssapi library used clear-text tickets
241 * (warped inside AP-REQ encryption), use the krb5_auth_context
242 * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those
243 * tickets. The session key is used otherwise to encrypt the
244 * forwarded ticket.
247 if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) {
248 cred.enc_part.etype = KRB5_ENCTYPE_NULL;
249 cred.enc_part.kvno = NULL;
250 CHOWN_BUF(cred.enc_part.cipher.data, buf);
251 cred.enc_part.cipher.length = buf_size;
252 } else {
254 * Here older versions then 0.7.2 of Heimdal used the local or
255 * remote subkey. That is wrong, the session key should be
256 * used. Heimdal 0.7.2 and newer have code to try both in the
257 * receiving end.
260 ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
261 if (ret == 0)
262 ret = krb5_encrypt_EncryptedData(context,
263 crypto,
264 KRB5_KU_KRB_CRED,
265 buf,
266 len,
268 &cred.enc_part);
269 if (ret)
270 goto out;
271 DISOWN_BUF(buf);
272 krb5_crypto_destroy(context, crypto);
275 ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret);
276 if (ret)
277 goto out;
279 CHOWN_BUF(out_data->data, buf);
280 out_data->length = len;
281 ret = 0;
283 out:
284 free_EncKrbCredPart(&enc_krb_cred_part);
285 free_KRB_CRED(&cred);
286 free(buf);
287 return ret;
291 * Make a KRB-CRED PDU with 1 credential.
293 * @param context A kerberos 5 context.
294 * @param auth_context The auth context with the key to encrypt the out_data.
295 * @param ppcred A credential to forward.
296 * @param ppdata The output KRB-CRED (to be freed by caller).
297 * @param replay_data (unused).
299 * @return Return an error code or 0.
301 * @ingroup krb5_credential
304 /* ARGSUSED */
305 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
306 krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context,
307 krb5_creds *ppcred, krb5_data **ppdata,
308 krb5_replay_data *replay_data)
310 krb5_creds *ppcreds[2] = { ppcred, NULL };
312 return krb5_mk_ncred(context, auth_context, ppcreds, ppdata, replay_data);
315 /* ARGSUSED */
316 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
317 _krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context,
318 krb5_creds *ppcred, krb5_data *ppdata,
319 krb5_replay_data *replay_data)
321 krb5_creds *ppcreds[2] = { ppcred, NULL };
323 return _krb5_mk_ncred(context, auth_context, ppcreds, ppdata, replay_data);