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