FILE *openf; /* open file, if any. */
char iobuf[BUFSIZ]; /* so we can zap it later */
int version; /* Version number of keytab */
+ unsigned int iter_count; /* Number of active iterators */
+ long start_offset; /* Starting offset after version */
k5_mutex_t lock; /* Protect openf, version */
} krb5_ktfile_data;
+/*
+ * Some limitations:
+ *
+ * If the file OPENF is left open between calls, we have an iterator
+ * active, and OPENF is opened in read-only mode. So, no changes
+ * can be made via that handle.
+ *
+ * An advisory file lock is used while the file is open. Thus,
+ * multiple handles on the same underlying file cannot be used without
+ * disrupting the locking in effect.
+ *
+ * The start_offset field is only valid if the file is open. It will
+ * almost certainly always be the same constant. It's used so that
+ * if an iterator is active, and we start another one, we don't have
+ * to seek back to the start and re-read the version number to set
+ * the position for the iterator.
+ */
+
/*
* Macros
*/
#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 KTITERS(id) (((krb5_ktfile_data *)(id)->data)->iter_count)
+#define KTSTARTOFF(id) (((krb5_ktfile_data *)(id)->data)->start_offset)
#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)
(void) strcpy(data->name, name);
data->openf = 0;
data->version = 0;
+ data->iter_count = 0;
(*id)->data = (krb5_pointer)data;
(*id)->magic = KV5M_KEYTAB;
int found_wrong_kvno = 0;
krb5_boolean similar;
int kvno_offset = 0;
+ int was_open;
kerror = KTLOCK(id);
if (kerror)
return kerror;
- /* Open the keyfile for reading */
- if ((kerror = krb5_ktfileint_openr(context, id))) {
- KTUNLOCK(id);
- return(kerror);
+ if (KTFILEP(id) != NULL) {
+ was_open = 1;
+
+ if (fseek(KTFILEP(id), KTSTARTOFF(id), SEEK_SET) == -1) {
+ KTUNLOCK(id);
+ return errno;
+ }
+ } else {
+ was_open = 0;
+
+ /* Open the keyfile for reading */
+ if ((kerror = krb5_ktfileint_openr(context, id))) {
+ KTUNLOCK(id);
+ return(kerror);
+ }
}
/*
kerror = KRB5_KT_NOTFOUND;
}
if (kerror) {
- (void) krb5_ktfileint_close(context, id);
+ if (was_open == 0)
+ (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) {
+ if (was_open == 0 && (kerror = krb5_ktfileint_close(context, id)) != 0) {
KTUNLOCK(id);
krb5_kt_free_entry(context, &cur_entry);
return kerror;
if (retval)
return retval;
- if ((retval = krb5_ktfileint_openr(context, id))) {
- KTUNLOCK(id);
- return retval;
+ if (KTITERS(id) == 0) {
+ if ((retval = krb5_ktfileint_openr(context, id))) {
+ KTUNLOCK(id);
+ return retval;
+ }
}
if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
- krb5_ktfileint_close(context, id);
+ if (KTITERS(id) == 0)
+ krb5_ktfileint_close(context, id);
KTUNLOCK(id);
return ENOMEM;
}
- *fileoff = ftell(KTFILEP(id));
+ *fileoff = KTSTARTOFF(id);
*cursorp = (krb5_kt_cursor)fileoff;
+ KTITERS(id)++;
+ if (KTITERS(id) == 0) {
+ /* Wrapped?! */
+ KTITERS(id)--;
+ KTUNLOCK(id);
+ return KRB5_KT_IOERR; /* XXX */
+ }
KTUNLOCK(id);
return 0;
krb5_xfree(*cursor);
KTLOCK(id);
- kerror = krb5_ktfileint_close(context, id);
+ KTITERS(id)--;
+ if (KTFILEP(id) != NULL && KTITERS(id) == 0)
+ kerror = krb5_ktfileint_close(context, id);
+ else
+ kerror = 0;
KTUNLOCK(id);
return kerror;
}
(void) strcpy(data->name, name);
data->openf = 0;
data->version = 0;
+ data->iter_count = 0;
(*id)->data = (krb5_pointer)data;
(*id)->magic = KV5M_KEYTAB;
retval = KTLOCK(id);
if (retval)
return retval;
+ if (KTFILEP(id)) {
+ /* Iterator(s) active -- no changes. */
+ KTUNLOCK(id);
+ return KRB5_KT_IOERR; /* XXX */
+ }
if ((retval = krb5_ktfileint_openw(context, id))) {
KTUNLOCK(id);
return retval;
kerror = KTLOCK(id);
if (kerror)
return kerror;
+ if (KTFILEP(id)) {
+ /* Iterator(s) active -- no changes. */
+ KTUNLOCK(id);
+ return KRB5_KT_IOERR; /* XXX */
+ }
if ((kerror = krb5_ktfileint_openw(context, id))) {
KTUNLOCK(id);
return KRB5_KEYTAB_BADVNO;
}
}
+ KTSTARTOFF(id) = ftell(KTFILEP(id));
return 0;
}
krb5_timestamp timestamp;
krb5_int32 princ_type;
krb5_int32 size_needed;
- krb5_int32 commit_point;
+ krb5_int32 commit_point = -1;
int i;
KTCHECKLOCK(id);