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 <afsconfig.h>
17 #include <afs/param.h>
20 #include <sys/types.h>
24 #include <netinet/in.h>
29 #include <afs/ptclient.h>
30 #include <afs/ptuser.h>
33 #ifdef AFS_PTHREAD_ENV
36 pthread_mutex_t acl_list_mutex;
37 #endif /* AFS_PTHREAD_ENV */
39 struct freeListEntry {
40 struct freeListEntry *next;
45 struct freeListEntry *freeList;
47 static int AddToList(struct freeListEntry **, struct freeListEntry *);
48 static int GetFromList(struct freeListEntry **, struct freeListEntry **,
51 /*todo: for sorting acls - make sure they work with new groups lists 10/5*/
53 CmpPlus(const void *arg1, const void *arg2)
55 const struct acl_accessEntry *a = (struct acl_accessEntry *) arg1;
56 const struct acl_accessEntry *b = (struct acl_accessEntry *) arg2;
65 CmpMinus(const void *arg1, const void *arg2)
67 const struct acl_accessEntry *a = (struct acl_accessEntry *) arg1;
68 const struct acl_accessEntry *b = (struct acl_accessEntry *) arg2;
89 acl_NewACL(int nEntries, struct acl_accessList **acl)
91 /* Creates an access list capable of holding at least nEntries entries.
92 * Returns 0 on success; aborts if we run out of memory. */
95 struct freeListEntry *e;
97 t = sizeof(struct acl_accessList) + (nEntries -
98 1) * sizeof(struct acl_accessEntry);
99 if (GetFromList(&freeList, &e, t) < 0) {
100 e = (struct freeListEntry *)malloc(t + sizeof(int) +
101 sizeof(struct freeListEntry *));
103 perror("acl_NewACL: malloc() failed");
107 *acl = (struct acl_accessList *)(e->body);
109 *acl = (struct acl_accessList *)(e->body);
111 (*acl)->size = t; /* May be less than actual size of storage */
112 (*acl)->version = ACL_ACLVERSION;
113 (*acl)->total = nEntries;
114 (*acl)->positive = (*acl)->negative = 0;
120 acl_FreeACL(struct acl_accessList **acl)
122 /* Releases the access list defined by acl. Returns 0 always. */
123 struct freeListEntry *x;
125 x = (struct freeListEntry *)
126 ((char *)*acl - sizeof(struct freeListEntry *) - sizeof(int));
128 return (AddToList(&freeList, x));
132 acl_NewExternalACL(int nEntries, char **r)
134 /* Puts an external acl big enough to hold nEntries in r. Returns 0 on success, aborts if insufficient memory. */
137 struct freeListEntry *e;
139 t = 20 + (nEntries) * (PR_MAXNAMELEN + 20);
140 /* Conservative estimate: enough space in each entry for longest
141 * name plus decimal 2**32 (for largest rights mask) plus some formatting */
143 if (GetFromList(&freeList, &e, t)) {
144 e = (struct freeListEntry *)malloc(t + sizeof(int) +
145 sizeof(struct freeListEntry *));
147 perror("acl_NewExternalACL(): malloc() failed");
154 sprintf(*r, "0\n0\n");
159 acl_FreeExternalACL(char **r)
161 /* Releases the external access list defined by r. Returns 0 always. */
163 struct freeListEntry *x;
165 x = (struct freeListEntry *)
166 ((char *)*r - sizeof(struct freeListEntry *) - sizeof(int));
168 return (AddToList(&freeList, x));
172 acl_Externalize_pr(int (*func)(idlist *ids, namelist *names), struct acl_accessList *acl, char **elist)
174 /* Converts the access list defined by acl into the external access list
175 * in elist. Non-translatable id's are converted to their ASCII string
176 * representations. Returns 0 on success, -1 if number of entries
177 * exceeds ACL_MAXENTRIES, or a failure code from the protection server
178 * if the problem occured there. */
187 if (acl->total > ACL_MAXENTRIES)
189 acl_NewExternalACL(acl->total, elist);
192 (afs_int32 *) malloc(ACL_MAXENTRIES * sizeof(afs_int32));
193 memset(lids.idlist_val, 0, ACL_MAXENTRIES * sizeof(afs_int32));
194 lids.idlist_len = acl->total;
195 lnames.namelist_len = 0;
196 lnames.namelist_val = (prname *) 0;
197 sprintf(nextc, "%d\n%d\n", acl->positive, acl->negative);
198 nextc += strlen(nextc);
199 for (i = 0; i < acl->positive; i++)
200 lids.idlist_val[i] = acl->entries[i].id;
202 for (i = acl->total - 1; i >= acl->total - acl->negative; i--, j++)
203 lids.idlist_val[j] = acl->entries[i].id;
204 code = (*func)(&lids, &lnames);
207 free(lids.idlist_val);
208 if (lnames.namelist_val)
209 free(lnames.namelist_val);
212 for (i = 0; i < acl->positive; i++) {
213 sprintf(nextc, "%s", lnames.namelist_val[i]);
214 nextc += strlen(nextc);
215 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
216 nextc += strlen(nextc);
219 for (i = acl->total - 1; i >= acl->total - acl->negative; i--, j++) {
220 sprintf(nextc, "%s", lnames.namelist_val[j]);
221 nextc += strlen(nextc);
222 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
223 nextc += strlen(nextc);
226 free(lids.idlist_val);
227 if (lnames.namelist_val)
228 free(lnames.namelist_val);
233 acl_Externalize(struct acl_accessList *acl, char **elist)
235 return acl_Externalize_pr(pr_IdToName, acl, elist);
239 acl_Internalize_pr(int (*func)(namelist *names, idlist *ids), char *elist, struct acl_accessList **acl)
241 /* Converts the external access list elist into the access list acl.
242 * Returns 0 on success, -1 if ANY name is not translatable, or if
243 * the number of entries exceeds al_maxExtEntries. */
252 if (sscanf(elist, "%d\n%d\n", &p, &n) != 2)
254 if (p + n > ACL_MAXENTRIES)
256 acl_NewACL(p + n, acl);
257 (*acl)->total = p + n;
258 (*acl)->positive = p;
259 (*acl)->negative = n;
260 if ((*acl)->total == 0) {
261 /* Empty acl entry; simply return success */
264 lnames.namelist_len = (*acl)->total;
265 lnames.namelist_val =
266 (prname *) malloc(lnames.namelist_len * PR_MAXNAMELEN);
267 if (lnames.namelist_val == 0) {
271 while (*nextc && *nextc != '\n')
274 while (*nextc && *nextc != '\n')
276 nextc++; /* now at the beginning of the entry list */
277 for (i = 0; i < (*acl)->positive; i++) {
279 if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[i], &k) != 2) {
280 free(lnames.namelist_val);
283 (*acl)->entries[i].rights = k;
284 nextc = strchr(nextc, '\n');
285 nextc++; /* 1 + index can cast ptr to integer */
288 for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative;
291 (nextc, "%s\t%d\n", lnames.namelist_val[j],
292 &((*acl)->entries[j].rights)) != 2) {
293 free(lnames.namelist_val);
296 nextc = strchr(nextc, '\n');
302 code = (*func)(&lnames, &lids);
304 free(lnames.namelist_val);
306 free(lids.idlist_val);
309 for (i = 0; i < (*acl)->positive; i++) {
310 if (lids.idlist_val[i] == ANONYMOUSID) {
311 free(lnames.namelist_val);
313 free(lids.idlist_val);
316 (*acl)->entries[i].id = lids.idlist_val[i];
319 for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative; i--) {
320 if (lids.idlist_val[i] == ANONYMOUSID) {
321 free(lnames.namelist_val);
323 free(lids.idlist_val);
326 (*acl)->entries[i].id = lids.idlist_val[i];
328 /* sort for easier lookup */
329 qsort(&((*acl)->entries[0]), (*acl)->positive,
330 sizeof(struct acl_accessEntry), CmpPlus);
331 qsort(&((*acl)->entries[(*acl)->total - (*acl)->negative]),
332 (*acl)->negative, sizeof(struct acl_accessEntry), CmpMinus);
333 free(lnames.namelist_val);
335 free(lids.idlist_val);
340 acl_Internalize(char *elist, struct acl_accessList **acl)
342 return acl_Internalize_pr(pr_NameToId, elist, acl);
346 acl_CheckRights(struct acl_accessList *acl, prlist *groups, int *rights)
348 /* Returns the rights given by acl to groups */
350 int temprights; /* positive rights accumulated so far */
351 int negrights; /* negative rights accumulated so far */
352 int a; /* index into next entry in acl */
353 int c; /* index into next entry in CPS */
355 /* more sanity checks */
356 if (acl->total > ACL_MAXENTRIES)
361 return 1; /* 192 is the room in a 256 byte vnode reserved for the ACL */
363 if (acl->total <= 0 || groups->prlist_len <= 0) {
367 if (groups->prlist_val[groups->prlist_len - 1] == SYSADMINID) {
372 /* Each iteration eats up exactly one entry from either acl or groups.
373 * Duplicate Entries in access list ==> accumulated rights are obtained.
374 * Duplicate Entries in groups ==> irrelevant */
377 while ((a < acl->positive) && (c < groups->prlist_len))
378 switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
384 temprights |= acl->entries[a].rights;
393 printf("CmpInt() returned bogus value. Aborting ...\n");
399 while ((c < groups->prlist_len) && (a > acl->total - acl->negative - 1))
400 switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
405 negrights |= acl->entries[a].rights;
412 *rights = temprights & (~negrights);
417 acl_Initialize(char *version)
419 /* I'm sure we need to do some initialization, I'm just not quite sure what yet! */
420 if (strcmp(version, ACL_VERSION) != 0) {
421 fprintf(stderr, "Wrong version of acl package!\n");
422 fprintf(stderr, "This is version %s, file server passed in %s.\n",
423 ACL_VERSION, version);
425 #ifdef AFS_PTHREAD_ENV
426 assert(pthread_mutex_init(&acl_list_mutex, NULL) == 0);
427 #endif /* AFS_PTHREAD_ENV */
432 acl_IsAMember(afs_int32 aid, prlist *cps)
436 for (i = 0; i < cps->prlist_len; i++)
437 if (cps->prlist_val[i] == aid)
444 AddToList(struct freeListEntry **pflist, struct freeListEntry *elem)
446 /* Adds elem to the freelist flist; returns 0 */
447 #ifdef AFS_PTHREAD_ENV
448 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
449 #endif /* AFS_PTHREAD_ENV */
450 elem->next = *pflist;
452 #ifdef AFS_PTHREAD_ENV
453 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
454 #endif /* AFS_PTHREAD_ENV */
459 GetFromList(struct freeListEntry **pflist, struct freeListEntry **elem,
462 /* Looks for an element whose body is at least minsize bytes in the
463 * freelist flist. If found, unlinks it, puts its address in elem,
464 * and returns 0, else returns -1. A trivial first-fit algorithm is
467 struct freeListEntry *y, *z;
469 #ifdef AFS_PTHREAD_ENV
470 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
471 #endif /* AFS_PTHREAD_ENV */
472 if (*pflist == NULL) {
473 #ifdef AFS_PTHREAD_ENV
474 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
475 #endif /* AFS_PTHREAD_ENV */
478 for (y = *pflist, z = NULL; y != NULL; z = y, y = y->next) {
479 if (y->size >= minsize) {
481 if (z == NULL) { /* pulling off the head */
483 #ifdef AFS_PTHREAD_ENV
484 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
485 #endif /* AFS_PTHREAD_ENV */
489 #ifdef AFS_PTHREAD_ENV
490 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
491 #endif /* AFS_PTHREAD_ENV */
495 #ifdef AFS_PTHREAD_ENV
496 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
497 #endif /* AFS_PTHREAD_ENV */