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