summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/access.h59
-rw-r--r--server/acl_files.c584
-rw-r--r--server/kopt.c481
-rw-r--r--server/new.h6
-rw-r--r--server/unix.h113
-rw-r--r--server/zalloc.c125
-rw-r--r--server/zalloc.h5
7 files changed, 1373 insertions, 0 deletions
diff --git a/server/access.h b/server/access.h
new file mode 100644
index 0000000..ec7903e
--- /dev/null
+++ b/server/access.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the Project Athena Zephyr Notification System.
+ *
+ * It contains declarations for use in the server, relating to access
+ * control.
+ *
+ * Created by Ken Raeburn.
+ *
+ * $Source$
+ * $Author$
+ * $Id$
+ *
+ * Copyright (c) 1990 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#include <zephyr/acl.h>
+#include "ZString.h"
+#include "unix.h"
+
+typedef enum _ZAccess_t {
+ TRANSMIT, /* use transmission acl */
+ SUBSCRIBE, /* use subscription acl */
+ INSTWILD, /* use instance wildcard acl */
+ INSTUID /* use instance UID identity acl */
+} ZAccess_t;
+
+class ZAcl_t {
+ char *acl_filename;
+ int acl_types; /* Flag field indcating which acls
+ are present. Used ONLY in access.c */
+ public:
+ int ok (ZString, ZAccess_t);
+ ZAcl_t (const char *path) {
+ extern char * strsave (const char *);
+ acl_filename = strsave (path);
+ acl_types = 0;
+ check ();
+ }
+ ~ZAcl_t () {
+ xfree (acl_filename);
+ }
+ private:
+ void check (void);
+ void check_acl_type (ZAccess_t, int);
+};
+
+inline int access_check(ZString sender, ZAcl_t *acl, ZAccess_t accesstype) {
+ return acl->ok (sender, accesstype);
+}
+
+/* found in access.c */
+extern void access_init (void), access_reinit (void);
+
+/* external data relevant */
+extern int zdebug;
diff --git a/server/acl_files.c b/server/acl_files.c
new file mode 100644
index 0000000..203274c
--- /dev/null
+++ b/server/acl_files.c
@@ -0,0 +1,584 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains functions for maintaining Access Control Lists.
+ *
+ * Created by: John T. Kohl
+ *
+ * $Source$
+ * $Author$
+ *
+ * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+/* Define this if you really want the ACL-writing code included. */
+/* #define WRITE_ACL */
+
+/*
+ * Stolen from lib/acl_files.c because acl_load needs to be externally
+ * declared and not statically declared.
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef lint
+static char rcsid_acl_files_c[] = "$Id$";
+#endif lint
+
+/*** Routines for manipulating access control list files ***/
+
+#include <zephyr/zephyr.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+
+/* "aname.inst@realm" */
+#define MAX_PRINCIPAL_SIZE (ANAME_SZ + INST_SZ + REALM_SZ + 3)
+#define INST_SEP '.'
+#define REALM_SEP '@'
+
+#define LINESIZE 2048 /* Maximum line length in an acl file */
+
+#define NEW_FILE "%s.~NEWACL~" /* Format for name of altered acl file */
+#define WAIT_TIME 300 /* Maximum time allowed write acl file */
+
+#define CACHED_ACLS 64 /* How many acls to cache */
+#define ACL_LEN 256 /* Twice a reasonable acl length */
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#define COR(a,b) ((a!=NULL)?(a):(b))
+
+extern int errno;
+
+extern char *malloc(), *calloc();
+extern time_t time();
+
+/* Canonicalize a principal name */
+/* If instance is missing, it becomes "" */
+/* If realm is missing, it becomes the local realm */
+/* Canonicalized form is put in canon, which must be big enough to hold
+ MAX_PRINCIPAL_SIZE characters */
+acl_canonicalize_principal(principal, canon)
+char *principal;
+char *canon;
+{
+ char *dot, *atsign, *end;
+ int len;
+
+ dot = index(principal, INST_SEP);
+ atsign = index(principal, REALM_SEP);
+
+ /* Maybe we're done already */
+ if(dot != NULL && atsign != NULL) {
+ if(dot < atsign) {
+ /* It's for real */
+ /* Copy into canon */
+ strncpy(canon, principal, MAX_PRINCIPAL_SIZE);
+ canon[MAX_PRINCIPAL_SIZE-1] = '\0';
+ return;
+ } else {
+ /* Nope, it's part of the realm */
+ dot = NULL;
+ }
+ }
+
+ /* No such luck */
+ end = principal + strlen(principal);
+
+ /* Get the principal name */
+ len = MIN(ANAME_SZ, COR(dot, COR(atsign, end)) - principal);
+ strncpy(canon, principal, len);
+ canon += len;
+
+ /* Add INST_SEP */
+ *canon++ = INST_SEP;
+
+ /* Get the instance, if it exists */
+ if(dot != NULL) {
+ ++dot;
+ len = MIN(INST_SZ, COR(atsign, end) - dot);
+ strncpy(canon, dot, len);
+ canon += len;
+ }
+
+ /* Add REALM_SEP */
+ *canon++ = REALM_SEP;
+
+ /* Get the realm, if it exists */
+ /* Otherwise, default to local realm */
+ if(atsign != NULL) {
+ ++atsign;
+ len = MIN(REALM_SZ, end - atsign);
+ strncpy(canon, atsign, len);
+ canon += len;
+ *canon++ = '\0';
+ }
+#ifdef KERBEROS
+ else if(krb_get_lrealm(canon, 1) != KSUCCESS) {
+ strcpy(canon, KRB_REALM);
+ }
+#endif
+}
+
+#ifdef notdef
+/* Get a lock to modify acl_file */
+/* Return new FILE pointer */
+/* or NULL if file cannot be modified */
+/* REQUIRES WRITE PERMISSION TO CONTAINING DIRECTORY */
+static FILE *acl_lock_file(acl_file)
+char *acl_file;
+{
+ struct stat s;
+ char new[LINESIZE];
+ int nfd;
+ FILE *nf;
+ int mode;
+
+ if(stat(acl_file, &s) < 0) return(NULL);
+ mode = s.st_mode;
+ sprintf(new, NEW_FILE, acl_file);
+ for(;;) {
+ /* Open the new file */
+ if((nfd = open(new, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) {
+ if(errno == EEXIST) {
+ /* Maybe somebody got here already, maybe it's just old */
+ if(stat(new, &s) < 0) return(NULL);
+ if(time(0) - s.st_ctime > WAIT_TIME) {
+ /* File is stale, kill it */
+ unlink(new);
+ continue;
+ } else {
+ /* Wait and try again */
+ sleep(1);
+ continue;
+ }
+ } else {
+ /* Some other error, we lose */
+ return(NULL);
+ }
+ }
+
+ /* If we got to here, the lock file is ours and ok */
+ /* Reopen it under stdio */
+ if((nf = fdopen(nfd, "w")) == NULL) {
+ /* Oops, clean up */
+ unlink(new);
+ }
+ return(nf);
+ }
+}
+
+/* Commit changes to acl_file written onto FILE *f */
+/* Returns zero if successful */
+/* Returns > 0 if lock was broken */
+/* Returns < 0 if some other error occurs */
+/* Closes f */
+static int acl_commit(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+#ifdef WRITE_ACL
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ sprintf(new, NEW_FILE, acl_file);
+ if(fflush(f) < 0
+ || fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ acl_abort(acl_file, f);
+ return(-1);
+ }
+
+ ret = rename(new, acl_file);
+ fclose(f);
+ return(ret);
+#else
+ abort ();
+#endif
+}
+
+/* Abort changes to acl_file written onto FILE *f */
+/* Returns 0 if successful, < 0 otherwise */
+/* Closes f */
+static int acl_abort(acl_file, f)
+char *acl_file;
+FILE *f;
+{
+#ifdef WRITE_ACL
+ char new[LINESIZE];
+ int ret;
+ struct stat s;
+
+ /* make sure we aren't nuking someone else's file */
+ if(fstat(fileno(f), &s) < 0
+ || s.st_nlink == 0) {
+ fclose(f);
+ return(-1);
+ } else {
+ sprintf(new, NEW_FILE, acl_file);
+ ret = unlink(new);
+ fclose(f);
+ return(ret);
+ }
+#else
+ abort ();
+#endif
+}
+
+/* Initialize an acl_file */
+/* Creates the file with permissions perm if it does not exist */
+/* Erases it if it does */
+/* Returns return value of acl_commit */
+int acl_initialize(acl_file, perm)
+char *acl_file;
+int perm;
+{
+ FILE *new;
+ int fd;
+
+ /* Check if the file exists already */
+ if((new = acl_lock_file(acl_file)) != NULL) {
+ return(acl_commit(acl_file, new));
+ } else {
+ /* File must be readable and writable by owner */
+ if((fd = open(acl_file, O_CREAT|O_EXCL, perm|0600)) < 0) {
+ return(-1);
+ } else {
+ close(fd);
+ return(0);
+ }
+ }
+}
+
+#endif /* notdef */
+
+/* Eliminate all whitespace character in buf */
+/* Modifies its argument */
+static nuke_whitespace(buf)
+char *buf;
+{
+ register char *pin, *pout;
+
+ for(pin = pout = buf; *pin != '\0'; pin++)
+ if(!isspace(*pin)) *pout++ = *pin;
+ *pout = '\0'; /* Terminate the string */
+}
+
+/* Hash table stuff */
+
+struct hashtbl {
+ int size; /* Max number of entries */
+ int entries; /* Actual number of entries */
+ char **tbl; /* Pointer to start of table */
+};
+
+/* Make an empty hash table of size s */
+static struct hashtbl *make_hash(size)
+int size;
+{
+ struct hashtbl *h;
+
+ if(size < 1) size = 1;
+ h = (struct hashtbl *) malloc(sizeof(struct hashtbl));
+ h->size = size;
+ h->entries = 0;
+ h->tbl = (char **) calloc(size, sizeof(char *));
+ return(h);
+}
+
+/* Destroy a hash table */
+static void
+destroy_hash(h)
+ struct hashtbl *h;
+{
+ int i;
+
+ for(i = 0; i < h->size; i++) {
+ if(h->tbl[i] != NULL) free(h->tbl[i]);
+ }
+ free(h->tbl);
+ free(h);
+}
+
+/* Compute hash value for a string */
+static unsigned hashval(s)
+register char *s;
+{
+ register unsigned hv;
+
+ for(hv = 0; *s != '\0'; s++) {
+ hv ^= ((hv << 3) ^ *s);
+ }
+ return(hv);
+}
+
+/* Add an element to a hash table */
+static add_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+ char *s;
+ char **old;
+ int i;
+
+#if 0
+ fprintf (stderr, "adding %s to acl hash %08X\n", el, h);
+#endif
+ /* Make space if it isn't there already */
+ if(h->entries + 1 > (h->size >> 1)) {
+ old = h->tbl;
+ h->tbl = (char **) calloc(h->size << 1, sizeof(char *));
+ for(i = 0; i < h->size; i++) {
+ if(old[i] != NULL) {
+ hv = hashval(old[i]) % (h->size << 1);
+ while(h->tbl[hv] != NULL) hv = (hv+1) % (h->size << 1);
+ h->tbl[hv] = old[i];
+ }
+ }
+ h->size = h->size << 1;
+ free(old);
+ }
+
+ hv = hashval(el) % h->size;
+ while(h->tbl[hv] != NULL && strcmp(h->tbl[hv], el)) hv = (hv+1) % h->size;
+ s = malloc(strlen(el)+1);
+ strcpy(s, el);
+ h->tbl[hv] = s;
+ h->entries++;
+}
+
+/* Returns nonzero if el is in h */
+static check_hash(h, el)
+struct hashtbl *h;
+char *el;
+{
+ unsigned hv;
+
+#if 0
+ fprintf (stderr, "looking for %s in acl %08X\n", el, h);
+#endif
+ for(hv = hashval(el) % h->size; h->tbl[hv]; hv = (hv + 1) % h->size) {
+#if 0
+ fprintf (stderr, "\tstrcmp (%s,...)\n", h->tbl[hv]);
+#endif
+ if (!strcmp(h->tbl[hv], el)) {
+#if 0
+ fprintf (stderr, "success!\n");
+#endif
+ return 1;
+ }
+ }
+#if 0
+ fprintf (stderr, "failure\n");
+#endif
+ return 0;
+}
+
+struct acl {
+ char filename[LINESIZE]; /* Name of acl file */
+ struct hashtbl *acl; /* Acl entries */
+};
+
+static struct acl acl_cache[CACHED_ACLS];
+
+static int acl_cache_count = 0;
+static int acl_cache_next = 0;
+
+/* Returns < 0 if unsuccessful in loading acl */
+/* Returns index into acl_cache otherwise */
+/* Note that if acl is already loaded, this is just a lookup */
+int acl_load(name)
+char *name;
+{
+ int i,fd;
+ FILE *f;
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ /* See if it's there already */
+ for(i = 0; i < acl_cache_count; i++) {
+ if (!strcmp(acl_cache[i].filename, name))
+ goto got_it;
+ }
+
+ /* It isn't, load it in */
+ /* maybe there's still room */
+ if(acl_cache_count < CACHED_ACLS) {
+ i = acl_cache_count++;
+ } else {
+ /* No room, clean one out */
+ i = acl_cache_next;
+ acl_cache_next = (acl_cache_next + 1) % CACHED_ACLS;
+ if(acl_cache[i].acl) {
+ destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = (struct hashtbl *) 0;
+ }
+ }
+
+ /* Set up the acl */
+ strcpy(acl_cache[i].filename, name);
+ /* Force reload */
+ acl_cache[i].acl = (struct hashtbl *) 0;
+
+ got_it:
+ /*
+ * See if we need to reload the ACL
+ */
+ if (acl_cache[i].acl == (struct hashtbl *) 0) {
+ /* Gotta reload */
+#if 0
+ fprintf (stderr, "attempting to load %s\n", name);
+#endif
+ if ((f = fopen(name, "r")) == NULL) {
+#if 0
+ perror (name);
+#endif
+ return -1;
+ }
+ if (acl_cache[i].acl) destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = make_hash(ACL_LEN);
+ while(fgets(buf, sizeof(buf), f) != NULL) {
+ nuke_whitespace(buf);
+ acl_canonicalize_principal(buf, canon);
+ add_hash(acl_cache[i].acl, canon);
+ }
+ fclose(f);
+ }
+ return(i);
+}
+
+/*
+ * This destroys all cached ACL's so that new ones will be loaded in
+ * the next time they are requested.
+ */
+acl_cache_reset()
+{
+ int i;
+
+ /* See if it's there already */
+ for(i = 0; i < acl_cache_count; i++)
+ if (acl_cache[i].acl) {
+ destroy_hash(acl_cache[i].acl);
+ acl_cache[i].acl = (struct hashtbl *) 0;
+ }
+ acl_cache_count = 0;
+ acl_cache_next = 0;
+}
+
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Principal is not canonicalized, and no wildcarding is done */
+acl_exact_match(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+
+#if 0
+ fprintf (stderr, "checking for %s in %s\n", principal, acl);
+#endif
+ return((idx = acl_load(acl)) >= 0
+ && check_hash(acl_cache[idx].acl, principal));
+}
+
+/* Returns nonzero if it can be determined that acl contains principal */
+/* Recognizes wildcards in acl of the form
+ name.*@realm, *.*@realm, and *.*@* */
+acl_check(acl, principal)
+char *acl;
+char *principal;
+{
+ char buf[MAX_PRINCIPAL_SIZE];
+ char canon[MAX_PRINCIPAL_SIZE];
+ char *realm;
+
+ acl_canonicalize_principal(principal, canon);
+
+ /* Is it there? */
+ if (acl_exact_match(acl, canon))
+ return 1;
+
+ /* Try the wildcards */
+ realm = index(canon, REALM_SEP);
+ *index(canon, INST_SEP) = '\0'; /* Chuck the instance */
+
+ sprintf(buf, "%s.*%s", canon, realm);
+ if(acl_exact_match(acl, buf)) return 1;
+
+ sprintf(buf, "*.*%s", realm);
+ if(acl_exact_match(acl, buf) || acl_exact_match(acl, "*.*@*")) return(1);
+
+ return(0);
+}
+
+#ifdef notdef
+/* Adds principal to acl */
+/* Wildcards are interpreted literally */
+acl_add(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL) {
+ if(fputs(acl_cache[idx].acl->tbl[i], new) == NULL
+ || putc('\n', new) != '\n') {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ }
+ }
+ fputs(canon, new);
+ putc('\n', new);
+ return(acl_commit(acl, new));
+}
+
+/* Removes principal from acl */
+/* Wildcards are interpreted literally */
+acl_delete(acl, principal)
+char *acl;
+char *principal;
+{
+ int idx;
+ int i;
+ FILE *new;
+ char canon[MAX_PRINCIPAL_SIZE];
+
+ acl_canonicalize_principal(principal, canon);
+
+ if((new = acl_lock_file(acl)) == NULL) return(-1);
+ if((!acl_exact_match(acl, canon))
+ || (idx = acl_load(acl)) < 0) {
+ acl_abort(acl, new);
+ return(-1);
+ }
+ /* It isn't there yet, copy the file and put it in */
+ for(i = 0; i < acl_cache[idx].acl->size; i++) {
+ if(acl_cache[idx].acl->tbl[i] != NULL
+ && strcmp(acl_cache[idx].acl->tbl[i], canon)) {
+ fputs(acl_cache[idx].acl->tbl[i], new);
+ putc('\n', new);
+ }
+ }
+ return(acl_commit(acl, new));
+}
+#endif /* notdef */
diff --git a/server/kopt.c b/server/kopt.c
new file mode 100644
index 0000000..64b7417
--- /dev/null
+++ b/server/kopt.c
@@ -0,0 +1,481 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+/*
+ * This includes code taken from:
+ * $Kerberos: rd_req.c,v 4.16 89/03/22 14:52:06 jtkohl Exp $
+ * $Kerberos: prot.h,v 4.13 89/01/24 14:27:22 jtkohl Exp $
+ * $Kerberos: krb_conf.h,v 4.0 89/01/23 09:59:27 jtkohl Exp $
+ */
+
+#ifdef KERBEROS
+#ifndef NOENCRYPTION
+
+#ifndef lint
+static char *rcsid_rd_req_c =
+ "$Header$";
+#endif /* lint */
+
+#include <zephyr/mit-copyright.h>
+#include <stdio.h>
+#include <krb.h>
+
+/* Byte ordering */
+extern int krbONE;
+#define HOST_BYTE_ORDER (* (char *) &krbONE)
+
+#define KRB_PROT_VERSION 4
+
+/* Message types , always leave lsb for byte order */
+
+#define AUTH_MSG_KDC_REQUEST 1<<1
+#define AUTH_MSG_KDC_REPLY 2<<1
+#define AUTH_MSG_APPL_REQUEST 3<<1
+#define AUTH_MSG_APPL_REQUEST_MUTUAL 4<<1
+#define AUTH_MSG_ERR_REPLY 5<<1
+#define AUTH_MSG_PRIVATE 6<<1
+#define AUTH_MSG_SAFE 7<<1
+#define AUTH_MSG_APPL_ERR 8<<1
+#define AUTH_MSG_DIE 63<<1
+
+/* values for kerb error codes */
+
+#define KERB_ERR_OK 0
+#define KERB_ERR_NAME_EXP 1
+#define KERB_ERR_SERVICE_EXP 2
+#define KERB_ERR_AUTH_EXP 3
+#define KERB_ERR_PKT_VER 4
+#define KERB_ERR_NAME_MAST_KEY_VER 5
+#define KERB_ERR_SERV_MAST_KEY_VER 6
+#define KERB_ERR_BYTE_ORDER 7
+#define KERB_ERR_PRINCIPAL_UNKNOWN 8
+#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9
+#define KERB_ERR_NULL_KEY 10
+
+#include <sys/time.h>
+#include <strings.h>
+
+extern int krb_ap_req_debug;
+
+/*
+ * Keep the following information around for subsequent calls
+ * to this routine by the same server using the same key.
+ */
+
+/* Kerberos shouldn't stick us with array types... */
+typedef struct {
+ des_key_schedule s;
+} Sched;
+
+static Sched serv_key; /* Key sched to decrypt ticket */
+static des_cblock ky; /* Initialization vector */
+static int st_kvno; /* version number for this key */
+static char st_rlm[REALM_SZ]; /* server's realm */
+static char st_nam[ANAME_SZ]; /* service name */
+static char st_inst[INST_SZ]; /* server's instance */
+
+/*
+ * Cache of key schedules
+ */
+#define HASH_SIZE_1 255 /* not a power of 2 */
+#define HASH_SIZE_2 3
+static unsigned long last_use;
+typedef struct {
+ unsigned long last_time_used;
+ des_cblock key;
+ Sched schedule;
+} KeySchedRec;
+static KeySchedRec scheds[HASH_SIZE_1][HASH_SIZE_2];
+
+static Sched* check_key_sched_cache (des_cblock key) {
+ unsigned int hash_value = key[0] + key[1] * 256;
+ KeySchedRec *rec = scheds[hash_value % HASH_SIZE_1];
+ int i;
+
+ for (i = HASH_SIZE_2 - 1; i >= 0; i--)
+ if (rec[i].last_time_used
+ && key[0] == rec[i].key[0]
+ && !bcmp (key, rec[i].key, sizeof (des_cblock))) {
+ rec[i].last_time_used = last_use++;
+ return &rec[i].schedule;
+ }
+ return 0;
+}
+
+static void add_to_key_sched_cache (des_cblock key, Sched* sched) {
+ unsigned int hash_value = key[0] + key[1] * 256;
+ KeySchedRec *rec = scheds[hash_value % HASH_SIZE_1];
+ int i, oldest = HASH_SIZE_2 - 1;
+
+ for (i = HASH_SIZE_2 - 1; i >= 0; i--) {
+ if (rec[i].last_time_used == 0) {
+ oldest = i;
+ break;
+ }
+ if (rec[i].last_time_used < rec[oldest].last_time_used)
+ oldest = i;
+ }
+ bcopy (key, rec[oldest].key, sizeof (des_cblock));
+ rec[oldest].schedule = *sched;
+ rec[oldest].last_time_used = last_use++;
+}
+
+/*
+ * This file contains two functions. krb_set_key() takes a DES
+ * key or password string and returns a DES key (either the original
+ * key, or the password converted into a DES key) and a key schedule
+ * for it.
+ *
+ * krb_rd_req() reads an authentication request and returns information
+ * about the identity of the requestor, or an indication that the
+ * identity information was not authentic.
+ */
+
+/*
+ * krb_set_key() takes as its first argument either a DES key or a
+ * password string. The "cvt" argument indicates how the first
+ * argument "key" is to be interpreted: if "cvt" is null, "key" is
+ * taken to be a DES key; if "cvt" is non-null, "key" is taken to
+ * be a password string, and is converted into a DES key using
+ * string_to_key(). In either case, the resulting key is returned
+ * in the external static variable "ky". A key schedule is
+ * generated for "ky" and returned in the external static variable
+ * "serv_key".
+ *
+ * This routine returns the return value of des_key_sched.
+ *
+ * krb_set_key() needs to be in the same .o file as krb_rd_req() so that
+ * the key set by krb_set_key() is available in private storage for
+ * krb_rd_req().
+ */
+
+int
+krb_set_key(key,cvt)
+ char *key;
+ int cvt;
+{
+#ifdef NOENCRYPTION
+ bzero(ky, sizeof(ky));
+ return KSUCCESS;
+#else /* Encrypt */
+ Sched *s;
+ int ret;
+
+ if (cvt)
+ string_to_key(key,ky);
+ else
+ bcopy(key,(char *)ky,8);
+
+ s = check_key_sched_cache (ky);
+ if (s) {
+ serv_key = *s;
+ return 0;
+ }
+ ret = des_key_sched (ky, serv_key.s);
+ add_to_key_sched_cache (ky, &serv_key);
+ return ret;
+#endif /* NOENCRYPTION */
+}
+
+
+/*
+ * krb_rd_req() takes an AUTH_MSG_APPL_REQUEST or
+ * AUTH_MSG_APPL_REQUEST_MUTUAL message created by krb_mk_req(),
+ * checks its integrity and returns a judgement as to the requestor's
+ * identity.
+ *
+ * The "authent" argument is a pointer to the received message.
+ * The "service" and "instance" arguments name the receiving server,
+ * and are used to get the service's ticket to decrypt the ticket
+ * in the message, and to compare against the server name inside the
+ * ticket. "from_addr" is the network address of the host from which
+ * the message was received; this is checked against the network
+ * address in the ticket. If "from_addr" is zero, the check is not
+ * performed. "ad" is an AUTH_DAT structure which is
+ * filled in with information about the sender's identity according
+ * to the authenticator and ticket sent in the message. Finally,
+ * "fn" contains the name of the file containing the server's key.
+ * (If "fn" is NULL, the server's key is assumed to have been set
+ * by krb_set_key(). If "fn" is the null string ("") the default
+ * file KEYFILE, defined in "krb.h", is used.)
+ *
+ * krb_rd_req() returns RD_AP_OK if the authentication information
+ * was genuine, or one of the following error codes (defined in
+ * "krb.h"):
+ *
+ * RD_AP_VERSION - wrong protocol version number
+ * RD_AP_MSG_TYPE - wrong message type
+ * RD_AP_UNDEC - couldn't decipher the message
+ * RD_AP_INCON - inconsistencies found
+ * RD_AP_BADD - wrong network address
+ * RD_AP_TIME - client time (in authenticator)
+ * too far off server time
+ * RD_AP_NYV - Kerberos time (in ticket) too
+ * far off server time
+ * RD_AP_EXP - ticket expired
+ *
+ * For the message format, see krb_mk_req().
+ *
+ * Mutual authentication is not implemented.
+ */
+
+krb_rd_req(authent,service,instance,from_addr,ad,fn)
+ register KTEXT authent; /* The received message */
+ char *service; /* Service name */
+ char *instance; /* Service instance */
+ long from_addr; /* Net address of originating host */
+ AUTH_DAT *ad; /* Structure to be filled in */
+ char *fn; /* Filename to get keys from */
+{
+ KTEXT_ST ticket; /* Temp storage for ticket */
+ KTEXT tkt = &ticket;
+ KTEXT_ST req_id_st; /* Temp storage for authenticator */
+ register KTEXT req_id = &req_id_st;
+
+ struct timeval t_local;
+
+ char realm[REALM_SZ]; /* Realm of issuing kerberos */
+ Sched seskey_sched, *sched; /* Key sched for session key */
+ unsigned char skey[KKEY_SZ]; /* Session key from ticket */
+ char sname[SNAME_SZ]; /* Service name from ticket */
+ char iname[INST_SZ]; /* Instance name from ticket */
+ char r_aname[ANAME_SZ]; /* Client name from authenticator */
+ char r_inst[INST_SZ]; /* Client instance from authenticator */
+ char r_realm[REALM_SZ]; /* Client realm from authenticator */
+ unsigned int r_time_ms; /* Fine time from authenticator */
+ unsigned long r_time_sec; /* Coarse time from authenticator */
+ register char *ptr; /* For stepping through */
+ unsigned long delta_t; /* Time in authenticator - local time */
+ long tkt_age; /* Age of ticket */
+ int swap_bytes; /* Need to swap bytes? */
+ int mutual; /* Mutual authentication requested? */
+ unsigned char s_kvno; /* Version number of the server's key
+ * Kerberos used to encrypt ticket */
+ int status;
+
+ if (authent->length <= 0)
+ return(RD_AP_MODIFIED);
+
+ ptr = (char *) authent->dat;
+
+ /* get msg version, type and byte order, and server key version */
+
+ /* check version */
+ if (KRB_PROT_VERSION != (unsigned int) *ptr++)
+ return(RD_AP_VERSION);
+
+ /* byte order */
+ swap_bytes = 0;
+ if ((*ptr & 1) != HOST_BYTE_ORDER)
+ swap_bytes++;
+
+ /* check msg type */
+ mutual = 0;
+ switch (*ptr++ & ~1) {
+ case AUTH_MSG_APPL_REQUEST:
+ break;
+ case AUTH_MSG_APPL_REQUEST_MUTUAL:
+ mutual++;
+ break;
+ default:
+ return(RD_AP_MSG_TYPE);
+ }
+
+#ifdef lint
+ /* XXX mutual is set but not used; why??? */
+ /* this is a crock to get lint to shut up */
+ if (mutual)
+ mutual = 0;
+#endif /* lint */
+ s_kvno = *ptr++; /* get server key version */
+ (void) strcpy(realm,ptr); /* And the realm of the issuing KDC */
+ ptr += strlen(ptr) + 1; /* skip the realm "hint" */
+
+ /*
+ * If "fn" is NULL, key info should already be set; don't
+ * bother with ticket file. Otherwise, check to see if we
+ * already have key info for the given server and key version
+ * (saved in the static st_* variables). If not, go get it
+ * from the ticket file. If "fn" is the null string, use the
+ * default ticket file.
+ */
+ if (fn && (strcmp(st_nam,service) || strcmp(st_inst,instance) ||
+ strcmp(st_rlm,realm) || (st_kvno != s_kvno))) {
+ if (*fn == 0) fn = KEYFILE;
+ st_kvno = s_kvno;
+#ifndef NOENCRYPTION
+ if (read_service_key(service,instance,realm,(int) s_kvno,
+ fn,(char *)skey))
+ return(RD_AP_UNDEC);
+ if (status = krb_set_key((char *)skey,0))
+ return(status);
+#endif /* !NOENCRYPTION */
+ (void) strcpy(st_rlm,realm);
+ (void) strcpy(st_nam,service);
+ (void) strcpy(st_inst,instance);
+ }
+
+ /* Get ticket from authenticator */
+ tkt->length = (int) *ptr++;
+ if ((tkt->length + (ptr+1 - (char *) authent->dat)) > authent->length)
+ return(RD_AP_MODIFIED);
+ bcopy(ptr+1,(char *)(tkt->dat),tkt->length);
+
+ if (krb_ap_req_debug)
+ log("ticket->length: %d",tkt->length);
+
+#ifndef NOENCRYPTION
+ /* Decrypt and take apart ticket */
+#endif
+
+ if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
+ &(ad->address),ad->session, &(ad->life),
+ &(ad->time_sec),sname,iname,ky,serv_key.s))
+ return(RD_AP_UNDEC);
+
+ if (krb_ap_req_debug) {
+ log("Ticket Contents.");
+ log(" Aname: %s.%s",ad->pname,
+ ((int)*(ad->prealm) ? ad->prealm : "Athena"));
+ log(" Service: %s%s%s",sname,((int)*iname ? "." : ""),iname);
+ }
+
+ /* Extract the authenticator */
+ req_id->length = (int) *(ptr++);
+ if ((req_id->length + (ptr + tkt->length - (char *) authent->dat)) >
+ authent->length)
+ return(RD_AP_MODIFIED);
+ bcopy(ptr + tkt->length, (char *)(req_id->dat),req_id->length);
+
+#ifndef NOENCRYPTION
+ /* And decrypt it with the session key from the ticket */
+ if (krb_ap_req_debug) log("About to decrypt authenticator");
+ sched = check_key_sched_cache (ad->session);
+ if (!sched) {
+ sched = &seskey_sched;
+ key_sched (ad->session, seskey_sched.s);
+ add_to_key_sched_cache (ad->session, &seskey_sched);
+ }
+ /* can't do much to optimize this... */
+ pcbc_encrypt((C_Block *)req_id->dat,(C_Block *)req_id->dat,
+ (long) req_id->length, sched->s, ad->session,DES_DECRYPT);
+ if (krb_ap_req_debug) log("Done.");
+#endif /* NOENCRYPTION */
+
+#define check_ptr() if ((ptr - (char *) req_id->dat) > req_id->length) return(RD_AP_MODIFIED);
+
+ ptr = (char *) req_id->dat;
+ (void) strcpy(r_aname,ptr); /* Authentication name */
+ ptr += strlen(r_aname)+1;
+ check_ptr();
+ (void) strcpy(r_inst,ptr); /* Authentication instance */
+ ptr += strlen(r_inst)+1;
+ check_ptr();
+ (void) strcpy(r_realm,ptr); /* Authentication name */
+ ptr += strlen(r_realm)+1;
+ check_ptr();
+ bcopy(ptr,(char *)&ad->checksum,4); /* Checksum */
+ ptr += 4;
+ check_ptr();
+ if (swap_bytes) swap_u_long(ad->checksum);
+ r_time_ms = *(ptr++); /* Time (fine) */
+#ifdef lint
+ /* XXX r_time_ms is set but not used. why??? */
+ /* this is a crock to get lint to shut up */
+ if (r_time_ms)
+ r_time_ms = 0;
+#endif /* lint */
+ check_ptr();
+ /* assume sizeof(r_time_sec) == 4 ?? */
+ bcopy(ptr,(char *)&r_time_sec,4); /* Time (coarse) */
+ if (swap_bytes) swap_u_long(r_time_sec);
+
+ /* Check for authenticity of the request */
+ if (krb_ap_req_debug)
+ log("Pname: %s %s",ad->pname,r_aname);
+ if (strcmp(ad->pname,r_aname) != 0)
+ return(RD_AP_INCON);
+ if (strcmp(ad->pinst,r_inst) != 0)
+ return(RD_AP_INCON);
+ if (krb_ap_req_debug)
+ log("Realm: %s %s",ad->prealm,r_realm);
+ if ((strcmp(ad->prealm,r_realm) != 0))
+ return(RD_AP_INCON);
+
+ if (krb_ap_req_debug)
+ log("Address: %d %d",ad->address,from_addr);
+ if (from_addr && (ad->address != from_addr))
+ return(RD_AP_BADD);
+
+ (void) gettimeofday(&t_local,(struct timezone *) 0);
+ delta_t = abs((int)(t_local.tv_sec - r_time_sec));
+ if (delta_t > CLOCK_SKEW) {
+ if (krb_ap_req_debug)
+ log("Time out of range: %d - %d = %d",
+ t_local.tv_sec,r_time_sec,delta_t);
+ return(RD_AP_TIME);
+ }
+
+ /* Now check for expiration of ticket */
+
+ tkt_age = t_local.tv_sec - ad->time_sec;
+ if (krb_ap_req_debug)
+ log("Time: %d Issue Date: %d Diff: %d Life %x",
+ t_local.tv_sec,ad->time_sec,tkt_age,ad->life);
+
+ if (t_local.tv_sec < ad->time_sec) {
+ if ((ad->time_sec - t_local.tv_sec) > CLOCK_SKEW)
+ return(RD_AP_NYV);
+ }
+ else if ((t_local.tv_sec - ad->time_sec) > 5 * 60 * ad->life)
+ return(RD_AP_EXP);
+
+ /* All seems OK */
+ ad->reply.length = 0;
+
+ return(RD_AP_OK);
+}
+#endif /* NOENCRYPTION */
+
+static char local_realm_buffer[REALM_SZ+1];
+
+krb_get_lrealm(r,n)
+ char *r;
+ int n;
+{
+ FILE *cnffile, *fopen();
+
+ if (n > 1)
+ return(KFAILURE); /* Temporary restriction */
+
+ if (local_realm_buffer[0]) {
+ strcpy (r, local_realm_buffer);
+ return KSUCCESS;
+ }
+
+ if ((cnffile = fopen(KRB_CONF, "r")) == NULL) {
+ if (n == 1) {
+ (void) strcpy(r, KRB_REALM);
+ return(KSUCCESS);
+ }
+ else
+ return(KFAILURE);
+ }
+
+ if (fscanf(cnffile,"%s",r) != 1) {
+ (void) fclose(cnffile);
+ return(KFAILURE);
+ }
+ (void) fclose(cnffile);
+ return(KSUCCESS);
+}
+
+#endif /* KERBEROS */
diff --git a/server/new.h b/server/new.h
new file mode 100644
index 0000000..62783c6
--- /dev/null
+++ b/server/new.h
@@ -0,0 +1,6 @@
+-*- text -*-
+
+This file is here just to confuse makedepend. Normally, makedepend
+will not search the directories used for C++ header files; thus,
+anything specific to C++ won't be found unless we fake it out by
+putting a file in the working directory for it to find.
diff --git a/server/unix.h b/server/unix.h
new file mode 100644
index 0000000..b5b09a5
--- /dev/null
+++ b/server/unix.h
@@ -0,0 +1,113 @@
+/* This file is part of the Project Athena Zephyr Notification System.
+ * It contains declarations for many standard UNIX library functions,
+ * and macros for aiding in interfacing to them.
+ *
+ * Created by Ken Raeburn.
+ *
+ * $Source$
+ * $Author$
+ * $Id$
+ *
+ * Copyright (c) 1990 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * "mit-copyright.h".
+ */
+
+#include <zephyr/mit-copyright.h>
+
+#ifndef ZSERVER_UNIX_H__
+
+extern "C" {
+ /* found in libc.a */
+#ifndef __GNUG__
+ void *malloc(unsigned), *realloc(void *, unsigned), free (void *);
+#endif
+ long random(void);
+
+ /*
+ * Queue-handling functions. This structure is basically a dummy;
+ * as long as the start of another structure looks like this,
+ * we're okay.
+ */
+ struct qelem {
+ struct qelem *q_forw;
+ struct qelem *q_back;
+ char *q_data;
+ };
+ void insque (qelem*, qelem*);
+ void remque (qelem *);
+#ifdef __GNUG__
+#if defined (ultrix)
+ void openlog (char *, int);
+#undef LOG_DEBUG
+#define LOG_DEBUG LOG_ERR
+#else
+ void openlog (char *, int, int); /* ??? */
+#endif
+#endif /* G++? */
+ void syslog (int, const char *, ...);
+ int setsockopt (int, int, int, const char *, int);
+ extern int strcasecmp (const char*, const char*);
+#ifdef __GNUG__
+ extern void setservent (int);
+ extern void endservent (void);
+#endif
+ extern void moncontrol (int);
+
+ /* From the Error table library */
+ char *error_message(long);
+
+ /* Kerberos */
+ extern int krb_get_lrealm (...);
+ extern int dest_tkt (...);
+ extern int krb_get_svc_in_tkt (...);
+ extern int krb_rd_req (...);
+ extern int krb_mk_req (...);
+ extern int krb_get_cred (...);
+ extern int des_quad_cksum (...);
+
+ /* hacked acl code */
+ extern void acl_cache_reset (void);
+}
+
+#ifdef vax
+#define HAVE_ALLOCA
+#endif
+
+#if defined (__GNUC__) || defined (__GNUG__)
+
+/* GCC/G++ has a built-in function for allocating automatic storage. */
+#define LOCAL_ALLOC(X) __builtin_alloca(X)
+#define LOCAL_FREE(X)
+
+#else /* not gcc or g++ */
+
+#if defined (ibm032)
+/*
+ * Unfortunately, there's no way to get cfront to access _Alloca. So
+ * we compile with -ma and call alloca. Sigh.
+ */
+#define LOCAL_ALLOC(X) alloca(X)
+#define LOCAL_FREE(X)
+extern "C" void * alloca (unsigned int);
+
+#else /* none of above */
+#ifdef HAVE_ALLOCA
+#define LOCAL_ALLOC(X) alloca(X)
+#define LOCAL_FREE(X)
+#endif
+#endif
+#endif
+
+#ifndef LOCAL_ALLOC
+#define LOCAL_ALLOC(X) malloc(X)
+#define LOCAL_FREE(X) free(X)
+#endif
+
+#define xfree(foo) free((caddr_t) (foo))
+#define xinsque(a,b) insque((struct qelem *)(a), (struct qelem *)(b))
+#define xremque(a) remque((struct qelem *)(a))
+#define xmalloc(a) malloc((unsigned)(a))
+
+#define ZSERVER_UNIX_H__
+#endif
diff --git a/server/zalloc.c b/server/zalloc.c
new file mode 100644
index 0000000..783cde8
--- /dev/null
+++ b/server/zalloc.c
@@ -0,0 +1,125 @@
+/*
+ * Memory allocator for Zephyr server.
+ */
+
+#include <stdio.h>
+#include "zalloc.h"
+
+/*
+ * Pick some size here that will help keep down the number of calls to
+ * malloc, but doesn't waste too much space. To avoid waste of space,
+ * we leave some overhead before the next power of two.
+ */
+const int alloc_size = 16368;
+
+/*
+ * What's the maximum number of words to expect to allocate through
+ * this mechanism? (Larger requests will be fed to malloc.)
+ */
+const int max_size = 32;
+
+static void *free_space;
+static int free_space_size;
+static void *buckets[max_size];
+
+const unsigned int sz = sizeof (void *);
+inline unsigned int round (unsigned int size) {
+ size += sz - 1;
+ size -= (size % sz);
+ return size;
+}
+#define ROUND(size) (size = round (size))
+inline int BUCKET (unsigned int size) {
+ ROUND (size);
+ return size / sz - 1;
+}
+
+extern "C" {
+ void * malloc (unsigned int);
+ void free (void *);
+ void abort ();
+ void bzero (void *, unsigned int);
+}
+
+static inline void memset (void *ptr, int size, int fill) {
+#ifdef ZALLOC_DEBUG
+ char *cptr = (char *) ptr;
+ while (size--)
+ cptr[size] = fill;
+#endif
+}
+
+void *zalloc (unsigned int size) {
+ ROUND (size);
+
+ int bucket = BUCKET (size);
+ if (bucket < 0 || bucket >= max_size)
+ return malloc (size);
+
+ void *ret;
+ void **ptr = &buckets[bucket];
+#ifdef ZALLOC_DEBUG
+ fprintf (stderr, "zalloc(%d); looking in bucket %d, found %08X\n",
+ size, bucket, *ptr);
+#endif
+ if (*ptr) {
+ ret = *ptr;
+ *ptr = *(void**)ret;
+ memset (ret, size, 0xe5);
+ return ret;
+ }
+
+ if (free_space_size < size) {
+ if (free_space_size > 0) {
+ ptr = &buckets[BUCKET (free_space_size)];
+ *(void**)free_space = *ptr;
+ *ptr = free_space;
+#ifdef ZALLOC_DEBUG
+ fprintf (stderr, "tossing %08X into bucket %d\n",
+ free_space, bucket);
+#endif
+ }
+
+ free_space_size = (4080 / sizeof (void *)) * sizeof (void *);
+ free_space = malloc (free_space_size);
+ if (!free_space)
+ abort ();
+#ifdef ZALLOC_DEBUG
+ fprintf (stderr, "grabbing more free store at %08X\n", free_space);
+#endif
+ }
+
+ ret = free_space;
+ free_space = (char *) free_space + size;
+ free_space_size -= size;
+#ifdef ZALLOC_DEBUG
+ fprintf (stderr, "returning %08X\n", ret);
+#endif
+ memset (ret, size, 0xe5);
+ return ret;
+}
+
+void zfree (void *ptr, unsigned int size) {
+ ROUND (size);
+
+ int bucket = BUCKET (size);
+ if (bucket < 0 || bucket >= max_size) {
+ free (ptr);
+ return;
+ }
+
+ void **b = &buckets[bucket];
+ memset (ptr, size, 0xe5);
+ *(void **) ptr = *b;
+ *b = ptr;
+#ifdef ZALLOC_DEBUG
+ fprintf (stderr, "putting %08X into bucket %d\n",
+ ptr, bucket);
+#if 0
+ fprintf (stderr, "bucket %d:");
+ for (ptr = buckets[bucket]; ptr; ptr=*(void**)ptr)
+ fprintf (stderr, " %X", ptr);
+ fprintf (stderr, "\n");
+#endif
+#endif
+}
diff --git a/server/zalloc.h b/server/zalloc.h
new file mode 100644
index 0000000..3e25f3f
--- /dev/null
+++ b/server/zalloc.h
@@ -0,0 +1,5 @@
+/*
+ */
+
+extern void * zalloc (unsigned int);
+extern void zfree (void *, unsigned int);