2 * Copyright (c) 1997-2002 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
41 * fetch the server from `t', returning the name in malloced memory in
42 * `spn' and the entry itself in `server'
45 static krb5_error_code
46 fetch_server (const Ticket
*t
,
52 krb5_principal sprinc
;
54 ret
= principalname2krb5_principal(&sprinc
, t
->sname
, t
->realm
);
56 kdc_log(0, "principalname2krb5_principal: %s",
57 krb5_get_err_text(context
, ret
));
60 ret
= krb5_unparse_name(context
, sprinc
, spn
);
62 krb5_free_principal(context
, sprinc
);
63 kdc_log(0, "krb5_unparse_name: %s", krb5_get_err_text(context
, ret
));
66 ret
= db_fetch(sprinc
, server
);
67 krb5_free_principal(context
, sprinc
);
70 "Request to convert ticket from %s for unknown principal %s: %s",
71 from
, *spn
, krb5_get_err_text(context
, ret
));
72 if (ret
== HDB_ERR_NOENTRY
)
73 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
79 static krb5_error_code
80 log_524 (const EncTicketPart
*et
,
84 krb5_principal client
;
88 ret
= principalname2krb5_principal(&client
, et
->cname
, et
->crealm
);
90 kdc_log(0, "principalname2krb5_principal: %s",
91 krb5_get_err_text (context
, ret
));
94 ret
= krb5_unparse_name(context
, client
, &cpn
);
96 krb5_free_principal(context
, client
);
97 kdc_log(0, "krb5_unparse_name: %s",
98 krb5_get_err_text (context
, ret
));
101 kdc_log(1, "524-REQ %s from %s for %s", cpn
, from
, spn
);
103 krb5_free_principal(context
, client
);
107 static krb5_error_code
108 verify_flags (const EncTicketPart
*et
,
111 if(et
->endtime
< kdc_time
){
112 kdc_log(0, "Ticket expired (%s)", spn
);
113 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
115 if(et
->flags
.invalid
){
116 kdc_log(0, "Ticket not valid (%s)", spn
);
117 return KRB5KRB_AP_ERR_TKT_NYV
;
123 * set the `et->caddr' to the most appropriate address to use, where
124 * `addr' is the address the request was received from.
127 static krb5_error_code
128 set_address (EncTicketPart
*et
,
129 struct sockaddr
*addr
,
133 krb5_address
*v4_addr
;
135 v4_addr
= malloc (sizeof(*v4_addr
));
139 ret
= krb5_sockaddr2address(context
, addr
, v4_addr
);
142 kdc_log(0, "Failed to convert address (%s)", from
);
146 if (et
->caddr
&& !krb5_address_search (context
, v4_addr
, et
->caddr
)) {
147 kdc_log(0, "Incorrect network address (%s)", from
);
148 krb5_free_address(context
, v4_addr
);
150 return KRB5KRB_AP_ERR_BADADDR
;
152 if(v4_addr
->addr_type
== KRB5_ADDRESS_INET
) {
153 /* we need to collapse the addresses in the ticket to a
154 single address; best guess is to use the address the
155 connection came from */
157 if (et
->caddr
!= NULL
) {
158 free_HostAddresses(et
->caddr
);
160 et
->caddr
= malloc (sizeof (*et
->caddr
));
161 if (et
->caddr
== NULL
) {
162 krb5_free_address(context
, v4_addr
);
167 et
->caddr
->val
= v4_addr
;
170 krb5_free_address(context
, v4_addr
);
177 * process a 5->4 request, based on `t', and received `from, addr',
178 * returning the reply in `reply'
182 do_524(const Ticket
*t
, krb5_data
*reply
,
183 const char *from
, struct sockaddr
*addr
)
185 krb5_error_code ret
= 0;
187 hdb_entry
*server
= NULL
;
191 EncryptedData ticket
;
194 unsigned char buf
[MAX_KTXT_LEN
+ 4 * 4];
198 ret
= KRB5KDC_ERR_POLICY
;
199 kdc_log(0, "Rejected ticket conversion request from %s", from
);
203 ret
= fetch_server (t
, &spn
, &server
, from
);
208 ret
= hdb_enctype2key(context
, server
, t
->enc_part
.etype
, &skey
);
210 kdc_log(0, "No suitable key found for server (%s) from %s", spn
, from
);
213 ret
= krb5_crypto_init(context
, &skey
->key
, 0, &crypto
);
215 kdc_log(0, "krb5_crypto_init failed: %s",
216 krb5_get_err_text(context
, ret
));
219 ret
= krb5_decrypt_EncryptedData (context
,
224 krb5_crypto_destroy(context
, crypto
);
226 kdc_log(0, "Failed to decrypt ticket from %s for %s", from
, spn
);
229 ret
= krb5_decode_EncTicketPart(context
, et_data
.data
, et_data
.length
,
231 krb5_data_free(&et_data
);
233 kdc_log(0, "Failed to decode ticket from %s for %s", from
, spn
);
237 ret
= log_524 (&et
, from
, spn
);
239 free_EncTicketPart(&et
);
243 ret
= verify_flags (&et
, spn
);
245 free_EncTicketPart(&et
);
249 ret
= set_address (&et
, addr
, from
);
251 free_EncTicketPart(&et
);
254 if (!enable_v4_cross_realm
&& strcmp (et
.crealm
, t
->realm
) != 0) {
255 kdc_log(0, "524 cross-realm %s -> %s disabled", et
.crealm
,
257 return KRB5KDC_ERR_POLICY
;
260 ret
= encode_v4_ticket(buf
+ sizeof(buf
) - 1, sizeof(buf
),
261 &et
, &t
->sname
, &len
);
262 free_EncTicketPart(&et
);
264 kdc_log(0, "Failed to encode v4 ticket (%s)", spn
);
267 ret
= get_des_key(server
, TRUE
, FALSE
, &skey
);
269 kdc_log(0, "no suitable DES key for server (%s)", spn
);
272 ret
= encrypt_v4_ticket(buf
+ sizeof(buf
) - len
, len
,
273 skey
->key
.keyvalue
.data
, &ticket
);
275 kdc_log(0, "Failed to encrypt v4 ticket (%s)", spn
);
280 memset(buf
, 0, sizeof(buf
));
281 sp
= krb5_storage_from_mem(buf
, sizeof(buf
));
282 krb5_store_int32(sp
, ret
);
284 krb5_store_int32(sp
, server
->kvno
); /* is this right? */
285 krb5_store_data(sp
, ticket
.cipher
);
286 /* Aargh! This is coded as a KTEXT_ST. */
287 krb5_storage_seek(sp
, MAX_KTXT_LEN
- ticket
.cipher
.length
, SEEK_CUR
);
288 krb5_store_int32(sp
, 0); /* mbz */
289 free_EncryptedData(&ticket
);
291 ret
= krb5_storage_to_data(sp
, reply
);
292 reply
->length
= krb5_storage_seek(sp
, 0, SEEK_CUR
);
293 krb5_storage_free(sp
);