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