{
krb5_creds ** creds = NULL;
krb5_error_code retval;
+ krb5_ccache template_ccache = NULL;
krb5_ccache ccache = NULL;
krb5_gss_cred_id_t cred = NULL;
krb5_auth_context new_auth_ctx = NULL;
/* Lots of kludging going on here... Some day the ccache interface
will be rewritten though */
- if ((retval = krb5_cc_resolve(context, "MEMORY:GSSAPI", &ccache)))
- goto cleanup;
+ if ((retval = krb5_cc_resolve(context, "MEMORY:GSSAPI", &template_ccache)))
+ goto cleanup;
+ ccache = template_ccache; /* krb5_cc_gen_new will replace so make a copy */
if ((retval = krb5_cc_gen_new(context, &ccache)))
goto cleanup;
cred->prerfc_mech = 1; /* this cred will work with all three mechs */
cred->rfc_mech = 1;
cred->keytab = NULL; /* no keytab associated with this... */
- cred->ccache = ccache; /* but there is a credential cache */
cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
+ cred->ccache = ccache; /* the ccache containing the credential */
+ ccache = NULL; /* cred takes ownership so don't destroy */
}
/* If there were errors, there might have been a memory leak
if (creds)
krb5_free_tgt_creds(context, creds);
- if (!cred && ccache)
- (void)krb5_cc_close(context, ccache);
+ if (template_ccache)
+ (void)krb5_cc_close(context, template_ccache);
+
+ if (ccache)
+ (void)krb5_cc_destroy(context, ccache);
if (out_cred)
*out_cred = cred; /* return credential */
return 0;
}
+static krb5_error_code random_string (krb5_context, char *, krb5_int32);
+
/*
* Effects:
* Creates a new file cred cache whose name is guaranteed to be
* krb5_ccache. id is undefined.
* system errors (from open)
*/
+
krb5_error_code KRB5_CALLCONV
krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
{
krb5_ccache lid;
- char scratch[6+1]; /* 6 for the scratch part, +1 for NUL */
+ char uniquename[8];
krb5_error_code err;
krb5_mcc_data *d;
+ krb5_mcc_list_node *ptr;
/* Allocate memory */
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
lid->ops = &krb5_mcc_ops;
- (void) strcpy(scratch, "XXXXXX");
- mktemp(scratch);
+ random_string (context, uniquename, sizeof (uniquename));
err = k5_mutex_lock(&krb5int_mcc_mutex);
if (err) {
free(lid);
return err;
}
- err = new_mcc_data(scratch, &d);
+
+ /* Check for uniqueness with mutex locked to avoid race conditions */
+ while (1) {
+ for (ptr = mcc_head; ptr; ptr=ptr->next) {
+ if (!strcmp(ptr->cache->name, uniquename)) {
+ /* name already exists. Pick a new one and start over. */
+ random_string (context, uniquename, sizeof (uniquename));
+ ptr = mcc_head;
+ continue;
+ }
+ }
+ break; /* got a unique name. Stop. */
+ }
+
+ err = new_mcc_data(uniquename, &d);
+
k5_mutex_unlock(&krb5int_mcc_mutex);
if (err) {
krb5_xfree(lid);
return err;
}
lid->data = d;
+ *id = lid;
krb5_change_cache ();
return KRB5_OK;
}
+/* Utility routine: Creates a random memory ccache name.
+ * This algorithm was selected because it creates readable
+ * random ccache names in a fixed size buffer. */
+
+static krb5_error_code
+random_string (krb5_context context, char *string, krb5_int32 length)
+{
+ static const unsigned char charlist[] =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ krb5_error_code err = 0;
+ u_int8_t *bytes = NULL;
+ size_t bytecount = length - 1;
+
+ if (!err) {
+ bytes = malloc (bytecount);
+ if (bytes == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ krb5_data data;
+ data.length = bytecount;
+ data.data = (char *) bytes;
+ err = krb5_c_random_make_octets (context, &data);
+ }
+
+ if (!err) {
+ krb5_int32 i;
+ for (i = 0; i < bytecount; i++) {
+ string [i] = charlist[bytes[i] % (sizeof (charlist) - 1)];
+ }
+ string[length - 1] = '\0';
+ }
+
+ if (bytes != NULL) { free (bytes); }
+
+ return err;
+}
+
/*
* Requires:
* id is a file credential cache
krb5_error_code ret;
krb5_principal server;
krb5_keytab keytab;
+ krb5_ccache template_ccache;
krb5_ccache ccache;
krb5_keytab_entry kte;
krb5_creds in_creds, *out_creds;
server = NULL;
keytab = NULL;
+ template_ccache = NULL;
ccache = NULL;
out_creds = NULL;
authcon = NULL;
internals with a coherent idea of "in" and "out". */
/* insert the initial cred into the ccache */
-
- if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req", &ccache)))
+
+ if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req", &template_ccache)))
goto cleanup;
-
+ ccache = template_ccache; /* krb5_cc_gen_new will replace so make a copy */
+
+ if ((ret = krb5_cc_gen_new(context, &ccache)))
+ goto cleanup;
+
if ((ret = krb5_cc_initialize(context, ccache, creds->client)))
goto cleanup;
krb5_free_principal(context, server);
if (!keytab_arg && keytab)
krb5_kt_close(context, keytab);
+ if (template_ccache)
+ krb5_cc_close(context, template_ccache);
if (ccache)
krb5_cc_destroy(context, ccache);
if (out_creds)