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 <afs/param.h>
13 #include <sys/types.h>
18 #include <netinet/in.h>
24 #include <afs/com_err.h>
25 #include <afs/cellconfig.h>
30 /* Foreign cells are represented by the group system:authuser@cell*/
31 #define AUTHUSER_GROUP "system:authuser"
34 extern struct ubik_dbase *dbase;
35 extern struct afsconf_dir *prdir;
39 extern afs_int32 AddToEntry();
40 static char *whoami = "ptserver";
42 /* CorrectUserName - Check to make sure a user name is OK. It must not include
43 * either a colon (or it would look like a group) or an atsign (or it would
44 * look like a foreign user). The length is checked as well to make sure
45 * that the user name, an atsign, and the local cell name will fit in
46 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
47 * a foreign user with our cell name tacked on. This is a predicate, so it
48 * return one if name is OK and zero if name is bogus. */
50 static int CorrectUserName (name)
53 extern int pr_realmNameLen;
55 /* We accept foreign names, so we will deal with '@' later */
56 if (strchr (name, ':') || strchr(name, '\n')) return 0;
57 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
61 /* CorrectGroupName - Like the above but handles more complicated cases caused
62 * by including the ownership in the name. The interface works by calculating
63 * the correct name based on a given name and owner. This allows easy use by
64 * rename, which then compares the correct name with the requested new name. */
66 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
67 struct ubik_trans *ut;
68 char aname[PR_MAXNAMELEN]; /* name for group */
69 afs_int32 cid; /* caller id */
70 afs_int32 oid; /* owner of group */
71 char cname[PR_MAXNAMELEN]; /* correct name for group */
75 char *prefix; /* ptr to group owner part */
76 char *suffix; /* ptr to group name part */
77 char name[PR_MAXNAMELEN]; /* correct name for group */
78 struct prentry tentry;
80 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
81 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
83 if (oid == 0) oid = cid;
85 /* Determine the correct prefix for the name. */
86 if (oid == SYSADMINID) prefix = "system";
88 afs_int32 loc = FindByID (ut, oid);
90 /* let admin create groups owned by non-existent ids (probably
91 * setting a group to own itself). Check that they look like
92 * groups (with a colon) or otherwise are good user names. */
94 strcpy (cname, aname);
99 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
100 if (code) return code;
101 if (ntohl(tentry.flags) & PRGRP) {
102 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
103 /* terminate prefix at colon if there is one */
104 if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
106 prefix = tentry.name;
108 /* only sysadmin allow to use 'system:' prefix */
109 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
111 strcpy (name, aname); /* in case aname & cname are same */
112 suffix = strchr(name, ':');
114 /* sysadmin can make groups w/o ':', but they must still look like
115 * legal user names. */
116 if (!admin) return PRBADNAM;
117 strcpy (cname, name);
120 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
121 strcpy (cname, prefix);
122 strcat (cname, suffix);
125 /* check for legal name with either group rules or user rules */
126 if ((suffix = strchr(cname, ':'))) {
127 /* check for confusing characters */
128 if (strchr(cname, '\n') || /* restrict so recreate can work */
129 strchr(suffix+1, ':')) /* avoid multiple colons */
132 if (!CorrectUserName (cname)) return PRBADNAM;
137 int AccessOK (ut, cid, tentry, mem, any)
138 struct ubik_trans *ut;
139 afs_int32 cid; /* caller id */
140 struct prentry *tentry; /* object being accessed */
141 int mem; /* check membership in aid, if group */
142 int any; /* if set return true */
147 if (pr_noAuth) return 1;
148 if (cid == SYSADMINID) return 1; /* special case fileserver */
150 flags = tentry->flags;
154 flags = oid = aid = 0;
156 if (!(flags & PRACCESS)) { /* provide default access */
158 flags |= PRP_GROUP_DEFAULT;
160 flags |= PRP_USER_DEFAULT;
163 if (flags & any) return 1;
166 IsAMemberOf (ut, cid, oid)) return 1;
168 if (aid > 0) { /* checking on a user */
169 if (aid == cid) return 1;
170 } else if (aid < 0) { /* checking on group */
171 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
173 /* Allow members of SYSVIEWERID to get membership and status only */
174 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
175 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
176 return 0; /* no access */
179 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
180 struct ubik_trans *at;
181 char aname[PR_MAXNAMELEN];
188 /* get and init a new entry */
191 struct prentry tentry, tent;
194 memset(&tentry, 0, sizeof(tentry));
196 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
199 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
200 if (code) return code;
201 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
202 } else { /* non-group must not have colon */
203 if (!CorrectUserName(aname)) return PRBADNAM;
204 strcpy (tentry.name, aname);
207 if (FindByName(at,aname, &tent)) return PREXIST;
209 newEntry = AllocBlock(at);
210 if (!newEntry) return PRDBFAIL;
211 #ifdef PR_REMEMBER_TIMES
212 tentry.createTime = time(0);
216 tentry.flags = PRGRP;
218 } else if (flag == 0) {
220 tentry.owner = SYSADMINID;
225 atsign = strchr(aname, '@');
227 /* A normal user or group. Pick an id for it */
231 code= AllocID(at,flag,&tentry.id);
232 if (code != PRSUCCESS) return code;
234 } else if (flag & PRGRP) {
235 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
236 * Then pick an id for the group.
241 badFormat = strcmp(AUTHUSER_GROUP, aname);
243 if (badFormat) return PRBADNAM;
248 code= AllocID(at,flag,&tentry.id);
249 if (code != PRSUCCESS) return code;
252 /* A foreign user: <name>@<cell>. The foreign user is added to
253 * its representing group. It is
257 struct prentry centry;
258 extern afs_int32 allocNextId();
260 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
263 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
264 strcpy(cellGroup, AUTHUSER_GROUP);
265 strcat(cellGroup, atsign);
266 pos = FindByName(at, cellGroup, ¢ry);
267 if (!pos) return PRBADNAM;
268 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
269 if (code) return code;
271 /* cellid is the id of the group representing the cell */
272 tentry.cellid = ntohl(centry.id);
275 /* Check if id is good */
276 if (!inRange(¢ry,*aid)) return PRBADARG;
279 /* Allocate an ID special for this foreign user. It is based
280 * on the representing group's id and nusers count.
282 tentry.id = allocNextId(¢ry);
285 /* The foreign user will be added to the representing foreign
286 * group. The group can hold up to 30 entries.
288 if (!(ntohl(centry.flags) & PRQUOTA)) {
289 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
290 centry.ngroups = htonl(30);
292 n = ntohl(centry.ngroups);
293 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
294 centry.ngroups = htonl(n - 1);
296 /* write updated entry for group */
297 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
299 /* Now add the new user entry to the database */
300 tentry.creator = creator;
302 code = pr_WriteEntry(at, 0, newEntry, &tentry);
303 if (code) return PRDBFAIL;
304 code = AddToIDHash(at, *aid, newEntry);
305 if (code != PRSUCCESS) return code;
306 code = AddToNameHash(at, aname, newEntry);
307 if (code != PRSUCCESS) return code;
308 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
310 /* Now add the entry to the authuser group for this cell.
311 * We will reread the entries for the user and the group
312 * instead of modifying them before writing them in the
313 * previous steps. Although not very efficient, much simpler
315 pos = FindByID(at, tentry.cellid);
316 if (!pos) return PRBADNAM;
317 code = pr_ReadEntry (at, 0, pos, ¢ry);
318 if (code) return code;
319 code = AddToEntry(at, ¢ry, pos, *aid);
320 if (code) return code;
321 /* and now the user entry */
322 pos = FindByID(at,*aid);
323 if (!pos) return PRBADNAM;
324 code = pr_ReadEntry (at, 0, pos, &tentry);
325 if (code) return code;
326 code = AddToEntry(at, &tentry, pos, tentry.cellid);
327 if (code) return code;
332 /* Remember the largest group id or largest user id */
334 /* group ids are negative */
335 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
336 code = set_header_word (at, maxGroup, htonl(tentry.id));
337 if (code) return PRDBFAIL;
341 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
342 code = set_header_word (at, maxID, htonl(tentry.id));
343 if (code) return PRDBFAIL;
347 /* Charge the creator for this group */
349 afs_int32 loc = FindByID (at, creator);
350 struct prentry centry;
353 if (loc) { /* this should only fail during initialization */
354 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
355 if (code) return code;
357 /* If quota is uninitialized, do it */
358 if (!(ntohl(centry.flags) & PRQUOTA)) {
359 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
360 centry.ngroups = centry.nusers = htonl(20);
363 /* Admins don't get charged for creating a group.
364 * If in noAuth mode, you get changed for it but you
365 * are still allowed to create as many groups as you want.
367 admin = ( (creator == SYSADMINID) ||
368 IsAMemberOf(at,creator,SYSADMINID) );
370 if (ntohl(centry.ngroups) <= 0) {
371 if (!pr_noAuth) return PRNOMORE;
373 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
377 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
378 if (code) return code;
382 /* Initialize the quota for the user. Groups don't have their
385 tentry.flags |= PRQUOTA;
386 tentry.ngroups = tentry.nusers = 20;
389 tentry.creator = creator;
391 code = pr_WriteEntry(at, 0, newEntry, &tentry);
392 if (code) return PRDBFAIL;
393 code = AddToIDHash(at,*aid,newEntry);
394 if (code != PRSUCCESS) return code;
395 code = AddToNameHash(at,aname,newEntry);
396 if (code != PRSUCCESS) return code;
397 if (tentry.flags & PRGRP) {
398 code = AddToOwnerChain(at,tentry.id,oid);
399 if (code) return code;
401 if (tentry.flags & PRGRP) {
402 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
404 else if (tentry.flags & PRINST) {
405 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
408 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
414 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
415 * entry if appropriate */
417 afs_int32 RemoveFromEntry (at, aid, bid)
418 struct ubik_trans *at;
423 struct prentry tentry;
424 struct contentry centry;
425 struct contentry hentry;
431 if (aid == bid) return PRINCONSISTENT;
432 memset(&hentry, 0, sizeof(hentry));
433 temp = FindByID(at,bid);
434 if (temp == 0) return PRNOENT;
435 code = pr_ReadEntry(at, 0, temp, &tentry);
436 if (code != 0) return code;
437 #ifdef PR_REMEMBER_TIMES
438 tentry.removeTime = time(0);
440 for (i=0;i<PRSIZE;i++) {
441 if (tentry.entries[i] == aid) {
442 tentry.entries[i] = PRBADID;
444 code = pr_WriteEntry(at,0,temp,&tentry);
445 if (code != 0) return code;
448 if (tentry.entries[i] == 0) /* found end of list */
454 code = pr_ReadCoEntry(at,0,nptr,¢ry);
455 if (code != 0) return code;
456 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
457 for (i=0;i<COSIZE;i++) {
458 if (centry.entries[i] == aid) {
459 centry.entries[i] = PRBADID;
460 for (j=0;j<COSIZE;j++)
461 if (centry.entries[j] != PRBADID &&
462 centry.entries[j] != 0) break;
463 if (j == COSIZE) { /* can free this block */
465 tentry.next = centry.next;
468 hentry.next = centry.next;
469 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
470 if (code != 0) return code;
472 code = FreeBlock (at, nptr);
473 if (code) return code;
475 else { /* can't free it yet */
476 code = pr_WriteCoEntry(at,0,nptr,¢ry);
477 if (code != 0) return code;
480 code = pr_WriteEntry(at,0,temp,&tentry);
481 if (code) return PRDBFAIL;
484 if (centry.entries[i] == 0) return PRNOENT;
485 } /* for all coentry slots */
488 memcpy(&hentry, ¢ry, sizeof(centry));
489 } /* while there are coentries */
493 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
494 * groups, putting groups owned by it on orphan chain, and freeing the space */
496 afs_int32 DeleteEntry (at, tentry, loc)
497 struct ubik_trans *at;
498 struct prentry *tentry;
502 struct contentry centry;
506 if (strchr(tentry->name,'@')) {
507 if (tentry->flags & PRGRP) {
508 /* If there are still foreign user accounts from that cell
509 don't delete the group */
510 if (tentry->count) return PRBADARG;
514 afs_int32 loc = FindByID (at, tentry->cellid);
515 struct prentry centry;
517 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
518 if (code) return code;
519 if (ntohl(centry.flags) & PRQUOTA) {
520 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
522 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
523 if (code) return code;
527 /* First remove the entire membership list */
528 for (i=0;i<PRSIZE;i++) {
529 if (tentry->entries[i] == PRBADID) continue;
530 if (tentry->entries[i] == 0) break;
531 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
532 if (code) return code;
535 while (nptr != (afs_int32)NULL) {
536 code = pr_ReadCoEntry(at,0,nptr,¢ry);
537 if (code != 0) return PRDBFAIL;
538 for (i=0;i<COSIZE;i++) {
539 if (centry.entries[i] == PRBADID) continue;
540 if (centry.entries[i] == 0) break;
541 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
542 if (code) return code;
544 code = FreeBlock (at, nptr); /* free continuation block */
545 if (code) return code;
549 /* Remove us from other's owned chain. Note that this will zero our owned
550 * field (on disk) so this step must follow the above step in case we are
551 * on our own owned list. */
552 if (tentry->flags & PRGRP) {
554 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
555 if (code) return code;
558 code = RemoveFromOrphan (at, tentry->id);
559 if (code) return code;
563 code = RemoveFromIDHash(at,tentry->id,&loc);
564 if (code != PRSUCCESS) return code;
565 code = RemoveFromNameHash(at,tentry->name,&loc);
566 if (code != PRSUCCESS) return code;
568 if (tentry->flags & PRGRP) {
569 afs_int32 loc = FindByID(at, tentry->creator);
570 struct prentry centry;
574 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
575 if (code) return code;
576 admin = ( (tentry->creator == SYSADMINID) ||
577 IsAMemberOf(at,tentry->creator,SYSADMINID) );
578 if (ntohl(centry.flags) & PRQUOTA) {
579 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
580 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
583 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
584 if (code) return code;
588 if (tentry->flags & PRGRP) {
589 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
591 else if (tentry->flags & PRINST) {
592 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
595 if (strchr(tentry->name,'@')) {
596 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
598 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
601 code = FreeBlock(at, loc);
605 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
608 * Note the entry is written out by this routine. */
610 afs_int32 AddToEntry (tt, entry, loc, aid)
611 struct ubik_trans *tt;
612 struct prentry *entry;
618 struct contentry nentry;
619 struct contentry aentry;
621 afs_int32 last; /* addr of last cont. block */
626 if (entry->id == aid) return PRINCONSISTENT;
627 #ifdef PR_REMEMBER_TIMES
628 entry->addTime = time(0);
630 for (i=0;i<PRSIZE;i++) {
631 if (entry->entries[i] == aid)
633 if (entry->entries[i] == PRBADID) { /* remember this spot */
637 else if (entry->entries[i] == 0) { /* end of the line */
647 while (nptr != (afs_int32)NULL) {
648 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
649 if (code != 0) return code;
651 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
652 for (i=0;i<COSIZE;i++) {
653 if (nentry.entries[i] == aid)
655 if (nentry.entries[i] == PRBADID) {
661 else if (nentry.entries[i] == 0) {
671 if (slot != -1) { /* we found a place */
673 if (first) { /* place is in first block */
674 entry->entries[slot] = aid;
675 code = pr_WriteEntry (tt, 0, loc, entry);
676 if (code != 0) return code;
679 code = pr_WriteEntry (tt, 0, loc, entry);
680 if (code) return code;
681 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
682 if (code != 0) return code;
683 aentry.entries[slot] = aid;
684 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
685 if (code != 0) return code;
688 /* have to allocate a continuation block if we got here */
689 nptr = AllocBlock(tt);
691 /* then we should tack new block after last block in cont. chain */
693 code = pr_WriteCoEntry(tt,0,last,&nentry);
694 if (code != 0) return code;
699 memset(&aentry, 0, sizeof(aentry));
700 aentry.flags |= PRCONT;
701 aentry.id = entry->id;
703 aentry.entries[0] = aid;
704 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
705 if (code != 0) return code;
706 /* don't forget to update count, here! */
708 code = pr_WriteEntry (tt, 0, loc, entry);
713 afs_int32 AddToPRList (alist, sizeP, id)
721 if (alist->prlist_len >= *sizeP) {
722 count = alist->prlist_len + 100;
723 if (alist->prlist_val) {
724 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
726 tmp = (char *) malloc(count*sizeof(afs_int32));
728 if (!tmp) return(PRNOMEM);
729 alist->prlist_val = (afs_int32 *)tmp;
732 alist->prlist_val[alist->prlist_len++] = id;
736 afs_int32 GetList (at, tentry, alist, add)
737 struct ubik_trans *at;
738 struct prentry *tentry;
744 struct contentry centry;
750 alist->prlist_val = 0;
751 alist->prlist_len = 0;
753 for (i=0;i<PRSIZE;i++) {
754 if (tentry->entries[i] == PRBADID) continue;
755 if (tentry->entries[i] == 0) break;
756 code = AddToPRList (alist, &size, tentry->entries[i]);
757 if (code) return code;
760 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
761 /* look through cont entries */
762 code = pr_ReadCoEntry(at,0,nptr,¢ry);
763 if (code != 0) return code;
764 for (i=0;i<COSIZE;i++) {
765 if (centry.entries[i] == PRBADID) continue;
766 if (centry.entries[i] == 0) break;
767 code = AddToPRList (alist, &size, centry.entries[i]);
768 if (code) return code;
770 if (count++ > 50) IOMGR_Poll(), count = 0;
773 if (add) { /* this is for a CPS, so tack on appropriate stuff */
774 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
775 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
776 (code = AddAuthGroup(tentry, alist, &size)) ||
777 (code = AddToPRList (alist, &size, tentry->id))) return code;
780 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
781 (code = AddToPRList (alist, &size, tentry->id))) return code;
784 if (alist->prlist_len > 100) IOMGR_Poll();
785 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
790 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
791 struct ubik_trans *at;
792 struct prentry *tentry;
793 struct prentry *tentry2;
799 struct contentry centry;
805 alist->prlist_val = 0;
806 alist->prlist_len = 0;
807 for (i=0;i<PRSIZE;i++) {
808 if (tentry->entries[i] == PRBADID) continue;
809 if (tentry->entries[i] == 0) break;
810 code = AddToPRList (alist, &size, tentry->entries[i]);
811 if (code) return code;
815 while (nptr != (afs_uint32)NULL) {
816 /* look through cont entries */
817 code = pr_ReadCoEntry(at,0,nptr,¢ry);
818 if (code != 0) return code;
819 for (i=0;i<COSIZE;i++) {
820 if (centry.entries[i] == PRBADID) continue;
821 if (centry.entries[i] == 0) break;
822 code = AddToPRList (alist, &size, centry.entries[i]);
823 if (code) return code;
826 if (count++ > 50) IOMGR_Poll(), count = 0;
829 for (i=0;i<PRSIZE;i++) {
830 if (tentry2->entries[i] == PRBADID) continue;
831 if (tentry2->entries[i] == 0) break;
832 code = AddToPRList (alist, &size, tentry2->entries[i]);
837 nptr = tentry2->next;
838 while (nptr != (afs_uint32)NULL) {
839 /* look through cont entries */
840 code = pr_ReadCoEntry(at,0,nptr,¢ry);
841 if (code != 0) break;
842 for (i=0;i<COSIZE;i++) {
843 if (centry.entries[i] == PRBADID) continue;
844 if (centry.entries[i] == 0) break;
845 code = AddToPRList (alist, &size, centry.entries[i]);
849 if (count++ > 50) IOMGR_Poll(), count = 0;
852 if (add) { /* this is for a CPS, so tack on appropriate stuff */
853 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
854 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
855 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
856 (code = AddToPRList (alist, &size, tentry->id))) return code;
859 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
860 (code = AddToPRList (alist, &size, tentry->id))) return code;
863 if (alist->prlist_len > 100) IOMGR_Poll();
864 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
868 afs_int32 GetOwnedChain (ut, next, alist)
869 struct ubik_trans *ut;
873 struct prentry tentry;
878 alist->prlist_val = 0;
879 alist->prlist_len = 0;
881 for (; *next; *next = ntohl(tentry.nextOwned)) {
882 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
883 if (code) return code;
884 code = AddToPRList (alist, &size, ntohl(tentry.id));
885 if (alist->prlist_len >= PR_MAXGROUPS) {
888 if (code) return code;
889 if (count++ > 50) IOMGR_Poll(), count = 0;
891 if (alist->prlist_len > 100) IOMGR_Poll();
892 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
896 afs_int32 GetMax(at,uid,gid)
897 struct ubik_trans *at;
901 *uid = ntohl(cheader.maxID);
902 *gid = ntohl(cheader.maxGroup);
906 afs_int32 SetMax(at,id,flag)
907 struct ubik_trans *at;
913 cheader.maxGroup = htonl(id);
914 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
915 if (code != 0) return code;
918 cheader.maxID = htonl(id);
919 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
920 if (code != 0) return code;
925 afs_int32 read_DbHeader(tt)
926 struct ubik_trans *tt;
930 if (!ubik_CacheUpdate(tt)) return 0;
932 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
934 com_err (whoami, code, "Couldn't read header");
945 struct ubik_trans *tt;
948 /* init the database. We'll try reading it, but if we're starting
949 * from scratch, we'll have to do a write transaction. */
951 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
953 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
954 if (code) return code;
955 code = ubik_SetLock(tt,1,1,LOCKREAD);
962 } else if (!ubik_CacheUpdate (tt)) {
963 code = ubik_EndTrans(tt);
967 len = sizeof(cheader);
968 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
970 com_err (whoami, code, "couldn't read header");
974 if ((ntohl(cheader.version) == PRDBVERSION) &&
975 ntohl(cheader.headerSize) == sizeof(cheader) &&
976 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
977 FindByID(tt,ANONYMOUSID) != 0){
978 /* database exists, so we don't have to build it */
979 code = ubik_EndTrans(tt);
980 if (code) return code;
983 /* else we need to build a database */
984 code = ubik_EndTrans(tt);
985 if (code) return code;
987 /* Only rebuild database if the db was deleted (the header is zero) and we
988 are running noAuth. */
989 { char *bp = (char *)&cheader;
991 for (i=0; i<sizeof(cheader); i++)
994 com_err (whoami, code,
995 "Can't rebuild database because it is not empty");
1001 com_err (whoami, code,
1002 "Can't rebuild database because not running NoAuth");
1006 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1007 if (code) return code;
1009 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1011 ubik_AbortTrans(tt);
1015 /* before doing a rebuild, check again that the dbase looks bad, because
1016 * the previous check was only under a ReadAny transaction, and there could
1017 * actually have been a good database out there. Now that we have a
1018 * real write transaction, make sure things are still bad.
1020 if ((ntohl(cheader.version) == PRDBVERSION) &&
1021 ntohl(cheader.headerSize) == sizeof(cheader) &&
1022 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1023 FindByID(tt,ANONYMOUSID) != 0){
1024 /* database exists, so we don't have to build it */
1025 code = ubik_EndTrans(tt);
1026 if (code) return code;
1030 /* Initialize the database header */
1031 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1032 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1033 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1034 com_err (whoami, code, "couldn't write header words");
1035 ubik_AbortTrans(tt);
1039 #define InitialGroup(id,name) do { \
1040 afs_int32 temp = (id); \
1041 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1042 code = CreateEntry \
1043 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1045 com_err (whoami, code, "couldn't create %s with id %di.", \
1047 ubik_AbortTrans(tt); \
1052 InitialGroup (SYSADMINID, "system:administrators");
1053 InitialGroup (SYSBACKUPID, "system:backup");
1054 InitialGroup (ANYUSERID, "system:anyuser");
1055 InitialGroup (AUTHUSERID, "system:authuser");
1056 InitialGroup (SYSVIEWERID, "system:ptsviewers");
1057 InitialGroup (ANONYMOUSID, "anonymous");
1059 /* Well, we don't really want the max id set to anonymousid, so we'll set
1061 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1063 com_err (whoami, code, "couldn't reset max id");
1064 ubik_AbortTrans(tt);
1068 code = ubik_EndTrans(tt);
1069 if (code) return code;
1073 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1074 struct ubik_trans *at;
1082 afs_int32 i, nptr, pos;
1083 struct contentry centry;
1084 struct prentry tentry, tent;
1087 char holder[PR_MAXNAMELEN];
1088 char temp[PR_MAXNAMELEN];
1089 char oldname[PR_MAXNAMELEN];
1092 memset(holder, 0, PR_MAXNAMELEN);
1093 memset(temp, 0, PR_MAXNAMELEN);
1094 loc = FindByID(at,aid);
1095 if (!loc) return PRNOENT;
1096 code = pr_ReadEntry(at,0,loc,&tentry);
1097 if (code) return PRDBFAIL;
1098 if (tentry.owner != cid &&
1099 !IsAMemberOf(at,cid,SYSADMINID) &&
1100 !IsAMemberOf(at,cid,tentry.owner) &&
1101 !pr_noAuth) return PRPERM;
1102 #ifdef PR_REMEMBER_TIMES
1103 tentry.changeTime = time(0);
1106 /* we're actually trying to change the id */
1107 if (newid && (newid != aid)) {
1108 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1110 pos = FindByID(at,newid);
1111 if (pos) return PRIDEXIST; /* new id already in use! */
1112 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1114 /* Should check that foreign users id to change to is good: inRange() */
1116 /* if new id is not in use, rehash things */
1117 code = RemoveFromIDHash(at,aid,&loc);
1118 if (code != PRSUCCESS) return code;
1120 code = pr_WriteEntry(at,0,loc,&tentry);
1121 if (code) return code;
1122 code = AddToIDHash(at,tentry.id,loc);
1123 if (code) return code;
1125 /* get current data */
1126 code = pr_ReadEntry(at, 0, loc, &tentry);
1127 if (code) return PRDBFAIL;
1129 /* Also change the references from the membership list */
1130 for (i=0; i<PRSIZE; i++) {
1131 if (tentry.entries[i] == PRBADID) continue;
1132 if (tentry.entries[i] == 0) break;
1133 pos = FindByID(at, tentry.entries[i]);
1134 if (!pos) return(PRDBFAIL);
1135 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1136 if (code) return code;
1137 code = pr_ReadEntry(at, 0, pos, &tent);
1138 if (code) return code;
1139 code = AddToEntry(at, &tent, pos, newid);
1140 if (code) return code;
1142 /* Look through cont entries too. This needs to be broken into
1143 * seperate transaction so that no one transaction becomes too
1144 * large to complete.
1146 for (nptr=tentry.next; nptr; nptr=centry.next) {
1147 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1148 if (code) return code;
1149 for (i=0; i<COSIZE; i++) {
1150 if (centry.entries[i] == PRBADID) continue;
1151 if (centry.entries[i] == 0) break;
1152 pos = FindByID(at, centry.entries[i]);
1153 if (!pos) return(PRDBFAIL);
1154 code = RemoveFromEntry(at, aid, centry.entries[i]);
1155 if (code) return code;
1156 code = pr_ReadEntry(at, 0, pos, &tent);
1157 if (code) return code;
1158 code = AddToEntry(at, &tent, pos, newid);
1159 if (code) return code;
1164 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
1166 /* Change the owner */
1167 if (oid && (oid != tentry.owner)) {
1168 /* only groups can have their owner's changed */
1169 if (!(tentry.flags & PRGRP)) return PRPERM;
1170 if (atsign != NULL) return PRPERM;
1171 oldowner = tentry.owner;
1173 /* The entry must be written through first so Remove and Add routines
1174 * can operate on disk data */
1175 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1176 if (code) return PRDBFAIL;
1178 /* switch owner chains */
1179 if (oldowner) /* if it has an owner */
1180 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1181 else /* must be an orphan */
1182 code = RemoveFromOrphan(at,tentry.id);
1183 if (code) return code;
1184 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1185 if (code) return code;
1187 /* fix up the name */
1188 if (strlen(name) == 0) name = tentry.name;
1189 /* get current data */
1190 code = pr_ReadEntry(at,0,loc,&tentry);
1191 if (code) return PRDBFAIL;
1194 /* Change the name, if name is a ptr to tentry.name then this name change
1195 * is due to a chown, otherwise caller has specified a new name */
1196 if ((name == tentry.name) ||
1197 (*name && (strcmp (tentry.name, name) != 0))) {
1198 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1199 if (tentry.flags & PRGRP) {
1200 /* don't let foreign cell groups change name */
1201 if (atsign != NULL) return PRPERM;
1202 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1203 if (code) return code;
1205 if (name == tentry.name) { /* owner fixup */
1206 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1207 } else { /* new name, caller must be correct */
1208 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1212 /* Allow a foreign name change only if the cellname part is
1217 newatsign = strchr(name, '@');
1218 if (newatsign != atsign){ /* if they are the same no problem*/
1219 /*if the pointers are not equal the strings better be */
1220 if ((atsign == NULL) || (newatsign == NULL) ||
1221 strcmp (atsign,newatsign)) return PRPERM;
1223 if (!CorrectUserName(name)) return PRBADNAM;
1226 pos = FindByName(at,name, &tent);
1227 if (pos) return PREXIST;
1228 code = RemoveFromNameHash (at, oldname, &loc);
1229 if (code != PRSUCCESS) return code;
1230 strncpy (tentry.name, name, PR_MAXNAMELEN);
1231 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1232 if (code) return PRDBFAIL;
1233 code = AddToNameHash(at,tentry.name,loc);
1234 if (code != PRSUCCESS) return code;
1241 afs_int32 allocNextId(cellEntry)
1242 struct prentry *cellEntry;
1244 /* Id's for foreign cell entries are constructed as follows:
1245 The 16 low order bits are the group id of the cell and the
1246 top 16 bits identify the particular users in that cell */
1251 id = (ntohl(cellEntry -> nusers) +1);
1252 cellEntry->nusers = htonl(id);
1253 /* use the field nusers to keep
1254 the next available id in that
1255 foreign cell's group. Note :
1256 It would seem more appropriate
1257 to use ngroup for that and nusers
1258 to enforce the quota, however pts
1259 does not have an option to change
1260 foreign users quota yet */
1262 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1266 int inRange(cellEntry,aid)
1267 struct prentry *cellEntry;
1270 afs_uint32 id,cellid,groupid;
1274 The only thing that we want to make sure here is that
1275 the id is in the legal range of this group. If it is
1276 a duplicate we don't care since it will get caught
1277 in a different check.
1280 cellid = aid & 0x0000ffff;
1281 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1282 if (cellid != groupid) return 0; /* not in range */
1285 if we got here we're ok but we need to update the nusers
1286 field in order to get the id correct the next time that
1287 we try to allocate it automatically
1291 if (id > ntohl(cellEntry -> nusers))
1292 cellEntry -> nusers = htonl(id);
1297 AddAuthGroup(tentry, alist, size)
1298 struct prentry *tentry;
1302 if (!(strchr(tentry->name, '@')))
1303 return (AddToPRList (alist, size, AUTHUSERID));