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