xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/store_cred.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/store_cred.c */
3 /*
4  * Copyright 2009 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 #include "k5-int.h"
28 #include "gssapiP_krb5.h"
29 
30 static OM_uint32
copy_initiator_creds(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store)31 copy_initiator_creds(OM_uint32 *minor_status,
32                      gss_cred_id_t input_cred_handle,
33                      const gss_OID desired_mech,
34                      OM_uint32 overwrite_cred,
35                      OM_uint32 default_cred,
36                      gss_const_key_value_set_t cred_store)
37 {
38     OM_uint32 major_status;
39     krb5_error_code ret;
40     krb5_gss_cred_id_t kcred = NULL;
41     krb5_context context = NULL;
42     krb5_ccache cache = NULL, defcache = NULL, mcc = NULL;
43     krb5_principal princ = NULL;
44     krb5_boolean switch_to_cache = FALSE;
45     const char *ccache_name, *deftype;
46 
47     *minor_status = 0;
48 
49     ret = krb5_gss_init_context(&context);
50     if (ret)
51         goto kerr_cleanup;
52 
53     major_status = krb5_gss_validate_cred_1(minor_status,
54                                             input_cred_handle,
55                                             context);
56     if (GSS_ERROR(major_status))
57         goto cleanup;
58 
59     kcred = (krb5_gss_cred_id_t)input_cred_handle;
60 
61     if (kcred->ccache == NULL) {
62         *minor_status = KG_CCACHE_NOMATCH;
63         major_status = GSS_S_DEFECTIVE_CREDENTIAL;
64         goto cleanup;
65     }
66 
67     major_status = kg_value_from_cred_store(cred_store,
68                                             KRB5_CS_CCACHE_URN, &ccache_name);
69     if (GSS_ERROR(major_status))
70         goto cleanup;
71 
72     if (ccache_name != NULL) {
73         ret = krb5_cc_set_default_name(context, ccache_name);
74         if (ret)
75             goto kerr_cleanup;
76     } else {
77         major_status = kg_sync_ccache_name(context, minor_status);
78         if (major_status != GSS_S_COMPLETE)
79             goto cleanup;
80     }
81 
82     /* Resolve the default ccache and get its type. */
83     ret = krb5_cc_default(context, &defcache);
84     if (ret)
85         goto kerr_cleanup;
86     deftype = krb5_cc_get_type(context, defcache);
87 
88     if (krb5_cc_support_switch(context, deftype)) {
89         /* Use an existing or new cache within the collection. */
90         ret = krb5_cc_cache_match(context, kcred->name->princ, &cache);
91         if (!ret && !overwrite_cred) {
92             major_status = GSS_S_DUPLICATE_ELEMENT;
93             goto cleanup;
94         }
95         if (ret == KRB5_CC_NOTFOUND)
96             ret = krb5_cc_new_unique(context, deftype, NULL, &cache);
97         if (ret)
98             goto kerr_cleanup;
99         switch_to_cache = default_cred;
100     } else {
101         /* Use the default cache. */
102         cache = defcache;
103         defcache = NULL;
104         ret = krb5_cc_get_principal(context, cache, &princ);
105         krb5_free_principal(context, princ);
106         if (!ret && !overwrite_cred) {
107             major_status = GSS_S_DUPLICATE_ELEMENT;
108             goto cleanup;
109         }
110     }
111 
112     ret = krb5_cc_new_unique(context, "MEMORY", NULL, &mcc);
113     if (ret)
114         goto kerr_cleanup;
115     ret = krb5_cc_initialize(context, mcc, kcred->name->princ);
116     if (ret)
117         goto kerr_cleanup;
118     ret = krb5_cc_copy_creds(context, kcred->ccache, mcc);
119     if (ret)
120         goto kerr_cleanup;
121     ret = krb5_cc_move(context, mcc, cache);
122     if (ret)
123         goto kerr_cleanup;
124     mcc = NULL;
125 
126     if (switch_to_cache) {
127         ret = krb5_cc_switch(context, cache);
128         if (ret)
129             goto kerr_cleanup;
130     }
131 
132     *minor_status = 0;
133     major_status = GSS_S_COMPLETE;
134 
135 cleanup:
136     if (kcred != NULL)
137         k5_mutex_unlock(&kcred->lock);
138     if (defcache != NULL)
139         krb5_cc_close(context, defcache);
140     if (cache != NULL)
141         krb5_cc_close(context, cache);
142     if (mcc != NULL)
143         krb5_cc_destroy(context, mcc);
144     krb5_free_context(context);
145 
146     return major_status;
147 
148 kerr_cleanup:
149     *minor_status = ret;
150     major_status = GSS_S_FAILURE;
151     goto cleanup;
152 }
153 
154 OM_uint32 KRB5_CALLCONV
krb5_gss_store_cred(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)155 krb5_gss_store_cred(OM_uint32 *minor_status,
156                     gss_cred_id_t input_cred_handle,
157                     gss_cred_usage_t cred_usage,
158                     const gss_OID desired_mech,
159                     OM_uint32 overwrite_cred,
160                     OM_uint32 default_cred,
161                     gss_OID_set *elements_stored,
162                     gss_cred_usage_t *cred_usage_stored)
163 {
164     return krb5_gss_store_cred_into(minor_status, input_cred_handle,
165                                     cred_usage, desired_mech,
166                                     overwrite_cred, default_cred,
167                                     GSS_C_NO_CRED_STORE,
168                                     elements_stored, cred_usage_stored);
169 }
170 
171 OM_uint32 KRB5_CALLCONV
krb5_gss_store_cred_into(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)172 krb5_gss_store_cred_into(OM_uint32 *minor_status,
173                          gss_cred_id_t input_cred_handle,
174                          gss_cred_usage_t cred_usage,
175                          const gss_OID desired_mech,
176                          OM_uint32 overwrite_cred,
177                          OM_uint32 default_cred,
178                          gss_const_key_value_set_t cred_store,
179                          gss_OID_set *elements_stored,
180                          gss_cred_usage_t *cred_usage_stored)
181 {
182     OM_uint32 major_status;
183     gss_cred_usage_t actual_usage;
184     OM_uint32 lifetime;
185 
186     if (input_cred_handle == GSS_C_NO_CREDENTIAL)
187         return GSS_S_NO_CRED;
188 
189     major_status = GSS_S_FAILURE;
190 
191     if (cred_usage == GSS_C_ACCEPT) {
192         *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
193         return GSS_S_FAILURE;
194     } else if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
195         *minor_status = G_BAD_USAGE;
196         return GSS_S_FAILURE;
197     }
198 
199     major_status = krb5_gss_inquire_cred(minor_status, input_cred_handle,
200                                          NULL, &lifetime,
201                                          &actual_usage, elements_stored);
202     if (GSS_ERROR(major_status))
203         return major_status;
204 
205     if (lifetime == 0)
206         return GSS_S_CREDENTIALS_EXPIRED;
207 
208     if (actual_usage != GSS_C_INITIATE && actual_usage != GSS_C_BOTH) {
209         *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
210         return GSS_S_FAILURE;
211     }
212 
213     major_status = copy_initiator_creds(minor_status, input_cred_handle,
214                                         desired_mech, overwrite_cred,
215                                         default_cred, cred_store);
216     if (GSS_ERROR(major_status))
217         return major_status;
218 
219     if (cred_usage_stored != NULL)
220         *cred_usage_stored = GSS_C_INITIATE;
221 
222     return GSS_S_COMPLETE;
223 }
224