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>
22 #include <sys/types.h>
26 #include <netinet/in.h>
31 #include <afs/ptclient.h>
34 #ifdef AFS_PTHREAD_ENV
37 pthread_mutex_t acl_list_mutex;
38 #endif /* AFS_PTHREAD_ENV */
40 static int AddToList();
41 static int GetFromList();
43 struct freeListEntry {
44 struct freeListEntry *next;
49 struct freeListEntry *freeList;
51 /*todo: for sorting acls - make sure they work with new groups lists 10/5*/
54 struct acl_accessEntry *a, *b;
65 struct acl_accessEntry *a, *b;
87 acl_NewACL(int nEntries, struct acl_accessList **acl)
89 /* Creates an access list capable of holding at least nEntries entries.
90 * Returns 0 on success; aborts if we run out of memory. */
93 struct freeListEntry *e;
95 t = sizeof(struct acl_accessList) + (nEntries -
96 1) * sizeof(struct acl_accessEntry);
97 if (GetFromList(&freeList, &e, t) < 0) {
98 e = (struct freeListEntry *)malloc(t + sizeof(int) +
99 sizeof(struct freeListEntry *));
101 perror("acl_NewACL: malloc() failed");
105 *acl = (struct acl_accessList *)(e->body);
107 *acl = (struct acl_accessList *)(e->body);
109 (*acl)->size = t; /* May be less than actual size of storage */
110 (*acl)->version = ACL_ACLVERSION;
111 (*acl)->total = nEntries;
112 (*acl)->positive = (*acl)->negative = 0;
118 acl_FreeACL(struct acl_accessList **acl)
120 /* Releases the access list defined by acl. Returns 0 always. */
121 struct freeListEntry *x;
123 x = (struct freeListEntry *)
124 ((char *)*acl - sizeof(struct freeListEntry *) - sizeof(int));
126 return (AddToList(&freeList, x));
130 acl_NewExternalACL(int nEntries, char **r)
132 /* Puts an external acl big enough to hold nEntries in r. Returns 0 on success, aborts if insufficient memory. */
135 struct freeListEntry *e;
137 t = 20 + (nEntries) * (PR_MAXNAMELEN + 20);
138 /* Conservative estimate: enough space in each entry for longest
139 * name plus decimal 2**32 (for largest rights mask) plus some formatting */
141 if (GetFromList(&freeList, &e, t)) {
142 e = (struct freeListEntry *)malloc(t + sizeof(int) +
143 sizeof(struct freeListEntry *));
145 perror("acl_NewExternalACL(): malloc() failed");
152 sprintf(*r, "0\n0\n");
157 acl_FreeExternalACL(char **r)
159 /* Releases the external access list defined by r. Returns 0 always. */
161 struct freeListEntry *x;
163 x = (struct freeListEntry *)
164 ((char *)*r - sizeof(struct freeListEntry *) - sizeof(int));
166 return (AddToList(&freeList, x));
171 acl_Externalize(struct acl_accessList *acl, char **elist)
173 /* 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. */
178 register char *nextc;
182 if (acl->total > ACL_MAXENTRIES)
184 acl_NewExternalACL(acl->total, elist);
187 (afs_int32 *) malloc(ACL_MAXENTRIES * sizeof(afs_int32));
188 memset(lids.idlist_val, 0, ACL_MAXENTRIES * sizeof(afs_int32));
189 lids.idlist_len = acl->total;
190 lnames.namelist_len = 0;
191 lnames.namelist_val = (prname *) 0;
192 sprintf(nextc, "%d\n%d\n", acl->positive, acl->negative);
193 nextc += strlen(nextc);
194 for (i = 0; i < acl->positive; i++)
195 lids.idlist_val[i] = acl->entries[i].id;
197 for (i = acl->total - 1; i >= acl->total - acl->negative; i--, j++)
198 lids.idlist_val[j] = acl->entries[i].id;
199 code = pr_IdToName(&lids, &lnames);
202 free(lids.idlist_val);
203 if (lnames.namelist_val)
204 free(lnames.namelist_val);
207 for (i = 0; i < acl->positive; i++) {
208 sprintf(nextc, "%s", lnames.namelist_val[i]);
209 nextc += strlen(nextc);
210 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
211 nextc += strlen(nextc);
214 for (i = acl->total - 1; i >= acl->total - acl->negative; i--, j++) {
215 sprintf(nextc, "%s", lnames.namelist_val[j]);
216 nextc += strlen(nextc);
217 sprintf(nextc, "\t%d\n", acl->entries[i].rights);
218 nextc += strlen(nextc);
221 free(lids.idlist_val);
222 if (lnames.namelist_val)
223 free(lnames.namelist_val);
229 acl_Internalize(char *elist, struct acl_accessList **acl)
231 /* 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. */
234 register char *nextc;
235 register afs_int32 code;
240 if (sscanf(elist, "%d\n%d\n", &p, &n) != 2)
242 if (p + n > ACL_MAXENTRIES)
244 acl_NewACL(p + n, acl);
245 (*acl)->total = p + n;
246 (*acl)->positive = p;
247 (*acl)->negative = n;
248 if ((*acl)->total == 0) {
249 /* Empty acl entry; simply return success */
252 lnames.namelist_len = (*acl)->total;
253 lnames.namelist_val =
254 (prname *) malloc(lnames.namelist_len * PR_MAXNAMELEN);
255 if (lnames.namelist_val == 0) {
259 while (*nextc && *nextc != '\n')
262 while (*nextc && *nextc != '\n')
264 nextc++; /* now at the beginning of the entry list */
265 for (i = 0; i < (*acl)->positive; i++) {
267 if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[i], &k) != 2) {
268 free(lnames.namelist_val);
271 (*acl)->entries[i].rights = k;
272 nextc = strchr(nextc, '\n');
273 nextc++; /* 1 + index can cast ptr to integer */
276 for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative;
279 (nextc, "%s\t%d\n", lnames.namelist_val[j],
280 &((*acl)->entries[j].rights)) != 2) {
281 free(lnames.namelist_val);
284 nextc = strchr(nextc, '\n');
290 code = pr_NameToId(&lnames, &lids);
292 free(lnames.namelist_val);
294 free(lids.idlist_val);
297 for (i = 0; i < (*acl)->positive; i++) {
298 if (lids.idlist_val[i] == ANONYMOUSID) {
299 free(lnames.namelist_val);
301 free(lids.idlist_val);
304 (*acl)->entries[i].id = lids.idlist_val[i];
307 for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative; i--) {
308 if (lids.idlist_val[i] == ANONYMOUSID) {
309 free(lnames.namelist_val);
311 free(lids.idlist_val);
314 (*acl)->entries[i].id = lids.idlist_val[i];
316 /* sort for easier lookup */
317 qsort(&((*acl)->entries[0]), (*acl)->positive,
318 sizeof(struct acl_accessEntry), CmpPlus);
319 qsort(&((*acl)->entries[(*acl)->total - (*acl)->negative]),
320 (*acl)->negative, sizeof(struct acl_accessEntry), CmpMinus);
321 free(lnames.namelist_val);
323 free(lids.idlist_val);
329 acl_CheckRights(struct acl_accessList *acl, prlist *groups, int *rights)
331 /* Returns the rights given by acl to groups */
333 int temprights; /* positive rights accumulated so far */
334 int negrights; /* negative rights accumulated so far */
335 int a; /* index into next entry in acl */
336 int c; /* index into next entry in CPS */
338 /* more sanity checks */
339 if (acl->total > ACL_MAXENTRIES)
344 return 1; /* 192 is the room in a 256 byte vnode reserved for the ACL */
346 if (acl->total <= 0 || groups->prlist_len <= 0) {
350 if (groups->prlist_val[groups->prlist_len - 1] == SYSADMINID) {
355 /* Each iteration eats up exactly one entry from either acl or groups.
356 * Duplicate Entries in access list ==> accumulated rights are obtained.
357 * Duplicate Entries in groups ==> irrelevant */
360 while ((a < acl->positive) && (c < groups->prlist_len))
361 switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
367 temprights |= acl->entries[a].rights;
376 printf("CmpInt() returned bogus value. Aborting ...\n");
382 while ((c < groups->prlist_len) && (a > acl->total - acl->negative - 1))
383 switch (CmpInt(acl->entries[a].id, groups->prlist_val[c])) {
388 negrights |= acl->entries[a].rights;
395 *rights = temprights & (~negrights);
400 acl_Initialize(char *version)
402 /* I'm sure we need to do some initialization, I'm just not quite sure what yet! */
403 if (strcmp(version, ACL_VERSION) != 0) {
404 fprintf(stderr, "Wrong version of acl package!\n");
405 fprintf(stderr, "This is version %s, file server passed in %s.\n",
406 ACL_VERSION, version);
408 #ifdef AFS_PTHREAD_ENV
409 assert(pthread_mutex_init(&acl_list_mutex, NULL) == 0);
410 #endif /* AFS_PTHREAD_ENV */
415 acl_IsAMember(afs_int32 aid, prlist *cps)
419 for (i = 0; i < cps->prlist_len; i++)
420 if (cps->prlist_val[i] == aid)
427 AddToList(pflist, elem)
428 struct freeListEntry **pflist;
429 struct freeListEntry *elem;
431 /* Adds elem to the freelist flist; returns 0 */
432 #ifdef AFS_PTHREAD_ENV
433 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
434 #endif /* AFS_PTHREAD_ENV */
435 elem->next = *pflist;
437 #ifdef AFS_PTHREAD_ENV
438 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
439 #endif /* AFS_PTHREAD_ENV */
444 GetFromList(pflist, elem, minsize)
445 struct freeListEntry **pflist;
446 struct freeListEntry **elem;
449 /* 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. */
451 struct freeListEntry *y, *z;
453 #ifdef AFS_PTHREAD_ENV
454 assert(pthread_mutex_lock(&acl_list_mutex) == 0);
455 #endif /* AFS_PTHREAD_ENV */
456 if (*pflist == NULL) {
457 #ifdef AFS_PTHREAD_ENV
458 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
459 #endif /* AFS_PTHREAD_ENV */
462 for (y = *pflist, z = NULL; y != NULL; z = y, y = y->next) {
463 if (y->size >= minsize) {
465 if (z == NULL) { /* pulling off the head */
467 #ifdef AFS_PTHREAD_ENV
468 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
469 #endif /* AFS_PTHREAD_ENV */
473 #ifdef AFS_PTHREAD_ENV
474 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
475 #endif /* AFS_PTHREAD_ENV */
479 #ifdef AFS_PTHREAD_ENV
480 assert(pthread_mutex_unlock(&acl_list_mutex) == 0);
481 #endif /* AFS_PTHREAD_ENV */