1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/val_renew.c */
3 /*
4 * Copyright (C) 2010 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
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.
11 *
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.
25 */
26
27 /*
28 * Implements the following APIs:
29 *
30 * krb5_get_credentials_validate
31 * krb5_get_credentials_renew
32 * krb5_get_validated_creds
33 * krb5_get_renewed_creds
34 *
35 * The first two are old but not formally deprecated; the latter two are newer.
36 */
37
38 #include "k5-int.h"
39 #include "int-proto.h"
40
41 /*
42 * Get a validated or renewed credential matching in_creds, by retrieving a
43 * matching credential from ccache and renewing or validating it with the
44 * credential's realm's KDC. kdcopt specifies whether to validate or renew.
45 * The result is placed in *out_creds.
46 */
47 static krb5_error_code
get_new_creds(krb5_context context,krb5_ccache ccache,krb5_creds * in_creds,krb5_flags kdcopt,krb5_creds ** out_creds)48 get_new_creds(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
49 krb5_flags kdcopt, krb5_creds **out_creds)
50 {
51 krb5_error_code code;
52 krb5_creds old_creds, *new_creds = NULL;
53
54 *out_creds = NULL;
55
56 /* Retrieve an existing cached credential matching in_creds. */
57 code = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_SUPPORTED_KTYPES,
58 in_creds, &old_creds);
59 if (code != 0)
60 return code;
61
62 /* Use KDC options from old credential as well as requested options. */
63 kdcopt |= (old_creds.ticket_flags & KDC_TKT_COMMON_MASK);
64
65 /* Use the old credential to get a new credential from the KDC. */
66 code = krb5_get_cred_via_tkt(context, &old_creds, kdcopt,
67 old_creds.addresses, in_creds, &new_creds);
68 krb5_free_cred_contents(context, &old_creds);
69 if (code != 0)
70 return code;
71
72 *out_creds = new_creds;
73 return code;
74 }
75
76 /*
77 * Core of the older pair of APIs: get a validated or renewed credential
78 * matching in_creds and reinitialize ccache so that it contains only the new
79 * credential.
80 */
81 static krb5_error_code
gc_valrenew(krb5_context context,krb5_ccache ccache,krb5_creds * in_creds,krb5_flags kdcopt,krb5_creds ** out_creds)82 gc_valrenew(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
83 krb5_flags kdcopt, krb5_creds **out_creds)
84 {
85 krb5_error_code code;
86 krb5_creds *new_creds = NULL;
87 krb5_principal default_princ = NULL;
88
89 /* Get the validated or renewed credential. */
90 code = get_new_creds(context, ccache, in_creds, kdcopt, &new_creds);
91 if (code != 0)
92 goto cleanup;
93
94 /* Reinitialize the cache without changing its default principal. */
95 code = krb5_cc_get_principal(context, ccache, &default_princ);
96 if (code != 0)
97 goto cleanup;
98 code = krb5_cc_initialize(context, ccache, default_princ);
99 if (code != 0)
100 goto cleanup;
101
102 /* Store the validated or renewed cred in the now-empty cache. */
103 code = krb5_cc_store_cred(context, ccache, new_creds);
104 if (code != 0)
105 goto cleanup;
106
107 *out_creds = new_creds;
108 new_creds = NULL;
109
110 cleanup:
111 krb5_free_principal(context, default_princ);
112 krb5_free_creds(context, new_creds);
113 return code;
114 }
115
116 krb5_error_code KRB5_CALLCONV
krb5_get_credentials_validate(krb5_context context,krb5_flags options,krb5_ccache ccache,krb5_creds * in_creds,krb5_creds ** out_creds)117 krb5_get_credentials_validate(krb5_context context, krb5_flags options,
118 krb5_ccache ccache, krb5_creds *in_creds,
119 krb5_creds **out_creds)
120 {
121 return gc_valrenew(context, ccache, in_creds, KDC_OPT_VALIDATE, out_creds);
122 }
123
124 krb5_error_code KRB5_CALLCONV
krb5_get_credentials_renew(krb5_context context,krb5_flags options,krb5_ccache ccache,krb5_creds * in_creds,krb5_creds ** out_creds)125 krb5_get_credentials_renew(krb5_context context, krb5_flags options,
126 krb5_ccache ccache, krb5_creds *in_creds,
127 krb5_creds **out_creds)
128 {
129 return gc_valrenew(context, ccache, in_creds, KDC_OPT_RENEW, out_creds);
130 }
131
132 /*
133 * Core of the newer pair of APIs: get new credentials for in_tkt_service
134 * (defaults to the TGT of the client's realm) and store them into *out_creds.
135 */
136 static krb5_error_code
get_valrenewed_creds(krb5_context context,krb5_creds * out_creds,krb5_principal client,krb5_ccache ccache,const char * in_tkt_service,int kdcopt)137 get_valrenewed_creds(krb5_context context, krb5_creds *out_creds,
138 krb5_principal client, krb5_ccache ccache,
139 const char *in_tkt_service, int kdcopt)
140 {
141 krb5_error_code code;
142 krb5_creds in_creds, *new_creds;
143 krb5_principal server = NULL;
144
145 if (in_tkt_service != NULL) {
146 /* Parse in_tkt_service, but use the client's realm. */
147 code = krb5_parse_name(context, in_tkt_service, &server);
148 if (code != 0)
149 goto cleanup;
150 krb5_free_data_contents(context, &server->realm);
151 code = krb5int_copy_data_contents(context, &client->realm,
152 &server->realm);
153 if (code != 0)
154 goto cleanup;
155 } else {
156 /* Use the TGT name for the client's realm. */
157 code = krb5int_tgtname(context, &client->realm, &client->realm,
158 &server);
159 if (code != 0)
160 goto cleanup;
161 }
162
163 memset(&in_creds, 0, sizeof(krb5_creds));
164 in_creds.client = client;
165 in_creds.server = server;
166
167 /* Get the validated or renewed credential from the KDC. */
168 code = get_new_creds(context, ccache, &in_creds, kdcopt, &new_creds);
169 if (code != 0)
170 goto cleanup;
171
172 /* Fill in *out_creds and free the unwanted new_creds container. */
173 *out_creds = *new_creds;
174 free(new_creds);
175
176 cleanup:
177 krb5_free_principal(context, server);
178 return code;
179 }
180
181 krb5_error_code KRB5_CALLCONV
krb5_get_validated_creds(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_ccache ccache,const char * in_tkt_service)182 krb5_get_validated_creds(krb5_context context, krb5_creds *creds,
183 krb5_principal client, krb5_ccache ccache,
184 const char *in_tkt_service)
185 {
186 return get_valrenewed_creds(context, creds, client, ccache,
187 in_tkt_service, KDC_OPT_VALIDATE);
188 }
189
190 krb5_error_code KRB5_CALLCONV
krb5_get_renewed_creds(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_ccache ccache,const char * in_tkt_service)191 krb5_get_renewed_creds(krb5_context context, krb5_creds *creds,
192 krb5_principal client, krb5_ccache ccache,
193 const char *in_tkt_service)
194 {
195 return get_valrenewed_creds(context, creds, client, ccache,
196 in_tkt_service, KDC_OPT_RENEW);
197 }
198