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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
21 #include <netinet/in.h>
33 #include <afs/com_err.h>
34 #include <afs/cellconfig.h>
39 /* Foreign cells are represented by the group system:authuser@cell*/
40 #define AUTHUSER_GROUP "system:authuser"
43 extern struct ubik_dbase *dbase;
44 extern struct afsconf_dir *prdir;
48 extern afs_int32 AddToEntry();
49 static char *whoami = "ptserver";
51 /* CorrectUserName - Check to make sure a user name is OK. It must not include
52 * either a colon (or it would look like a group) or an atsign (or it would
53 * look like a foreign user). The length is checked as well to make sure
54 * that the user name, an atsign, and the local cell name will fit in
55 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
56 * a foreign user with our cell name tacked on. This is a predicate, so it
57 * return one if name is OK and zero if name is bogus. */
59 static int CorrectUserName (name)
62 extern int pr_realmNameLen;
64 /* We accept foreign names, so we will deal with '@' later */
65 if (strchr (name, ':') || strchr(name, '\n')) return 0;
66 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
70 /* CorrectGroupName - Like the above but handles more complicated cases caused
71 * by including the ownership in the name. The interface works by calculating
72 * the correct name based on a given name and owner. This allows easy use by
73 * rename, which then compares the correct name with the requested new name. */
75 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
76 struct ubik_trans *ut;
77 char aname[PR_MAXNAMELEN]; /* name for group */
78 afs_int32 cid; /* caller id */
79 afs_int32 oid; /* owner of group */
80 char cname[PR_MAXNAMELEN]; /* correct name for group */
84 char *prefix; /* ptr to group owner part */
85 char *suffix; /* ptr to group name part */
86 char name[PR_MAXNAMELEN]; /* correct name for group */
87 struct prentry tentry;
89 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
90 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
92 if (oid == 0) oid = cid;
94 /* Determine the correct prefix for the name. */
95 if (oid == SYSADMINID) prefix = "system";
97 afs_int32 loc = FindByID (ut, oid);
99 /* let admin create groups owned by non-existent ids (probably
100 * setting a group to own itself). Check that they look like
101 * groups (with a colon) or otherwise are good user names. */
103 strcpy (cname, aname);
108 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
109 if (code) return code;
110 if (ntohl(tentry.flags) & PRGRP) {
111 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
112 /* terminate prefix at colon if there is one */
113 if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
115 prefix = tentry.name;
117 /* only sysadmin allow to use 'system:' prefix */
118 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
120 strcpy (name, aname); /* in case aname & cname are same */
121 suffix = strchr(name, ':');
123 /* sysadmin can make groups w/o ':', but they must still look like
124 * legal user names. */
125 if (!admin) return PRBADNAM;
126 strcpy (cname, name);
129 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
130 strcpy (cname, prefix);
131 strcat (cname, suffix);
134 /* check for legal name with either group rules or user rules */
135 if ((suffix = strchr(cname, ':'))) {
136 /* check for confusing characters */
137 if (strchr(cname, '\n') || /* restrict so recreate can work */
138 strchr(suffix+1, ':')) /* avoid multiple colons */
141 if (!CorrectUserName (cname)) return PRBADNAM;
146 int AccessOK (ut, cid, tentry, mem, any)
147 struct ubik_trans *ut;
148 afs_int32 cid; /* caller id */
149 struct prentry *tentry; /* object being accessed */
150 int mem; /* check membership in aid, if group */
151 int any; /* if set return true */
156 if (pr_noAuth) return 1;
157 if (cid == SYSADMINID) return 1; /* special case fileserver */
159 flags = tentry->flags;
163 flags = oid = aid = 0;
165 if (!(flags & PRACCESS)) { /* provide default access */
167 flags |= PRP_GROUP_DEFAULT;
169 flags |= PRP_USER_DEFAULT;
172 if (flags & any) return 1;
175 IsAMemberOf (ut, cid, oid)) return 1;
177 if (aid > 0) { /* checking on a user */
178 if (aid == cid) return 1;
179 } else if (aid < 0) { /* checking on group */
180 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
182 /* Allow members of SYSVIEWERID to get membership and status only */
183 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
184 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
185 return 0; /* no access */
188 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
189 struct ubik_trans *at;
190 char aname[PR_MAXNAMELEN];
197 /* get and init a new entry */
200 struct prentry tentry, tent;
203 memset(&tentry, 0, sizeof(tentry));
205 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
208 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
209 if (code) return code;
210 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
211 } else { /* non-group must not have colon */
212 if (!CorrectUserName(aname)) return PRBADNAM;
213 strcpy (tentry.name, aname);
216 if (FindByName(at,aname, &tent)) return PREXIST;
218 newEntry = AllocBlock(at);
219 if (!newEntry) return PRDBFAIL;
220 #ifdef PR_REMEMBER_TIMES
221 tentry.createTime = time(0);
225 tentry.flags = PRGRP;
227 } else if (flag == 0) {
229 tentry.owner = SYSADMINID;
234 atsign = strchr(aname, '@');
236 /* A normal user or group. Pick an id for it */
240 code= AllocID(at,flag,&tentry.id);
241 if (code != PRSUCCESS) return code;
243 } else if (flag & PRGRP) {
244 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
245 * Then pick an id for the group.
250 badFormat = strcmp(AUTHUSER_GROUP, aname);
252 if (badFormat) return PRBADNAM;
257 code= AllocID(at,flag,&tentry.id);
258 if (code != PRSUCCESS) return code;
261 /* A foreign user: <name>@<cell>. The foreign user is added to
262 * its representing group. It is
266 struct prentry centry;
267 extern afs_int32 allocNextId();
269 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
272 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
273 strcpy(cellGroup, AUTHUSER_GROUP);
274 strcat(cellGroup, atsign);
275 pos = FindByName(at, cellGroup, ¢ry);
276 if (!pos) return PRBADNAM;
277 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
278 if (code) return code;
280 /* cellid is the id of the group representing the cell */
281 tentry.cellid = ntohl(centry.id);
284 /* Check if id is good */
285 if (!inRange(¢ry,*aid)) return PRBADARG;
288 /* Allocate an ID special for this foreign user. It is based
289 * on the representing group's id and nusers count.
291 tentry.id = allocNextId(¢ry);
294 /* The foreign user will be added to the representing foreign
295 * group. The group can hold up to 30 entries.
297 if (!(ntohl(centry.flags) & PRQUOTA)) {
298 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
299 centry.ngroups = htonl(30);
301 n = ntohl(centry.ngroups);
302 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
303 centry.ngroups = htonl(n - 1);
305 /* write updated entry for group */
306 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
308 /* Now add the new user entry to the database */
309 tentry.creator = creator;
311 code = pr_WriteEntry(at, 0, newEntry, &tentry);
312 if (code) return PRDBFAIL;
313 code = AddToIDHash(at, *aid, newEntry);
314 if (code != PRSUCCESS) return code;
315 code = AddToNameHash(at, aname, newEntry);
316 if (code != PRSUCCESS) return code;
317 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
319 /* Now add the entry to the authuser group for this cell.
320 * We will reread the entries for the user and the group
321 * instead of modifying them before writing them in the
322 * previous steps. Although not very efficient, much simpler
324 pos = FindByID(at, tentry.cellid);
325 if (!pos) return PRBADNAM;
326 code = pr_ReadEntry (at, 0, pos, ¢ry);
327 if (code) return code;
328 code = AddToEntry(at, ¢ry, pos, *aid);
329 if (code) return code;
330 /* and now the user entry */
331 pos = FindByID(at,*aid);
332 if (!pos) return PRBADNAM;
333 code = pr_ReadEntry (at, 0, pos, &tentry);
334 if (code) return code;
335 code = AddToEntry(at, &tentry, pos, tentry.cellid);
336 if (code) return code;
341 /* Remember the largest group id or largest user id */
343 /* group ids are negative */
344 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
345 code = set_header_word (at, maxGroup, htonl(tentry.id));
346 if (code) return PRDBFAIL;
350 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
351 code = set_header_word (at, maxID, htonl(tentry.id));
352 if (code) return PRDBFAIL;
356 /* Charge the creator for this group */
358 afs_int32 loc = FindByID (at, creator);
359 struct prentry centry;
362 if (loc) { /* this should only fail during initialization */
363 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
364 if (code) return code;
366 /* If quota is uninitialized, do it */
367 if (!(ntohl(centry.flags) & PRQUOTA)) {
368 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
369 centry.ngroups = centry.nusers = htonl(20);
372 /* Admins don't get charged for creating a group.
373 * If in noAuth mode, you get changed for it but you
374 * are still allowed to create as many groups as you want.
376 admin = ( (creator == SYSADMINID) ||
377 IsAMemberOf(at,creator,SYSADMINID) );
379 if (ntohl(centry.ngroups) <= 0) {
380 if (!pr_noAuth) return PRNOMORE;
382 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
386 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
387 if (code) return code;
391 /* Initialize the quota for the user. Groups don't have their
394 tentry.flags |= PRQUOTA;
395 tentry.ngroups = tentry.nusers = 20;
398 tentry.creator = creator;
400 code = pr_WriteEntry(at, 0, newEntry, &tentry);
401 if (code) return PRDBFAIL;
402 code = AddToIDHash(at,*aid,newEntry);
403 if (code != PRSUCCESS) return code;
404 code = AddToNameHash(at,aname,newEntry);
405 if (code != PRSUCCESS) return code;
406 if (tentry.flags & PRGRP) {
407 code = AddToOwnerChain(at,tentry.id,oid);
408 if (code) return code;
410 if (tentry.flags & PRGRP) {
411 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
413 else if (tentry.flags & PRINST) {
414 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
417 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
423 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
424 * entry if appropriate */
426 afs_int32 RemoveFromEntry (at, aid, bid)
427 struct ubik_trans *at;
432 struct prentry tentry;
433 struct contentry centry;
434 struct contentry hentry;
440 if (aid == bid) return PRINCONSISTENT;
441 memset(&hentry, 0, sizeof(hentry));
442 temp = FindByID(at,bid);
443 if (temp == 0) return PRNOENT;
444 code = pr_ReadEntry(at, 0, temp, &tentry);
445 if (code != 0) return code;
446 #ifdef PR_REMEMBER_TIMES
447 tentry.removeTime = time(0);
449 for (i=0;i<PRSIZE;i++) {
450 if (tentry.entries[i] == aid) {
451 tentry.entries[i] = PRBADID;
453 code = pr_WriteEntry(at,0,temp,&tentry);
454 if (code != 0) return code;
457 if (tentry.entries[i] == 0) /* found end of list */
463 code = pr_ReadCoEntry(at,0,nptr,¢ry);
464 if (code != 0) return code;
465 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
466 for (i=0;i<COSIZE;i++) {
467 if (centry.entries[i] == aid) {
468 centry.entries[i] = PRBADID;
469 for (j=0;j<COSIZE;j++)
470 if (centry.entries[j] != PRBADID &&
471 centry.entries[j] != 0) break;
472 if (j == COSIZE) { /* can free this block */
474 tentry.next = centry.next;
477 hentry.next = centry.next;
478 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
479 if (code != 0) return code;
481 code = FreeBlock (at, nptr);
482 if (code) return code;
484 else { /* can't free it yet */
485 code = pr_WriteCoEntry(at,0,nptr,¢ry);
486 if (code != 0) return code;
489 code = pr_WriteEntry(at,0,temp,&tentry);
490 if (code) return PRDBFAIL;
493 if (centry.entries[i] == 0) return PRNOENT;
494 } /* for all coentry slots */
497 memcpy(&hentry, ¢ry, sizeof(centry));
498 } /* while there are coentries */
502 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
503 * groups, putting groups owned by it on orphan chain, and freeing the space */
505 afs_int32 DeleteEntry (at, tentry, loc)
506 struct ubik_trans *at;
507 struct prentry *tentry;
511 struct contentry centry;
515 if (strchr(tentry->name,'@')) {
516 if (tentry->flags & PRGRP) {
517 /* If there are still foreign user accounts from that cell
518 don't delete the group */
519 if (tentry->count) return PRBADARG;
523 afs_int32 loc = FindByID (at, tentry->cellid);
524 struct prentry centry;
526 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
527 if (code) return code;
528 if (ntohl(centry.flags) & PRQUOTA) {
529 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
531 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
532 if (code) return code;
536 /* First remove the entire membership list */
537 for (i=0;i<PRSIZE;i++) {
538 if (tentry->entries[i] == PRBADID) continue;
539 if (tentry->entries[i] == 0) break;
540 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
541 if (code) return code;
544 while (nptr != (afs_int32)NULL) {
545 code = pr_ReadCoEntry(at,0,nptr,¢ry);
546 if (code != 0) return PRDBFAIL;
547 for (i=0;i<COSIZE;i++) {
548 if (centry.entries[i] == PRBADID) continue;
549 if (centry.entries[i] == 0) break;
550 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
551 if (code) return code;
553 code = FreeBlock (at, nptr); /* free continuation block */
554 if (code) return code;
558 /* Remove us from other's owned chain. Note that this will zero our owned
559 * field (on disk) so this step must follow the above step in case we are
560 * on our own owned list. */
561 if (tentry->flags & PRGRP) {
563 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
564 if (code) return code;
567 code = RemoveFromOrphan (at, tentry->id);
568 if (code) return code;
572 code = RemoveFromIDHash(at,tentry->id,&loc);
573 if (code != PRSUCCESS) return code;
574 code = RemoveFromNameHash(at,tentry->name,&loc);
575 if (code != PRSUCCESS) return code;
577 if (tentry->flags & PRGRP) {
578 afs_int32 loc = FindByID(at, tentry->creator);
579 struct prentry centry;
583 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
584 if (code) return code;
585 admin = ( (tentry->creator == SYSADMINID) ||
586 IsAMemberOf(at,tentry->creator,SYSADMINID) );
587 if (ntohl(centry.flags) & PRQUOTA) {
588 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
589 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
592 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
593 if (code) return code;
597 if (tentry->flags & PRGRP) {
598 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
600 else if (tentry->flags & PRINST) {
601 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
604 if (strchr(tentry->name,'@')) {
605 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
607 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
610 code = FreeBlock(at, loc);
614 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
617 * Note the entry is written out by this routine. */
619 afs_int32 AddToEntry (tt, entry, loc, aid)
620 struct ubik_trans *tt;
621 struct prentry *entry;
627 struct contentry nentry;
628 struct contentry aentry;
630 afs_int32 last; /* addr of last cont. block */
635 if (entry->id == aid) return PRINCONSISTENT;
636 #ifdef PR_REMEMBER_TIMES
637 entry->addTime = time(0);
639 for (i=0;i<PRSIZE;i++) {
640 if (entry->entries[i] == aid)
642 if (entry->entries[i] == PRBADID) { /* remember this spot */
646 else if (entry->entries[i] == 0) { /* end of the line */
656 while (nptr != (afs_int32)NULL) {
657 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
658 if (code != 0) return code;
660 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
661 for (i=0;i<COSIZE;i++) {
662 if (nentry.entries[i] == aid)
664 if (nentry.entries[i] == PRBADID) {
670 else if (nentry.entries[i] == 0) {
680 if (slot != -1) { /* we found a place */
682 if (first) { /* place is in first block */
683 entry->entries[slot] = aid;
684 code = pr_WriteEntry (tt, 0, loc, entry);
685 if (code != 0) return code;
688 code = pr_WriteEntry (tt, 0, loc, entry);
689 if (code) return code;
690 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
691 if (code != 0) return code;
692 aentry.entries[slot] = aid;
693 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
694 if (code != 0) return code;
697 /* have to allocate a continuation block if we got here */
698 nptr = AllocBlock(tt);
700 /* then we should tack new block after last block in cont. chain */
702 code = pr_WriteCoEntry(tt,0,last,&nentry);
703 if (code != 0) return code;
708 memset(&aentry, 0, sizeof(aentry));
709 aentry.flags |= PRCONT;
710 aentry.id = entry->id;
712 aentry.entries[0] = aid;
713 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
714 if (code != 0) return code;
715 /* don't forget to update count, here! */
717 code = pr_WriteEntry (tt, 0, loc, entry);
722 afs_int32 AddToPRList (alist, sizeP, id)
730 if (alist->prlist_len >= *sizeP) {
731 count = alist->prlist_len + 100;
732 if (alist->prlist_val) {
733 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
735 tmp = (char *) malloc(count*sizeof(afs_int32));
737 if (!tmp) return(PRNOMEM);
738 alist->prlist_val = (afs_int32 *)tmp;
741 alist->prlist_val[alist->prlist_len++] = id;
745 afs_int32 GetList (at, tentry, alist, add)
746 struct ubik_trans *at;
747 struct prentry *tentry;
753 struct contentry centry;
759 alist->prlist_val = 0;
760 alist->prlist_len = 0;
762 for (i=0;i<PRSIZE;i++) {
763 if (tentry->entries[i] == PRBADID) continue;
764 if (tentry->entries[i] == 0) break;
765 code = AddToPRList (alist, &size, tentry->entries[i]);
766 if (code) return code;
769 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
770 /* look through cont entries */
771 code = pr_ReadCoEntry(at,0,nptr,¢ry);
772 if (code != 0) return code;
773 for (i=0;i<COSIZE;i++) {
774 if (centry.entries[i] == PRBADID) continue;
775 if (centry.entries[i] == 0) break;
776 code = AddToPRList (alist, &size, centry.entries[i]);
777 if (code) return code;
779 if (count++ > 50) IOMGR_Poll(), count = 0;
782 if (add) { /* this is for a CPS, so tack on appropriate stuff */
783 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
784 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
785 (code = AddAuthGroup(tentry, alist, &size)) ||
786 (code = AddToPRList (alist, &size, tentry->id))) return code;
789 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
790 (code = AddToPRList (alist, &size, tentry->id))) return code;
793 if (alist->prlist_len > 100) IOMGR_Poll();
794 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
799 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
800 struct ubik_trans *at;
801 struct prentry *tentry;
802 struct prentry *tentry2;
808 struct contentry centry;
814 alist->prlist_val = 0;
815 alist->prlist_len = 0;
816 for (i=0;i<PRSIZE;i++) {
817 if (tentry->entries[i] == PRBADID) continue;
818 if (tentry->entries[i] == 0) break;
819 code = AddToPRList (alist, &size, tentry->entries[i]);
820 if (code) return code;
824 while (nptr != (afs_uint32)NULL) {
825 /* look through cont entries */
826 code = pr_ReadCoEntry(at,0,nptr,¢ry);
827 if (code != 0) return code;
828 for (i=0;i<COSIZE;i++) {
829 if (centry.entries[i] == PRBADID) continue;
830 if (centry.entries[i] == 0) break;
831 code = AddToPRList (alist, &size, centry.entries[i]);
832 if (code) return code;
835 if (count++ > 50) IOMGR_Poll(), count = 0;
838 for (i=0;i<PRSIZE;i++) {
839 if (tentry2->entries[i] == PRBADID) continue;
840 if (tentry2->entries[i] == 0) break;
841 code = AddToPRList (alist, &size, tentry2->entries[i]);
846 nptr = tentry2->next;
847 while (nptr != (afs_uint32)NULL) {
848 /* look through cont entries */
849 code = pr_ReadCoEntry(at,0,nptr,¢ry);
850 if (code != 0) break;
851 for (i=0;i<COSIZE;i++) {
852 if (centry.entries[i] == PRBADID) continue;
853 if (centry.entries[i] == 0) break;
854 code = AddToPRList (alist, &size, centry.entries[i]);
858 if (count++ > 50) IOMGR_Poll(), count = 0;
861 if (add) { /* this is for a CPS, so tack on appropriate stuff */
862 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
863 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
864 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
865 (code = AddToPRList (alist, &size, tentry->id))) return code;
868 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
869 (code = AddToPRList (alist, &size, tentry->id))) return code;
872 if (alist->prlist_len > 100) IOMGR_Poll();
873 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
877 afs_int32 GetOwnedChain (ut, next, alist)
878 struct ubik_trans *ut;
882 struct prentry tentry;
887 alist->prlist_val = 0;
888 alist->prlist_len = 0;
890 for (; *next; *next = ntohl(tentry.nextOwned)) {
891 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
892 if (code) return code;
893 code = AddToPRList (alist, &size, ntohl(tentry.id));
894 if (alist->prlist_len >= PR_MAXGROUPS) {
897 if (code) return code;
898 if (count++ > 50) IOMGR_Poll(), count = 0;
900 if (alist->prlist_len > 100) IOMGR_Poll();
901 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
905 afs_int32 GetMax(at,uid,gid)
906 struct ubik_trans *at;
910 *uid = ntohl(cheader.maxID);
911 *gid = ntohl(cheader.maxGroup);
915 afs_int32 SetMax(at,id,flag)
916 struct ubik_trans *at;
922 cheader.maxGroup = htonl(id);
923 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
924 if (code != 0) return code;
927 cheader.maxID = htonl(id);
928 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
929 if (code != 0) return code;
934 afs_int32 read_DbHeader(tt)
935 struct ubik_trans *tt;
939 if (!ubik_CacheUpdate(tt)) return 0;
941 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
943 com_err (whoami, code, "Couldn't read header");
954 struct ubik_trans *tt;
957 /* init the database. We'll try reading it, but if we're starting
958 * from scratch, we'll have to do a write transaction. */
960 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
962 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
963 if (code) return code;
964 code = ubik_SetLock(tt,1,1,LOCKREAD);
971 } else if (!ubik_CacheUpdate (tt)) {
972 code = ubik_EndTrans(tt);
976 len = sizeof(cheader);
977 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
979 com_err (whoami, code, "couldn't read header");
983 if ((ntohl(cheader.version) == PRDBVERSION) &&
984 ntohl(cheader.headerSize) == sizeof(cheader) &&
985 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
986 FindByID(tt,ANONYMOUSID) != 0){
987 /* database exists, so we don't have to build it */
988 code = ubik_EndTrans(tt);
989 if (code) return code;
992 /* else we need to build a database */
993 code = ubik_EndTrans(tt);
994 if (code) return code;
996 /* Only rebuild database if the db was deleted (the header is zero) and we
997 are running noAuth. */
998 { char *bp = (char *)&cheader;
1000 for (i=0; i<sizeof(cheader); i++)
1003 com_err (whoami, code,
1004 "Can't rebuild database because it is not empty");
1010 com_err (whoami, code,
1011 "Can't rebuild database because not running NoAuth");
1015 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1016 if (code) return code;
1018 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1020 ubik_AbortTrans(tt);
1024 /* before doing a rebuild, check again that the dbase looks bad, because
1025 * the previous check was only under a ReadAny transaction, and there could
1026 * actually have been a good database out there. Now that we have a
1027 * real write transaction, make sure things are still bad.
1029 if ((ntohl(cheader.version) == PRDBVERSION) &&
1030 ntohl(cheader.headerSize) == sizeof(cheader) &&
1031 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1032 FindByID(tt,ANONYMOUSID) != 0){
1033 /* database exists, so we don't have to build it */
1034 code = ubik_EndTrans(tt);
1035 if (code) return code;
1039 /* Initialize the database header */
1040 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1041 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1042 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1043 com_err (whoami, code, "couldn't write header words");
1044 ubik_AbortTrans(tt);
1048 #define InitialGroup(id,name) do { \
1049 afs_int32 temp = (id); \
1050 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1051 code = CreateEntry \
1052 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1054 com_err (whoami, code, "couldn't create %s with id %di.", \
1056 ubik_AbortTrans(tt); \
1061 InitialGroup (SYSADMINID, "system:administrators");
1062 InitialGroup (SYSBACKUPID, "system:backup");
1063 InitialGroup (ANYUSERID, "system:anyuser");
1064 InitialGroup (AUTHUSERID, "system:authuser");
1065 InitialGroup (SYSVIEWERID, "system:ptsviewers");
1066 InitialGroup (ANONYMOUSID, "anonymous");
1068 /* Well, we don't really want the max id set to anonymousid, so we'll set
1070 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1072 com_err (whoami, code, "couldn't reset max id");
1073 ubik_AbortTrans(tt);
1077 code = ubik_EndTrans(tt);
1078 if (code) return code;
1082 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1083 struct ubik_trans *at;
1091 afs_int32 i, nptr, pos;
1092 struct contentry centry;
1093 struct prentry tentry, tent;
1096 char holder[PR_MAXNAMELEN];
1097 char temp[PR_MAXNAMELEN];
1098 char oldname[PR_MAXNAMELEN];
1101 memset(holder, 0, PR_MAXNAMELEN);
1102 memset(temp, 0, PR_MAXNAMELEN);
1103 loc = FindByID(at,aid);
1104 if (!loc) return PRNOENT;
1105 code = pr_ReadEntry(at,0,loc,&tentry);
1106 if (code) return PRDBFAIL;
1107 if (tentry.owner != cid &&
1108 !IsAMemberOf(at,cid,SYSADMINID) &&
1109 !IsAMemberOf(at,cid,tentry.owner) &&
1110 !pr_noAuth) return PRPERM;
1111 #ifdef PR_REMEMBER_TIMES
1112 tentry.changeTime = time(0);
1115 /* we're actually trying to change the id */
1116 if (newid && (newid != aid)) {
1117 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1119 pos = FindByID(at,newid);
1120 if (pos) return PRIDEXIST; /* new id already in use! */
1121 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1123 /* Should check that foreign users id to change to is good: inRange() */
1125 /* if new id is not in use, rehash things */
1126 code = RemoveFromIDHash(at,aid,&loc);
1127 if (code != PRSUCCESS) return code;
1129 code = pr_WriteEntry(at,0,loc,&tentry);
1130 if (code) return code;
1131 code = AddToIDHash(at,tentry.id,loc);
1132 if (code) return code;
1134 /* get current data */
1135 code = pr_ReadEntry(at, 0, loc, &tentry);
1136 if (code) return PRDBFAIL;
1138 /* Also change the references from the membership list */
1139 for (i=0; i<PRSIZE; i++) {
1140 if (tentry.entries[i] == PRBADID) continue;
1141 if (tentry.entries[i] == 0) break;
1142 pos = FindByID(at, tentry.entries[i]);
1143 if (!pos) return(PRDBFAIL);
1144 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1145 if (code) return code;
1146 code = pr_ReadEntry(at, 0, pos, &tent);
1147 if (code) return code;
1148 code = AddToEntry(at, &tent, pos, newid);
1149 if (code) return code;
1151 /* Look through cont entries too. This needs to be broken into
1152 * seperate transaction so that no one transaction becomes too
1153 * large to complete.
1155 for (nptr=tentry.next; nptr; nptr=centry.next) {
1156 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1157 if (code) return code;
1158 for (i=0; i<COSIZE; i++) {
1159 if (centry.entries[i] == PRBADID) continue;
1160 if (centry.entries[i] == 0) break;
1161 pos = FindByID(at, centry.entries[i]);
1162 if (!pos) return(PRDBFAIL);
1163 code = RemoveFromEntry(at, aid, centry.entries[i]);
1164 if (code) return code;
1165 code = pr_ReadEntry(at, 0, pos, &tent);
1166 if (code) return code;
1167 code = AddToEntry(at, &tent, pos, newid);
1168 if (code) return code;
1173 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
1175 /* Change the owner */
1176 if (oid && (oid != tentry.owner)) {
1177 /* only groups can have their owner's changed */
1178 if (!(tentry.flags & PRGRP)) return PRPERM;
1179 if (atsign != NULL) return PRPERM;
1180 oldowner = tentry.owner;
1182 /* The entry must be written through first so Remove and Add routines
1183 * can operate on disk data */
1184 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1185 if (code) return PRDBFAIL;
1187 /* switch owner chains */
1188 if (oldowner) /* if it has an owner */
1189 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1190 else /* must be an orphan */
1191 code = RemoveFromOrphan(at,tentry.id);
1192 if (code) return code;
1193 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1194 if (code) return code;
1196 /* fix up the name */
1197 if (strlen(name) == 0) name = tentry.name;
1198 /* get current data */
1199 code = pr_ReadEntry(at,0,loc,&tentry);
1200 if (code) return PRDBFAIL;
1203 /* Change the name, if name is a ptr to tentry.name then this name change
1204 * is due to a chown, otherwise caller has specified a new name */
1205 if ((name == tentry.name) ||
1206 (*name && (strcmp (tentry.name, name) != 0))) {
1207 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1208 if (tentry.flags & PRGRP) {
1209 /* don't let foreign cell groups change name */
1210 if (atsign != NULL) return PRPERM;
1211 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1212 if (code) return code;
1214 if (name == tentry.name) { /* owner fixup */
1215 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1216 } else { /* new name, caller must be correct */
1217 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1221 /* Allow a foreign name change only if the cellname part is
1226 newatsign = strchr(name, '@');
1227 if (newatsign != atsign){ /* if they are the same no problem*/
1228 /*if the pointers are not equal the strings better be */
1229 if ((atsign == NULL) || (newatsign == NULL) ||
1230 strcmp (atsign,newatsign)) return PRPERM;
1232 if (!CorrectUserName(name)) return PRBADNAM;
1235 pos = FindByName(at,name, &tent);
1236 if (pos) return PREXIST;
1237 code = RemoveFromNameHash (at, oldname, &loc);
1238 if (code != PRSUCCESS) return code;
1239 strncpy (tentry.name, name, PR_MAXNAMELEN);
1240 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1241 if (code) return PRDBFAIL;
1242 code = AddToNameHash(at,tentry.name,loc);
1243 if (code != PRSUCCESS) return code;
1250 afs_int32 allocNextId(cellEntry)
1251 struct prentry *cellEntry;
1253 /* Id's for foreign cell entries are constructed as follows:
1254 The 16 low order bits are the group id of the cell and the
1255 top 16 bits identify the particular users in that cell */
1260 id = (ntohl(cellEntry -> nusers) +1);
1261 cellEntry->nusers = htonl(id);
1262 /* use the field nusers to keep
1263 the next available id in that
1264 foreign cell's group. Note :
1265 It would seem more appropriate
1266 to use ngroup for that and nusers
1267 to enforce the quota, however pts
1268 does not have an option to change
1269 foreign users quota yet */
1271 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1275 int inRange(cellEntry,aid)
1276 struct prentry *cellEntry;
1279 afs_uint32 id,cellid,groupid;
1283 The only thing that we want to make sure here is that
1284 the id is in the legal range of this group. If it is
1285 a duplicate we don't care since it will get caught
1286 in a different check.
1289 cellid = aid & 0x0000ffff;
1290 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1291 if (cellid != groupid) return 0; /* not in range */
1294 if we got here we're ok but we need to update the nusers
1295 field in order to get the id correct the next time that
1296 we try to allocate it automatically
1300 if (id > ntohl(cellEntry -> nusers))
1301 cellEntry -> nusers = htonl(id);
1306 AddAuthGroup(tentry, alist, size)
1307 struct prentry *tentry;
1311 if (!(strchr(tentry->name, '@')))
1312 return (AddToPRList (alist, size, AUTHUSERID));