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 * Implementation of the ACL and quota-related operations used
12 * by the AFS user account facility.
16 * --------------------- Required definitions ---------------------
18 #include <afsconfig.h>
19 #include <afs/param.h>
25 #include <afs/afsint.h>
26 #include <afs/prs_fs.h>
27 #include <afs/com_err.h>
28 #include <afs/afs_consts.h>
32 #include "uss_common.h"
42 struct AclEntry *pluslist;
43 struct AclEntry *minuslist;
47 struct AclEntry *next;
52 static int PruneList(struct AclEntry **a_aclPP);
55 /*------------------------------------------------------------------------
59 * String comparison with case-folding.
62 * a_str1 : First string.
63 * a_str2 : Second string.
66 * 0 if the two strings match,
70 * Nothing interesting.
74 *------------------------------------------------------------------------*/
77 foldcmp(char *a_str1, char *a_str2)
85 if (t >= 'A' && t <= 'Z')
87 if (u >= 'A' && u <= 'Z')
90 return (1); /*Difference */
92 return (0); /*Match */
97 /*------------------------------------------------------------------------
101 * Convert rights as expressed in a character string to an integer
102 * with the appropriate bits set.
105 * a_rights : String version of access rights.
111 * Nothing interesting.
114 * Exits the program if a badly-formatted rights string is
116 *------------------------------------------------------------------------*/
119 Convert(char *a_rights)
126 if (!strcmp(a_rights, "read"))
127 return (PRSFS_READ | PRSFS_LOOKUP);
129 if (!strcmp(a_rights, "write"))
130 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
131 PRSFS_WRITE | PRSFS_LOCK);
133 if (!strcmp(a_rights, "mail"))
134 return (PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP);
136 if (!strcmp(a_rights, "all"))
137 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
138 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER);
140 if (!strcmp(a_rights, "none"))
143 len = strlen(a_rights);
145 for (i = 0; i < len; i++) {
150 mode |= PRSFS_LOOKUP;
152 mode |= PRSFS_INSERT;
154 mode |= PRSFS_DELETE;
160 mode |= PRSFS_ADMINISTER;
162 printf("%s: Bogus rights character '%c'.\n", uss_whoami, tc);
171 /*------------------------------------------------------------------------
175 * Find the entry with the given name in the passed-in ACL.
178 * a_alist : Internalized ACL to look through.
179 * a_name : Name to find.
182 * Ptr to the ACL entry found, or null pointer if none.
185 * Nothing interesting.
189 *------------------------------------------------------------------------*/
191 static struct AclEntry *
192 FindList(struct AclEntry *a_alist, char *a_name)
196 if (!foldcmp(a_alist->name, a_name))
198 a_alist = a_alist->next;
205 /*------------------------------------------------------------------------
209 * Set the rights for the named entry to the given value, creating
210 * an entry if one does not yet exist.
213 * a_al : Ptr to the internalized ACL.
214 * a_plus : Positive or negative rights?
215 * a_name : Name to look for.
216 * a_rights : Rights to set.
219 * 0 if the two strings match,
223 * Nothing interesting.
227 *------------------------------------------------------------------------*/
230 ChangeList(struct Acl *a_al, afs_int32 a_plus, char *a_name,
234 struct AclEntry *tlist;
236 tlist = (a_plus ? a_al->pluslist : a_al->minuslist);
237 tlist = FindList(tlist, a_name);
240 * Found the item already in the list.
242 tlist->rights = a_rights;
244 a_al->nplus -= PruneList(&a_al->pluslist);
246 a_al->nminus -= PruneList(&a_al->minuslist);
251 * Otherwise, we make a new item and plug in the new data.
253 tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
254 strcpy(tlist->name, a_name);
255 tlist->rights = a_rights;
257 tlist->next = a_al->pluslist;
258 a_al->pluslist = tlist;
261 a_al->nplus -= PruneList(&a_al->pluslist);
263 tlist->next = a_al->minuslist;
264 a_al->minuslist = tlist;
267 a_al->nminus -= PruneList(&a_al->minuslist);
272 /*------------------------------------------------------------------------
276 * Remove all entries whose rights fields are set to zero.
279 * a_aclPP : Ptr to the location of the ACL to purne.
282 * Number of entries pruned off.
285 * Nothing interesting.
289 *------------------------------------------------------------------------*/
292 PruneList(struct AclEntry **a_aclPP)
295 struct AclEntry **lPP;
296 struct AclEntry *tP, *nP;
301 for (tP = *a_aclPP; tP; tP = nP) {
302 if (tP->rights == 0) {
318 /*------------------------------------------------------------------------
322 * Skip chars until we eat a newline.
325 * a_str : String to process.
328 * Ptr to the first char past the newline.
331 * Nothing interesting.
335 *------------------------------------------------------------------------*/
338 SkipLine(char *a_str)
341 while (*a_str != '\n')
349 /*------------------------------------------------------------------------
353 * Create an empty internalized ACL.
359 * Ptr to an initialized and empty internalized ACL.
362 * Nothing interesting.
366 *------------------------------------------------------------------------*/
374 tp = (struct Acl *)malloc(sizeof(struct Acl));
375 tp->nplus = tp->nminus = 0;
376 tp->pluslist = tp->minuslist = 0;
382 /*------------------------------------------------------------------------
386 * Given an externalized ACL (i.e., in string format), convert it
387 * into its internalized form.
390 * a_str : Ptr to Externalized ACL.
393 * Ptr to the equivalent internalized ACL.
396 * Nothing interesting.
400 *------------------------------------------------------------------------*/
403 ParseAcl(char *a_str)
406 int nplus, nminus, i, trights;
408 struct AclEntry *first, *last, *tl;
412 * Pull out the number of positive & negative entries in the externalized
415 sscanf(a_str, "%d", &nplus);
416 a_str = SkipLine(a_str);
417 sscanf(a_str, "%d", &nminus);
418 a_str = SkipLine(a_str);
421 * Allocate and initialize the first entry.
423 ta = (struct Acl *)malloc(sizeof(struct Acl));
428 * Translate the positive entries.
432 for (i = 0; i < nplus; i++) {
433 sscanf(a_str, "%100s %d", tname, &trights);
434 a_str = SkipLine(a_str);
435 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
438 strcpy(tl->name, tname);
439 tl->rights = trights;
445 ta->pluslist = first;
448 * Translate the negative entries.
452 for (i = 0; i < nminus; i++) {
453 sscanf(a_str, "%100s %d", tname, &trights);
454 a_str = SkipLine(a_str);
455 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
458 strcpy(tl->name, tname);
459 tl->rights = trights;
465 ta->minuslist = first;
472 /*------------------------------------------------------------------------
476 * Given an internalized ACL, convert it to its externalized form,
477 * namely a character string.
480 * a_acl : Internalized ACL to externalize.
483 * Ptr to the externalized version.
486 * Nothing interesting.
490 *------------------------------------------------------------------------*/
493 AclToString(struct Acl *a_acl)
496 static char mydata[AFS_PIOCTL_MAXSIZE];
497 char tstring[AFS_PIOCTL_MAXSIZE];
501 * Print out the number of positive & negative entries on one line.
503 sprintf(mydata, "%d\n%d\n", a_acl->nplus, a_acl->nminus);
506 * Externalize the positive list.
508 for (tp = a_acl->pluslist; tp; tp = tp->next) {
509 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
510 strcat(mydata, tstring);
514 * Externalize the negative list.
516 for (tp = a_acl->minuslist; tp; tp = tp->next) {
517 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
518 strcat(mydata, tstring);
525 /*------------------------------------------------------------------------
526 * static uss_acl_SetAccess
529 * ACL comes in as a single string, prefixed with the pathname to
530 * which the ACL is applied. The a_clear argument, if set, causes
531 * us to act like sac instead of sa.
535 *------------------------------------------------------------------------*/
538 uss_acl_SetAccess(char *a_access, int a_clear, int a_negative)
539 { /*uss_acl_SetAccess */
543 static char rn[] = "uss_acl_SetAccess";
546 char *externalizedACL;
549 char tmp_str[AFS_PIOCTL_MAXSIZE];
550 char path_field[AFS_PIOCTL_MAXSIZE], user_field[64], rights_field[64], *tp;
556 * Pull out the pathname from our argument.
558 tp = uss_common_FieldCp(path_field, a_access, ' ', sizeof(path_field),
561 fprintf(stderr, "%s: * Pathname field too long (max is %" AFS_SIZET_FMT " chars)\n",
562 uss_whoami, sizeof(path_field));
567 * Ask the Cache Manager to give us the externalized ACL for the
570 code = uss_fs_GetACL(path_field, tmp_str, AFS_PIOCTL_MAXSIZE);
572 afs_com_err(uss_whoami, code, "while getting access list for %s",
575 printf("%s: Error code from uss_fs_GetACL %d, errno %d\n", rn, code,
577 #endif /* USS_ACL_DB */
582 printf("%s: ACL for pathname '%s' is: '%s'\n", rn, path_field,
584 #endif /* USS_ACL_DB */
587 * Generate the proper internalized ACL.
592 ta = ParseAcl(tmp_str);
595 * For each given entry, pull out the information and alter the
596 * internalized ACL to reflect it.
598 while (*tp != '\0') {
599 tp = uss_common_FieldCp(user_field, tp, ' ', 64, &overflow);
601 fprintf(stderr, "%s: * User field too long (max is 64 chars)\n",
606 printf("%s: Missing second half of user/access pair.\n",
610 tp = uss_common_FieldCp(rights_field, tp, ' ', 64, &overflow);
612 fprintf(stderr, "%s: * Rights field too long (max is 64 chars)\n",
616 rights = Convert(rights_field);
617 ChangeList(ta, plusp, user_field, rights);
621 * Externalize the fully-processed internal ACL, then pass it back
622 * to the Cache Manager.
624 externalizedACL = AclToString(ta);
626 uss_fs_SetACL(path_field, externalizedACL,
627 strlen(externalizedACL) + 1);
630 printf("%s: uss_fs_SetACL() failed, code is %d, errno is %d\n", rn,
632 #endif /* USS_ACL_DB */
633 if (errno == EINVAL) {
634 printf("Can't set ACL for directory '%s' to '%s'\n", path_field,
636 printf("Invalid argument, possible reasons include:\n");
637 printf("\t1. File not in AFS, or\n");
638 printf("\t2. Too many users on the ACL, or\n");
639 printf("\t3. Non-existent user or group on ACL.\n");
642 afs_com_err(uss_whoami, code, "while setting the access list");
648 } /*uss_acl_SetAccess */
651 /*------------------------------------------------------------------------
652 * static us_acl_SetDiskQuota
655 * Nothing interesting.
659 *------------------------------------------------------------------------*/
662 uss_acl_SetDiskQuota(char *a_path, int a_q)
663 { /*uss_acl_SetDiskQuota */
667 static char rn[] = "uss_acl_SetDiskQuota";
669 uss_VolumeStatus_t *status;
670 char *name, *motd, *offmsg;
672 char tmp_str[AFS_PIOCTL_MAXSIZE];
676 "Setting disk quota on volume mounted at '%s' to %d blocks\n",
679 status = (uss_VolumeStatus_t *) tmp_str;
680 status->MinQuota = status->MaxQuota = -1;
681 name = motd = offmsg = NULL;
682 status->MaxQuota = a_q;
684 input = (char *)status + sizeof(*status);
689 code = uss_fs_SetVolStat(a_path, tmp_str, sizeof(*status) + 3);
691 afs_com_err(uss_whoami, code, "while setting disk quota");
693 printf("%s: uss_fs_SetVolStat() error code: %d, errno is %d\n", rn,
695 #endif /* USS_ACL_DB */
701 } /*uss_acl_SetDiskQuota */
704 /*-----------------------------------------------------------------------
705 * EXPORTED uss_acl_CleanUp
708 * The uss_currentDir variable contains directories touched by the
713 *------------------------------------------------------------------------*/
716 uss_acl_CleanUp(void)
717 { /*uss_acl_CleanUp */
719 struct uss_subdir *t, *old_t = NULL;
720 char tmp_str[uss_MAX_SIZE];
723 * Restore the ACL for each directory created for our caller to its
724 * original setting. The uss_AccountCreator's access was (potentially)
725 * amplified to full rights - any excess ability must now be removed.
727 for (t = uss_currentDir; t != NULL; t = t->previous) {
728 sprintf(tmp_str, "%s %s", t->path, t->finalACL);
730 fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
732 uss_acl_SetAccess(tmp_str, 1, 0);
734 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
740 } /*Remove caller from user directory ACL */
746 * Return successfully.
750 } /*uss_acl_CleanUp */