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