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