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