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 "uss_common.h"
28 #include <sys/socket.h>
29 #include <sys/types.h>
37 #include <afs/afsint.h>
38 #include <afs/prs_fs.h>
39 #include <afs/com_err.h>
49 struct AclEntry *pluslist;
50 struct AclEntry *minuslist;
54 struct AclEntry *next;
59 static int PruneList(struct AclEntry **a_aclPP);
62 /*------------------------------------------------------------------------
66 * String comparison with case-folding.
69 * a_str1 : First string.
70 * a_str2 : Second string.
73 * 0 if the two strings match,
77 * Nothing interesting.
81 *------------------------------------------------------------------------*/
84 foldcmp(register char *a_str1, register char *a_str2)
92 if (t >= 'A' && t <= 'Z')
94 if (u >= 'A' && u <= 'Z')
97 return (1); /*Difference */
99 return (0); /*Match */
104 /*------------------------------------------------------------------------
108 * Convert rights as expressed in a character string to an integer
109 * with the appropriate bits set.
112 * a_rights : String version of access rights.
118 * Nothing interesting.
121 * Exits the program if a badly-formatted rights string is
123 *------------------------------------------------------------------------*/
126 Convert(register char *a_rights)
133 if (!strcmp(a_rights, "read"))
134 return (PRSFS_READ | PRSFS_LOOKUP);
136 if (!strcmp(a_rights, "write"))
137 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
138 PRSFS_WRITE | PRSFS_LOCK);
140 if (!strcmp(a_rights, "mail"))
141 return (PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP);
143 if (!strcmp(a_rights, "all"))
144 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
145 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER);
147 if (!strcmp(a_rights, "none"))
150 len = strlen(a_rights);
152 for (i = 0; i < len; i++) {
157 mode |= PRSFS_LOOKUP;
159 mode |= PRSFS_INSERT;
161 mode |= PRSFS_DELETE;
167 mode |= PRSFS_ADMINISTER;
169 printf("%s: Bogus rights character '%c'.\n", uss_whoami, tc);
178 /*------------------------------------------------------------------------
182 * Find the entry with the given name in the passed-in ACL.
185 * a_alist : Internalized ACL to look through.
186 * a_name : Name to find.
189 * Ptr to the ACL entry found, or null pointer if none.
192 * Nothing interesting.
196 *------------------------------------------------------------------------*/
198 static struct AclEntry *
199 FindList(register struct AclEntry *a_alist, char *a_name)
203 if (!foldcmp(a_alist->name, a_name))
205 a_alist = a_alist->next;
212 /*------------------------------------------------------------------------
216 * Set the rights for the named entry to the given value, creating
217 * an entry if one does not yet exist.
220 * a_al : Ptr to the internalized ACL.
221 * a_plus : Positive or negative rights?
222 * a_name : Name to look for.
223 * a_rights : Rights to set.
226 * 0 if the two strings match,
230 * Nothing interesting.
234 *------------------------------------------------------------------------*/
237 ChangeList(struct Acl *a_al, afs_int32 a_plus, char *a_name,
241 struct AclEntry *tlist;
243 tlist = (a_plus ? a_al->pluslist : a_al->minuslist);
244 tlist = FindList(tlist, a_name);
247 * Found the item already in the list.
249 tlist->rights = a_rights;
251 a_al->nplus -= PruneList(&a_al->pluslist);
253 a_al->nminus -= PruneList(&a_al->minuslist);
258 * Otherwise, we make a new item and plug in the new data.
260 tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
261 strcpy(tlist->name, a_name);
262 tlist->rights = a_rights;
264 tlist->next = a_al->pluslist;
265 a_al->pluslist = tlist;
268 a_al->nplus -= PruneList(&a_al->pluslist);
270 tlist->next = a_al->minuslist;
271 a_al->minuslist = tlist;
274 a_al->nminus -= PruneList(&a_al->minuslist);
279 /*------------------------------------------------------------------------
283 * Remove all entries whose rights fields are set to zero.
286 * a_aclPP : Ptr to the location of the ACL to purne.
289 * Number of entries pruned off.
292 * Nothing interesting.
296 *------------------------------------------------------------------------*/
299 PruneList(struct AclEntry **a_aclPP)
302 struct AclEntry **lPP;
303 struct AclEntry *tP, *nP;
308 for (tP = *a_aclPP; tP; tP = nP) {
309 if (tP->rights == 0) {
325 /*------------------------------------------------------------------------
329 * Skip chars until we eat a newline.
332 * a_str : String to process.
335 * Ptr to the first char past the newline.
338 * Nothing interesting.
342 *------------------------------------------------------------------------*/
345 SkipLine(register char *a_str)
348 while (*a_str != '\n')
356 /*------------------------------------------------------------------------
360 * Create an empty internalized ACL.
366 * Ptr to an initialized and empty internalized ACL.
369 * Nothing interesting.
373 *------------------------------------------------------------------------*/
379 register struct Acl *tp;
381 tp = (struct Acl *)malloc(sizeof(struct Acl));
382 tp->nplus = tp->nminus = 0;
383 tp->pluslist = tp->minuslist = 0;
389 /*------------------------------------------------------------------------
393 * Given an externalized ACL (i.e., in string format), convert it
394 * into its internalized form.
397 * a_str : Ptr to Externalized ACL.
400 * Ptr to the equivalent internalized ACL.
403 * Nothing interesting.
407 *------------------------------------------------------------------------*/
410 ParseAcl(char *a_str)
413 int nplus, nminus, i, trights;
415 struct AclEntry *first, *last, *tl;
419 * Pull out the number of positive & negative entries in the externalized
422 sscanf(a_str, "%d", &nplus);
423 a_str = SkipLine(a_str);
424 sscanf(a_str, "%d", &nminus);
425 a_str = SkipLine(a_str);
428 * Allocate and initialize the first entry.
430 ta = (struct Acl *)malloc(sizeof(struct Acl));
435 * Translate the positive entries.
439 for (i = 0; i < nplus; i++) {
440 sscanf(a_str, "%100s %d", tname, &trights);
441 a_str = SkipLine(a_str);
442 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
445 strcpy(tl->name, tname);
446 tl->rights = trights;
452 ta->pluslist = first;
455 * Translate the negative entries.
459 for (i = 0; i < nminus; i++) {
460 sscanf(a_str, "%100s %d", tname, &trights);
461 a_str = SkipLine(a_str);
462 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
465 strcpy(tl->name, tname);
466 tl->rights = trights;
472 ta->minuslist = first;
479 /*------------------------------------------------------------------------
483 * Given an internalized ACL, convert it to its externalized form,
484 * namely a character string.
487 * a_acl : Internalized ACL to externalize.
490 * Ptr to the externalized version.
493 * Nothing interesting.
497 *------------------------------------------------------------------------*/
500 AclToString(struct Acl *a_acl)
503 static char mydata[MAXSIZE];
504 char tstring[MAXSIZE];
508 * Print out the number of positive & negative entries on one line.
510 sprintf(mydata, "%d\n%d\n", a_acl->nplus, a_acl->nminus);
513 * Externalize the positive list.
515 for (tp = a_acl->pluslist; tp; tp = tp->next) {
516 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
517 strcat(mydata, tstring);
521 * Externalize the negative list.
523 for (tp = a_acl->minuslist; tp; tp = tp->next) {
524 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
525 strcat(mydata, tstring);
532 /*------------------------------------------------------------------------
533 * static uss_acl_SetAccess
536 * ACL comes in as a single string, prefixed with the pathname to
537 * which the ACL is applied. The a_clear argument, if set, causes
538 * us to act like sac instead of sa.
542 *------------------------------------------------------------------------*/
545 uss_acl_SetAccess(char *a_access, int a_clear, int a_negative)
546 { /*uss_acl_SetAccess */
548 register afs_int32 code;
550 static char rn[] = "uss_acl_SetAccess";
553 char *externalizedACL;
556 char tmp_str[MAXSIZE];
557 char path_field[MAXSIZE], user_field[64], rights_field[64], *tp;
563 * Pull out the pathname from our argument.
565 tp = uss_common_FieldCp(path_field, a_access, ' ', sizeof(path_field),
568 fprintf(stderr, "%s: * Pathname field too long (max is %lu chars)\n",
569 uss_whoami, sizeof(path_field));
574 * Ask the Cache Manager to give us the externalized ACL for the
577 code = uss_fs_GetACL(path_field, tmp_str, MAXSIZE);
579 afs_com_err(uss_whoami, code, "while getting access list for %s",
582 printf("%s: Error code from uss_fs_GetACL %d, errno %d\n", rn, code,
584 #endif /* USS_ACL_DB */
589 printf("%s: ACL for pathname '%s' is: '%s'\n", rn, path_field,
591 #endif /* USS_ACL_DB */
594 * Generate the proper internalized ACL.
599 ta = ParseAcl(tmp_str);
602 * For each given entry, pull out the information and alter the
603 * internalized ACL to reflect it.
605 while (*tp != '\0') {
606 tp = uss_common_FieldCp(user_field, tp, ' ', 64, &overflow);
608 fprintf(stderr, "%s: * User field too long (max is 64 chars)\n",
613 printf("%s: Missing second half of user/access pair.\n",
617 tp = uss_common_FieldCp(rights_field, tp, ' ', 64, &overflow);
619 fprintf(stderr, "%s: * Rights field too long (max is 64 chars)\n",
623 rights = Convert(rights_field);
624 ChangeList(ta, plusp, user_field, rights);
628 * Externalize the fully-processed internal ACL, then pass it back
629 * to the Cache Manager.
631 externalizedACL = AclToString(ta);
633 uss_fs_SetACL(path_field, externalizedACL,
634 strlen(externalizedACL) + 1);
637 printf("%s: uss_fs_SetACL() failed, code is %d, errno is %d\n", rn,
639 #endif /* USS_ACL_DB */
640 if (errno == EINVAL) {
641 printf("Can't set ACL for directory '%s' to '%s'\n", path_field,
643 printf("Invalid argument, possible reasons include:\n");
644 printf("\t1. File not in AFS, or\n");
645 printf("\t2. Too many users on the ACL, or\n");
646 printf("\t3. Non-existent user or group on ACL.\n");
649 afs_com_err(uss_whoami, code, "while setting the access list");
655 } /*uss_acl_SetAccess */
658 /*------------------------------------------------------------------------
659 * static us_acl_SetDiskQuota
662 * Nothing interesting.
666 *------------------------------------------------------------------------*/
669 uss_acl_SetDiskQuota(char *a_path, int a_q)
670 { /*uss_acl_SetDiskQuota */
672 register afs_int32 code;
674 static char rn[] = "uss_acl_SetDiskQuota";
676 uss_VolumeStatus_t *status;
677 char *name, *motd, *offmsg;
679 char tmp_str[MAXSIZE];
683 "Setting disk quota on volume mounted at '%s' to %d blocks\n",
686 status = (uss_VolumeStatus_t *) tmp_str;
687 status->MinQuota = status->MaxQuota = -1;
688 name = motd = offmsg = NULL;
689 status->MaxQuota = a_q;
691 input = (char *)status + sizeof(*status);
696 code = uss_fs_SetVolStat(a_path, tmp_str, sizeof(*status) + 3);
698 afs_com_err(uss_whoami, code, "while setting disk quota");
700 printf("%s: uss_fs_SetVolStat() error code: %d, errno is %d\n", rn,
702 #endif /* USS_ACL_DB */
708 } /*uss_acl_SetDiskQuota */
711 /*-----------------------------------------------------------------------
712 * EXPORTED uss_acl_CleanUp
715 * The uss_currentDir variable contains directories touched by the
720 *------------------------------------------------------------------------*/
723 uss_acl_CleanUp(void)
724 { /*uss_acl_CleanUp */
726 struct uss_subdir *t, *old_t = NULL;
727 char tmp_str[uss_MAX_SIZE];
730 * Restore the ACL for each directory created for our caller to its
731 * original setting. The uss_AccountCreator's access was (potentially)
732 * amplified to full rights - any excess ability must now be removed.
734 for (t = uss_currentDir; t != NULL; t = t->previous) {
735 sprintf(tmp_str, "%s %s", t->path, t->finalACL);
737 fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
739 uss_acl_SetAccess(tmp_str, 1, 0);
741 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
747 } /*Remove caller from user directory ACL */
753 * Return successfully.
757 } /*uss_acl_CleanUp */