etc.
*/
/* todo:
-Make sure that each time a function returns KRB5_NOMEM, everything
-allocated earlier in the function and stack tree is freed.
+ Make sure that each time a function returns KRB5_NOMEM, everything
+ allocated earlier in the function and stack tree is freed.
#ifndef USE_STDIO
-File locking
+ File locking
-fcc_nseq.c and fcc_read don't check return values a lot.
+ Use pread/pwrite if available, so multiple threads can read
+ simultaneously. (That may require reader/writer locks.)
+
+ fcc_nseq.c and fcc_read don't check return values a lot.
#else
-Overwrite cache file with nulls before removing it.
-#endif
+ Overwrite cache file with nulls before removing it.
-#ifdef USE_STDIO
-Check return values and sanity-check parameters more thoroughly. This
-code was derived from UNIX file I/O code, and the conversion of
-error-trapping may be incomplete. Probably lots of bugs dealing with
-end-of-file versus other errors.
+ Check return values and sanity-check parameters more thoroughly. This
+ code was derived from UNIX file I/O code, and the conversion of
+ error-trapping may be incomplete. Probably lots of bugs dealing with
+ end-of-file versus other errors.
#endif
*/
#include "k5-int.h"
typedef struct _krb5_fcc_data {
char *filename;
+ k5_mutex_t lock;
#ifndef USE_STDIO
int file;
#else
#endif
} krb5_fcc_cursor;
-#define MAYBE_OPEN(CONTEXT, ID, MODE) \
+#define MAYBE_OPEN(CONTEXT, ID, MODE) \
{ \
+ k5_assert_locked(&((krb5_fcc_data *)(ID)->data)->lock); \
if (OPENCLOSE (ID)) { \
- krb5_error_code maybe_open_ret = krb5_fcc_open_file (CONTEXT,ID,MODE); \
- if (maybe_open_ret) return maybe_open_ret; } }
+ krb5_error_code maybe_open_ret; \
+ maybe_open_ret = krb5_fcc_open_file (CONTEXT,ID,MODE); \
+ if (maybe_open_ret) { \
+ k5_mutex_unlock(&((krb5_fcc_data *)(ID)->data)->lock); \
+ return maybe_open_ret; \
+ } \
+ } \
+}
#define MAYBE_CLOSE(CONTEXT, ID, RET) \
{ \
#endif
#define CHECK(ret) if (ret != KRB5_OK) goto errout;
-
+
#ifndef USE_STDIO
#define NO_FILE -1
#else
* Effects:
* Reads len bytes from the cache id, storing them in buf.
*
+ * Requires:
+ * Must be called with mutex locked.
+ *
* Errors:
* KRB5_CC_END - there were not len bytes available
* system errors (read)
{
int ret;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
#ifndef USE_STDIO
ret = read(((krb5_fcc_data *) id->data)->file, (char *) buf, len);
if (ret == -1)
* Requires:
* id is open and set to read at the appropriate place in the file
*
+ * mutex is locked
+ *
* Effects:
* Fills in the second argument with data of the appropriate type from
* the file. In some cases, the functions have to allocate space for
krb5_int32 length, type;
int i;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if (data->version == KRB5_FCC_FVNO_1) {
type = KRB5_NT_UNKNOWN;
} else {
size_t msize;
int i;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
*addrs = 0;
/* Read the number of components */
krb5_ui_2 ui2;
krb5_int32 int32;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
keyblock->magic = KV5M_KEYBLOCK;
keyblock->contents = 0;
krb5_error_code kret;
krb5_int32 len;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
data->magic = KV5M_DATA;
data->data = 0;
krb5_ui_2 ui2;
krb5_int32 int32;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
addr->magic = KV5M_ADDRESS;
addr->contents = 0;
unsigned char buf[4];
krb5_int32 val;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_int32));
krb5_error_code retval;
unsigned char buf[2];
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_ui_2));
static krb5_error_code
krb5_fcc_read_octet(krb5_context context, krb5_ccache id, krb5_octet *i)
{
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
return krb5_fcc_read(context, id, (krb5_pointer) i, 1);
}
krb5_error_code retval;
krb5_int32 i;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_read(context, id, (krb5_pointer) t, sizeof(krb5_ticket_times));
size_t msize;
int i;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
*a = 0;
/* Read the number of components */
krb5_int32 int32;
krb5_ui_2 ui2;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
a->magic = KV5M_AUTHDATA;
a->contents = NULL;
krb5_fcc_write(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned int len)
{
int ret;
+
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
#ifndef USE_STDIO
ret = write(((krb5_fcc_data *)id->data)->file, (char *) buf, len);
if (ret < 0)
*
* Requires:
* ((krb5_fcc_data *) id->data)->file is open and at the right position.
+ *
+ * mutex is locked
*
* Effects:
* Stores an encoded version of the second argument in the
krb5_error_code ret;
krb5_int32 i, length, tmp, type;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
type = krb5_princ_type(context, princ);
tmp = length = krb5_princ_size(context, princ);
krb5_address **temp;
krb5_int32 i, length = 0;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
/* Count the number of components */
if (addrs) {
temp = addrs;
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
krb5_error_code ret;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
CHECK(ret);
if (data->version == KRB5_FCC_FVNO_3) {
{
krb5_error_code ret;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
ret = krb5_fcc_store_ui_2(context, id, addr->addrtype);
CHECK(ret);
ret = krb5_fcc_store_ui_4(context, id, addr->length);
{
krb5_error_code ret;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
ret = krb5_fcc_store_ui_4(context, id, data->length);
CHECK(ret);
return krb5_fcc_write(context, id, data->data, data->length);
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
unsigned char buf[4];
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_write(context, id, (char *) &i, sizeof(krb5_int32));
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
unsigned char buf[4];
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_write(context, id, (char *) &i, sizeof(krb5_int32));
krb5_ui_2 ibuf;
unsigned char buf[2];
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2)) {
ibuf = (krb5_ui_2) i;
{
krb5_octet ibuf;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
ibuf = (krb5_octet) i;
return krb5_fcc_write(context, id, (char *) &ibuf, 1);
}
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
krb5_error_code retval;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if ((data->version == KRB5_FCC_FVNO_1) ||
(data->version == KRB5_FCC_FVNO_2))
return krb5_fcc_write(context, id, (char *) t, sizeof(krb5_ticket_times));
krb5_authdata **temp;
krb5_int32 i, length=0;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if (a != NULL) {
for (temp=a; *temp; temp++)
length++;
krb5_fcc_store_authdatum (krb5_context context, krb5_ccache id, krb5_authdata *a)
{
krb5_error_code ret;
+
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
ret = krb5_fcc_store_ui_2(context, id, a->ad_type);
CHECK(ret);
ret = krb5_fcc_store_ui_4(context, id, a->length);
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
krb5_error_code retval;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if (data->file == NO_FILE)
return KRB5_FCC_INTERNAL;
int lock_flag;
krb5_error_code retval = 0;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
if (data->file != NO_FILE) {
/* Don't know what state it's in; shut down and start anew. */
#ifndef USE_STDIO
krb5_error_code kret;
krb5_ui_2 fcc_flen;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
#ifndef USE_STDIO
lseek(data->file, (off_t) sizeof(krb5_ui_2), SEEK_SET);
#else
krb5_error_code kret;
krb5_principal princ;
+ k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
kret = krb5_fcc_read_principal(context, id, &princ);
if (kret != KRB5_OK)
return kret;
int reti = 0;
#endif
+ kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+ if (kret)
+ return kret;
+
#ifndef USE_STDIO
MAYBE_OPEN(context, id, FCC_OPEN_AND_ERASE);
#else
kret = krb5_fcc_open_file (context, id, FCC_OPEN_AND_ERASE);
- if (kret < 0)
- return krb5_fcc_interpret(context, errno);
+ if (kret < 0) {
+ int e = errno;
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+ return krb5_fcc_interpret(context, e);
+ }
#endif
#ifndef USE_STDIO
if (reti == -1) {
kret = krb5_fcc_interpret(context, errno);
MAYBE_CLOSE(context, id, kret);
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
return kret;
}
}
kret = krb5_fcc_store_principal(context, id, princ);
MAYBE_CLOSE(context, id, kret);
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
krb5_change_cache ();
return kret;
}
register int closeval = KRB5_OK;
register krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+ /* If locking fails, ignore it, since we're destroying the thing
+ anyways. */
+ k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
#ifndef USE_STDIO
if (data->file >= 0)
krb5_fcc_close_file(context, id);
}
#endif
krb5_xfree(data->filename);
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+ k5_mutex_destroy(&((krb5_fcc_data *) id->data)->lock);
krb5_xfree(data);
krb5_xfree(id);
static krb5_error_code KRB5_CALLCONV
krb5_fcc_destroy(krb5_context context, krb5_ccache id)
{
+ krb5_error_code kret = 0;
+ krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+ register int ret;
+
#ifndef USE_STDIO
struct stat buf;
unsigned long i, size;
unsigned int wlen;
char zeros[BUFSIZ];
- register int ret;
- krb5_error_code kret = 0;
-
-
+
if (OPENCLOSE(id)) {
ret = THREEPARAMOPEN(((krb5_fcc_data *) id->data)->filename, O_RDWR | O_BINARY, 0);
if (ret < 0) {
#endif /* MSDOS_FILESYSTEM */
- cleanup:
- krb5_xfree(((krb5_fcc_data *) id->data)->filename);
- krb5_xfree(id->data);
- krb5_xfree(id);
-
- krb5_change_cache ();
- return kret;
#else
- krb5_fcc_data *data = (krb5_fcc_data *) id->data;
- register int ret;
if (!OPENCLOSE(id)) {
(void) fclose(data->file);
ret = remove (data->filename);
if (ret < 0) {
- ret = krb5_fcc_interpret(context, errno);
+ kret = krb5_fcc_interpret(context, errno);
if (OPENCLOSE(id)) {
(void) fclose(data->file);
data->file = 0;
*/
if (ret)
- ret = krb5_fcc_interpret(context, errno);
+ kret = krb5_fcc_interpret(context, errno);
+#endif
cleanup:
krb5_xfree(data->filename);
+ k5_mutex_destroy(&data->lock);
krb5_xfree(data);
krb5_xfree(id);
krb5_change_cache ();
- return ret;
-#endif
+ return kret;
}
extern const krb5_cc_ops krb5_fcc_ops;
krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
{
krb5_ccache lid;
-
+ krb5_error_code kret;
+ krb5_fcc_data *data;
+
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
if (lid == NULL)
return KRB5_CC_NOMEM;
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
+ data = (krb5_fcc_data *) lid->data;
+ data->filename = (char *) malloc(strlen(residual) + 1);
- ((krb5_fcc_data *) lid->data)->filename = (char *)
- malloc(strlen(residual) + 1);
-
- if (((krb5_fcc_data *) lid->data)->filename == NULL) {
- krb5_xfree(((krb5_fcc_data *) lid->data));
+ if (data->filename == NULL) {
+ krb5_xfree(data);
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
+ kret = k5_mutex_init(&data->lock);
+ if (kret) {
+ krb5_xfree(data->filename);
+ krb5_xfree(data);
+ krb5_xfree(lid);
+ return kret;
+ }
+
/* default to open/close on every trn */
- ((krb5_fcc_data *) lid->data)->flags = KRB5_TC_OPENCLOSE;
+ data->flags = KRB5_TC_OPENCLOSE;
#ifndef USE_STDIO
- ((krb5_fcc_data *) lid->data)->file = -1;
+ data->file = -1;
#else
- ((krb5_fcc_data *) lid->data)->file = 0;
+ data->file = 0;
#endif
/* Set up the filename */
- strcpy(((krb5_fcc_data *) lid->data)->filename, residual);
+ strcpy(data->filename, residual);
lid->magic = KV5M_CCACHE;
krb5_error_code kret = KRB5_OK;
krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+ kret = k5_mutex_lock(&data->lock);
+ if (kret)
+ return kret;
+
fcursor = (krb5_fcc_cursor *) malloc(sizeof(krb5_fcc_cursor));
- if (fcursor == NULL)
- return KRB5_CC_NOMEM;
+ if (fcursor == NULL) {
+ k5_mutex_unlock(&data->lock);
+ return KRB5_CC_NOMEM;
+ }
#ifndef USE_STDIO
if (OPENCLOSE(id)) {
kret = krb5_fcc_open_file(context, id, FCC_OPEN_RDONLY);
if (kret) {
krb5_xfree(fcursor);
+ k5_mutex_unlock(&data->lock);
return kret;
}
}
/* Make sure we start reading right after the primary principal */
#ifdef USE_STDIO
MAYBE_OPEN (context, id, FCC_OPEN_RDONLY);
-
#endif
+
kret = krb5_fcc_skip_header(context, id);
if (kret) goto done;
kret = krb5_fcc_skip_principal(context, id);
done:
MAYBE_CLOSE(context, id, kret);
+ k5_mutex_unlock(&data->lock);
return kret;
}
krb5_fcc_cursor *fcursor;
krb5_int32 int32;
krb5_octet octet;
+ krb5_fcc_data *d = (krb5_fcc_data *) id->data;
-#ifndef USE_STDIO
- memset((char *)creds, 0, sizeof(*creds));
-#else
-#define Z(field) creds->field = 0
- Z (client);
- Z (server);
- Z (keyblock.contents);
- Z (authdata);
- Z (ticket.data);
- Z (second_ticket.data);
- Z (addresses);
-#undef Z
-#endif
+ kret = k5_mutex_lock(&d->lock);
+ if (kret)
+ return kret;
+ memset((char *)creds, 0, sizeof(*creds));
MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
-
fcursor = (krb5_fcc_cursor *) *cursor;
#ifndef USE_STDIO
- kret = (lseek(((krb5_fcc_data *) id->data)->file, fcursor->pos, SEEK_SET) == (off_t) -1);
+ kret = (lseek(d->file, fcursor->pos, SEEK_SET) == (off_t) -1);
#else
- kret = (fseek(((krb5_fcc_data *) id->data)->file, fcursor->pos, 0) < 0);
+ kret = (fseek(d->file, fcursor->pos, 0) < 0);
#endif
if (kret) {
kret = krb5_fcc_interpret(context, errno);
MAYBE_CLOSE(context, id, kret);
+ k5_mutex_unlock(&d->lock);
return kret;
}
TCHECK(kret);
#ifndef USE_STDIO
- fcursor->pos = lseek(((krb5_fcc_data *) id->data)->file, (off_t) 0,
- SEEK_CUR);
+ fcursor->pos = lseek(d->file, (off_t) 0, SEEK_CUR);
#else
- fcursor->pos = ftell(((krb5_fcc_data *) id->data)->file);
+ fcursor->pos = ftell(d->file);
#endif
cursor = (krb5_cc_cursor *) fcursor;
lose:
-#ifndef USE_STDIO
- MAYBE_CLOSE(context, id, kret); /* won't overwrite kret
- if already set */
-#endif
+ MAYBE_CLOSE (context, id, kret);
+ k5_mutex_unlock(&d->lock);
if (kret != KRB5_OK)
krb5_free_cred_contents(context, creds);
-#ifdef USE_STDIO
- MAYBE_CLOSE (context, id, kret);
-#endif
return kret;
}
static krb5_error_code KRB5_CALLCONV
krb5_fcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
{
+ /* We don't do anything with the file cache itself, so
+ no need to lock anything. */
+
/* don't close; it may be left open by the caller,
and if not, fcc_start_seq_get and/or fcc_next_cred will do the
MAYBE_CLOSE.
MAYBE_CLOSE(context, id, kret); */
krb5_xfree((krb5_fcc_cursor *) *cursor);
-
return 0;
}
{
krb5_error_code kret = KRB5_OK;
+ kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+ if (kret)
+ return kret;
+
MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
/* make sure we're beyond the header */
done:
MAYBE_CLOSE(context, id, kret);
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
return kret;
}
#define TCHECK(ret) if (ret != KRB5_OK) goto lose;
krb5_error_code ret;
+ ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+ if (ret)
+ return ret;
+
/* Make sure we are writing to the end of the file */
MAYBE_OPEN(context, id, FCC_OPEN_RDWR);
#ifndef USE_STDIO
MAYBE_CLOSE_IGNORE(context, id);
#endif
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
return krb5_fcc_interpret(context, errno);
}
lose:
MAYBE_CLOSE(context, id, ret);
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
krb5_change_cache ();
return ret;
#undef TCHECK
{
krb5_error_code ret = KRB5_OK;
+ ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+ if (ret)
+ return ret;
+
/* XXX This should check for illegal combinations, if any.. */
if (flags & KRB5_TC_OPENCLOSE) {
/* asking to turn on OPENCLOSE mode */
}
((krb5_fcc_data *) id->data)->flags = flags;
+ k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
return ret;
}