aboutsummaryrefslogtreecommitdiff
path: root/src/lib/krb5/keytab/kt_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5/keytab/kt_file.c')
-rw-r--r--src/lib/krb5/keytab/kt_file.c125
1 files changed, 99 insertions, 26 deletions
diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
index c6f94f2..6fb9f7b 100644
--- a/src/lib/krb5/keytab/kt_file.c
+++ b/src/lib/krb5/keytab/kt_file.c
@@ -52,7 +52,9 @@
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;
/*
@@ -61,7 +63,11 @@ typedef struct _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;
@@ -175,6 +181,7 @@ krb5_error_code KRB5_CALLCONV
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);
@@ -185,7 +192,14 @@ krb5_ktfile_resolve(krb5_context context, const char *name, krb5_keytab *id)
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);
@@ -217,6 +231,8 @@ krb5_ktfile_close(krb5_context context, krb5_keytab id)
*/
{
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);
@@ -230,7 +246,9 @@ krb5_ktfile_close(krb5_context context, krb5_keytab 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;
@@ -238,9 +256,15 @@ krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal
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
@@ -347,13 +371,16 @@ krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal
}
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;
}
@@ -399,15 +426,23 @@ krb5_ktfile_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *
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;
}
@@ -423,12 +458,20 @@ krb5_ktfile_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *en
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;
}
@@ -439,8 +482,13 @@ krb5_ktfile_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *en
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;
}
/*
@@ -745,6 +793,7 @@ krb5_error_code KRB5_CALLCONV
krb5_ktfile_wresolve(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);
@@ -755,7 +804,14 @@ krb5_ktfile_wresolve(krb5_context context, const char *name, krb5_keytab *id)
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);
@@ -780,12 +836,20 @@ krb5_ktfile_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
{
krb5_error_code retval;
- if ((retval = krb5_ktfileint_openw(context, id)))
+ retval = KTLOCK(id);
+ if (retval)
return retval;
- if (fseek(KTFILEP(id), 0, 2) == -1)
+ if ((retval = krb5_ktfileint_openw(context, id))) {
+ KTUNLOCK(id);
+ return retval;
+ }
+ 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;
}
@@ -800,7 +864,12 @@ krb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entr
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;
}
@@ -829,6 +898,7 @@ krb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entr
if (kerror) {
(void) krb5_ktfileint_close(context, id);
+ KTUNLOCK(id);
return kerror;
}
@@ -839,7 +909,7 @@ krb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entr
} else {
kerror = krb5_ktfileint_close(context, id);
}
-
+ KTUNLOCK(id);
return kerror;
}
@@ -999,6 +1069,8 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
krb5_kt_vno kt_vno;
int writevno = 0;
+ KTCHECKLOCK(id);
+ errno = 0;
KTFILEP(id) = fopen(KTFILENAME(id),
(mode == KRB5_LOCKMODE_EXCLUSIVE) ?
fopen_mode_rbplus : fopen_mode_rb);
@@ -1006,12 +1078,13 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
/* try making it first time around */
krb5_create_secure_file(context, KTFILENAME(id));
+ errno = 0;
KTFILEP(id) = fopen(KTFILENAME(id), fopen_mode_rbplus);
if (!KTFILEP(id))
- return errno;
+ return errno ? errno : EMFILE;
writevno = 1;
} else /* some other error */
- return errno;
+ return errno ? errno : EMFILE;
}
if ((kerror = krb5_lock_file(context, fileno(KTFILEP(id)), mode))) {
(void) fclose(KTFILEP(id));
@@ -1019,7 +1092,7 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
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) {
@@ -1067,6 +1140,7 @@ krb5_ktfileint_close(krb5_context context, krb5_keytab id)
{
krb5_error_code kerror;
+ KTCHECKLOCK(id);
if (!KTFILEP(id))
return 0;
kerror = krb5_unlock_file(context, fileno(KTFILEP(id)));
@@ -1082,6 +1156,7 @@ krb5_ktfileint_delete_entry(krb5_context context, krb5_keytab id, krb5_int32 del
krb5_int32 len;
char iobuf[BUFSIZ];
+ KTCHECKLOCK(id);
if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
return errno;
}
@@ -1140,6 +1215,7 @@ krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_ke
char *tmpdata;
krb5_data *princ;
+ KTCHECKLOCK(id);
memset(ret_entry, 0, sizeof(krb5_keytab_entry));
ret_entry->magic = KV5M_KEYTAB_ENTRY;
@@ -1356,8 +1432,8 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent
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;
@@ -1365,10 +1441,8 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent
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;
@@ -1382,7 +1456,6 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent
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;
@@ -1457,14 +1530,13 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent
}
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;
@@ -1478,6 +1550,8 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent
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;
@@ -1536,6 +1610,7 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_
krb5_boolean found = FALSE;
char iobuf[BUFSIZ];
+ KTCHECKLOCK(id);
/*
* Skip over file version number
*/
@@ -1552,11 +1627,10 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_
/*
* 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;
@@ -1607,7 +1681,6 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_
* 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);
@@ -1623,6 +1696,7 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_
memset(iobuf, 0, (size_t) size);
xfwrite(iobuf, 1, (size_t) size, KTFILEP(id));
+ fflush(KTFILEP(id));
if (feof(KTFILEP(id))) {
break;
}
@@ -1633,7 +1707,6 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_
}
}
- setbuf(KTFILEP(id), 0);
if (fseek(KTFILEP(id), zero_point, SEEK_SET)) {
return errno;
}