Windows: ensure that afsconfig.h and afs/param.h are included
[openafs.git] / src / ptserver / utils.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <assert.h>
14 #include <sys/types.h>
15 #include <lock.h>
16 #include <ubik.h>
17 #include <stdio.h>
18 #ifdef AFS_NT40_ENV
19 #include <winsock2.h>
20 #else
21 #include <netinet/in.h>
22 #include <netdb.h>
23 #endif
24 #include <string.h>
25 #include "ptserver.h"
26 #include "pterror.h"
27
28 #if defined(SUPERGROUPS)
29 extern afs_int32 depthsg;
30 afs_int32 IsAMemberOfSG(struct ubik_trans *at, afs_int32 aid, afs_int32 gid,
31                         afs_int32 depth);
32 #endif
33
34 static afs_int32
35 IDHash(afs_int32 x)
36 {
37     /* returns hash bucket for x */
38     return ((abs(x)) % HASHSIZE);
39 }
40
41 afs_int32
42 NameHash(register char *aname)
43 {
44     /* returns hash bucket for aname */
45     register unsigned int hash = 0;
46     register size_t i;
47 /* stolen directly from the HashString function in the vol package */
48     for (i = strlen(aname), aname += i - 1; i--; aname--)
49         hash = (hash * 31) + (*(unsigned char *)aname - 31);
50     return (hash % HASHSIZE);
51 }
52
53
54 afs_int32
55 pr_Write(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, void *buff, afs_int32 len)
56 {
57     /* package up seek and write into one procedure for ease of use */
58     afs_int32 code;
59     if ((pos < sizeof(cheader)) && (buff != (char *)&cheader + pos)) {
60         fprintf(stderr,
61                 "ptserver: dbwrite: Illegal attempt to write a location 0\n");
62         return PRDBFAIL;
63     }
64     code = ubik_Seek(tt, afd, pos);
65     if (code)
66         return code;
67     code = ubik_Write(tt, buff, len);
68     return code;
69 }
70
71 afs_int32
72 pr_Read(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, void *buff, afs_int32 len)
73 {
74     /* same thing for read */
75     afs_int32 code;
76     code = ubik_Seek(tt, afd, pos);
77     if (code)
78         return code;
79     code = ubik_Read(tt, buff, len);
80     return code;
81 }
82
83 int
84 pr_WriteEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct prentry *tentry)
85 {
86     afs_int32 code;
87     register afs_int32 i;
88     struct prentry nentry;
89
90     if (ntohl(1) != 1) {        /* Need to swap bytes. */
91         memset(&nentry, 0, sizeof(nentry));     /* make sure reseved fields are zero */
92         nentry.flags = htonl(tentry->flags);
93         nentry.id = htonl(tentry->id);
94         nentry.cellid = htonl(tentry->cellid);
95         nentry.next = htonl(tentry->next);
96         nentry.nextID = htonl(tentry->nextID);
97         nentry.nextName = htonl(tentry->nextName);
98         nentry.owner = htonl(tentry->owner);
99         nentry.creator = htonl(tentry->creator);
100         nentry.ngroups = htonl(tentry->ngroups);
101         nentry.nusers = htonl(tentry->nusers);
102         nentry.count = htonl(tentry->count);
103         nentry.instance = htonl(tentry->instance);
104         nentry.owned = htonl(tentry->owned);
105         nentry.nextOwned = htonl(tentry->nextOwned);
106         nentry.parent = htonl(tentry->parent);
107         nentry.sibling = htonl(tentry->sibling);
108         nentry.child = htonl(tentry->child);
109         strncpy(nentry.name, tentry->name, PR_MAXNAMELEN);
110 #ifdef PR_REMEMBER_TIMES
111         nentry.createTime = htonl(tentry->createTime);
112         nentry.addTime = htonl(tentry->addTime);
113         nentry.removeTime = htonl(tentry->removeTime);
114         nentry.changeTime = htonl(tentry->changeTime);
115 #endif
116         for (i = 0; i < PRSIZE; i++)
117             nentry.entries[i] = htonl(tentry->entries[i]);
118         tentry = &nentry;
119     }
120     code = pr_Write(tt, afd, pos, (char *)tentry, sizeof(struct prentry));
121     return (code);
122 }
123
124 int
125 pr_ReadEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct prentry *tentry)
126 {
127     afs_int32 code;
128     register afs_int32 i;
129     struct prentry nentry;
130     code = ubik_Seek(tt, afd, pos);
131     if (code)
132         return (code);
133     if (ntohl(1) == 1) {        /* no swapping needed */
134         code = ubik_Read(tt, (char *)tentry, sizeof(struct prentry));
135         return (code);
136     }
137     code = ubik_Read(tt, (char *)&nentry, sizeof(struct prentry));
138     if (code)
139         return (code);
140     memset(tentry, 0, sizeof(*tentry)); /* make sure reseved fields are zero */
141     tentry->flags = ntohl(nentry.flags);
142     tentry->id = ntohl(nentry.id);
143     tentry->cellid = ntohl(nentry.cellid);
144     tentry->next = ntohl(nentry.next);
145     tentry->nextID = ntohl(nentry.nextID);
146     tentry->nextName = ntohl(nentry.nextName);
147     tentry->owner = ntohl(nentry.owner);
148     tentry->creator = ntohl(nentry.creator);
149     tentry->ngroups = ntohl(nentry.ngroups);
150     tentry->nusers = ntohl(nentry.nusers);
151     tentry->count = ntohl(nentry.count);
152     tentry->instance = ntohl(nentry.instance);
153     tentry->owned = ntohl(nentry.owned);
154     tentry->nextOwned = ntohl(nentry.nextOwned);
155     tentry->parent = ntohl(nentry.parent);
156     tentry->sibling = ntohl(nentry.sibling);
157     tentry->child = ntohl(nentry.child);
158     strncpy(tentry->name, nentry.name, PR_MAXNAMELEN);
159 #ifdef PR_REMEMBER_TIMES
160     tentry->createTime = ntohl(nentry.createTime);
161     tentry->addTime = ntohl(nentry.addTime);
162     tentry->removeTime = ntohl(nentry.removeTime);
163     tentry->changeTime = ntohl(nentry.changeTime);
164 #endif
165     for (i = 0; i < PRSIZE; i++)
166         tentry->entries[i] = ntohl(nentry.entries[i]);
167     return (code);
168 }
169
170 int
171 pr_WriteCoEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct contentry *tentry)
172 {
173     afs_int32 code;
174     register afs_int32 i;
175     struct contentry nentry;
176
177     if (ntohl(1) != 1) {        /* No need to swap */
178         memset(&nentry, 0, sizeof(nentry));     /* make reseved fields zero */
179         nentry.flags = htonl(tentry->flags);
180         nentry.id = htonl(tentry->id);
181         nentry.cellid = htonl(tentry->cellid);
182         nentry.next = htonl(tentry->next);
183         for (i = 0; i < COSIZE; i++)
184             nentry.entries[i] = htonl(tentry->entries[i]);
185         tentry = &nentry;
186     }
187     code = pr_Write(tt, afd, pos, (char *)tentry, sizeof(struct contentry));
188     return (code);
189 }
190
191 int
192 pr_ReadCoEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct contentry *tentry)
193 {
194     afs_int32 code;
195     register afs_int32 i;
196     struct contentry nentry;
197     code = ubik_Seek(tt, afd, pos);
198     if (code)
199         return (code);
200     if (ntohl(1) == 1) {        /* No swapping needed. */
201         code = ubik_Read(tt, (char *)tentry, sizeof(struct contentry));
202         return (code);
203     }
204     code = ubik_Read(tt, (char *)&nentry, sizeof(struct contentry));
205     if (code)
206         return (code);
207     memset(tentry, 0, sizeof(*tentry)); /* make reseved fields zero */
208     tentry->flags = ntohl(nentry.flags);
209     tentry->id = ntohl(nentry.id);
210     tentry->cellid = ntohl(nentry.cellid);
211     tentry->next = ntohl(nentry.next);
212     for (i = 0; i < COSIZE; i++)
213         tentry->entries[i] = ntohl(nentry.entries[i]);
214     return (code);
215 }
216
217 /* AllocBloc - allocate a free block of storage for entry, returning address of
218  * new entry */
219
220 afs_int32
221 AllocBlock(register struct ubik_trans *at)
222 {
223     register afs_int32 code;
224     afs_int32 temp;
225     struct prentry tentry;
226
227     if (cheader.freePtr) {
228         /* allocate this dude */
229         temp = ntohl(cheader.freePtr);
230         code = pr_ReadEntry(at, 0, temp, &tentry);
231         if (code)
232             return 0;
233         cheader.freePtr = htonl(tentry.next);
234         code =
235             pr_Write(at, 0, 8, (char *)&cheader.freePtr,
236                      sizeof(cheader.freePtr));
237         if (code != 0)
238             return 0;
239         return temp;
240     } else {
241         /* hosed, nothing on free list, grow file */
242         temp = ntohl(cheader.eofPtr);   /* remember this guy */
243         cheader.eofPtr = htonl(temp + ENTRYSIZE);
244         code =
245             pr_Write(at, 0, 12, (char *)&cheader.eofPtr,
246                      sizeof(cheader.eofPtr));
247         if (code != 0)
248             return 0;
249         return temp;
250     }
251 }
252
253 afs_int32
254 FreeBlock(register struct ubik_trans *at, afs_int32 pos)
255 {
256     /* add a block of storage to the free list */
257     register afs_int32 code;
258     struct prentry tentry;
259
260     memset(&tentry, 0, sizeof(tentry));
261     tentry.next = ntohl(cheader.freePtr);
262     tentry.flags |= PRFREE;
263     cheader.freePtr = htonl(pos);
264     code =
265         pr_Write(at, 0, 8, (char *)&cheader.freePtr, sizeof(cheader.freePtr));
266     if (code != 0)
267         return code;
268     code = pr_WriteEntry(at, 0, pos, &tentry);
269     if (code != 0)
270         return code;
271     return PRSUCCESS;
272 }
273
274 afs_int32
275 FindByID(register struct ubik_trans *at, afs_int32 aid)
276 {
277     /* returns address of entry if found, 0 otherwise */
278     register afs_int32 code;
279     afs_int32 i;
280     struct prentry tentry;
281     afs_int32 entry;
282
283     if ((aid == PRBADID) || (aid == 0))
284         return 0;
285     i = IDHash(aid);
286     entry = ntohl(cheader.idHash[i]);
287     if (entry == 0)
288         return entry;
289     memset(&tentry, 0, sizeof(tentry));
290     code = pr_ReadEntry(at, 0, entry, &tentry);
291     if (code != 0)
292         return 0;
293     if (aid == tentry.id)
294         return entry;
295     assert(entry != tentry.nextID);
296     entry = tentry.nextID;
297     while (entry != 0) {
298         memset(&tentry, 0, sizeof(tentry));
299         code = pr_ReadEntry(at, 0, entry, &tentry);
300         if (code != 0)
301             return 0;
302         if (aid == tentry.id)
303             return entry;
304         assert(entry != tentry.nextID);
305         entry = tentry.nextID;
306     }
307     return 0;
308 }
309
310 afs_int32
311 FindByName(register struct ubik_trans *at, char aname[PR_MAXNAMELEN], struct prentry *tentryp)
312 {
313     /* ditto */
314     register afs_int32 code;
315     afs_int32 i;
316     afs_int32 entry;
317
318     i = NameHash(aname);
319     entry = ntohl(cheader.nameHash[i]);
320     if (entry == 0)
321         return entry;
322     memset(tentryp, 0, sizeof(struct prentry));
323     code = pr_ReadEntry(at, 0, entry, tentryp);
324     if (code != 0)
325         return 0;
326     if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
327         return entry;
328     assert(entry != tentryp->nextName);
329     entry = tentryp->nextName;
330     while (entry != 0) {
331         memset(tentryp, 0, sizeof(struct prentry));
332         code = pr_ReadEntry(at, 0, entry, tentryp);
333         if (code != 0)
334             return 0;
335         if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
336             return entry;
337         assert(entry != tentryp->nextName);
338         entry = tentryp->nextName;
339     }
340     return 0;
341 }
342
343 afs_int32
344 AllocID(register struct ubik_trans *at, afs_int32 flag, afs_int32 *aid)
345 {
346     /* allocs an id from the proper area of address space, based on flag */
347     register afs_int32 code = 1;
348     register afs_int32 i = 0;
349     register int maxcount = 50; /* to prevent infinite loops */
350
351     if (flag & PRGRP) {
352         *aid = ntohl(cheader.maxGroup);
353         while (code && i < maxcount) {
354             --(*aid);
355             code = FindByID(at, *aid);
356             i++;
357         }
358         if (code)
359             return PRNOIDS;
360         cheader.maxGroup = htonl(*aid);
361         code =
362             pr_Write(at, 0, 16, (char *)&cheader.maxGroup,
363                      sizeof(cheader.maxGroup));
364         if (code)
365             return PRDBFAIL;
366         return PRSUCCESS;
367     } else if (flag & PRFOREIGN) {
368         *aid = ntohl(cheader.maxForeign);
369         while (code && i < maxcount) {
370             ++(*aid);
371             code = FindByID(at, *aid);
372             i++;
373         }
374         if (code)
375             return PRNOIDS;
376         cheader.maxForeign = htonl(*aid);
377         code =
378             pr_Write(at, 0, 24, (char *)&cheader.maxForeign,
379                      sizeof(cheader.maxForeign));
380         if (code)
381             return PRDBFAIL;
382         return PRSUCCESS;
383     } else {
384         *aid = ntohl(cheader.maxID);
385         while (code && i < maxcount) {
386             ++(*aid);
387             code = FindByID(at, *aid);
388             i++;
389         }
390         if (code)
391             return PRNOIDS;
392         cheader.maxID = htonl(*aid);
393         code =
394             pr_Write(at, 0, 20, (char *)&cheader.maxID,
395                      sizeof(cheader.maxID));
396         if (code)
397             return PRDBFAIL;
398         return PRSUCCESS;
399     }
400 }
401
402 afs_int32
403 IDToName(register struct ubik_trans *at, afs_int32 aid, char aname[PR_MAXNAMELEN])
404 {
405     afs_int32 temp;
406     struct prentry tentry;
407     register afs_int32 code;
408
409     temp = FindByID(at, aid);
410     if (temp == 0)
411         return PRNOENT;
412     code = pr_Read(at, 0, temp, (char *)&tentry, sizeof(tentry));
413     if (code)
414         return code;
415     strncpy(aname, tentry.name, PR_MAXNAMELEN);
416     return PRSUCCESS;
417 }
418
419 afs_int32
420 NameToID(register struct ubik_trans *at, char aname[PR_MAXNAMELEN], afs_int32 *aid)
421 {
422     afs_int32 temp;
423     struct prentry tentry;
424
425     temp = FindByName(at, aname, &tentry);
426     if (!temp)
427         return PRNOENT;
428     *aid = tentry.id;
429     return PRSUCCESS;
430 }
431
432 int
433 IDCmp(const void *a, const void *b)
434 {
435     /* used to sort CPS's so that comparison with acl's is easier */
436     if (*(afs_int32 *)a > *(afs_int32 *)b) {
437         return 1;
438     } else if (*(afs_int32 *)a == *(afs_int32 *)b) {
439         return 0;
440     } else /* (*a < *b) */ {
441         return -1;
442     }
443 }
444
445 afs_int32
446 RemoveFromIDHash(struct ubik_trans *tt, afs_int32 aid, afs_int32 *loc)          /* ??? in case ID hashed twice ??? */
447 {
448     /* remove entry designated by aid from id hash table */
449     register afs_int32 code;
450     afs_int32 current, trail, i;
451     struct prentry tentry;
452     struct prentry bentry;
453
454     if ((aid == PRBADID) || (aid == 0))
455         return PRINCONSISTENT;
456     i = IDHash(aid);
457     current = ntohl(cheader.idHash[i]);
458     memset(&tentry, 0, sizeof(tentry));
459     memset(&bentry, 0, sizeof(bentry));
460     trail = 0;
461     if (current == 0)
462         return PRSUCCESS;       /* already gone */
463     code = pr_ReadEntry(tt, 0, current, &tentry);
464     if (code)
465         return PRDBFAIL;
466     while (aid != tentry.id) {
467         assert(trail != current);
468         trail = current;
469         current = tentry.nextID;
470         if (current == 0)
471             break;
472         code = pr_ReadEntry(tt, 0, current, &tentry);
473         if (code)
474             return PRDBFAIL;
475     }
476     if (current == 0)
477         return PRSUCCESS;       /* we didn't find him, so he's already gone */
478     if (trail == 0) {
479         /* it's the first entry! */
480         cheader.idHash[i] = htonl(tentry.nextID);
481         code =
482             pr_Write(tt, 0, 72 + HASHSIZE * 4 + i * 4,
483                      (char *)&cheader.idHash[i], sizeof(cheader.idHash[i]));
484         if (code)
485             return PRDBFAIL;
486     } else {
487         code = pr_ReadEntry(tt, 0, trail, &bentry);
488         if (code)
489             return PRDBFAIL;
490         bentry.nextID = tentry.nextID;
491         code = pr_WriteEntry(tt, 0, trail, &bentry);
492     }
493     *loc = current;
494     return PRSUCCESS;
495 }
496
497 afs_int32
498 AddToIDHash(struct ubik_trans *tt, afs_int32 aid, afs_int32 loc)
499 {
500     /* add entry at loc designated by aid to id hash table */
501     register afs_int32 code;
502     afs_int32 i;
503     struct prentry tentry;
504
505     if ((aid == PRBADID) || (aid == 0))
506         return PRINCONSISTENT;
507     i = IDHash(aid);
508     memset(&tentry, 0, sizeof(tentry));
509     code = pr_ReadEntry(tt, 0, loc, &tentry);
510     if (code)
511         return PRDBFAIL;
512     tentry.nextID = ntohl(cheader.idHash[i]);
513     cheader.idHash[i] = htonl(loc);
514     code = pr_WriteEntry(tt, 0, loc, &tentry);
515     if (code)
516         return PRDBFAIL;
517     code =
518         pr_Write(tt, 0, 72 + HASHSIZE * 4 + i * 4, (char *)&cheader.idHash[i],
519                  sizeof(cheader.idHash[i]));
520     if (code)
521         return PRDBFAIL;
522     return PRSUCCESS;
523 }
524
525 afs_int32
526 RemoveFromNameHash(struct ubik_trans *tt, char *aname, afs_int32 *loc)
527 {
528     /* remove from name hash */
529     register afs_int32 code;
530     afs_int32 current, trail, i;
531     struct prentry tentry;
532     struct prentry bentry;
533
534     i = NameHash(aname);
535     current = ntohl(cheader.nameHash[i]);
536     memset(&tentry, 0, sizeof(tentry));
537     memset(&bentry, 0, sizeof(bentry));
538     trail = 0;
539     if (current == 0)
540         return PRSUCCESS;       /* already gone */
541     code = pr_ReadEntry(tt, 0, current, &tentry);
542     if (code)
543         return PRDBFAIL;
544     while (strcmp(aname, tentry.name)) {
545         assert(trail != current);
546         trail = current;
547         current = tentry.nextName;
548         if (current == 0)
549             break;
550         code = pr_ReadEntry(tt, 0, current, &tentry);
551         if (code)
552             return PRDBFAIL;
553     }
554     if (current == 0)
555         return PRSUCCESS;       /* we didn't find him, already gone */
556     if (trail == 0) {
557         /* it's the first entry! */
558         cheader.nameHash[i] = htonl(tentry.nextName);
559         code =
560             pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
561                      sizeof(cheader.nameHash[i]));
562         if (code)
563             return PRDBFAIL;
564     } else {
565         code = pr_ReadEntry(tt, 0, trail, &bentry);
566         if (code)
567             return PRDBFAIL;
568         bentry.nextName = tentry.nextName;
569         code = pr_WriteEntry(tt, 0, trail, &bentry);
570     }
571     *loc = current;
572     return PRSUCCESS;
573 }
574
575 afs_int32
576 AddToNameHash(struct ubik_trans *tt, char *aname, afs_int32 loc)
577 {
578     /* add to name hash */
579     register afs_int32 code;
580     afs_int32 i;
581     struct prentry tentry;
582
583     i = NameHash(aname);
584     memset(&tentry, 0, sizeof(tentry));
585     code = pr_ReadEntry(tt, 0, loc, &tentry);
586     if (code)
587         return PRDBFAIL;
588     tentry.nextName = ntohl(cheader.nameHash[i]);
589     cheader.nameHash[i] = htonl(loc);
590     code = pr_WriteEntry(tt, 0, loc, &tentry);
591     if (code)
592         return PRDBFAIL;
593     code =
594         pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
595                  sizeof(cheader.nameHash[i]));
596     if (code)
597         return PRDBFAIL;
598     return PRSUCCESS;
599 }
600
601 afs_int32
602 AddToOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
603 {
604     /* add entry designated by gid to owner chain of entry designated by oid */
605     register afs_int32 code;
606     afs_int32 loc;
607     struct prentry tentry;
608     struct prentry gentry;
609     afs_int32 gloc;
610
611     loc = FindByID(at, oid);
612     if (!loc)
613         return PRNOENT;
614     code = pr_ReadEntry(at, 0, loc, &tentry);
615     if (code != 0)
616         return PRDBFAIL;
617     if (oid == gid) {           /* added it to its own chain */
618         tentry.nextOwned = tentry.owned;
619         tentry.owned = loc;
620     } else {
621         gloc = FindByID(at, gid);
622         code = pr_ReadEntry(at, 0, gloc, &gentry);
623         if (code != 0)
624             return PRDBFAIL;
625         gentry.nextOwned = tentry.owned;
626         tentry.owned = gloc;
627         code = pr_WriteEntry(at, 0, gloc, &gentry);
628         if (code != 0)
629             return PRDBFAIL;
630     }
631     code = pr_WriteEntry(at, 0, loc, &tentry);
632     if (code != 0)
633         return PRDBFAIL;
634     return PRSUCCESS;
635 }
636
637 /* RemoveFromOwnerChain - remove gid from owner chain for oid */
638
639 afs_int32
640 RemoveFromOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
641 {
642     register afs_int32 code;
643     afs_int32 nptr;
644     struct prentry thisEntry;
645     struct prentry thatEntry;
646     struct prentry *te;         /* pointer to current (this) entry */
647     struct prentry *le;         /* pointer to previous (last) entry */
648     afs_int32 loc, lastLoc;
649
650     loc = FindByID(at, oid);
651     if (!loc)
652         return PRNOENT;
653     code = pr_ReadEntry(at, 0, loc, &thisEntry);
654     if (code != 0)
655         return PRDBFAIL;
656     le = &thisEntry;
657     lastLoc = 0;
658     nptr = thisEntry.owned;
659     while (nptr != 0) {
660         if (nptr == lastLoc)
661             te = le;
662         else {
663             if (&thisEntry == le)
664                 te = &thatEntry;
665             else
666                 te = &thisEntry;
667             code = pr_ReadEntry(at, 0, nptr, te);
668             if (code != 0)
669                 return PRDBFAIL;
670         }
671         if (te->id == gid) {
672             /* found it */
673             if (lastLoc == 0) { /* modifying first of chain */
674                 le->owned = te->nextOwned;
675                 lastLoc = loc;  /* so we write to correct location */
676             } else
677                 le->nextOwned = te->nextOwned;
678             te->nextOwned = 0;
679             if (te != le) {
680                 code = pr_WriteEntry(at, 0, nptr, te);
681                 if (code != 0)
682                     return PRDBFAIL;
683             }
684             code = pr_WriteEntry(at, 0, lastLoc, le);
685             if (code != 0)
686                 return PRDBFAIL;
687             return PRSUCCESS;
688         }
689         lastLoc = nptr;
690         le = te;
691         nptr = te->nextOwned;
692     }
693     return PRSUCCESS;           /* already removed? */
694 }
695
696 /* AddToOrphan - add gid to orphan list, as it's owner has died */
697
698 afs_int32
699 AddToOrphan(struct ubik_trans *at, afs_int32 gid)
700 {
701     register afs_int32 code;
702     afs_int32 loc;
703     struct prentry tentry;
704
705     loc = FindByID(at, gid);
706     if (!loc)
707         return PRNOENT;
708     code = pr_ReadEntry(at, 0, loc, &tentry);
709     if (code != 0)
710         return PRDBFAIL;
711     tentry.nextOwned = ntohl(cheader.orphan);
712     code = set_header_word(at, orphan, htonl(loc));
713     if (code != 0)
714         return PRDBFAIL;
715     tentry.owner = 0;           /* so there's no confusion later */
716     code = pr_WriteEntry(at, 0, loc, &tentry);
717     if (code != 0)
718         return PRDBFAIL;
719     return PRSUCCESS;
720 }
721
722 afs_int32
723 RemoveFromOrphan(struct ubik_trans *at, afs_int32 gid)
724 {
725     /* remove gid from the orphan list */
726     register afs_int32 code;
727     afs_int32 loc;
728     afs_int32 nptr;
729     struct prentry tentry;
730     struct prentry bentry;
731
732     loc = FindByID(at, gid);
733     if (!loc)
734         return PRNOENT;
735     code = pr_ReadEntry(at, 0, loc, &tentry);
736     if (code != 0)
737         return PRDBFAIL;
738     if (cheader.orphan == htonl(loc)) {
739         cheader.orphan = htonl(tentry.nextOwned);
740         tentry.nextOwned = 0;
741         code =
742             pr_Write(at, 0, 32, (char *)&cheader.orphan,
743                      sizeof(cheader.orphan));
744         if (code != 0)
745             return PRDBFAIL;
746         code = pr_WriteEntry(at, 0, loc, &tentry);
747         if (code != 0)
748             return PRDBFAIL;
749         return PRSUCCESS;
750     }
751     nptr = ntohl(cheader.orphan);
752     memset(&bentry, 0, sizeof(bentry));
753     loc = 0;
754     while (nptr != 0) {
755         code = pr_ReadEntry(at, 0, nptr, &tentry);
756         if (code != 0)
757             return PRDBFAIL;
758         if (gid == tentry.id) {
759             /* found it */
760             bentry.nextOwned = tentry.nextOwned;
761             tentry.nextOwned = 0;
762             code = pr_WriteEntry(at, 0, loc, &bentry);
763             if (code != 0)
764                 return PRDBFAIL;
765             code = pr_WriteEntry(at, 0, nptr, &tentry);
766             if (code != 0)
767                 return PRDBFAIL;
768             return PRSUCCESS;
769         }
770         loc = nptr;
771         nptr = tentry.nextOwned;
772         memcpy(&bentry, &tentry, sizeof(tentry));
773     }
774     return PRSUCCESS;
775 }
776
777 afs_int32
778 IsOwnerOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
779 {
780     /* returns 1 if aid is the owner of gid, 0 otherwise */
781     register afs_int32 code;
782     struct prentry tentry;
783     afs_int32 loc;
784
785     loc = FindByID(at, gid);
786     if (!loc)
787         return 0;
788     code = pr_ReadEntry(at, 0, loc, &tentry);
789     if (code != 0)
790         return 0;
791     if (tentry.owner == aid)
792         return 1;
793     return 0;
794 }
795
796 afs_int32
797 OwnerOf(struct ubik_trans *at, afs_int32 gid)
798 {
799     /* returns the owner of gid */
800     register afs_int32 code;
801     afs_int32 loc;
802     struct prentry tentry;
803
804     loc = FindByID(at, gid);
805     if (!loc)
806         return 0;
807     code = pr_ReadEntry(at, 0, loc, &tentry);
808     if (code != 0)
809         return 0;
810     return tentry.owner;
811 }
812
813
814 afs_int32
815 IsAMemberOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
816 {
817     /* returns true if aid is a member of gid */
818 #if !defined(SUPERGROUPS)
819     struct prentry tentry;
820     struct contentry centry;
821     register afs_int32 code;
822     afs_int32 i;
823     afs_int32 loc;
824 #endif
825
826     /* special case anyuser and authuser */
827     if (gid == ANYUSERID)
828         return 1;
829     if (gid == AUTHUSERID && aid != ANONYMOUSID)
830         return 1;
831     /* check -localauth case */
832     if (gid == SYSADMINID && aid == SYSADMINID)
833         return 1;
834     if ((gid == 0) || (aid == 0))
835         return 0;
836 #if defined(SUPERGROUPS)
837     return IsAMemberOfSG(at, aid, gid, depthsg);
838 #else
839     loc = FindByID(at, gid);
840     if (!loc)
841         return 0;
842     memset(&tentry, 0, sizeof(tentry));
843     code = pr_ReadEntry(at, 0, loc, &tentry);
844     if (code)
845         return 0;
846     if (!(tentry.flags & PRGRP))
847         return 0;
848     for (i = 0; i < PRSIZE; i++) {
849         if (tentry.entries[i] == 0)
850             return 0;
851         if (tentry.entries[i] == aid)
852             return 1;
853     }
854     if (tentry.next) {
855         loc = tentry.next;
856         while (loc) {
857             memset(&centry, 0, sizeof(centry));
858             code = pr_ReadCoEntry(at, 0, loc, &centry);
859             if (code)
860                 return 0;
861             for (i = 0; i < COSIZE; i++) {
862                 if (centry.entries[i] == aid)
863                     return 1;
864                 if (centry.entries[i] == 0)
865                     return 0;
866             }
867             loc = centry.next;
868         }
869     }
870     return 0;                   /* actually, should never get here */
871 #endif
872 }
873
874
875 #if defined(SUPERGROUPS)
876 afs_int32
877 IsAMemberOfSG(struct ubik_trans *at, afs_int32 aid, afs_int32 gid, afs_int32 depth) 
878 {
879     /* returns true if aid is a member of gid */
880     struct prentry tentry;
881     struct contentry centry;
882     register afs_int32 code;
883     afs_int32 i;
884     afs_int32 loc;
885
886     if (depth < 1)
887         return 0;
888     loc = FindByID(at, gid);
889     if (!loc)
890         return 0;
891     memset(&tentry, 0, sizeof(tentry));
892     code = pr_ReadEntry(at, 0, loc, &tentry);
893     if (code)
894         return 0;
895     if (!(tentry.flags & PRGRP))
896         return 0;
897     for (i = 0; i < PRSIZE; i++) {
898         gid = tentry.entries[i];
899         if (gid == 0)
900             return 0;
901         if (gid == aid)
902             return 1;
903         if (gid == ANYUSERID)
904             return 1;
905         if (gid == AUTHUSERID && aid != ANONYMOUSID)
906             return 1;
907         if (gid < 0) {
908 #ifndef AFS_PTHREAD_ENV
909             IOMGR_Poll();
910 #endif
911             if (IsAMemberOfSG(at, aid, gid, depth - 1))
912                 return 1;
913         }
914     }
915     if (tentry.next) {
916         loc = tentry.next;
917         while (loc) {
918             memset(&centry, 0, sizeof(centry));
919             code = pr_ReadCoEntry(at, 0, loc, &centry);
920             if (code)
921                 return 0;
922             for (i = 0; i < COSIZE; i++) {
923                 gid = centry.entries[i];
924                 if (gid == 0)
925                     return 0;
926                 if (gid == aid)
927                     return 1;
928                 if (gid == ANYUSERID)
929                     return 1;
930                 if (gid == AUTHUSERID && aid != ANONYMOUSID)
931                     return 1;
932                 if (gid < 0) {
933 #ifndef AFS_PTHREAD_ENV
934                     IOMGR_Poll();
935 #endif
936                     if (IsAMemberOfSG(at, aid, gid, depth - 1))
937                         return 1;
938                 }
939             }
940             loc = centry.next;
941         }
942     }
943     return 0;                   /* actually, should never get here */
944 }
945 #endif /* SUPERGROUPS */