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