87d24a7ba2bd4e46798eac9ea19fedc0e07f98db
[openafs.git] / src / ptserver / ptutils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /* 
11  *                      (5) Add functions to process supergroups:
12  *                          ChangeIDEntry(), RemoveFromSGEntry(),
13  *                          AddToSGEntry(), GetListSG2().
14  *                      (6) Add code to existing functions to process
15  *                          supergroups.
16  *      2/1/98 jjm      Add mdw's changes for bit mapping for supergroups
17  *
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.
21  */
22
23 #include <afsconfig.h>
24 #include <afs/param.h>
25
26
27 #include <afs/stds.h>
28 #include <sys/types.h>
29 #include <stdio.h>
30 #ifdef AFS_NT40_ENV
31 #include <winsock2.h>
32 #else
33 #include <netinet/in.h>
34 #endif
35 #include <string.h>
36 #include <lock.h>
37 #include <ubik.h>
38 #include <rx/xdr.h>
39 #include <afs/com_err.h>
40 #include <afs/cellconfig.h>
41 #include "ptserver.h"
42 #include "pterror.h"
43 #include "ptprototypes.h"
44 #include <stdlib.h>
45
46 /* Foreign cells are represented by the group system:authuser@cell*/
47 #define AUTHUSER_GROUP "system:authuser"
48
49 extern int restricted;
50 extern struct ubik_dbase *dbase;
51 extern struct afsconf_dir *prdir;
52 extern int pr_noAuth;
53
54 static int inRange(struct prentry *cellEntry, afs_int32 aid);
55 static afs_int32 allocNextId(struct ubik_trans *, struct prentry *);
56 static int AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size);
57
58 static char *whoami = "ptserver";
59
60 int prp_user_default = PRP_USER_DEFAULT;
61 int prp_group_default = PRP_GROUP_DEFAULT;
62
63 #if defined(SUPERGROUPS)
64
65 #include "map.h"
66
67 afs_int32 depthsg = 5;          /* Maximum iterations used during IsAMemberOF */
68 afs_int32 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist * alist,
69                      afs_int32 * sizeP, afs_int32 depth);
70
71 struct map *sg_flagged;
72 struct map *sg_found;
73
74 #define NIL_MAP ((struct map *) 0)
75
76 /* pt_mywrite hooks into the logic that writes ubik records to disk
77  *  at a very low level.  It invalidates mappings in sg_flagged/sg_found.
78  *  By hoooking in at this level, we ensure that a ubik file reload
79  *  invalidates our incore cache.
80  *
81  * We assert records, cheaders and everything else are 0 mod 64.
82  *  So, we can always see the first 64 bytes of any record written.
83  *  The stuff we're interested in (flags, id) are in the first 8 bytes.
84  *  so we can always tell if we're writing a group record.
85  */
86
87 int (*pt_save_dbase_write) ();
88
89 int
90 pt_mywrite(struct ubik_dbase *tdb, afs_int32 fno, char *bp, afs_int32 pos, afs_int32 count)
91 {
92     afs_uint32 headersize = ntohl(cheader.headerSize);
93
94     if (fno == 0 && pos + count > headersize) {
95         afs_int32 p, l, c, o;
96         char *cp;
97         p = pos - headersize;
98         cp = bp;
99         l = count;
100         if (p < 0) {
101             l += p;
102             p = 0;
103         }
104         while (l > 0) {
105             o = p % ENTRYSIZE;
106             c = ENTRYSIZE - o;
107             if (c > l)
108                 c = l;
109 #define xPT(p,x) ((((struct prentry *)(p))->flags & htonl(PRTYPE)) == htonl(x))
110 #if DEBUG_SG_MAP
111             if (o)
112                 fprintf(stderr, "Writing %d bytes of entry @ %#lx(+%d)\n", c,
113                         p - o, o);
114             else if (c == ENTRYSIZE)
115                 fprintf(stderr,
116                         "Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n",
117                         c, p, ntohl(((struct prentry *)cp)->flags),
118                         xPT(cp,PRUSER) ? "user" : xPT(cp,PRFREE) ? "free" :
119                         xPT(cp,PRGRP) ? "group" : xPT(cp,PRCONT) ? "cont" :
120                         xPT(cp,PRCELL) ? "cell" : xPT(cp,PRFOREIGN) ? "foreign" :
121                         xPT(cp,PRINST) ? "sub/super instance" : "?",
122                         ntohl(((struct prentry *)cp)->id));
123             else if (c >= 8)
124                 fprintf(stderr,
125                         "Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n",
126                         c, p, ntohl(((struct prentry *)cp)->flags),
127                         xPT(cp,PRUSER) ? "user" : xPT(cp,PRFREE) ? "free" :
128                         xPT(cp,PRGRP) ? "group" : xPT(cp,PRCONT) ? "cont" :
129                         xPT(cp,PRCELL) ? "cell" : xPT(cp,PRFOREIGN) ? "foreign" :
130                         xPT(cp,PRINST) ? "sub/super instance" : "?",
131                         ntohl(((struct prentry *)cp)->id));
132             else
133                 fprintf(stderr, "Writing %d bytes of entry @ %#lx\n", c, p);
134 #endif
135             if (!o && c >= 8 && xPT(cp,PRGRP)) {
136 #if DEBUG_SG_MAP
137                 if (in_map(sg_found, -ntohl(((struct prentry *)cp)->id)))
138                     fprintf(stderr, "Unfound: Removing group %d\n",
139                             ntohl(((struct prentry *)cp)->id));
140                 if (in_map(sg_flagged, -ntohl(((struct prentry *)cp)->id)))
141                     fprintf(stderr, "Unflag: Removing group %d\n",
142                             ntohl(((struct prentry *)cp)->id));
143 #endif
144                 sg_found =
145                     bic_map(sg_found,
146                         add_map(NIL_MAP, -ntohl(((struct prentry *)cp)->id)));
147                 sg_flagged =
148                     bic_map(sg_flagged,
149                         add_map(NIL_MAP, -ntohl(((struct prentry *)cp)->id)));
150             }
151             cp += c;
152             p += c;
153             l -= c;
154 #undef xPT
155         }
156     }
157     return (*pt_save_dbase_write) (tdb, fno, bp, pos, count);
158 }
159
160 /*
161  * this function attaches pt_mywrite.  It's called once,
162  *  just after ubik_ServerInit.
163  */
164
165 void 
166 pt_hook_write()
167 {
168     extern struct ubik_dbase *ubik_dbase;
169     if (ubik_dbase->write != pt_mywrite) {
170         pt_save_dbase_write = ubik_dbase->write;
171         ubik_dbase->write = pt_mywrite;
172     }
173 }
174
175 #endif /* SUPERGROUPS */
176
177 /* CorrectUserName - Check to make sure a user name is OK.  It must not include
178  *   either a colon (or it would look like a group) or an atsign (or it would
179  *   look like a foreign user).  The length is checked as well to make sure
180  *   that the user name, an atsign, and the local cell name will fit in
181  *   PR_MAXNAMELEN.  This is so this user can fit in another cells database as
182  *   a foreign user with our cell name tacked on.  This is a predicate, so it
183  *   return one if name is OK and zero if name is bogus. */
184
185 static int
186 CorrectUserName(char *name)
187 {
188     extern int pr_realmNameLen;
189
190     /* We accept foreign names, so we will deal with '@' later */
191     if (strchr(name, ':') || strchr(name, '\n'))
192         return 0;
193     if (strlen(name) >= PR_MAXNAMELEN - pr_realmNameLen - 1)
194         return 0;
195     return 1;
196 }
197
198 /* CorrectGroupName - Like the above but handles more complicated cases caused
199  * by including the ownership in the name.  The interface works by calculating
200  * the correct name based on a given name and owner.  This allows easy use by
201  * rename, which then compares the correct name with the requested new name. */
202
203 static afs_int32
204 CorrectGroupName(struct ubik_trans *ut, char aname[PR_MAXNAMELEN],      /* name for group */
205                  afs_int32 cid,         /* caller id */
206                  afs_int32 oid,         /* owner of group */
207                  char cname[PR_MAXNAMELEN])     /* correct name for group */
208 {
209     afs_int32 code;
210     int admin;
211     char *prefix;               /* ptr to group owner part */
212     char *suffix;               /* ptr to group name part */
213     char name[PR_MAXNAMELEN];   /* correct name for group */
214     struct prentry tentry;
215
216     if (strlen(aname) >= PR_MAXNAMELEN)
217         return PRBADNAM;
218     admin = pr_noAuth || IsAMemberOf(ut, cid, SYSADMINID);
219
220     if (oid == 0)
221         oid = cid;
222
223     /* Determine the correct prefix for the name. */
224     if (oid == SYSADMINID)
225         prefix = "system";
226     else {
227         afs_int32 loc = FindByID(ut, oid);
228         if (loc == 0) {
229             /* let admin create groups owned by non-existent ids (probably
230              * setting a group to own itself).  Check that they look like
231              * groups (with a colon) or otherwise are good user names. */
232             if (admin) {
233                 strcpy(cname, aname);
234                 goto done;
235             }
236             return PRNOENT;
237         }
238         code = pr_Read(ut, 0, loc, &tentry, sizeof(tentry));
239         if (code)
240             return code;
241         if (ntohl(tentry.flags) & PRGRP) {
242             if ((tentry.count == 0) && !admin)
243                 return PRGROUPEMPTY;
244             /* terminate prefix at colon if there is one */
245             if ((prefix = strchr(tentry.name, ':')))
246                 *prefix = 0;
247         }
248         prefix = tentry.name;
249     }
250     /* only sysadmin allow to use 'system:' prefix */
251     if ((strcmp(prefix, "system") == 0) && !admin)
252         return PRPERM;
253
254     strcpy(name, aname);        /* in case aname & cname are same */
255     suffix = strchr(name, ':');
256     if (suffix == 0) {
257         /* sysadmin can make groups w/o ':', but they must still look like
258          * legal user names. */
259         if (!admin)
260             return PRBADNAM;
261         strcpy(cname, name);
262     } else {
263         if (strlen(prefix) + strlen(suffix) >= PR_MAXNAMELEN)
264             return PRBADNAM;
265         strcpy(cname, prefix);
266         strcat(cname, suffix);
267     }
268   done:
269     /* check for legal name with either group rules or user rules */
270     if ((suffix = strchr(cname, ':'))) {
271         /* check for confusing characters */
272         if (strchr(cname, '\n') ||      /* restrict so recreate can work */
273             strchr(suffix + 1, ':'))    /* avoid multiple colons */
274             return PRBADNAM;
275     } else {
276         if (!CorrectUserName(cname))
277             return PRBADNAM;
278     }
279     return 0;
280 }
281
282 int
283 AccessOK(struct ubik_trans *ut, afs_int32 cid,          /* caller id */
284          struct prentry *tentry,        /* object being accessed */
285          int mem,                       /* check membership in aid, if group */
286          int any)                       /* if set return true */
287 {
288     afs_int32 flags;
289     afs_int32 oid;
290     afs_int32 aid;
291
292     if (pr_noAuth)
293         return 1;
294     if (cid == SYSADMINID)
295         return 1;               /* special case fileserver */
296     if (restricted && ((mem == PRP_ADD_MEM) || (mem == PRP_REMOVE_MEM)) && (any == 0))
297         return 0;
298     if (tentry) {
299         flags = tentry->flags;
300         oid = tentry->owner;
301         aid = tentry->id;
302     } else {
303         flags = oid = aid = 0;
304     }
305     if (!(flags & PRACCESS)) {  /* provide default access */
306         if (flags & PRGRP)
307             flags |= prp_group_default;
308         else
309             flags |= prp_user_default;
310     }
311
312     if (flags & any)
313         return 1;
314     if (oid) {
315         if ((cid == oid) || IsAMemberOf(ut, cid, oid))
316             return 1;
317     }
318     if (aid > 0) {              /* checking on a user */
319         if (aid == cid)
320             return 1;
321     } else if (aid < 0) {       /* checking on group */
322         if ((flags & mem) && IsAMemberOf(ut, cid, aid))
323             return 1;
324     }
325     /* Allow members of SYSVIEWERID to get membership and status only */
326     if (((mem == PRP_STATUS_MEM) || (mem == PRP_MEMBER_MEM)
327          || (any == PRP_OWNED_ANY)) && (IsAMemberOf(ut, cid, SYSVIEWERID)))
328         return 1;
329     if (IsAMemberOf(ut, cid, SYSADMINID))
330         return 1;
331     return 0;                   /* no access */
332 }
333
334 afs_int32
335 CreateEntry(struct ubik_trans *at, char aname[PR_MAXNAMELEN], afs_int32 *aid, afs_int32 idflag, afs_int32 flag, afs_int32 oid, afs_int32 creator)
336 {
337     /* get and init a new entry */
338     afs_int32 code;
339     afs_int32 newEntry;
340     struct prentry tentry, tent;
341     char *atsign;
342
343     memset(&tentry, 0, sizeof(tentry));
344
345     if ((oid == 0) || (oid == ANONYMOUSID))
346         oid = creator;
347
348     if (flag & PRGRP) {
349         code = CorrectGroupName(at, aname, creator, oid, tentry.name);
350         if (code)
351             return code;
352         if (strcmp(aname, tentry.name) != 0)
353             return PRBADNAM;
354     } else {                    /* non-group must not have colon */
355         if (!CorrectUserName(aname))
356             return PRBADNAM;
357         strcpy(tentry.name, aname);
358     }
359
360     if (FindByName(at, aname, &tent))
361         return PREXIST;
362
363     newEntry = AllocBlock(at);
364     if (!newEntry)
365         return PRDBFAIL;
366 #ifdef PR_REMEMBER_TIMES
367     tentry.createTime = time(0);
368 #endif
369
370     if (flag & PRGRP) {
371         tentry.flags = PRGRP;
372         tentry.owner = oid;
373     } else if (flag == 0) {
374         tentry.flags = 0;
375         tentry.owner = SYSADMINID;
376     } else {
377         return PRBADARG;
378     }
379
380     atsign = strchr(aname, '@');
381     if (!atsign) {
382         /* A normal user or group. Pick an id for it */
383         if (idflag)
384             tentry.id = *aid;
385         else {
386             code = AllocID(at, flag, &tentry.id);
387             if (code != PRSUCCESS)
388                 return code;
389         }
390     } else if (flag & PRGRP) {
391         /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
392          * Then pick an id for the group.
393          */
394         int badFormat;
395
396         *atsign = '\0';
397         badFormat = strcmp(AUTHUSER_GROUP, aname);
398         *atsign = '@';
399         if (badFormat)
400             return PRBADNAM;
401
402         if (idflag)
403             tentry.id = *aid;
404         else {
405             code = AllocID(at, flag, &tentry.id);
406             if (code != PRSUCCESS)
407                 return code;
408         }
409     } else {
410         /* A foreign user: <name>@<cell>. The foreign user is added to
411          * its representing group. It is 
412          */
413         char *cellGroup;
414         afs_int32 pos, n;
415         struct prentry centry;
416
417         /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
418          * must exist.
419          */
420         cellGroup =
421             (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
422         strcpy(cellGroup, AUTHUSER_GROUP);
423         strcat(cellGroup, atsign);
424         pos = FindByName(at, cellGroup, &centry);
425         free(cellGroup);
426         if (!pos)
427             return PRBADNAM;
428         code = pr_Read(at, 0, pos, &centry, sizeof(centry));
429         if (code)
430             return code;
431
432         /* cellid is the id of the group representing the cell */
433         tentry.cellid = ntohl(centry.id);
434
435         if (idflag) {
436             /* Check if id is good */
437             if (!inRange(&centry, *aid))
438                 return PRBADARG;
439             tentry.id = *aid;
440         } else {
441             /* Allocate an ID special for this foreign user. It is based 
442              * on the representing group's id and nusers count.
443              */
444             tentry.id = allocNextId(at, &centry);
445             if (!tentry.id)
446                 return PRNOIDS;
447         }
448
449         /* The foreign user will be added to the representing foreign
450          * group. The group can hold up to 30 entries.
451          */
452         if (!(ntohl(centry.flags) & PRQUOTA)) {
453             centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
454             centry.ngroups = htonl(30);
455         }
456         n = ntohl(centry.ngroups);
457         if ((n <= 0) && !pr_noAuth)
458             return PRNOMORE;
459         centry.ngroups = htonl(n - 1);
460
461         /* write updated entry for group */
462         code = pr_Write(at, 0, pos, &centry, sizeof(centry));
463
464         /* Now add the new user entry to the database */
465         tentry.creator = creator;
466         *aid = tentry.id;
467         code = pr_WriteEntry(at, 0, newEntry, &tentry);
468         if (code)
469             return PRDBFAIL;
470         code = AddToIDHash(at, *aid, newEntry);
471         if (code != PRSUCCESS)
472             return code;
473         code = AddToNameHash(at, aname, newEntry);
474         if (code != PRSUCCESS)
475             return code;
476         if (inc_header_word(at, foreigncount, 1))
477             return PRDBFAIL;
478
479         /* Now add the entry to the authuser group for this cell.
480          * We will reread the entries for the user and the group
481          * instead of modifying them before writing them in the
482          * previous steps. Although not very efficient, much simpler
483          */
484         pos = FindByID(at, tentry.cellid);
485         if (!pos)
486             return PRBADNAM;
487         code = pr_ReadEntry(at, 0, pos, &centry);
488         if (code)
489             return code;
490         code = AddToEntry(at, &centry, pos, *aid);
491         if (code)
492             return code;
493         /* and now the user entry */
494         pos = FindByID(at, *aid);
495         if (!pos)
496             return PRBADNAM;
497         code = pr_ReadEntry(at, 0, pos, &tentry);
498         if (code)
499             return code;
500         code = AddToEntry(at, &tentry, pos, tentry.cellid);
501         if (code)
502             return code;
503
504         return PRSUCCESS;
505     }
506
507     /* Remember the largest group id or largest user id */
508     if (flag & PRGRP) {
509         /* group ids are negative */
510         if (tentry.id < (afs_int32) ntohl(cheader.maxGroup)) {
511             code = set_header_word(at, maxGroup, htonl(tentry.id));
512             if (code)
513                 return PRDBFAIL;
514         }
515     } else {
516         if (tentry.id > (afs_int32) ntohl(cheader.maxID)) {
517             code = set_header_word(at, maxID, htonl(tentry.id));
518             if (code)
519                 return PRDBFAIL;
520         }
521     }
522
523     /* Charge the creator for this group */
524     if (flag & PRGRP) {
525         afs_int32 loc = FindByID(at, creator);
526         struct prentry centry;
527         int admin;
528
529         if (loc) {              /* this should only fail during initialization */
530             code = pr_Read(at, 0, loc, &centry, sizeof(centry));
531             if (code)
532                 return code;
533
534             /* If quota is uninitialized, do it */
535             if (!(ntohl(centry.flags) & PRQUOTA)) {
536                 centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
537                 centry.ngroups = centry.nusers = htonl(20);
538             }
539
540             /* Admins don't get charged for creating a group.
541              * If in noAuth mode, you get changed for it but you 
542              * are still allowed to create as many groups as you want.
543              */
544             admin = ((creator == SYSADMINID)
545                      || IsAMemberOf(at, creator, SYSADMINID));
546             if (!admin) {
547                 if (ntohl(centry.ngroups) <= 0) {
548                     if (!pr_noAuth)
549                         return PRNOMORE;
550                 } else {
551                     centry.ngroups = htonl(ntohl(centry.ngroups) - 1);
552                 }
553             }
554
555             code = pr_Write(at, 0, loc, &centry, sizeof(centry));
556             if (code)
557                 return code;
558         }                       /* if (loc) */
559     } else {
560         /* Initialize the quota for the user. Groups don't have their
561          * quota initialized.
562          */
563         tentry.flags |= PRQUOTA;
564         tentry.ngroups = tentry.nusers = 20;
565     }
566
567     tentry.creator = creator;
568     *aid = tentry.id;
569     code = pr_WriteEntry(at, 0, newEntry, &tentry);
570     if (code)
571         return PRDBFAIL;
572     code = AddToIDHash(at, *aid, newEntry);
573     if (code != PRSUCCESS)
574         return code;
575     code = AddToNameHash(at, aname, newEntry);
576     if (code != PRSUCCESS)
577         return code;
578     if (tentry.flags & PRGRP) {
579         code = AddToOwnerChain(at, tentry.id, oid);
580         if (code)
581             return code;
582     }
583     if (tentry.flags & PRGRP) {
584         if (inc_header_word(at, groupcount, 1))
585             return PRDBFAIL;
586     } else if (tentry.flags & PRINST) {
587         if (inc_header_word(at, instcount, 1))
588             return PRDBFAIL;
589     } else {
590         if (inc_header_word(at, usercount, 1))
591             return PRDBFAIL;
592     }
593     return PRSUCCESS;
594 }
595
596
597 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
598  * entry if appropriate */
599
600 afs_int32
601 RemoveFromEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
602 {
603     afs_int32 code;
604     struct prentry tentry;
605     struct contentry centry;
606     struct contentry hentry;
607     afs_int32 temp;
608     afs_int32 i, j;
609     afs_int32 nptr;
610     afs_int32 hloc;
611
612     if (aid == bid)
613         return PRINCONSISTENT;
614     memset(&hentry, 0, sizeof(hentry));
615     temp = FindByID(at, bid);
616     if (temp == 0)
617         return PRNOENT;
618     code = pr_ReadEntry(at, 0, temp, &tentry);
619     if (code != 0)
620         return code;
621 #ifdef PR_REMEMBER_TIMES
622     tentry.removeTime = time(0);
623 #endif
624     for (i = 0; i < PRSIZE; i++) {
625         if (tentry.entries[i] == aid) {
626             tentry.entries[i] = PRBADID;
627             tentry.count--;
628             code = pr_WriteEntry(at, 0, temp, &tentry);
629             if (code != 0)
630                 return code;
631             return PRSUCCESS;
632         }
633         if (tentry.entries[i] == 0)     /* found end of list */
634             return PRNOENT;
635     }
636     hloc = 0;
637     nptr = tentry.next;
638     while (nptr != 0) {
639         code = pr_ReadCoEntry(at, 0, nptr, &centry);
640         if (code != 0)
641             return code;
642         if ((centry.id != bid) || !(centry.flags & PRCONT))
643             return PRDBBAD;
644         for (i = 0; i < COSIZE; i++) {
645             if (centry.entries[i] == aid) {
646                 centry.entries[i] = PRBADID;
647                 for (j = 0; j < COSIZE; j++)
648                     if (centry.entries[j] != PRBADID
649                         && centry.entries[j] != 0)
650                         break;
651                 if (j == COSIZE) {      /* can free this block */
652                     if (hloc == 0) {
653                         tentry.next = centry.next;
654                     } else {
655                         hentry.next = centry.next;
656                         code = pr_WriteCoEntry(at, 0, hloc, &hentry);
657                         if (code != 0)
658                             return code;
659                     }
660                     code = FreeBlock(at, nptr);
661                     if (code)
662                         return code;
663                 } else {        /* can't free it yet */
664                     code = pr_WriteCoEntry(at, 0, nptr, &centry);
665                     if (code != 0)
666                         return code;
667                 }
668                 tentry.count--;
669                 code = pr_WriteEntry(at, 0, temp, &tentry);
670                 if (code)
671                     return PRDBFAIL;
672                 return 0;
673             }
674             if (centry.entries[i] == 0)
675                 return PRNOENT;
676         }                       /* for all coentry slots */
677         hloc = nptr;
678         nptr = centry.next;
679         memcpy(&hentry, &centry, sizeof(centry));
680     }                           /* while there are coentries */
681     return PRNOENT;
682 }
683
684 #if defined(SUPERGROUPS)
685 /* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
686  * entry if appropriate */
687
688 afs_int32
689 ChangeIDEntry(register struct ubik_trans *at, register afs_int32 aid, afs_int32 newid, register afs_int32 bid)
690 {
691     register afs_int32 code;
692     struct prentry tentry;
693     struct contentry centry;
694     afs_int32 temp;
695     afs_int32 i, j;
696     afs_int32 nptr;
697
698     if (aid == bid)
699         return PRINCONSISTENT;
700     temp = FindByID(at, bid);
701     if (temp == 0) {
702         return PRNOENT;
703     }
704     code = pr_ReadEntry(at, 0, temp, &tentry);
705     if (code != 0)
706         return code;
707     for (i = 0; i < PRSIZE; i++) {
708         if (tentry.entries[i] == aid) {
709             tentry.entries[i] = newid;
710             code = pr_WriteEntry(at, 0, temp, &tentry);
711             if (code != 0)
712                 return code;
713             return PRSUCCESS;
714         }
715         if (tentry.entries[i] == 0) {   /* found end of list */
716             return PRNOENT;
717         }
718     }
719
720     nptr = tentry.next;
721     while (nptr) {
722         code = pr_ReadCoEntry(at, 0, nptr, &centry);
723         if (code != 0)
724             return code;
725         if ((centry.id != bid) || !(centry.flags & PRCONT)) {
726             fprintf(stderr,
727                     "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
728                     bid, centry.id, centry.flags);
729             return PRDBBAD;
730         }
731         for (i = 0; i < COSIZE; i++) {
732             if (centry.entries[i] == aid) {
733                 centry.entries[i] = newid;
734                 for (j = 0; j < COSIZE; j++)
735                     if (centry.entries[j] != PRBADID
736                         && centry.entries[j] != 0)
737                         break;
738                 code = pr_WriteCoEntry(at, 0, nptr, &centry);
739                 if (code != 0)
740                     return code;
741                 return 0;
742             }
743             if (centry.entries[i] == 0) {
744                 return PRNOENT;
745             }
746         }                       /* for all coentry slots */
747         nptr = centry.next;
748     }                           /* while there are coentries */
749     return PRNOENT;
750 }
751
752 /*  #ifdef SUPERGROUPS */
753 /* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
754  * continuation entry if appropriate */
755
756 afs_int32
757 RemoveFromSGEntry(register struct ubik_trans *at, register afs_int32 aid, register afs_int32 bid)
758 {
759     register afs_int32 code;
760     struct prentry tentry;
761     struct prentryg *tentryg;
762     struct contentry centry;
763     struct contentry hentry;
764     afs_int32 temp;
765     afs_int32 i, j;
766     afs_int32 nptr;
767     afs_int32 hloc;
768
769     if (aid == bid)
770         return PRINCONSISTENT;
771     memset(&hentry, 0, sizeof(hentry));
772     temp = FindByID(at, bid);
773     if (temp == 0) {
774         return PRNOENT;
775     }
776     code = pr_ReadEntry(at, 0, temp, &tentry);
777     if (code != 0)
778         return code;
779 #ifdef PR_REMEMBER_TIMES
780     tentry.removeTime = time(NULL);
781 #endif
782     tentryg = (struct prentryg *)&tentry;
783     for (i = 0; i < SGSIZE; i++) {
784         if (tentryg->supergroup[i] == aid) {
785             tentryg->supergroup[i] = PRBADID;
786             tentryg->countsg--;
787             code = pr_WriteEntry(at, 0, temp, &tentry);
788             if (code != 0)
789                 return code;
790             return PRSUCCESS;
791         }
792         if (tentryg->supergroup[i] == 0) {      /* found end of list */
793             return PRNOENT;
794         }
795     }
796     hloc = 0;
797     nptr = tentryg->nextsg;
798     while (nptr) {
799         code = pr_ReadCoEntry(at, 0, nptr, &centry);
800         if (code != 0)
801             return code;
802         if ((centry.id != bid) || !(centry.flags & PRCONT)) {
803             fprintf(stderr,
804                     "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
805                     bid, centry.id, centry.flags);
806             return PRDBBAD;
807         }
808         for (i = 0; i < COSIZE; i++) {
809             if (centry.entries[i] == aid) {
810                 centry.entries[i] = PRBADID;
811                 for (j = 0; j < COSIZE; j++)
812                     if (centry.entries[j] != PRBADID
813                         && centry.entries[j] != 0)
814                         break;
815                 if (j == COSIZE) {      /* can free this block */
816                     if (hloc == 0) {
817                         tentryg->nextsg = centry.next;
818                     } else {
819                         hentry.next = centry.next;
820                         code = pr_WriteCoEntry(at, 0, hloc, &hentry);
821                         if (code != 0)
822                             return code;
823                     }
824                     code = FreeBlock(at, nptr);
825                     if (code)
826                         return code;
827                 } else {        /* can't free it yet */
828                     code = pr_WriteCoEntry(at, 0, nptr, &centry);
829                     if (code != 0)
830                         return code;
831                 }
832                 tentryg->countsg--;
833                 code = pr_WriteEntry(at, 0, temp, &tentry);
834                 if (code)
835                     return PRDBFAIL;
836                 return 0;
837             }
838             if (centry.entries[i] == 0) {
839                 return PRNOENT;
840             }
841         }                       /* for all coentry slots */
842         hloc = nptr;
843         nptr = centry.next;
844         memcpy((char *)&centry, (char *)&hentry, sizeof(centry));
845     }                           /* while there are coentries */
846     return PRNOENT;
847 }
848
849 #endif /* SUPERGROUPS */
850
851 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
852  * groups, putting groups owned by it on orphan chain, and freeing the space */
853
854 afs_int32
855 DeleteEntry(struct ubik_trans *at, struct prentry *tentry, afs_int32 loc)
856 {
857     afs_int32 code;
858     struct contentry centry;
859     afs_int32 i;
860     afs_int32 nptr;
861
862     if (strchr(tentry->name, '@')) {
863         if (tentry->flags & PRGRP) {
864             /* If there are still foreign user accounts from that cell
865              * don't delete the group */
866             if (tentry->count)
867                 return PRBADARG;
868         } else {
869             /* adjust quota */
870
871             afs_int32 loc = FindByID(at, tentry->cellid);
872             struct prentry centry;
873             if (loc) {
874                 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
875                 if (code)
876                     return code;
877                 if (ntohl(centry.flags) & PRQUOTA) {
878                     centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
879                 }
880                 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
881                 if (code)
882                     return code;
883             }
884         }
885     }
886     /* First remove the entire membership list */
887     for (i = 0; i < PRSIZE; i++) {
888         if (tentry->entries[i] == PRBADID)
889             continue;
890         if (tentry->entries[i] == 0)
891             break;
892 #if defined(SUPERGROUPS)
893         if ((tentry->flags & PRGRP) && tentry->entries[i] < 0)  /* Supergroup */
894             code = RemoveFromSGEntry(at, tentry->id, tentry->entries[i]);
895         else
896 #endif
897             code = RemoveFromEntry(at, tentry->id, tentry->entries[i]);
898         if (code)
899             return code;
900     }
901 #if defined(SUPERGROUPS)
902     {
903         struct prentryg *tentryg = (struct prentryg *)tentry;
904
905         /* Then remove the entire supergroup list */
906         for (i = 0; i < SGSIZE; i++) {
907             if (tentryg->supergroup[i] == PRBADID)
908                 continue;
909             if (tentryg->supergroup[i] == 0)
910                 break;
911             code = RemoveFromEntry(at, tentry->id, tentryg->supergroup[i]);
912             if (code)
913                 return code;
914         }
915     }
916 #endif /* SUPERGROUPS */
917     nptr = tentry->next;
918     while (nptr != 0) {
919         code = pr_ReadCoEntry(at, 0, nptr, &centry);
920         if (code != 0)
921             return PRDBFAIL;
922         for (i = 0; i < COSIZE; i++) {
923             if (centry.entries[i] == PRBADID)
924                 continue;
925             if (centry.entries[i] == 0)
926                 break;
927             code = RemoveFromEntry(at, tentry->id, centry.entries[i]);
928             if (code)
929                 return code;
930         }
931         code = FreeBlock(at, nptr);     /* free continuation block */
932         if (code)
933             return code;
934         nptr = centry.next;
935     }
936
937     /* Remove us from other's owned chain.  Note that this will zero our owned
938      * field (on disk) so this step must follow the above step in case we are
939      * on our own owned list. */
940     if (tentry->flags & PRGRP) {
941         if (tentry->owner) {
942             code = RemoveFromOwnerChain(at, tentry->id, tentry->owner);
943             if (code)
944                 return code;
945         } else {
946             code = RemoveFromOrphan(at, tentry->id);
947             if (code)
948                 return code;
949         }
950     }
951
952     code = RemoveFromIDHash(at, tentry->id, &loc);
953     if (code != PRSUCCESS)
954         return code;
955     code = RemoveFromNameHash(at, tentry->name, &loc);
956     if (code != PRSUCCESS)
957         return code;
958
959     if (tentry->flags & PRGRP) {
960         afs_int32 loc = FindByID(at, tentry->creator);
961         struct prentry centry;
962         int admin;
963
964         if (loc) {
965             code = pr_Read(at, 0, loc, &centry, sizeof(centry));
966             if (code)
967                 return code;
968             admin = ((tentry->creator == SYSADMINID)
969                      || IsAMemberOf(at, tentry->creator, SYSADMINID));
970             if (ntohl(centry.flags) & PRQUOTA) {
971                 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
972                     centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
973                 }
974             }
975             code = pr_Write(at, 0, loc, &centry, sizeof(centry));
976             if (code)
977                 return code;
978         }
979     }
980
981     if (tentry->flags & PRGRP) {
982         if (inc_header_word(at, groupcount, -1))
983             return PRDBFAIL;
984     } else if (tentry->flags & PRINST) {
985         if (inc_header_word(at, instcount, -1))
986             return PRDBFAIL;
987     } else {
988         if (strchr(tentry->name, '@')) {
989             if (inc_header_word(at, foreigncount, -1))
990                 return PRDBFAIL;
991         } else {
992             if (inc_header_word(at, usercount, -1))
993                 return PRDBFAIL;
994         }
995     }
996     code = FreeBlock(at, loc);
997     return code;
998 }
999
1000 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
1001  * if needed.
1002  *
1003  * Note the entry is written out by this routine. */
1004
1005 afs_int32
1006 AddToEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1007 {
1008     afs_int32 code;
1009     afs_int32 i;
1010     struct contentry nentry;
1011     struct contentry aentry;
1012     afs_int32 nptr;
1013     afs_int32 last;             /* addr of last cont. block */
1014     afs_int32 first = 0;
1015     afs_int32 cloc = 0;
1016     afs_int32 slot = -1;
1017
1018     if (entry->id == aid)
1019         return PRINCONSISTENT;
1020 #ifdef PR_REMEMBER_TIMES
1021     entry->addTime = time(0);
1022 #endif
1023     for (i = 0; i < PRSIZE; i++) {
1024         if (entry->entries[i] == aid)
1025             return PRIDEXIST;
1026         if (entry->entries[i] == PRBADID) {     /* remember this spot */
1027             first = 1;
1028             slot = i;
1029         } else if (entry->entries[i] == 0) {    /* end of the line */
1030             if (slot == -1) {
1031                 first = 1;
1032                 slot = i;
1033             }
1034             break;
1035         }
1036     }
1037     last = 0;
1038     nptr = entry->next;
1039     while (nptr != 0) {
1040         code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1041         if (code != 0)
1042             return code;
1043         last = nptr;
1044         if (!(nentry.flags & PRCONT))
1045             return PRDBFAIL;
1046         for (i = 0; i < COSIZE; i++) {
1047             if (nentry.entries[i] == aid)
1048                 return PRIDEXIST;
1049             if (nentry.entries[i] == PRBADID) {
1050                 if (slot == -1) {
1051                     slot = i;
1052                     cloc = nptr;
1053                 }
1054             } else if (nentry.entries[i] == 0) {
1055                 if (slot == -1) {
1056                     slot = i;
1057                     cloc = nptr;
1058                 }
1059                 break;
1060             }
1061         }
1062         nptr = nentry.next;
1063     }
1064     if (slot != -1) {           /* we found a place */
1065         entry->count++;
1066         if (first) {            /* place is in first block */
1067             entry->entries[slot] = aid;
1068             code = pr_WriteEntry(tt, 0, loc, entry);
1069             if (code != 0)
1070                 return code;
1071             return PRSUCCESS;
1072         }
1073         code = pr_WriteEntry(tt, 0, loc, entry);
1074         if (code)
1075             return code;
1076         code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1077         if (code != 0)
1078             return code;
1079         aentry.entries[slot] = aid;
1080         code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1081         if (code != 0)
1082             return code;
1083         return PRSUCCESS;
1084     }
1085     /* have to allocate a continuation block if we got here */
1086     nptr = AllocBlock(tt);
1087     if (last) {
1088         /* then we should tack new block after last block in cont. chain */
1089         nentry.next = nptr;
1090         code = pr_WriteCoEntry(tt, 0, last, &nentry);
1091         if (code != 0)
1092             return code;
1093     } else {
1094         entry->next = nptr;
1095     }
1096     memset(&aentry, 0, sizeof(aentry));
1097     aentry.flags |= PRCONT;
1098     aentry.id = entry->id;
1099     aentry.next = 0;
1100     aentry.entries[0] = aid;
1101     code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1102     if (code != 0)
1103         return code;
1104     /* don't forget to update count, here! */
1105     entry->count++;
1106     code = pr_WriteEntry(tt, 0, loc, entry);
1107     return code;
1108
1109 }
1110
1111 #if defined(SUPERGROUPS)
1112
1113 /* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
1114  * continuation block if needed.
1115  *
1116  * Note the entry is written out by this routine. */
1117
1118 afs_int32
1119 AddToSGEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1120 {
1121     register afs_int32 code;
1122     afs_int32 i;
1123     struct contentry nentry;
1124     struct contentry aentry;
1125     struct prentryg *entryg;
1126     afs_int32 nptr;
1127     afs_int32 last;             /* addr of last cont. block */
1128     afs_int32 first = 0;
1129     afs_int32 cloc;
1130     afs_int32 slot = -1;
1131
1132     if (entry->id == aid)
1133         return PRINCONSISTENT;
1134 #ifdef PR_REMEMBER_TIMES
1135     entry->addTime = time(NULL);
1136 #endif
1137     entryg = (struct prentryg *)entry;
1138     for (i = 0; i < SGSIZE; i++) {
1139         if (entryg->supergroup[i] == aid)
1140             return PRIDEXIST;
1141         if (entryg->supergroup[i] == PRBADID) { /* remember this spot */
1142             first = 1;
1143             slot = i;
1144         } else if (entryg->supergroup[i] == 0) {        /* end of the line */
1145             if (slot == -1) {
1146                 first = 1;
1147                 slot = i;
1148             }
1149             break;
1150         }
1151     }
1152     last = 0;
1153     nptr = entryg->nextsg;
1154     while (nptr) {
1155         code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1156         if (code != 0)
1157             return code;
1158         last = nptr;
1159         if (!(nentry.flags & PRCONT))
1160             return PRDBFAIL;
1161         for (i = 0; i < COSIZE; i++) {
1162             if (nentry.entries[i] == aid)
1163                 return PRIDEXIST;
1164             if (nentry.entries[i] == PRBADID) {
1165                 if (slot == -1) {
1166                     slot = i;
1167                     cloc = nptr;
1168                 }
1169             } else if (nentry.entries[i] == 0) {
1170                 if (slot == -1) {
1171                     slot = i;
1172                     cloc = nptr;
1173                 }
1174                 break;
1175             }
1176         }
1177         nptr = nentry.next;
1178     }
1179     if (slot != -1) {           /* we found a place */
1180         entryg->countsg++;
1181         if (first) {            /* place is in first block */
1182             entryg->supergroup[slot] = aid;
1183             code = pr_WriteEntry(tt, 0, loc, entry);
1184             if (code != 0)
1185                 return code;
1186             return PRSUCCESS;
1187         }
1188         code = pr_WriteEntry(tt, 0, loc, entry);
1189         if (code)
1190             return code;
1191         code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1192         if (code != 0)
1193             return code;
1194         aentry.entries[slot] = aid;
1195         code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1196         if (code != 0)
1197             return code;
1198         return PRSUCCESS;
1199     }
1200     /* have to allocate a continuation block if we got here */
1201     nptr = AllocBlock(tt);
1202     if (last) {
1203         /* then we should tack new block after last block in cont. chain */
1204         nentry.next = nptr;
1205         code = pr_WriteCoEntry(tt, 0, last, &nentry);
1206         if (code != 0)
1207             return code;
1208     } else {
1209         entryg->nextsg = nptr;
1210     }
1211     memset(&aentry, 0, sizeof(aentry));
1212     aentry.flags |= PRCONT;
1213     aentry.id = entry->id;
1214     aentry.next = 0;
1215     aentry.entries[0] = aid;
1216     code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1217     if (code != 0)
1218         return code;
1219     /* don't forget to update count, here! */
1220     entryg->countsg++;
1221     code = pr_WriteEntry(tt, 0, loc, entry);
1222     return code;
1223
1224 }
1225 #endif /* SUPERGROUPS */
1226
1227 afs_int32
1228 AddToPRList(prlist *alist, int *sizeP, afs_int32 id)
1229 {
1230     char *tmp;
1231     int count;
1232
1233     if (alist->prlist_len >= *sizeP) {
1234         count = alist->prlist_len + 100;
1235         if (alist->prlist_val) {
1236             tmp =
1237                 (char *)realloc(alist->prlist_val, count * sizeof(afs_int32));
1238         } else {
1239             tmp = (char *)malloc(count * sizeof(afs_int32));
1240         }
1241         if (!tmp)
1242             return (PRNOMEM);
1243         alist->prlist_val = (afs_int32 *) tmp;
1244         *sizeP = count;
1245     }
1246     alist->prlist_val[alist->prlist_len++] = id;
1247     return 0;
1248 }
1249
1250 afs_int32
1251 GetList(struct ubik_trans *at, struct prentry *tentry, prlist *alist, afs_int32 add)
1252 {
1253     afs_int32 code;
1254     afs_int32 i;
1255     struct contentry centry;
1256     afs_int32 nptr;
1257     int size;
1258     int count = 0;
1259
1260     size = 0;
1261     alist->prlist_val = 0;
1262     alist->prlist_len = 0;
1263
1264     for (i = 0; i < PRSIZE; i++) {
1265         if (tentry->entries[i] == PRBADID)
1266             continue;
1267         if (tentry->entries[i] == 0)
1268             break;
1269         code = AddToPRList(alist, &size, tentry->entries[i]);
1270         if (code)
1271             return code;
1272 #if defined(SUPERGROUPS)
1273         if (!add)
1274             continue;
1275         code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1276         if (code)
1277             return code;
1278 #endif
1279     }
1280
1281     for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
1282         /* look through cont entries */
1283         code = pr_ReadCoEntry(at, 0, nptr, &centry);
1284         if (code != 0)
1285             return code;
1286         for (i = 0; i < COSIZE; i++) {
1287             if (centry.entries[i] == PRBADID)
1288                 continue;
1289             if (centry.entries[i] == 0)
1290                 break;
1291             code = AddToPRList(alist, &size, centry.entries[i]);
1292             if (code)
1293                 return code;
1294 #if defined(SUPERGROUPS)
1295             if (!add)
1296                 continue;
1297             code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1298             if (code)
1299                 return code;
1300 #endif
1301         }
1302         if (count++ > 50) {
1303 #ifndef AFS_PTHREAD_ENV
1304             IOMGR_Poll();
1305 #endif
1306             count = 0;
1307         }
1308     }
1309
1310     if (add) {                  /* this is for a CPS, so tack on appropriate stuff */
1311         if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1312             if ((code = AddToPRList(alist, &size, ANYUSERID))
1313                 || (code = AddAuthGroup(tentry, alist, &size))
1314                 || (code = AddToPRList(alist, &size, tentry->id)))
1315                 return code;
1316         } else {
1317             if ((code = AddToPRList(alist, &size, ANYUSERID))
1318                 || (code = AddToPRList(alist, &size, tentry->id)))
1319                 return code;
1320         }
1321     }
1322 #ifndef AFS_PTHREAD_ENV
1323     if (alist->prlist_len > 100)
1324         IOMGR_Poll();
1325 #endif
1326     qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1327     return PRSUCCESS;
1328 }
1329
1330
1331 afs_int32
1332 GetList2(struct ubik_trans *at, struct prentry *tentry, struct prentry *tentry2, prlist *alist, afs_int32 add)
1333 {
1334     afs_int32 code = 0;
1335     afs_int32 i;
1336     struct contentry centry;
1337     afs_int32 nptr;
1338     afs_int32 size;
1339     int count = 0;
1340
1341     size = 0;
1342     alist->prlist_val = 0;
1343     alist->prlist_len = 0;
1344     for (i = 0; i < PRSIZE; i++) {
1345         if (tentry->entries[i] == PRBADID)
1346             continue;
1347         if (tentry->entries[i] == 0)
1348             break;
1349         code = AddToPRList(alist, &size, tentry->entries[i]);
1350         if (code)
1351             return code;
1352 #if defined(SUPERGROUPS)
1353         if (!add)
1354             continue;
1355         code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1356         if (code)
1357             return code;
1358 #endif
1359     }
1360
1361     nptr = tentry->next;
1362     while (nptr != 0) {
1363         /* look through cont entries */
1364         code = pr_ReadCoEntry(at, 0, nptr, &centry);
1365         if (code != 0)
1366             return code;
1367         for (i = 0; i < COSIZE; i++) {
1368             if (centry.entries[i] == PRBADID)
1369                 continue;
1370             if (centry.entries[i] == 0)
1371                 break;
1372             code = AddToPRList(alist, &size, centry.entries[i]);
1373             if (code)
1374                 return code;
1375 #if defined(SUPERGROUPS)
1376             if (!add)
1377                 continue;
1378             code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1379             if (code)
1380                 return code;
1381 #endif
1382         }
1383         nptr = centry.next;
1384         if (count++ > 50) {
1385 #ifndef AFS_PTHREAD_ENV
1386             IOMGR_Poll();
1387 #endif
1388             count = 0;
1389         }
1390     }
1391
1392     for (i = 0; i < PRSIZE; i++) {
1393         if (tentry2->entries[i] == PRBADID)
1394             continue;
1395         if (tentry2->entries[i] == 0)
1396             break;
1397         code = AddToPRList(alist, &size, tentry2->entries[i]);
1398         if (code)
1399             break;
1400     }
1401
1402     if (!code) {
1403         nptr = tentry2->next;
1404         while (nptr != 0) {
1405             /* look through cont entries */
1406             code = pr_ReadCoEntry(at, 0, nptr, &centry);
1407             if (code != 0)
1408                 break;
1409             for (i = 0; i < COSIZE; i++) {
1410                 if (centry.entries[i] == PRBADID)
1411                     continue;
1412                 if (centry.entries[i] == 0)
1413                     break;
1414                 code = AddToPRList(alist, &size, centry.entries[i]);
1415                 if (code)
1416                     break;
1417             }
1418             nptr = centry.next;
1419             if (count++ > 50) {
1420 #ifndef AFS_PTHREAD_ENV
1421                 IOMGR_Poll();
1422 #endif
1423                 count = 0;
1424             }
1425         }
1426     }
1427     if (add) {                  /* this is for a CPS, so tack on appropriate stuff */
1428         if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1429             if ((code = AddToPRList(alist, &size, ANYUSERID))
1430                 || (code = AddToPRList(alist, &size, AUTHUSERID))
1431                 || (code = AddToPRList(alist, &size, tentry->id)))
1432                 return code;
1433         } else {
1434             if ((code = AddToPRList(alist, &size, ANYUSERID))
1435                 || (code = AddToPRList(alist, &size, tentry->id)))
1436                 return code;
1437         }
1438     }
1439 #ifndef AFS_PTHREAD_ENV
1440     if (alist->prlist_len > 100)
1441         IOMGR_Poll();
1442 #endif
1443     qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1444     return PRSUCCESS;
1445 }
1446
1447 #if defined(SUPERGROUPS)
1448
1449 afs_int32
1450 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist *alist, afs_int32 *sizeP, afs_int32 depth)
1451 {
1452     register afs_int32 code;
1453     struct prentry tentry;
1454     struct prentryg *tentryg = (struct prentryg *)&tentry;
1455     afs_int32 i;
1456     struct contentry centry;
1457     afs_int32 nptr;
1458     int count = 0;
1459     afs_int32 temp;
1460     int didsomething;
1461 #if DEBUG_SG_MAP
1462     int predictfound, predictflagged;
1463 #endif
1464
1465 #if DEBUG_SG_MAP
1466     predictfound = 0;
1467     if (!in_map(sg_flagged, -gid)) {
1468         predictflagged = 0;
1469         fprintf(stderr, "GetListSG2: I have not yet searched for gid=%d\n",
1470                 gid);
1471     } else if (predictflagged = 1, in_map(sg_found, -gid)) {
1472         predictfound = 1;
1473         fprintf(stderr,
1474                 "GetListSG2: I have already searched for gid=%d, and predict success.\n",
1475                 gid);
1476     }
1477 #endif
1478
1479     if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) {
1480 #if DEBUG_SG_MAP
1481         fprintf(stderr,
1482                 "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
1483                 gid);
1484 #else
1485         return 0;
1486 #endif
1487     }
1488
1489     if (depth < 1)
1490         return 0;
1491     temp = FindByID(at, gid);
1492     if (!temp) {
1493         code = PRNOENT;
1494         return code;
1495     }
1496     code = pr_ReadEntry(at, 0, temp, &tentry);
1497     if (code)
1498         return code;
1499 #if DEBUG_SG_MAP
1500     fprintf(stderr, "GetListSG2: lookup for gid=%d [\n", gid);
1501 #endif
1502     didsomething = 0;
1503
1504     for (i = 0; i < SGSIZE; i++) {
1505         if (tentryg->supergroup[i] == PRBADID)
1506             continue;
1507         if (tentryg->supergroup[i] == 0)
1508             break;
1509         didsomething = 1;
1510 #if DEBUG_SG_MAP
1511         fprintf(stderr, "via gid=%d, added %d\n", gid,
1512                 e.tentryg.supergroup[i]);
1513 #endif
1514         code = AddToPRList(alist, sizeP, tentryg->supergroup[i]);
1515         if (code)
1516             return code;
1517         code =
1518             GetListSG2(at, tentryg->supergroup[i], alist, sizeP, depth - 1);
1519         if (code)
1520             return code;
1521     }
1522
1523     nptr = tentryg->nextsg;
1524     while (nptr) {
1525         didsomething = 1;
1526         /* look through cont entries */
1527         code = pr_ReadCoEntry(at, 0, nptr, &centry);
1528         if (code != 0)
1529             return code;
1530         for (i = 0; i < COSIZE; i++) {
1531             if (centry.entries[i] == PRBADID)
1532                 continue;
1533             if (centry.entries[i] == 0)
1534                 break;
1535 #if DEBUG_SG_MAP
1536             fprintf(stderr, "via gid=%d, added %d\n", gid,
1537                     e.centry.entries[i]);
1538 #endif
1539             code = AddToPRList(alist, sizeP, centry.entries[i]);
1540             if (code)
1541                 return code;
1542             code = GetListSG2(at, centry.entries[i], alist, sizeP, depth - 1);
1543             if (code)
1544                 return code;
1545         }
1546         nptr = centry.next;
1547         if (count++ > 50) {
1548 #ifndef AFS_PTHREAD_ENV
1549             IOMGR_Poll();
1550 #endif
1551             count = 0;
1552         }
1553     }
1554 #if DEBUG_SG_MAP
1555     fprintf(stderr, "] for gid %d, done [flag=%s]\n", gid,
1556             didsomething ? "TRUE" : "FALSE");
1557     if (predictflagged && didsomething != predictfound)
1558         fprintf(stderr, "**** for gid=%d, didsomething=%d predictfound=%d\n",
1559                 didsomething, predictfound);
1560 #endif
1561     if (didsomething)
1562         sg_found = add_map(sg_found, -gid);
1563     else
1564         sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid));
1565     sg_flagged = add_map(sg_flagged, -gid);
1566     return 0;
1567 }
1568
1569 afs_int32
1570 GetSGList(struct ubik_trans *at, struct prentry *tentry, prlist *alist)
1571 {
1572     register afs_int32 code;
1573     afs_int32 i;
1574     struct contentry centry;
1575     struct prentryg *tentryg;
1576     afs_int32 nptr;
1577     int size;
1578     int count = 0;
1579
1580     size = 0;
1581     alist->prlist_val = 0;
1582     alist->prlist_len = 0;
1583
1584     tentryg = (struct prentryg *)tentry;
1585     for (i = 0; i < SGSIZE; i++) {
1586         if (tentryg->supergroup[i] == PRBADID)
1587             continue;
1588         if (tentryg->supergroup[i] == 0)
1589             break;
1590         code = AddToPRList(alist, &size, tentryg->supergroup[i]);
1591         if (code)
1592             return code;
1593     }
1594
1595     nptr = tentryg->nextsg;
1596     while (nptr) {
1597         /* look through cont entries */
1598         code = pr_ReadCoEntry(at, 0, nptr, &centry);
1599         if (code != 0)
1600             return code;
1601         for (i = 0; i < COSIZE; i++) {
1602             if (centry.entries[i] == PRBADID)
1603                 continue;
1604             if (centry.entries[i] == 0)
1605                 break;
1606             code = AddToPRList(alist, &size, centry.entries[i]);
1607             if (code)
1608                 return code;
1609         }
1610         nptr = centry.next;
1611         if (count++ > 50) {
1612 #ifndef AFS_PTHREAD_ENV
1613             IOMGR_Poll();
1614 #endif
1615             count = 0;
1616         }
1617     }
1618
1619 #ifndef AFS_PTHREAD_ENV
1620     if (alist->prlist_len > 100)
1621         IOMGR_Poll();
1622 #endif
1623     qsort((char *)alist->prlist_val, (int)alist->prlist_len,
1624           sizeof(afs_int32), IDCmp);
1625     return PRSUCCESS;
1626 }
1627 #endif /* SUPERGROUPS */
1628
1629 afs_int32
1630 GetOwnedChain(struct ubik_trans *ut, afs_int32 *next, prlist *alist)
1631 {
1632     afs_int32 code;
1633     struct prentry tentry;
1634     int size;
1635     int count = 0;
1636
1637     size = 0;
1638     alist->prlist_val = 0;
1639     alist->prlist_len = 0;
1640
1641     for (; *next; *next = ntohl(tentry.nextOwned)) {
1642         code = pr_Read(ut, 0, *next, &tentry, sizeof(tentry));
1643         if (code)
1644             return code;
1645         code = AddToPRList(alist, &size, ntohl(tentry.id));
1646         if (alist->prlist_len >= PR_MAXGROUPS) {
1647             return PRTOOMANY;
1648         }
1649         if (code)
1650             return code;
1651         if (count++ > 50) {
1652 #ifndef AFS_PTHREAD_ENV
1653             IOMGR_Poll();
1654 #endif
1655             count = 0;
1656         }
1657     }
1658 #ifndef AFS_PTHREAD_ENV
1659     if (alist->prlist_len > 100)
1660         IOMGR_Poll();
1661 #endif
1662     qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1663     return PRSUCCESS;
1664 }
1665
1666 afs_int32
1667 GetMax(struct ubik_trans *at, afs_int32 *uid, afs_int32 *gid)
1668 {
1669     *uid = ntohl(cheader.maxID);
1670     *gid = ntohl(cheader.maxGroup);
1671     return PRSUCCESS;
1672 }
1673
1674 afs_int32
1675 SetMax(struct ubik_trans *at, afs_int32 id, afs_int32 flag)
1676 {
1677     afs_int32 code;
1678     if (flag & PRGRP) {
1679         cheader.maxGroup = htonl(id);
1680         code =
1681             pr_Write(at, 0, 16, (char *)&cheader.maxGroup,
1682                      sizeof(cheader.maxGroup));
1683         if (code != 0)
1684             return code;
1685     } else {
1686         cheader.maxID = htonl(id);
1687         code =
1688             pr_Write(at, 0, 20, (char *)&cheader.maxID,
1689                      sizeof(cheader.maxID));
1690         if (code != 0)
1691             return code;
1692     }
1693     return PRSUCCESS;
1694 }
1695
1696 afs_int32
1697 read_DbHeader(struct ubik_trans *tt)
1698 {
1699     afs_int32 code;
1700
1701     if (!ubik_CacheUpdate(tt))
1702         return 0;
1703
1704     code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1705     if (code != 0) {
1706         afs_com_err(whoami, code, "Couldn't read header");
1707     }
1708     return code;
1709 }
1710
1711 int pr_noAuth;
1712 afs_int32 initd = 0;
1713
1714 afs_int32
1715 Initdb(void)
1716 {
1717     afs_int32 code;
1718     struct ubik_trans *tt;
1719     afs_int32 len;
1720
1721     /* init the database.  We'll try reading it, but if we're starting
1722      * from scratch, we'll have to do a write transaction. */
1723
1724     pr_noAuth = afsconf_GetNoAuthFlag(prdir);
1725
1726     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1727     if (code)
1728         return code;
1729     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1730     if (code) {
1731         ubik_AbortTrans(tt);
1732         return code;
1733     }
1734     if (!initd) {
1735         initd = 1;
1736     } else if (!ubik_CacheUpdate(tt)) {
1737         code = ubik_EndTrans(tt);
1738         return code;
1739     }
1740
1741     len = sizeof(cheader);
1742     code = pr_Read(tt, 0, 0, (char *)&cheader, len);
1743     if (code != 0) {
1744         afs_com_err(whoami, code, "couldn't read header");
1745         ubik_AbortTrans(tt);
1746         return code;
1747     }
1748     if ((ntohl(cheader.version) == PRDBVERSION)
1749         && ntohl(cheader.headerSize) == sizeof(cheader)
1750         && ntohl(cheader.eofPtr) != 0
1751         && FindByID(tt, ANONYMOUSID) != 0) {
1752         /* database exists, so we don't have to build it */
1753         code = ubik_EndTrans(tt);
1754         if (code)
1755             return code;
1756         return PRSUCCESS;
1757     }
1758     /* else we need to build a database */
1759     code = ubik_EndTrans(tt);
1760     if (code)
1761         return code;
1762
1763     /* Only rebuild database if the db was deleted (the header is zero) and we
1764      * are running noAuth. */
1765     {
1766         char *bp = (char *)&cheader;
1767         int i;
1768         for (i = 0; i < sizeof(cheader); i++)
1769             if (bp[i]) {
1770                 code = PRDBBAD;
1771                 afs_com_err(whoami, code,
1772                         "Can't rebuild database because it is not empty");
1773                 return code;
1774             }
1775     }
1776     if (!pr_noAuth) {
1777         code = PRDBBAD;
1778         afs_com_err(whoami, code,
1779                 "Can't rebuild database because not running NoAuth");
1780         return code;
1781     }
1782
1783     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1784     if (code)
1785         return code;
1786
1787     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1788     if (code) {
1789         ubik_AbortTrans(tt);
1790         return code;
1791     }
1792
1793     /* before doing a rebuild, check again that the dbase looks bad, because
1794      * the previous check was only under a ReadAny transaction, and there could
1795      * actually have been a good database out there.  Now that we have a
1796      * real write transaction, make sure things are still bad.
1797      */
1798     if ((ntohl(cheader.version) == PRDBVERSION)
1799         && ntohl(cheader.headerSize) == sizeof(cheader)
1800         && ntohl(cheader.eofPtr) != 0
1801         && FindByID(tt, ANONYMOUSID) != 0) {
1802         /* database exists, so we don't have to build it */
1803         code = ubik_EndTrans(tt);
1804         if (code)
1805             return code;
1806         return PRSUCCESS;
1807     }
1808
1809     /* Initialize the database header */
1810     if ((code = set_header_word(tt, version, htonl(PRDBVERSION)))
1811         || (code = set_header_word(tt, headerSize, htonl(sizeof(cheader))))
1812         || (code = set_header_word(tt, eofPtr, cheader.headerSize))) {
1813         afs_com_err(whoami, code, "couldn't write header words");
1814         ubik_AbortTrans(tt);
1815         return code;
1816     }
1817 #define InitialGroup(id,name) do {    \
1818     afs_int32 temp = (id);                    \
1819     afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1820     code = CreateEntry                \
1821         (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1822     if (code) {                       \
1823         afs_com_err (whoami, code, "couldn't create %s with id %di.",   \
1824                  (name), (id));       \
1825         ubik_AbortTrans(tt);          \
1826         return code;                  \
1827     }                                 \
1828 } while (0)
1829
1830     InitialGroup(SYSADMINID, "system:administrators");
1831     InitialGroup(SYSBACKUPID, "system:backup");
1832     InitialGroup(ANYUSERID, "system:anyuser");
1833     InitialGroup(AUTHUSERID, "system:authuser");
1834     InitialGroup(SYSVIEWERID, "system:ptsviewers");
1835     InitialGroup(ANONYMOUSID, "anonymous");
1836
1837     /* Well, we don't really want the max id set to anonymousid, so we'll set
1838      * it back to 0 */
1839     code = set_header_word(tt, maxID, 0);       /* correct in any byte order */
1840     if (code) {
1841         afs_com_err(whoami, code, "couldn't reset max id");
1842         ubik_AbortTrans(tt);
1843         return code;
1844     }
1845
1846     code = ubik_EndTrans(tt);
1847     if (code)
1848         return code;
1849     return PRSUCCESS;
1850 }
1851
1852 afs_int32
1853 ChangeEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 cid, char *name, afs_int32 oid, afs_int32 newid)
1854 {
1855     afs_int32 code;
1856     afs_int32 i, nptr, pos;
1857 #if defined(SUPERGROUPS)
1858     afs_int32 nextpos;
1859 #endif
1860     struct contentry centry;
1861     struct prentry tentry, tent;
1862     afs_int32 loc;
1863     afs_int32 oldowner;
1864     char holder[PR_MAXNAMELEN];
1865     char temp[PR_MAXNAMELEN];
1866     char oldname[PR_MAXNAMELEN];
1867     char *atsign;
1868
1869     memset(holder, 0, PR_MAXNAMELEN);
1870     memset(temp, 0, PR_MAXNAMELEN);
1871     loc = FindByID(at, aid);
1872     if (!loc)
1873         return PRNOENT;
1874     code = pr_ReadEntry(at, 0, loc, &tentry);
1875     if (code)
1876         return PRDBFAIL;
1877     if (restricted && !IsAMemberOf(at, cid, SYSADMINID)) 
1878         return PRPERM;
1879     if (tentry.owner != cid && !IsAMemberOf(at, cid, SYSADMINID)
1880         && !IsAMemberOf(at, cid, tentry.owner) && !pr_noAuth)
1881         return PRPERM;
1882 #ifdef PR_REMEMBER_TIMES
1883     tentry.changeTime = time(0);
1884 #endif
1885
1886     /* we're actually trying to change the id */
1887     if (newid && (newid != aid)) {
1888         if (!IsAMemberOf(at, cid, SYSADMINID) && !pr_noAuth)
1889             return PRPERM;
1890
1891         pos = FindByID(at, newid);
1892         if (pos)
1893             return PRIDEXIST;   /* new id already in use! */
1894         if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0))
1895             return PRPERM;
1896
1897         /* Should check that foreign users id to change to is good: inRange() */
1898
1899         /* if new id is not in use, rehash things */
1900         code = RemoveFromIDHash(at, aid, &loc);
1901         if (code != PRSUCCESS)
1902             return code;
1903         tentry.id = newid;
1904         code = pr_WriteEntry(at, 0, loc, &tentry);
1905         if (code)
1906             return code;
1907         code = AddToIDHash(at, tentry.id, loc);
1908         if (code)
1909             return code;
1910
1911         /* get current data */
1912         code = pr_ReadEntry(at, 0, loc, &tentry);
1913         if (code)
1914             return PRDBFAIL;
1915
1916 #if defined(SUPERGROUPS)
1917         if (tentry.id > (afs_int32) ntohl(cheader.maxID))
1918             code = set_header_word(at, maxID, htonl(tentry.id));
1919         if (code)
1920             return PRDBFAIL;
1921
1922         /* need to fix up: membership
1923          * (supergroups?)
1924          * ownership
1925          */
1926
1927         for (i = 0; i < PRSIZE; i++) {
1928             if (tentry.entries[i] == PRBADID)
1929                 continue;
1930             if (tentry.entries[i] == 0)
1931                 break;
1932             if ((tentry.flags & PRGRP) && tentry.entries[i] < 0) {      /* Supergroup */
1933                 return 5;       /* not yet, in short. */
1934             } else {
1935                 code = ChangeIDEntry(at, aid, newid, tentry.entries[i]);
1936             }
1937             if (code)
1938                 return code;
1939         }
1940         for (pos = ntohl(tentry.owned); pos; pos = nextpos) {
1941             code = pr_ReadEntry(at, 0, pos, &tent);
1942             if (code)
1943                 break;
1944             tent.owner = newid;
1945             nextpos = tent.nextOwned;
1946             code = pr_WriteEntry(at, 0, pos, &tent);
1947             if (code)
1948                 break;
1949         }
1950         pos = tentry.next;
1951         while (pos) {
1952 #define centry  (*(struct contentry*)&tent)
1953             code = pr_ReadCoEntry(at, 0, pos, &centry);
1954             if ((centry.id != aid)
1955                 || !(centry.flags & PRCONT)) {
1956                 fprintf(stderr,
1957                         "ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
1958                         aid, centry.id, centry.flags);
1959                 return PRDBBAD;
1960             }
1961             centry.id = newid;
1962             for (i = 0; i < COSIZE; i++) {
1963                 if (centry.entries[i] == PRBADID)
1964                     continue;
1965                 if (centry.entries[i] == 0)
1966                     break;
1967                 if ((centry.flags & PRGRP) && centry.entries[i] < 0) {  /* Supergroup */
1968                     return 5;   /* not yet, in short. */
1969                 } else {
1970                     code = ChangeIDEntry(at, aid, newid, centry.entries[i]);
1971                 }
1972                 if (code)
1973                     return code;
1974             }
1975             code = pr_WriteCoEntry(at, 0, pos, &centry);
1976             pos = centry.next;
1977 #undef centry
1978         }
1979         if (code)
1980             return code;
1981
1982 #else /* SUPERGROUPS */
1983
1984
1985         /* Also change the references from the membership list */
1986         for (i = 0; i < PRSIZE; i++) {
1987             if (tentry.entries[i] == PRBADID)
1988                 continue;
1989             if (tentry.entries[i] == 0)
1990                 break;
1991             pos = FindByID(at, tentry.entries[i]);
1992             if (!pos)
1993                 return (PRDBFAIL);
1994             code = RemoveFromEntry(at, aid, tentry.entries[i]);
1995             if (code)
1996                 return code;
1997             code = pr_ReadEntry(at, 0, pos, &tent);
1998             if (code)
1999                 return code;
2000             code = AddToEntry(at, &tent, pos, newid);
2001             if (code)
2002                 return code;
2003         }
2004         /* Look through cont entries too. This needs to be broken into
2005          * seperate transaction so that no one transaction becomes too 
2006          * large to complete.
2007          */
2008         for (nptr = tentry.next; nptr; nptr = centry.next) {
2009             code = pr_ReadCoEntry(at, 0, nptr, &centry);
2010             if (code)
2011                 return code;
2012             for (i = 0; i < COSIZE; i++) {
2013                 if (centry.entries[i] == PRBADID)
2014                     continue;
2015                 if (centry.entries[i] == 0)
2016                     break;
2017                 pos = FindByID(at, centry.entries[i]);
2018                 if (!pos)
2019                     return (PRDBFAIL);
2020                 code = RemoveFromEntry(at, aid, centry.entries[i]);
2021                 if (code)
2022                     return code;
2023                 code = pr_ReadEntry(at, 0, pos, &tent);
2024                 if (code)
2025                     return code;
2026                 code = AddToEntry(at, &tent, pos, newid);
2027                 if (code)
2028                     return code;
2029             }
2030         }
2031 #endif /* SUPERGROUPS */
2032     }
2033
2034     atsign = strchr(tentry.name, '@');  /* check for foreign entry */
2035
2036     /* Change the owner */
2037     if (oid && (oid != tentry.owner)) {
2038         /* only groups can have their owner's changed */
2039         if (!(tentry.flags & PRGRP))
2040             return PRPERM;
2041         if (atsign != NULL)
2042             return PRPERM;
2043         oldowner = tentry.owner;
2044         tentry.owner = oid;
2045         /* The entry must be written through first so Remove and Add routines
2046          * can operate on disk data */
2047         code = pr_WriteEntry(at, 0, loc, &tentry);
2048         if (code)
2049             return PRDBFAIL;
2050
2051         /* switch owner chains */
2052         if (oldowner)           /* if it has an owner */
2053             code = RemoveFromOwnerChain(at, tentry.id, oldowner);
2054         else                    /* must be an orphan */
2055             code = RemoveFromOrphan(at, tentry.id);
2056         if (code)
2057             return code;
2058         code = AddToOwnerChain(at, tentry.id, tentry.owner);
2059         if (code)
2060             return code;
2061
2062         /* fix up the name */
2063         if (strlen(name) == 0)
2064             name = tentry.name;
2065         /* get current data */
2066         code = pr_ReadEntry(at, 0, loc, &tentry);
2067         if (code)
2068             return PRDBFAIL;
2069     }
2070
2071     /* Change the name, if name is a ptr to tentry.name then this name change
2072      * is due to a chown, otherwise caller has specified a new name */
2073     if ((name == tentry.name) || (*name && (strcmp(tentry.name, name) != 0))) {
2074         strncpy(oldname, tentry.name, PR_MAXNAMELEN);
2075         if (tentry.flags & PRGRP) {
2076             /* don't let foreign cell groups change name */
2077             if (atsign != NULL)
2078                 return PRPERM;
2079             code = CorrectGroupName(at, name, cid, tentry.owner, tentry.name);
2080             if (code)
2081                 return code;
2082
2083             if (name == tentry.name) {  /* owner fixup */
2084                 if (strcmp(oldname, tentry.name) == 0)
2085                     goto nameOK;
2086             } else {            /* new name, caller must be correct */
2087                 if (strcmp(name, tentry.name) != 0)
2088                     return PRBADNAM;
2089             }
2090         } else
2091             /* Allow a foreign name change only if the cellname part is
2092              * the same */
2093         {
2094             char *newatsign;
2095
2096             newatsign = strchr(name, '@');
2097             if (newatsign != atsign) {  /* if they are the same no problem */
2098                 /*if the pointers are not equal the strings better be */
2099                 if ((atsign == NULL) || (newatsign == NULL)
2100                     || strcmp(atsign, newatsign))
2101                     return PRPERM;
2102             }
2103             if (!CorrectUserName(name))
2104                 return PRBADNAM;
2105         }
2106
2107         pos = FindByName(at, name, &tent);
2108         if (pos)
2109             return PREXIST;
2110         code = RemoveFromNameHash(at, oldname, &loc);
2111         if (code != PRSUCCESS)
2112             return code;
2113         strncpy(tentry.name, name, PR_MAXNAMELEN);
2114         code = pr_WriteEntry(at, 0, loc, &tentry);
2115         if (code)
2116             return PRDBFAIL;
2117         code = AddToNameHash(at, tentry.name, loc);
2118         if (code != PRSUCCESS)
2119             return code;
2120       nameOK:;
2121     }
2122     return PRSUCCESS;
2123 }
2124
2125
2126 static afs_int32
2127 allocNextId(struct ubik_trans * at, struct prentry * cellEntry)
2128 {
2129     /* Id's for foreign cell entries are constructed as follows:
2130      * The 16 low order bits are the group id of the cell and the
2131      * top 16 bits identify the particular users in that cell */
2132
2133     afs_int32 id;
2134     afs_int32 cellid = ((ntohl(cellEntry->id)) & 0x0000ffff);
2135
2136     id = (ntohl(cellEntry->nusers) + 1);
2137     while (FindByID(at, ((id << 16) | cellid))) {
2138         id++;
2139         if (id > 0xffff)
2140             return 0;
2141     }
2142
2143     cellEntry->nusers = htonl(id);
2144     /* use the field nusers to keep 
2145      * the next available id in that
2146      * foreign cell's group. Note :
2147      * It would seem more appropriate
2148      * to use ngroup for that and nusers
2149      * to enforce the quota, however pts
2150      * does not have an option to change 
2151      * foreign users quota yet  */
2152
2153     id = (id << 16) | cellid;
2154     return id;
2155 }
2156
2157 static int
2158 inRange(struct prentry *cellEntry, afs_int32 aid)
2159 {
2160     afs_uint32 id, cellid, groupid;
2161
2162
2163     /*
2164      * The only thing that we want to make sure here is that
2165      * the id is in the legal range of this group. If it is
2166      * a duplicate we don't care since it will get caught 
2167      * in a different check.
2168      */
2169
2170     cellid = aid & 0x0000ffff;
2171     groupid = (ntohl(cellEntry->id)) & 0x0000ffff;
2172     if (cellid != groupid)
2173         return 0;               /* not in range */
2174
2175     /* 
2176      * if we got here we're ok but we need to update the nusers
2177      * field in order to get the id correct the next time that 
2178      * we try to allocate it automatically
2179      */
2180
2181     id = aid >> 16;
2182     if (id > ntohl(cellEntry->nusers))
2183         cellEntry->nusers = htonl(id);
2184     return 1;
2185
2186 }
2187
2188 static int
2189 AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size)
2190 {
2191     if (!(strchr(tentry->name, '@')))
2192         return (AddToPRList(alist, size, AUTHUSERID));
2193     else
2194         return PRSUCCESS;
2195 }