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>
32 #include <afs/com_err.h>
33 #include <afs/cellconfig.h>
37 #include "ptprototypes.h"
39 /* Foreign cells are represented by the group system:authuser@cell*/
40 #define AUTHUSER_GROUP "system:authuser"
42 extern int restricted
;
43 extern struct ubik_dbase
*dbase
;
44 extern struct afsconf_dir
*prdir
;
47 static int inRange(struct prentry
*cellEntry
, afs_int32 aid
);
48 static afs_int32
allocNextId(struct ubik_trans
*, struct prentry
*);
49 static int AddAuthGroup(struct prentry
*tentry
, prlist
*alist
, afs_int32
*size
);
51 static char *whoami
= "ptserver";
53 int prp_user_default
= PRP_USER_DEFAULT
;
54 int prp_group_default
= PRP_GROUP_DEFAULT
;
56 #if defined(SUPERGROUPS)
60 afs_int32 depthsg
= 5; /* Maximum iterations used during IsAMemberOF */
61 afs_int32
GetListSG2(struct ubik_trans
*at
, afs_int32 gid
, prlist
* alist
,
62 afs_int32
* sizeP
, afs_int32 depth
);
64 struct map
*sg_flagged
;
67 #define NIL_MAP ((struct map *) 0)
69 /* pt_mywrite hooks into the logic that writes ubik records to disk
70 * at a very low level. It invalidates mappings in sg_flagged/sg_found.
71 * By hoooking in at this level, we ensure that a ubik file reload
72 * invalidates our incore cache.
74 * We assert records, cheaders and everything else are 0 mod 64.
75 * So, we can always see the first 64 bytes of any record written.
76 * The stuff we're interested in (flags, id) are in the first 8 bytes.
77 * so we can always tell if we're writing a group record.
80 int (*pt_save_dbase_write
)(struct ubik_dbase
*, afs_int32
, void *, afs_int32
,
84 pt_mywrite(struct ubik_dbase
*tdb
, afs_int32 fno
, void *bp
, afs_int32 pos
, afs_int32 count
)
86 afs_uint32 headersize
= ntohl(cheader
.headerSize
);
88 if (fno
== 0 && pos
+ count
> headersize
) {
103 #define xPT(p,x) ((((struct prentry *)(p))->flags & htonl(PRTYPE)) == htonl(x))
106 fprintf(stderr
, "Writing %d bytes of entry @ %#lx(+%d)\n", c
,
108 else if (c
== ENTRYSIZE
)
110 "Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n",
111 c
, p
, ntohl(((struct prentry
*)cp
)->flags
),
112 xPT(cp
,PRUSER
) ? "user" : xPT(cp
,PRFREE
) ? "free" :
113 xPT(cp
,PRGRP
) ? "group" : xPT(cp
,PRCONT
) ? "cont" :
114 xPT(cp
,PRCELL
) ? "cell" : xPT(cp
,PRFOREIGN
) ? "foreign" :
115 xPT(cp
,PRINST
) ? "sub/super instance" : "?",
116 ntohl(((struct prentry
*)cp
)->id
));
119 "Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n",
120 c
, p
, ntohl(((struct prentry
*)cp
)->flags
),
121 xPT(cp
,PRUSER
) ? "user" : xPT(cp
,PRFREE
) ? "free" :
122 xPT(cp
,PRGRP
) ? "group" : xPT(cp
,PRCONT
) ? "cont" :
123 xPT(cp
,PRCELL
) ? "cell" : xPT(cp
,PRFOREIGN
) ? "foreign" :
124 xPT(cp
,PRINST
) ? "sub/super instance" : "?",
125 ntohl(((struct prentry
*)cp
)->id
));
127 fprintf(stderr
, "Writing %d bytes of entry @ %#lx\n", c
, p
);
129 if (!o
&& c
>= 8 && xPT(cp
,PRGRP
)) {
131 if (in_map(sg_found
, -ntohl(((struct prentry
*)cp
)->id
)))
132 fprintf(stderr
, "Unfound: Removing group %d\n",
133 ntohl(((struct prentry
*)cp
)->id
));
134 if (in_map(sg_flagged
, -ntohl(((struct prentry
*)cp
)->id
)))
135 fprintf(stderr
, "Unflag: Removing group %d\n",
136 ntohl(((struct prentry
*)cp
)->id
));
140 add_map(NIL_MAP
, -ntohl(((struct prentry
*)cp
)->id
)));
143 add_map(NIL_MAP
, -ntohl(((struct prentry
*)cp
)->id
)));
151 return (*pt_save_dbase_write
) (tdb
, fno
, bp
, pos
, count
);
155 * this function attaches pt_mywrite. It's called once,
156 * just after ubik_ServerInit.
162 extern struct ubik_dbase
*ubik_dbase
;
163 if (ubik_dbase
->write
!= pt_mywrite
) {
164 pt_save_dbase_write
= ubik_dbase
->write
;
165 ubik_dbase
->write
= pt_mywrite
;
169 #endif /* SUPERGROUPS */
171 /* CorrectUserName - Check to make sure a user name is OK. It must not include
172 * either a colon (or it would look like a group) or a newline (which can
173 * confuse some ptdb code, depending on the format we're reading from).
174 * This is a predicate, so it return one if name is OK and zero if name is
178 CorrectUserName(char *name
)
180 /* We accept foreign names, so we will deal with '@' later */
181 if (strchr(name
, ':') || strchr(name
, '\n'))
183 if (strlen(name
) >= PR_MAXNAMELEN
)
188 /* CorrectGroupName - Like the above but handles more complicated cases caused
189 * by including the ownership in the name. The interface works by calculating
190 * the correct name based on a given name and owner. This allows easy use by
191 * rename, which then compares the correct name with the requested new name. */
194 CorrectGroupName(struct ubik_trans
*ut
, char aname
[PR_MAXNAMELEN
], /* name for group */
195 afs_int32 cid
, /* caller id */
196 afs_int32 oid
, /* owner of group */
197 afs_int32 admin
, /* non-zero if admin */
198 char cname
[PR_MAXNAMELEN
]) /* correct name for group */
201 char *prefix
; /* ptr to group owner part */
202 char *suffix
; /* ptr to group name part */
203 char name
[PR_MAXNAMELEN
]; /* correct name for group */
204 struct prentry tentry
;
206 if (strlen(aname
) >= PR_MAXNAMELEN
)
209 /* Determine the correct prefix for the name. */
210 if (oid
== SYSADMINID
)
213 afs_int32 loc
= FindByID(ut
, oid
);
215 /* let admin create groups owned by non-existent ids (probably
216 * setting a group to own itself). Check that they look like
217 * groups (with a colon) or otherwise are good user names. */
219 strcpy(cname
, aname
);
224 code
= pr_Read(ut
, 0, loc
, &tentry
, sizeof(tentry
));
227 if (ntohl(tentry
.flags
) & PRGRP
) {
228 if ((tentry
.count
== 0) && !admin
)
230 /* terminate prefix at colon if there is one */
231 if ((prefix
= strchr(tentry
.name
, ':')))
234 prefix
= tentry
.name
;
236 /* only sysadmin allow to use 'system:' prefix */
237 if ((strcmp(prefix
, "system") == 0) && !admin
)
240 strcpy(name
, aname
); /* in case aname & cname are same */
241 suffix
= strchr(name
, ':');
242 /* let e.g. pt_util create groups with "wrong" names (like
243 * an orphan whose parent ID was reused). Check that they look like
244 * groups (with a colon) or otherwise are good user names. */
246 strcpy(cname
, aname
);
250 /* sysadmin can make groups w/o ':', but they must still look like
251 * legal user names. */
256 if (strlen(prefix
) + strlen(suffix
) >= PR_MAXNAMELEN
)
258 strcpy(cname
, prefix
);
259 strcat(cname
, suffix
);
262 /* check for legal name with either group rules or user rules */
263 if ((suffix
= strchr(cname
, ':'))) {
264 /* check for confusing characters */
265 if (strchr(cname
, '\n') || /* restrict so recreate can work */
266 strchr(suffix
+ 1, ':')) /* avoid multiple colons */
269 if (!CorrectUserName(cname
))
276 AccessOK(struct ubik_trans
*ut
, afs_int32 cid
, /* caller id */
277 struct prentry
*tentry
, /* object being accessed */
278 int mem
, /* check membership in aid, if group */
279 int any
) /* if set return true */
287 if (cid
== SYSADMINID
)
288 return 1; /* special case fileserver */
289 if (restricted
&& !IsAMemberOf(ut
, cid
, SYSADMINID
)) {
290 if (mem
== PRP_ADD_MEM
|| mem
== PRP_REMOVE_MEM
) {
291 /* operation is for adding/removing members from a group */
294 if (mem
== 0 && any
== 0) {
295 /* operation is for modifying an entry (or some administrative
296 * global operations) */
301 flags
= tentry
->flags
;
305 flags
= oid
= aid
= 0;
307 if (!(flags
& PRACCESS
)) { /* provide default access */
309 flags
|= prp_group_default
;
311 flags
|= prp_user_default
;
317 if ((cid
== oid
) || IsAMemberOf(ut
, cid
, oid
))
320 if (aid
> 0) { /* checking on a user */
323 } else if (aid
< 0) { /* checking on group */
324 if ((flags
& mem
) && IsAMemberOf(ut
, cid
, aid
))
327 /* Allow members of SYSVIEWERID to get membership and status only */
328 if (((mem
== PRP_STATUS_MEM
) || (mem
== PRP_MEMBER_MEM
)
329 || (any
== PRP_OWNED_ANY
)) && (IsAMemberOf(ut
, cid
, SYSVIEWERID
)))
331 if (IsAMemberOf(ut
, cid
, SYSADMINID
))
333 return 0; /* no access */
337 CreateEntry(struct ubik_trans
*at
, char aname
[PR_MAXNAMELEN
], afs_int32
*aid
, afs_int32 idflag
, afs_int32 flag
, afs_int32 oid
, afs_int32 creator
)
339 /* get and init a new entry */
343 struct prentry tentry
, tent
;
346 memset(&tentry
, 0, sizeof(tentry
));
348 admin
= pr_noAuth
|| IsAMemberOf(at
, creator
, SYSADMINID
);
350 if (oid
== 0 || oid
== ANONYMOUSID
) {
351 if (!admin
&& creator
== 0)
357 code
= CorrectGroupName(at
, aname
, creator
, oid
, admin
, tentry
.name
);
360 if (strcmp(aname
, tentry
.name
) != 0)
362 } else { /* non-group must not have colon */
363 if (!CorrectUserName(aname
))
365 strcpy(tentry
.name
, aname
);
368 if (FindByName(at
, aname
, &tent
))
371 newEntry
= AllocBlock(at
);
374 tentry
.createTime
= time(0);
377 tentry
.flags
= PRGRP
;
379 } else if (flag
== 0) {
381 tentry
.owner
= SYSADMINID
;
386 atsign
= strchr(aname
, '@');
388 /* A normal user or group. Pick an id for it */
392 code
= AllocID(at
, flag
, &tentry
.id
);
393 if (code
!= PRSUCCESS
)
396 } else if (flag
& PRGRP
) {
397 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
398 * Then pick an id for the group.
403 badFormat
= strcmp(AUTHUSER_GROUP
, aname
);
411 code
= AllocID(at
, flag
, &tentry
.id
);
412 if (code
!= PRSUCCESS
)
416 /* A foreign user: <name>@<cell>. The foreign user is added to
417 * its representing group. It is
421 struct prentry centry
;
423 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
426 if (asprintf(&cellGroup
, "%s%s", AUTHUSER_GROUP
, atsign
) < 0)
428 pos
= FindByName(at
, cellGroup
, ¢ry
);
432 code
= pr_Read(at
, 0, pos
, ¢ry
, sizeof(centry
));
436 /* cellid is the id of the group representing the cell */
437 tentry
.cellid
= ntohl(centry
.id
);
440 /* Check if id is good */
441 if (!inRange(¢ry
, *aid
))
445 /* Allocate an ID special for this foreign user. It is based
446 * on the representing group's id and nusers count.
448 tentry
.id
= allocNextId(at
, ¢ry
);
453 /* The foreign user will be added to the representing foreign
454 * group. The group can hold up to 30 entries.
456 if (!(ntohl(centry
.flags
) & PRQUOTA
)) {
457 centry
.flags
= htonl(ntohl(centry
.flags
) | PRQUOTA
);
458 centry
.ngroups
= htonl(30);
460 n
= ntohl(centry
.ngroups
);
461 if ((n
<= 0) && !pr_noAuth
)
463 centry
.ngroups
= htonl(n
- 1);
465 /* write updated entry for group */
466 code
= pr_Write(at
, 0, pos
, ¢ry
, sizeof(centry
));
470 /* Now add the new user entry to the database */
472 tentry
.creator
= tentry
.id
;
474 tentry
.creator
= creator
;
476 code
= pr_WriteEntry(at
, 0, newEntry
, &tentry
);
479 code
= AddToIDHash(at
, *aid
, newEntry
);
480 if (code
!= PRSUCCESS
)
482 code
= AddToNameHash(at
, aname
, newEntry
);
483 if (code
!= PRSUCCESS
)
485 if (inc_header_word(at
, foreigncount
, 1))
488 /* Now add the entry to the authuser group for this cell.
489 * We will reread the entries for the user and the group
490 * instead of modifying them before writing them in the
491 * previous steps. Although not very efficient, much simpler
493 pos
= FindByID(at
, tentry
.cellid
);
496 code
= pr_ReadEntry(at
, 0, pos
, ¢ry
);
499 code
= AddToEntry(at
, ¢ry
, pos
, *aid
);
502 /* and now the user entry */
503 pos
= FindByID(at
, *aid
);
506 code
= pr_ReadEntry(at
, 0, pos
, &tentry
);
509 code
= AddToEntry(at
, &tentry
, pos
, tentry
.cellid
);
516 /* Remember the largest group id or largest user id */
518 /* group ids are negative */
519 if (tentry
.id
< (afs_int32
) ntohl(cheader
.maxGroup
)) {
520 code
= set_header_word(at
, maxGroup
, htonl(tentry
.id
));
525 if (tentry
.id
> (afs_int32
) ntohl(cheader
.maxID
)) {
526 code
= set_header_word(at
, maxID
, htonl(tentry
.id
));
532 /* Charge the creator for this group */
534 afs_int32 loc
= FindByID(at
, creator
);
535 struct prentry centry
;
538 if (loc
) { /* this should only fail during initialization */
539 code
= pr_Read(at
, 0, loc
, ¢ry
, sizeof(centry
));
543 /* If quota is uninitialized, do it */
544 if (!(ntohl(centry
.flags
) & PRQUOTA
)) {
545 centry
.flags
= htonl(ntohl(centry
.flags
) | PRQUOTA
);
546 centry
.ngroups
= centry
.nusers
= htonl(20);
549 /* Admins don't get charged for creating a group.
550 * If in noAuth mode, you get changed for it but you
551 * are still allowed to create as many groups as you want.
553 admin
= ((creator
== SYSADMINID
)
554 || IsAMemberOf(at
, creator
, SYSADMINID
));
556 if (ntohl(centry
.ngroups
) <= 0) {
560 centry
.ngroups
= htonl(ntohl(centry
.ngroups
) - 1);
564 code
= pr_Write(at
, 0, loc
, ¢ry
, sizeof(centry
));
569 /* Initialize the quota for the user. Groups don't have their
572 tentry
.flags
|= PRQUOTA
;
573 tentry
.ngroups
= tentry
.nusers
= 20;
577 tentry
.creator
= tentry
.id
;
579 tentry
.creator
= creator
;
581 code
= pr_WriteEntry(at
, 0, newEntry
, &tentry
);
584 code
= AddToIDHash(at
, *aid
, newEntry
);
585 if (code
!= PRSUCCESS
)
587 code
= AddToNameHash(at
, aname
, newEntry
);
588 if (code
!= PRSUCCESS
)
590 if (tentry
.flags
& PRGRP
) {
591 code
= AddToOwnerChain(at
, tentry
.id
, oid
);
595 if (tentry
.flags
& PRGRP
) {
596 if (inc_header_word(at
, groupcount
, 1))
598 } else if (tentry
.flags
& PRINST
) {
599 if (inc_header_word(at
, instcount
, 1))
602 if (inc_header_word(at
, usercount
, 1))
609 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
610 * entry if appropriate */
613 RemoveFromEntry(struct ubik_trans
*at
, afs_int32 aid
, afs_int32 bid
)
616 struct prentry tentry
;
617 struct contentry centry
;
618 struct contentry hentry
;
625 return PRINCONSISTENT
;
626 memset(&hentry
, 0, sizeof(hentry
));
627 temp
= FindByID(at
, bid
);
630 code
= pr_ReadEntry(at
, 0, temp
, &tentry
);
633 tentry
.removeTime
= time(0);
634 for (i
= 0; i
< PRSIZE
; i
++) {
635 if (tentry
.entries
[i
] == aid
) {
636 tentry
.entries
[i
] = PRBADID
;
638 code
= pr_WriteEntry(at
, 0, temp
, &tentry
);
643 if (tentry
.entries
[i
] == 0) /* found end of list */
649 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
652 if ((centry
.id
!= bid
) || !(centry
.flags
& PRCONT
))
654 for (i
= 0; i
< COSIZE
; i
++) {
655 if (centry
.entries
[i
] == aid
) {
656 centry
.entries
[i
] = PRBADID
;
657 for (j
= 0; j
< COSIZE
; j
++)
658 if (centry
.entries
[j
] != PRBADID
659 && centry
.entries
[j
] != 0)
661 if (j
== COSIZE
) { /* can free this block */
663 tentry
.next
= centry
.next
;
665 hentry
.next
= centry
.next
;
666 code
= pr_WriteCoEntry(at
, 0, hloc
, &hentry
);
670 code
= FreeBlock(at
, nptr
);
673 } else { /* can't free it yet */
674 code
= pr_WriteCoEntry(at
, 0, nptr
, ¢ry
);
679 code
= pr_WriteEntry(at
, 0, temp
, &tentry
);
684 if (centry
.entries
[i
] == 0)
686 } /* for all coentry slots */
689 memcpy(&hentry
, ¢ry
, sizeof(centry
));
690 } /* while there are coentries */
694 #if defined(SUPERGROUPS)
695 /* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
696 * entry if appropriate */
699 ChangeIDEntry(struct ubik_trans
*at
, afs_int32 aid
, afs_int32 newid
, afs_int32 bid
)
702 struct prentry tentry
;
703 struct contentry centry
;
709 return PRINCONSISTENT
;
710 temp
= FindByID(at
, bid
);
714 code
= pr_ReadEntry(at
, 0, temp
, &tentry
);
717 for (i
= 0; i
< PRSIZE
; i
++) {
718 if (tentry
.entries
[i
] == aid
) {
719 tentry
.entries
[i
] = newid
;
720 code
= pr_WriteEntry(at
, 0, temp
, &tentry
);
725 if (tentry
.entries
[i
] == 0) { /* found end of list */
732 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
735 if ((centry
.id
!= bid
) || !(centry
.flags
& PRCONT
)) {
737 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
738 bid
, centry
.id
, centry
.flags
);
741 for (i
= 0; i
< COSIZE
; i
++) {
742 if (centry
.entries
[i
] == aid
) {
743 centry
.entries
[i
] = newid
;
744 for (j
= 0; j
< COSIZE
; j
++)
745 if (centry
.entries
[j
] != PRBADID
746 && centry
.entries
[j
] != 0)
748 code
= pr_WriteCoEntry(at
, 0, nptr
, ¢ry
);
753 if (centry
.entries
[i
] == 0) {
756 } /* for all coentry slots */
758 } /* while there are coentries */
762 /* #ifdef SUPERGROUPS */
763 /* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
764 * continuation entry if appropriate */
767 RemoveFromSGEntry(struct ubik_trans
*at
, afs_int32 aid
, afs_int32 bid
)
770 struct prentry tentry
;
771 struct prentryg
*tentryg
;
772 struct contentry centry
;
773 struct contentry hentry
;
780 return PRINCONSISTENT
;
781 memset(&hentry
, 0, sizeof(hentry
));
782 temp
= FindByID(at
, bid
);
786 code
= pr_ReadEntry(at
, 0, temp
, &tentry
);
789 tentry
.removeTime
= time(NULL
);
790 tentryg
= (struct prentryg
*)&tentry
;
791 for (i
= 0; i
< SGSIZE
; i
++) {
792 if (tentryg
->supergroup
[i
] == aid
) {
793 tentryg
->supergroup
[i
] = PRBADID
;
795 code
= pr_WriteEntry(at
, 0, temp
, &tentry
);
800 if (tentryg
->supergroup
[i
] == 0) { /* found end of list */
805 nptr
= tentryg
->nextsg
;
807 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
810 if ((centry
.id
!= bid
) || !(centry
.flags
& PRCONT
)) {
812 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
813 bid
, centry
.id
, centry
.flags
);
816 for (i
= 0; i
< COSIZE
; i
++) {
817 if (centry
.entries
[i
] == aid
) {
818 centry
.entries
[i
] = PRBADID
;
819 for (j
= 0; j
< COSIZE
; j
++)
820 if (centry
.entries
[j
] != PRBADID
821 && centry
.entries
[j
] != 0)
823 if (j
== COSIZE
) { /* can free this block */
825 tentryg
->nextsg
= centry
.next
;
827 hentry
.next
= centry
.next
;
828 code
= pr_WriteCoEntry(at
, 0, hloc
, &hentry
);
832 code
= FreeBlock(at
, nptr
);
835 } else { /* can't free it yet */
836 code
= pr_WriteCoEntry(at
, 0, nptr
, ¢ry
);
841 code
= pr_WriteEntry(at
, 0, temp
, &tentry
);
846 if (centry
.entries
[i
] == 0) {
849 } /* for all coentry slots */
852 memcpy(&hentry
, ¢ry
, sizeof(centry
));
853 } /* while there are coentries */
857 #endif /* SUPERGROUPS */
859 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
860 * groups, putting groups owned by it on orphan chain, and freeing the space */
863 DeleteEntry(struct ubik_trans
*at
, struct prentry
*tentry
, afs_int32 loc
)
866 struct contentry centry
;
870 if (strchr(tentry
->name
, '@')) {
871 if (tentry
->flags
& PRGRP
) {
872 /* If there are still foreign user accounts from that cell
873 * don't delete the group */
879 afs_int32 loc
= FindByID(at
, tentry
->cellid
);
880 struct prentry centry
;
882 code
= pr_Read(at
, 0, loc
, ¢ry
, sizeof(centry
));
885 if (ntohl(centry
.flags
) & PRQUOTA
) {
886 centry
.ngroups
= htonl(ntohl(centry
.ngroups
) + 1);
888 code
= pr_Write(at
, 0, loc
, ¢ry
, sizeof(centry
));
894 /* First remove the entire membership list */
895 for (i
= 0; i
< PRSIZE
; i
++) {
896 if (tentry
->entries
[i
] == PRBADID
)
898 if (tentry
->entries
[i
] == 0)
900 #if defined(SUPERGROUPS)
901 if ((tentry
->flags
& PRGRP
) && tentry
->entries
[i
] < 0) /* Supergroup */
902 code
= RemoveFromSGEntry(at
, tentry
->id
, tentry
->entries
[i
]);
905 code
= RemoveFromEntry(at
, tentry
->id
, tentry
->entries
[i
]);
909 #if defined(SUPERGROUPS)
911 struct prentryg
*tentryg
= (struct prentryg
*)tentry
;
913 /* Then remove the entire supergroup list */
914 for (i
= 0; i
< SGSIZE
; i
++) {
915 if (tentryg
->supergroup
[i
] == PRBADID
)
917 if (tentryg
->supergroup
[i
] == 0)
919 code
= RemoveFromEntry(at
, tentry
->id
, tentryg
->supergroup
[i
]);
924 #endif /* SUPERGROUPS */
927 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
930 for (i
= 0; i
< COSIZE
; i
++) {
931 if (centry
.entries
[i
] == PRBADID
)
933 if (centry
.entries
[i
] == 0)
935 code
= RemoveFromEntry(at
, tentry
->id
, centry
.entries
[i
]);
939 code
= FreeBlock(at
, nptr
); /* free continuation block */
945 /* Remove us from other's owned chain. Note that this will zero our owned
946 * field (on disk) so this step must follow the above step in case we are
947 * on our own owned list. */
948 if (tentry
->flags
& PRGRP
) {
950 code
= RemoveFromOwnerChain(at
, tentry
->id
, tentry
->owner
);
954 code
= RemoveFromOrphan(at
, tentry
->id
);
960 code
= RemoveFromIDHash(at
, tentry
->id
, &loc
);
961 if (code
!= PRSUCCESS
)
963 code
= RemoveFromNameHash(at
, tentry
->name
, &loc
);
964 if (code
!= PRSUCCESS
)
967 if (tentry
->flags
& PRGRP
) {
968 afs_int32 loc
= FindByID(at
, tentry
->creator
);
969 struct prentry centry
;
973 code
= pr_Read(at
, 0, loc
, ¢ry
, sizeof(centry
));
976 admin
= ((tentry
->creator
== SYSADMINID
)
977 || IsAMemberOf(at
, tentry
->creator
, SYSADMINID
));
978 if (ntohl(centry
.flags
) & PRQUOTA
) {
979 if (!(admin
&& (ntohl(centry
.ngroups
) >= 20))) {
980 centry
.ngroups
= htonl(ntohl(centry
.ngroups
) + 1);
983 code
= pr_Write(at
, 0, loc
, ¢ry
, sizeof(centry
));
989 if (tentry
->flags
& PRGRP
) {
990 if (inc_header_word(at
, groupcount
, -1))
992 } else if (tentry
->flags
& PRINST
) {
993 if (inc_header_word(at
, instcount
, -1))
996 if (strchr(tentry
->name
, '@')) {
997 if (inc_header_word(at
, foreigncount
, -1))
1000 if (inc_header_word(at
, usercount
, -1))
1004 code
= FreeBlock(at
, loc
);
1008 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
1011 * Note the entry is written out by this routine. */
1014 AddToEntry(struct ubik_trans
*tt
, struct prentry
*entry
, afs_int32 loc
, afs_int32 aid
)
1018 struct contentry nentry
;
1019 struct contentry aentry
;
1021 afs_int32 last
; /* addr of last cont. block */
1022 afs_int32 first
= 0;
1024 afs_int32 slot
= -1;
1026 if (entry
->id
== aid
)
1027 return PRINCONSISTENT
;
1028 entry
->addTime
= time(0);
1029 for (i
= 0; i
< PRSIZE
; i
++) {
1030 if (entry
->entries
[i
] == aid
)
1032 if (entry
->entries
[i
] == PRBADID
) { /* remember this spot */
1035 } else if (entry
->entries
[i
] == 0) { /* end of the line */
1046 code
= pr_ReadCoEntry(tt
, 0, nptr
, &nentry
);
1050 if (!(nentry
.flags
& PRCONT
))
1052 for (i
= 0; i
< COSIZE
; i
++) {
1053 if (nentry
.entries
[i
] == aid
)
1055 if (nentry
.entries
[i
] == PRBADID
) {
1060 } else if (nentry
.entries
[i
] == 0) {
1070 if (slot
!= -1) { /* we found a place */
1072 if (first
) { /* place is in first block */
1073 entry
->entries
[slot
] = aid
;
1074 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1079 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1082 code
= pr_ReadCoEntry(tt
, 0, cloc
, &aentry
);
1085 aentry
.entries
[slot
] = aid
;
1086 code
= pr_WriteCoEntry(tt
, 0, cloc
, &aentry
);
1091 /* have to allocate a continuation block if we got here */
1092 nptr
= AllocBlock(tt
);
1094 /* then we should tack new block after last block in cont. chain */
1096 code
= pr_WriteCoEntry(tt
, 0, last
, &nentry
);
1102 memset(&aentry
, 0, sizeof(aentry
));
1103 aentry
.flags
|= PRCONT
;
1104 aentry
.id
= entry
->id
;
1106 aentry
.entries
[0] = aid
;
1107 code
= pr_WriteCoEntry(tt
, 0, nptr
, &aentry
);
1110 /* don't forget to update count, here! */
1112 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1117 #if defined(SUPERGROUPS)
1119 /* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
1120 * continuation block if needed.
1122 * Note the entry is written out by this routine. */
1125 AddToSGEntry(struct ubik_trans
*tt
, struct prentry
*entry
, afs_int32 loc
, afs_int32 aid
)
1129 struct contentry nentry
;
1130 struct contentry aentry
;
1131 struct prentryg
*entryg
;
1133 afs_int32 last
; /* addr of last cont. block */
1134 afs_int32 first
= 0;
1136 afs_int32 slot
= -1;
1138 if (entry
->id
== aid
)
1139 return PRINCONSISTENT
;
1140 entry
->addTime
= time(NULL
);
1141 entryg
= (struct prentryg
*)entry
;
1142 for (i
= 0; i
< SGSIZE
; i
++) {
1143 if (entryg
->supergroup
[i
] == aid
)
1145 if (entryg
->supergroup
[i
] == PRBADID
) { /* remember this spot */
1148 } else if (entryg
->supergroup
[i
] == 0) { /* end of the line */
1157 nptr
= entryg
->nextsg
;
1159 code
= pr_ReadCoEntry(tt
, 0, nptr
, &nentry
);
1163 if (!(nentry
.flags
& PRCONT
))
1165 for (i
= 0; i
< COSIZE
; i
++) {
1166 if (nentry
.entries
[i
] == aid
)
1168 if (nentry
.entries
[i
] == PRBADID
) {
1173 } else if (nentry
.entries
[i
] == 0) {
1183 if (slot
!= -1) { /* we found a place */
1185 if (first
) { /* place is in first block */
1186 entryg
->supergroup
[slot
] = aid
;
1187 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1192 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1195 code
= pr_ReadCoEntry(tt
, 0, cloc
, &aentry
);
1198 aentry
.entries
[slot
] = aid
;
1199 code
= pr_WriteCoEntry(tt
, 0, cloc
, &aentry
);
1204 /* have to allocate a continuation block if we got here */
1205 nptr
= AllocBlock(tt
);
1207 /* then we should tack new block after last block in cont. chain */
1209 code
= pr_WriteCoEntry(tt
, 0, last
, &nentry
);
1213 entryg
->nextsg
= nptr
;
1215 memset(&aentry
, 0, sizeof(aentry
));
1216 aentry
.flags
|= PRCONT
;
1217 aentry
.id
= entry
->id
;
1219 aentry
.entries
[0] = aid
;
1220 code
= pr_WriteCoEntry(tt
, 0, nptr
, &aentry
);
1223 /* don't forget to update count, here! */
1225 code
= pr_WriteEntry(tt
, 0, loc
, entry
);
1229 #endif /* SUPERGROUPS */
1232 AddToPRList(prlist
*alist
, int *sizeP
, afs_int32 id
)
1237 if (alist
->prlist_len
>= *sizeP
) {
1238 count
= alist
->prlist_len
+ 100;
1239 if (alist
->prlist_val
) {
1240 tmp
= realloc(alist
->prlist_val
, count
* sizeof(afs_int32
));
1242 tmp
= malloc(count
* sizeof(afs_int32
));
1246 alist
->prlist_val
= tmp
;
1249 alist
->prlist_val
[alist
->prlist_len
++] = id
;
1254 GetList(struct ubik_trans
*at
, struct prentry
*tentry
, prlist
*alist
, afs_int32 add
)
1258 struct contentry centry
;
1264 alist
->prlist_val
= 0;
1265 alist
->prlist_len
= 0;
1267 for (i
= 0; i
< PRSIZE
; i
++) {
1268 if (tentry
->entries
[i
] == PRBADID
)
1270 if (tentry
->entries
[i
] == 0)
1272 code
= AddToPRList(alist
, &size
, tentry
->entries
[i
]);
1275 #if defined(SUPERGROUPS)
1278 code
= GetListSG2(at
, tentry
->entries
[i
], alist
, &size
, depthsg
);
1284 for (nptr
= tentry
->next
; nptr
!= 0; nptr
= centry
.next
) {
1285 /* look through cont entries */
1286 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
1289 for (i
= 0; i
< COSIZE
; i
++) {
1290 if (centry
.entries
[i
] == PRBADID
)
1292 if (centry
.entries
[i
] == 0)
1294 code
= AddToPRList(alist
, &size
, centry
.entries
[i
]);
1297 #if defined(SUPERGROUPS)
1300 code
= GetListSG2(at
, centry
.entries
[i
], alist
, &size
, depthsg
);
1306 #ifndef AFS_PTHREAD_ENV
1313 if (add
) { /* this is for a CPS, so tack on appropriate stuff */
1314 if (tentry
->id
!= ANONYMOUSID
&& tentry
->id
!= ANYUSERID
) {
1315 if ((code
= AddToPRList(alist
, &size
, ANYUSERID
))
1316 || (code
= AddAuthGroup(tentry
, alist
, &size
))
1317 || (code
= AddToPRList(alist
, &size
, tentry
->id
)))
1320 if ((code
= AddToPRList(alist
, &size
, ANYUSERID
))
1321 || (code
= AddToPRList(alist
, &size
, tentry
->id
)))
1325 #ifndef AFS_PTHREAD_ENV
1326 if (alist
->prlist_len
> 100)
1329 qsort(alist
->prlist_val
, alist
->prlist_len
, sizeof(afs_int32
), IDCmp
);
1335 GetList2(struct ubik_trans
*at
, struct prentry
*tentry
, struct prentry
*tentry2
, prlist
*alist
, afs_int32 add
)
1339 struct contentry centry
;
1345 alist
->prlist_val
= 0;
1346 alist
->prlist_len
= 0;
1347 for (i
= 0; i
< PRSIZE
; i
++) {
1348 if (tentry
->entries
[i
] == PRBADID
)
1350 if (tentry
->entries
[i
] == 0)
1352 code
= AddToPRList(alist
, &size
, tentry
->entries
[i
]);
1355 #if defined(SUPERGROUPS)
1358 code
= GetListSG2(at
, tentry
->entries
[i
], alist
, &size
, depthsg
);
1364 nptr
= tentry
->next
;
1366 /* look through cont entries */
1367 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
1370 for (i
= 0; i
< COSIZE
; i
++) {
1371 if (centry
.entries
[i
] == PRBADID
)
1373 if (centry
.entries
[i
] == 0)
1375 code
= AddToPRList(alist
, &size
, centry
.entries
[i
]);
1378 #if defined(SUPERGROUPS)
1381 code
= GetListSG2(at
, centry
.entries
[i
], alist
, &size
, depthsg
);
1388 #ifndef AFS_PTHREAD_ENV
1395 for (i
= 0; i
< PRSIZE
; i
++) {
1396 if (tentry2
->entries
[i
] == PRBADID
)
1398 if (tentry2
->entries
[i
] == 0)
1400 code
= AddToPRList(alist
, &size
, tentry2
->entries
[i
]);
1406 nptr
= tentry2
->next
;
1408 /* look through cont entries */
1409 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
1412 for (i
= 0; i
< COSIZE
; i
++) {
1413 if (centry
.entries
[i
] == PRBADID
)
1415 if (centry
.entries
[i
] == 0)
1417 code
= AddToPRList(alist
, &size
, centry
.entries
[i
]);
1423 #ifndef AFS_PTHREAD_ENV
1430 if (add
) { /* this is for a CPS, so tack on appropriate stuff */
1431 if (tentry
->id
!= ANONYMOUSID
&& tentry
->id
!= ANYUSERID
) {
1432 if ((code
= AddToPRList(alist
, &size
, ANYUSERID
))
1433 || (code
= AddToPRList(alist
, &size
, AUTHUSERID
))
1434 || (code
= AddToPRList(alist
, &size
, tentry
->id
)))
1437 if ((code
= AddToPRList(alist
, &size
, ANYUSERID
))
1438 || (code
= AddToPRList(alist
, &size
, tentry
->id
)))
1442 #ifndef AFS_PTHREAD_ENV
1443 if (alist
->prlist_len
> 100)
1446 qsort(alist
->prlist_val
, alist
->prlist_len
, sizeof(afs_int32
), IDCmp
);
1450 #if defined(SUPERGROUPS)
1453 GetListSG2(struct ubik_trans
*at
, afs_int32 gid
, prlist
*alist
, afs_int32
*sizeP
, afs_int32 depth
)
1456 struct prentry tentry
;
1457 struct prentryg
*tentryg
= (struct prentryg
*)&tentry
;
1459 struct contentry centry
;
1465 int predictfound
, predictflagged
;
1470 if (!in_map(sg_flagged
, -gid
)) {
1472 fprintf(stderr
, "GetListSG2: I have not yet searched for gid=%d\n",
1474 } else if (predictflagged
= 1, in_map(sg_found
, -gid
)) {
1477 "GetListSG2: I have already searched for gid=%d, and predict success.\n",
1482 if (in_map(sg_flagged
, -gid
) && !in_map(sg_found
, -gid
)) {
1485 "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
1494 temp
= FindByID(at
, gid
);
1499 code
= pr_ReadEntry(at
, 0, temp
, &tentry
);
1503 fprintf(stderr
, "GetListSG2: lookup for gid=%d [\n", gid
);
1507 for (i
= 0; i
< SGSIZE
; i
++) {
1508 if (tentryg
->supergroup
[i
] == PRBADID
)
1510 if (tentryg
->supergroup
[i
] == 0)
1514 fprintf(stderr
, "via gid=%d, added %d\n", gid
,
1515 e
.tentryg
.supergroup
[i
]);
1517 code
= AddToPRList(alist
, sizeP
, tentryg
->supergroup
[i
]);
1521 GetListSG2(at
, tentryg
->supergroup
[i
], alist
, sizeP
, depth
- 1);
1526 nptr
= tentryg
->nextsg
;
1529 /* look through cont entries */
1530 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
1533 for (i
= 0; i
< COSIZE
; i
++) {
1534 if (centry
.entries
[i
] == PRBADID
)
1536 if (centry
.entries
[i
] == 0)
1539 fprintf(stderr
, "via gid=%d, added %d\n", gid
,
1540 e
.centry
.entries
[i
]);
1542 code
= AddToPRList(alist
, sizeP
, centry
.entries
[i
]);
1545 code
= GetListSG2(at
, centry
.entries
[i
], alist
, sizeP
, depth
- 1);
1551 #ifndef AFS_PTHREAD_ENV
1558 fprintf(stderr
, "] for gid %d, done [flag=%s]\n", gid
,
1559 didsomething
? "TRUE" : "FALSE");
1560 if (predictflagged
&& didsomething
!= predictfound
)
1561 fprintf(stderr
, "**** for gid=%d, didsomething=%d predictfound=%d\n",
1562 didsomething
, predictfound
);
1565 sg_found
= add_map(sg_found
, -gid
);
1567 sg_found
= bic_map(sg_found
, add_map(NIL_MAP
, -gid
));
1568 sg_flagged
= add_map(sg_flagged
, -gid
);
1573 GetSGList(struct ubik_trans
*at
, struct prentry
*tentry
, prlist
*alist
)
1577 struct contentry centry
;
1578 struct prentryg
*tentryg
;
1584 alist
->prlist_val
= 0;
1585 alist
->prlist_len
= 0;
1587 tentryg
= (struct prentryg
*)tentry
;
1588 for (i
= 0; i
< SGSIZE
; i
++) {
1589 if (tentryg
->supergroup
[i
] == PRBADID
)
1591 if (tentryg
->supergroup
[i
] == 0)
1593 code
= AddToPRList(alist
, &size
, tentryg
->supergroup
[i
]);
1598 nptr
= tentryg
->nextsg
;
1600 /* look through cont entries */
1601 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
1604 for (i
= 0; i
< COSIZE
; i
++) {
1605 if (centry
.entries
[i
] == PRBADID
)
1607 if (centry
.entries
[i
] == 0)
1609 code
= AddToPRList(alist
, &size
, centry
.entries
[i
]);
1615 #ifndef AFS_PTHREAD_ENV
1622 #ifndef AFS_PTHREAD_ENV
1623 if (alist
->prlist_len
> 100)
1626 qsort((char *)alist
->prlist_val
, (int)alist
->prlist_len
,
1627 sizeof(afs_int32
), IDCmp
);
1630 #endif /* SUPERGROUPS */
1633 GetOwnedChain(struct ubik_trans
*ut
, afs_int32
*next
, prlist
*alist
)
1636 struct prentry tentry
;
1641 alist
->prlist_val
= 0;
1642 alist
->prlist_len
= 0;
1644 for (; *next
; *next
= ntohl(tentry
.nextOwned
)) {
1645 code
= pr_Read(ut
, 0, *next
, &tentry
, sizeof(tentry
));
1648 code
= AddToPRList(alist
, &size
, ntohl(tentry
.id
));
1649 if (alist
->prlist_len
>= PR_MAXGROUPS
) {
1655 #ifndef AFS_PTHREAD_ENV
1661 #ifndef AFS_PTHREAD_ENV
1662 if (alist
->prlist_len
> 100)
1665 qsort(alist
->prlist_val
, alist
->prlist_len
, sizeof(afs_int32
), IDCmp
);
1670 GetMax(struct ubik_trans
*at
, afs_int32
*uid
, afs_int32
*gid
)
1672 *uid
= ntohl(cheader
.maxID
);
1673 *gid
= ntohl(cheader
.maxGroup
);
1678 SetMax(struct ubik_trans
*at
, afs_int32 id
, afs_int32 flag
)
1682 cheader
.maxGroup
= htonl(id
);
1684 pr_Write(at
, 0, 16, (char *)&cheader
.maxGroup
,
1685 sizeof(cheader
.maxGroup
));
1689 cheader
.maxID
= htonl(id
);
1691 pr_Write(at
, 0, 20, (char *)&cheader
.maxID
,
1692 sizeof(cheader
.maxID
));
1700 UpdateCache(struct ubik_trans
*tt
, void *rock
)
1704 code
= pr_Read(tt
, 0, 0, (char *)&cheader
, sizeof(cheader
));
1706 afs_com_err(whoami
, code
, "Couldn't read header");
1712 read_DbHeader(struct ubik_trans
*tt
)
1714 return ubik_CheckCache(tt
, UpdateCache
, NULL
);
1720 * reads in db cache from ubik.
1722 * @param[in] ut ubik transaction
1723 * @param[out] rock opaque pointer to an int*, which on success will be set
1724 * to 1 if we need to build the database, or 0 if we do not
1726 * @return operation status
1730 Initdb_check(struct ubik_trans
*tt
, void *rock
)
1732 int *build_rock
= rock
;
1736 len
= sizeof(cheader
);
1737 code
= pr_Read(tt
, 0, 0, (char *)&cheader
, len
);
1739 afs_com_err(whoami
, code
, "couldn't read header");
1742 if ((ntohl(cheader
.version
) == PRDBVERSION
)
1743 && ntohl(cheader
.headerSize
) == sizeof(cheader
)
1744 && ntohl(cheader
.eofPtr
) != 0
1745 && FindByID(tt
, ANONYMOUSID
) != 0) {
1746 /* database exists, so we don't have to build it */
1751 /* else we need to build a database */
1759 struct ubik_trans
*tt
;
1763 /* init the database. We'll try reading it, but if we're starting
1764 * from scratch, we'll have to do a write transaction. */
1766 pr_noAuth
= afsconf_GetNoAuthFlag(prdir
);
1768 code
= ubik_BeginTransReadAny(dbase
, UBIK_READTRANS
, &tt
);
1771 code
= ubik_SetLock(tt
, 1, 1, LOCKREAD
);
1773 ubik_AbortTrans(tt
);
1777 code
= ubik_CheckCache(tt
, Initdb_check
, &build
);
1779 ubik_AbortTrans(tt
);
1784 /* Only rebuild database if the db was deleted (the header is zero) */
1785 char *bp
= (char *)&cheader
;
1787 for (i
= 0; i
< sizeof(cheader
); i
++) {
1790 afs_com_err(whoami
, code
,
1791 "Can't rebuild database because it is not empty");
1800 code
= ubik_EndTrans(tt
);
1802 if (code
|| !build
) {
1803 /* either we encountered an error, or we don't need to build the db */
1807 code
= ubik_BeginTrans(dbase
, UBIK_WRITETRANS
, &tt
);
1811 code
= ubik_SetLock(tt
, 1, 1, LOCKWRITE
);
1813 ubik_AbortTrans(tt
);
1817 /* before doing a rebuild, check again that the dbase looks bad, because
1818 * the previous check was only under a ReadAny transaction, and there could
1819 * actually have been a good database out there. Now that we have a
1820 * real write transaction, make sure things are still bad.
1822 code
= pr_Read(tt
, 0, 0, (char *)&cheader
, sizeof(cheader
));
1824 afs_com_err(whoami
, code
, "couldn't read header");
1825 ubik_AbortTrans(tt
);
1828 if ((ntohl(cheader
.version
) == PRDBVERSION
)
1829 && ntohl(cheader
.headerSize
) == sizeof(cheader
)
1830 && ntohl(cheader
.eofPtr
) != 0
1831 && FindByID(tt
, ANONYMOUSID
) != 0) {
1832 /* database exists, so we don't have to build it */
1833 code
= ubik_EndTrans(tt
);
1839 /* Initialize the database header */
1840 if ((code
= set_header_word(tt
, version
, htonl(PRDBVERSION
)))
1841 || (code
= set_header_word(tt
, headerSize
, htonl(sizeof(cheader
))))
1842 || (code
= set_header_word(tt
, eofPtr
, cheader
.headerSize
))) {
1843 afs_com_err(whoami
, code
, "couldn't write header words");
1844 ubik_AbortTrans(tt
);
1847 #define InitialGroup(id,name) do { \
1848 afs_int32 temp = (id); \
1849 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1850 code = CreateEntry \
1851 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1853 afs_com_err (whoami, code, "couldn't create %s with id %di.", \
1855 ubik_AbortTrans(tt); \
1860 InitialGroup(SYSADMINID
, "system:administrators");
1861 InitialGroup(SYSBACKUPID
, "system:backup");
1862 InitialGroup(ANYUSERID
, "system:anyuser");
1863 InitialGroup(AUTHUSERID
, "system:authuser");
1864 InitialGroup(SYSVIEWERID
, "system:ptsviewers");
1865 InitialGroup(ANONYMOUSID
, "anonymous");
1867 /* Well, we don't really want the max id set to anonymousid, so we'll set
1869 code
= set_header_word(tt
, maxID
, 0); /* correct in any byte order */
1871 afs_com_err(whoami
, code
, "couldn't reset max id");
1872 ubik_AbortTrans(tt
);
1876 code
= ubik_EndTrans(tt
);
1883 ChangeEntry(struct ubik_trans
*at
, afs_int32 aid
, afs_int32 cid
, char *name
, afs_int32 oid
, afs_int32 newid
)
1887 #if defined(SUPERGROUPS)
1891 struct contentry centry
;
1893 struct prentry tentry
, tent
;
1897 char holder
[PR_MAXNAMELEN
];
1898 char temp
[PR_MAXNAMELEN
];
1899 char oldname
[PR_MAXNAMELEN
];
1902 memset(holder
, 0, PR_MAXNAMELEN
);
1903 memset(temp
, 0, PR_MAXNAMELEN
);
1904 loc
= FindByID(at
, aid
);
1907 code
= pr_ReadEntry(at
, 0, loc
, &tentry
);
1910 if (restricted
&& !IsAMemberOf(at
, cid
, SYSADMINID
))
1912 if (tentry
.owner
!= cid
&& !IsAMemberOf(at
, cid
, SYSADMINID
)
1913 && !IsAMemberOf(at
, cid
, tentry
.owner
) && !pr_noAuth
)
1915 tentry
.changeTime
= time(0);
1916 admin
= pr_noAuth
|| IsAMemberOf(at
, cid
, SYSADMINID
);
1918 /* we're actually trying to change the id */
1919 if (newid
&& (newid
!= aid
)) {
1923 pos
= FindByID(at
, newid
);
1925 return PRIDEXIST
; /* new id already in use! */
1926 if ((aid
< 0 && newid
> 0) || (aid
> 0 && newid
< 0))
1929 /* Should check that foreign users id to change to is good: inRange() */
1931 /* if new id is not in use, rehash things */
1932 code
= RemoveFromIDHash(at
, aid
, &loc
);
1933 if (code
!= PRSUCCESS
)
1936 code
= pr_WriteEntry(at
, 0, loc
, &tentry
);
1939 code
= AddToIDHash(at
, tentry
.id
, loc
);
1943 /* get current data */
1944 code
= pr_ReadEntry(at
, 0, loc
, &tentry
);
1948 #if defined(SUPERGROUPS)
1949 if (tentry
.id
> (afs_int32
) ntohl(cheader
.maxID
))
1950 code
= set_header_word(at
, maxID
, htonl(tentry
.id
));
1954 /* need to fix up: membership
1959 for (i
= 0; i
< PRSIZE
; i
++) {
1960 if (tentry
.entries
[i
] == PRBADID
)
1962 if (tentry
.entries
[i
] == 0)
1964 if ((tentry
.flags
& PRGRP
) && tentry
.entries
[i
] < 0) { /* Supergroup */
1965 return 5; /* not yet, in short. */
1967 code
= ChangeIDEntry(at
, aid
, newid
, tentry
.entries
[i
]);
1972 for (pos
= ntohl(tentry
.owned
); pos
; pos
= nextpos
) {
1973 code
= pr_ReadEntry(at
, 0, pos
, &tent
);
1977 nextpos
= tent
.nextOwned
;
1978 code
= pr_WriteEntry(at
, 0, pos
, &tent
);
1984 #define centry (*(struct contentry*)&tent)
1985 code
= pr_ReadCoEntry(at
, 0, pos
, ¢ry
);
1986 if ((centry
.id
!= aid
)
1987 || !(centry
.flags
& PRCONT
)) {
1989 "ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
1990 aid
, centry
.id
, centry
.flags
);
1994 for (i
= 0; i
< COSIZE
; i
++) {
1995 if (centry
.entries
[i
] == PRBADID
)
1997 if (centry
.entries
[i
] == 0)
1999 if ((centry
.flags
& PRGRP
) && centry
.entries
[i
] < 0) { /* Supergroup */
2000 return 5; /* not yet, in short. */
2002 code
= ChangeIDEntry(at
, aid
, newid
, centry
.entries
[i
]);
2007 code
= pr_WriteCoEntry(at
, 0, pos
, ¢ry
);
2014 #else /* SUPERGROUPS */
2017 /* Also change the references from the membership list */
2018 for (i
= 0; i
< PRSIZE
; i
++) {
2019 if (tentry
.entries
[i
] == PRBADID
)
2021 if (tentry
.entries
[i
] == 0)
2023 pos
= FindByID(at
, tentry
.entries
[i
]);
2026 code
= RemoveFromEntry(at
, aid
, tentry
.entries
[i
]);
2029 code
= pr_ReadEntry(at
, 0, pos
, &tent
);
2032 code
= AddToEntry(at
, &tent
, pos
, newid
);
2036 /* Look through cont entries too. This needs to be broken into
2037 * seperate transaction so that no one transaction becomes too
2038 * large to complete.
2040 for (nptr
= tentry
.next
; nptr
; nptr
= centry
.next
) {
2041 code
= pr_ReadCoEntry(at
, 0, nptr
, ¢ry
);
2044 for (i
= 0; i
< COSIZE
; i
++) {
2045 if (centry
.entries
[i
] == PRBADID
)
2047 if (centry
.entries
[i
] == 0)
2049 pos
= FindByID(at
, centry
.entries
[i
]);
2052 code
= RemoveFromEntry(at
, aid
, centry
.entries
[i
]);
2055 code
= pr_ReadEntry(at
, 0, pos
, &tent
);
2058 code
= AddToEntry(at
, &tent
, pos
, newid
);
2063 #endif /* SUPERGROUPS */
2066 atsign
= strchr(tentry
.name
, '@'); /* check for foreign entry */
2068 /* Change the owner */
2069 if (oid
&& (oid
!= tentry
.owner
)) {
2070 /* only groups can have their owner's changed */
2071 if (!(tentry
.flags
& PRGRP
))
2075 oldowner
= tentry
.owner
;
2077 /* The entry must be written through first so Remove and Add routines
2078 * can operate on disk data */
2079 code
= pr_WriteEntry(at
, 0, loc
, &tentry
);
2083 /* switch owner chains */
2084 if (oldowner
) /* if it has an owner */
2085 code
= RemoveFromOwnerChain(at
, tentry
.id
, oldowner
);
2086 else /* must be an orphan */
2087 code
= RemoveFromOrphan(at
, tentry
.id
);
2090 code
= AddToOwnerChain(at
, tentry
.id
, tentry
.owner
);
2094 /* fix up the name */
2095 if (strlen(name
) == 0)
2097 /* get current data */
2098 code
= pr_ReadEntry(at
, 0, loc
, &tentry
);
2103 /* Change the name, if name is a ptr to tentry.name then this name change
2104 * is due to a chown, otherwise caller has specified a new name */
2105 if ((name
== tentry
.name
) || (*name
&& (strcmp(tentry
.name
, name
) != 0))) {
2106 strncpy(oldname
, tentry
.name
, PR_MAXNAMELEN
);
2107 if (tentry
.flags
& PRGRP
) {
2108 /* don't let foreign cell groups change name */
2112 if (tentry
.owner
== 0 || tentry
.owner
== ANONYMOUSID
)
2115 code
= CorrectGroupName(at
, name
, cid
, tentry
.owner
, admin
, tentry
.name
);
2119 if (name
== tentry
.name
) { /* owner fixup */
2120 if (strcmp(oldname
, tentry
.name
) == 0)
2122 } else { /* new name, caller must be correct */
2123 if (strcmp(name
, tentry
.name
) != 0)
2127 /* Allow a foreign name change only if the cellname part is
2132 newatsign
= strchr(name
, '@');
2133 if (newatsign
!= atsign
) { /* if they are the same no problem */
2134 /*if the pointers are not equal the strings better be */
2135 if ((atsign
== NULL
) || (newatsign
== NULL
)
2136 || strcmp(atsign
, newatsign
))
2139 if (!CorrectUserName(name
))
2143 pos
= FindByName(at
, name
, &tent
);
2146 code
= RemoveFromNameHash(at
, oldname
, &loc
);
2147 if (code
!= PRSUCCESS
)
2149 strncpy(tentry
.name
, name
, PR_MAXNAMELEN
);
2150 code
= pr_WriteEntry(at
, 0, loc
, &tentry
);
2153 code
= AddToNameHash(at
, tentry
.name
, loc
);
2154 if (code
!= PRSUCCESS
)
2163 allocNextId(struct ubik_trans
* at
, struct prentry
* cellEntry
)
2165 /* Id's for foreign cell entries are constructed as follows:
2166 * The 16 low order bits are the group id of the cell and the
2167 * top 16 bits identify the particular users in that cell */
2170 afs_int32 cellid
= ((ntohl(cellEntry
->id
)) & 0x0000ffff);
2172 id
= (ntohl(cellEntry
->nusers
) + 1);
2173 while (FindByID(at
, ((id
<< 16) | cellid
))) {
2179 cellEntry
->nusers
= htonl(id
);
2180 /* use the field nusers to keep
2181 * the next available id in that
2182 * foreign cell's group. Note :
2183 * It would seem more appropriate
2184 * to use ngroup for that and nusers
2185 * to enforce the quota, however pts
2186 * does not have an option to change
2187 * foreign users quota yet */
2189 id
= (id
<< 16) | cellid
;
2194 inRange(struct prentry
*cellEntry
, afs_int32 aid
)
2196 afs_uint32 id
, cellid
, groupid
;
2200 * The only thing that we want to make sure here is that
2201 * the id is in the legal range of this group. If it is
2202 * a duplicate we don't care since it will get caught
2203 * in a different check.
2206 cellid
= aid
& 0x0000ffff;
2207 groupid
= (ntohl(cellEntry
->id
)) & 0x0000ffff;
2208 if (cellid
!= groupid
)
2209 return 0; /* not in range */
2212 * if we got here we're ok but we need to update the nusers
2213 * field in order to get the id correct the next time that
2214 * we try to allocate it automatically
2218 if (id
> ntohl(cellEntry
->nusers
))
2219 cellEntry
->nusers
= htonl(id
);
2225 AddAuthGroup(struct prentry
*tentry
, prlist
*alist
, afs_int32
*size
)
2227 if (!(strchr(tentry
->name
, '@')))
2228 return (AddToPRList(alist
, size
, AUTHUSERID
));