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>
23 #include "uss_common.h"
26 #include <sys/socket.h>
27 #include <sys/types.h>
35 #include <afs/afsint.h>
36 #include <afs/prs_fs.h>
37 #include <afs/com_err.h>
38 #include <afs/afs_consts.h>
47 struct AclEntry *pluslist;
48 struct AclEntry *minuslist;
52 struct AclEntry *next;
57 static int PruneList(struct AclEntry **a_aclPP);
60 /*------------------------------------------------------------------------
64 * String comparison with case-folding.
67 * a_str1 : First string.
68 * a_str2 : Second string.
71 * 0 if the two strings match,
75 * Nothing interesting.
79 *------------------------------------------------------------------------*/
82 foldcmp(register char *a_str1, register char *a_str2)
90 if (t >= 'A' && t <= 'Z')
92 if (u >= 'A' && u <= 'Z')
95 return (1); /*Difference */
97 return (0); /*Match */
102 /*------------------------------------------------------------------------
106 * Convert rights as expressed in a character string to an integer
107 * with the appropriate bits set.
110 * a_rights : String version of access rights.
116 * Nothing interesting.
119 * Exits the program if a badly-formatted rights string is
121 *------------------------------------------------------------------------*/
124 Convert(register char *a_rights)
131 if (!strcmp(a_rights, "read"))
132 return (PRSFS_READ | PRSFS_LOOKUP);
134 if (!strcmp(a_rights, "write"))
135 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
136 PRSFS_WRITE | PRSFS_LOCK);
138 if (!strcmp(a_rights, "mail"))
139 return (PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP);
141 if (!strcmp(a_rights, "all"))
142 return (PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
143 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER);
145 if (!strcmp(a_rights, "none"))
148 len = strlen(a_rights);
150 for (i = 0; i < len; i++) {
155 mode |= PRSFS_LOOKUP;
157 mode |= PRSFS_INSERT;
159 mode |= PRSFS_DELETE;
165 mode |= PRSFS_ADMINISTER;
167 printf("%s: Bogus rights character '%c'.\n", uss_whoami, tc);
176 /*------------------------------------------------------------------------
180 * Find the entry with the given name in the passed-in ACL.
183 * a_alist : Internalized ACL to look through.
184 * a_name : Name to find.
187 * Ptr to the ACL entry found, or null pointer if none.
190 * Nothing interesting.
194 *------------------------------------------------------------------------*/
196 static struct AclEntry *
197 FindList(register struct AclEntry *a_alist, char *a_name)
201 if (!foldcmp(a_alist->name, a_name))
203 a_alist = a_alist->next;
210 /*------------------------------------------------------------------------
214 * Set the rights for the named entry to the given value, creating
215 * an entry if one does not yet exist.
218 * a_al : Ptr to the internalized ACL.
219 * a_plus : Positive or negative rights?
220 * a_name : Name to look for.
221 * a_rights : Rights to set.
224 * 0 if the two strings match,
228 * Nothing interesting.
232 *------------------------------------------------------------------------*/
235 ChangeList(struct Acl *a_al, afs_int32 a_plus, char *a_name,
239 struct AclEntry *tlist;
241 tlist = (a_plus ? a_al->pluslist : a_al->minuslist);
242 tlist = FindList(tlist, a_name);
245 * Found the item already in the list.
247 tlist->rights = a_rights;
249 a_al->nplus -= PruneList(&a_al->pluslist);
251 a_al->nminus -= PruneList(&a_al->minuslist);
256 * Otherwise, we make a new item and plug in the new data.
258 tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
259 strcpy(tlist->name, a_name);
260 tlist->rights = a_rights;
262 tlist->next = a_al->pluslist;
263 a_al->pluslist = tlist;
266 a_al->nplus -= PruneList(&a_al->pluslist);
268 tlist->next = a_al->minuslist;
269 a_al->minuslist = tlist;
272 a_al->nminus -= PruneList(&a_al->minuslist);
277 /*------------------------------------------------------------------------
281 * Remove all entries whose rights fields are set to zero.
284 * a_aclPP : Ptr to the location of the ACL to purne.
287 * Number of entries pruned off.
290 * Nothing interesting.
294 *------------------------------------------------------------------------*/
297 PruneList(struct AclEntry **a_aclPP)
300 struct AclEntry **lPP;
301 struct AclEntry *tP, *nP;
306 for (tP = *a_aclPP; tP; tP = nP) {
307 if (tP->rights == 0) {
323 /*------------------------------------------------------------------------
327 * Skip chars until we eat a newline.
330 * a_str : String to process.
333 * Ptr to the first char past the newline.
336 * Nothing interesting.
340 *------------------------------------------------------------------------*/
343 SkipLine(register char *a_str)
346 while (*a_str != '\n')
354 /*------------------------------------------------------------------------
358 * Create an empty internalized ACL.
364 * Ptr to an initialized and empty internalized ACL.
367 * Nothing interesting.
371 *------------------------------------------------------------------------*/
377 register struct Acl *tp;
379 tp = (struct Acl *)malloc(sizeof(struct Acl));
380 tp->nplus = tp->nminus = 0;
381 tp->pluslist = tp->minuslist = 0;
387 /*------------------------------------------------------------------------
391 * Given an externalized ACL (i.e., in string format), convert it
392 * into its internalized form.
395 * a_str : Ptr to Externalized ACL.
398 * Ptr to the equivalent internalized ACL.
401 * Nothing interesting.
405 *------------------------------------------------------------------------*/
408 ParseAcl(char *a_str)
411 int nplus, nminus, i, trights;
413 struct AclEntry *first, *last, *tl;
417 * Pull out the number of positive & negative entries in the externalized
420 sscanf(a_str, "%d", &nplus);
421 a_str = SkipLine(a_str);
422 sscanf(a_str, "%d", &nminus);
423 a_str = SkipLine(a_str);
426 * Allocate and initialize the first entry.
428 ta = (struct Acl *)malloc(sizeof(struct Acl));
433 * Translate the positive entries.
437 for (i = 0; i < nplus; i++) {
438 sscanf(a_str, "%100s %d", tname, &trights);
439 a_str = SkipLine(a_str);
440 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
443 strcpy(tl->name, tname);
444 tl->rights = trights;
450 ta->pluslist = first;
453 * Translate the negative entries.
457 for (i = 0; i < nminus; i++) {
458 sscanf(a_str, "%100s %d", tname, &trights);
459 a_str = SkipLine(a_str);
460 tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
463 strcpy(tl->name, tname);
464 tl->rights = trights;
470 ta->minuslist = first;
477 /*------------------------------------------------------------------------
481 * Given an internalized ACL, convert it to its externalized form,
482 * namely a character string.
485 * a_acl : Internalized ACL to externalize.
488 * Ptr to the externalized version.
491 * Nothing interesting.
495 *------------------------------------------------------------------------*/
498 AclToString(struct Acl *a_acl)
501 static char mydata[MAXSIZE];
502 char tstring[MAXSIZE];
506 * Print out the number of positive & negative entries on one line.
508 sprintf(mydata, "%d\n%d\n", a_acl->nplus, a_acl->nminus);
511 * Externalize the positive list.
513 for (tp = a_acl->pluslist; tp; tp = tp->next) {
514 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
515 strcat(mydata, tstring);
519 * Externalize the negative list.
521 for (tp = a_acl->minuslist; tp; tp = tp->next) {
522 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
523 strcat(mydata, tstring);
530 /*------------------------------------------------------------------------
531 * static uss_acl_SetAccess
534 * ACL comes in as a single string, prefixed with the pathname to
535 * which the ACL is applied. The a_clear argument, if set, causes
536 * us to act like sac instead of sa.
540 *------------------------------------------------------------------------*/
543 uss_acl_SetAccess(char *a_access, int a_clear, int a_negative)
544 { /*uss_acl_SetAccess */
546 register afs_int32 code;
548 static char rn[] = "uss_acl_SetAccess";
551 char *externalizedACL;
554 char tmp_str[MAXSIZE];
555 char path_field[MAXSIZE], user_field[64], rights_field[64], *tp;
561 * Pull out the pathname from our argument.
563 tp = uss_common_FieldCp(path_field, a_access, ' ', sizeof(path_field),
566 fprintf(stderr, "%s: * Pathname field too long (max is %" AFS_SIZET_FMT " chars)\n",
567 uss_whoami, sizeof(path_field));
572 * Ask the Cache Manager to give us the externalized ACL for the
575 code = uss_fs_GetACL(path_field, tmp_str, MAXSIZE);
577 afs_com_err(uss_whoami, code, "while getting access list for %s",
580 printf("%s: Error code from uss_fs_GetACL %d, errno %d\n", rn, code,
582 #endif /* USS_ACL_DB */
587 printf("%s: ACL for pathname '%s' is: '%s'\n", rn, path_field,
589 #endif /* USS_ACL_DB */
592 * Generate the proper internalized ACL.
597 ta = ParseAcl(tmp_str);
600 * For each given entry, pull out the information and alter the
601 * internalized ACL to reflect it.
603 while (*tp != '\0') {
604 tp = uss_common_FieldCp(user_field, tp, ' ', 64, &overflow);
606 fprintf(stderr, "%s: * User field too long (max is 64 chars)\n",
611 printf("%s: Missing second half of user/access pair.\n",
615 tp = uss_common_FieldCp(rights_field, tp, ' ', 64, &overflow);
617 fprintf(stderr, "%s: * Rights field too long (max is 64 chars)\n",
621 rights = Convert(rights_field);
622 ChangeList(ta, plusp, user_field, rights);
626 * Externalize the fully-processed internal ACL, then pass it back
627 * to the Cache Manager.
629 externalizedACL = AclToString(ta);
631 uss_fs_SetACL(path_field, externalizedACL,
632 strlen(externalizedACL) + 1);
635 printf("%s: uss_fs_SetACL() failed, code is %d, errno is %d\n", rn,
637 #endif /* USS_ACL_DB */
638 if (errno == EINVAL) {
639 printf("Can't set ACL for directory '%s' to '%s'\n", path_field,
641 printf("Invalid argument, possible reasons include:\n");
642 printf("\t1. File not in AFS, or\n");
643 printf("\t2. Too many users on the ACL, or\n");
644 printf("\t3. Non-existent user or group on ACL.\n");
647 afs_com_err(uss_whoami, code, "while setting the access list");
653 } /*uss_acl_SetAccess */
656 /*------------------------------------------------------------------------
657 * static us_acl_SetDiskQuota
660 * Nothing interesting.
664 *------------------------------------------------------------------------*/
667 uss_acl_SetDiskQuota(char *a_path, int a_q)
668 { /*uss_acl_SetDiskQuota */
670 register afs_int32 code;
672 static char rn[] = "uss_acl_SetDiskQuota";
674 uss_VolumeStatus_t *status;
675 char *name, *motd, *offmsg;
677 char tmp_str[MAXSIZE];
681 "Setting disk quota on volume mounted at '%s' to %d blocks\n",
684 status = (uss_VolumeStatus_t *) tmp_str;
685 status->MinQuota = status->MaxQuota = -1;
686 name = motd = offmsg = NULL;
687 status->MaxQuota = a_q;
689 input = (char *)status + sizeof(*status);
694 code = uss_fs_SetVolStat(a_path, tmp_str, sizeof(*status) + 3);
696 afs_com_err(uss_whoami, code, "while setting disk quota");
698 printf("%s: uss_fs_SetVolStat() error code: %d, errno is %d\n", rn,
700 #endif /* USS_ACL_DB */
706 } /*uss_acl_SetDiskQuota */
709 /*-----------------------------------------------------------------------
710 * EXPORTED uss_acl_CleanUp
713 * The uss_currentDir variable contains directories touched by the
718 *------------------------------------------------------------------------*/
721 uss_acl_CleanUp(void)
722 { /*uss_acl_CleanUp */
724 struct uss_subdir *t, *old_t = NULL;
725 char tmp_str[uss_MAX_SIZE];
728 * Restore the ACL for each directory created for our caller to its
729 * original setting. The uss_AccountCreator's access was (potentially)
730 * amplified to full rights - any excess ability must now be removed.
732 for (t = uss_currentDir; t != NULL; t = t->previous) {
733 sprintf(tmp_str, "%s %s", t->path, t->finalACL);
735 fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
737 uss_acl_SetAccess(tmp_str, 1, 0);
739 fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
745 } /*Remove caller from user directory ACL */
751 * Return successfully.
755 } /*uss_acl_CleanUp */