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