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