*** empty log message ***
authorJohn Kohl <jtkohl@mit.edu>
Tue, 3 Apr 1990 11:30:31 +0000 (11:30 +0000)
committerJohn Kohl <jtkohl@mit.edu>
Tue, 3 Apr 1990 11:30:31 +0000 (11:30 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@452 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/rcache/rc_base.h [new file with mode: 0644]
src/lib/krb5/rcache/rc_dfl.c [new file with mode: 0644]

diff --git a/src/lib/krb5/rcache/rc_base.h b/src/lib/krb5/rcache/rc_base.h
new file mode 100644 (file)
index 0000000..047b816
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+Copyright 1990, Daniel J. Bernstein. All rights reserved.
+
+Please address any questions or comments to the author at brnstnd@acf10.nyu.edu.
+*/
+
+#ifndef KRB5_RC_H
+#define KRB5_RC_H
+#include "krb5/krb5.h"
+
+typedef struct krb5_inRC
+ {
+  struct krb5_rc_type *ops;
+  void *data;
+ }
+*krb5_RC;
+
+struct krb5_rc_type
+ {
+  char *type;
+  krb5_error_code (*init)PROTOTYPE((krb5_RC,krb5_deltat)); /* i.e., create */
+  krb5_error_code (*recover)PROTOTYPE((krb5_RC)); /* i.e., open */
+  krb5_error_code (*destroy)PROTOTYPE((krb5_RC));
+  krb5_error_code (*close)PROTOTYPE((krb5_RC));
+  krb5_error_code (*store)PROTOTYPE((krb5_RC,krb5_tkt_authent *));
+  krb5_error_code (*expunge)PROTOTYPE((krb5_RC));
+  krb5_error_code (*get_span)PROTOTYPE((krb5_RC,krb5_deltat *));
+  char *(*get_name)PROTOTYPE((krb5_RC));
+  krb5_error_code (*resolve)PROTOTYPE((krb5_RC *,char *name));
+ }
+;
+
+krb5_error_code krb5_rc_register_type PROTOTYPE((struct krb5_rc_type *ops));
+krb5_error_code krb5_rc_resolve_type PROTOTYPE((krb5_RC *id,char *type));
+char *krb5_rc_get_type PROTOTYPE((krb5_RC id));
+char *krb5_rc_default_type PROTOTYPE((void));
+char *krb5_rc_default_name PROTOTYPE((void));
+
+#endif
diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
new file mode 100644 (file)
index 0000000..643ebd2
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+Copyright 1990, Daniel J. Bernstein. All rights reserved.
+
+Please address any questions or comments to the author at brnstnd@acf10.nyu.edu.
+*/
+
+#include <string.h>
+#include <malloc.h>
+extern int free(char *);
+#define FREE(x) ((void) free((char *) (x)))
+#include "krb5/krb5.h"
+krb5_error_code krb5_timeofday PROTOTYPE((krb5_int32 *)); /* aargh */
+#include "rc_base.h"
+#include "rc_dfl.h"
+#include "rc_io.h"
+#include "rc_err.h"
+#include "rc_io_err.h"
+
+/*
+If NOIOSTUFF is defined at compile time, dfl rcaches will be per-process.
+*/
+
+/*
+Local stuff:
+
+struct auth_replay
+  exactly that info which must not be replayed---by this cache type, that is
+static int hash(struct auth_replay *rep,int hsize)
+  returns hash value of *rep, between 0 and hsize - 1
+HASHSIZE
+  size of hash table (constant), can be preset
+static int auth_to_rep(krb5_tkt_authent *auth,struct auth_replay *rep)
+  given auth, take important information and make rep; return -1 if failed
+static int cmp(struct auth_replay *old,struct auth_replay *new,krb5_deltat t)
+  compare old and new; return CMP_REPLAY or CMP_HOHUM
+static int alive(struct auth_replay *new,krb5_deltat t)
+  see if new is still alive; return CMP_EXPIRED or CMP_HOHUM
+CMP_MALLOC, CMP_EXPIRED, CMP_REPLAY, CMP_HOHUM
+  return codes from cmp(), alive(), and store()
+struct dfl_data
+  data stored in this cache type, namely "dfl"
+struct authlist
+  multilinked list of reps
+static int store(krb5_RC id,struct auth_replay *rep)
+  store rep in cache id; return CMP_REPLAY if replay, else CMP_MALLOC/CMP_HOHUM
+
+*/
+
+#ifndef HASHSIZE
+#define HASHSIZE 997 /* a convenient prime */
+#endif
+
+#ifndef EXCESSREPS
+#define EXCESSREPS 30
+#endif
+/* The rcache will be automatically expunged when the number of expired
+auth_replays encountered incidentally in searching exceeds the number
+of live auth_replays by EXCESSREPS. With the defaults here, a typical
+cache might build up some 10K of expired auth_replays before an automatic
+expunge, with the waste basically independent of the number of stores per
+minute. */
+
+struct auth_replay
+ {
+  char *server; /* null-terminated */
+  char *client; /* null-terminated */
+  krb5_ui_2 cmsec;
+  krb5_timestamp ctime;
+ }
+;
+
+static int hash(struct auth_replay *rep,int hsize)
+{
+ return (((rep->cmsec + rep->ctime + *rep->server + *rep->client)
+        % hsize) + hsize) % hsize;
+ /* We take this opportunity to once again complain about C's idiotic %. */
+}
+
+static int auth_to_rep(krb5_tkt_authent *auth,struct auth_replay *rep)
+{
+ rep->cmsec = auth->authenticator->cmsec;
+ rep->ctime = auth->authenticator->ctime;
+ if (krb5_unparse_name(auth->ticket->server,&rep->server))
+   return -1; /* shouldn't happen */
+ if (krb5_unparse_name(auth->authenticator->client,&rep->client))
+   return -1; /* shouldn't happen. */
+ return 0;
+}
+
+#define CMP_MALLOC -3
+#define CMP_EXPIRED -2
+#define CMP_REPLAY -1
+#define CMP_HOHUM 0
+
+static int cmp(struct auth_replay *old,struct auth_replay *new,krb5_deltat t)
+{
+ if ((old->cmsec == new->cmsec) && /* most likely to distinguish */
+     (old->ctime == new->ctime) &&
+     (strcmp(old->client,new->client) == 0) &&
+     (strcmp(old->server,new->server) == 0)) /* always true */
+   return CMP_REPLAY;
+ return CMP_HOHUM;
+}
+
+static int alive(struct auth_replay *new,krb5_deltat t)
+{
+ krb5_int32 time;
+
+ if (krb5_timeofday(&time))
+   return CMP_HOHUM; /* who cares? */
+ if (new->ctime + t < time) /* I hope we don't have to worry about overflow */
+   return CMP_EXPIRED;
+ return CMP_HOHUM;
+}
+
+struct dfl_data
+ {
+  char *name;
+  krb5_deltat lifespan;
+  int hsize;
+  int numhits;
+  int nummisses;
+  struct authlist **h;
+  struct authlist *a;
+#ifndef NOIOSTUFF
+  krb5_rc_iostuff d;
+#endif
+ }
+;
+
+struct authlist
+ {
+  struct auth_replay rep;
+  struct authlist *na;
+  struct authlist *nh;
+ }
+;
+
+/* of course, list is backwards from file */
+/* hash could be forwards since we have to search on match, but naaaah */
+
+static int store(krb5_RC id,struct auth_replay *rep)
+{
+ struct dfl_data *t = id->data;
+ int rephash;
+ struct authlist *ta;
+
+ rephash = hash(rep,t->hsize);
+
+ for (ta = t->h[rephash];ta;ta = ta->nh)
+   switch(cmp(&ta->rep,rep,t->lifespan))
+    {
+     case CMP_REPLAY: return CMP_REPLAY;
+     case CMP_HOHUM: if (alive(&ta->rep,t->lifespan) == CMP_EXPIRED)
+                      t->nummisses++;
+                    else
+                      t->numhits++;
+                    break;
+     default: ; /* wtf? */
+    }
+ if (!(ta = (struct authlist *) malloc(sizeof(struct authlist))))
+   return CMP_MALLOC;
+ ta->na = t->a; t->a = ta;
+ ta->nh = t->h[rephash]; t->h[rephash] = ta;
+ ta->rep = *rep;
+ return CMP_HOHUM;
+}
+
+char *krb5_rc_dfl_get_name(krb5_RC id)
+{
+ return ((struct dfl_data *) (id->data))->name;
+}
+
+krb5_error_code krb5_rc_dfl_get_span(krb5_RC id,krb5_deltat *lifespan)
+{
+ *lifespan = ((struct dfl_data *) (id->data))->lifespan;
+ return 0;
+}
+
+krb5_error_code krb5_rc_dfl_init(krb5_RC id,krb5_deltat lifespan)
+{
+ struct dfl_data *t = id->data;
+ int i;
+
+ t->lifespan = lifespan;
+#ifndef NOIOSTUFF
+ if (krb5_rc_io_creat(&t->d,&t->name))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan)))
+   return KRB5_RC_IO;
+#endif
+ t->numhits = t->nummisses = 0;
+ t->hsize = HASHSIZE; /* could be variable, but naaaah */
+ if (!(t->h = (struct authlist **) malloc(t->hsize*sizeof(struct authlist *))))
+   return KRB5_RC_MALLOC;
+ for (i = 0;i < t->hsize;i++)
+   t->h[i] = (struct authlist *) 0;
+ t->a = (struct authlist *) 0;
+ return 0;
+}
+
+krb5_error_code krb5_rc_dfl_close(krb5_RC id)
+{
+ struct dfl_data *t = id->data;
+ struct authlist *q;
+
+ FREE(t->h);
+ while (q = t->a)
+  {
+   t->a = q->na;
+   FREE(q->rep.client);
+   FREE(q->rep.server);
+   FREE(q);
+  }
+#ifndef NOIOSTUFF
+ (void) krb5_rc_io_close(&t->d);
+#endif
+ FREE(t);
+ return 0;
+}
+
+krb5_error_code krb5_rc_dfl_destroy(krb5_RC id)
+{
+#ifndef NOIOSTUFF
+ if (krb5_rc_io_destroy(&((struct dfl_data *) (id->data))->d))
+   return KRB5_RC_IO;
+#endif
+ return krb5_rc_dfl_close(id);
+}
+
+krb5_error_code krb5_rc_dfl_resolve(krb5_RC *id,char *name)
+{
+ struct dfl_data *t;
+
+ /* allocate id? no */
+ if (!(t = (struct dfl_data *) malloc(sizeof(struct dfl_data))))
+   return KRB5_RC_MALLOC;
+ (*id)->data = t;
+ t->name = name; /* gee, difficult... */
+ return 0;
+}
+
+krb5_error_code krb5_rc_dfl_recover(krb5_RC id)
+{
+#ifdef NOIOSTUFF
+ return KRB5_RC_NOIO;
+#else
+
+ struct dfl_data *t = id->data;
+ int i;
+ struct auth_replay *rep;
+
+ if (krb5_rc_io_open(&t->d,t->name))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_read(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan)))
+   return KRB5_RC_IO;
+ t->numhits = t->nummisses = 0;
+ t->hsize = HASHSIZE; /* no need to store---it's memory-only */
+ if (!(t->h = (struct authlist **) malloc(t->hsize*sizeof(struct authlist *))))
+   return KRB5_RC_MALLOC;
+ for (i = 0;i < t->hsize;i++)
+   t->h[i] = (struct authlist *) 0;
+ t->a = (struct authlist *) 0;
+
+ /* now read in each auth_replay and insert into table */
+ for (;;)
+  {
+#define FREE1 FREE(rep);
+#define FREE2 FREE(rep->client); FREE(rep);
+#define FREE3 FREE(rep->server); FREE(rep->client); FREE(rep);
+   if (krb5_rc_io_mark(&t->d))
+     return KRB5_RC_IO;
+   if (!(rep = (struct auth_replay *) malloc(sizeof(struct auth_replay))))
+     return KRB5_RC_MALLOC;
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) &i,sizeof(i)))
+    {
+     case KRB5_RC_IO_EOF: FREE1; goto end_loop;
+     case 0: break; default: FREE1; return KRB5_RC_IO; break;
+    }
+   if (!(rep->client = malloc(i)))
+    { FREE1; return KRB5_RC_MALLOC; }
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) rep->client,i))
+    {
+     case KRB5_RC_IO_EOF: FREE2; goto end_loop;
+     case 0: break; default: FREE2; return KRB5_RC_IO; break;
+    }
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) &i,sizeof(i)))
+    {
+     case KRB5_RC_IO_EOF: FREE2; goto end_loop;
+     case 0: break; default: FREE2; return KRB5_RC_IO; break;
+    }
+   if (!(rep->server = malloc(i)))
+    { FREE2; return KRB5_RC_MALLOC; }
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) rep->server,i))
+    {
+     case KRB5_RC_IO_EOF: FREE3; goto end_loop;
+     case 0: break; default: FREE3; return KRB5_RC_IO; break;
+    }
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) &rep->cmsec,sizeof(rep->cmsec))) 
+    {
+     case KRB5_RC_IO_EOF: FREE3; goto end_loop;
+     case 0: break; default: FREE3; return KRB5_RC_IO; break;
+    }
+   switch(krb5_rc_io_read(&t->d,(krb5_pointer) &rep->ctime,sizeof(rep->ctime)))
+    {
+     case KRB5_RC_IO_EOF: FREE3; goto end_loop;
+     case 0: break; default: FREE3; return KRB5_RC_IO; break;
+    }
+   if (alive(rep,t->lifespan) != CMP_EXPIRED)
+     if (store(id,rep) == CMP_MALLOC) /* can't be a replay */
+       return KRB5_RC_MALLOC; 
+  }
+ end_loop: krb5_rc_io_unmark(&t->d);
+/* An automatic expunge here could remove the need for mark/unmark but
+would be inefficient. */
+ return 0;
+#endif
+}
+
+krb5_error_code krb5_rc_dfl_store(krb5_RC id,krb5_tkt_authent *auth)
+{
+ struct dfl_data *t = id->data;
+ struct auth_replay *rep;
+ int i;
+
+ if (!(rep = (struct auth_replay *) malloc(sizeof(struct auth_replay))))
+   return KRB5_RC_MALLOC;
+ if (auth_to_rep(auth,rep))
+  { FREE(rep); return KRB5_RC_UNKNOWN; }
+ switch(store(id,rep))
+  {
+   case CMP_MALLOC: FREE(rep); return KRB5_RC_MALLOC; break;
+   case CMP_REPLAY: FREE(rep); return KRB5_RC_REPLAY; break;
+   case 0: break;
+   default: /* wtf? */ ;
+  }
+#ifndef NOIOSTUFF
+ i = strlen(rep->client) + 1;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) &i,sizeof(i)))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) rep->client,i))
+   return KRB5_RC_IO;
+ i = strlen(rep->server) + 1;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) &i,sizeof(i)))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) rep->server,i))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) &rep->cmsec,sizeof(rep->cmsec)))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&t->d,(krb5_pointer) &rep->ctime,sizeof(rep->ctime)))
+   return KRB5_RC_IO;
+#endif
+ /* Shall we automatically expunge? */
+ if (t->nummisses > t->numhits + EXCESSREPS)
+   return krb5_rc_dfl_expunge(id);
+ return 0;
+}
+
+krb5_error_code krb5_rc_dfl_expunge(krb5_RC id)
+{
+ struct dfl_data *t = id->data;
+ int i;
+#ifdef NOIOSTUFF
+ struct authlist **q;
+ struct authlist **qt;
+ struct authlist *r;
+ struct authlist *rt;
+
+ for (q = &t->a;*q;q = qt)
+  {
+   qt = &(*q)->na;
+   if (alive(&(*q)->rep,t->lifespan) == CMP_EXPIRED)
+    {
+     FREE((*q)->rep.client);
+     FREE((*q)->rep.server);
+     FREE(*q);
+     *q = *qt; /* why doesn't this feel right? */
+    }
+  }
+ for (i = 0;i < t->hsize;i++)
+   t->h[i] = (struct authlist *) 0;
+ for (r = t->a;r;r = r->na)
+  {
+   i = hash(&r->rep,t->hsize);
+   rt = t->h[i];
+   t->h[i] = r;
+   r->nh = rt;
+  }
+  
+#else
+ struct krb5_rc_iostuff tmp;
+ struct authlist *q;
+
+ (void) krb5_rc_dfl_close(id);
+ switch(krb5_rc_dfl_recover(id))
+  {
+   case KRB5_RC_MALLOC: return KRB5_RC_MALLOC;
+   case KRB5_RC_IO: return KRB5_RC_IO;
+   default: ;
+  }
+ if (krb5_rc_io_creat(&tmp,(char **) 0))
+   return KRB5_RC_IO;
+ if (krb5_rc_io_write(&tmp,(krb5_pointer) &t->lifespan,sizeof(t->lifespan)))
+   return KRB5_RC_IO;
+ for (q = t->a;q;q = q->na)
+  {
+   i = strlen(q->rep.client) + 1;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) &i,sizeof(i)))
+     return KRB5_RC_IO;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) q->rep.client,i))
+     return KRB5_RC_IO;
+   i = strlen(q->rep.server) + 1;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) &i,sizeof(i)))
+     return KRB5_RC_IO;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) q->rep.server,i))
+     return KRB5_RC_IO;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) &q->rep.cmsec,sizeof(q->rep.cmsec)))
+     return KRB5_RC_IO;
+   if (krb5_rc_io_write(&tmp,(krb5_pointer) &q->rep.ctime,sizeof(q->rep.ctime)))
+     return KRB5_RC_IO;
+  }
+ if (krb5_rc_io_move(&t->d,&tmp))
+   return KRB5_RC_IO;
+#endif
+ return 0;
+}
+
+struct krb5_rc_type krb5_rc_dfl_ops =
+ {
+  "dfl",
+  krb5_rc_dfl_init,
+  krb5_rc_dfl_recover,
+  krb5_rc_dfl_destroy,
+  krb5_rc_dfl_close,
+  krb5_rc_dfl_store,
+  krb5_rc_dfl_expunge,
+  krb5_rc_dfl_get_span,
+  krb5_rc_dfl_get_name,
+  krb5_rc_dfl_resolve
+ }
+;