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