k5_cc_mutex lock;
krb5_principal prin;
krb5_mcc_link *link;
+ krb5_mcc_link **tail; /* Where to store next added cred */
/* Time offsets for clock-skewed clients. */
krb5_int32 time_offset;
krb5_int32 usec_offset;
free(curr);
}
d->link = NULL;
+ d->tail = &d->link;
d->generation++;
krb5_free_principal(context, d->prin);
d->prin = NULL;
return KRB5_CC_NOMEM;
}
d->link = NULL;
+ d->tail = &d->link;
d->prin = NULL;
d->time_offset = 0;
d->usec_offset = 0;
new_node = malloc(sizeof(krb5_mcc_link));
if (new_node == NULL)
return ENOMEM;
+ new_node->next = NULL;
err = krb5_copy_creds(ctx, creds, &new_node->creds);
if (err)
goto cleanup;
+
+ /* Place the new node at the tail of the list. */
k5_cc_mutex_lock(ctx, &mptr->lock);
- new_node->next = mptr->link;
- mptr->link = new_node;
+ *mptr->tail = new_node;
+ mptr->tail = &new_node->next;
k5_cc_mutex_unlock(ctx, &mptr->lock);
+
return 0;
cleanup:
free(new_node);
free_test_cred(context);
}
+/* Check that order is preserved during iteration. Not all cache types have
+ * this property. */
+static void
+test_order(krb5_context context, const char *name)
+{
+ krb5_error_code kret;
+ krb5_ccache id;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+
+ kret = init_test_cred(context);
+ CHECK(kret, "init_creds");
+
+ kret = krb5_cc_resolve(context, name, &id);
+ CHECK(kret, "resolve");
+ kret = krb5_cc_initialize(context, id, test_creds.client);
+ CHECK(kret, "initialize");
+ kret = krb5_cc_store_cred(context, id, &test_creds);
+ CHECK(kret, "store 1");
+ kret = krb5_cc_store_cred(context, id, &test_creds2);
+ CHECK(kret, "store 2");
+
+ kret = krb5_cc_start_seq_get(context, id, &cursor);
+ CHECK(kret, "start_seq_get");
+ kret = krb5_cc_next_cred(context, id, &cursor, &creds);
+ CHECK(kret, "next_cred 1");
+ CHECK_BOOL(krb5_principal_compare(context, creds.server,
+ test_creds.server) != TRUE,
+ "first cred does not match", "principal_compare");
+ krb5_free_cred_contents(context, &creds);
+
+ kret = krb5_cc_next_cred(context, id, &cursor, &creds);
+ CHECK(kret, "next_cred 2");
+ CHECK_BOOL(krb5_principal_compare(context, creds.server,
+ test_creds2.server) != TRUE,
+ "second cred does not match", "principal_compare");
+ krb5_free_cred_contents(context, &creds);
+
+ free_test_cred(context);
+}
+
extern const krb5_cc_ops krb5_mcc_ops;
extern const krb5_cc_ops krb5_fcc_ops;
test_memory_concurrent(context);
+ test_order(context, "MEMORY:order");
+
krb5_free_context(context);
return 0;
}