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