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