570a0bdb32661d9bc7411e9c59ac9524007577ef
[openafs.git] / src / ptserver / ptprocs.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 /*
11  *                      (3) function addToGroup
12  *
13  *                          1. Eliminate the code that tests for adding groups
14  *                             to groups. This is an error in normal AFS.
15  *                          2. If adding a group to a group call AddToSGEntry
16  *                             to add the id of the group it's a member of.
17  *
18  *                      (4) function Delete
19  *
20  *                          1. Print a messsage if an error is returned from
21  *                             FindByID() and PTDEBUG is defined.
22  *                          2. If removing a group from a group call
23  *                             RemoveFromSGEntry to remove the id of the
24  *                             group it's a member of.
25  *                          3. Remove supergroup continuation records.
26  *
27  *                      (5) function RemoveFromGroup
28  *
29  *                          1. Eliminate the code that tests for adding groups
30  *                             to groups. This is an error in normal AFS.
31  *                          2. If removing a group from a group call
32  *                             RemoveFromSGEntry to remove the id of the
33  *                             group it's a member of.
34  *
35  *                      (6) Add new functions PR_ListSuperGroups and
36  *                          listSuperGroups.
37  *
38  *                      (7) function isAMemberOf
39  *
40  *                          1. Allow groups to be members of groups.
41  *
42  *                      Transarc does not currently use opcodes past 520, but
43  *                      they *could* decide at any time to use more opcodes.
44  *                      If they did, then one part of our local mods,
45  *                      ListSupergroups, would break.  I've therefore
46  *                      renumbered it to 530, and put logic in to enable the
47  *                      old opcode to work (for now).
48  */
49
50 #include <afsconfig.h>
51 #include <afs/param.h>
52 #include <afs/stds.h>
53
54 #include <roken.h>
55
56 #include <ctype.h>
57
58 #include <lock.h>
59 #include <afs/afsutil.h>
60 #include <ubik.h>
61 #include <rx/xdr.h>
62 #include <rx/rx.h>
63 #include <rx/rxkad.h>
64 #include <afs/auth.h>
65
66 #include "ptserver.h"
67 #include "pterror.h"
68 #include "ptprototypes.h"
69 #include "afs/audit.h"
70
71 #ifdef AFS_ATHENA_STDENV
72 #include <krb.h>
73 #endif
74
75 extern int restricted;
76 extern struct ubik_dbase *dbase;
77 extern int pr_noAuth;
78 extern char *pr_realmName;
79 extern int prp_group_default;
80 extern int prp_user_default;
81
82 static afs_int32 iNewEntry(struct rx_call *call, char aname[], afs_int32 aid,
83                            afs_int32 oid, afs_int32 *cid);
84 static afs_int32 newEntry(struct rx_call *call, char aname[], afs_int32 flag,
85                           afs_int32 oid, afs_int32 *aid, afs_int32 *cid);
86 static afs_int32 whereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos,
87                            afs_int32 *cid);
88 static afs_int32 dumpEntry(struct rx_call *call, afs_int32 apos,
89                            struct prdebugentry *aentry, afs_int32 *cid);
90 static afs_int32 addToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid,
91                             afs_int32 *cid);
92 static afs_int32 nameToID(struct rx_call *call, namelist *aname, idlist *aid);
93 static afs_int32 idToName(struct rx_call *call, idlist *aid, namelist *aname);
94 static afs_int32 Delete(struct rx_call *call, afs_int32 aid, afs_int32 *cid);
95 static afs_int32 UpdateEntry(struct rx_call *call, afs_int32 aid, char *name,
96                              struct PrUpdateEntry *uentry, afs_int32 *cid);
97 static afs_int32 removeFromGroup(struct rx_call *call, afs_int32 aid,
98                                  afs_int32 gid, afs_int32 *cid);
99 static afs_int32 getCPS(struct rx_call *call, afs_int32 aid, prlist *alist,
100                         afs_int32 *over, afs_int32 *cid);
101 static afs_int32 getCPS2(struct rx_call *call, afs_int32 aid, afs_uint32 ahost,
102                          prlist *alist, afs_int32 *over, afs_int32 *cid);
103 static afs_int32 getHostCPS(struct rx_call *call, afs_uint32 ahost,
104                             prlist *alist, afs_int32 *over);
105 static afs_int32 listMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid);
106 static afs_int32 setMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag,
107                         afs_int32 *cid);
108 static afs_int32 listEntry(struct rx_call *call, afs_int32 aid,
109                            struct prcheckentry *aentry, afs_int32 *cid);
110 static afs_int32 listEntries(struct rx_call *call, afs_int32 flag,
111                              afs_int32 startindex, prentries *bulkentries,
112                              afs_int32 *nextstartindex, afs_int32 *cid);
113 static afs_int32 put_prentries(struct prentry *tentry, prentries *bulkentries);
114 static afs_int32 changeEntry(struct rx_call *call, afs_int32 aid, char *name,
115                              afs_int32 oid, afs_int32 newid, afs_int32 *cid);
116 static afs_int32 setFieldsEntry(struct rx_call *call, afs_int32 id,
117                                 afs_int32 mask, afs_int32 flags,
118                                 afs_int32 ngroups, afs_int32 nusers,
119                                 afs_int32 spare1, afs_int32 spare2,
120                                 afs_int32 *cid);
121 static afs_int32 listElements(struct rx_call *call, afs_int32 aid,
122                               prlist *alist, afs_int32 *over, afs_int32 *cid);
123 #if defined(SUPERGROUPS)
124 static afs_int32 listSuperGroups(struct rx_call *call, afs_int32 aid,
125                                  prlist *alist, afs_int32 *over,
126                                  afs_int32 *cid);
127 #endif
128 static afs_int32 listOwned(struct rx_call *call, afs_int32 aid, prlist *alist,
129                            afs_int32 *lastP, afs_int32 *cid);
130 static afs_int32 isAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid,
131                              afs_int32 *flag, afs_int32 *cid);
132 static afs_int32 addWildCards(struct ubik_trans *tt, prlist *alist,
133                               afs_uint32 host);
134 static afs_int32 WhoIsThisWithName(struct rx_call *acall,
135                                    struct ubik_trans *at, afs_int32 *aid,
136                                    char *aname);
137
138 /* when we abort, the ubik cachedVersion will be reset, so we'll read in the
139  * header on the next call.
140  * Abort the transaction and return the code.
141  */
142 #define ABORT_WITH(tt,code) return(ubik_AbortTrans(tt),code)
143
144 static int
145 CreateOK(struct ubik_trans *ut, afs_int32 cid, afs_int32 oid, afs_int32 flag,
146          int admin)
147 {
148     if (restricted && !admin)
149         return 0;
150
151     if (flag & PRFOREIGN) {
152         /* Foreign users are recognized by the '@' sign and
153          * not by the PRFOREIGN flag.
154          */
155         return 0;
156     } else if (flag & PRGRP) {
157         /* Allow anonymous group creation only if owner specified
158          * and running noAuth.
159          */
160         if (cid == ANONYMOUSID) {
161             if ((oid == 0) || !pr_noAuth)
162                 return 0;
163         }
164     } else {                    /* creating a user */
165         if (!admin && !pr_noAuth)
166             return 0;
167     }
168     return 1;                   /* OK! */
169 }
170
171 afs_int32
172 WhoIsThis(struct rx_call *acall, struct ubik_trans *at, afs_int32 *aid)
173 {
174     int code = WhoIsThisWithName(acall, at, aid, NULL);
175     if (code == 2 && *aid == ANONYMOUSID)
176         return PRNOENT;
177     return code;
178 }
179
180 afs_int32
181 SPR_INewEntry(struct rx_call *call, char aname[], afs_int32 aid, afs_int32 oid)
182 {
183     afs_int32 code;
184     afs_int32 cid = ANONYMOUSID;
185
186     code = iNewEntry(call, aname, aid, oid, &cid);
187     osi_auditU(call, PTS_INewEntEvent, code, AUD_ID, aid, AUD_STR, aname,
188                AUD_ID, oid, AUD_END);
189     ViceLog(5, ("PTS_INewEntry: code %d cid %d aid %d aname %s oid %d\n", code, cid, aid, aname, oid));
190     return code;
191 }
192
193 static afs_int32
194 iNewEntry(struct rx_call *call, char aname[], afs_int32 aid, afs_int32 oid,
195           afs_int32 *cid)
196 {
197     /* used primarily for conversion - not intended to be used as usual means
198      * of entering people into the database. */
199     struct ubik_trans *tt;
200     afs_int32 code;
201     afs_int32 gflag = 0;
202     int admin;
203
204     stolower(aname);
205     code = Initdb();
206     if (code != PRSUCCESS)
207         return code;
208     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
209     if (code)
210         return code;
211     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
212     if (code)
213         ABORT_WITH(tt, code);
214     code = read_DbHeader(tt);
215     if (code)
216         ABORT_WITH(tt, code);
217
218     code = WhoIsThis(call, tt, cid);
219     if (code)
220         ABORT_WITH(tt, PRPERM);
221     admin = IsAMemberOf(tt, *cid, SYSADMINID);
222
223     /* first verify the id is good */
224     if (aid == 0)
225         ABORT_WITH(tt, PRPERM);
226     if (aid < 0) {
227         gflag |= PRGRP;
228         /* only sysadmin can reuse a group id */
229         if (!admin && !pr_noAuth && (aid != ntohl(cheader.maxGroup) - 1))
230             ABORT_WITH(tt, PRPERM);
231     }
232     if (FindByID(tt, aid))
233         ABORT_WITH(tt, PRIDEXIST);
234
235     /* check a few other things */
236     if (!CreateOK(tt, *cid, oid, gflag, admin))
237         ABORT_WITH(tt, PRPERM);
238
239     code = CreateEntry(tt, aname, &aid, 1, gflag, oid, *cid);
240     if (code != PRSUCCESS)
241         ABORT_WITH(tt, code);
242
243     /* finally, commit transaction */
244     code = ubik_EndTrans(tt);
245     if (code)
246         return code;
247     return PRSUCCESS;
248 }
249
250
251 afs_int32
252 SPR_NewEntry(struct rx_call *call, char aname[], afs_int32 flag, afs_int32 oid,
253              afs_int32 *aid)
254 {
255     afs_int32 code;
256     afs_int32 cid = ANONYMOUSID;
257
258     code = newEntry(call, aname, flag, oid, aid, &cid);
259     osi_auditU(call, PTS_NewEntEvent, code, AUD_ID, *aid, AUD_STR, aname,
260                AUD_ID, oid, AUD_END);
261     ViceLog(5, ("PTS_NewEntry: code %d cid %d aid %d aname %s oid %d\n", code, cid, *aid, aname, oid));
262     return code;
263 }
264
265 static afs_int32
266 newEntry(struct rx_call *call, char aname[], afs_int32 flag, afs_int32 oid,
267          afs_int32 *aid, afs_int32 *cid)
268 {
269     afs_int32 code;
270     struct ubik_trans *tt;
271     int admin;
272     char cname[PR_MAXNAMELEN];
273     stolower(aname);
274     code = Initdb();
275     if (code)
276         return code;
277     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
278     if (code)
279         return code;
280     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
281     if (code)
282         ABORT_WITH(tt, code);
283     code = read_DbHeader(tt);
284     if (code)
285         ABORT_WITH(tt, code);
286
287     /* this is for cross-cell self registration. It is not added in the
288      * SPR_INewEntry because we want self-registration to only do
289      * automatic id assignment.
290      */
291     code = WhoIsThisWithName(call, tt, cid, cname);
292     if (code != 2) {            /* 2 specifies that this is a foreign cell request */
293         if (code)
294             ABORT_WITH(tt, PRPERM);
295         admin = IsAMemberOf(tt, *cid, SYSADMINID);
296     } else {
297         admin = ((!restricted && !strcmp(aname, cname))) || IsAMemberOf(tt, *cid, SYSADMINID);
298         oid = *cid = SYSADMINID;
299     }
300     if (!CreateOK(tt, *cid, oid, flag, admin))
301         ABORT_WITH(tt, PRPERM);
302
303     code = CreateEntry(tt, aname, aid, 0, flag, oid, *cid);
304     if (code != PRSUCCESS)
305         ABORT_WITH(tt, code);
306
307     code = ubik_EndTrans(tt);
308     if (code)
309         return code;
310     return PRSUCCESS;
311 }
312
313
314
315 afs_int32
316 SPR_WhereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos)
317 {
318     afs_int32 code;
319     afs_int32 cid = ANONYMOUSID;
320
321     code = whereIsIt(call, aid, apos, &cid);
322     osi_auditU(call, PTS_WheIsItEvent, code, AUD_ID, aid, AUD_LONG, *apos,
323                AUD_END);
324     ViceLog(125, ("PTS_WhereIsIt: code %d cid %d aid %d apos %d\n", code, cid, aid, *apos));
325     return code;
326 }
327
328 static afs_int32
329 whereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos, afs_int32 *cid)
330 {
331     afs_int32 code;
332     struct ubik_trans *tt;
333     afs_int32 temp;
334
335     code = Initdb();
336     if (code != PRSUCCESS)
337         return code;
338     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
339     if (code)
340         return code;
341     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
342     if (code)
343         ABORT_WITH(tt, code);
344     code = read_DbHeader(tt);
345     if (code)
346         ABORT_WITH(tt, code);
347
348     code = WhoIsThis(call, tt, cid);
349     if (code)
350         ABORT_WITH(tt, PRPERM);
351
352     temp = FindByID(tt, aid);
353     if (!temp)
354         ABORT_WITH(tt, PRNOENT);
355     *apos = temp;
356     code = ubik_EndTrans(tt);
357     if (code)
358         return code;
359     return PRSUCCESS;
360 }
361
362
363 afs_int32
364 SPR_DumpEntry(struct rx_call *call, afs_int32 apos,
365               struct prdebugentry *aentry)
366 {
367     afs_int32 code;
368     afs_int32 cid = ANONYMOUSID;
369
370     code = dumpEntry(call, apos, aentry, &cid);
371     osi_auditU(call, PTS_DmpEntEvent, code, AUD_LONG, apos, AUD_END);
372     ViceLog(125, ("PTS_DumpEntry: code %d cid %d apos %d\n", code, cid, apos));
373     return code;
374 }
375
376 static afs_int32
377 dumpEntry(struct rx_call *call, afs_int32 apos, struct prdebugentry *aentry,
378           afs_int32 *cid)
379 {
380     afs_int32 code;
381     struct ubik_trans *tt;
382
383     code = Initdb();
384     if (code != PRSUCCESS)
385         return code;
386     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
387     if (code)
388         return code;
389     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
390     if (code)
391         ABORT_WITH(tt, code);
392     code = read_DbHeader(tt);
393     if (code)
394         ABORT_WITH(tt, code);
395
396     code = WhoIsThis(call, tt, cid);
397     if (code)
398         ABORT_WITH(tt, PRPERM);
399     code = pr_ReadEntry(tt, 0, apos, (struct prentry *)aentry);
400     if (code)
401         ABORT_WITH(tt, code);
402
403     if (!AccessOK(tt, *cid, 0, PRP_STATUS_MEM, 0))
404         ABORT_WITH(tt, PRPERM);
405
406     /* Since prdebugentry is in the form of a prentry not a coentry, we will
407      * return the coentry slots in network order where the string is. */
408 #if 0
409     if (aentry->flags & PRCONT) {       /* wrong type, get coentry instead */
410         code = pr_ReadCoEntry(tt, 0, apos, aentry);
411         if (code)
412             ABORT_WITH(tt, code);
413     }
414 #endif
415     code = ubik_EndTrans(tt);
416     if (code)
417         return code;
418     return PRSUCCESS;
419 }
420
421 afs_int32
422 SPR_AddToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid)
423 {
424     afs_int32 code;
425     afs_int32 cid = ANONYMOUSID;
426
427     code = addToGroup(call, aid, gid, &cid);
428     osi_auditU(call, PTS_AdToGrpEvent, code, AUD_ID, gid, AUD_ID, aid,
429                AUD_END);
430     ViceLog(5, ("PTS_AddToGroup: code %d cid %d gid %d aid %d\n", code, cid, gid, aid));
431     return code;
432 }
433
434 static afs_int32
435 addToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid, afs_int32 *cid)
436 {
437     afs_int32 code;
438     struct ubik_trans *tt;
439     afs_int32 tempu;
440     afs_int32 tempg;
441     struct prentry tentry;
442     struct prentry uentry;
443
444     code = Initdb();
445     if (code != PRSUCCESS)
446         return code;
447     if (gid == ANYUSERID || gid == AUTHUSERID)
448         return PRPERM;
449     if (aid == ANONYMOUSID)
450         return PRPERM;
451     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
452     if (code)
453         return code;
454     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
455     if (code)
456         ABORT_WITH(tt, code);
457     code = read_DbHeader(tt);
458     if (code)
459         ABORT_WITH(tt, code);
460
461     code = WhoIsThis(call, tt, cid);
462     if (code)
463         ABORT_WITH(tt, PRPERM);
464     tempu = FindByID(tt, aid);
465     if (!tempu)
466         ABORT_WITH(tt, PRNOENT);
467     memset(&uentry, 0, sizeof(uentry));
468     code = pr_ReadEntry(tt, 0, tempu, &uentry);
469     if (code != 0)
470         ABORT_WITH(tt, code);
471
472 #if !defined(SUPERGROUPS)
473     /* we don't allow groups as members of groups at present */
474     if (uentry.flags & PRGRP)
475         ABORT_WITH(tt, PRNOTUSER);
476 #endif
477
478     tempg = FindByID(tt, gid);
479     if (!tempg)
480         ABORT_WITH(tt, PRNOENT);
481     code = pr_ReadEntry(tt, 0, tempg, &tentry);
482     if (code != 0)
483         ABORT_WITH(tt, code);
484     /* make sure that this is a group */
485     if (!(tentry.flags & PRGRP))
486         ABORT_WITH(tt, PRNOTGROUP);
487     if (!AccessOK(tt, *cid, &tentry, PRP_ADD_MEM, PRP_ADD_ANY))
488         ABORT_WITH(tt, PRPERM);
489
490     code = AddToEntry(tt, &tentry, tempg, aid);
491     if (code != PRSUCCESS)
492         ABORT_WITH(tt, code);
493
494 #if defined(SUPERGROUPS)
495     if (uentry.flags & PRGRP)
496         code = AddToSGEntry(tt, &uentry, tempu, gid);   /* mod group to be in sg */
497     else
498 #endif
499         /* now, modify the user's entry as well */
500         code = AddToEntry(tt, &uentry, tempu, gid);
501     if (code != PRSUCCESS)
502         ABORT_WITH(tt, code);
503     code = ubik_EndTrans(tt);
504     if (code)
505         return code;
506     return PRSUCCESS;
507 }
508
509 afs_int32
510 SPR_NameToID(struct rx_call *call, namelist *aname, idlist *aid)
511 {
512     afs_int32 code;
513
514     code = nameToID(call, aname, aid);
515     osi_auditU(call, PTS_NmToIdEvent, code, AUD_END);
516     ViceLog(125, ("PTS_NameToID: code %d\n", code));
517     return code;
518 }
519
520 static afs_int32
521 nameToID(struct rx_call *call, namelist *aname, idlist *aid)
522 {
523     afs_int32 code;
524     struct ubik_trans *tt;
525     afs_int32 i;
526     int size;
527     int count = 0;
528
529     /* Initialize return struct */
530     aid->idlist_len = 0;
531     aid->idlist_val = NULL;
532
533     size = aname->namelist_len;
534     if (size == 0)
535         return 0;
536     if (size < 0)
537         return PRTOOMANY;
538
539     aid->idlist_val = (afs_int32 *) malloc(size * sizeof(afs_int32));
540     if (!aid->idlist_val)
541         return PRNOMEM;
542
543     code = Initdb();
544     if (code != PRSUCCESS)
545         return code;
546     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
547     if (code)
548         return code;
549     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
550     if (code)
551         ABORT_WITH(tt, code);
552     code = read_DbHeader(tt);
553     if (code)
554         ABORT_WITH(tt, code);
555
556     for (i = 0; i < aname->namelist_len; i++) {
557         char vname[256];
558         char *nameinst, *cell;
559
560         strncpy(vname, aname->namelist_val[i], sizeof(vname));
561         vname[sizeof(vname)-1] ='\0';
562
563         nameinst = vname;
564         cell = strchr(vname, '@');
565         if (cell) {
566             *cell = '\0';
567             cell++;
568         }
569
570         if (cell && afs_is_foreign_ticket_name(nameinst,NULL,cell,pr_realmName))
571             code = NameToID(tt, aname->namelist_val[i], &aid->idlist_val[i]);
572         else
573             code = NameToID(tt, nameinst, &aid->idlist_val[i]);
574
575         if (code != PRSUCCESS)
576             aid->idlist_val[i] = ANONYMOUSID;
577         osi_audit(PTS_NmToIdEvent, code, AUD_STR,
578                    aname->namelist_val[i], AUD_ID, aid->idlist_val[i],
579                    AUD_END);
580         ViceLog(125, ("PTS_NameToID: code %d aname %s aid %d\n", code,
581                       aname->namelist_val[i], aid->idlist_val[i]));
582         if (count++ > 50) {
583 #ifndef AFS_PTHREAD_ENV
584             IOMGR_Poll();
585 #endif
586             count = 0;
587         }
588     }
589     aid->idlist_len = aname->namelist_len;
590
591     code = ubik_EndTrans(tt);
592     if (code)
593         return code;
594     return PRSUCCESS;
595 }
596
597 /*
598  * SPR_IDToName
599  * Given an array of ids, find the name for each of them.
600  * The array of ids and names is unlimited.
601  */
602 afs_int32
603 SPR_IDToName(struct rx_call *call, idlist *aid, namelist *aname)
604 {
605     afs_int32 code;
606
607     code = idToName(call, aid, aname);
608     osi_auditU(call, PTS_IdToNmEvent, code, AUD_END);
609     ViceLog(125, ("PTS_IDToName: code %d\n", code));
610     return code;
611 }
612
613 static afs_int32
614 idToName(struct rx_call *call, idlist *aid, namelist *aname)
615 {
616     afs_int32 code;
617     struct ubik_trans *tt;
618     afs_int32 i;
619     int size;
620     int count = 0;
621
622     /* leave this first for rpc stub */
623     size = aid->idlist_len;
624     if (size == 0)
625         return 0;
626     if (size < 0)
627         return PRTOOMANY;
628     aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN);
629     aname->namelist_len = 0;
630     if (aname->namelist_val == 0)
631         return PRNOMEM;
632     if (aid->idlist_len == 0)
633         return 0;
634     if (size == 0)
635         return PRTOOMANY;       /* rxgen will probably handle this */
636
637     code = Initdb();
638     if (code != PRSUCCESS)
639         return code;
640     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
641     if (code)
642         return code;
643     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
644     if (code)
645         ABORT_WITH(tt, code);
646     code = read_DbHeader(tt);
647     if (code)
648         ABORT_WITH(tt, code);
649
650     for (i = 0; i < aid->idlist_len; i++) {
651         code = IDToName(tt, aid->idlist_val[i], aname->namelist_val[i]);
652         if (code != PRSUCCESS)
653             sprintf(aname->namelist_val[i], "%d", aid->idlist_val[i]);
654         osi_audit(PTS_IdToNmEvent, code, AUD_ID, aid->idlist_val[i],
655                   AUD_STR, aname->namelist_val[i], AUD_END);
656         ViceLog(125, ("PTS_idToName: code %d aid %d aname %s\n", code,
657                       aid->idlist_val[i], aname->namelist_val[i]));
658         if (count++ > 50) {
659 #ifndef AFS_PTHREAD_ENV
660             IOMGR_Poll();
661 #endif
662             count = 0;
663         }
664     }
665     aname->namelist_len = aid->idlist_len;
666
667     code = ubik_EndTrans(tt);
668     if (code)
669         return code;
670     return PRSUCCESS;
671 }
672
673 afs_int32
674 SPR_Delete(struct rx_call *call, afs_int32 aid)
675 {
676     afs_int32 code;
677     afs_int32 cid = ANONYMOUSID;
678
679     code = Delete(call, aid, &cid);
680     osi_auditU(call, PTS_DelEvent, code, AUD_ID, aid, AUD_END);
681     ViceLog(5, ("PTS_Delete: code %d cid %d aid %d\n", code, cid, aid));
682     return code;
683 }
684
685 static afs_int32
686 Delete(struct rx_call *call, afs_int32 aid, afs_int32 *cid)
687 {
688     afs_int32 code;
689     struct ubik_trans *tt;
690     struct prentry tentry;
691     afs_int32 loc, nptr;
692     int count;
693
694     code = Initdb();
695     if (code)
696         return code;
697     if (code != PRSUCCESS)
698         return code;
699     if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
700         || aid == ANONYMOUSID)
701         return PRPERM;
702     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
703     if (code)
704         return code;
705     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
706     if (code)
707         ABORT_WITH(tt, code);
708     code = read_DbHeader(tt);
709     if (code)
710         ABORT_WITH(tt, code);
711
712     code = WhoIsThis(call, tt, cid);
713     if (code)
714         ABORT_WITH(tt, PRPERM);
715
716     /* Read in entry to be deleted */
717     loc = FindByID(tt, aid);
718     if (loc == 0)
719         ABORT_WITH(tt, PRNOENT);
720     code = pr_ReadEntry(tt, 0, loc, &tentry);
721     if (code)
722         ABORT_WITH(tt, PRDBFAIL);
723
724     /* Do some access checking */
725     if (tentry.owner != *cid && !IsAMemberOf(tt, *cid, SYSADMINID)
726         && !IsAMemberOf(tt, *cid, tentry.owner) && !pr_noAuth)
727         ABORT_WITH(tt, PRPERM);
728
729     /* Delete each continuation block as a separate transaction so that no one
730      * transaction become to large to complete. */
731     nptr = tentry.next;
732     while (nptr != 0) {
733         struct contentry centry;
734         int i;
735
736         code = pr_ReadCoEntry(tt, 0, nptr, &centry);
737         if (code != 0)
738             ABORT_WITH(tt, PRDBFAIL);
739         for (i = 0; i < COSIZE; i++) {
740             if (centry.entries[i] == PRBADID)
741                 continue;
742             if (centry.entries[i] == 0)
743                 break;
744 #if defined(SUPERGROUPS)
745             if (aid < 0 && centry.entries[i] < 0)       /* Supergroup */
746                 code = RemoveFromSGEntry(tt, aid, centry.entries[i]);
747             else
748 #endif
749                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
750             if (code)
751                 ABORT_WITH(tt, code);
752             tentry.count--;     /* maintain count */
753 #ifndef AFS_PTHREAD_ENV
754             if ((i & 3) == 0)
755                 IOMGR_Poll();
756 #endif
757         }
758         tentry.next = centry.next;      /* thread out this block */
759         code = FreeBlock(tt, nptr);     /* free continuation block */
760         if (code)
761             ABORT_WITH(tt, code);
762         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
763         if (code)
764             ABORT_WITH(tt, code);
765
766         /* end this trans and start a new one */
767         code = ubik_EndTrans(tt);
768         if (code)
769             return code;
770 #ifndef AFS_PTHREAD_ENV
771         IOMGR_Poll();           /* just to keep the connection alive */
772 #endif
773         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
774         if (code)
775             return code;
776         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
777         if (code)
778             ABORT_WITH(tt, code);
779
780         /* re-read entry to get consistent uptodate info */
781         loc = FindByID(tt, aid);
782         if (loc == 0)
783             ABORT_WITH(tt, PRNOENT);
784         code = pr_ReadEntry(tt, 0, loc, &tentry);
785         if (code)
786             ABORT_WITH(tt, PRDBFAIL);
787
788         nptr = tentry.next;
789     }
790
791 #if defined(SUPERGROUPS)
792     /* Delete each continuation block as a separate transaction
793      * so that no one transaction become too large to complete. */
794     {
795         struct prentryg *tentryg = (struct prentryg *)&tentry;
796         nptr = tentryg->nextsg;
797         while (nptr != 0) {
798             struct contentry centry;
799             int i;
800
801             code = pr_ReadCoEntry(tt, 0, nptr, &centry);
802             if (code != 0)
803                 ABORT_WITH(tt, PRDBFAIL);
804             for (i = 0; i < COSIZE; i++) {
805                 if (centry.entries[i] == PRBADID)
806                     continue;
807                 if (centry.entries[i] == 0)
808                     break;
809                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
810                 if (code)
811                     ABORT_WITH(tt, code);
812                 tentryg->countsg--;     /* maintain count */
813 #ifndef AFS_PTHREAD_ENV
814                 if ((i & 3) == 0)
815                     IOMGR_Poll();
816 #endif
817             }
818             tentryg->nextsg = centry.next;      /* thread out this block */
819             code = FreeBlock(tt, nptr); /* free continuation block */
820             if (code)
821                 ABORT_WITH(tt, code);
822             code = pr_WriteEntry(tt, 0, loc, &tentry);  /* update main entry */
823             if (code)
824                 ABORT_WITH(tt, code);
825
826             /* end this trans and start a new one */
827             code = ubik_EndTrans(tt);
828             if (code)
829                 return code;
830 #ifndef AFS_PTHREAD_ENV
831             IOMGR_Poll();       /* just to keep the connection alive */
832 #endif
833
834             code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
835             if (code)
836                 return code;
837             code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
838             if (code)
839                 ABORT_WITH(tt, code);
840
841             /* re-read entry to get consistent uptodate info */
842             loc = FindByID(tt, aid);
843             if (loc == 0)
844                 ABORT_WITH(tt, PRNOENT);
845             code = pr_ReadEntry(tt, 0, loc, &tentry);
846             if (code)
847                 ABORT_WITH(tt, PRDBFAIL);
848
849             nptr = tentryg->nextsg;
850         }
851     }
852
853 #endif /* SUPERGROUPS */
854
855     /* Then move the owned chain, except possibly ourself to the orphan list.
856      * Because this list can be very long and so exceed the size of a ubik
857      * transaction, we start a new transaction every 50 entries. */
858     count = 0;
859     nptr = tentry.owned;
860     while (nptr != 0) {
861         struct prentry nentry;
862
863         code = pr_ReadEntry(tt, 0, nptr, &nentry);
864         if (code)
865             ABORT_WITH(tt, PRDBFAIL);
866         nptr = tentry.owned = nentry.nextOwned; /* thread out */
867
868         if (nentry.id != tentry.id) {   /* don't add us to orphan chain! */
869             code = AddToOrphan(tt, nentry.id);
870             if (code)
871                 ABORT_WITH(tt, code);
872             count++;
873 #ifndef AFS_PTHREAD_ENV
874             if ((count & 3) == 0)
875                 IOMGR_Poll();
876 #endif
877         }
878         if (count < 50)
879             continue;
880         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
881         if (code)
882             ABORT_WITH(tt, code);
883
884         /* end this trans and start a new one */
885         code = ubik_EndTrans(tt);
886         if (code)
887             return code;
888 #ifndef AFS_PTHREAD_ENV
889         IOMGR_Poll();           /* just to keep the connection alive */
890 #endif
891         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
892         if (code)
893             return code;
894         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
895         if (code)
896             ABORT_WITH(tt, code);
897
898         /* re-read entry to get consistent uptodate info */
899         loc = FindByID(tt, aid);
900         if (loc == 0)
901             ABORT_WITH(tt, PRNOENT);
902         code = pr_ReadEntry(tt, 0, loc, &tentry);
903         if (code)
904             ABORT_WITH(tt, PRDBFAIL);
905
906         nptr = tentry.owned;
907     }
908
909     /* now do what's left of the deletion stuff */
910     code = DeleteEntry(tt, &tentry, loc);
911     if (code != PRSUCCESS)
912         ABORT_WITH(tt, code);
913
914     code = ubik_EndTrans(tt);
915     if (code)
916         return code;
917     return PRSUCCESS;
918 }
919
920 afs_int32
921 SPR_UpdateEntry(struct rx_call *call, afs_int32 aid, char *name,
922                 struct PrUpdateEntry *uentry)
923 {
924     afs_int32 code;
925     afs_int32 cid = ANONYMOUSID;
926
927     code = UpdateEntry(call, aid, name, uentry, &cid);
928     osi_auditU(call, PTS_UpdEntEvent, code, AUD_ID, aid, AUD_STR, name, AUD_END);
929     ViceLog(5, ("PTS_UpdateEntry: code %d cid %d aid %d name %s\n", code, cid, aid, name));
930     return code;
931 }
932
933 afs_int32
934 UpdateEntry(struct rx_call *call, afs_int32 aid, char *name,
935             struct PrUpdateEntry *uentry, afs_int32 *cid)
936 {
937     afs_int32 code;
938     struct ubik_trans *tt;
939     struct prentry tentry;
940     afs_int32 loc;
941     int id = 0;
942
943     code = Initdb();
944     if (code)
945         return code;
946     if (code != PRSUCCESS)
947         return code;
948     if (aid) {
949         id = aid;
950         if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
951             || aid == ANONYMOUSID)
952             return PRPERM;
953     }
954     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
955     if (code)
956         return code;
957     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
958     if (code)
959         ABORT_WITH(tt, code);
960     code = read_DbHeader(tt);
961     if (code)
962         ABORT_WITH(tt, code);
963
964     code = WhoIsThis(call, tt, cid);
965     if (code)
966         ABORT_WITH(tt, PRPERM);
967     code = IsAMemberOf(tt, *cid, SYSADMINID);
968     if (!code && !pr_noAuth)
969         ABORT_WITH(tt, PRPERM);
970
971     /* Read in entry to be deleted */
972     if (id) {
973         loc = FindByID(tt, aid);
974     } else {
975         loc = FindByName(tt, name, &tentry);
976     }
977     if (loc == 0)
978         ABORT_WITH(tt, PRNOENT);
979     code = pr_ReadEntry(tt, 0, loc, &tentry);
980     if (code)
981         ABORT_WITH(tt, PRDBFAIL);
982
983     if (uentry->Mask & PRUPDATE_NAMEHASH) {
984         int tloc;
985         code = RemoveFromNameHash(tt, tentry.name, &tloc);
986         if (code != PRSUCCESS)
987             ABORT_WITH(tt, PRDBFAIL);
988         code = AddToNameHash(tt, tentry.name, loc);
989         if (code)
990             ABORT_WITH(tt, code);
991     }
992
993     if (uentry->Mask & PRUPDATE_IDHASH) {
994         int tloc;
995         if (!id)
996             id = tentry.id;
997         code = RemoveFromIDHash(tt, id, &tloc);
998         if (code != PRSUCCESS)
999             ABORT_WITH(tt, PRDBFAIL);
1000         code = AddToIDHash(tt, id, loc);
1001         if (code)
1002             ABORT_WITH(tt, code);
1003     }
1004
1005     code = ubik_EndTrans(tt);
1006     if (code)
1007         return code;
1008     return PRSUCCESS;
1009 }
1010
1011 afs_int32
1012 SPR_RemoveFromGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid)
1013 {
1014     afs_int32 code;
1015     afs_int32 cid = ANONYMOUSID;
1016
1017     code = removeFromGroup(call, aid, gid, &cid);
1018     osi_auditU(call, PTS_RmFmGrpEvent, code, AUD_ID, gid, AUD_ID, aid,
1019                AUD_END);
1020     ViceLog(5, ("PTS_RemoveFromGroup: code %d cid %d gid %d aid %d\n", code, cid, gid, aid));
1021     return code;
1022 }
1023
1024 static afs_int32
1025 removeFromGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid,
1026                 afs_int32 *cid)
1027 {
1028     afs_int32 code;
1029     struct ubik_trans *tt;
1030     afs_int32 tempu;
1031     afs_int32 tempg;
1032     struct prentry uentry;
1033     struct prentry gentry;
1034
1035     code = Initdb();
1036     if (code != PRSUCCESS)
1037         return code;
1038     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1039     if (code)
1040         return code;
1041     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1042     if (code)
1043         ABORT_WITH(tt, code);
1044     code = read_DbHeader(tt);
1045     if (code)
1046         ABORT_WITH(tt, code);
1047
1048     code = WhoIsThis(call, tt, cid);
1049     if (code)
1050         ABORT_WITH(tt, PRPERM);
1051     tempu = FindByID(tt, aid);
1052     if (!tempu)
1053         ABORT_WITH(tt, PRNOENT);
1054     tempg = FindByID(tt, gid);
1055     if (!tempg)
1056         ABORT_WITH(tt, PRNOENT);
1057     memset(&uentry, 0, sizeof(uentry));
1058     memset(&gentry, 0, sizeof(gentry));
1059     code = pr_ReadEntry(tt, 0, tempu, &uentry);
1060     if (code != 0)
1061         ABORT_WITH(tt, code);
1062     code = pr_ReadEntry(tt, 0, tempg, &gentry);
1063     if (code != 0)
1064         ABORT_WITH(tt, code);
1065     if (!(gentry.flags & PRGRP))
1066         ABORT_WITH(tt, PRNOTGROUP);
1067 #if !defined(SUPERGROUPS)
1068     if (uentry.flags & PRGRP)
1069         ABORT_WITH(tt, PRNOTUSER);
1070 #endif
1071     if (!AccessOK(tt, *cid, &gentry, PRP_REMOVE_MEM, 0))
1072         ABORT_WITH(tt, PRPERM);
1073     code = RemoveFromEntry(tt, aid, gid);
1074     if (code != PRSUCCESS)
1075         ABORT_WITH(tt, code);
1076 #if defined(SUPERGROUPS)
1077     if (!(uentry.flags & PRGRP))
1078 #endif
1079         code = RemoveFromEntry(tt, gid, aid);
1080 #if defined(SUPERGROUPS)
1081     else
1082         code = RemoveFromSGEntry(tt, gid, aid);
1083 #endif
1084     if (code != PRSUCCESS)
1085         ABORT_WITH(tt, code);
1086
1087     code = ubik_EndTrans(tt);
1088     if (code)
1089         return code;
1090     return PRSUCCESS;
1091 }
1092
1093
1094 afs_int32
1095 SPR_GetCPS(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *over)
1096 {
1097     afs_int32 code;
1098     afs_int32 cid = ANONYMOUSID;
1099
1100     code = getCPS(call, aid, alist, over, &cid);
1101     osi_auditU(call, PTS_GetCPSEvent, code, AUD_ID, aid, AUD_END);
1102     ViceLog(125, ("PTS_GetCPS: code %d cid %d aid %d\n", code, cid, aid));
1103     return code;
1104 }
1105
1106 static afs_int32
1107 getCPS(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *over,
1108        afs_int32 *cid)
1109 {
1110     afs_int32 code;
1111     struct ubik_trans *tt;
1112     afs_int32 temp;
1113     struct prentry tentry;
1114
1115     *over = 0;
1116     alist->prlist_len = 0;
1117     alist->prlist_val = NULL;
1118     code = Initdb();
1119     if (code != PRSUCCESS)
1120         return code;
1121     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1122     if (code)
1123         return code;
1124     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1125     if (code)
1126         ABORT_WITH(tt, code);
1127     code = read_DbHeader(tt);
1128     if (code)
1129         ABORT_WITH(tt, code);
1130
1131     temp = FindByID(tt, aid);
1132     if (!temp)
1133         ABORT_WITH(tt, PRNOENT);
1134     code = pr_ReadEntry(tt, 0, temp, &tentry);
1135     if (code)
1136         ABORT_WITH(tt, code);
1137
1138     /* afs does authenticate now */
1139     code = WhoIsThis(call, tt, cid);
1140     if (code || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1141         ABORT_WITH(tt, PRPERM);
1142
1143     code = GetList(tt, &tentry, alist, 1);
1144     if (code != PRSUCCESS)
1145         ABORT_WITH(tt, code);
1146
1147     code = ubik_EndTrans(tt);
1148     return code;
1149 }
1150
1151
1152 int
1153 inCPS(prlist CPS, afs_int32 id)
1154 {
1155     int i;
1156
1157     for (i = (CPS.prlist_len - 1); i >= 0; i--) {
1158         if (CPS.prlist_val[i] == id)
1159             return (1);
1160     }
1161     return (0);
1162 }
1163
1164
1165 afs_int32
1166 SPR_GetCPS2(struct rx_call *call, afs_int32 aid, afs_int32 ahost,
1167             prlist *alist, afs_int32 *over)
1168 {
1169     afs_int32 code;
1170     afs_int32 cid = ANONYMOUSID;
1171
1172     code = getCPS2(call, aid, ahost, alist, over, &cid);
1173     osi_auditU(call, PTS_GetCPS2Event, code, AUD_ID, aid, AUD_HOST, htonl(ahost),
1174                AUD_END);
1175     ViceLog(125, ("PTS_GetCPS2: code %d cid %d aid %d ahost %d\n", code, cid, aid, ahost));
1176     return code;
1177 }
1178
1179 static afs_int32
1180 getCPS2(struct rx_call *call, afs_int32 aid, afs_uint32 ahost, prlist *alist,
1181         afs_int32 *over, afs_int32 *cid)
1182 {
1183     afs_int32 code;
1184     struct ubik_trans *tt;
1185     afs_int32 temp;
1186     struct prentry tentry;
1187     struct prentry host_tentry;
1188     afs_int32 hostid;
1189     int host_list = 0;
1190     struct in_addr iaddr;
1191
1192     *over = 0;
1193     iaddr.s_addr = ntohl(ahost);
1194     alist->prlist_len = 0;
1195     alist->prlist_val = NULL;
1196     code = Initdb();
1197     if (code != PRSUCCESS)
1198         return code;
1199     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1200     if (code)
1201         return code;
1202     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1203     if (code)
1204         ABORT_WITH(tt, code);
1205     code = read_DbHeader(tt);
1206     if (code)
1207         ABORT_WITH(tt, code);
1208
1209     if (aid != PRBADID) {
1210         temp = FindByID(tt, aid);
1211         if (!temp)
1212             ABORT_WITH(tt, PRNOENT);
1213         code = pr_ReadEntry(tt, 0, temp, &tentry);
1214         if (code)
1215             ABORT_WITH(tt, code);
1216
1217         /* afs does authenticate now */
1218         code = WhoIsThis(call, tt, cid);
1219         if (code
1220             || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1221             ABORT_WITH(tt, PRPERM);
1222     }
1223     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1224     if (code == PRSUCCESS && hostid != 0) {
1225         temp = FindByID(tt, hostid);
1226         if (temp) {
1227             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1228             if (code == PRSUCCESS)
1229                 host_list = 1;
1230             else
1231                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1232         } else
1233             fprintf(stderr, "FindByID Failed -- Not found\n");
1234     }
1235     if (host_list)
1236         code = GetList2(tt, &tentry, &host_tentry, alist, 1);
1237     else
1238         code = GetList(tt, &tentry, alist, 1);
1239     if (!code)
1240         code = addWildCards(tt, alist, ntohl(ahost));
1241     if (code != PRSUCCESS)
1242         ABORT_WITH(tt, code);
1243
1244     code = ubik_EndTrans(tt);
1245     return code;
1246 }
1247
1248
1249 afs_int32
1250 SPR_GetHostCPS(struct rx_call *call, afs_int32 ahost, prlist *alist,
1251                afs_int32 *over)
1252 {
1253     afs_int32 code;
1254
1255     code = getHostCPS(call, ahost, alist, over);
1256     osi_auditU(call, PTS_GetHCPSEvent, code, AUD_HOST, htonl(ahost), AUD_END);
1257     ViceLog(125, ("PTS_GetHostCPS: code %d ahost %d\n", code, ahost));
1258     return code;
1259 }
1260
1261 afs_int32
1262 getHostCPS(struct rx_call *call, afs_uint32 ahost, prlist *alist,
1263            afs_int32 *over)
1264 {
1265     afs_int32 code, temp;
1266     struct ubik_trans *tt;
1267     struct prentry host_tentry;
1268     afs_int32 hostid;
1269     struct in_addr iaddr;
1270
1271     *over = 0;
1272     iaddr.s_addr = ntohl(ahost);
1273     alist->prlist_len = 0;
1274     alist->prlist_val = NULL;
1275     code = Initdb();
1276     if (code != PRSUCCESS)
1277         return code;
1278     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1279     if (code)
1280         return code;
1281     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1282     if (code)
1283         ABORT_WITH(tt, code);
1284     code = read_DbHeader(tt);
1285     if (code)
1286         ABORT_WITH(tt, code);
1287
1288     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1289     if (code == PRSUCCESS && hostid != 0) {
1290         temp = FindByID(tt, hostid);
1291         if (temp) {
1292             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1293             if (code == PRSUCCESS) {
1294                 code = GetList(tt, &host_tentry, alist, 0);
1295                 if (code)
1296                     goto bad;
1297             } else
1298                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1299         } else
1300             fprintf(stderr, "FindByID Failed -- Not found\n");
1301     }
1302     code = addWildCards(tt, alist, ntohl(ahost));
1303   bad:
1304     if (code != PRSUCCESS)
1305         ABORT_WITH(tt, code);
1306
1307     code = ubik_EndTrans(tt);
1308     return code;
1309 }
1310
1311
1312 afs_int32
1313 SPR_ListMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid)
1314 {
1315     afs_int32 code;
1316
1317     code = listMax(call, uid, gid);
1318     osi_auditU(call, PTS_LstMaxEvent, code, AUD_END);
1319     ViceLog(125, ("PTS_ListMax: code %d\n", code));
1320     return code;
1321 }
1322
1323 afs_int32
1324 listMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid)
1325 {
1326     afs_int32 code;
1327     struct ubik_trans *tt;
1328
1329     code = Initdb();
1330     if (code != PRSUCCESS)
1331         return code;
1332     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1333     if (code)
1334         return code;
1335     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1336     if (code)
1337         ABORT_WITH(tt, code);
1338     code = read_DbHeader(tt);
1339     if (code)
1340         ABORT_WITH(tt, code);
1341
1342     code = GetMax(tt, uid, gid);
1343     if (code != PRSUCCESS)
1344         ABORT_WITH(tt, code);
1345
1346     code = ubik_EndTrans(tt);
1347     if (code)
1348         return code;
1349     return PRSUCCESS;
1350 }
1351
1352 afs_int32
1353 SPR_SetMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag)
1354 {
1355     afs_int32 code;
1356     afs_int32 cid = ANONYMOUSID;
1357
1358     code = setMax(call, aid, gflag, &cid);
1359     osi_auditU(call, PTS_SetMaxEvent, code, AUD_ID, aid, AUD_LONG, gflag,
1360                AUD_END);
1361     ViceLog(125, ("PTS_SetMax: code %d cid %d aid %d gflag %d\n", code, cid, aid, gflag));
1362     return code;
1363 }
1364
1365 static afs_int32
1366 setMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag, afs_int32 *cid)
1367 {
1368     afs_int32 code;
1369     struct ubik_trans *tt;
1370
1371     code = Initdb();
1372     if (code != PRSUCCESS)
1373         return code;
1374     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1375     if (code)
1376         return code;
1377     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1378     if (code)
1379         ABORT_WITH(tt, code);
1380     code = read_DbHeader(tt);
1381     if (code)
1382         ABORT_WITH(tt, code);
1383
1384     code = WhoIsThis(call, tt, cid);
1385     if (code)
1386         ABORT_WITH(tt, PRPERM);
1387     if (!AccessOK(tt, *cid, 0, 0, 0))
1388         ABORT_WITH(tt, PRPERM);
1389     if (((gflag & PRGRP) && (aid > 0)) || (!(gflag & PRGRP) && (aid < 0)))
1390         ABORT_WITH(tt, PRBADARG);
1391
1392     code = SetMax(tt, aid, gflag);
1393     if (code != PRSUCCESS)
1394         ABORT_WITH(tt, code);
1395
1396     code = ubik_EndTrans(tt);
1397     if (code)
1398         return code;
1399     return PRSUCCESS;
1400 }
1401
1402 afs_int32
1403 SPR_ListEntry(struct rx_call *call, afs_int32 aid, struct prcheckentry *aentry)
1404 {
1405     afs_int32 code;
1406     afs_int32 cid = ANONYMOUSID;
1407
1408     code = listEntry(call, aid, aentry, &cid);
1409     osi_auditU(call, PTS_LstEntEvent, code, AUD_ID, aid, AUD_END);
1410     ViceLog(125, ("PTS_ListEntry: code %d cid %d aid %d\n", code, cid, aid));
1411     return code;
1412 }
1413
1414 static afs_int32
1415 listEntry(struct rx_call *call, afs_int32 aid, struct prcheckentry *aentry,
1416           afs_int32 *cid)
1417 {
1418     afs_int32 code;
1419     struct ubik_trans *tt;
1420     afs_int32 temp;
1421     struct prentry tentry;
1422
1423     code = Initdb();
1424     if (code != PRSUCCESS)
1425         return code;
1426     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1427     if (code)
1428         return code;
1429     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1430     if (code)
1431         ABORT_WITH(tt, code);
1432     code = read_DbHeader(tt);
1433     if (code)
1434         ABORT_WITH(tt, code);
1435
1436     code = WhoIsThis(call, tt, cid);
1437     if (code)
1438         ABORT_WITH(tt, PRPERM);
1439     temp = FindByID(tt, aid);
1440     if (!temp)
1441         ABORT_WITH(tt, PRNOENT);
1442     code = pr_ReadEntry(tt, 0, temp, &tentry);
1443     if (code != 0)
1444         ABORT_WITH(tt, code);
1445     if (!AccessOK(tt, *cid, &tentry, PRP_STATUS_MEM, PRP_STATUS_ANY))
1446         ABORT_WITH(tt, PRPERM);
1447
1448     aentry->flags = tentry.flags >> PRIVATE_SHIFT;
1449     if (aentry->flags == 0) {
1450         if (tentry.flags & PRGRP)
1451             aentry->flags = prp_group_default >> PRIVATE_SHIFT;
1452         else
1453             aentry->flags = prp_user_default >> PRIVATE_SHIFT;
1454     }
1455     aentry->owner = tentry.owner;
1456     aentry->id = tentry.id;
1457     strncpy(aentry->name, tentry.name, PR_MAXNAMELEN);
1458     aentry->creator = tentry.creator;
1459     aentry->ngroups = tentry.ngroups;
1460     aentry->nusers = tentry.nusers;
1461     aentry->count = tentry.count;
1462     memset(aentry->reserved, 0, sizeof(aentry->reserved));
1463     code = ubik_EndTrans(tt);
1464     if (code)
1465         return code;
1466     return PRSUCCESS;
1467 }
1468
1469 afs_int32
1470 SPR_ListEntries(struct rx_call *call, afs_int32 flag, afs_int32 startindex,
1471                 prentries *bulkentries, afs_int32 *nextstartindex)
1472 {
1473     afs_int32 code;
1474     afs_int32 cid = ANONYMOUSID;
1475
1476     code = listEntries(call, flag, startindex, bulkentries, nextstartindex, &cid);
1477     osi_auditU(call, PTS_LstEntsEvent, code, AUD_LONG, flag, AUD_END);
1478     ViceLog(125, ("PTS_ListEntries: code %d cid %d flag %d\n", code, cid, flag));
1479     return code;
1480 }
1481
1482 static afs_int32
1483 listEntries(struct rx_call *call, afs_int32 flag, afs_int32 startindex,
1484             prentries *bulkentries, afs_int32 *nextstartindex, afs_int32 *cid)
1485 {
1486     afs_int32 code;
1487     struct ubik_trans *tt;
1488     afs_int32 i, eof, pos, maxentries, f;
1489     struct prentry tentry;
1490     afs_int32 pollcount = 0;
1491
1492     *nextstartindex = -1;
1493     bulkentries->prentries_val = 0;
1494     bulkentries->prentries_len = 0;
1495
1496     code = Initdb();
1497     if (code != PRSUCCESS)
1498         return code;
1499     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1500     if (code)
1501         return code;
1502     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1503     if (code)
1504         ABORT_WITH(tt, code);
1505     code = read_DbHeader(tt);
1506     if (code)
1507         ABORT_WITH(tt, code);
1508
1509     /* Make sure we are an authenticated caller and that we are on the
1510      * SYSADMIN list.
1511      */
1512     code = WhoIsThis(call, tt, cid);
1513     if (code)
1514         ABORT_WITH(tt, PRPERM);
1515     code = IsAMemberOf(tt, *cid, SYSADMINID);
1516     if (!code && !pr_noAuth)
1517         ABORT_WITH(tt, PRPERM);
1518
1519     eof = ntohl(cheader.eofPtr) - sizeof(cheader);
1520     maxentries = eof / sizeof(struct prentry);
1521     for (i = startindex; i < maxentries; i++) {
1522         pos = i * sizeof(struct prentry) + sizeof(cheader);
1523         code = pr_ReadEntry(tt, 0, pos, &tentry);
1524         if (code)
1525             goto done;
1526
1527         if (++pollcount > 50) {
1528 #ifndef AFS_PTHREAD_ENV
1529             IOMGR_Poll();
1530 #endif
1531             pollcount = 0;
1532         }
1533
1534         f = (tentry.flags & PRTYPE);
1535         if (((flag & PRUSERS) && (f == 0)) ||   /* User  entry */
1536             ((flag & PRGROUPS) && (f & PRGRP))) {       /* Group entry */
1537             code = put_prentries(&tentry, bulkentries);
1538             if (code == -1)
1539                 break;          /* Filled return array */
1540             if (code)
1541                 goto done;
1542         }
1543     }
1544     code = 0;
1545     if (i < maxentries)
1546         *nextstartindex = i;
1547
1548   done:
1549     if (code) {
1550         if (bulkentries->prentries_val)
1551             free(bulkentries->prentries_val);
1552         bulkentries->prentries_val = 0;
1553         bulkentries->prentries_len = 0;
1554         ABORT_WITH(tt, code);
1555     } else {
1556         code = ubik_EndTrans(tt);
1557     }
1558     if (code)
1559         return code;
1560     return PRSUCCESS;
1561 }
1562
1563 #define PR_MAXENTRIES 500
1564 static afs_int32
1565 put_prentries(struct prentry *tentry, prentries *bulkentries)
1566 {
1567     struct prlistentries *entry;
1568
1569     if (bulkentries->prentries_val == 0) {
1570         bulkentries->prentries_len = 0;
1571         bulkentries->prentries_val =
1572             (struct prlistentries *)malloc(PR_MAXENTRIES *
1573                                            sizeof(struct prentry));
1574         if (!bulkentries->prentries_val) {
1575             return (PRNOMEM);
1576         }
1577     }
1578
1579     if (bulkentries->prentries_len >= PR_MAXENTRIES) {
1580         return (-1);
1581     }
1582
1583     entry = (struct prlistentries *)bulkentries->prentries_val;
1584     entry += bulkentries->prentries_len;
1585
1586     entry->flags = tentry->flags >> PRIVATE_SHIFT;
1587     if (entry->flags == 0) {
1588         entry->flags =
1589             ((tentry->
1590               flags & PRGRP) ? prp_group_default : prp_user_default) >>
1591             PRIVATE_SHIFT;
1592     }
1593     entry->owner = tentry->owner;
1594     entry->id = tentry->id;
1595     entry->creator = tentry->creator;
1596     entry->ngroups = tentry->ngroups;
1597     entry->nusers = tentry->nusers;
1598     entry->count = tentry->count;
1599     strncpy(entry->name, tentry->name, PR_MAXNAMELEN);
1600     memset(entry->reserved, 0, sizeof(entry->reserved));
1601     bulkentries->prentries_len++;
1602     return 0;
1603 }
1604
1605 afs_int32
1606 SPR_ChangeEntry(struct rx_call *call, afs_int32 aid, char *name, afs_int32 oid,
1607                 afs_int32 newid)
1608 {
1609     afs_int32 code;
1610     afs_int32 cid = ANONYMOUSID;
1611
1612     code = changeEntry(call, aid, name, oid, newid, &cid);
1613     osi_auditU(call, PTS_ChgEntEvent, code, AUD_ID, aid, AUD_STR, name,
1614                AUD_LONG, oid, AUD_LONG, newid, AUD_END);
1615     ViceLog(5, ("PTS_ChangeEntry: code %d cid %d aid %d name %s oid %d newid %d\n", code, cid, aid, name, oid, newid));
1616     return code;
1617 }
1618
1619 static afs_int32
1620 changeEntry(struct rx_call *call, afs_int32 aid, char *name, afs_int32 oid,
1621             afs_int32 newid, afs_int32 *cid)
1622 {
1623     afs_int32 code;
1624     struct ubik_trans *tt;
1625     afs_int32 pos;
1626
1627     if (!name)
1628         return PRPERM;
1629     stolower(name);
1630
1631     code = Initdb();
1632     if (code)
1633         return code;
1634     if (aid == ANYUSERID || aid == AUTHUSERID || aid == ANONYMOUSID
1635         || aid == SYSADMINID)
1636         return PRPERM;
1637     if (code != PRSUCCESS)
1638         return code;
1639     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1640     if (code)
1641         return code;
1642     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1643     if (code)
1644         ABORT_WITH(tt, code);
1645     code = read_DbHeader(tt);
1646     if (code)
1647         ABORT_WITH(tt, code);
1648
1649     code = WhoIsThis(call, tt, cid);
1650     if (code)
1651         ABORT_WITH(tt, PRPERM);
1652     pos = FindByID(tt, aid);
1653     if (!pos)
1654         ABORT_WITH(tt, PRNOENT);
1655     /* protection check in changeentry */
1656     code = ChangeEntry(tt, aid, *cid, name, oid, newid);
1657     if (code != PRSUCCESS)
1658         ABORT_WITH(tt, code);
1659
1660     code = ubik_EndTrans(tt);
1661     return code;
1662 }
1663
1664 afs_int32
1665 SPR_SetFieldsEntry(struct rx_call *call,
1666                    afs_int32 id,
1667                    afs_int32 mask, /* specify which fields to update */
1668                    afs_int32 flags, afs_int32 ngroups, afs_int32 nusers,
1669                    afs_int32 spare1, afs_int32 spare2)
1670 {
1671     afs_int32 code;
1672     afs_int32 cid = ANONYMOUSID;
1673
1674     code =
1675         setFieldsEntry(call, id, mask, flags, ngroups, nusers, spare1,
1676                        spare2, &cid);
1677     osi_auditU(call, PTS_SetFldEntEvent, code, AUD_ID, id, AUD_END);
1678     ViceLog(5, ("PTS_SetFieldsEntry: code %d cid %d id %d\n", code, cid, id));
1679     return code;
1680 }
1681
1682 static afs_int32
1683 setFieldsEntry(struct rx_call *call,
1684                afs_int32 id,
1685                afs_int32 mask, /* specify which fields to update */
1686                afs_int32 flags, afs_int32 ngroups, afs_int32 nusers,
1687                afs_int32 spare1, afs_int32 spare2, afs_int32 *cid)
1688 {
1689     afs_int32 code;
1690     struct ubik_trans *tt;
1691     afs_int32 pos;
1692     struct prentry tentry;
1693     afs_int32 tflags;
1694
1695     if (mask == 0)
1696         return 0;               /* no-op */
1697     code = Initdb();
1698     if (code)
1699         return code;
1700     if (id == ANYUSERID || id == AUTHUSERID || id == ANONYMOUSID)
1701         return PRPERM;
1702     if (code != PRSUCCESS)
1703         return code;
1704     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1705     if (code)
1706         return code;
1707     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1708     if (code)
1709         ABORT_WITH(tt, code);
1710     code = read_DbHeader(tt);
1711     if (code)
1712         ABORT_WITH(tt, code);
1713
1714     code = WhoIsThis(call, tt, cid);
1715     if (code)
1716         ABORT_WITH(tt, PRPERM);
1717     pos = FindByID(tt, id);
1718     if (!pos)
1719         ABORT_WITH(tt, PRNOENT);
1720     code = pr_ReadEntry(tt, 0, pos, &tentry);
1721     if (code)
1722         ABORT_WITH(tt, code);
1723     tflags = tentry.flags;
1724
1725     if (mask & (PR_SF_NGROUPS | PR_SF_NUSERS)) {
1726         if (!AccessOK(tt, *cid, 0, 0, 0))
1727             ABORT_WITH(tt, PRPERM);
1728         if ((tflags & PRQUOTA) == 0) {  /* default if only setting one */
1729             tentry.ngroups = tentry.nusers = 20;
1730         }
1731     } else {
1732         if (!AccessOK(tt, *cid, &tentry, 0, 0))
1733             ABORT_WITH(tt, PRPERM);
1734     }
1735
1736     if (mask & 0xffff) {        /* if setting flag bits */
1737         afs_int32 flagsMask = mask & 0xffff;
1738         tflags &= ~(flagsMask << PRIVATE_SHIFT);
1739         tflags |= (flags & flagsMask) << PRIVATE_SHIFT;
1740         tflags |= PRACCESS;
1741     }
1742
1743     if (mask & PR_SF_NGROUPS) { /* setting group limit */
1744         if (ngroups < 0)
1745             ABORT_WITH(tt, PRBADARG);
1746         tentry.ngroups = ngroups;
1747         tflags |= PRQUOTA;
1748     }
1749
1750     if (mask & PR_SF_NUSERS) {  /* setting foreign user limit */
1751         if (nusers < 0)
1752             ABORT_WITH(tt, PRBADARG);
1753         tentry.nusers = nusers;
1754         tflags |= PRQUOTA;
1755     }
1756     tentry.flags = tflags;
1757
1758     code = pr_WriteEntry(tt, 0, pos, &tentry);
1759     if (code)
1760         ABORT_WITH(tt, code);
1761
1762     code = ubik_EndTrans(tt);
1763     return code;
1764 }
1765
1766 afs_int32
1767 SPR_ListElements(struct rx_call *call, afs_int32 aid, prlist *alist,
1768                  afs_int32 *over)
1769 {
1770     afs_int32 code;
1771     afs_int32 cid = ANONYMOUSID;
1772
1773     code = listElements(call, aid, alist, over, &cid);
1774     osi_auditU(call, PTS_LstEleEvent, code, AUD_ID, aid, AUD_END);
1775     ViceLog(125, ("PTS_ListElements: code %d cid %d aid %d\n", code, cid, aid));
1776     return code;
1777 }
1778
1779 static afs_int32
1780 listElements(struct rx_call *call, afs_int32 aid, prlist *alist,
1781              afs_int32 *over, afs_int32 *cid)
1782 {
1783     afs_int32 code;
1784     struct ubik_trans *tt;
1785     afs_int32 temp;
1786     struct prentry tentry;
1787
1788     *over = 0;
1789     alist->prlist_len = 0;
1790     alist->prlist_val = NULL;
1791
1792     code = Initdb();
1793     if (code != PRSUCCESS)
1794         return code;
1795     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1796     if (code)
1797         return code;
1798     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1799     if (code)
1800         ABORT_WITH(tt, code);
1801     code = read_DbHeader(tt);
1802     if (code)
1803         ABORT_WITH(tt, code);
1804
1805     code = WhoIsThis(call, tt, cid);
1806     if (code)
1807         ABORT_WITH(tt, PRPERM);
1808
1809     temp = FindByID(tt, aid);
1810     if (!temp)
1811         ABORT_WITH(tt, PRNOENT);
1812     code = pr_ReadEntry(tt, 0, temp, &tentry);
1813     if (code)
1814         ABORT_WITH(tt, code);
1815     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1816         ABORT_WITH(tt, PRPERM);
1817
1818     code = GetList(tt, &tentry, alist, 0);
1819     if (code != PRSUCCESS)
1820         ABORT_WITH(tt, code);
1821
1822     code = ubik_EndTrans(tt);
1823     return code;
1824 }
1825
1826
1827 afs_int32
1828 SPR_ListSuperGroups(struct rx_call *call, afs_int32 aid, prlist *alist,
1829                     afs_int32 *over)
1830 {
1831 #if defined(SUPERGROUPS)
1832     afs_int32 code;
1833     afs_int32 cid = ANONYMOUSID;
1834
1835     code = listSuperGroups(call, aid, alist, over, &cid);
1836     osi_auditU(call, PTS_LstSGrps, code, AUD_ID, aid, AUD_END);
1837     ViceLog(125, ("PTS_ListSuperGroups: code %d cid %d aid %d\n", code, cid, aid));
1838     return code;
1839 #else
1840     return RXGEN_OPCODE;
1841 #endif
1842 }
1843
1844 #if defined(SUPERGROUPS)
1845 static afs_int32
1846 listSuperGroups(struct rx_call *call, afs_int32 aid, prlist *alist,
1847                 afs_int32 *over, afs_int32 *cid)
1848 {
1849     afs_int32 code;
1850     struct ubik_trans *tt;
1851     afs_int32 temp;
1852     struct prentry tentry;
1853
1854     alist->prlist_len = 0;
1855     alist->prlist_val = (afs_int32 *) 0;
1856
1857     code = Initdb();
1858     if (code != PRSUCCESS)
1859         goto done;
1860     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1861     if (code)
1862         goto done;
1863     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1864     if (code)
1865         ABORT_WITH(tt, code);
1866     code = WhoIsThis(call, tt, cid);
1867     if (code)
1868         ABORT_WITH(tt, PRPERM);
1869
1870     temp = FindByID(tt, aid);
1871     if (!temp)
1872         ABORT_WITH(tt, PRNOENT);
1873     code = pr_ReadEntry(tt, 0, temp, &tentry);
1874     if (code)
1875         ABORT_WITH(tt, code);
1876     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1877         ABORT_WITH(tt, PRPERM);
1878
1879     code = GetSGList(tt, &tentry, alist);
1880     *over = 0;
1881     if (code == PRTOOMANY)
1882         *over = 1;
1883     else if (code != PRSUCCESS)
1884         ABORT_WITH(tt, code);
1885
1886     code = ubik_EndTrans(tt);
1887
1888   done:
1889     return code;
1890 }
1891
1892 #endif /* SUPERGROUPS */
1893
1894 /*
1895  * SPR_ListOwned
1896  * List the entries owned by this id.  If the id is zero,
1897  * return the orphans list. This will return up to PR_MAXGROUPS
1898  * at a time with the lastP available to get the rest. The
1899  * maximum value is enforced in GetOwnedChain().
1900  */
1901 afs_int32
1902 SPR_ListOwned(struct rx_call *call, afs_int32 aid, prlist *alist,
1903               afs_int32 *lastP)
1904 {
1905     afs_int32 code;
1906     afs_int32 cid = ANONYMOUSID;
1907
1908     code = listOwned(call, aid, alist, lastP, &cid);
1909     osi_auditU(call, PTS_LstOwnEvent, code, AUD_ID, aid, AUD_END);
1910     ViceLog(125, ("PTS_ListOwned: code %d cid %d aid %d\n", code, cid, aid));
1911     return code;
1912 }
1913
1914 afs_int32
1915 listOwned(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *lastP,
1916           afs_int32 *cid)
1917 {
1918     afs_int32 code;
1919     struct ubik_trans *tt;
1920     struct prentry tentry;
1921     afs_int32 head = 0;
1922     afs_int32 start;
1923
1924     alist->prlist_len = 0;
1925     alist->prlist_val = NULL;
1926
1927     if (!lastP)
1928         return PRBADARG;
1929     start = *lastP;
1930     *lastP = 0;
1931
1932     code = Initdb();
1933     if (code != PRSUCCESS)
1934         return code;
1935     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1936     if (code)
1937         return code;
1938     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1939     if (code)
1940         ABORT_WITH(tt, code);
1941     code = read_DbHeader(tt);
1942     if (code)
1943         ABORT_WITH(tt, code);
1944
1945     code = WhoIsThis(call, tt, cid);
1946     if (code)
1947         ABORT_WITH(tt, PRPERM);
1948
1949     if (start) {
1950         code = pr_ReadEntry(tt, 0, start, &tentry);
1951         if (!code && (tentry.owner == aid))
1952             head = start;       /* pick up where we left off */
1953     }
1954
1955     if (!head) {
1956         if (aid) {
1957             afs_int32 loc = FindByID(tt, aid);
1958             if (loc == 0)
1959                 ABORT_WITH(tt, PRNOENT);
1960             code = pr_ReadEntry(tt, 0, loc, &tentry);
1961             if (code)
1962                 ABORT_WITH(tt, code);
1963
1964             if (!AccessOK(tt, *cid, &tentry, -1, PRP_OWNED_ANY))
1965                 ABORT_WITH(tt, PRPERM);
1966             head = tentry.owned;
1967         } else {
1968             if (!AccessOK(tt, *cid, 0, 0, 0))
1969                 ABORT_WITH(tt, PRPERM);
1970             head = ntohl(cheader.orphan);
1971         }
1972     }
1973
1974     code = GetOwnedChain(tt, &head, alist);
1975     if (code) {
1976         if (code == PRTOOMANY)
1977             *lastP = head;
1978         else
1979             ABORT_WITH(tt, code);
1980     }
1981
1982     code = ubik_EndTrans(tt);
1983     return code;
1984 }
1985
1986 afs_int32
1987 SPR_IsAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid,
1988                 afs_int32 *flag)
1989 {
1990     afs_int32 code;
1991     afs_int32 cid = ANONYMOUSID;
1992
1993     code = isAMemberOf(call, uid, gid, flag, &cid);
1994     osi_auditU(call, PTS_IsMemOfEvent, code, AUD_LONG, uid, AUD_LONG, gid,
1995                AUD_END);
1996     ViceLog(125, ("PTS_IsAMemberOf: code %d cid %d uid %d gid %d\n", code, cid, uid, gid));
1997     return code;
1998 }
1999
2000 static afs_int32
2001 isAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid, afs_int32 *flag,
2002             afs_int32 *cid)
2003 {
2004     afs_int32 code;
2005     struct ubik_trans *tt;
2006
2007     code = Initdb();
2008     if (code != PRSUCCESS)
2009         return code;
2010     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2011     if (code)
2012         return code;
2013     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2014     if (code)
2015         ABORT_WITH(tt, code);
2016     code = read_DbHeader(tt);
2017     if (code)
2018         ABORT_WITH(tt, code);
2019
2020     {
2021         afs_int32 uloc = FindByID(tt, uid);
2022         afs_int32 gloc = FindByID(tt, gid);
2023         struct prentry uentry, gentry;
2024
2025         if (!uloc || !gloc)
2026             ABORT_WITH(tt, PRNOENT);
2027         code = WhoIsThis(call, tt, cid);
2028         if (code)
2029             ABORT_WITH(tt, PRPERM);
2030         code = pr_ReadEntry(tt, 0, uloc, &uentry);
2031         if (code)
2032             ABORT_WITH(tt, code);
2033         code = pr_ReadEntry(tt, 0, gloc, &gentry);
2034         if (code)
2035             ABORT_WITH(tt, code);
2036 #if !defined(SUPERGROUPS)
2037         if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP))
2038             ABORT_WITH(tt, PRBADARG);
2039 #else
2040         if (!(gentry.flags & PRGRP))
2041             ABORT_WITH(tt, PRBADARG);
2042 #endif
2043         if (!AccessOK(tt, *cid, &uentry, 0, PRP_MEMBER_ANY)
2044             && !AccessOK(tt, *cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
2045             ABORT_WITH(tt, PRPERM);
2046     }
2047
2048     *flag = IsAMemberOf(tt, uid, gid);
2049     code = ubik_EndTrans(tt);
2050     return code;
2051 }
2052
2053 static afs_int32
2054 addWildCards(struct ubik_trans *tt, prlist *alist, afs_uint32 host)
2055 {
2056     afs_int32 temp;
2057     struct prentry tentry;
2058     prlist wlist;
2059     unsigned wild = htonl(0xffffff00);
2060     struct in_addr iaddr;
2061     afs_int32 hostid;
2062     int size = 0, i, code;
2063     int added = 0;
2064
2065     while ((host = (host & wild))) {
2066         wild = htonl(ntohl(wild) << 8);
2067         iaddr.s_addr = host;
2068         code = NameToID(tt, inet_ntoa(iaddr), &hostid);
2069         if (code == PRSUCCESS && hostid != 0) {
2070             temp = FindByID(tt, hostid);
2071             if (temp) {
2072                 code = pr_ReadEntry(tt, 0, temp, &tentry);
2073                 if (code != PRSUCCESS)
2074                     continue;
2075             } else
2076                 continue;
2077         } else
2078             continue;
2079         wlist.prlist_len = 0;
2080         wlist.prlist_val = NULL;
2081
2082         code = GetList(tt, &tentry, &wlist, 0);
2083         if (code)
2084             return code;
2085         added += wlist.prlist_len;
2086         for (i = 0; i < wlist.prlist_len; i++) {
2087             if (!inCPS(*alist, wlist.prlist_val[i]))
2088                 if ((code = AddToPRList(alist, &size, wlist.prlist_val[i]))) {
2089                     free(wlist.prlist_val);
2090                     return (code);
2091                 }
2092         }
2093         if (wlist.prlist_val)
2094             free(wlist.prlist_val);
2095     }
2096     if (added)
2097         qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
2098     return 0;
2099 }
2100
2101 static afs_int32
2102 WhoIsThisWithName(struct rx_call *acall, struct ubik_trans *at, afs_int32 *aid,
2103                   char *aname)
2104 {
2105     int foreign = 0;
2106     /* aid is set to the identity of the caller, if known, else ANONYMOUSID */
2107     /* returns -1 and sets aid to ANONYMOUSID on any failure */
2108     struct rx_connection *tconn;
2109     afs_int32 code;
2110     char tcell[MAXKTCREALMLEN];
2111     char name[MAXKTCNAMELEN];
2112     char inst[MAXKTCNAMELEN];
2113     int ilen;
2114     char vname[256];
2115
2116     *aid = ANONYMOUSID;
2117     tconn = rx_ConnectionOf(acall);
2118     code = rx_SecurityClassOf(tconn);
2119     if (code == 0)
2120         return 0;
2121     else if (code == 1) {       /* vab class */
2122         goto done;              /* no longer supported */
2123     } else if (code == 2) {     /* kad class */
2124         if ((code = rxkad_GetServerInfo(acall->conn, NULL, NULL,
2125                                         name, inst, tcell, NULL)))
2126             goto done;
2127
2128         if (tcell[0])
2129             foreign = afs_is_foreign_ticket_name(name, inst, tcell,
2130                                                  pr_realmName);
2131
2132         strncpy(vname, name, sizeof(vname));
2133         if ((ilen = strlen(inst))) {
2134             if (strlen(vname) + 1 + ilen >= sizeof(vname))
2135                 goto done;
2136             strcat(vname, ".");
2137             strcat(vname, inst);
2138         }
2139         if (foreign) {
2140              if (strlen(vname) + strlen(tcell) + 1  >= sizeof(vname))
2141                 goto done;
2142              strcat(vname, "@");
2143              strcat(vname, tcell);
2144              lcstring(vname, vname, sizeof(vname));
2145              code = NameToID(at, vname, aid);
2146              if (aname)
2147                 strcpy(aname, vname);
2148              return 2;
2149         }
2150
2151         if (strcmp(AUTH_SUPERUSER, vname) == 0)
2152             *aid = SYSADMINID;  /* special case for the fileserver */
2153         else {
2154             lcstring(vname, vname, sizeof(vname));
2155             code = NameToID(at, vname, aid);
2156         }
2157     }
2158   done:
2159     if (code && !pr_noAuth)
2160         return -1;
2161     return 0;
2162 }