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