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>
24 #include "uss_common.h"
27 #include <sys/socket.h>
28 #include <sys/types.h>
42 #include <afs/afsint.h>
43 #include <afs/prs_fs.h>
44 #include <afs/com_err.h>
54 struct AclEntry *pluslist;
55 struct AclEntry *minuslist;
59 struct AclEntry *next;
64 static int PruneList();
67 /*------------------------------------------------------------------------
71 * String comparison with case-folding.
74 * a_str1 : First string.
75 * a_str2 : Second string.
78 * 0 if the two strings match,
82 * Nothing interesting.
86 *------------------------------------------------------------------------*/
88 static foldcmp(a_str1, a_str2)
89 register char *a_str1;
90 register char *a_str2;
99 if (t >= 'A' && t <= 'Z') t += 0x20;
100 if (u >= 'A' && u <= 'Z') u += 0x20;
102 return(1); /*Difference*/
109 /*------------------------------------------------------------------------
113 * Convert rights as expressed in a character string to an integer
114 * with the appropriate bits set.
117 * a_rights : String version of access rights.
123 * Nothing interesting.
126 * Exits the program if a badly-formatted rights string is
128 *------------------------------------------------------------------------*/
130 static afs_int32 Convert(a_rights)
131 register char *a_rights;
139 if (!strcmp(a_rights,"read"))
140 return(PRSFS_READ | PRSFS_LOOKUP);
142 if (!strcmp(a_rights, "write"))
150 if (!strcmp(a_rights, "mail"))
155 if (!strcmp(a_rights, "all"))
164 if (!strcmp(a_rights, "none"))
167 len = strlen(a_rights);
169 for (i = 0; i < len; i++) {
171 if (tc == 'r') mode |= PRSFS_READ;
172 else if (tc == 'l') mode |= PRSFS_LOOKUP;
173 else if (tc == 'i') mode |= PRSFS_INSERT;
174 else if (tc == 'd') mode |= PRSFS_DELETE;
175 else if (tc == 'w') mode |= PRSFS_WRITE;
176 else if (tc == 'k') mode |= PRSFS_LOCK;
177 else if (tc == 'a') mode |= PRSFS_ADMINISTER;
179 printf("%s: Bogus rights character '%c'.\n",
189 /*------------------------------------------------------------------------
193 * Find the entry with the given name in the passed-in ACL.
196 * a_alist : Internalized ACL to look through.
197 * a_name : Name to find.
200 * Ptr to the ACL entry found, or null pointer if none.
203 * Nothing interesting.
207 *------------------------------------------------------------------------*/
209 static struct AclEntry *FindList(a_alist, a_name)
210 register struct AclEntry *a_alist;
216 if (!foldcmp(a_alist->name, a_name))
218 a_alist = a_alist->next;
225 /*------------------------------------------------------------------------
229 * Set the rights for the named entry to the given value, creating
230 * an entry if one does not yet exist.
233 * a_al : Ptr to the internalized ACL.
234 * a_plus : Positive or negative rights?
235 * a_name : Name to look for.
236 * a_rights : Rights to set.
239 * 0 if the two strings match,
243 * Nothing interesting.
247 *------------------------------------------------------------------------*/
249 static void ChangeList (a_al, a_plus, a_name, a_rights)
257 struct AclEntry *tlist;
259 tlist = (a_plus ? a_al->pluslist : a_al->minuslist);
260 tlist = FindList(tlist, a_name);
263 * Found the item already in the list.
265 tlist->rights = a_rights;
267 a_al->nplus -= PruneList(&a_al->pluslist);
269 a_al->nminus -= PruneList(&a_al->minuslist);
274 * Otherwise, we make a new item and plug in the new data.
276 tlist = (struct AclEntry *) malloc(sizeof(struct AclEntry));
277 strcpy(tlist->name, a_name);
278 tlist->rights = a_rights;
280 tlist->next = a_al->pluslist;
281 a_al->pluslist = tlist;
284 a_al->nplus -= PruneList(&a_al->pluslist);
287 tlist->next = a_al->minuslist;
288 a_al->minuslist = tlist;
291 a_al->nminus -= PruneList(&a_al->minuslist);
296 /*------------------------------------------------------------------------
300 * Remove all entries whose rights fields are set to zero.
303 * a_aclPP : Ptr to the location of the ACL to purne.
306 * Number of entries pruned off.
309 * Nothing interesting.
313 *------------------------------------------------------------------------*/
315 static int PruneList (a_aclPP)
316 struct AclEntry **a_aclPP;
320 struct AclEntry **lPP;
321 struct AclEntry *tP, *nP;
326 for (tP = *a_aclPP; tP; tP = nP) {
327 if (tP->rights == 0) {
344 /*------------------------------------------------------------------------
348 * Skip chars until we eat a newline.
351 * a_str : String to process.
354 * Ptr to the first char past the newline.
357 * Nothing interesting.
361 *------------------------------------------------------------------------*/
363 static char *SkipLine(a_str)
364 register char *a_str;
368 while (*a_str !='\n') a_str++;
375 /*------------------------------------------------------------------------
379 * Create an empty internalized ACL.
385 * Ptr to an initialized and empty internalized ACL.
388 * Nothing interesting.
392 *------------------------------------------------------------------------*/
394 static struct Acl *EmptyAcl()
398 register struct Acl *tp;
400 tp = (struct Acl *) malloc(sizeof (struct Acl));
401 tp->nplus = tp->nminus = 0;
402 tp->pluslist = tp->minuslist = 0;
408 /*------------------------------------------------------------------------
412 * Given an externalized ACL (i.e., in string format), convert it
413 * into its internalized form.
416 * a_str : Ptr to Externalized ACL.
419 * Ptr to the equivalent internalized ACL.
422 * Nothing interesting.
426 *------------------------------------------------------------------------*/
428 static struct Acl *ParseAcl(a_str)
433 int nplus, nminus, i, trights;
435 struct AclEntry *first, *last, *tl;
439 * Pull out the number of positive & negative entries in the externalized
442 sscanf(a_str, "%d", &nplus);
443 a_str = SkipLine(a_str);
444 sscanf(a_str, "%d", &nminus);
445 a_str = SkipLine(a_str);
448 * Allocate and initialize the first entry.
450 ta = (struct Acl *) malloc(sizeof (struct Acl));
455 * Translate the positive entries.
459 for(i = 0; i < nplus; 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->pluslist = first;
475 * Translate the negative entries.
479 for (i = 0; i < nminus; i++) {
480 sscanf(a_str, "%100s %d", tname, &trights);
481 a_str = SkipLine(a_str);
482 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
485 strcpy(tl->name, tname);
486 tl->rights = trights;
492 ta->minuslist = first;
499 /*------------------------------------------------------------------------
503 * Given an internalized ACL, convert it to its externalized form,
504 * namely a character string.
507 * a_acl : Internalized ACL to externalize.
510 * Ptr to the externalized version.
513 * Nothing interesting.
517 *------------------------------------------------------------------------*/
519 static char *AclToString(a_acl)
524 static char mydata[MAXSIZE];
525 char tstring[MAXSIZE];
529 * Print out the number of positive & negative entries on one line.
531 sprintf(mydata, "%d\n%d\n", a_acl->nplus, a_acl->nminus);
534 * Externalize the positive list.
536 for (tp = a_acl->pluslist; tp; tp = tp->next) {
537 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
538 strcat(mydata, tstring);
542 * Externalize the negative list.
544 for (tp = a_acl->minuslist; tp; tp = tp->next) {
545 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
546 strcat(mydata, tstring);
553 /*------------------------------------------------------------------------
554 * static uss_acl_SetAccess
557 * ACL comes in as a single string, prefixed with the pathname to
558 * which the ACL is applied. The a_clear argument, if set, causes
559 * us to act like sac instead of sa.
563 *------------------------------------------------------------------------*/
565 afs_int32 uss_acl_SetAccess(a_access, a_clear, a_negative)
570 { /*uss_acl_SetAccess*/
572 register afs_int32 code;
573 static char rn[] = "uss_acl_SetAccess";
575 char *externalizedACL;
578 char tmp_str[MAXSIZE];
579 char path_field[MAXSIZE], user_field[64], rights_field[64], *tp;
585 * Pull out the pathname from our argument.
587 tp = uss_common_FieldCp(path_field, a_access, ' ', sizeof(path_field),
591 "%s: * Pathname field too long (max is %d chars)\n",
592 uss_whoami, sizeof(path_field));
597 * Ask the Cache Manager to give us the externalized ACL for the
600 code = uss_fs_GetACL(path_field, tmp_str, MAXSIZE);
602 com_err(uss_whoami, code,
603 "while getting access list for %s", path_field);
605 printf("%s: Error code from uss_fs_GetACL %d, errno %d\n",
607 #endif /* USS_ACL_DB */
612 printf("%s: ACL for pathname '%s' is: '%s'\n",
613 rn, path_field, tmp_str);
614 #endif /* USS_ACL_DB */
617 * Generate the proper internalized ACL.
622 ta = ParseAcl(tmp_str);
625 * For each given entry, pull out the information and alter the
626 * internalized ACL to reflect it.
629 tp = uss_common_FieldCp(user_field, tp, ' ', 64, &overflow);
632 "%s: * User field too long (max is 64 chars)\n",
637 printf("%s: Missing second half of user/access pair.\n",
641 tp = uss_common_FieldCp(rights_field, tp, ' ', 64, &overflow);
644 "%s: * Rights field too long (max is 64 chars)\n",
648 rights = Convert(rights_field);
649 ChangeList(ta, plusp, user_field, rights);
653 * Externalize the fully-processed internal ACL, then pass it back
654 * to the Cache Manager.
656 externalizedACL = AclToString(ta);
657 code = uss_fs_SetACL(path_field, externalizedACL,
658 strlen(externalizedACL)+1);
661 printf("%s: uss_fs_SetACL() failed, code is %d, errno is %d\n",
663 #endif /* USS_ACL_DB */
664 if (errno == EINVAL) {
665 printf("Can't set ACL for directory '%s' to '%s'\n",
666 path_field, externalizedACL);
667 printf("Invalid argument, possible reasons include:\n");
668 printf("\t1. File not in AFS, or\n");
669 printf("\t2. Too many users on the ACL, or\n");
670 printf("\t3. Non-existent user or group on ACL.\n");
674 com_err(uss_whoami, code, "while setting the access list");
680 } /*uss_acl_SetAccess*/
683 /*------------------------------------------------------------------------
684 * static us_acl_SetDiskQuota
687 * Nothing interesting.
691 *------------------------------------------------------------------------*/
693 afs_int32 uss_acl_SetDiskQuota(a_path, a_q)
697 { /*uss_acl_SetDiskQuota*/
699 register afs_int32 code;
700 static char rn[] = "uss_acl_SetDiskQuota";
701 uss_VolumeStatus_t *status;
702 char *name, *motd, *offmsg;
704 char tmp_str[MAXSIZE];
708 "Setting disk quota on volume mounted at '%s' to %d blocks\n",
711 status = (uss_VolumeStatus_t *)tmp_str;
712 status->MinQuota = status->MaxQuota = -1;
713 name = motd = offmsg = NULL;
714 status->MaxQuota = a_q;
716 input = (char *)status + sizeof(*status);
721 code = uss_fs_SetVolStat(a_path, tmp_str, sizeof(*status)+3);
723 com_err(uss_whoami, code, "while setting disk quota");
725 printf("%s: uss_fs_SetVolStat() error code: %d, errno is %d\n",
727 #endif /* USS_ACL_DB */
733 } /*uss_acl_SetDiskQuota*/
736 /*-----------------------------------------------------------------------
737 * EXPORTED uss_acl_CleanUp
740 * The uss_currentDir variable contains directories touched by the
745 *------------------------------------------------------------------------*/
747 afs_int32 uss_acl_CleanUp()
749 { /*uss_acl_CleanUp*/
751 static char rn[] = "uss_acl_CleanUp";
752 struct uss_subdir *t, *old_t = NULL;
753 char tmp_str[uss_MAX_SIZE];
756 * Restore the ACL for each directory created for our caller to its
757 * original setting. The uss_AccountCreator's access was (potentially)
758 * amplified to full rights - any excess ability must now be removed.
760 for (t = uss_currentDir; t != NULL; t = t->previous) {
761 sprintf(tmp_str, "%s %s", t->path, t->finalACL);
763 fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
765 uss_acl_SetAccess(tmp_str, 1, 0);
768 "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
774 } /*Remove caller from user directory ACL*/
780 * Return successfully.
784 } /*uss_acl_CleanUp*/