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