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