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 * (5) Add functions to process supergroups:
12 * ChangeIDEntry(), RemoveFromSGEntry(),
13 * AddToSGEntry(), GetListSG2().
14 * (6) Add code to existing functions to process
16 * 2/1/98 jjm Add mdw's changes for bit mapping for supergroups
18 * 09/26/02 kwc Move depthsg definition here from ptserver.c since
19 * pt_util needs it defined also, and this file is
20 * common between the two programs.
23 #include <afsconfig.h>
24 #include <afs/param.h>
29 #include <sys/types.h>
34 #include <netinet/in.h>
46 #include <afs/com_err.h>
47 #include <afs/cellconfig.h>
52 /* Foreign cells are represented by the group system:authuser@cell*/
53 #define AUTHUSER_GROUP "system:authuser"
56 extern struct ubik_dbase *dbase;
57 extern struct afsconf_dir *prdir;
61 extern afs_int32 AddToEntry();
62 static char *whoami = "ptserver";
64 #if defined(SUPERGROUPS)
68 afs_int32 depthsg = 5; /* Maximum iterations used during IsAMemberOF */
70 afs_int32 GetListSG2 (struct ubik_trans *at, afs_int32 gid, prlist *alist,
71 afs_int32 *sizeP, afs_int32 depth);
73 struct map *sg_flagged;
76 #define NIL_MAP ((struct map *) 0)
78 /* pt_mywrite hooks into the logic that writes ubik records to disk
79 * at a very low level. It invalidates mappings in sg_flagged/sg_found.
80 * By hoooking in at this level, we ensure that a ubik file reload
81 * invalidates our incore cache.
83 * We assert records, cheaders and everything else are 0 mod 64.
84 * So, we can always see the first 64 bytes of any record written.
85 * The stuff we're interested in (flags, id) are in the first 8 bytes.
86 * so we can always tell if we're writing a group record.
89 int (*pt_save_dbase_write)();
91 int pt_mywrite(tdb, fno, bp, pos, count)
92 struct ubik_dbase *tdb;
93 afs_int32 fno, pos, count;
96 afs_uint32 headersize = ntohl(cheader.headerSize);
98 if (fno == 0 && pos+count > headersize)
100 afs_int32 p, l, c, o;
117 fprintf (stderr,"Writing %d bytes of entry @ %#lx(+%d)\n",
119 else if (c == ENTRYSIZE)
120 fprintf (stderr,"Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n",
122 ((struct prentry *)cp)->flags,
123 (((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" :
124 (((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" :
125 (((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" :
126 (((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" :
127 (((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" :
128 (((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" :
129 (((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" :
131 ((struct prentry *)cp)->id);
133 fprintf (stderr,"Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n",
135 ((struct prentry *)cp)->flags,
136 (((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" :
137 (((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" :
138 (((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" :
139 (((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" :
140 (((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" :
141 (((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" :
142 (((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" :
144 ((struct prentry *)cp)->id);
146 fprintf (stderr,"Writing %d bytes of entry @ %#lx\n",
150 (((struct prentry *)cp)->flags&PRTYPE)==PRGRP)
153 if (in_map(sg_found, -((struct prentry *)cp)->id))fprintf(stderr,"Unfound: Removing group %d\n",
154 ((struct prentry *)cp)->id);
155 if (in_map(sg_flagged, -((struct prentry *)cp)->id))fprintf(stderr,"Unflag: Removing group %d\n",
156 ((struct prentry *)cp)->id);
158 sg_found = bic_map(sg_found, add_map(NIL_MAP,
159 -((struct prentry *)cp)->id));
160 sg_flagged = bic_map(sg_flagged, add_map(NIL_MAP,
161 -((struct prentry *)cp)->id));
168 return (*pt_save_dbase_write)(tdb, fno, bp, pos, count);
172 * this function attaches pt_mywrite. It's called once,
173 * just after ubik_ServerInit.
178 extern struct ubik_dbase *ubik_dbase;
179 if (ubik_dbase->write != pt_mywrite)
181 pt_save_dbase_write = ubik_dbase->write;
182 ubik_dbase->write = pt_mywrite;
186 #endif /* SUPERGROUPS */
188 /* CorrectUserName - Check to make sure a user name is OK. It must not include
189 * either a colon (or it would look like a group) or an atsign (or it would
190 * look like a foreign user). The length is checked as well to make sure
191 * that the user name, an atsign, and the local cell name will fit in
192 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
193 * a foreign user with our cell name tacked on. This is a predicate, so it
194 * return one if name is OK and zero if name is bogus. */
196 static int CorrectUserName (name)
199 extern int pr_realmNameLen;
201 /* We accept foreign names, so we will deal with '@' later */
202 if (strchr (name, ':') || strchr(name, '\n')) return 0;
203 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
207 /* CorrectGroupName - Like the above but handles more complicated cases caused
208 * by including the ownership in the name. The interface works by calculating
209 * the correct name based on a given name and owner. This allows easy use by
210 * rename, which then compares the correct name with the requested new name. */
212 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
213 struct ubik_trans *ut;
214 char aname[PR_MAXNAMELEN]; /* name for group */
215 afs_int32 cid; /* caller id */
216 afs_int32 oid; /* owner of group */
217 char cname[PR_MAXNAMELEN]; /* correct name for group */
221 char *prefix; /* ptr to group owner part */
222 char *suffix; /* ptr to group name part */
223 char name[PR_MAXNAMELEN]; /* correct name for group */
224 struct prentry tentry;
226 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
227 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
229 if (oid == 0) oid = cid;
231 /* Determine the correct prefix for the name. */
232 if (oid == SYSADMINID) prefix = "system";
234 afs_int32 loc = FindByID (ut, oid);
236 /* let admin create groups owned by non-existent ids (probably
237 * setting a group to own itself). Check that they look like
238 * groups (with a colon) or otherwise are good user names. */
240 strcpy (cname, aname);
245 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
246 if (code) return code;
247 if (ntohl(tentry.flags) & PRGRP) {
248 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
249 /* terminate prefix at colon if there is one */
250 if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
252 prefix = tentry.name;
254 /* only sysadmin allow to use 'system:' prefix */
255 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
257 strcpy (name, aname); /* in case aname & cname are same */
258 suffix = strchr(name, ':');
260 /* sysadmin can make groups w/o ':', but they must still look like
261 * legal user names. */
262 if (!admin) return PRBADNAM;
263 strcpy (cname, name);
266 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
267 strcpy (cname, prefix);
268 strcat (cname, suffix);
271 /* check for legal name with either group rules or user rules */
272 if ((suffix = strchr(cname, ':'))) {
273 /* check for confusing characters */
274 if (strchr(cname, '\n') || /* restrict so recreate can work */
275 strchr(suffix+1, ':')) /* avoid multiple colons */
278 if (!CorrectUserName (cname)) return PRBADNAM;
283 int AccessOK (ut, cid, tentry, mem, any)
284 struct ubik_trans *ut;
285 afs_int32 cid; /* caller id */
286 struct prentry *tentry; /* object being accessed */
287 int mem; /* check membership in aid, if group */
288 int any; /* if set return true */
293 if (pr_noAuth) return 1;
294 if (cid == SYSADMINID) return 1; /* special case fileserver */
296 flags = tentry->flags;
300 flags = oid = aid = 0;
302 if (!(flags & PRACCESS)) { /* provide default access */
304 flags |= PRP_GROUP_DEFAULT;
306 flags |= PRP_USER_DEFAULT;
309 if (flags & any) return 1;
312 IsAMemberOf (ut, cid, oid)) return 1;
314 if (aid > 0) { /* checking on a user */
315 if (aid == cid) return 1;
316 } else if (aid < 0) { /* checking on group */
317 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
319 /* Allow members of SYSVIEWERID to get membership and status only */
320 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM)||
321 (any == PRP_OWNED_ANY))&&(IsAMemberOf (ut, cid, SYSVIEWERID)))
323 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
324 return 0; /* no access */
327 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
328 struct ubik_trans *at;
329 char aname[PR_MAXNAMELEN];
336 /* get and init a new entry */
339 struct prentry tentry, tent;
342 memset(&tentry, 0, sizeof(tentry));
344 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
347 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
348 if (code) return code;
349 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
350 } else { /* non-group must not have colon */
351 if (!CorrectUserName(aname)) return PRBADNAM;
352 strcpy (tentry.name, aname);
355 if (FindByName(at,aname, &tent)) return PREXIST;
357 newEntry = AllocBlock(at);
358 if (!newEntry) return PRDBFAIL;
359 #ifdef PR_REMEMBER_TIMES
360 tentry.createTime = time(0);
364 tentry.flags = PRGRP;
366 } else if (flag == 0) {
368 tentry.owner = SYSADMINID;
373 atsign = strchr(aname, '@');
375 /* A normal user or group. Pick an id for it */
379 code= AllocID(at,flag,&tentry.id);
380 if (code != PRSUCCESS) return code;
382 } else if (flag & PRGRP) {
383 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
384 * Then pick an id for the group.
389 badFormat = strcmp(AUTHUSER_GROUP, aname);
391 if (badFormat) return PRBADNAM;
396 code= AllocID(at,flag,&tentry.id);
397 if (code != PRSUCCESS) return code;
400 /* A foreign user: <name>@<cell>. The foreign user is added to
401 * its representing group. It is
405 struct prentry centry;
406 extern afs_int32 allocNextId();
408 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
411 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
412 strcpy(cellGroup, AUTHUSER_GROUP);
413 strcat(cellGroup, atsign);
414 pos = FindByName(at, cellGroup, ¢ry);
415 if (!pos) return PRBADNAM;
416 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
417 if (code) return code;
419 /* cellid is the id of the group representing the cell */
420 tentry.cellid = ntohl(centry.id);
423 /* Check if id is good */
424 if (!inRange(¢ry,*aid)) return PRBADARG;
427 /* Allocate an ID special for this foreign user. It is based
428 * on the representing group's id and nusers count.
430 tentry.id = allocNextId(¢ry);
433 /* The foreign user will be added to the representing foreign
434 * group. The group can hold up to 30 entries.
436 if (!(ntohl(centry.flags) & PRQUOTA)) {
437 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
438 centry.ngroups = htonl(30);
440 n = ntohl(centry.ngroups);
441 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
442 centry.ngroups = htonl(n - 1);
444 /* write updated entry for group */
445 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
447 /* Now add the new user entry to the database */
448 tentry.creator = creator;
450 code = pr_WriteEntry(at, 0, newEntry, &tentry);
451 if (code) return PRDBFAIL;
452 code = AddToIDHash(at, *aid, newEntry);
453 if (code != PRSUCCESS) return code;
454 code = AddToNameHash(at, aname, newEntry);
455 if (code != PRSUCCESS) return code;
456 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
458 /* Now add the entry to the authuser group for this cell.
459 * We will reread the entries for the user and the group
460 * instead of modifying them before writing them in the
461 * previous steps. Although not very efficient, much simpler
463 pos = FindByID(at, tentry.cellid);
464 if (!pos) return PRBADNAM;
465 code = pr_ReadEntry (at, 0, pos, ¢ry);
466 if (code) return code;
467 code = AddToEntry(at, ¢ry, pos, *aid);
468 if (code) return code;
469 /* and now the user entry */
470 pos = FindByID(at,*aid);
471 if (!pos) return PRBADNAM;
472 code = pr_ReadEntry (at, 0, pos, &tentry);
473 if (code) return code;
474 code = AddToEntry(at, &tentry, pos, tentry.cellid);
475 if (code) return code;
480 /* Remember the largest group id or largest user id */
482 /* group ids are negative */
483 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
484 code = set_header_word (at, maxGroup, htonl(tentry.id));
485 if (code) return PRDBFAIL;
489 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
490 code = set_header_word (at, maxID, htonl(tentry.id));
491 if (code) return PRDBFAIL;
495 /* Charge the creator for this group */
497 afs_int32 loc = FindByID (at, creator);
498 struct prentry centry;
501 if (loc) { /* this should only fail during initialization */
502 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
503 if (code) return code;
505 /* If quota is uninitialized, do it */
506 if (!(ntohl(centry.flags) & PRQUOTA)) {
507 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
508 centry.ngroups = centry.nusers = htonl(20);
511 /* Admins don't get charged for creating a group.
512 * If in noAuth mode, you get changed for it but you
513 * are still allowed to create as many groups as you want.
515 admin = ( (creator == SYSADMINID) ||
516 IsAMemberOf(at,creator,SYSADMINID) );
518 if (ntohl(centry.ngroups) <= 0) {
519 if (!pr_noAuth) return PRNOMORE;
521 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
525 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
526 if (code) return code;
530 /* Initialize the quota for the user. Groups don't have their
533 tentry.flags |= PRQUOTA;
534 tentry.ngroups = tentry.nusers = 20;
537 tentry.creator = creator;
539 code = pr_WriteEntry(at, 0, newEntry, &tentry);
540 if (code) return PRDBFAIL;
541 code = AddToIDHash(at,*aid,newEntry);
542 if (code != PRSUCCESS) return code;
543 code = AddToNameHash(at,aname,newEntry);
544 if (code != PRSUCCESS) return code;
545 if (tentry.flags & PRGRP) {
546 code = AddToOwnerChain(at,tentry.id,oid);
547 if (code) return code;
549 if (tentry.flags & PRGRP) {
550 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
552 else if (tentry.flags & PRINST) {
553 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
556 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
562 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
563 * entry if appropriate */
565 afs_int32 RemoveFromEntry (at, aid, bid)
566 struct ubik_trans *at;
571 struct prentry tentry;
572 struct contentry centry;
573 struct contentry hentry;
579 if (aid == bid) return PRINCONSISTENT;
580 memset(&hentry, 0, sizeof(hentry));
581 temp = FindByID(at,bid);
582 if (temp == 0) return PRNOENT;
583 code = pr_ReadEntry(at, 0, temp, &tentry);
584 if (code != 0) return code;
585 #ifdef PR_REMEMBER_TIMES
586 tentry.removeTime = time(0);
588 for (i=0;i<PRSIZE;i++) {
589 if (tentry.entries[i] == aid) {
590 tentry.entries[i] = PRBADID;
592 code = pr_WriteEntry(at,0,temp,&tentry);
593 if (code != 0) return code;
596 if (tentry.entries[i] == 0) /* found end of list */
602 code = pr_ReadCoEntry(at,0,nptr,¢ry);
603 if (code != 0) return code;
604 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
605 for (i=0;i<COSIZE;i++) {
606 if (centry.entries[i] == aid) {
607 centry.entries[i] = PRBADID;
608 for (j=0;j<COSIZE;j++)
609 if (centry.entries[j] != PRBADID &&
610 centry.entries[j] != 0) break;
611 if (j == COSIZE) { /* can free this block */
613 tentry.next = centry.next;
616 hentry.next = centry.next;
617 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
618 if (code != 0) return code;
620 code = FreeBlock (at, nptr);
621 if (code) return code;
623 else { /* can't free it yet */
624 code = pr_WriteCoEntry(at,0,nptr,¢ry);
625 if (code != 0) return code;
628 code = pr_WriteEntry(at,0,temp,&tentry);
629 if (code) return PRDBFAIL;
632 if (centry.entries[i] == 0) return PRNOENT;
633 } /* for all coentry slots */
636 memcpy(&hentry, ¢ry, sizeof(centry));
637 } /* while there are coentries */
641 #if defined(SUPERGROUPS)
642 /* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
643 * entry if appropriate */
645 afs_int32 ChangeIDEntry (at, aid, newid, bid)
646 register struct ubik_trans *at;
647 register afs_int32 aid;
648 register afs_int32 bid;
651 register afs_int32 code;
652 struct prentry tentry;
653 struct contentry centry;
658 if (aid == bid) return PRINCONSISTENT;
659 temp = FindByID(at,bid);
663 code = pr_ReadEntry(at, 0, temp, &tentry);
664 if (code != 0) return code;
665 for (i=0;i<PRSIZE;i++) {
666 if (tentry.entries[i] == aid) {
667 tentry.entries[i] = newid;
668 code = pr_WriteEntry(at,0,temp,&tentry);
669 if (code != 0) return code;
672 if (tentry.entries[i] == 0) { /* found end of list */
678 while (nptr != NULL) {
679 code = pr_ReadCoEntry(at,0,nptr,¢ry);
680 if (code != 0) return code;
681 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
682 fprintf(stderr,"ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
683 bid, centry.id, centry.flags);
686 for (i=0;i<COSIZE;i++) {
687 if (centry.entries[i] == aid) {
688 centry.entries[i] = newid;
689 for (j=0;j<COSIZE;j++)
690 if (centry.entries[j] != PRBADID &&
691 centry.entries[j] != 0) break;
692 code = pr_WriteCoEntry(at,0,nptr,¢ry);
693 if (code != 0) return code;
696 if (centry.entries[i] == 0) {
699 } /* for all coentry slots */
701 } /* while there are coentries */
705 /* #ifdef SUPERGROUPS */
706 /* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
707 * continuation entry if appropriate */
709 afs_int32 RemoveFromSGEntry (at, aid, bid)
710 register struct ubik_trans *at;
711 register afs_int32 aid;
712 register afs_int32 bid;
714 register afs_int32 code;
715 struct prentry tentry;
716 struct prentryg *tentryg;
717 struct contentry centry;
718 struct contentry hentry;
724 if (aid == bid) return PRINCONSISTENT;
725 memset(&hentry, 0, sizeof(hentry));
726 temp = FindByID(at,bid);
730 code = pr_ReadEntry(at, 0, temp, &tentry);
731 if (code != 0) return code;
732 #ifdef PR_REMEMBER_TIMES
733 tentry.removeTime = time((afs_int32*)0);
735 tentryg = (struct prentryg *)&tentry;
736 for (i=0;i<SGSIZE;i++) {
737 if (tentryg->supergroup[i] == aid) {
738 tentryg->supergroup[i] = PRBADID;
740 code = pr_WriteEntry(at,0,temp,&tentry);
741 if (code != 0) return code;
744 if (tentryg->supergroup[i] == 0) { /* found end of list */
749 nptr = tentryg->nextsg;
750 while (nptr != NULL) {
751 code = pr_ReadCoEntry(at,0,nptr,¢ry);
752 if (code != 0) return code;
753 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
754 fprintf(stderr,"ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
755 bid, centry.id, centry.flags);
758 for (i=0;i<COSIZE;i++) {
759 if (centry.entries[i] == aid) {
760 centry.entries[i] = PRBADID;
761 for (j=0;j<COSIZE;j++)
762 if (centry.entries[j] != PRBADID &&
763 centry.entries[j] != 0) break;
764 if (j == COSIZE) { /* can free this block */
766 tentryg->nextsg = centry.next;
769 hentry.next = centry.next;
770 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
771 if (code != 0) return code;
773 code = FreeBlock (at, nptr);
774 if (code) return code;
776 else { /* can't free it yet */
777 code = pr_WriteCoEntry(at,0,nptr,¢ry);
778 if (code != 0) return code;
781 code = pr_WriteEntry(at,0,temp,&tentry);
782 if (code) return PRDBFAIL;
785 if (centry.entries[i] == 0) {
788 } /* for all coentry slots */
791 bcopy((char*)¢ry,(char*)&hentry,sizeof(centry));
792 } /* while there are coentries */
796 #endif /* SUPERGROUPS */
798 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
799 * groups, putting groups owned by it on orphan chain, and freeing the space */
801 afs_int32 DeleteEntry (at, tentry, loc)
802 struct ubik_trans *at;
803 struct prentry *tentry;
807 struct contentry centry;
811 if (strchr(tentry->name,'@')) {
812 if (tentry->flags & PRGRP) {
813 /* If there are still foreign user accounts from that cell
814 don't delete the group */
815 if (tentry->count) return PRBADARG;
819 afs_int32 loc = FindByID (at, tentry->cellid);
820 struct prentry centry;
822 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
823 if (code) return code;
824 if (ntohl(centry.flags) & PRQUOTA) {
825 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
827 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
828 if (code) return code;
832 /* First remove the entire membership list */
833 for (i=0;i<PRSIZE;i++) {
834 if (tentry->entries[i] == PRBADID) continue;
835 if (tentry->entries[i] == 0) break;
836 #if defined(SUPERGROUPS)
837 if ((tentry->flags & PRGRP) && tentry->entries[i] < 0) /* Supergroup */
838 code = RemoveFromSGEntry (at, tentry->id, tentry->entries[i]);
841 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
842 if (code) return code;
844 #if defined(SUPERGROUPS)
846 struct prentryg *tentryg = (struct prentryg *)tentry;
848 /* Then remove the entire supergroup list */
849 for (i=0;i<SGSIZE;i++) {
850 if (tentryg->supergroup[i] == PRBADID) continue;
851 if (tentryg->supergroup[i] == 0) break;
852 code = RemoveFromEntry (at, tentry->id, tentryg->supergroup[i]);
853 if (code) return code;
856 #endif /* SUPERGROUPS */
858 while (nptr != (afs_int32)NULL) {
859 code = pr_ReadCoEntry(at,0,nptr,¢ry);
860 if (code != 0) return PRDBFAIL;
861 for (i=0;i<COSIZE;i++) {
862 if (centry.entries[i] == PRBADID) continue;
863 if (centry.entries[i] == 0) break;
864 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
865 if (code) return code;
867 code = FreeBlock (at, nptr); /* free continuation block */
868 if (code) return code;
872 /* Remove us from other's owned chain. Note that this will zero our owned
873 * field (on disk) so this step must follow the above step in case we are
874 * on our own owned list. */
875 if (tentry->flags & PRGRP) {
877 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
878 if (code) return code;
881 code = RemoveFromOrphan (at, tentry->id);
882 if (code) return code;
886 code = RemoveFromIDHash(at,tentry->id,&loc);
887 if (code != PRSUCCESS) return code;
888 code = RemoveFromNameHash(at,tentry->name,&loc);
889 if (code != PRSUCCESS) return code;
891 if (tentry->flags & PRGRP) {
892 afs_int32 loc = FindByID(at, tentry->creator);
893 struct prentry centry;
897 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
898 if (code) return code;
899 admin = ( (tentry->creator == SYSADMINID) ||
900 IsAMemberOf(at,tentry->creator,SYSADMINID) );
901 if (ntohl(centry.flags) & PRQUOTA) {
902 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
903 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
906 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
907 if (code) return code;
911 if (tentry->flags & PRGRP) {
912 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
914 else if (tentry->flags & PRINST) {
915 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
918 if (strchr(tentry->name,'@')) {
919 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
921 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
924 code = FreeBlock(at, loc);
928 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
931 * Note the entry is written out by this routine. */
933 afs_int32 AddToEntry (tt, entry, loc, aid)
934 struct ubik_trans *tt;
935 struct prentry *entry;
941 struct contentry nentry;
942 struct contentry aentry;
944 afs_int32 last; /* addr of last cont. block */
949 if (entry->id == aid) return PRINCONSISTENT;
950 #ifdef PR_REMEMBER_TIMES
951 entry->addTime = time(0);
953 for (i=0;i<PRSIZE;i++) {
954 if (entry->entries[i] == aid)
956 if (entry->entries[i] == PRBADID) { /* remember this spot */
960 else if (entry->entries[i] == 0) { /* end of the line */
970 while (nptr != (afs_int32)NULL) {
971 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
972 if (code != 0) return code;
974 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
975 for (i=0;i<COSIZE;i++) {
976 if (nentry.entries[i] == aid)
978 if (nentry.entries[i] == PRBADID) {
984 else if (nentry.entries[i] == 0) {
994 if (slot != -1) { /* we found a place */
996 if (first) { /* place is in first block */
997 entry->entries[slot] = aid;
998 code = pr_WriteEntry (tt, 0, loc, entry);
999 if (code != 0) return code;
1002 code = pr_WriteEntry (tt, 0, loc, entry);
1003 if (code) return code;
1004 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
1005 if (code != 0) return code;
1006 aentry.entries[slot] = aid;
1007 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
1008 if (code != 0) return code;
1011 /* have to allocate a continuation block if we got here */
1012 nptr = AllocBlock(tt);
1014 /* then we should tack new block after last block in cont. chain */
1016 code = pr_WriteCoEntry(tt,0,last,&nentry);
1017 if (code != 0) return code;
1022 memset(&aentry, 0, sizeof(aentry));
1023 aentry.flags |= PRCONT;
1024 aentry.id = entry->id;
1026 aentry.entries[0] = aid;
1027 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
1028 if (code != 0) return code;
1029 /* don't forget to update count, here! */
1031 code = pr_WriteEntry (tt, 0, loc, entry);
1036 #if defined(SUPERGROUPS)
1038 /* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
1039 * continuation block if needed.
1041 * Note the entry is written out by this routine. */
1043 afs_int32 AddToSGEntry (tt, entry, loc, aid)
1044 struct ubik_trans *tt;
1045 struct prentry *entry;
1049 register afs_int32 code;
1051 struct contentry nentry;
1052 struct contentry aentry;
1053 struct prentryg *entryg;
1055 afs_int32 last; /* addr of last cont. block */
1056 afs_int32 first = 0;
1058 afs_int32 slot = -1;
1060 if (entry->id == aid) return PRINCONSISTENT;
1061 #ifdef PR_REMEMBER_TIMES
1062 entry->addTime = time((afs_int32*)0);
1064 entryg = (struct prentryg *)entry;
1065 for (i=0;i<SGSIZE;i++) {
1066 if (entryg->supergroup[i] == aid)
1068 if (entryg->supergroup[i] == PRBADID) { /* remember this spot */
1072 else if (entryg->supergroup[i] == 0) { /* end of the line */
1081 nptr = entryg->nextsg;
1082 while (nptr != NULL) {
1083 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
1084 if (code != 0) return code;
1086 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
1087 for (i=0;i<COSIZE;i++) {
1088 if (nentry.entries[i] == aid)
1090 if (nentry.entries[i] == PRBADID) {
1096 else if (nentry.entries[i] == 0) {
1106 if (slot != -1) { /* we found a place */
1108 if (first) { /* place is in first block */
1109 entryg->supergroup[slot] = aid;
1110 code = pr_WriteEntry (tt, 0, loc, entry);
1111 if (code != 0) return code;
1114 code = pr_WriteEntry (tt, 0, loc, entry);
1115 if (code) return code;
1116 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
1117 if (code != 0) return code;
1118 aentry.entries[slot] = aid;
1119 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
1120 if (code != 0) return code;
1123 /* have to allocate a continuation block if we got here */
1124 nptr = AllocBlock(tt);
1126 /* then we should tack new block after last block in cont. chain */
1128 code = pr_WriteCoEntry(tt,0,last,&nentry);
1129 if (code != 0) return code;
1132 entryg->nextsg = nptr;
1134 memset(&aentry, 0, sizeof(aentry));
1135 aentry.flags |= PRCONT;
1136 aentry.id = entry->id;
1138 aentry.entries[0] = aid;
1139 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
1140 if (code != 0) return code;
1141 /* don't forget to update count, here! */
1143 code = pr_WriteEntry (tt, 0, loc, entry);
1147 #endif /* SUPERGROUPS */
1149 afs_int32 AddToPRList (alist, sizeP, id)
1157 if (alist->prlist_len >= *sizeP) {
1158 count = alist->prlist_len + 100;
1159 if (alist->prlist_val) {
1160 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
1162 tmp = (char *) malloc(count*sizeof(afs_int32));
1164 if (!tmp) return(PRNOMEM);
1165 alist->prlist_val = (afs_int32 *)tmp;
1168 alist->prlist_val[alist->prlist_len++] = id;
1172 afs_int32 GetList (at, tentry, alist, add)
1173 struct ubik_trans *at;
1174 struct prentry *tentry;
1180 struct contentry centry;
1186 alist->prlist_val = 0;
1187 alist->prlist_len = 0;
1189 for (i=0;i<PRSIZE;i++) {
1190 if (tentry->entries[i] == PRBADID) continue;
1191 if (tentry->entries[i] == 0) break;
1192 code = AddToPRList (alist, &size, tentry->entries[i]);
1193 if (code) return code;
1194 #if defined(SUPERGROUPS)
1196 code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg);
1197 if (code) return code;
1201 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
1202 /* look through cont entries */
1203 code = pr_ReadCoEntry(at,0,nptr,¢ry);
1204 if (code != 0) return code;
1205 for (i=0;i<COSIZE;i++) {
1206 if (centry.entries[i] == PRBADID) continue;
1207 if (centry.entries[i] == 0) break;
1208 code = AddToPRList (alist, &size, centry.entries[i]);
1209 if (code) return code;
1210 #if defined(SUPERGROUPS)
1212 code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg);
1213 if (code) return code;
1216 if (count++ > 50) IOMGR_Poll(), count = 0;
1219 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1220 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1221 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
1222 (code = AddAuthGroup(tentry, alist, &size)) ||
1223 (code = AddToPRList (alist, &size, tentry->id))) return code;
1226 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
1227 (code = AddToPRList (alist, &size, tentry->id))) return code;
1230 if (alist->prlist_len > 100) IOMGR_Poll();
1231 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
1236 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
1237 struct ubik_trans *at;
1238 struct prentry *tentry;
1239 struct prentry *tentry2;
1245 struct contentry centry;
1251 alist->prlist_val = 0;
1252 alist->prlist_len = 0;
1253 for (i=0;i<PRSIZE;i++) {
1254 if (tentry->entries[i] == PRBADID) continue;
1255 if (tentry->entries[i] == 0) break;
1256 code = AddToPRList (alist, &size, tentry->entries[i]);
1257 if (code) return code;
1258 #if defined(SUPERGROUPS)
1260 code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg);
1261 if (code) return code;
1265 nptr = tentry->next;
1266 while (nptr != (afs_uint32)NULL) {
1267 /* look through cont entries */
1268 code = pr_ReadCoEntry(at,0,nptr,¢ry);
1269 if (code != 0) return code;
1270 for (i=0;i<COSIZE;i++) {
1271 if (centry.entries[i] == PRBADID) continue;
1272 if (centry.entries[i] == 0) break;
1273 code = AddToPRList (alist, &size, centry.entries[i]);
1274 if (code) return code;
1275 #if defined(SUPERGROUPS)
1277 code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg);
1278 if (code) return code;
1282 if (count++ > 50) IOMGR_Poll(), count = 0;
1285 for (i=0;i<PRSIZE;i++) {
1286 if (tentry2->entries[i] == PRBADID) continue;
1287 if (tentry2->entries[i] == 0) break;
1288 code = AddToPRList (alist, &size, tentry2->entries[i]);
1293 nptr = tentry2->next;
1294 while (nptr != (afs_uint32)NULL) {
1295 /* look through cont entries */
1296 code = pr_ReadCoEntry(at,0,nptr,¢ry);
1297 if (code != 0) break;
1298 for (i=0;i<COSIZE;i++) {
1299 if (centry.entries[i] == PRBADID) continue;
1300 if (centry.entries[i] == 0) break;
1301 code = AddToPRList (alist, &size, centry.entries[i]);
1305 if (count++ > 50) IOMGR_Poll(), count = 0;
1308 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1309 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1310 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
1311 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
1312 (code = AddToPRList (alist, &size, tentry->id))) return code;
1315 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
1316 (code = AddToPRList (alist, &size, tentry->id))) return code;
1319 if (alist->prlist_len > 100) IOMGR_Poll();
1320 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
1324 #if defined(SUPERGROUPS)
1326 afs_int32 GetListSG2 (at, gid, alist, sizeP, depth)
1327 struct ubik_trans *at;
1333 register afs_int32 code;
1334 struct prentry tentry;
1335 struct prentryg *tentryg = (struct prentryg *)&tentry;
1337 struct contentry centry;
1343 int predictfound, predictflagged;
1348 if (!in_map(sg_flagged, -gid))
1351 fprintf(stderr,"GetListSG2: I have not yet searched for gid=%d\n", gid);
1353 else if (predictflagged = 1, in_map(sg_found, -gid)) {
1356 "GetListSG2: I have already searched for gid=%d, and predict success.\n",
1361 if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) {
1364 "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
1371 if (depth < 1) return 0;
1372 temp = FindByID (at, gid);
1377 code = pr_ReadEntry (at, 0, temp, &tentry);
1378 if (code) return code;
1380 fprintf (stderr,"GetListSG2: lookup for gid=%d [\n", gid);
1384 for (i=0;i<SGSIZE;i++) {
1385 if (tentryg->supergroup[i] == PRBADID) continue;
1386 if (tentryg->supergroup[i] == 0) break;
1389 fprintf (stderr,"via gid=%d, added %d\n", gid, e.tentryg.supergroup[i]);
1391 code = AddToPRList (alist, sizeP, tentryg->supergroup[i]);
1392 if (code) return code;
1393 code = GetListSG2 (at, tentryg->supergroup[i], alist, sizeP, depth-1);
1394 if (code) return code;
1397 nptr = tentryg->nextsg;
1398 while (nptr != NULL) {
1400 /* look through cont entries */
1401 code = pr_ReadCoEntry(at,0,nptr,¢ry);
1402 if (code != 0) return code;
1403 for (i=0;i<COSIZE;i++) {
1404 if (centry.entries[i] == PRBADID) continue;
1405 if (centry.entries[i] == 0) break;
1407 fprintf (stderr,"via gid=%d, added %d\n", gid, e.centry.entries[i]);
1409 code = AddToPRList (alist, sizeP, centry.entries[i]);
1410 if (code) return code;
1411 code = GetListSG2 (at, centry.entries[i], alist, sizeP, depth-1);
1412 if (code) return code;
1415 if (count++ > 50) IOMGR_Poll(), count = 0;
1418 fprintf (stderr,"] for gid %d, done [flag=%s]\n", gid, didsomething ? "TRUE" : "FALSE");
1419 if (predictflagged && didsomething != predictfound)
1420 fprintf (stderr,"**** for gid=%d, didsomething=%d predictfound=%d\n",
1421 didsomething, predictfound);
1424 sg_found = add_map(sg_found, -gid);
1425 else sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid));
1426 sg_flagged = add_map(sg_flagged, -gid);
1430 afs_int32 GetSGList (at, tentry, alist)
1431 struct ubik_trans *at;
1432 struct prentry *tentry;
1435 register afs_int32 code;
1437 struct contentry centry;
1438 struct prentryg *tentryg;
1444 alist->prlist_val = 0;
1445 alist->prlist_len = 0;
1447 tentryg = (struct prentryg *)tentry;
1448 for (i=0;i<SGSIZE;i++) {
1449 if (tentryg->supergroup[i] == PRBADID) continue;
1450 if (tentryg->supergroup[i] == 0) break;
1451 code = AddToPRList (alist, &size, tentryg->supergroup[i]);
1452 if (code) return code;
1455 nptr = tentryg->nextsg;
1456 while (nptr != NULL) {
1457 /* look through cont entries */
1458 code = pr_ReadCoEntry(at,0,nptr,¢ry);
1459 if (code != 0) return code;
1460 for (i=0;i<COSIZE;i++) {
1461 if (centry.entries[i] == PRBADID) continue;
1462 if (centry.entries[i] == 0) break;
1463 code = AddToPRList (alist, &size, centry.entries[i]);
1464 if (code) return code;
1467 if (count++ > 50) IOMGR_Poll(), count = 0;
1470 if (alist->prlist_len > 100) IOMGR_Poll();
1471 qsort((char*)alist->prlist_val,(int)alist->prlist_len,sizeof(afs_int32),IDCmp);
1474 #endif /* SUPERGROUPS */
1476 afs_int32 GetOwnedChain (ut, next, alist)
1477 struct ubik_trans *ut;
1481 struct prentry tentry;
1486 alist->prlist_val = 0;
1487 alist->prlist_len = 0;
1489 for (; *next; *next = ntohl(tentry.nextOwned)) {
1490 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
1491 if (code) return code;
1492 code = AddToPRList (alist, &size, ntohl(tentry.id));
1493 if (alist->prlist_len >= PR_MAXGROUPS) {
1496 if (code) return code;
1497 if (count++ > 50) IOMGR_Poll(), count = 0;
1499 if (alist->prlist_len > 100) IOMGR_Poll();
1500 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
1504 afs_int32 GetMax(at,uid,gid)
1505 struct ubik_trans *at;
1509 *uid = ntohl(cheader.maxID);
1510 *gid = ntohl(cheader.maxGroup);
1514 afs_int32 SetMax(at,id,flag)
1515 struct ubik_trans *at;
1521 cheader.maxGroup = htonl(id);
1522 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
1523 if (code != 0) return code;
1526 cheader.maxID = htonl(id);
1527 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
1528 if (code != 0) return code;
1533 afs_int32 read_DbHeader(tt)
1534 struct ubik_trans *tt;
1538 if (!ubik_CacheUpdate(tt)) return 0;
1540 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1542 com_err (whoami, code, "Couldn't read header");
1553 struct ubik_trans *tt;
1556 /* init the database. We'll try reading it, but if we're starting
1557 * from scratch, we'll have to do a write transaction. */
1559 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
1561 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
1562 if (code) return code;
1563 code = ubik_SetLock(tt,1,1,LOCKREAD);
1565 ubik_AbortTrans(tt);
1570 } else if (!ubik_CacheUpdate (tt)) {
1571 code = ubik_EndTrans(tt);
1575 len = sizeof(cheader);
1576 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
1578 com_err (whoami, code, "couldn't read header");
1579 ubik_AbortTrans(tt);
1582 if ((ntohl(cheader.version) == PRDBVERSION) &&
1583 ntohl(cheader.headerSize) == sizeof(cheader) &&
1584 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1585 FindByID(tt,ANONYMOUSID) != 0){
1586 /* database exists, so we don't have to build it */
1587 code = ubik_EndTrans(tt);
1588 if (code) return code;
1591 /* else we need to build a database */
1592 code = ubik_EndTrans(tt);
1593 if (code) return code;
1595 /* Only rebuild database if the db was deleted (the header is zero) and we
1596 are running noAuth. */
1597 { char *bp = (char *)&cheader;
1599 for (i=0; i<sizeof(cheader); i++)
1602 com_err (whoami, code,
1603 "Can't rebuild database because it is not empty");
1609 com_err (whoami, code,
1610 "Can't rebuild database because not running NoAuth");
1614 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1615 if (code) return code;
1617 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1619 ubik_AbortTrans(tt);
1623 /* before doing a rebuild, check again that the dbase looks bad, because
1624 * the previous check was only under a ReadAny transaction, and there could
1625 * actually have been a good database out there. Now that we have a
1626 * real write transaction, make sure things are still bad.
1628 if ((ntohl(cheader.version) == PRDBVERSION) &&
1629 ntohl(cheader.headerSize) == sizeof(cheader) &&
1630 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1631 FindByID(tt,ANONYMOUSID) != 0){
1632 /* database exists, so we don't have to build it */
1633 code = ubik_EndTrans(tt);
1634 if (code) return code;
1638 /* Initialize the database header */
1639 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1640 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1641 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1642 com_err (whoami, code, "couldn't write header words");
1643 ubik_AbortTrans(tt);
1647 #define InitialGroup(id,name) do { \
1648 afs_int32 temp = (id); \
1649 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1650 code = CreateEntry \
1651 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1653 com_err (whoami, code, "couldn't create %s with id %di.", \
1655 ubik_AbortTrans(tt); \
1660 InitialGroup (SYSADMINID, "system:administrators");
1661 InitialGroup (SYSBACKUPID, "system:backup");
1662 InitialGroup (ANYUSERID, "system:anyuser");
1663 InitialGroup (AUTHUSERID, "system:authuser");
1664 InitialGroup (SYSVIEWERID, "system:ptsviewers");
1665 InitialGroup (ANONYMOUSID, "anonymous");
1667 /* Well, we don't really want the max id set to anonymousid, so we'll set
1669 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1671 com_err (whoami, code, "couldn't reset max id");
1672 ubik_AbortTrans(tt);
1676 code = ubik_EndTrans(tt);
1677 if (code) return code;
1681 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1682 struct ubik_trans *at;
1690 afs_int32 i, nptr, pos;
1691 #if defined(SUPERGROUPS)
1694 struct contentry centry;
1695 struct prentry tentry, tent;
1698 char holder[PR_MAXNAMELEN];
1699 char temp[PR_MAXNAMELEN];
1700 char oldname[PR_MAXNAMELEN];
1703 memset(holder, 0, PR_MAXNAMELEN);
1704 memset(temp, 0, PR_MAXNAMELEN);
1705 loc = FindByID(at,aid);
1706 if (!loc) return PRNOENT;
1707 code = pr_ReadEntry(at,0,loc,&tentry);
1708 if (code) return PRDBFAIL;
1709 if (tentry.owner != cid &&
1710 !IsAMemberOf(at,cid,SYSADMINID) &&
1711 !IsAMemberOf(at,cid,tentry.owner) &&
1712 !pr_noAuth) return PRPERM;
1713 #ifdef PR_REMEMBER_TIMES
1714 tentry.changeTime = time(0);
1717 /* we're actually trying to change the id */
1718 if (newid && (newid != aid)) {
1719 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1721 pos = FindByID(at,newid);
1722 if (pos) return PRIDEXIST; /* new id already in use! */
1723 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1725 /* Should check that foreign users id to change to is good: inRange() */
1727 /* if new id is not in use, rehash things */
1728 code = RemoveFromIDHash(at,aid,&loc);
1729 if (code != PRSUCCESS) return code;
1731 code = pr_WriteEntry(at,0,loc,&tentry);
1732 if (code) return code;
1733 code = AddToIDHash(at,tentry.id,loc);
1734 if (code) return code;
1736 /* get current data */
1737 code = pr_ReadEntry(at, 0, loc, &tentry);
1738 if (code) return PRDBFAIL;
1740 #if defined(SUPERGROUPS)
1741 if (tentry.id > (afs_int32)ntohl(cheader.maxID))
1742 code = set_header_word (at, maxID, htonl(tentry.id));
1743 if (code) return PRDBFAIL;
1745 /* need to fix up: membership
1750 for (i=0;i<PRSIZE;i++) {
1751 if (tentry.entries[i] == PRBADID) continue;
1752 if (tentry.entries[i] == 0) break;
1753 if ((tentry.flags & PRGRP) && tentry.entries[i] < 0) { /* Supergroup */
1754 return 5; /* not yet, in short. */
1757 code = ChangeIDEntry (at, aid, newid, tentry.entries[i]);
1759 if (code) return code;
1761 for (pos = ntohl(tentry.owned); pos; pos = nextpos) {
1762 code = pr_ReadEntry(at, 0, pos, &tent);
1765 nextpos = tent.nextOwned;
1766 code = pr_WriteEntry(at, 0, pos, &tent);
1770 while (pos != NULL) {
1771 #define centry (*(struct contentry*)&tent)
1772 code = pr_ReadCoEntry(at,0,pos,¢ry);
1773 if ((centry.id != aid)
1774 || !(centry.flags & PRCONT)) {
1775 fprintf(stderr,"ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
1776 aid, centry.id, centry.flags);
1780 for (i=0;i<COSIZE;i++) {
1781 if (centry.entries[i] == PRBADID) continue;
1782 if (centry.entries[i] == 0) break;
1783 if ((centry.flags & PRGRP) && centry.entries[i] < 0) { /* Supergroup */
1784 return 5; /* not yet, in short. */
1787 code = ChangeIDEntry (at, aid, newid, centry.entries[i]);
1789 if (code) return code;
1791 code = pr_WriteCoEntry (at, 0, pos, ¢ry);
1795 if (code) return code;
1797 #else /* SUPERGROUPS */
1800 /* Also change the references from the membership list */
1801 for (i=0; i<PRSIZE; i++) {
1802 if (tentry.entries[i] == PRBADID) continue;
1803 if (tentry.entries[i] == 0) break;
1804 pos = FindByID(at, tentry.entries[i]);
1805 if (!pos) return(PRDBFAIL);
1806 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1807 if (code) return code;
1808 code = pr_ReadEntry(at, 0, pos, &tent);
1809 if (code) return code;
1810 code = AddToEntry(at, &tent, pos, newid);
1811 if (code) return code;
1813 /* Look through cont entries too. This needs to be broken into
1814 * seperate transaction so that no one transaction becomes too
1815 * large to complete.
1817 for (nptr=tentry.next; nptr; nptr=centry.next) {
1818 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1819 if (code) return code;
1820 for (i=0; i<COSIZE; i++) {
1821 if (centry.entries[i] == PRBADID) continue;
1822 if (centry.entries[i] == 0) break;
1823 pos = FindByID(at, centry.entries[i]);
1824 if (!pos) return(PRDBFAIL);
1825 code = RemoveFromEntry(at, aid, centry.entries[i]);
1826 if (code) return code;
1827 code = pr_ReadEntry(at, 0, pos, &tent);
1828 if (code) return code;
1829 code = AddToEntry(at, &tent, pos, newid);
1830 if (code) return code;
1833 #endif /* SUPERGROUPS */
1836 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
1838 /* Change the owner */
1839 if (oid && (oid != tentry.owner)) {
1840 /* only groups can have their owner's changed */
1841 if (!(tentry.flags & PRGRP)) return PRPERM;
1842 if (atsign != NULL) return PRPERM;
1843 oldowner = tentry.owner;
1845 /* The entry must be written through first so Remove and Add routines
1846 * can operate on disk data */
1847 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1848 if (code) return PRDBFAIL;
1850 /* switch owner chains */
1851 if (oldowner) /* if it has an owner */
1852 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1853 else /* must be an orphan */
1854 code = RemoveFromOrphan(at,tentry.id);
1855 if (code) return code;
1856 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1857 if (code) return code;
1859 /* fix up the name */
1860 if (strlen(name) == 0) name = tentry.name;
1861 /* get current data */
1862 code = pr_ReadEntry(at,0,loc,&tentry);
1863 if (code) return PRDBFAIL;
1866 /* Change the name, if name is a ptr to tentry.name then this name change
1867 * is due to a chown, otherwise caller has specified a new name */
1868 if ((name == tentry.name) ||
1869 (*name && (strcmp (tentry.name, name) != 0))) {
1870 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1871 if (tentry.flags & PRGRP) {
1872 /* don't let foreign cell groups change name */
1873 if (atsign != NULL) return PRPERM;
1874 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1875 if (code) return code;
1877 if (name == tentry.name) { /* owner fixup */
1878 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1879 } else { /* new name, caller must be correct */
1880 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1884 /* Allow a foreign name change only if the cellname part is
1889 newatsign = strchr(name, '@');
1890 if (newatsign != atsign){ /* if they are the same no problem*/
1891 /*if the pointers are not equal the strings better be */
1892 if ((atsign == NULL) || (newatsign == NULL) ||
1893 strcmp (atsign,newatsign)) return PRPERM;
1895 if (!CorrectUserName(name)) return PRBADNAM;
1898 pos = FindByName(at,name, &tent);
1899 if (pos) return PREXIST;
1900 code = RemoveFromNameHash (at, oldname, &loc);
1901 if (code != PRSUCCESS) return code;
1902 strncpy (tentry.name, name, PR_MAXNAMELEN);
1903 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1904 if (code) return PRDBFAIL;
1905 code = AddToNameHash(at,tentry.name,loc);
1906 if (code != PRSUCCESS) return code;
1913 afs_int32 allocNextId(cellEntry)
1914 struct prentry *cellEntry;
1916 /* Id's for foreign cell entries are constructed as follows:
1917 The 16 low order bits are the group id of the cell and the
1918 top 16 bits identify the particular users in that cell */
1923 id = (ntohl(cellEntry -> nusers) +1);
1924 cellEntry->nusers = htonl(id);
1925 /* use the field nusers to keep
1926 the next available id in that
1927 foreign cell's group. Note :
1928 It would seem more appropriate
1929 to use ngroup for that and nusers
1930 to enforce the quota, however pts
1931 does not have an option to change
1932 foreign users quota yet */
1934 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1938 int inRange(cellEntry,aid)
1939 struct prentry *cellEntry;
1942 afs_uint32 id,cellid,groupid;
1946 The only thing that we want to make sure here is that
1947 the id is in the legal range of this group. If it is
1948 a duplicate we don't care since it will get caught
1949 in a different check.
1952 cellid = aid & 0x0000ffff;
1953 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1954 if (cellid != groupid) return 0; /* not in range */
1957 if we got here we're ok but we need to update the nusers
1958 field in order to get the id correct the next time that
1959 we try to allocate it automatically
1963 if (id > ntohl(cellEntry -> nusers))
1964 cellEntry -> nusers = htonl(id);
1969 AddAuthGroup(tentry, alist, size)
1970 struct prentry *tentry;
1974 if (!(strchr(tentry->name, '@')))
1975 return (AddToPRList (alist, size, AUTHUSERID));