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