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