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