1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for maintaining Access Control Lists.
4 * Created by: John T. Kohl
8 * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
13 /* Define this if you really want the ACL-writing code included. */
16 * Stolen from lib/acl_files.c because acl_load needs to be externally
17 * declared and not statically declared.
20 #include <zephyr/mit-copyright.h>
22 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
23 /* this needs to be rethought for a world without krb4 */
27 static const char rcsid_acl_files_c[] = "$Id$";
31 /*** Routines for manipulating access control list files ***/
38 /* "aname.inst@realm" */
39 #ifndef MAX_PRINCIPAL_SIZE
40 #define MAX_PRINCIPAL_SIZE (ANAME_SZ + INST_SZ + REALM_SZ + 3)
45 #define LINESIZE 2048 /* Maximum line length in an acl file */
47 #define NEW_FILE "%s.~NEWACL~" /* Format for name of altered acl file */
48 #define WAIT_TIME 300 /* Maximum time allowed write acl file */
50 #define CACHED_ACLS 64 /* How many acls to cache */
51 #define ACL_LEN 256 /* Twice a reasonable acl length */
53 #define MAX(a,b) (((a)>(b))?(a):(b))
54 #define MIN(a,b) (((a)<(b))?(a):(b))
56 #define COR(a,b) ((a!=NULL)?(a):(b))
58 /* Canonicalize a principal name */
59 /* If instance is missing, it becomes "" */
60 /* If realm is missing, it becomes the local realm */
61 /* Canonicalized form is put in canon, which must be big enough to hold
62 MAX_PRINCIPAL_SIZE characters */
63 void acl_canonicalize_principal(char *principal,
70 dot = strchr(principal, INST_SEP);
71 atsign = strchr(principal, REALM_SEP);
73 /* Maybe we're done already */
74 if (dot != NULL && atsign != NULL) {
78 strncpy(canon, principal, MAX_PRINCIPAL_SIZE);
79 canon[MAX_PRINCIPAL_SIZE-1] = '\0';
82 /* Nope, it's part of the realm */
88 end = principal + strlen(principal);
90 /* Get the principal name */
91 len = MIN(ANAME_SZ, COR(dot, COR(atsign, end)) - principal);
92 strncpy(canon, principal, len);
98 /* Get the instance, if it exists */
101 len = MIN(INST_SZ, COR(atsign, end) - dot);
102 strncpy(canon, dot, len);
107 *canon++ = REALM_SEP;
109 /* Get the realm, if it exists */
110 /* Otherwise, default to local realm */
111 if (atsign != NULL) {
113 len = MIN(REALM_SZ, end - atsign);
114 strncpy(canon, atsign, len);
119 else if (krb_get_lrealm(canon, 1) != KSUCCESS) {
120 strcpy(canon, KRB_REALM);
125 /* Eliminate all whitespace character in buf */
126 /* Modifies its argument */
128 nuke_whitespace(char *buf)
132 for (pin = pout = buf; *pin != '\0'; pin++)
133 if (!isspace(*pin)) *pout++ = *pin;
134 *pout = '\0'; /* Terminate the string */
137 /* Hash table stuff */
140 int size; /* Max number of entries */
141 int entries; /* Actual number of entries */
142 char **tbl; /* Pointer to start of table */
145 /* Make an empty hash table of size s */
146 static struct hashtbl *
151 if (size < 1) size = 1;
152 h = (struct hashtbl *) malloc(sizeof(struct hashtbl));
155 h->tbl = (char **) calloc(size, sizeof(char *));
159 /* Destroy a hash table */
161 destroy_hash(struct hashtbl *h)
165 for (i = 0; i < h->size; i++) {
166 if (h->tbl[i] != NULL) free(h->tbl[i]);
172 /* Compute hash value for a string */
178 for (hv = 0; *s != '\0'; s++) {
179 hv ^= ((hv << 3) ^ *s);
184 /* Add an element to a hash table */
186 add_hash(struct hashtbl *h,
194 /* Make space if it isn't there already */
195 if (h->entries + 1 > (h->size >> 1)) {
197 h->tbl = (char **) calloc(h->size << 1, sizeof(char *));
198 for (i = 0; i < h->size; i++) {
199 if (old[i] != NULL) {
200 hv = hashval(old[i]) % (h->size << 1);
201 while(h->tbl[hv] != NULL) hv = (hv+1) % (h->size << 1);
205 h->size = h->size << 1;
209 hv = hashval(el) % h->size;
210 while(h->tbl[hv] != NULL && strcmp(h->tbl[hv], el)) hv = (hv+1) % h->size;
211 s = (char *) malloc(strlen(el)+1);
217 /* Returns nonzero if el is in h */
219 check_hash(struct hashtbl *h,
224 for (hv = hashval(el) % h->size; h->tbl[hv]; hv = (hv + 1) % h->size) {
225 if (!strcmp(h->tbl[hv], el)) {
233 char filename[LINESIZE]; /* Name of acl file */
234 struct hashtbl *acl; /* Acl entries */
237 static struct acl acl_cache[CACHED_ACLS];
239 static int acl_cache_count = 0;
240 static int acl_cache_next = 0;
242 /* Returns < 0 if unsuccessful in loading acl */
243 /* Returns index into acl_cache otherwise */
244 /* Note that if acl is already loaded, this is just a lookup */
245 int acl_load(char *name)
249 char buf[MAX_PRINCIPAL_SIZE];
250 char canon[MAX_PRINCIPAL_SIZE];
252 /* See if it's there already */
253 for (i = 0; i < acl_cache_count; i++) {
254 if (!strcmp(acl_cache[i].filename, name))
258 /* It isn't, load it in */
259 /* maybe there's still room */
260 if (acl_cache_count < CACHED_ACLS) {
261 i = acl_cache_count++;
263 /* No room, clean one out */
265 acl_cache_next = (acl_cache_next + 1) % CACHED_ACLS;
266 if (acl_cache[i].acl) {
267 destroy_hash(acl_cache[i].acl);
268 acl_cache[i].acl = (struct hashtbl *) 0;
273 strcpy(acl_cache[i].filename, name);
275 acl_cache[i].acl = (struct hashtbl *) 0;
279 * See if we need to reload the ACL
281 if (acl_cache[i].acl == (struct hashtbl *) 0) {
283 if ((f = fopen(name, "r")) == NULL) {
284 syslog(LOG_ERR, "Error loading acl file %s: %m", name);
287 if (acl_cache[i].acl) destroy_hash(acl_cache[i].acl);
288 acl_cache[i].acl = make_hash(ACL_LEN);
289 while(fgets(buf, sizeof(buf), f) != NULL) {
290 nuke_whitespace(buf);
291 acl_canonicalize_principal(buf, canon);
292 add_hash(acl_cache[i].acl, canon);
300 * This destroys all cached ACL's so that new ones will be loaded in
301 * the next time they are requested.
304 acl_cache_reset(void)
308 /* See if it's there already */
309 for (i = 0; i < acl_cache_count; i++)
310 if (acl_cache[i].acl) {
311 destroy_hash(acl_cache[i].acl);
312 acl_cache[i].acl = (struct hashtbl *) 0;
319 /* Returns nonzero if it can be determined that acl contains principal */
320 /* Principal is not canonicalized, and no wildcarding is done */
322 acl_exact_match(char *acl,
327 return((idx = acl_load(acl)) >= 0
328 && check_hash(acl_cache[idx].acl, principal));
331 /* Returns nonzero if it can be determined that acl contains principal */
332 /* Recognizes wildcards in acl. */
337 char buf[MAX_PRINCIPAL_SIZE];
338 char canon[MAX_PRINCIPAL_SIZE];
339 char *instance, *realm;
342 /* Parse into principal, instance, and realm. */
343 acl_canonicalize_principal(principal, canon);
344 instance = (char *) strchr(canon, INST_SEP);
346 realm = (char *) strchr(instance, REALM_SEP);
349 for (p = 0; p <= 1; p++) {
350 for (i = 0; i <= 1; i++) {
351 for (r = 0; r <= 1; r++) {
352 sprintf(buf, "%s%c%s%c%s", (p) ? canon : "*", INST_SEP,
353 (i) ? instance : "*", REALM_SEP, (r) ? realm : "*");
354 if (acl_exact_match(acl, buf))