@@ -170,7 +170,16 @@ static krb5_error_code gpp_construct_cred(gssx_cred *creds, krb5_context ctx,
170
170
return 0 ;
171
171
}
172
172
173
- uint32_t gpp_store_remote_creds (uint32_t * min , bool default_creds ,
173
+ /* Store creds from remote in a local ccache, updating where possible.
174
+ *
175
+ * If store_as_default_cred is true, the cred is made default for its
176
+ * collection, if there is one. Note that if the ccache is not of a
177
+ * collection type, the creds will overwrite the ccache.
178
+ *
179
+ * If no "ccache" entry is specified in cred_store, the default ccache for a
180
+ * new context will be used.
181
+ */
182
+ uint32_t gpp_store_remote_creds (uint32_t * min , bool store_as_default_cred ,
174
183
gss_const_key_value_set_t cred_store ,
175
184
gssx_cred * creds )
176
185
{
@@ -179,7 +188,7 @@ uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds,
179
188
krb5_creds cred ;
180
189
krb5_error_code ret ;
181
190
char cred_name [creds -> desired_name .display_name .octet_string_len + 1 ];
182
- const char * cc_type ;
191
+ const char * cc_name ;
183
192
184
193
* min = 0 ;
185
194
@@ -191,38 +200,64 @@ uint32_t gpp_store_remote_creds(uint32_t *min, bool default_creds,
191
200
goto done ;
192
201
}
193
202
194
- if (cred_store ) {
195
- for (unsigned i = 0 ; i < cred_store -> count ; i ++ ) {
196
- if (strcmp (cred_store -> elements [i ].key , "ccache" ) == 0 ) {
197
- ret = krb5_cc_resolve (ctx , cred_store -> elements [i ].value ,
198
- & ccache );
199
- if (ret ) goto done ;
200
- break ;
201
- }
203
+ for (unsigned i = 0 ; cred_store && i < cred_store -> count ; i ++ ) {
204
+ if (strcmp (cred_store -> elements [i ].key , "ccache" ) == 0 ) {
205
+ /* krb5 creates new ccaches based off the default name. */
206
+ ret = krb5_cc_set_default_name (ctx ,
207
+ cred_store -> elements [i ].value );
208
+ if (ret )
209
+ goto done ;
210
+
211
+ break ;
202
212
}
203
213
}
204
- if (!ccache ) {
205
- if (!default_creds ) {
206
- ret = ENOMEDIUM ;
207
- goto done ;
208
- }
209
- ret = krb5_cc_default (ctx , & ccache );
210
- if (ret ) goto done ;
211
- }
212
214
213
- cc_type = krb5_cc_get_type (ctx , ccache );
214
- if (strcmp ( cc_type , "FILE" ) == 0 ) {
215
+ cc_name = krb5_cc_default_name (ctx );
216
+ if (strncmp ( cc_name , "FILE:" , 5 ) == 0 || ! strchr ( cc_name , ':' ) ) {
215
217
/* FILE ccaches don't handle updates properly: if they have the same
216
218
* principal name, they are blackholed. We either have to change the
217
219
* name (at which point the file grows forever) or flash the cache on
218
220
* every update. */
221
+ ret = krb5_cc_default (ctx , & ccache );
222
+ if (ret )
223
+ goto done ;
224
+
219
225
ret = krb5_cc_initialize (ctx , ccache , cred .client );
220
- if (ret != 0 ) {
226
+ if (ret != 0 )
227
+ goto done ;
228
+
229
+ ret = krb5_cc_store_cred (ctx , ccache , & cred );
230
+ goto done ;
231
+ }
232
+
233
+ ret = krb5_cc_cache_match (ctx , cred .client , & ccache );
234
+ if (ret == KRB5_CC_NOTFOUND ) {
235
+ /* A new ccache within the collection whose name is based off the
236
+ * default_name for the context. krb5_cc_new_unique only accepts the
237
+ * leading component of a name as a type. */
238
+ char * cc_type ;
239
+ const char * p ;
240
+
241
+ p = strchr (cc_name , ':' ); /* can't be FILE here */
242
+ cc_type = strndup (cc_name , p - cc_name );
243
+ if (!cc_type ) {
244
+ ret = ENOMEM ;
221
245
goto done ;
222
246
}
247
+
248
+ ret = krb5_cc_new_unique (ctx , cc_type , NULL , & ccache );
249
+ free (cc_type );
223
250
}
251
+ if (ret )
252
+ goto done ;
224
253
225
254
ret = krb5_cc_store_cred (ctx , ccache , & cred );
255
+ if (ret )
256
+ goto done ;
257
+
258
+ if (store_as_default_cred ) {
259
+ ret = krb5_cc_switch (ctx , ccache );
260
+ }
226
261
227
262
done :
228
263
if (ctx ) {
0 commit comments