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