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

Revision 25469, 10.8 KB checked in by geofft, 12 years ago (diff)
In discuss: * Fix FTBFS with -Werror=format-security.
RevLine 
[132]1/*
[1939]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/*
[22404]9 *      $Id: acl.c,v 1.18 2006-03-10 07:11:39 ghudson Exp $
[132]10 *
[148]11 *      Routines for the manipulation of access control lists in core,
12 *      along with routines to move them to and from files.
13 *
[132]14 */
15
[1476]16#ifndef __STDC__
17#define const
18#endif
19
[132]20#ifndef lint
[1476]21static const char rcsid_acl_c[] =
[22404]22    "$Id: acl.c,v 1.18 2006-03-10 07:11:39 ghudson Exp $";
[12459]23#endif /* lint */
[132]24
25#include <stdio.h>
[22404]26#include <stdlib.h>
[8855]27#include <string.h>
[818]28#include <ctype.h>
[1476]29#include <discuss/discuss.h>
[1624]30#include "internal.h"
[132]31
32char *acl_union(), *acl_intersection(), *acl_subtract();
[1476]33static void panic ();
[132]34
[166]35bool acl_check(list, principal, modes)
[1476]36    dsc_acl *list;
37    const char *principal;
38    const char *modes;
[132]39{
[1476]40        register dsc_acl_entry *ae;
[132]41        register int n;
42        for (ae = list->acl_entries, n=list->acl_length;
43             n;
44             ae++, n--) {
45                if ((strcmp(principal, ae->principal) == 0) ||
46                    (strcmp("*", ae->principal) == 0))
47                        return(acl_is_subset(modes, ae->modes));
48        }
49        return (FALSE);
50}
51
[1476]52dsc_acl *acl_read(fd)
53    int fd;
[132]54{
55        static char buf[128];
[628]56        FILE *f=fdopen(dup(fd), "r");
[132]57        register char *cp;
58        register int n;
[1476]59        register dsc_acl_entry *ae;
60        register dsc_acl *list;
[818]61
62        if (!f) return NULL;    /* oops. */
63       
[1476]64        list = (dsc_acl *) malloc(sizeof(dsc_acl));
[823]65        if (!list) goto punt;
[1476]66        list->acl_entries = (dsc_acl_entry *)NULL;
[823]67        list->acl_length = 0;
68       
[818]69        if (fgets(buf, 128, f) == NULL) goto punt;
[823]70        if (!isdigit((unsigned)buf[0])) goto punt;
[818]71       
72        n=atoi(buf);
[1476]73        list->acl_entries =
74            (dsc_acl_entry *)malloc((unsigned)(n * sizeof(dsc_acl_entry)));
[818]75        if (!list->acl_entries) goto punt;
76       
77        list->acl_length = 0;
78        for (ae=list->acl_entries; n; --n)  {
[132]79                buf[0]=0;
[818]80                if (fgets(buf, 128, f) == NULL) goto punt;
[7182]81                if(cp=strchr(buf, '\n')) *cp='\0';
82                if(cp=strchr(buf, ':')) {
[132]83                        *cp='\0';
[818]84                        list->acl_length++;
85                        ae->principal = NULL;
[166]86                        ae->modes = malloc((unsigned)(strlen(buf)+1));
[818]87                        if (!ae->modes) goto punt;
[166]88                        (void) strcpy(ae->modes, buf);
89                        ae->principal = malloc((unsigned)(strlen(cp+1)+1));
[818]90                        if (!ae->principal) goto punt;
[166]91                        (void) strcpy(ae->principal, cp+1);
[818]92                        ae++;
[132]93                } else { /* skip line */
94                }
95        }
[628]96        (void) fclose(f);
[132]97        return(list);
[818]98punt:
99        fclose(f);
100        if (list) acl_destroy(list);
101        return NULL;
[132]102}
[628]103/*
104 * Attempt to write an access control list to fd.
105 * Return FALSE on failure with reason in errno.
106 */
[132]107
[166]108bool acl_write(fd, list)
[132]109     int fd;
[1476]110     dsc_acl *list;
[132]111{
[628]112        FILE *f=fdopen(dup(fd), "w");
[132]113        register int n;
[1476]114        register dsc_acl_entry *ae;
[628]115        char buf[BUFSIZ];
116        int len;
117
118        (void) sprintf(buf, "%d\n", list->acl_length);
119        len = strlen(buf);
120        if (fwrite(buf, 1, len, f) != len) goto punt;
121       
122        for (ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
[15700]123                (void) sprintf(buf, "%s:%.100s\n", ae->modes, ae->principal);
[628]124                len = strlen(buf);
125                if (fwrite(buf, 1, len, f) != len) goto punt;
126        }
127        if (fflush(f) == EOF) goto punt;
128        if (fsync(fileno(f)) < 0) goto punt;
129        if (fclose(f) == EOF) return FALSE;
[148]130        return(TRUE);
[628]131punt:
132        fclose(f);
133        return(FALSE);
[132]134}
135
136acl_add_access(list, principal, modes)
[1476]137    dsc_acl *list;
138    const char *principal;
139    const char *modes;
[132]140{
141        register int n;
[1476]142        register dsc_acl_entry *ae;
[132]143        char *new_modes;
144        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
145                if (!strcmp(ae->principal, principal)) {
146                        new_modes = acl_union(modes, ae->modes);
[166]147                        (void) free(ae->modes);
[132]148                        ae->modes=new_modes;
149                        return;
150                }
151        }
152        /*
153         * Whoops.. fell through.
154         * Realloc the world - or at least the vector.
155         */
156        list->acl_length++;
[1476]157        list->acl_entries =
158            (dsc_acl_entry *) realloc((char *)(list->acl_entries),
159                                  (unsigned)(list->acl_length
160                                             * sizeof(dsc_acl_entry)));
[132]161        ae = list->acl_entries + list->acl_length - 2;
162        /*
163         * Is the last entry "*"?  If so, push it back one.
164         */
[180]165        if (list -> acl_length > 1) {           /* non-empty acl */
166             if (!strcmp(ae->principal, "*")) {
167                  if(!strcmp(principal, "*"))
[258]168                          panic("acl broke");
[180]169                  *(ae+1) = *ae;
170                  --ae;
171             }
[132]172        }
173        ae++;
[166]174        ae->principal = malloc((unsigned)(strlen(principal)+1));
175        (void) strcpy(ae->principal, principal);
176        ae->modes = malloc((unsigned)(strlen(modes)+1));
177        (void) strcpy(ae->modes, modes);
[132]178}
179
[148]180#ifdef notdef
181acl_delete_modes(list, principal, modes)
[1476]182     dsc_acl *list;
[132]183     char *principal;
184     char *modes;
185{
[1476]186        register dsc_acl_entry *ae, *ae1;
[132]187        register int n;
188        char *new_modes;
189        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
190                if (!strcmp(ae->principal, principal)) {
191                        new_modes = acl_subtract(modes, ae->modes);
[166]192                        (void) free(ae->modes);
[132]193                        ae->modes=new_modes;
194                        goto cleanup;
195                }
196        }
197        return;
198cleanup:
199        ae1 = list->acl_entries + list->acl_length - 1;
200        if ((strcmp(ae1->principal, "*")!= 0 && strcmp(ae->modes, "")) ||
201            (!strcmp(ae1->principal, "*") && !strcmp(ae->modes, ae1->modes))) {
[166]202                    (void) free(ae->principal);
203                    (void) free(ae->modes);
[132]204                for (; ae <ae1; ae++) *ae= *(ae+1);
205                list->acl_length--;
206                list->acl_entries = (acl_entry *) realloc(list->acl_entries,
[1476]207                                       list->acl_length * sizeof(dsc_acl_entry));
[132]208        }
209
210}             
[12459]211#endif /* notdef */
[132]212acl_replace_access(list, principal, modes)
[1476]213    dsc_acl *list;
214    const char *principal;
215    const char *modes;
[132]216{
[1476]217        register dsc_acl_entry *ae;
[148]218        register int n;
219        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
220                if (!strcmp(ae->principal, principal)) {
[166]221                        (void) free(ae->modes);
222                        ae->modes = malloc((unsigned)(strlen(modes)+1));
223                        (void) strcpy(ae->modes, modes);
[148]224                        return;
225                }
226        }
227        /* Didn't find it.  Insert it.. the easy way. */
228        acl_add_access(list, principal, modes);
229}
[132]230
[166]231bool
[148]232acl_delete_access(list, principal)
[1476]233        dsc_acl *list;
234        const char *principal;
[148]235{
[1476]236        register dsc_acl_entry *ae;
[148]237        register int n;
238        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
239                if (!strcmp(ae->principal, principal)) {
240                        /* gotcha! */
241                        list->acl_length--;
242                        while (--n) {
243                                *ae= *(ae+1);
244                                ae++;
245                        }
246                        return TRUE;
247                }
248        }
249        return FALSE;
[132]250}
251/*
252 * Return empty ACL
253 */
254
[1476]255dsc_acl *acl_create()
[132]256{
[1476]257        register dsc_acl *result = (dsc_acl *) malloc(sizeof(dsc_acl));
[132]258        result->acl_length=0;
[1476]259        result->acl_entries=(dsc_acl_entry *) malloc(sizeof(dsc_acl_entry));
[132]260        return(result);
261}
262
[1476]263dsc_acl *acl_copy (old_acl)
264    dsc_acl *old_acl;
[258]265{
[1476]266     register dsc_acl *new_acl = (dsc_acl *) malloc (sizeof(dsc_acl));
267     register dsc_acl_entry *old_ae,*new_ae;
[258]268     register int n;
269
270     new_acl -> acl_length = old_acl -> acl_length;
[1476]271     new_acl -> acl_entries = (dsc_acl_entry *) malloc ((unsigned)(new_acl -> acl_length * sizeof(dsc_acl_entry)));
[258]272
273     for (old_ae = old_acl->acl_entries, new_ae = new_acl->acl_entries, n=new_acl->acl_length;
274          n;
275          --n, ++old_ae, ++new_ae) {
276               new_ae->principal = malloc (strlen(old_ae->principal)+1);
277               strcpy (new_ae->principal,old_ae->principal);
278               new_ae->modes = malloc (strlen(old_ae->modes)+1);
279               strcpy (new_ae->modes,old_ae->modes);
280          }
281               
282     return (new_acl);
283}
284
[1476]285const char *acl_get_access(list, principal)
286        dsc_acl *list;
287        const char *principal;
[132]288{
[1476]289        register dsc_acl_entry *ae;
[132]290        register int n;
291
292        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
293                if (!strcmp(ae->principal, principal) ||
294                    !strcmp(ae->principal, "*")) {
295                        return(ae->modes);
296                }
297        }
298        return("");
299}
300/*
301 * Destroy an ACL.     
302 */
303
304acl_destroy(list)
[1476]305     dsc_acl *list;
[132]306{
[1476]307        register dsc_acl_entry *ae;
[132]308        register int n;
309        if(!list) return;
310        for (ae=list->acl_entries, n=list->acl_length;
[818]311             ae && n;
[132]312             --n, ++ae) {
[818]313                     if (ae->principal) (void) free(ae->principal);
314                     if (ae->modes) (void) free(ae->modes);
[132]315        }
[818]316        if (ae) (void) free((char *)(list->acl_entries));
[166]317        (void) free((char *)list);
[132]318}
319
320/*
321 * Returns true if every character of s1 occurs in s2.
322 */
[166]323bool acl_is_subset(s1, s2)
[1476]324     register const char *s1, *s2;
[132]325{
326        register char *last;
[7182]327        while(*s1 && (last = strchr(s2, *s1))) s1++;
[132]328
329        return(last != NULL);
330}
331
332/*
333 * Returns the intersection of the two strings s1 and s2.
334 * This function allocates a new string, which should be freed
335 * when not needed.
336 */
337char *acl_intersection(s1, s2)
[1476]338     register const char *s1, *s2;
[132]339{
340        register char *result=malloc(1);
341        register int resp=0;
342
343        while(*s1) {
[7182]344                if(strchr(s2, *s1)) {
[132]345                        result[resp++] = *s1;
[166]346                        result=realloc(result, (unsigned)(resp+1));
[132]347                }
348                s1++;
349        }
350        result[resp] = '\0';
351        return(result);
352}
353
354char *acl_union(s1, s2)
[1476]355     register const char *s1, *s2;
[132]356{
357        register int resp=strlen(s2);
[166]358        register char *result=malloc((unsigned)(resp+1));
[132]359        strcpy(result, s2);
360        while(*s1) {
[7182]361                if (!strchr(result, *s1)) {
[132]362                        result[resp++]= *s1;
[166]363                        result=realloc(result, (unsigned)(resp+1));
[132]364                }
365                s1++;
366        }
367        result[resp]='\0';
368        return(result);
369}
370
371char *acl_subtract(s1, s2)
[1476]372     register const char *s1, *s2;
[132]373{
374        register char *result = malloc(1);
375        register int len=0;
376        for (; *s2; s2++) {
[7182]377                if (!strchr(s1, *s2)) {
[166]378                        result = realloc(result, (unsigned)(len+2));
[132]379                        result[len++]= *s2;
380                }
381        }
382        result[len]='\0';
383        return(result);
384}
385
[148]386/*
387 * Canonicalize an acl string; sort the characters of s1 into
388 * the order found in s2, removing duplicates, and returning an error code if
389 * any of them are not in s2.
390 * This is a sucky algorithm, but who really gives?
391 */
[132]392
[148]393char *acl_canon(s1, s2, code)
[1476]394        register const char *s1, *s2;
[148]395        int *code;
396{
[1476]397        register const char *cp;
[148]398        register char *out;
[197]399        register int len, maxlen;
[148]400
401        *code = 0;
402        for (cp = s1; *cp; cp++) {
[7182]403                if (*cp != ' ' && !strchr(s2, *cp))
[148]404                        *code = BAD_MODES;
405        }
[197]406        maxlen = strlen(s2);
407        out = malloc(maxlen + 1); len = 0;
[148]408        for (cp = s2; *cp; cp++) {
[197]409                len++;
410                if (len > maxlen) /* shouldn't happen, but.. */
411                        out = realloc(out, (unsigned)len + 1);
412
[7182]413                out[len-1] = (strchr(s1, *cp) ? *cp : ' ');
[148]414        }
415        out[len]='\0';
416        return(out);
417}
418
419       
420
421
[132]422#ifdef TESTS
423#include <sys/file.h>
424main()
425{
426        int fd;
[1476]427        dsc_acl *a;
[132]428
429        printf("%s * %s = %s\n", "eabce", "abcd",
430               acl_intersection("eabce", "abcd"));
431        printf("%s + %s = %s\n", "abc", "cbade", acl_union("abc", "cbade"));
432        printf("%s < %s = %d\n", "ab", "bcde", acl_is_subset("ab", "bcde"));
433        printf("%s < %s = %d\n", "ab", "abcde", acl_is_subset("ab", "abcde"));
434
435        fd = open ("foo.acl", O_RDONLY);
436        a=acl_read(fd);
[166]437        (void) close(fd);
[132]438        printf("a for wesommer: %d\n", acl_check(a, "wesommer", "a"));
439        printf("a for foobar: %d\n", acl_check(a, "foobar", "a"));
440        printf("a for spook: %d\n", acl_check(a, "spook", "a"));
441        printf("g for foobar: %d\n", acl_check(a, "foobar", "g"));
442        printf("g for wesommer: %d\n", acl_check(a, "wesommer", "g"));
443        printf("g for spook: %d\n", acl_check(a, "spook", "g"));
444        printf("d for spook: %d\n", acl_check(a, "spook", "d"));
445        printf("d for wesommer: %d\n", acl_check(a, "wesommer", "d"));
446        acl_add_access(a, "zot", "qna");
447        acl_add_access(a, "spook", "d");
448        acl_add_access(a, "*", "w");
449        fd = open("bar.acl", O_WRONLY+O_CREAT+O_TRUNC);
450        acl_write(fd, a);
[166]451        (void) close(fd);
[132]452}
[12459]453#endif /* TESTS */
[258]454
[1476]455static void panic(s)
[132]456        char *s;
457{
[25469]458        printf("%s\n", s);
[132]459        fflush(stdout);
460        abort();
461}
Note: See TracBrowser for help on using the repository browser.