2 * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
36 RCSID("$Id: 524.c,v 1.29 2003/03/17 05:35:47 assar Exp $");
39 #include <krb5-v4compat.h>
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
,
54 krb5_principal sprinc
;
56 ret
= principalname2krb5_principal(&sprinc
, t
->sname
, t
->realm
);
58 kdc_log(0, "principalname2krb5_principal: %s",
59 krb5_get_err_text(context
, ret
));
62 ret
= krb5_unparse_name(context
, sprinc
, spn
);
64 krb5_free_principal(context
, sprinc
);
65 kdc_log(0, "krb5_unparse_name: %s", krb5_get_err_text(context
, ret
));
68 ret
= db_fetch(sprinc
, server
);
69 krb5_free_principal(context
, sprinc
);
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
;
81 static krb5_error_code
82 log_524 (const EncTicketPart
*et
,
86 krb5_principal client
;
90 ret
= principalname2krb5_principal(&client
, et
->cname
, et
->crealm
);
92 kdc_log(0, "principalname2krb5_principal: %s",
93 krb5_get_err_text (context
, ret
));
96 ret
= krb5_unparse_name(context
, client
, &cpn
);
98 krb5_free_principal(context
, client
);
99 kdc_log(0, "krb5_unparse_name: %s",
100 krb5_get_err_text (context
, ret
));
103 kdc_log(1, "524-REQ %s from %s for %s", cpn
, from
, spn
);
105 krb5_free_principal(context
, client
);
109 static krb5_error_code
110 verify_flags (const EncTicketPart
*et
,
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
;
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
,
135 krb5_address
*v4_addr
;
137 v4_addr
= malloc (sizeof(*v4_addr
));
141 ret
= krb5_sockaddr2address(context
, addr
, v4_addr
);
144 kdc_log(0, "Failed to convert address (%s)", from
);
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
);
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
);
162 et
->caddr
= malloc (sizeof (*et
->caddr
));
163 if (et
->caddr
== NULL
) {
164 krb5_free_address(context
, v4_addr
);
169 et
->caddr
->val
= v4_addr
;
172 krb5_free_address(context
, v4_addr
);
179 static krb5_error_code
180 encrypt_v4_ticket(void *buf
,
183 EncryptedData
*reply
)
187 ret
= krb5_crypto_init(context
, skey
, ETYPE_DES_PCBC_NONE
, &crypto
);
190 kdc_log(0, "krb5_crypto_init failed: %s",
191 krb5_get_err_text(context
, ret
));
195 ret
= krb5_encrypt_EncryptedData(context
,
202 krb5_crypto_destroy(context
, crypto
);
204 kdc_log(0, "Failed to encrypt data: %s",
205 krb5_get_err_text(context
, ret
));
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
)
219 use_2b
= krb5_config_get_bool(context
, NULL
, "kdc", "use_2b", spn
, NULL
);
221 ASN1_MALLOC_ENCODE(EncryptedData
,
222 ticket
->cipher
.data
, ticket
->cipher
.length
,
223 &t
->enc_part
, &len
, ret
);
226 kdc_log(0, "Failed to encode v4 (2b) ticket (%s)", spn
);
232 *kvno
= 213; /* 2b's use this magic kvno */
234 unsigned char buf
[MAX_KTXT_LEN
+ 4 * 4];
237 if (!enable_v4_cross_realm
&& strcmp (et
.crealm
, t
->realm
) != 0) {
238 kdc_log(0, "524 cross-realm %s -> %s disabled", et
.crealm
,
240 return KRB5KDC_ERR_POLICY
;
243 ret
= encode_v4_ticket(buf
+ sizeof(buf
) - 1, sizeof(buf
),
244 &et
, &t
->sname
, &len
);
246 kdc_log(0, "Failed to encode v4 ticket (%s)", spn
);
249 ret
= get_des_key(server
, TRUE
, FALSE
, &skey
);
251 kdc_log(0, "no suitable DES key for server (%s)", spn
);
254 ret
= encrypt_v4_ticket(buf
+ sizeof(buf
) - len
, len
,
257 kdc_log(0, "Failed to encrypt v4 ticket (%s)", spn
);
260 *kvno
= server
->kvno
;
267 * process a 5->4 request, based on `t', and received `from, addr',
268 * returning the reply in `reply'
272 do_524(const Ticket
*t
, krb5_data
*reply
,
273 const char *from
, struct sockaddr
*addr
)
275 krb5_error_code ret
= 0;
277 hdb_entry
*server
= NULL
;
281 EncryptedData ticket
;
284 unsigned char buf
[MAX_KTXT_LEN
+ 4 * 4];
289 ret
= KRB5KDC_ERR_POLICY
;
290 kdc_log(0, "Rejected ticket conversion request from %s", from
);
294 ret
= fetch_server (t
, &spn
, &server
, from
);
299 ret
= hdb_enctype2key(context
, server
, t
->enc_part
.etype
, &skey
);
301 kdc_log(0, "No suitable key found for server (%s) from %s", spn
, from
);
304 ret
= krb5_crypto_init(context
, &skey
->key
, 0, &crypto
);
306 kdc_log(0, "krb5_crypto_init failed: %s",
307 krb5_get_err_text(context
, ret
));
310 ret
= krb5_decrypt_EncryptedData (context
,
315 krb5_crypto_destroy(context
, crypto
);
317 kdc_log(0, "Failed to decrypt ticket from %s for %s", from
, spn
);
320 ret
= krb5_decode_EncTicketPart(context
, et_data
.data
, et_data
.length
,
322 krb5_data_free(&et_data
);
324 kdc_log(0, "Failed to decode ticket from %s for %s", from
, spn
);
328 ret
= log_524 (&et
, from
, spn
);
330 free_EncTicketPart(&et
);
334 ret
= verify_flags (&et
, spn
);
336 free_EncTicketPart(&et
);
340 ret
= set_address (&et
, addr
, from
);
342 free_EncTicketPart(&et
);
346 ret
= encode_524_response(spn
, et
, t
, server
, &ticket
, &kvno
);
347 free_EncTicketPart(&et
);
351 memset(buf
, 0, sizeof(buf
));
352 sp
= krb5_storage_from_mem(buf
, sizeof(buf
));
353 krb5_store_int32(sp
, ret
);
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
);