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