winnt-include-sanity-20030314
[openafs.git] / src / libacl / aclprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11         Information Technology Center
12         Carnegie-Mellon University
13 */
14
15
16 #include <afsconfig.h>
17 #include <afs/param.h>
18
19 RCSID("$Header$");
20
21 #include <sys/types.h>
22 #ifdef AFS_NT40_ENV
23 #include <winsock2.h>
24 #else
25 #include <netinet/in.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 #include <rx/xdr.h>
31 #include <rx/rx.h>
32 #include <afs/ptclient.h>
33 #include "acl.h"
34
35 #ifdef AFS_PTHREAD_ENV
36 #include <assert.h>
37 #include <pthread.h>
38 pthread_mutex_t acl_list_mutex;
39 #endif /* AFS_PTHREAD_ENV */
40
41 static int AddToList();
42 static int GetFromList();
43
44 struct freeListEntry {
45     struct freeListEntry *next;
46     int size;
47     char body[1];       
48 };
49
50 struct freeListEntry *freeList;
51
52 /*todo: for sorting acls - make sure they work with new groups lists 10/5*/
53 static int CmpPlus(a,b)
54 struct acl_accessEntry *a, *b;
55 {
56      if (a->id < b ->id) return(-1);
57      if (a->id == b->id) return(0);
58      return(1);
59 }
60
61 static int CmpMinus(a,b)
62 struct acl_accessEntry *a, *b;
63 {
64      if (a->id > b ->id) return(-1);
65      if (a->id == b->id) return(0);
66      return(1);
67 }
68
69 static int CmpInt(x,y)
70 afs_int32 x, y;
71 {
72      if (x < y) return (-1);
73      if (x == y) return (0);
74      return (1);
75 }
76
77
78 int acl_NewACL(nEntries,acl)
79 int nEntries;
80 struct acl_accessList **acl;
81 {
82     /* Creates an access list capable of holding at least nEntries entries.
83       Returns 0 on success; aborts if we run out of memory. */
84
85     int t;
86     struct freeListEntry *e;
87
88     t = sizeof(struct acl_accessList) + (nEntries-1)*sizeof(struct acl_accessEntry);
89     if (GetFromList(&freeList, &e, t) < 0) {
90         e = (struct freeListEntry *) malloc(t + sizeof(int)+sizeof(struct freeListEntry *));
91         if (e == NULL) {
92             perror("acl_NewACL: malloc() failed");
93             abort();
94         }
95         e->size = t;
96         *acl = (struct acl_accessList *)(e->body);
97     }
98     else
99         *acl = (struct acl_accessList *)(e->body);
100
101     (*acl)->size = t;                   /* May be less than actual size of storage */
102     (*acl)->version = ACL_ACLVERSION;
103     (*acl)->total = nEntries;
104     (*acl)->positive = (*acl)->negative = 0;
105     return(0);
106 }
107
108
109 int acl_FreeACL(acl)
110 struct acl_accessList **acl;
111 {
112     /* Releases the access list defined by acl.  Returns 0 always. */
113     struct freeListEntry *x;
114
115     x = (struct freeListEntry *)
116       ((char *)*acl - sizeof(struct freeListEntry *) - sizeof(int));
117     *acl = NULL;
118     return(AddToList(&freeList, x));
119 }
120
121 int acl_NewExternalACL(nEntries,r)
122 int nEntries;
123 char **r;
124 {
125     /* Puts an external acl big enough to hold nEntries in r.  Returns 0 on success, aborts if insufficient memory. */
126
127     int t;
128     struct freeListEntry *e;
129
130     t = 20 + (nEntries)*(PR_MAXNAMELEN+20);
131     /* Conservative estimate: enough space in each entry for longest 
132         name plus decimal 2**32 (for largest rights mask) plus some formatting */
133
134     if (GetFromList(&freeList, &e, t)) {
135         e = (struct freeListEntry *) malloc(t + sizeof(int)+sizeof(struct freeListEntry *));
136         if (e == NULL) {
137             perror("acl_NewExternalACL(): malloc() failed");
138             abort();
139         }
140         e->size= t;
141     }
142
143     *r = e->body;
144     sprintf(*r, "0\n0\n");
145     return(0);
146 }
147
148 int acl_FreeExternalACL(r)
149 char **r;
150 {
151     /* Releases the external access list defined by r.  Returns 0 always.  */
152
153     struct freeListEntry *x;
154
155     x = (struct freeListEntry *)
156       ((char *)*r - sizeof(struct freeListEntry *) - sizeof(int));
157     *r = NULL;
158     return(AddToList(&freeList, x));
159 }
160
161
162 int acl_Externalize(acl,elist)
163 struct acl_accessList *acl;
164 char **elist;
165 {
166     /* Converts the access list defined by acl into the external access list in elist.  Non-translatable id's are converted to their ASCII string representations.  Returns 0 on success, -1 if number of entries exceeds ACL_MAXENTRIES, or a failure code from the protection server if the problem occured there. */
167
168     register int i;
169     register int j;
170     register code;
171     register char *nextc;
172     idlist lids;
173     namelist lnames;
174
175     if (acl->total > ACL_MAXENTRIES) return(-1);
176     acl_NewExternalACL(acl->total, elist);
177     nextc = *elist;
178     lids.idlist_val = (afs_int32 *)malloc(ACL_MAXENTRIES *sizeof(afs_int32));
179     memset(lids.idlist_val, 0, ACL_MAXENTRIES * sizeof(afs_int32));
180     lids.idlist_len = acl->total;
181     lnames.namelist_len = 0;
182     lnames.namelist_val = (prname *)0;
183     sprintf(nextc, "%d\n%d\n", acl->positive,acl->negative);
184     nextc += strlen(nextc);
185     for (i = 0; i < acl->positive; i++)
186         lids.idlist_val[i] = acl->entries[i].id;
187     j=i;
188     for(i=acl->total - 1;i >= acl->total - acl->negative; i--,j++)
189         lids.idlist_val[j] = acl->entries[i].id;
190     code = pr_IdToName(&lids,&lnames);
191     if (code != 0) {
192         if (lids.idlist_val) free(lids.idlist_val);
193         if (lnames.namelist_val) free(lnames.namelist_val);
194         return code;
195     }
196     for (i=0; i <acl->positive;i++) {
197         sprintf(nextc, "%s", lnames.namelist_val[i]);
198         nextc += strlen(nextc);
199         sprintf(nextc, "\t%d\n", acl->entries[i].rights);
200         nextc += strlen(nextc);
201     }
202     j = i;
203     for (i=acl->total -1;i >= acl->total - acl->negative;i--,j++) {
204         sprintf(nextc, "%s", lnames.namelist_val[j]);
205         nextc += strlen(nextc);
206         sprintf(nextc, "\t%d\n", acl->entries[i].rights);
207         nextc += strlen(nextc);
208     }
209     if (lids.idlist_val) free(lids.idlist_val);
210     if (lnames.namelist_val) free(lnames.namelist_val);
211     return (0);
212 }
213
214
215 int acl_Internalize(elist,acl)
216 char *elist;
217 struct acl_accessList **acl;
218 {
219     /* Converts the external access list elist into the access list acl.  Returns 0 on success, -1 if ANY name is not translatable, or if the number of entries exceeds al_maxExtEntries. */
220     register int i;
221     register int j;
222     register char *nextc;
223     register afs_int32 code;
224     int p,n;
225     namelist lnames;
226     idlist lids;
227
228     if (sscanf(elist, "%d\n%d\n", &p,&n) != 2) return -1;
229     if (p+n > ACL_MAXENTRIES) return(-1);
230     acl_NewACL(p+n, acl);
231     (*acl)->total = p+n;
232     (*acl)->positive = p;
233     (*acl)->negative = n;
234     if ((*acl)->total == 0) {
235       /* Empty acl entry; simply return success */
236       return 0;
237     }
238     lnames.namelist_len = (*acl)->total;
239     lnames.namelist_val = (prname *)malloc(lnames.namelist_len*PR_MAXNAMELEN);
240     if (lnames.namelist_val == 0) {
241       return -1; 
242     }
243     nextc = elist;
244     while(*nextc && *nextc != '\n') nextc++;
245     nextc++;
246     while(*nextc && *nextc != '\n') nextc++;
247     nextc++;    /* now at the beginning of the entry list */
248     for (i = 0; i < (*acl)->positive; i++) {
249         int k;
250         if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[i], &k) != 2)
251             return(-1);
252         (*acl)->entries[i].rights = k;
253         nextc = strchr(nextc, '\n');
254         nextc ++;       /* 1 + index can cast ptr to integer */
255     }
256     j=i;
257     for (i = (*acl)->total - 1; i >= (*acl)->total -  (*acl)->negative; i--,j++) {
258         if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[j], &((*acl)->entries[j].rights)) != 2)
259             return(-1);
260         nextc = strchr(nextc, '\n');
261         nextc ++;
262     }
263     lids.idlist_len = 0;
264     lids.idlist_val = 0;
265
266     code = pr_NameToId(&lnames,&lids);
267     if (code) {
268         free(lnames.namelist_val);
269         if (lids.idlist_val) free(lids.idlist_val);
270         return -1;
271     }
272     for (i=0;i<(*acl)->positive;i++) {
273         if (lids.idlist_val[i] == ANONYMOUSID) {
274             free(lnames.namelist_val);
275             if (lids.idlist_val) free(lids.idlist_val);
276             return -1;
277         }
278         (*acl)->entries[i].id = lids.idlist_val[i];
279     }
280     j = i;
281     for (i=(*acl)->total - 1;i >= (*acl)->total - (*acl)->negative;i--) {
282         if (lids.idlist_val[i] == ANONYMOUSID) {
283             free(lnames.namelist_val);
284             if (lids.idlist_val) free(lids.idlist_val);
285             return -1;
286         }
287         (*acl)->entries[i].id = lids.idlist_val[i];
288     }
289     /* sort for easier lookup */
290     qsort(&((*acl)->entries[0]),(*acl)->positive,sizeof(struct acl_accessEntry),CmpPlus);
291     qsort(&((*acl)->entries[(*acl)->total - (*acl)->negative]),(*acl)->negative,sizeof(struct acl_accessEntry),CmpMinus);
292     free(lnames.namelist_val);
293     if (lids.idlist_val) free(lids.idlist_val);
294     return(0);
295 }
296
297
298 int acl_CheckRights(acl,groups,rights)
299 struct acl_accessList *acl;
300 prlist *groups;
301 int *rights;
302 {
303     /* Returns the rights given by acl to groups */
304
305     int temprights;             /* positive rights accumulated so far */
306     int negrights;              /* negative rights accumulated so far */
307     int a;                      /* index into next entry in acl */
308     int c;                      /* index into next entry in CPS */
309
310     /* more sanity checks */
311     if (acl->total > ACL_MAXENTRIES) return 1;
312     if (acl->total < 0) return 1;
313     if (acl->size > 192) return 1;      /* 192 is the room in a 256 byte vnode reserved for the ACL */
314
315     if (acl->total <= 0 || groups->prlist_len <= 0) {
316         *rights = 0;
317         return(0);
318     }
319     if (groups->prlist_val[groups->prlist_len -1] == SYSADMINID) {
320         *rights = -1;
321         return 0;
322     }
323     
324     /* Each iteration eats up exactly one entry from either acl or groups.
325       Duplicate Entries in access list ==> accumulated rights are obtained.
326       Duplicate Entries in groups ==> irrelevant */
327     temprights = 0;
328     c = a = 0;    
329     while ( (a < acl->positive)  && (c < groups->prlist_len) )
330         switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
331             case -1:
332                 a += 1;
333                 break;
334
335             case 0:
336                 temprights |= acl->entries[a].rights;
337                 a += 1;
338                 break;
339
340             case 1:
341                 c += 1;
342                 break;      
343
344             default:
345                 printf("CmpInt() returned bogus value. Aborting ...\n");
346                 abort();
347         }
348     negrights = 0;
349     c = 0;
350     a = acl->total -1;
351     while ((c<groups->prlist_len) && (a > acl->total - acl->negative - 1))
352         switch(CmpInt(acl->entries[a].id,groups->prlist_val[c])) {
353             case -1:
354                 a -= 1;
355                 break;
356             case 0:
357                 negrights |= acl->entries[a].rights;
358                 a -= 1;
359                 break;
360             case 1:
361                 c += 1;
362                 break;
363         }
364     *rights = temprights & (~negrights);
365     return(0);
366 }
367
368 int acl_Initialize(version)
369 char *version;
370 {
371     /* I'm sure we need to do some initialization, I'm just not quite sure what yet! */
372     if (strcmp(version, ACL_VERSION) != 0) {
373         fprintf(stderr,"Wrong version of acl package!\n");
374         fprintf(stderr,"This is version %s, file server passed in %s.\n",ACL_VERSION,version);
375     }
376 #ifdef AFS_PTHREAD_ENV
377     assert(pthread_mutex_init(&acl_list_mutex, NULL) == 0);
378 #endif /* AFS_PTHREAD_ENV */
379     return 0;
380 }
381
382 int acl_IsAMember(aid,cps)
383 afs_int32 aid;
384 prlist *cps;
385 {
386     afs_int32 i;
387
388     for (i=0;i<cps->prlist_len;i++)
389         if (cps->prlist_val[i] == aid) return 1;
390     return 0;
391 }
392
393
394 static int AddToList(pflist,elem)
395 struct freeListEntry **pflist;
396 struct freeListEntry  *elem;
397 {
398     /* Adds elem to the freelist flist;  returns 0 */
399 #ifdef AFS_PTHREAD_ENV
400     assert(pthread_mutex_lock(&acl_list_mutex) == 0);
401 #endif /* AFS_PTHREAD_ENV */
402     elem->next = *pflist;
403     *pflist = elem;
404 #ifdef AFS_PTHREAD_ENV
405     assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
406 #endif /* AFS_PTHREAD_ENV */
407     return 0;
408 }
409
410 static int GetFromList(pflist,elem,minsize)
411 struct freeListEntry **pflist;
412 struct freeListEntry  **elem;
413 afs_int32 minsize;
414 {
415     /* Looks for an element whose body is at least minsize bytes in the freelist flist.  If found, unlinks it, puts its address in elem, and returns 0, else returns -1.  A trivial first-fit algorithm is used. */
416
417     struct freeListEntry *y,*z;
418
419 #ifdef AFS_PTHREAD_ENV
420     assert(pthread_mutex_lock(&acl_list_mutex) == 0);
421 #endif /* AFS_PTHREAD_ENV */
422     if (*pflist == NULL) {
423 #ifdef AFS_PTHREAD_ENV
424         assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
425 #endif /* AFS_PTHREAD_ENV */
426         return -1;
427     }
428     for (y= *pflist,z=NULL;y!= NULL;z=y,y=y->next) {
429         if (y->size >= minsize) {
430             *elem = y;
431             if (z == NULL) { /* pulling off the head */
432                 *pflist = y->next;
433 #ifdef AFS_PTHREAD_ENV
434                 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
435 #endif /* AFS_PTHREAD_ENV */
436                 return 0;
437             }
438             z->next = y->next;
439 #ifdef AFS_PTHREAD_ENV
440             assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
441 #endif /* AFS_PTHREAD_ENV */
442             return 0;
443         }
444     }
445 #ifdef AFS_PTHREAD_ENV
446     assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
447 #endif /* AFS_PTHREAD_ENV */
448     return -1;
449 }
450