remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / kdc / 524.c
blob225594e6fcd14f97d2e01f0daabd57fe8215f782
1 /*
2 * Copyright (c) 1997-2003 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 "kdc_locl.h"
36 RCSID("$Id: 524.c,v 1.29 2003/03/17 05:35:47 assar Exp $");
38 #ifndef KRB4
39 #include <krb5-v4compat.h>
40 #endif
43 * fetch the server from `t', returning the name in malloced memory in
44 * `spn' and the entry itself in `server'
47 static krb5_error_code
48 fetch_server (const Ticket *t,
49 char **spn,
50 hdb_entry **server,
51 const char *from)
53 krb5_error_code ret;
54 krb5_principal sprinc;
56 ret = principalname2krb5_principal(&sprinc, t->sname, t->realm);
57 if (ret) {
58 kdc_log(0, "principalname2krb5_principal: %s",
59 krb5_get_err_text(context, ret));
60 return ret;
62 ret = krb5_unparse_name(context, sprinc, spn);
63 if (ret) {
64 krb5_free_principal(context, sprinc);
65 kdc_log(0, "krb5_unparse_name: %s", krb5_get_err_text(context, ret));
66 return ret;
68 ret = db_fetch(sprinc, server);
69 krb5_free_principal(context, sprinc);
70 if (ret) {
71 kdc_log(0,
72 "Request to convert ticket from %s for unknown principal %s: %s",
73 from, *spn, krb5_get_err_text(context, ret));
74 if (ret == HDB_ERR_NOENTRY)
75 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
76 return ret;
78 return 0;
81 static krb5_error_code
82 log_524 (const EncTicketPart *et,
83 const char *from,
84 const char *spn)
86 krb5_principal client;
87 char *cpn;
88 krb5_error_code ret;
90 ret = principalname2krb5_principal(&client, et->cname, et->crealm);
91 if (ret) {
92 kdc_log(0, "principalname2krb5_principal: %s",
93 krb5_get_err_text (context, ret));
94 return ret;
96 ret = krb5_unparse_name(context, client, &cpn);
97 if (ret) {
98 krb5_free_principal(context, client);
99 kdc_log(0, "krb5_unparse_name: %s",
100 krb5_get_err_text (context, ret));
101 return ret;
103 kdc_log(1, "524-REQ %s from %s for %s", cpn, from, spn);
104 free(cpn);
105 krb5_free_principal(context, client);
106 return 0;
109 static krb5_error_code
110 verify_flags (const EncTicketPart *et,
111 const char *spn)
113 if(et->endtime < kdc_time){
114 kdc_log(0, "Ticket expired (%s)", spn);
115 return KRB5KRB_AP_ERR_TKT_EXPIRED;
117 if(et->flags.invalid){
118 kdc_log(0, "Ticket not valid (%s)", spn);
119 return KRB5KRB_AP_ERR_TKT_NYV;
121 return 0;
125 * set the `et->caddr' to the most appropriate address to use, where
126 * `addr' is the address the request was received from.
129 static krb5_error_code
130 set_address (EncTicketPart *et,
131 struct sockaddr *addr,
132 const char *from)
134 krb5_error_code ret;
135 krb5_address *v4_addr;
137 v4_addr = malloc (sizeof(*v4_addr));
138 if (v4_addr == NULL)
139 return ENOMEM;
141 ret = krb5_sockaddr2address(context, addr, v4_addr);
142 if(ret) {
143 free (v4_addr);
144 kdc_log(0, "Failed to convert address (%s)", from);
145 return ret;
148 if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) {
149 kdc_log(0, "Incorrect network address (%s)", from);
150 krb5_free_address(context, v4_addr);
151 free (v4_addr);
152 return KRB5KRB_AP_ERR_BADADDR;
154 if(v4_addr->addr_type == KRB5_ADDRESS_INET) {
155 /* we need to collapse the addresses in the ticket to a
156 single address; best guess is to use the address the
157 connection came from */
159 if (et->caddr != NULL) {
160 free_HostAddresses(et->caddr);
161 } else {
162 et->caddr = malloc (sizeof (*et->caddr));
163 if (et->caddr == NULL) {
164 krb5_free_address(context, v4_addr);
165 free(v4_addr);
166 return ENOMEM;
169 et->caddr->val = v4_addr;
170 et->caddr->len = 1;
171 } else {
172 krb5_free_address(context, v4_addr);
173 free(v4_addr);
175 return 0;
179 static krb5_error_code
180 encrypt_v4_ticket(void *buf,
181 size_t len,
182 krb5_keyblock *skey,
183 EncryptedData *reply)
185 krb5_crypto crypto;
186 krb5_error_code ret;
187 ret = krb5_crypto_init(context, skey, ETYPE_DES_PCBC_NONE, &crypto);
188 if (ret) {
189 free(buf);
190 kdc_log(0, "krb5_crypto_init failed: %s",
191 krb5_get_err_text(context, ret));
192 return ret;
195 ret = krb5_encrypt_EncryptedData(context,
196 crypto,
197 KRB5_KU_TICKET,
198 buf,
199 len,
201 reply);
202 krb5_crypto_destroy(context, crypto);
203 if(ret) {
204 kdc_log(0, "Failed to encrypt data: %s",
205 krb5_get_err_text(context, ret));
206 return ret;
208 return 0;
211 static krb5_error_code
212 encode_524_response(const char *spn, const EncTicketPart et, const Ticket *t,
213 hdb_entry *server, EncryptedData *ticket, int *kvno)
215 krb5_error_code ret;
216 int use_2b;
217 size_t len;
219 use_2b = krb5_config_get_bool(context, NULL, "kdc", "use_2b", spn, NULL);
220 if(use_2b) {
221 ASN1_MALLOC_ENCODE(EncryptedData,
222 ticket->cipher.data, ticket->cipher.length,
223 &t->enc_part, &len, ret);
225 if (ret) {
226 kdc_log(0, "Failed to encode v4 (2b) ticket (%s)", spn);
227 return ret;
230 ticket->etype = 0;
231 ticket->kvno = NULL;
232 *kvno = 213; /* 2b's use this magic kvno */
233 } else {
234 unsigned char buf[MAX_KTXT_LEN + 4 * 4];
235 Key *skey;
237 if (!enable_v4_cross_realm && strcmp (et.crealm, t->realm) != 0) {
238 kdc_log(0, "524 cross-realm %s -> %s disabled", et.crealm,
239 t->realm);
240 return KRB5KDC_ERR_POLICY;
243 ret = encode_v4_ticket(buf + sizeof(buf) - 1, sizeof(buf),
244 &et, &t->sname, &len);
245 if(ret){
246 kdc_log(0, "Failed to encode v4 ticket (%s)", spn);
247 return ret;
249 ret = get_des_key(server, TRUE, FALSE, &skey);
250 if(ret){
251 kdc_log(0, "no suitable DES key for server (%s)", spn);
252 return ret;
254 ret = encrypt_v4_ticket(buf + sizeof(buf) - len, len,
255 &skey->key, ticket);
256 if(ret){
257 kdc_log(0, "Failed to encrypt v4 ticket (%s)", spn);
258 return ret;
260 *kvno = server->kvno;
263 return 0;
267 * process a 5->4 request, based on `t', and received `from, addr',
268 * returning the reply in `reply'
271 krb5_error_code
272 do_524(const Ticket *t, krb5_data *reply,
273 const char *from, struct sockaddr *addr)
275 krb5_error_code ret = 0;
276 krb5_crypto crypto;
277 hdb_entry *server = NULL;
278 Key *skey;
279 krb5_data et_data;
280 EncTicketPart et;
281 EncryptedData ticket;
282 krb5_storage *sp;
283 char *spn = NULL;
284 unsigned char buf[MAX_KTXT_LEN + 4 * 4];
285 size_t len;
286 int kvno;
288 if(!enable_524) {
289 ret = KRB5KDC_ERR_POLICY;
290 kdc_log(0, "Rejected ticket conversion request from %s", from);
291 goto out;
294 ret = fetch_server (t, &spn, &server, from);
295 if (ret) {
296 goto out;
299 ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey);
300 if(ret){
301 kdc_log(0, "No suitable key found for server (%s) from %s", spn, from);
302 goto out;
304 ret = krb5_crypto_init(context, &skey->key, 0, &crypto);
305 if (ret) {
306 kdc_log(0, "krb5_crypto_init failed: %s",
307 krb5_get_err_text(context, ret));
308 goto out;
310 ret = krb5_decrypt_EncryptedData (context,
311 crypto,
312 KRB5_KU_TICKET,
313 &t->enc_part,
314 &et_data);
315 krb5_crypto_destroy(context, crypto);
316 if(ret){
317 kdc_log(0, "Failed to decrypt ticket from %s for %s", from, spn);
318 goto out;
320 ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length,
321 &et, &len);
322 krb5_data_free(&et_data);
323 if(ret){
324 kdc_log(0, "Failed to decode ticket from %s for %s", from, spn);
325 goto out;
328 ret = log_524 (&et, from, spn);
329 if (ret) {
330 free_EncTicketPart(&et);
331 goto out;
334 ret = verify_flags (&et, spn);
335 if (ret) {
336 free_EncTicketPart(&et);
337 goto out;
340 ret = set_address (&et, addr, from);
341 if (ret) {
342 free_EncTicketPart(&et);
343 goto out;
346 ret = encode_524_response(spn, et, t, server, &ticket, &kvno);
347 free_EncTicketPart(&et);
349 out:
350 /* make reply */
351 memset(buf, 0, sizeof(buf));
352 sp = krb5_storage_from_mem(buf, sizeof(buf));
353 krb5_store_int32(sp, ret);
354 if(ret == 0){
355 krb5_store_int32(sp, kvno);
356 krb5_store_data(sp, ticket.cipher);
357 /* Aargh! This is coded as a KTEXT_ST. */
358 krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR);
359 krb5_store_int32(sp, 0); /* mbz */
360 free_EncryptedData(&ticket);
362 ret = krb5_storage_to_data(sp, reply);
363 reply->length = krb5_storage_seek(sp, 0, SEEK_CUR);
364 krb5_storage_free(sp);
366 if(spn)
367 free(spn);
368 if(server)
369 free_ent (server);
370 return ret;