/* Utility routine: Creates the back-end data for a memory cache, and threads it into the global linked list. Call with the global list lock held. */ static krb5_error_code new_mcc_data (const char *name, krb5_mcc_data **dataptr) { krb5_error_code err; krb5_mcc_data *d; krb5_mcc_list_node *n; d = malloc(sizeof(krb5_mcc_data)); if (d == NULL) return KRB5_CC_NOMEM; err = k5_cc_mutex_init(&d->lock); if (err) { free(d); return err; } d->name = strdup(name); if (d->name == NULL) { k5_cc_mutex_destroy(&d->lock); free(d); return KRB5_CC_NOMEM; } d->link = NULL; d->prin = NULL; d->changetime = 0; d->time_offset = 0; d->usec_offset = 0; update_mcc_change_time(d); n = malloc(sizeof(krb5_mcc_list_node)); if (n == NULL) { free(d->name); k5_cc_mutex_destroy(&d->lock); free(d); return KRB5_CC_NOMEM; } n->cache = d; n->next = mcc_head; mcc_head = n; *dataptr = d; return 0; }
/* * Utility routine: Creates the back-end data for a memory cache, and adds it * to the global table. Give the new object two references, one for the table * slot and one for the caller's handle. * * Call with the global table lock held. */ static krb5_error_code new_mcc_data (const char *name, krb5_mcc_data **dataptr) { krb5_error_code err; krb5_mcc_data *d; d = malloc(sizeof(krb5_mcc_data)); if (d == NULL) return KRB5_CC_NOMEM; err = k5_cc_mutex_init(&d->lock); if (err) { free(d); return err; } d->name = strdup(name); if (d->name == NULL) { k5_cc_mutex_destroy(&d->lock); free(d); return KRB5_CC_NOMEM; } d->link = NULL; d->prin = NULL; d->time_offset = 0; d->usec_offset = 0; d->refcount = 2; d->generation = 0; if (k5_hashtab_add(mcc_hashtab, d->name, strlen(d->name), d) != 0) { free(d->name); k5_cc_mutex_destroy(&d->lock); free(d); return KRB5_CC_NOMEM; } *dataptr = d; return 0; }
/* Create a file ccache handle for the pathname given by residual. */ static krb5_error_code KRB5_CALLCONV fcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) { krb5_ccache lid; krb5_error_code ret; fcc_data *data; struct fcc_set *setptr; k5_cc_mutex_lock(context, &krb5int_cc_file_mutex); for (setptr = fccs; setptr; setptr = setptr->next) { if (!strcmp(setptr->data->filename, residual)) break; } if (setptr) { data = setptr->data; assert(setptr->refcount != 0); setptr->refcount++; assert(setptr->refcount != 0); k5_cc_mutex_lock(context, &data->lock); k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); } else { data = malloc(sizeof(fcc_data)); if (data == NULL) { k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); return KRB5_CC_NOMEM; } data->filename = strdup(residual); if (data->filename == NULL) { k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); free(data); return KRB5_CC_NOMEM; } ret = k5_cc_mutex_init(&data->lock); if (ret) { k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); free(data->filename); free(data); return ret; } k5_cc_mutex_lock(context, &data->lock); /* data->version,mode filled in for real later */ data->version = data->mode = 0; data->flags = KRB5_TC_OPENCLOSE; data->fd = -1; data->valid_bytes = 0; setptr = malloc(sizeof(struct fcc_set)); if (setptr == NULL) { k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); k5_cc_mutex_unlock(context, &data->lock); k5_cc_mutex_destroy(&data->lock); free(data->filename); free(data); return KRB5_CC_NOMEM; } setptr->refcount = 1; setptr->data = data; setptr->next = fccs; fccs = setptr; k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex); } k5_cc_mutex_assert_locked(context, &data->lock); k5_cc_mutex_unlock(context, &data->lock); lid = malloc(sizeof(struct _krb5_ccache)); if (lid == NULL) { dereference(context, data); return KRB5_CC_NOMEM; } lid->ops = &krb5_fcc_ops; lid->data = data; lid->magic = KV5M_CCACHE; /* Other routines will get errors on open, and callers must expect them, if * cache is non-existent/unusable. */ *id = lid; return 0; }