5 * Copyright 1990 by the Massachusetts Institute of Technology.
7 * For copying and distribution information, please see the file
13 #if !defined(lint) && !defined(SABER)
14 static char rcsid_get_in_tkt_c[] =
16 #endif /* !lint & !SABER */
18 #include <krb5/copyright.h>
19 #include <krb5/krb5.h>
20 #include <krb5/asn1.h>
21 #include <krb5/libos-proto.h>
22 #include <krb5/ext-proto.h>
25 All-purpose initial ticket routine, usually called via
26 krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
28 Attempts to get an initial ticket for creds->client to use server
29 creds->server, (realm is taken from creds->client), with options
30 options, requesting encryption type etype, and using
31 creds->times.starttime, creds->times.endtime, creds->times.renew_till
32 as from, till, and rtime. creds->times.renew_till is ignored unless
33 the RENEWABLE option is requested.
35 key_proc is called to fill in the key to be used for decryption.
36 keyseed is passed on to key_proc.
38 decrypt_proc is called to perform the decryption of the response (the
39 encrypted part is in dec_rep->enc_part; the decrypted part should be
40 allocated and filled into dec_rep->enc_part2
41 arg is passed on to decrypt_proc.
43 If addrs is non-NULL, it is used for the addresses requested. If it is
44 null, the system standard addresses are used.
46 A succesful call will place the ticket in the credentials cache ccache
47 and fill in creds with the ticket information used/returned..
49 returns system errors, encryption errors
54 extern krb5_deltat krb5_clockskew;
55 #define in_clock_skew(date) (abs((date)-request.ctime) < krb5_clockskew)
57 /* some typedef's for the function args to make things look a bit cleaner */
59 typedef krb5_error_code (*git_key_proc) PROTOTYPE((const krb5_keytype,
61 krb5_const_pointer ));
62 typedef krb5_error_code (*git_decrypt_proc) PROTOTYPE((const krb5_keyblock *,
66 krb5_get_in_tkt(DECLARG(const krb5_flags, options),
67 DECLARG(krb5_address * const *, addrs),
68 DECLARG(const krb5_enctype, etype),
69 DECLARG(const krb5_keytype, keytype),
70 DECLARG(git_key_proc, key_proc),
71 DECLARG(krb5_const_pointer, keyseed),
72 DECLARG(git_decrypt_proc, decrypt_proc),
73 DECLARG(krb5_const_pointer, decryptarg),
74 DECLARG(krb5_creds *, creds),
75 DECLARG(krb5_ccache, ccache))
76 OLDDECLARG(const krb5_flags, options)
77 OLDDECLARG(krb5_address * const *, addrs)
78 OLDDECLARG(const krb5_enctype, etype)
79 OLDDECLARG(const krb5_keytype, keytype)
80 OLDDECLARG(git_key_proc, key_proc)
81 OLDDECLARG(krb5_const_pointer, keyseed)
82 OLDDECLARG(git_decrypt_proc, decrypt_proc)
83 OLDDECLARG(krb5_const_pointer, decryptarg)
84 OLDDECLARG(krb5_creds *, creds)
85 OLDDECLARG(krb5_ccache, ccache)
88 krb5_kdc_rep *as_reply;
89 krb5_error *err_reply;
90 krb5_error_code retval;
93 krb5_keyblock *decrypt_key;
95 request.msg_type = KRB5_AS_REQ;
97 /* AS_REQ has no pre-authentication. */
98 request.padata_type = 0;
99 request.padata.data = 0;
100 request.padata.length = 0;
102 request.kdc_options = options;
103 request.client = creds->client;
104 request.server = creds->server;
106 request.from = creds->times.starttime;
107 request.till = creds->times.endtime;
108 request.rtime = creds->times.renew_till;
109 if (retval = krb5_timeofday(&request.ctime))
111 /* XXX we know they are the same size... */
112 request.nonce = (krb5_int32) request.ctime;
113 request.etype = etype;
114 request.addresses = (krb5_address **) addrs;
115 request.second_ticket = 0;
116 request.authorization_data = 0;
118 /* encode & send to KDC */
119 if (retval = encode_krb5_as_req(&request, &packet))
121 retval = krb5_sendto_kdc(packet, krb5_princ_realm(creds->client), &reply);
122 krb5_free_data(packet);
126 /* now decode the reply...could be error or as_rep */
128 if (!krb5_is_as_rep(&reply) && !krb5_is_krb_error(&reply))
129 return KRB5KRB_AP_ERR_MSG_TYPE;
130 if (retval = decode_krb5_as_rep(&reply, &as_reply)) {
131 if (decode_krb5_error(&reply, &err_reply))
132 return retval; /* some other reply--??? */
133 /* it was an error */
135 if ((err_reply->ctime != request.ctime) ||
136 !krb5_principal_compare(err_reply->server, request.server) ||
137 !krb5_principal_compare(err_reply->client, request.client))
138 retval = KRB5_KDCREP_MODIFIED;
140 retval = err_reply->error + ERROR_TABLE_BASE_krb5;
142 /* XXX somehow make error msg text available to application? */
144 krb5_free_error(err_reply);
148 /* it was a kdc_rep--decrypt & check */
150 /* generate the key */
151 if (retval = (*key_proc)(keytype, &decrypt_key, keyseed)) {
152 krb5_free_kdc_rep(as_reply);
156 retval = (*decrypt_proc)(decrypt_key, decryptarg, as_reply);
157 memset((char *)decrypt_key->contents, 0, decrypt_key->length);
158 krb5_free_keyblock(decrypt_key);
160 krb5_free_kdc_rep(as_reply);
164 /* check the contents for sanity: */
165 if (!krb5_principal_compare(as_reply->client, request.client)
166 || !krb5_principal_compare(as_reply->enc_part2->server, request.server)
167 || !krb5_principal_compare(as_reply->ticket->server, request.server)
168 || (request.nonce != as_reply->enc_part2->nonce)
169 /* XXX check for extraneous flags */
170 /* XXX || (!krb5_addresses_compare(addrs, as_reply->enc_part2->caddrs)) */
171 || ((request.from == 0) &&
172 !in_clock_skew(as_reply->enc_part2->times.starttime))
173 || ((request.from != 0) &&
174 (request.from != as_reply->enc_part2->times.starttime))
175 || ((request.till != 0) &&
176 (as_reply->enc_part2->times.endtime > request.till))
177 || ((request.kdc_options & KDC_OPT_RENEWABLE) &&
178 (request.rtime != 0) &&
179 (as_reply->enc_part2->times.renew_till > request.rtime))
180 || ((request.kdc_options & KDC_OPT_RENEWABLE_OK) &&
181 (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
182 (request.till != 0) &&
183 (as_reply->enc_part2->times.renew_till > request.till))
185 memset((char *)as_reply->enc_part2->session->contents, 0,
186 as_reply->enc_part2->session->length);
187 krb5_free_kdc_rep(as_reply);
188 return KRB5_KDCREP_MODIFIED;
191 /* XXX issue warning if as_reply->enc_part2->key_exp is nearby */
193 /* fill in the credentials */
194 if (retval = krb5_copy_keyblock(as_reply->enc_part2->session,
196 memset((char *)as_reply->enc_part2->session->contents, 0,
197 as_reply->enc_part2->session->length);
198 krb5_free_kdc_rep(as_reply);
201 #define cleanup_key() {memset((char *)creds->keyblock.contents, 0,\
202 creds->keyblock.length); \
203 free((char *)creds->keyblock.contents); \
204 creds->keyblock.contents = 0; \
205 creds->keyblock.length = 0;}
207 creds->times = as_reply->enc_part2->times;
208 creds->is_skey = FALSE; /* this is an AS_REQ, so cannot
209 be encrypted in skey */
210 creds->ticket_flags = as_reply->enc_part2->flags;
211 if (retval = krb5_copy_addresses(as_reply->enc_part2->caddrs,
212 &creds->addresses)) {
216 creds->second_ticket.length = 0;
217 creds->second_ticket.data = 0;
219 retval = encode_krb5_ticket(as_reply->ticket, &packet);
220 krb5_free_kdc_rep(as_reply);
222 krb5_free_address(creds->addresses);
226 creds->ticket = *packet;
227 free((char *) packet);
229 /* store it in the ccache! */
230 if (retval = krb5_cc_store_cred(ccache, creds)) {
231 /* clean up the pieces */
232 free((char *)creds->ticket.data);
233 krb5_free_address(creds->addresses);