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