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