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.
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 *      $Id: acl.c,v 1.18 2006-03-10 07:11:39 ghudson Exp $
10 *
11 *      Routines for the manipulation of access control lists in core,
12 *      along with routines to move them to and from files.
13 *
14 */
15
16#ifndef __STDC__
17#define const
18#endif
19
20#ifndef lint
21static const char rcsid_acl_c[] =
22    "$Id: acl.c,v 1.18 2006-03-10 07:11:39 ghudson Exp $";
23#endif /* lint */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <discuss/discuss.h>
30#include "internal.h"
31
32char *acl_union(), *acl_intersection(), *acl_subtract();
33static void panic ();
34
35bool acl_check(list, principal, modes)
36    dsc_acl *list;
37    const char *principal;
38    const char *modes;
39{
40        register dsc_acl_entry *ae;
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
52dsc_acl *acl_read(fd)
53    int fd;
54{
55        static char buf[128];
56        FILE *f=fdopen(dup(fd), "r");
57        register char *cp;
58        register int n;
59        register dsc_acl_entry *ae;
60        register dsc_acl *list;
61
62        if (!f) return NULL;    /* oops. */
63       
64        list = (dsc_acl *) malloc(sizeof(dsc_acl));
65        if (!list) goto punt;
66        list->acl_entries = (dsc_acl_entry *)NULL;
67        list->acl_length = 0;
68       
69        if (fgets(buf, 128, f) == NULL) goto punt;
70        if (!isdigit((unsigned)buf[0])) goto punt;
71       
72        n=atoi(buf);
73        list->acl_entries =
74            (dsc_acl_entry *)malloc((unsigned)(n * sizeof(dsc_acl_entry)));
75        if (!list->acl_entries) goto punt;
76       
77        list->acl_length = 0;
78        for (ae=list->acl_entries; n; --n)  {
79                buf[0]=0;
80                if (fgets(buf, 128, f) == NULL) goto punt;
81                if(cp=strchr(buf, '\n')) *cp='\0';
82                if(cp=strchr(buf, ':')) {
83                        *cp='\0';
84                        list->acl_length++;
85                        ae->principal = NULL;
86                        ae->modes = malloc((unsigned)(strlen(buf)+1));
87                        if (!ae->modes) goto punt;
88                        (void) strcpy(ae->modes, buf);
89                        ae->principal = malloc((unsigned)(strlen(cp+1)+1));
90                        if (!ae->principal) goto punt;
91                        (void) strcpy(ae->principal, cp+1);
92                        ae++;
93                } else { /* skip line */
94                }
95        }
96        (void) fclose(f);
97        return(list);
98punt:
99        fclose(f);
100        if (list) acl_destroy(list);
101        return NULL;
102}
103/*
104 * Attempt to write an access control list to fd.
105 * Return FALSE on failure with reason in errno.
106 */
107
108bool acl_write(fd, list)
109     int fd;
110     dsc_acl *list;
111{
112        FILE *f=fdopen(dup(fd), "w");
113        register int n;
114        register dsc_acl_entry *ae;
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) {
123                (void) sprintf(buf, "%s:%.100s\n", ae->modes, ae->principal);
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;
130        return(TRUE);
131punt:
132        fclose(f);
133        return(FALSE);
134}
135
136acl_add_access(list, principal, modes)
137    dsc_acl *list;
138    const char *principal;
139    const char *modes;
140{
141        register int n;
142        register dsc_acl_entry *ae;
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);
147                        (void) free(ae->modes);
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++;
157        list->acl_entries =
158            (dsc_acl_entry *) realloc((char *)(list->acl_entries),
159                                  (unsigned)(list->acl_length
160                                             * sizeof(dsc_acl_entry)));
161        ae = list->acl_entries + list->acl_length - 2;
162        /*
163         * Is the last entry "*"?  If so, push it back one.
164         */
165        if (list -> acl_length > 1) {           /* non-empty acl */
166             if (!strcmp(ae->principal, "*")) {
167                  if(!strcmp(principal, "*"))
168                          panic("acl broke");
169                  *(ae+1) = *ae;
170                  --ae;
171             }
172        }
173        ae++;
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);
178}
179
180#ifdef notdef
181acl_delete_modes(list, principal, modes)
182     dsc_acl *list;
183     char *principal;
184     char *modes;
185{
186        register dsc_acl_entry *ae, *ae1;
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);
192                        (void) free(ae->modes);
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))) {
202                    (void) free(ae->principal);
203                    (void) free(ae->modes);
204                for (; ae <ae1; ae++) *ae= *(ae+1);
205                list->acl_length--;
206                list->acl_entries = (acl_entry *) realloc(list->acl_entries,
207                                       list->acl_length * sizeof(dsc_acl_entry));
208        }
209
210}             
211#endif /* notdef */
212acl_replace_access(list, principal, modes)
213    dsc_acl *list;
214    const char *principal;
215    const char *modes;
216{
217        register dsc_acl_entry *ae;
218        register int n;
219        for(ae=list->acl_entries, n=list->acl_length; n; --n, ++ae) {
220                if (!strcmp(ae->principal, principal)) {
221                        (void) free(ae->modes);
222                        ae->modes = malloc((unsigned)(strlen(modes)+1));
223                        (void) strcpy(ae->modes, modes);
224                        return;
225                }
226        }
227        /* Didn't find it.  Insert it.. the easy way. */
228        acl_add_access(list, principal, modes);
229}
230
231bool
232acl_delete_access(list, principal)
233        dsc_acl *list;
234        const char *principal;
235{
236        register dsc_acl_entry *ae;
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;
250}
251/*
252 * Return empty ACL
253 */
254
255dsc_acl *acl_create()
256{
257        register dsc_acl *result = (dsc_acl *) malloc(sizeof(dsc_acl));
258        result->acl_length=0;
259        result->acl_entries=(dsc_acl_entry *) malloc(sizeof(dsc_acl_entry));
260        return(result);
261}
262
263dsc_acl *acl_copy (old_acl)
264    dsc_acl *old_acl;
265{
266     register dsc_acl *new_acl = (dsc_acl *) malloc (sizeof(dsc_acl));
267     register dsc_acl_entry *old_ae,*new_ae;
268     register int n;
269
270     new_acl -> acl_length = old_acl -> acl_length;
271     new_acl -> acl_entries = (dsc_acl_entry *) malloc ((unsigned)(new_acl -> acl_length * sizeof(dsc_acl_entry)));
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
285const char *acl_get_access(list, principal)
286        dsc_acl *list;
287        const char *principal;
288{
289        register dsc_acl_entry *ae;
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)
305     dsc_acl *list;
306{
307        register dsc_acl_entry *ae;
308        register int n;
309        if(!list) return;
310        for (ae=list->acl_entries, n=list->acl_length;
311             ae && n;
312             --n, ++ae) {
313                     if (ae->principal) (void) free(ae->principal);
314                     if (ae->modes) (void) free(ae->modes);
315        }
316        if (ae) (void) free((char *)(list->acl_entries));
317        (void) free((char *)list);
318}
319
320/*
321 * Returns true if every character of s1 occurs in s2.
322 */
323bool acl_is_subset(s1, s2)
324     register const char *s1, *s2;
325{
326        register char *last;
327        while(*s1 && (last = strchr(s2, *s1))) s1++;
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)
338     register const char *s1, *s2;
339{
340        register char *result=malloc(1);
341        register int resp=0;
342
343        while(*s1) {
344                if(strchr(s2, *s1)) {
345                        result[resp++] = *s1;
346                        result=realloc(result, (unsigned)(resp+1));
347                }
348                s1++;
349        }
350        result[resp] = '\0';
351        return(result);
352}
353
354char *acl_union(s1, s2)
355     register const char *s1, *s2;
356{
357        register int resp=strlen(s2);
358        register char *result=malloc((unsigned)(resp+1));
359        strcpy(result, s2);
360        while(*s1) {
361                if (!strchr(result, *s1)) {
362                        result[resp++]= *s1;
363                        result=realloc(result, (unsigned)(resp+1));
364                }
365                s1++;
366        }
367        result[resp]='\0';
368        return(result);
369}
370
371char *acl_subtract(s1, s2)
372     register const char *s1, *s2;
373{
374        register char *result = malloc(1);
375        register int len=0;
376        for (; *s2; s2++) {
377                if (!strchr(s1, *s2)) {
378                        result = realloc(result, (unsigned)(len+2));
379                        result[len++]= *s2;
380                }
381        }
382        result[len]='\0';
383        return(result);
384}
385
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 */
392
393char *acl_canon(s1, s2, code)
394        register const char *s1, *s2;
395        int *code;
396{
397        register const char *cp;
398        register char *out;
399        register int len, maxlen;
400
401        *code = 0;
402        for (cp = s1; *cp; cp++) {
403                if (*cp != ' ' && !strchr(s2, *cp))
404                        *code = BAD_MODES;
405        }
406        maxlen = strlen(s2);
407        out = malloc(maxlen + 1); len = 0;
408        for (cp = s2; *cp; cp++) {
409                len++;
410                if (len > maxlen) /* shouldn't happen, but.. */
411                        out = realloc(out, (unsigned)len + 1);
412
413                out[len-1] = (strchr(s1, *cp) ? *cp : ' ');
414        }
415        out[len]='\0';
416        return(out);
417}
418
419       
420
421
422#ifdef TESTS
423#include <sys/file.h>
424main()
425{
426        int fd;
427        dsc_acl *a;
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);
437        (void) close(fd);
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);
451        (void) close(fd);
452}
453#endif /* TESTS */
454
455static void panic(s)
456        char *s;
457{
458        printf("%s\n", s);
459        fflush(stdout);
460        abort();
461}
Note: See TracBrowser for help on using the repository browser.