2 * Copyright 2000, International Business Machines Corporation and others.
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
11 Information Technology Center
12 Carnegie-Mellon University
16 #include <afs/param.h>
17 #include <afsconfig.h>
21 #include <sys/types.h>
25 #include <netinet/in.h>
32 #ifdef AFS_PTHREAD_ENV
35 pthread_mutex_t acl_list_mutex;
36 #endif /* AFS_PTHREAD_ENV */
38 static int AddToList();
39 static int GetFromList();
45 struct freeListEntry {
46 struct freeListEntry *next;
51 struct freeListEntry *freeList;
53 /*todo: for sorting acls - make sure they work with new groups lists 10/5*/
54 static int CmpPlus(a,b)
55 struct acl_accessEntry *a, *b;
57 if (a->id < b ->id) return(-1);
58 if (a->id == b->id) return(0);
62 static int CmpMinus(a,b)
63 struct acl_accessEntry *a, *b;
65 if (a->id > b ->id) return(-1);
66 if (a->id == b->id) return(0);
70 static int CmpInt(x,y)
73 if (x < y) return (-1);
74 if (x == y) return (0);
79 int acl_NewACL(nEntries,acl)
81 struct acl_accessList **acl;
83 /* Creates an access list capable of holding at least nEntries entries.
84 Returns 0 on success; aborts if we run out of memory. */
87 struct freeListEntry *e;
89 t = sizeof(struct acl_accessList) + (nEntries-1)*sizeof(struct acl_accessEntry);
90 if (GetFromList(&freeList, &e, t) < 0) {
91 e = (struct freeListEntry *) malloc(t + sizeof(int)+sizeof(struct freeListEntry *));
93 perror("acl_NewACL: malloc() failed");
97 *acl = (struct acl_accessList *)(e->body);
100 *acl = (struct acl_accessList *)(e->body);
102 (*acl)->size = t; /* May be less than actual size of storage */
103 (*acl)->version = ACL_ACLVERSION;
104 (*acl)->total = nEntries;
105 (*acl)->positive = (*acl)->negative = 0;
111 struct acl_accessList **acl;
113 /* Releases the access list defined by acl. Returns 0 always. */
114 struct freeListEntry *x;
116 x = (struct freeListEntry *)
117 ((char *)*acl - sizeof(struct freeListEntry *) - sizeof(int));
119 return(AddToList(&freeList, x));
122 int acl_NewExternalACL(nEntries,r)
126 /* Puts an external acl big enough to hold nEntries in r. Returns 0 on success, aborts if insufficient memory. */
129 struct freeListEntry *e;
131 t = 20 + (nEntries)*(PR_MAXNAMELEN+20);
132 /* Conservative estimate: enough space in each entry for longest
133 name plus decimal 2**32 (for largest rights mask) plus some formatting */
135 if (GetFromList(&freeList, &e, t)) {
136 e = (struct freeListEntry *) malloc(t + sizeof(int)+sizeof(struct freeListEntry *));
138 perror("acl_NewExternalACL(): malloc() failed");
145 sprintf(*r, "0\n0\n");
149 int acl_FreeExternalACL(r)
152 /* Releases the external access list defined by r. Returns 0 always. */
154 struct freeListEntry *x;
156 x = (struct freeListEntry *)
157 ((char *)*r - sizeof(struct freeListEntry *) - sizeof(int));
159 return(AddToList(&freeList, x));
163 int acl_Externalize(acl,elist)
164 struct acl_accessList *acl;
167 /* 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. */
172 register char *nextc;
176 if (acl->total > ACL_MAXENTRIES) return(-1);
177 acl_NewExternalACL(acl->total, elist);
179 lids.idlist_val = (afs_int32 *)malloc(ACL_MAXENTRIES *sizeof(afs_int32));
180 bzero(lids.idlist_val, ACL_MAXENTRIES * sizeof(afs_int32));
181 lids.idlist_len = acl->total;
182 lnames.namelist_len = 0;
183 lnames.namelist_val = (prname *)0;
184 sprintf(nextc, "%d\n%d\n", acl->positive,acl->negative);
185 nextc += strlen(nextc);
186 for (i = 0; i < acl->positive; i++)
187 lids.idlist_val[i] = acl->entries[i].id;
189 for(i=acl->total - 1;i >= acl->total - acl->negative; i--,j++)
190 lids.idlist_val[j] = acl->entries[i].id;
191 code = pr_IdToName(&lids,&lnames);
193 if (lids.idlist_val) free(lids.idlist_val);
194 if (lnames.namelist_val) free(lnames.namelist_val);
197 for (i=0; i <acl->positive;i++) {
198 sprintf(nextc, "%s", lnames.namelist_val[i]);
199 nextc += strlen(nextc);
200 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
201 nextc += strlen(nextc);
204 for (i=acl->total -1;i >= acl->total - acl->negative;i--,j++) {
205 sprintf(nextc, "%s", lnames.namelist_val[j]);
206 nextc += strlen(nextc);
207 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
208 nextc += strlen(nextc);
210 if (lids.idlist_val) free(lids.idlist_val);
211 if (lnames.namelist_val) free(lnames.namelist_val);
216 int acl_Internalize(elist,acl)
218 struct acl_accessList **acl;
220 /* 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. */
223 register char *nextc;
224 register afs_int32 code;
226 char tbuf[PR_MAXNAMELEN+1];
230 if (sscanf(elist, "%d\n%d\n", &p,&n) != 2) return -1;
231 if (p+n > ACL_MAXENTRIES) return(-1);
232 acl_NewACL(p+n, acl);
234 (*acl)->positive = p;
235 (*acl)->negative = n;
236 if ((*acl)->total == 0) {
237 /* Empty acl entry; simply return success */
240 lnames.namelist_len = (*acl)->total;
241 lnames.namelist_val = (prname *)malloc(lnames.namelist_len*PR_MAXNAMELEN);
242 if (lnames.namelist_val == 0) {
246 while(*nextc && *nextc != '\n') nextc++;
248 while(*nextc && *nextc != '\n') nextc++;
249 nextc++; /* now at the beginning of the entry list */
250 for (i = 0; i < (*acl)->positive; i++) {
252 if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[i], &k) != 2)
254 (*acl)->entries[i].rights = k;
255 nextc = (char *) (index(nextc, '\n'));
256 nextc ++; /* 1 + index can cast ptr to integer */
259 for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative; i--,j++) {
260 if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[j], &((*acl)->entries[j].rights)) != 2)
262 nextc = (char *) (index(nextc, '\n'));
268 code = pr_NameToId(&lnames,&lids);
270 free(lnames.namelist_val);
271 if (lids.idlist_val) free(lids.idlist_val);
274 for (i=0;i<(*acl)->positive;i++) {
275 if (lids.idlist_val[i] == ANONYMOUSID) {
276 free(lnames.namelist_val);
277 if (lids.idlist_val) free(lids.idlist_val);
280 (*acl)->entries[i].id = lids.idlist_val[i];
283 for (i=(*acl)->total - 1;i >= (*acl)->total - (*acl)->negative;i--) {
284 if (lids.idlist_val[i] == ANONYMOUSID) {
285 free(lnames.namelist_val);
286 if (lids.idlist_val) free(lids.idlist_val);
289 (*acl)->entries[i].id = lids.idlist_val[i];
291 /* sort for easier lookup */
292 qsort(&((*acl)->entries[0]),(*acl)->positive,sizeof(struct acl_accessEntry),CmpPlus);
293 qsort(&((*acl)->entries[(*acl)->total - (*acl)->negative]),(*acl)->negative,sizeof(struct acl_accessEntry),CmpMinus);
294 free(lnames.namelist_val);
295 if (lids.idlist_val) free(lids.idlist_val);
300 int acl_CheckRights(acl,groups,rights)
301 struct acl_accessList *acl;
305 /* Returns the rights given by acl to groups */
307 int temprights; /* positive rights accumulated so far */
308 int negrights; /* negative rights accumulated so far */
309 int a; /* index into next entry in acl */
310 int c; /* index into next entry in CPS */
312 /* more sanity checks */
313 if (acl->total > ACL_MAXENTRIES) return 1;
314 if (acl->total < 0) return 1;
315 if (acl->size > 192) return 1; /* 192 is the room in a 256 byte vnode reserved for the ACL */
317 if (acl->total <= 0 || groups->prlist_len <= 0) {
321 if (groups->prlist_val[groups->prlist_len -1] == SYSADMINID) {
326 /* Each iteration eats up exactly one entry from either acl or groups.
327 Duplicate Entries in access list ==> accumulated rights are obtained.
328 Duplicate Entries in groups ==> irrelevant */
331 while ( (a < acl->positive) && (c < groups->prlist_len) )
332 switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
338 temprights |= acl->entries[a].rights;
347 printf("CmpInt() returned bogus value. Aborting ...\n");
353 while ((c<groups->prlist_len) && (a > acl->total - acl->negative - 1))
354 switch(CmpInt(acl->entries[a].id,groups->prlist_val[c])) {
359 negrights |= acl->entries[a].rights;
366 *rights = temprights & (~negrights);
370 int acl_Initialize(version)
373 /* I'm sure we need to do some initialization, I'm just not quite sure what yet! */
374 if (strcmp(version, ACL_VERSION) != 0) {
375 fprintf(stderr,"Wrong version of acl package!\n");
376 fprintf(stderr,"This is version %s, file server passed in %s.\n",ACL_VERSION,version);
378 #ifdef AFS_PTHREAD_ENV
379 assert(pthread_mutex_init(&acl_list_mutex, NULL) == 0);
380 #endif /* AFS_PTHREAD_ENV */
383 int acl_IsAMember(aid,cps)
389 for (i=0;i<cps->prlist_len;i++)
390 if (cps->prlist_val[i] == aid) return 1;
395 static int AddToList(pflist,elem)
396 struct freeListEntry **pflist;
397 struct freeListEntry *elem;
399 /* Adds elem to the freelist flist; returns 0 */
400 #ifdef AFS_PTHREAD_ENV
401 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
402 #endif /* AFS_PTHREAD_ENV */
403 elem->next = *pflist;
405 #ifdef AFS_PTHREAD_ENV
406 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
407 #endif /* AFS_PTHREAD_ENV */
411 static int GetFromList(pflist,elem,minsize)
412 struct freeListEntry **pflist;
413 struct freeListEntry **elem;
416 /* 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. */
418 struct freeListEntry *y,*z;
420 #ifdef AFS_PTHREAD_ENV
421 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
422 #endif /* AFS_PTHREAD_ENV */
423 if (*pflist == NULL) {
424 #ifdef AFS_PTHREAD_ENV
425 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
426 #endif /* AFS_PTHREAD_ENV */
429 for (y= *pflist,z=NULL;y!= NULL;z=y,y=y->next) {
430 if (y->size >= minsize) {
432 if (z == NULL) { /* pulling off the head */
434 #ifdef AFS_PTHREAD_ENV
435 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
436 #endif /* AFS_PTHREAD_ENV */
440 #ifdef AFS_PTHREAD_ENV
441 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
442 #endif /* AFS_PTHREAD_ENV */
446 #ifdef AFS_PTHREAD_ENV
447 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
448 #endif /* AFS_PTHREAD_ENV */