typedef struct _krb5_ktfile_data {
char *name; /* Name of the file */
FILE *openf; /* open file, if any. */
+ char iobuf[BUFSIZ]; /* so we can zap it later */
int version; /* Version number of keytab */
+ k5_mutex_t lock; /* Protect openf, version */
} krb5_ktfile_data;
/*
#define KTPRIVATE(id) ((krb5_ktfile_data *)(id)->data)
#define KTFILENAME(id) (((krb5_ktfile_data *)(id)->data)->name)
#define KTFILEP(id) (((krb5_ktfile_data *)(id)->data)->openf)
+#define KTFILEBUFP(id) (((krb5_ktfile_data *)(id)->data)->iobuf)
#define KTVERSION(id) (((krb5_ktfile_data *)(id)->data)->version)
+#define KTLOCK(id) k5_mutex_lock(&((krb5_ktfile_data *)(id)->data)->lock)
+#define KTUNLOCK(id) k5_mutex_unlock(&((krb5_ktfile_data *)(id)->data)->lock)
+#define KTCHECKLOCK(id) k5_mutex_assert_locked(&((krb5_ktfile_data *)(id)->data)->lock)
extern const struct _krb5_kt_ops krb5_ktf_ops;
extern const struct _krb5_kt_ops krb5_ktf_writable_ops;
krb5_ktfile_resolve(krb5_context context, const char *name, krb5_keytab *id)
{
krb5_ktfile_data *data;
+ krb5_error_code err;
if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
return(ENOMEM);
return(ENOMEM);
}
+ err = k5_mutex_init(&data->lock);
+ if (err) {
+ krb5_xfree(*id);
+ return err;
+ }
+
if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {
+ k5_mutex_destroy(&data->lock);
krb5_xfree(data);
krb5_xfree(*id);
return(ENOMEM);
*/
{
krb5_xfree(KTFILENAME(id));
+ zap(KTFILEBUFP(id), BUFSIZ);
+ k5_mutex_destroy(&((krb5_ktfile_data *)id->data)->lock);
krb5_xfree(id->data);
id->ops = 0;
krb5_xfree(id);
*/
krb5_error_code KRB5_CALLCONV
-krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry)
+krb5_ktfile_get_entry(krb5_context context, krb5_keytab id,
+ krb5_const_principal principal, krb5_kvno kvno,
+ krb5_enctype enctype, krb5_keytab_entry *entry)
{
krb5_keytab_entry cur_entry, new_entry;
krb5_error_code kerror = 0;
krb5_boolean similar;
int kvno_offset = 0;
+ kerror = KTLOCK(id);
+ if (kerror)
+ return kerror;
+
/* Open the keyfile for reading */
- if ((kerror = krb5_ktfileint_openr(context, id)))
+ if ((kerror = krb5_ktfileint_openr(context, id))) {
+ KTUNLOCK(id);
return(kerror);
+ }
/*
* For efficiency and simplicity, we'll use a while true that
}
if (kerror) {
(void) krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
krb5_kt_free_entry(context, &cur_entry);
return kerror;
}
if ((kerror = krb5_ktfileint_close(context, id)) != 0) {
+ KTUNLOCK(id);
krb5_kt_free_entry(context, &cur_entry);
return kerror;
}
+ KTUNLOCK(id);
*entry = cur_entry;
return 0;
}
krb5_error_code retval;
long *fileoff;
- if ((retval = krb5_ktfileint_openr(context, id)))
+ retval = KTLOCK(id);
+ if (retval)
+ return retval;
+
+ if ((retval = krb5_ktfileint_openr(context, id))) {
+ KTUNLOCK(id);
return retval;
+ }
if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
return ENOMEM;
}
*fileoff = ftell(KTFILEP(id));
*cursorp = (krb5_kt_cursor)fileoff;
+ KTUNLOCK(id);
return 0;
}
krb5_keytab_entry cur_entry;
krb5_error_code kerror;
- if (fseek(KTFILEP(id), *fileoff, 0) == -1)
+ kerror = KTLOCK(id);
+ if (kerror)
+ return kerror;
+ if (fseek(KTFILEP(id), *fileoff, 0) == -1) {
+ KTUNLOCK(id);
return KRB5_KT_END;
- if ((kerror = krb5_ktfileint_read_entry(context, id, &cur_entry)))
+ }
+ if ((kerror = krb5_ktfileint_read_entry(context, id, &cur_entry))) {
+ KTUNLOCK(id);
return kerror;
+ }
*fileoff = ftell(KTFILEP(id));
*entry = cur_entry;
+ KTUNLOCK(id);
return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_ktfile_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
{
+ krb5_error_code kerror;
+
krb5_xfree(*cursor);
- return krb5_ktfileint_close(context, id);
+ KTLOCK(id);
+ kerror = krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
+ return kerror;
}
/*
{
krb5_error_code retval;
- if ((retval = krb5_ktfileint_openw(context, id)))
+ retval = KTLOCK(id);
+ if (retval)
+ return retval;
+ if ((retval = krb5_ktfileint_openw(context, id))) {
+ KTUNLOCK(id);
return retval;
- if (fseek(KTFILEP(id), 0, 2) == -1)
+ }
+ if (fseek(KTFILEP(id), 0, 2) == -1) {
+ KTUNLOCK(id);
return KRB5_KT_END;
+ }
retval = krb5_ktfileint_write_entry(context, id, entry);
krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
return retval;
}
krb5_error_code kerror;
krb5_int32 delete_point;
+ kerror = KTLOCK(id);
+ if (kerror)
+ return kerror;
+
if ((kerror = krb5_ktfileint_openw(context, id))) {
+ KTUNLOCK(id);
return kerror;
}
if (kerror) {
(void) krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
return kerror;
}
} else {
kerror = krb5_ktfileint_close(context, id);
}
-
+ KTUNLOCK(id);
return kerror;
}
krb5_kt_vno kt_vno;
int writevno = 0;
+ KTCHECKLOCK(id);
errno = 0;
KTFILEP(id) = fopen(KTFILENAME(id),
(mode == KRB5_LOCKMODE_EXCLUSIVE) ?
return kerror;
}
/* assume ANSI or BSD-style stdio */
- setbuf(KTFILEP(id), NULL);
+ setbuf(KTFILEP(id), KTFILEBUFP(id));
/* get the vno and verify it */
if (writevno) {
{
krb5_error_code kerror;
+ KTCHECKLOCK(id);
if (!KTFILEP(id))
return 0;
kerror = krb5_unlock_file(context, fileno(KTFILEP(id)));
krb5_int32 len;
char iobuf[BUFSIZ];
+ KTCHECKLOCK(id);
if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
return errno;
}
char *tmpdata;
krb5_data *princ;
+ KTCHECKLOCK(id);
memset(ret_entry, 0, sizeof(krb5_keytab_entry));
ret_entry->magic = KV5M_KEYTAB_ENTRY;
krb5_int32 size_needed;
krb5_int32 commit_point;
int i;
- char iobuf[BUFSIZ];
+ KTCHECKLOCK(id);
retval = krb5_ktfileint_size_entry(context, entry, &size_needed);
if (retval)
return retval;
if (retval)
return retval;
- setbuf(KTFILEP(id), iobuf);
-
/* fseek to synchronise buffered I/O on the key table. */
-
+ /* XXX Without the weird setbuf crock, can we get rid of this now? */
if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
{
return errno;
if (!xfwrite(&count, sizeof(count), 1, KTFILEP(id))) {
abend:
- setbuf(KTFILEP(id), 0);
return KRB5_KT_IOERR;
}
size = krb5_princ_realm(context, entry->principal)->length;
}
if (!xfwrite(entry->key.contents, sizeof(krb5_octet),
entry->key.length, KTFILEP(id))) {
- memset(iobuf, 0, sizeof(iobuf));
- setbuf(KTFILEP(id), 0);
- return KRB5_KT_IOERR;
+ goto abend;
}
+ if (fflush(KTFILEP(id)))
+ goto abend;
+
retval = krb5_sync_disk_file(context, KTFILEP(id));
- (void) memset(iobuf, 0, sizeof(iobuf));
- setbuf(KTFILEP(id), 0);
if (retval) {
return retval;
if (!xfwrite(&size_needed, sizeof(size_needed), 1, KTFILEP(id))) {
goto abend;
}
+ if (fflush(KTFILEP(id)))
+ goto abend;
retval = krb5_sync_disk_file(context, KTFILEP(id));
return retval;
krb5_boolean found = FALSE;
char iobuf[BUFSIZ];
+ KTCHECKLOCK(id);
/*
* Skip over file version number
*/
/*
* Hit the end of file, reserve this slot.
*/
- setbuf(KTFILEP(id), 0);
size = 0;
/* fseek to synchronise buffered I/O on the key table. */
-
+ /* XXX Without the weird setbuf hack, can we nuke this now? */
if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
{
return errno;
* Make sure we zero any trailing data.
*/
zero_point = ftell(KTFILEP(id));
- setbuf(KTFILEP(id), iobuf);
while ((size = xfread(iobuf, 1, sizeof(iobuf), KTFILEP(id)))) {
if (size != sizeof(iobuf)) {
remainder = size % sizeof(krb5_int32);
memset(iobuf, 0, (size_t) size);
xfwrite(iobuf, 1, (size_t) size, KTFILEP(id));
+ fflush(KTFILEP(id));
if (feof(KTFILEP(id))) {
break;
}
}
}
- setbuf(KTFILEP(id), 0);
if (fseek(KTFILEP(id), zero_point, SEEK_SET)) {
return errno;
}