2 * lib/krb5/krb/get_creds.c
4 * Copyright 1990 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * krb5_get_credentials()
33 Attempts to use the credentials cache or TGS exchange to get an additional
35 client identified by in_creds->client, the server identified by
36 in_creds->server, with options options, expiration date specified in
37 in_creds->times.endtime (0 means as long as possible), session key type
38 specified in in_creds->keyblock.enctype (if non-zero)
40 Any returned ticket and intermediate ticket-granting tickets are
43 returns errors from encryption routines, system errors
48 static krb5_error_code
49 krb5_get_credentials_core(context, options, in_creds, mcreds, fields)
51 const krb5_flags options;
56 if (!in_creds || !in_creds->server || !in_creds->client)
59 memset((char *)mcreds, 0, sizeof(krb5_creds));
60 mcreds->magic = KV5M_CREDS;
61 mcreds->times.endtime = in_creds->times.endtime;
62 #ifdef HAVE_C_STRUCTURE_ASSIGNMENT
63 mcreds->keyblock = in_creds->keyblock;
65 memcpy(&mcreds->keyblock, &in_creds->keyblock, sizeof(krb5_keyblock));
67 mcreds->authdata = in_creds->authdata;
68 mcreds->server = in_creds->server;
69 mcreds->client = in_creds->client;
71 *fields = KRB5_TC_MATCH_TIMES /*XXX |KRB5_TC_MATCH_SKEY_TYPE */
72 | KRB5_TC_MATCH_AUTHDATA
73 | KRB5_TC_SUPPORTED_KTYPES;
74 if (mcreds->keyblock.enctype) {
79 *fields |= KRB5_TC_MATCH_KTYPE;
80 ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
81 for (i = 0; ktypes[i]; i++)
82 if (ktypes[i] == mcreds->keyblock.enctype)
85 ret = KRB5_CC_NOT_KTYPE;
90 if (options & KRB5_GC_USER_USER) {
91 /* also match on identical 2nd tkt and tkt encrypted in a
93 *fields |= KRB5_TC_MATCH_2ND_TKT|KRB5_TC_MATCH_IS_SKEY;
94 mcreds->is_skey = TRUE;
95 mcreds->second_ticket = in_creds->second_ticket;
96 if (!in_creds->second_ticket.length)
97 return KRB5_NO_2ND_TKT;
103 krb5_error_code KRB5_CALLCONV
104 krb5_get_credentials(context, options, ccache, in_creds, out_creds)
105 krb5_context context;
106 const krb5_flags options;
108 krb5_creds *in_creds;
109 krb5_creds **out_creds;
111 krb5_error_code retval;
118 retval = krb5_get_credentials_core(context, options,
122 if (retval) return retval;
124 if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
127 memset((char *)ncreds, 0, sizeof(krb5_creds));
128 ncreds->magic = KV5M_CREDS;
130 /* The caller is now responsible for cleaning up in_creds */
131 if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
139 if ((retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE)
140 || options & KRB5_GC_CACHED)
143 if (retval == KRB5_CC_NOT_KTYPE)
148 retval = krb5_get_cred_from_kdc(context, ccache, ncreds, out_creds, &tgts);
153 if ((rv2 = krb5_cc_store_cred(context, ccache, tgts[i]))) {
159 krb5_free_tgt_creds(context, tgts);
162 * Translate KRB5_CC_NOTFOUND if we previously got
163 * KRB5_CC_NOT_KTYPE from krb5_cc_retrieve_cred(), in order to
164 * handle the case where there is no TGT in the ccache and the
165 * input enctype didn't match. This handling is necessary because
166 * some callers, such as GSSAPI, iterate through enctypes and
167 * KRB5_CC_NOTFOUND passed through from the
168 * krb5_get_cred_from_kdc() is semantically incorrect, since the
169 * actual failure was the non-existence of a ticket of the correct
170 * enctype rather than the missing TGT.
172 if ((retval == KRB5_CC_NOTFOUND || retval == KRB5_CC_NOT_KTYPE)
174 retval = KRB5_CC_NOT_KTYPE;
177 retval = krb5_cc_store_cred(context, ccache, *out_creds);
181 #define INT_GC_VALIDATE 1
182 #define INT_GC_RENEW 2
184 static krb5_error_code
185 krb5_get_credentials_val_renew_core(context, options, ccache,
186 in_creds, out_creds, which)
187 krb5_context context;
188 const krb5_flags options;
190 krb5_creds *in_creds;
191 krb5_creds **out_creds;
194 krb5_error_code retval;
196 krb5_creds **tgts = 0;
199 case INT_GC_VALIDATE:
200 retval = krb5_get_cred_from_kdc_validate(context, ccache,
201 in_creds, out_creds, &tgts);
204 retval = krb5_get_cred_from_kdc_renew(context, ccache,
205 in_creds, out_creds, &tgts);
208 /* Should never happen */
212 if (retval) return retval;
213 if (tgts) krb5_free_tgt_creds(context, tgts);
215 retval = krb5_cc_get_principal(context, ccache, &tmp);
216 if (retval) return retval;
218 retval = krb5_cc_initialize(context, ccache, tmp);
219 if (retval) return retval;
221 retval = krb5_cc_store_cred(context, ccache, *out_creds);
225 krb5_error_code KRB5_CALLCONV
226 krb5_get_credentials_validate(context, options, ccache, in_creds, out_creds)
227 krb5_context context;
228 const krb5_flags options;
230 krb5_creds *in_creds;
231 krb5_creds **out_creds;
233 return(krb5_get_credentials_val_renew_core(context, options, ccache,
238 krb5_error_code KRB5_CALLCONV
239 krb5_get_credentials_renew(context, options, ccache, in_creds, out_creds)
240 krb5_context context;
241 const krb5_flags options;
243 krb5_creds *in_creds;
244 krb5_creds **out_creds;
247 return(krb5_get_credentials_val_renew_core(context, options, ccache,
252 static krb5_error_code
253 krb5_validate_or_renew_creds(context, creds, client, ccache, in_tkt_service,
255 krb5_context context;
257 krb5_principal client;
259 char *in_tkt_service;
263 krb5_creds in_creds; /* only client and server need to be filled in */
264 krb5_creds *out_creds = 0; /* for check before dereferencing below */
267 memset((char *)&in_creds, 0, sizeof(krb5_creds));
269 in_creds.server = NULL;
272 in_creds.client = client;
274 if (in_tkt_service) {
275 /* this is ugly, because so are the data structures involved. I'm
276 in the library, so I'm going to manipulate the data structures
277 directly, otherwise, it will be worse. */
279 if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server)))
282 /* stuff the client realm into the server principal.
283 realloc if necessary */
284 if (in_creds.server->realm.length < in_creds.client->realm.length)
285 if ((in_creds.server->realm.data =
286 (char *) realloc(in_creds.server->realm.data,
287 in_creds.client->realm.length)) == NULL) {
292 in_creds.server->realm.length = in_creds.client->realm.length;
293 memcpy(in_creds.server->realm.data, in_creds.client->realm.data,
294 in_creds.client->realm.length);
296 if ((ret = krb5_build_principal_ext(context, &in_creds.server,
297 in_creds.client->realm.length,
298 in_creds.client->realm.data,
301 in_creds.client->realm.length,
302 in_creds.client->realm.data,
308 ret = krb5_get_cred_from_kdc_validate(context, ccache,
309 &in_creds, &out_creds, &tgts);
311 ret = krb5_get_cred_from_kdc_renew(context, ccache,
312 &in_creds, &out_creds, &tgts);
314 /* ick. copy the struct contents, free the container */
317 krb5_xfree(out_creds);
323 krb5_free_principal(context, in_creds.server);
325 krb5_free_tgt_creds(context, tgts);
330 krb5_error_code KRB5_CALLCONV
331 krb5_get_validated_creds(context, creds, client, ccache, in_tkt_service)
332 krb5_context context;
334 krb5_principal client;
336 char *in_tkt_service;
338 return(krb5_validate_or_renew_creds(context, creds, client, ccache,
342 krb5_error_code KRB5_CALLCONV
343 krb5_get_renewed_creds(context, creds, client, ccache, in_tkt_service)
344 krb5_context context;
346 krb5_principal client;
348 char *in_tkt_service;
350 return(krb5_validate_or_renew_creds(context, creds, client, ccache,