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