source: trunk/athena/bin/discuss/server/acl.c @ 1939

Revision 1939, 12.4 KB checked in by srz, 36 years ago (diff)
Added standard copyright notice.
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl.c,v $
10 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl.c,v 1.12 1989-06-03 00:41:20 srz Exp $
11 *
12 *      Routines for the manipulation of access control lists in core,
13 *      along with routines to move them to and from files.
14 *
15 *      $Log: not supported by cvs2svn $
16 * Revision 1.11  89/01/04  22:20:45  raeburn
17 * Fixed include path: internal.h doesn't need to be in the discuss
18 * subdirectory.
19 *
20 * Revision 1.10  88/09/23  17:03:09  raeburn
21 * Changed type names in accordance with acl.h; used "const" where
22 * appropriate.  Also changed include files to use <discuss/discuss.h>
23 * and <discuss/internal.h>.
24 *
25 * Revision 1.9  87/10/24  07:02:44  wesommer
26 * A bit more robustness.
27 *
28 * Revision 1.8  87/10/24  00:53:39  wesommer
29 * Robustify the acl_read routine.
30 *
31 * Revision 1.7  87/07/20  21:23:25  wesommer
32 * Removed fdclose (kludge), added checking to acl_write() to detect
33 * disk full conditions.
34 *
35 * Revision 1.6  87/03/17  02:25:19  srz
36 * Added expunging.  added acl_copy, and fixed acl_canon to deal with
37 * spaces without barfing.
38 *
39 * Revision 1.5  86/12/08  23:30:56  wesommer
40 * Changed acl_canon() to line up columns.
41 *
42 * Revision 1.4  86/12/04  10:18:57  srz
43 * You !#@$% C programmers don't know what negative subscripts are! ;-)
44 *
45 * Revision 1.3  86/11/22  06:17:45  spook
46 * Changed to make lint happy; also punted duplicate boolean types.
47 *
48 * Revision 1.2  86/11/16  06:01:47  wesommer
49 * Implemented acl_replace_access.
50 * Redefined acl_delete_access and diked out the old one.
51 * Implemented acl_canon (canonicalizes ACL mode string).
52 * Implemented modularity-violating fdclose (blech) so we can use stdio
53 * with fdopen in acl_{read,write} and not lose FILE *'s to a storage leak.
54 *
55 */
56
57#ifndef __STDC__
58#define const
59#endif
60
61#ifndef lint
62static const char rcsid_acl_c[] =
63    "$Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl.c,v 1.12 1989-06-03 00:41:20 srz Exp $";
64#endif lint
65
66#include <stdio.h>
67#include <strings.h>
68#include <ctype.h>
69#include <discuss/discuss.h>
70#include "internal.h"
71
72char *malloc(), *realloc();
73char *acl_union(), *acl_intersection(), *acl_subtract();
74static void panic ();
75
76bool acl_check(list, principal, modes)
77    dsc_acl *list;
78    const char *principal;
79    const char *modes;
80{
81        register dsc_acl_entry *ae;
82        register int n;
83        for (ae = list->acl_entries, n=list->acl_length;
84             n;
85             ae++, n--) {
86                if ((strcmp(principal, ae->principal) == 0) ||
87                    (strcmp("*", ae->principal) == 0))
88                        return(acl_is_subset(modes, ae->modes));
89        }
90        return (FALSE);
91}
92
93dsc_acl *acl_read(fd)
94    int fd;
95{
96        static char buf[128];
97        FILE *f=fdopen(dup(fd), "r");
98        register char *cp;
99        register int n;
100        register dsc_acl_entry *ae;
101        register dsc_acl *list;
102
103        if (!f) return NULL;    /* oops. */
104       
105        list = (dsc_acl *) malloc(sizeof(dsc_acl));
106        if (!list) goto punt;
107        list->acl_entries = (dsc_acl_entry *)NULL;
108        list->acl_length = 0;
109       
110        if (fgets(buf, 128, f) == NULL) goto punt;
111        if (!isdigit((unsigned)buf[0])) goto punt;
112       
113        n=atoi(buf);
114        list->acl_entries =
115            (dsc_acl_entry *)malloc((unsigned)(n * sizeof(dsc_acl_entry)));
116        if (!list->acl_entries) goto punt;
117       
118        list->acl_length = 0;
119        for (ae=list->acl_entries; n; --n)  {
120                buf[0]=0;
121                if (fgets(buf, 128, f) == NULL) goto punt;
122                if(cp=index(buf, '\n')) *cp='\0';
123                if(cp=index(buf, ':')) {
124                        *cp='\0';
125                        list->acl_length++;
126                        ae->principal = NULL;
127                        ae->modes = malloc((unsigned)(strlen(buf)+1));
128                        if (!ae->modes) goto punt;
129                        (void) strcpy(ae->modes, buf);
130                        ae->principal = malloc((unsigned)(strlen(cp+1)+1));
131                        if (!ae->principal) goto punt;
132                        (void) strcpy(ae->principal, cp+1);
133                        ae++;
134                } else { /* skip line */
135                }
136        }
137        (void) fclose(f);
138        return(list);
139punt:
140        fclose(f);
141        if (list) acl_destroy(list);
142        return NULL;
143}
144/*
145 * Attempt to write an access control list to fd.
146 * Return FALSE on failure with reason in errno.
147 */
148
149bool acl_write(fd, list)
150     int fd;
151     dsc_acl *list;
152{
153        FILE *f=fdopen(dup(fd), "w");
154        register int n;
155        register dsc_acl_entry *ae;
156        char buf[BUFSIZ];
157        int len;
158
159        (void) sprintf(buf, "%d\n", list->acl_length);
160        len = strlen(buf);
161        if (fwrite(buf, 1, len, f) != len) goto punt;
162       
163        for (ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
164                (void) sprintf(buf, "%s:%s\n", ae->modes, ae->principal);
165                len = strlen(buf);
166                if (fwrite(buf, 1, len, f) != len) goto punt;
167        }
168        if (fflush(f) == EOF) goto punt;
169        if (fsync(fileno(f)) < 0) goto punt;
170        if (fclose(f) == EOF) return FALSE;
171        return(TRUE);
172punt:
173        fclose(f);
174        return(FALSE);
175}
176
177acl_add_access(list, principal, modes)
178    dsc_acl *list;
179    const char *principal;
180    const char *modes;
181{
182        register int n;
183        register dsc_acl_entry *ae;
184        char *new_modes;
185        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
186                if (!strcmp(ae->principal, principal)) {
187                        new_modes = acl_union(modes, ae->modes);
188                        (void) free(ae->modes);
189                        ae->modes=new_modes;
190                        return;
191                }
192        }
193        /*
194         * Whoops.. fell through.
195         * Realloc the world - or at least the vector.
196         */
197        list->acl_length++;
198        list->acl_entries =
199            (dsc_acl_entry *) realloc((char *)(list->acl_entries),
200                                  (unsigned)(list->acl_length
201                                             * sizeof(dsc_acl_entry)));
202        ae = list->acl_entries + list->acl_length - 2;
203        /*
204         * Is the last entry "*"?  If so, push it back one.
205         */
206        if (list -> acl_length > 1) {           /* non-empty acl */
207             if (!strcmp(ae->principal, "*")) {
208                  if(!strcmp(principal, "*"))
209                          panic("acl broke");
210                  *(ae+1) = *ae;
211                  --ae;
212             }
213        }
214        ae++;
215        ae->principal = malloc((unsigned)(strlen(principal)+1));
216        (void) strcpy(ae->principal, principal);
217        ae->modes = malloc((unsigned)(strlen(modes)+1));
218        (void) strcpy(ae->modes, modes);
219}
220
221#ifdef notdef
222acl_delete_modes(list, principal, modes)
223     dsc_acl *list;
224     char *principal;
225     char *modes;
226{
227        register dsc_acl_entry *ae, *ae1;
228        register int n;
229        char *new_modes;
230        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
231                if (!strcmp(ae->principal, principal)) {
232                        new_modes = acl_subtract(modes, ae->modes);
233                        (void) free(ae->modes);
234                        ae->modes=new_modes;
235                        goto cleanup;
236                }
237        }
238        return;
239cleanup:
240        ae1 = list->acl_entries + list->acl_length - 1;
241        if ((strcmp(ae1->principal, "*")!= 0 && strcmp(ae->modes, "")) ||
242            (!strcmp(ae1->principal, "*") && !strcmp(ae->modes, ae1->modes))) {
243                    (void) free(ae->principal);
244                    (void) free(ae->modes);
245                for (; ae <ae1; ae++) *ae= *(ae+1);
246                list->acl_length--;
247                list->acl_entries = (acl_entry *) realloc(list->acl_entries,
248                                       list->acl_length * sizeof(dsc_acl_entry));
249        }
250
251}             
252#endif notdef
253acl_replace_access(list, principal, modes)
254    dsc_acl *list;
255    const char *principal;
256    const char *modes;
257{
258        register dsc_acl_entry *ae;
259        register int n;
260        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
261                if (!strcmp(ae->principal, principal)) {
262                        (void) free(ae->modes);
263                        ae->modes = malloc((unsigned)(strlen(modes)+1));
264                        (void) strcpy(ae->modes, modes);
265                        return;
266                }
267        }
268        /* Didn't find it.  Insert it.. the easy way. */
269        acl_add_access(list, principal, modes);
270}
271
272bool
273acl_delete_access(list, principal)
274        dsc_acl *list;
275        const char *principal;
276{
277        register dsc_acl_entry *ae;
278        register int n;
279        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
280                if (!strcmp(ae->principal, principal)) {
281                        /* gotcha! */
282                        list->acl_length--;
283                        while (--n) {
284                                *ae= *(ae+1);
285                                ae++;
286                        }
287                        return TRUE;
288                }
289        }
290        return FALSE;
291}
292/*
293 * Return empty ACL
294 */
295
296dsc_acl *acl_create()
297{
298        register dsc_acl *result = (dsc_acl *) malloc(sizeof(dsc_acl));
299        result->acl_length=0;
300        result->acl_entries=(dsc_acl_entry *) malloc(sizeof(dsc_acl_entry));
301        return(result);
302}
303
304dsc_acl *acl_copy (old_acl)
305    dsc_acl *old_acl;
306{
307     register dsc_acl *new_acl = (dsc_acl *) malloc (sizeof(dsc_acl));
308     register dsc_acl_entry *old_ae,*new_ae;
309     register int n;
310
311     new_acl -> acl_length = old_acl -> acl_length;
312     new_acl -> acl_entries = (dsc_acl_entry *) malloc ((unsigned)(new_acl -> acl_length * sizeof(dsc_acl_entry)));
313
314     for (old_ae = old_acl->acl_entries, new_ae = new_acl->acl_entries, n=new_acl->acl_length;
315          n;
316          --n, ++old_ae, ++new_ae) {
317               new_ae->principal = malloc (strlen(old_ae->principal)+1);
318               strcpy (new_ae->principal,old_ae->principal);
319               new_ae->modes = malloc (strlen(old_ae->modes)+1);
320               strcpy (new_ae->modes,old_ae->modes);
321          }
322               
323     return (new_acl);
324}
325
326const char *acl_get_access(list, principal)
327        dsc_acl *list;
328        const char *principal;
329{
330        register dsc_acl_entry *ae;
331        register int n;
332
333        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
334                if (!strcmp(ae->principal, principal) ||
335                    !strcmp(ae->principal, "*")) {
336                        return(ae->modes);
337                }
338        }
339        return("");
340}
341/*
342 * Destroy an ACL.     
343 */
344
345acl_destroy(list)
346     dsc_acl *list;
347{
348        register dsc_acl_entry *ae;
349        register int n;
350        if(!list) return;
351        for (ae=list->acl_entries, n=list->acl_length;
352             ae && n;
353             --n, ++ae) {
354                     if (ae->principal) (void) free(ae->principal);
355                     if (ae->modes) (void) free(ae->modes);
356        }
357        if (ae) (void) free((char *)(list->acl_entries));
358        (void) free((char *)list);
359}
360
361/*
362 * Returns true if every character of s1 occurs in s2.
363 */
364bool acl_is_subset(s1, s2)
365     register const char *s1, *s2;
366{
367        register char *last;
368        while(*s1 && (last = index(s2, *s1))) s1++;
369
370        return(last != NULL);
371}
372
373/*
374 * Returns the intersection of the two strings s1 and s2.
375 * This function allocates a new string, which should be freed
376 * when not needed.
377 */
378char *acl_intersection(s1, s2)
379     register const char *s1, *s2;
380{
381        register char *result=malloc(1);
382        register int resp=0;
383
384        while(*s1) {
385                if(index(s2, *s1)) {
386                        result[resp++] = *s1;
387                        result=realloc(result, (unsigned)(resp+1));
388                }
389                s1++;
390        }
391        result[resp] = '\0';
392        return(result);
393}
394
395char *acl_union(s1, s2)
396     register const char *s1, *s2;
397{
398        register int resp=strlen(s2);
399        register char *result=malloc((unsigned)(resp+1));
400        strcpy(result, s2);
401        while(*s1) {
402                if (!index(result, *s1)) {
403                        result[resp++]= *s1;
404                        result=realloc(result, (unsigned)(resp+1));
405                }
406                s1++;
407        }
408        result[resp]='\0';
409        return(result);
410}
411
412char *acl_subtract(s1, s2)
413     register const char *s1, *s2;
414{
415        register char *result = malloc(1);
416        register int len=0;
417        for (; *s2; s2++) {
418                if (!index(s1, *s2)) {
419                        result = realloc(result, (unsigned)(len+2));
420                        result[len++]= *s2;
421                }
422        }
423        result[len]='\0';
424        return(result);
425}
426
427/*
428 * Canonicalize an acl string; sort the characters of s1 into
429 * the order found in s2, removing duplicates, and returning an error code if
430 * any of them are not in s2.
431 * This is a sucky algorithm, but who really gives?
432 */
433
434char *acl_canon(s1, s2, code)
435        register const char *s1, *s2;
436        int *code;
437{
438        register const char *cp;
439        register char *out;
440        register int len, maxlen;
441
442        *code = 0;
443        for (cp = s1; *cp; cp++) {
444                if (*cp != ' ' && !index(s2, *cp))
445                        *code = BAD_MODES;
446        }
447        maxlen = strlen(s2);
448        out = malloc(maxlen + 1); len = 0;
449        for (cp = s2; *cp; cp++) {
450                len++;
451                if (len > maxlen) /* shouldn't happen, but.. */
452                        out = realloc(out, (unsigned)len + 1);
453
454                out[len-1] = (index(s1, *cp) ? *cp : ' ');
455        }
456        out[len]='\0';
457        return(out);
458}
459
460       
461
462
463#ifdef TESTS
464#include <sys/file.h>
465main()
466{
467        int fd;
468        dsc_acl *a;
469
470        printf("%s * %s = %s\n", "eabce", "abcd",
471               acl_intersection("eabce", "abcd"));
472        printf("%s + %s = %s\n", "abc", "cbade", acl_union("abc", "cbade"));
473        printf("%s < %s = %d\n", "ab", "bcde", acl_is_subset("ab", "bcde"));
474        printf("%s < %s = %d\n", "ab", "abcde", acl_is_subset("ab", "abcde"));
475
476        fd = open ("foo.acl", O_RDONLY);
477        a=acl_read(fd);
478        (void) close(fd);
479        printf("a for wesommer: %d\n", acl_check(a, "wesommer", "a"));
480        printf("a for foobar: %d\n", acl_check(a, "foobar", "a"));
481        printf("a for spook: %d\n", acl_check(a, "spook", "a"));
482        printf("g for foobar: %d\n", acl_check(a, "foobar", "g"));
483        printf("g for wesommer: %d\n", acl_check(a, "wesommer", "g"));
484        printf("g for spook: %d\n", acl_check(a, "spook", "g"));
485        printf("d for spook: %d\n", acl_check(a, "spook", "d"));
486        printf("d for wesommer: %d\n", acl_check(a, "wesommer", "d"));
487        acl_add_access(a, "zot", "qna");
488        acl_add_access(a, "spook", "d");
489        acl_add_access(a, "*", "w");
490        fd = open("bar.acl", O_WRONLY+O_CREAT+O_TRUNC);
491        acl_write(fd, a);
492        (void) close(fd);
493}
494#endif TESTS
495
496static void panic(s)
497        char *s;
498{
499        printf(s);
500        fflush(stdout);
501        abort();
502}
Note: See TracBrowser for help on using the repository browser.