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