5 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
8 * Export of this software from the United States of America is assumed
9 * to require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. M.I.T. makes no representations about the suitability of
21 * this software for any purpose. It is provided "as is" without express
22 * or implied warranty.
25 * Get credentials from some KDC somewhere, possibly accumulating tgts
29 #if !defined(lint) && !defined(SABER)
30 static char rcsid_gcfkdc_c[] =
32 #endif /* !lint & !SABER */
35 #include <krb5/krb5.h>
36 #include <krb5/ext-proto.h>
37 #include "int-proto.h"
40 * Retrieve credentials for principal creds->client,
41 * server creds->server, ticket flags creds->ticket_flags, possibly
42 * second_ticket if needed by ticket_flags.
44 * Credentials are requested from the KDC for the server's realm. Any
45 * TGT credentials obtained in the process of contacting the KDC are
46 * returned in an array of credentials; tgts is filled in to point to an
47 * array of pointers to credential structures (if no TGT's were used, the
48 * pointer is zeroed). TGT's may be returned even if no useful end ticket
51 * The returned credentials are NOT cached.
53 * This routine should not be called if the credentials are already in
56 * If credentials are obtained, creds is filled in with the results;
57 * creds->ticket and creds->keyblock->key are set to allocated storage,
58 * which should be freed by the caller when finished.
60 * returns errors, system errors.
63 extern krb5_cksumtype krb5_kdc_req_sumtype;
65 /* helper function: convert flags to necessary KDC options */
66 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
69 krb5_get_cred_from_kdc (ccache, cred, tgts)
75 krb5_creds **ret_tgts = 0;
76 krb5_principal *tgs_list, *next_server;
77 krb5_principal final_server;
78 krb5_error_code retval;
80 int returning_tgt = 0;
83 /* in case we never get a TGT, zero the return */
87 * we know that the desired credentials aren't in the cache yet.
89 * To get them, we first need a tgt for the realm of the server.
90 * first, we see if we have such a TGT in cache.
94 * look for ticket with:
95 * client == cred->client,
96 * server == "krbtgt/realmof(cred->server)@realmof(cred->client)"
98 * (actually, the ticket may be issued by some other intermediate
99 * realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY below)
103 * we're sharing some substructure here, which is dangerous.
104 * Be sure that if you muck with things here that tgtq.* doesn't share
105 * any substructure before you deallocate/clean up/whatever.
107 memset((char *)&tgtq, 0, sizeof(tgtq));
108 tgtq.client = cred->client;
110 if (retval = krb5_tgtname(krb5_princ_realm(cred->server),
111 krb5_princ_realm(cred->client), &final_server))
113 tgtq.server = final_server;
115 /* try to fetch it directly */
116 retval = krb5_cc_retrieve_cred (ccache,
117 KRB5_TC_MATCH_SRV_NAMEONLY,
122 if (retval != KRB5_CC_NOTFOUND)
124 /* don't have the right TGT in the cred cache. Time to iterate
125 across realms to get the right TGT. */
127 /* get a list of realms to consult */
128 retval = krb5_walk_realm_tree(krb5_princ_realm(cred->client),
129 krb5_princ_realm(cred->server),
130 &tgs_list, KRB5_REALM_BRANCH_CHAR);
133 /* walk the list BACKWARDS until we find a cached
134 TGT, then move forward obtaining TGTs until we get the last
136 for (next_server = tgs_list; *next_server; next_server++);
137 nservers = next_server - tgs_list;
140 /* next_server now points to the last TGT */
141 for (; next_server >= tgs_list; next_server--) {
142 tgtq.server = *next_server;
143 retval = krb5_cc_retrieve_cred (ccache,
144 KRB5_TC_MATCH_SRV_NAMEONLY,
148 if (retval != KRB5_CC_NOTFOUND) {
149 krb5_free_realm_tree(tgs_list);
155 break; /* found one! */
157 if (next_server < tgs_list) {
158 /* didn't find any */
159 retval = KRB5_NO_TKT_IN_RLM;
160 krb5_free_realm_tree(tgs_list);
163 /* allocate storage for TGT pointers. */
164 ret_tgts = (krb5_creds **)calloc(nservers+1, sizeof(krb5_creds));
167 krb5_free_realm_tree(tgs_list);
171 for (nservers = 0; *next_server; next_server++, nservers++) {
175 if (!valid_keytype(tgt.keyblock.keytype)) {
176 retval = KRB5_PROG_KEYTYPE_NOSUPP;
177 krb5_free_realm_tree(tgs_list);
180 /* now get the TGTs */
181 memset((char *)&tgtq, 0, sizeof(tgtq));
182 tgtq.times = tgt.times;
183 tgtq.client = tgt.client;
185 /* ask each realm for a tgt to the end */
186 if (retval = krb5_copy_data(krb5_princ_realm(*next_server), &tmpdata)) {
187 krb5_free_realm_tree(tgs_list);
190 krb5_free_data(krb5_princ_realm(final_server));
191 krb5_princ_set_realm(final_server, tmpdata);
192 tgtq.server = final_server;
194 tgtq.is_skey = FALSE;
195 tgtq.ticket_flags = tgt.ticket_flags;
197 etype = krb5_keytype_array[tgt.keyblock.keytype]->system->proto_enctype;
198 if (retval = krb5_get_cred_via_tgt(&tgt,
199 flags2options(tgtq.ticket_flags),
201 krb5_kdc_req_sumtype,
203 krb5_free_realm_tree(tgs_list);
206 /* make sure the returned ticket is somewhere in the remaining
207 list, but we can tolerate different expected issuing realms */
208 while (*++next_server &&
209 !krb5_principal_compare(&(next_server[0])[1],
212 /* what we got back wasn't in the list! */
213 krb5_free_realm_tree(tgs_list);
214 retval = KRB5_KDCREP_MODIFIED;
218 /* save tgt in return array */
219 if (retval = krb5_copy_creds(&tgtq, &ret_tgts[nservers])) {
220 krb5_free_realm_tree(tgs_list);
223 tgt = *ret_tgts[nservers];
224 returning_tgt = 1; /* don't free it below... */
227 krb5_free_cred_contents(&tgtq);
229 krb5_free_realm_tree(tgs_list);
231 /* got/finally have tgt! */
232 if (!valid_keytype(tgt.keyblock.keytype)) {
233 retval = KRB5_PROG_KEYTYPE_NOSUPP;
236 etype = krb5_keytype_array[tgt.keyblock.keytype]->system->proto_enctype;
238 if (cred->second_ticket.length)
239 retval = krb5_get_cred_via_2tgt(&tgt,
240 KDC_OPT_ENC_TKT_IN_SKEY | flags2options(tgt.ticket_flags),
241 etype, krb5_kdc_req_sumtype, cred);
244 retval = krb5_get_cred_via_tgt(&tgt,
245 flags2options(tgt.ticket_flags),
247 krb5_kdc_req_sumtype,
251 krb5_free_cred_contents(&tgt);
253 krb5_free_principal(final_server);