audit-add-and-fix-messages-20050708
[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_ID, aid, AUD_STR, aname,
236                AUD_ID, oid, AUD_END);
237     ViceLog(25, ("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_ID, *aid, AUD_STR, aname,
316                AUD_ID, oid, AUD_END);
317     ViceLog(25, ("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_ID, aid, AUD_LONG, *apos,
388                AUD_END);
389     ViceLog(125, ("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(125, ("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_ID, gid, AUD_ID, 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(125, ("PTS_NameToID: code %d", code));
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         osi_audit(PTS_NmToIdEvent, code, AUD_STR,
648                    aname->namelist_val[i], AUD_ID, aid->idlist_val[i], 
649                    AUD_END);
650         ViceLog(125, ("PTS_NameToID: code %d aname %s aid %d", code,
651                       aname->namelist_val[i], aid->idlist_val[i]));
652         if (count++ > 50)
653             IOMGR_Poll(), count = 0;
654     }
655     aid->idlist_len = aname->namelist_len;
656
657     code = ubik_EndTrans(tt);
658     if (code)
659         return code;
660     return PRSUCCESS;
661 }
662
663 /*
664  * SPR_IDToName
665  * Given an array of ids, find the name for each of them.
666  * The array of ids and names is unlimited.
667  */
668 afs_int32
669 SPR_IDToName(call, aid, aname)
670      struct rx_call *call;
671      idlist *aid;
672      namelist *aname;
673 {
674     afs_int32 code;
675
676     code = idToName(call, aid, aname);
677     osi_auditU(call, PTS_IdToNmEvent, code, AUD_END);
678     ViceLog(125, ("PTS_IDToName: code %d", code));
679     return code;
680 }
681
682 afs_int32
683 idToName(call, aid, aname)
684      struct rx_call *call;
685      idlist *aid;
686      namelist *aname;
687 {
688     register afs_int32 code;
689     struct ubik_trans *tt;
690     afs_int32 i;
691     int size;
692     int count = 0;
693
694     /* leave this first for rpc stub */
695     size = aid->idlist_len;
696     if (size == 0)
697         return 0;
698     if (size < 0)
699         return PRTOOMANY;
700     aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN);
701     aname->namelist_len = 0;
702     if (aname->namelist_val == 0)
703         return PRNOMEM;
704     if (aid->idlist_len == 0)
705         return 0;
706     if (size == 0)
707         return PRTOOMANY;       /* rxgen will probably handle this */
708
709     code = Initdb();
710     if (code != PRSUCCESS)
711         return code;
712     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
713     if (code)
714         return code;
715     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
716     if (code)
717         ABORT_WITH(tt, code);
718     code = read_DbHeader(tt);
719     if (code)
720         ABORT_WITH(tt, code);
721
722     for (i = 0; i < aid->idlist_len; i++) {
723         code = IDToName(tt, aid->idlist_val[i], aname->namelist_val[i]);
724         if (code != PRSUCCESS)
725             sprintf(aname->namelist_val[i], "%d", aid->idlist_val[i]);
726         osi_audit(PTS_IdToNmEvent, code, AUD_ID, aid->idlist_val[i],
727                   AUD_STR, aname->namelist_val[i], AUD_END);
728         ViceLog(125, ("PTS_idToName: code %d aid %d aname %s", code,
729                       aid->idlist_val[i], aname->namelist_val[i]));
730         if (count++ > 50)
731             IOMGR_Poll(), count = 0;
732     }
733     aname->namelist_len = aid->idlist_len;
734
735     code = ubik_EndTrans(tt);
736     if (code)
737         return code;
738     return PRSUCCESS;
739 }
740
741 afs_int32
742 SPR_Delete(call, aid)
743      struct rx_call *call;
744      afs_int32 aid;
745 {
746     afs_int32 code;
747     afs_int32 cid = ANONYMOUSID;
748
749     code = Delete(call, aid, &cid);
750     osi_auditU(call, PTS_DelEvent, code, AUD_ID, aid, AUD_END);
751     ViceLog(25, ("PTS_Delete: code %d cid %d aid %d", code, cid, aid));
752     return code;
753 }
754
755 afs_int32
756 Delete(call, aid, cid)
757      struct rx_call *call;
758      afs_int32 aid;
759      afs_int32 *cid;
760 {
761     register afs_int32 code;
762     struct ubik_trans *tt;
763     struct prentry tentry;
764     afs_int32 loc, nptr;
765     int count;
766
767     code = Initdb();
768     if (code)
769         return code;
770     if (code != PRSUCCESS)
771         return code;
772     if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
773         || aid == ANONYMOUSID)
774         return PRPERM;
775     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
776     if (code)
777         return code;
778     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
779     if (code)
780         ABORT_WITH(tt, code);
781     code = read_DbHeader(tt);
782     if (code)
783         ABORT_WITH(tt, code);
784
785     code = WhoIsThis(call, tt, cid);
786     if (code)
787         ABORT_WITH(tt, PRPERM);
788
789     /* Read in entry to be deleted */
790     loc = FindByID(tt, aid);
791     if (loc == 0)
792         ABORT_WITH(tt, PRNOENT);
793     code = pr_ReadEntry(tt, 0, loc, &tentry);
794     if (code)
795         ABORT_WITH(tt, PRDBFAIL);
796
797     /* Do some access checking */
798     if (tentry.owner != *cid && !IsAMemberOf(tt, *cid, SYSADMINID)
799         && !IsAMemberOf(tt, *cid, tentry.owner) && !pr_noAuth)
800         ABORT_WITH(tt, PRPERM);
801
802     /* Delete each continuation block as a separate transaction so that no one
803      * transaction become to large to complete. */
804     nptr = tentry.next;
805     while (nptr != (afs_int32) NULL) {
806         struct contentry centry;
807         int i;
808
809         code = pr_ReadCoEntry(tt, 0, nptr, &centry);
810         if (code != 0)
811             ABORT_WITH(tt, PRDBFAIL);
812         for (i = 0; i < COSIZE; i++) {
813             if (centry.entries[i] == PRBADID)
814                 continue;
815             if (centry.entries[i] == 0)
816                 break;
817 #if defined(SUPERGROUPS)
818             if (aid < 0 && centry.entries[i] < 0)       /* Supergroup */
819                 code = RemoveFromSGEntry(tt, aid, centry.entries[i]);
820             else
821 #endif
822                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
823             if (code)
824                 ABORT_WITH(tt, code);
825             tentry.count--;     /* maintain count */
826             if ((i & 3) == 0)
827                 IOMGR_Poll();
828         }
829         tentry.next = centry.next;      /* thread out this block */
830         code = FreeBlock(tt, nptr);     /* free continuation block */
831         if (code)
832             ABORT_WITH(tt, code);
833         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
834         if (code)
835             ABORT_WITH(tt, code);
836
837         /* end this trans and start a new one */
838         code = ubik_EndTrans(tt);
839         if (code)
840             return code;
841         IOMGR_Poll();           /* just to keep the connection alive */
842         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
843         if (code)
844             return code;
845         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
846         if (code)
847             ABORT_WITH(tt, code);
848
849         /* re-read entry to get consistent uptodate info */
850         loc = FindByID(tt, aid);
851         if (loc == 0)
852             ABORT_WITH(tt, PRNOENT);
853         code = pr_ReadEntry(tt, 0, loc, &tentry);
854         if (code)
855             ABORT_WITH(tt, PRDBFAIL);
856
857         nptr = tentry.next;
858     }
859
860 #if defined(SUPERGROUPS)
861     /* Delete each continuation block as a separate transaction
862      * so that no one transaction become too large to complete. */
863     {
864         struct prentryg *tentryg = (struct prentryg *)&tentry;
865         nptr = tentryg->nextsg;
866         while (nptr != NULL) {
867             struct contentry centry;
868             int i;
869
870             code = pr_ReadCoEntry(tt, 0, nptr, &centry);
871             if (code != 0)
872                 ABORT_WITH(tt, PRDBFAIL);
873             for (i = 0; i < COSIZE; i++) {
874                 if (centry.entries[i] == PRBADID)
875                     continue;
876                 if (centry.entries[i] == 0)
877                     break;
878                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
879                 if (code)
880                     ABORT_WITH(tt, code);
881                 tentryg->countsg--;     /* maintain count */
882                 if ((i & 3) == 0)
883                     IOMGR_Poll();
884             }
885             tentryg->nextsg = centry.next;      /* thread out this block */
886             code = FreeBlock(tt, nptr); /* free continuation block */
887             if (code)
888                 ABORT_WITH(tt, code);
889             code = pr_WriteEntry(tt, 0, loc, &tentry);  /* update main entry */
890             if (code)
891                 ABORT_WITH(tt, code);
892
893             /* end this trans and start a new one */
894             code = ubik_EndTrans(tt);
895             if (code)
896                 return code;
897             IOMGR_Poll();       /* just to keep the connection alive */
898
899             code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
900             if (code)
901                 return code;
902             code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
903             if (code)
904                 ABORT_WITH(tt, code);
905
906             /* re-read entry to get consistent uptodate info */
907             loc = FindByID(tt, aid);
908             if (loc == 0)
909                 ABORT_WITH(tt, PRNOENT);
910             code = pr_ReadEntry(tt, 0, loc, &tentry);
911             if (code)
912                 ABORT_WITH(tt, PRDBFAIL);
913
914             nptr = tentryg->nextsg;
915         }
916     }
917
918 #endif /* SUPERGROUPS */
919
920     /* Then move the owned chain, except possibly ourself to the orphan list.
921      * Because this list can be very long and so exceed the size of a ubik
922      * transaction, we start a new transaction every 50 entries. */
923     count = 0;
924     nptr = tentry.owned;
925     while (nptr != (afs_int32) NULL) {
926         struct prentry nentry;
927
928         code = pr_ReadEntry(tt, 0, nptr, &nentry);
929         if (code)
930             ABORT_WITH(tt, PRDBFAIL);
931         nptr = tentry.owned = nentry.nextOwned; /* thread out */
932
933         if (nentry.id != tentry.id) {   /* don't add us to orphan chain! */
934             code = AddToOrphan(tt, nentry.id);
935             if (code)
936                 ABORT_WITH(tt, code);
937             count++;
938             if ((count & 3) == 0)
939                 IOMGR_Poll();
940         }
941         if (count < 50)
942             continue;
943         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
944         if (code)
945             ABORT_WITH(tt, code);
946
947         /* end this trans and start a new one */
948         code = ubik_EndTrans(tt);
949         if (code)
950             return code;
951         IOMGR_Poll();           /* just to keep the connection alive */
952         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
953         if (code)
954             return code;
955         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
956         if (code)
957             ABORT_WITH(tt, code);
958
959         /* re-read entry to get consistent uptodate info */
960         loc = FindByID(tt, aid);
961         if (loc == 0)
962             ABORT_WITH(tt, PRNOENT);
963         code = pr_ReadEntry(tt, 0, loc, &tentry);
964         if (code)
965             ABORT_WITH(tt, PRDBFAIL);
966
967         nptr = tentry.owned;
968     }
969
970     /* now do what's left of the deletion stuff */
971     code = DeleteEntry(tt, &tentry, loc);
972     if (code != PRSUCCESS)
973         ABORT_WITH(tt, code);
974
975     code = ubik_EndTrans(tt);
976     if (code)
977         return code;
978     return PRSUCCESS;
979 }
980
981 afs_int32
982 SPR_UpdateEntry(call, aid, name, uentry)
983      struct rx_call *call;
984      afs_int32 aid;
985      char *name;
986      struct PrUpdateEntry *uentry;
987 {
988     afs_int32 code;
989     afs_int32 cid = ANONYMOUSID;
990
991     code = UpdateEntry(call, aid, name, uentry, &cid);
992     osi_auditU(call, PTS_UpdEntEvent, code, AUD_ID, aid, AUD_STR, name, AUD_END);
993     ViceLog(5, ("PTS_UpdateEntry: code %d cid %d aid %d name %s", code, cid, aid, name));
994     return code;
995 }
996
997 afs_int32
998 UpdateEntry(call, aid, name, uentry, cid)
999      struct rx_call *call;
1000      afs_int32 aid;
1001      char *name;
1002      struct PrUpdateEntry *uentry;
1003      afs_int32 *cid;
1004 {
1005     register afs_int32 code;
1006     struct ubik_trans *tt;
1007     struct prentry tentry;
1008     afs_int32 loc;
1009     int id = 0;
1010
1011     code = Initdb();
1012     if (code)
1013         return code;
1014     if (code != PRSUCCESS)
1015         return code;
1016     if (aid) {
1017         id = aid;
1018         if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
1019             || aid == ANONYMOUSID)
1020             return PRPERM;
1021     }
1022     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1023     if (code)
1024         return code;
1025     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1026     if (code)
1027         ABORT_WITH(tt, code);
1028     code = read_DbHeader(tt);
1029     if (code)
1030         ABORT_WITH(tt, code);
1031
1032     code = WhoIsThis(call, tt, cid);
1033     if (code)
1034         ABORT_WITH(tt, PRPERM);
1035     code = IsAMemberOf(tt, *cid, SYSADMINID);
1036     if (!code && !pr_noAuth)
1037         ABORT_WITH(tt, PRPERM);
1038
1039     /* Read in entry to be deleted */
1040     if (id) {
1041         loc = FindByID(tt, aid);
1042     } else {
1043         loc = FindByName(tt, name, &tentry);
1044     }
1045     if (loc == 0)
1046         ABORT_WITH(tt, PRNOENT);
1047     code = pr_ReadEntry(tt, 0, loc, &tentry);
1048     if (code)
1049         ABORT_WITH(tt, PRDBFAIL);
1050
1051     if (uentry->Mask & PRUPDATE_NAMEHASH) {
1052         int tloc;
1053         code = RemoveFromNameHash(tt, tentry.name, &tloc);
1054         if (code != PRSUCCESS)
1055             ABORT_WITH(tt, PRDBFAIL);
1056         code = AddToNameHash(tt, tentry.name, loc);
1057         if (code)
1058             ABORT_WITH(tt, code);
1059     }
1060
1061     if (uentry->Mask & PRUPDATE_IDHASH) {
1062         int tloc;
1063         if (!id)
1064             id = tentry.id;
1065         code = RemoveFromIDHash(tt, id, &tloc);
1066         if (code != PRSUCCESS)
1067             ABORT_WITH(tt, PRDBFAIL);
1068         code = AddToIDHash(tt, id, loc);
1069         if (code)
1070             ABORT_WITH(tt, code);
1071     }
1072
1073     code = ubik_EndTrans(tt);
1074     if (code)
1075         return code;
1076     return PRSUCCESS;
1077 }
1078
1079 afs_int32
1080 SPR_RemoveFromGroup(call, aid, gid)
1081      struct rx_call *call;
1082      afs_int32 aid;
1083      afs_int32 gid;
1084 {
1085     afs_int32 code;
1086     afs_int32 cid = ANONYMOUSID;
1087
1088     code = removeFromGroup(call, aid, gid, &cid);
1089     osi_auditU(call, PTS_RmFmGrpEvent, code, AUD_ID, gid, AUD_ID, aid,
1090                AUD_END);
1091     ViceLog(5, ("PTS_RemoveFromGroup: code %d cid %d gid %d aid %d", code, cid, gid, aid));
1092     return code;
1093 }
1094
1095 afs_int32
1096 removeFromGroup(call, aid, gid, cid)
1097      struct rx_call *call;
1098      afs_int32 aid;
1099      afs_int32 gid;
1100      afs_int32 *cid;
1101 {
1102     register afs_int32 code;
1103     struct ubik_trans *tt;
1104     afs_int32 tempu;
1105     afs_int32 tempg;
1106     struct prentry uentry;
1107     struct prentry gentry;
1108
1109     code = Initdb();
1110     if (code != PRSUCCESS)
1111         return code;
1112     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1113     if (code)
1114         return code;
1115     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1116     if (code)
1117         ABORT_WITH(tt, code);
1118     code = read_DbHeader(tt);
1119     if (code)
1120         ABORT_WITH(tt, code);
1121
1122     code = WhoIsThis(call, tt, cid);
1123     if (code)
1124         ABORT_WITH(tt, PRPERM);
1125     tempu = FindByID(tt, aid);
1126     if (!tempu)
1127         ABORT_WITH(tt, PRNOENT);
1128     tempg = FindByID(tt, gid);
1129     if (!tempg)
1130         ABORT_WITH(tt, PRNOENT);
1131     memset(&uentry, 0, sizeof(uentry));
1132     memset(&gentry, 0, sizeof(gentry));
1133     code = pr_ReadEntry(tt, 0, tempu, &uentry);
1134     if (code != 0)
1135         ABORT_WITH(tt, code);
1136     code = pr_ReadEntry(tt, 0, tempg, &gentry);
1137     if (code != 0)
1138         ABORT_WITH(tt, code);
1139     if (!(gentry.flags & PRGRP))
1140         ABORT_WITH(tt, PRNOTGROUP);
1141 #if !defined(SUPERGROUPS)
1142     if (uentry.flags & PRGRP)
1143         ABORT_WITH(tt, PRNOTUSER);
1144 #endif
1145     if (!AccessOK(tt, *cid, &gentry, PRP_REMOVE_MEM, 0))
1146         ABORT_WITH(tt, PRPERM);
1147     code = RemoveFromEntry(tt, aid, gid);
1148     if (code != PRSUCCESS)
1149         ABORT_WITH(tt, code);
1150 #if defined(SUPERGROUPS)
1151     if (!(uentry.flags & PRGRP))
1152 #endif
1153         code = RemoveFromEntry(tt, gid, aid);
1154 #if defined(SUPERGROUPS)
1155     else
1156         code = RemoveFromSGEntry(tt, gid, aid);
1157 #endif
1158     if (code != PRSUCCESS)
1159         ABORT_WITH(tt, code);
1160
1161     code = ubik_EndTrans(tt);
1162     if (code)
1163         return code;
1164     return PRSUCCESS;
1165 }
1166
1167
1168 afs_int32
1169 SPR_GetCPS(call, aid, alist, over)
1170      struct rx_call *call;
1171      afs_int32 aid;
1172      prlist *alist;
1173      afs_int32 *over;
1174 {
1175     afs_int32 code;
1176     afs_int32 cid = ANONYMOUSID;
1177
1178     code = getCPS(call, aid, alist, over, &cid);
1179     osi_auditU(call, PTS_GetCPSEvent, code, AUD_ID, aid, AUD_END);
1180     ViceLog(125, ("PTS_GetCPS: code %d cid %d aid %d", code, cid, aid));
1181     return code;
1182 }
1183
1184 afs_int32
1185 getCPS(call, aid, alist, over, cid)
1186      struct rx_call *call;
1187      afs_int32 aid;
1188      prlist *alist;
1189      afs_int32 *over;
1190      afs_int32 *cid;
1191 {
1192     register afs_int32 code;
1193     struct ubik_trans *tt;
1194     afs_int32 temp;
1195     struct prentry tentry;
1196
1197     *over = 0;
1198     alist->prlist_len = 0;
1199     alist->prlist_val = NULL;
1200     code = Initdb();
1201     if (code != PRSUCCESS)
1202         return code;
1203     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1204     if (code)
1205         return code;
1206     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1207     if (code)
1208         ABORT_WITH(tt, code);
1209     code = read_DbHeader(tt);
1210     if (code)
1211         ABORT_WITH(tt, code);
1212
1213     temp = FindByID(tt, aid);
1214     if (!temp)
1215         ABORT_WITH(tt, PRNOENT);
1216     code = pr_ReadEntry(tt, 0, temp, &tentry);
1217     if (code)
1218         ABORT_WITH(tt, code);
1219
1220     /* afs does authenticate now */
1221     code = WhoIsThis(call, tt, cid);
1222     if (code || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1223         ABORT_WITH(tt, PRPERM);
1224
1225     code = GetList(tt, &tentry, alist, 1);
1226     if (code != PRSUCCESS)
1227         ABORT_WITH(tt, code);
1228
1229     code = ubik_EndTrans(tt);
1230     return code;
1231 }
1232
1233
1234 #ifdef IP_WILDCARDS
1235 int
1236 inCPS(CPS, id)
1237      prlist CPS;
1238      afs_int32 id;
1239 {
1240     int i;
1241
1242     for (i = (CPS.prlist_len - 1); i >= 0; i--) {
1243         if (CPS.prlist_val[i] == id)
1244             return (1);
1245     }
1246     return (0);
1247 }
1248 #endif /* IP_WILDCARDS */
1249
1250
1251 afs_int32
1252 SPR_GetCPS2(call, aid, ahost, alist, over)
1253      struct rx_call *call;
1254      afs_int32 aid;
1255      afs_int32 ahost;
1256      prlist *alist;
1257      afs_int32 *over;
1258 {
1259     afs_int32 code;
1260     afs_int32 cid = ANONYMOUSID;
1261
1262     code = getCPS2(call, aid, ahost, alist, over, &cid);
1263     osi_auditU(call, PTS_GetCPS2Event, code, AUD_ID, aid, AUD_HOST, ahost,
1264                AUD_END);
1265     ViceLog(125, ("PTS_GetCPS2: code %d cid %d aid %d ahost %d", code, cid, aid, ahost));
1266     return code;
1267 }
1268
1269 afs_int32
1270 getCPS2(call, aid, ahost, alist, over, cid)
1271      struct rx_call *call;
1272      afs_int32 aid;
1273      afs_int32 ahost;
1274      prlist *alist;
1275      afs_int32 *over;
1276      afs_int32 *cid;
1277 {
1278     register afs_int32 code;
1279     struct ubik_trans *tt;
1280     afs_int32 temp;
1281     struct prentry tentry;
1282     struct prentry host_tentry;
1283     afs_int32 hostid;
1284     int host_list = 0;
1285     struct in_addr iaddr;
1286 #if IP_WILDCARDS
1287     extern afs_int32 addWildCards();
1288 #endif /* IP_WILDCARDS */
1289
1290     *over = 0;
1291     iaddr.s_addr = ntohl(ahost);
1292     alist->prlist_len = 0;
1293     alist->prlist_val = NULL;
1294     code = Initdb();
1295     if (code != PRSUCCESS)
1296         return code;
1297     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1298     if (code)
1299         return code;
1300     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1301     if (code)
1302         ABORT_WITH(tt, code);
1303     code = read_DbHeader(tt);
1304     if (code)
1305         ABORT_WITH(tt, code);
1306
1307     if (aid != PRBADID) {
1308         temp = FindByID(tt, aid);
1309         if (!temp)
1310             ABORT_WITH(tt, PRNOENT);
1311         code = pr_ReadEntry(tt, 0, temp, &tentry);
1312         if (code)
1313             ABORT_WITH(tt, code);
1314
1315         /* afs does authenticate now */
1316         code = WhoIsThis(call, tt, cid);
1317         if (code
1318             || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1319             ABORT_WITH(tt, PRPERM);
1320     }
1321     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1322     if (code == PRSUCCESS && hostid != 0) {
1323         temp = FindByID(tt, hostid);
1324         if (temp) {
1325             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1326             if (code == PRSUCCESS)
1327                 host_list = 1;
1328             else
1329                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1330         } else
1331             fprintf(stderr, "FindByID Failed -- Not found\n");
1332     }
1333     if (host_list)
1334         code = GetList2(tt, &tentry, &host_tentry, alist, 1);
1335     else
1336         code = GetList(tt, &tentry, alist, 1);
1337 #if IP_WILDCARDS
1338     if (!code)
1339         code = addWildCards(tt, alist, ntohl(ahost));
1340 #endif /* IP_WILDCARDS */
1341     if (code != PRSUCCESS)
1342         ABORT_WITH(tt, code);
1343
1344     code = ubik_EndTrans(tt);
1345     return code;
1346 }
1347
1348
1349 afs_int32
1350 SPR_GetHostCPS(call, ahost, alist, over)
1351      struct rx_call *call;
1352      afs_int32 ahost;
1353      prlist *alist;
1354      afs_int32 *over;
1355 {
1356     afs_int32 code;
1357
1358     code = getHostCPS(call, ahost, alist, over);
1359     osi_auditU(call, PTS_GetHCPSEvent, code, AUD_HOST, ahost, AUD_END);
1360     ViceLog(125, ("PTS_GetHostCPS: code %d ahost %d", code, ahost));
1361     return code;
1362 }
1363
1364 afs_int32
1365 getHostCPS(call, ahost, alist, over)
1366      struct rx_call *call;
1367      afs_int32 ahost;
1368      prlist *alist;
1369      afs_int32 *over;
1370 {
1371     register afs_int32 code, temp;
1372     struct ubik_trans *tt;
1373     struct prentry host_tentry;
1374     afs_int32 hostid;
1375     struct in_addr iaddr;
1376 #if IP_WILDCARDS
1377     extern afs_int32 addWildCards();
1378 #endif /* IP_WILDCARDS */
1379
1380     *over = 0;
1381     iaddr.s_addr = ntohl(ahost);
1382     alist->prlist_len = 0;
1383     alist->prlist_val = NULL;
1384     code = Initdb();
1385     if (code != PRSUCCESS)
1386         return code;
1387     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1388     if (code)
1389         return code;
1390     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1391     if (code)
1392         ABORT_WITH(tt, code);
1393     code = read_DbHeader(tt);
1394     if (code)
1395         ABORT_WITH(tt, code);
1396
1397     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1398     if (code == PRSUCCESS && hostid != 0) {
1399         temp = FindByID(tt, hostid);
1400         if (temp) {
1401             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1402             if (code == PRSUCCESS) {
1403                 code = GetList(tt, &host_tentry, alist, 0);
1404                 if (code)
1405                     goto bad;
1406             } else
1407                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1408         } else
1409             fprintf(stderr, "FindByID Failed -- Not found\n");
1410     }
1411 #if IP_WILDCARDS
1412     code = addWildCards(tt, alist, ntohl(ahost));
1413 #endif /* IP_WILDCARDS */
1414   bad:
1415     if (code != PRSUCCESS)
1416         ABORT_WITH(tt, code);
1417
1418     code = ubik_EndTrans(tt);
1419     return code;
1420 }
1421
1422
1423 afs_int32
1424 SPR_ListMax(call, uid, gid)
1425      struct rx_call *call;
1426      afs_int32 *uid;
1427      afs_int32 *gid;
1428 {
1429     afs_int32 code;
1430
1431     code = listMax(call, uid, gid);
1432     osi_auditU(call, PTS_LstMaxEvent, code, AUD_END);
1433     ViceLog(125, ("PTS_ListMax: code %d", code));
1434     return code;
1435 }
1436
1437 afs_int32
1438 listMax(call, uid, gid)
1439      struct rx_call *call;
1440      afs_int32 *uid;
1441      afs_int32 *gid;
1442 {
1443     register afs_int32 code;
1444     struct ubik_trans *tt;
1445
1446     code = Initdb();
1447     if (code != PRSUCCESS)
1448         return code;
1449     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1450     if (code)
1451         return code;
1452     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1453     if (code)
1454         ABORT_WITH(tt, code);
1455     code = read_DbHeader(tt);
1456     if (code)
1457         ABORT_WITH(tt, code);
1458
1459     code = GetMax(tt, uid, gid);
1460     if (code != PRSUCCESS)
1461         ABORT_WITH(tt, code);
1462
1463     code = ubik_EndTrans(tt);
1464     if (code)
1465         return code;
1466     return PRSUCCESS;
1467 }
1468
1469 afs_int32
1470 SPR_SetMax(call, aid, gflag)
1471      struct rx_call *call;
1472      afs_int32 aid;
1473      afs_int32 gflag;
1474 {
1475     afs_int32 code;
1476     afs_int32 cid = ANONYMOUSID;
1477
1478     code = setMax(call, aid, gflag, &cid);
1479     osi_auditU(call, PTS_SetMaxEvent, code, AUD_ID, aid, AUD_LONG, gflag,
1480                AUD_END);
1481     ViceLog(125, ("PTS_SetMax: code %d cid %d aid %d gflag %d", code, cid, aid, gflag));
1482     return code;
1483 }
1484
1485 afs_int32
1486 setMax(call, aid, gflag, cid)
1487      struct rx_call *call;
1488      afs_int32 aid;
1489      afs_int32 gflag;
1490      afs_int32 *cid;
1491 {
1492     register afs_int32 code;
1493     struct ubik_trans *tt;
1494
1495     code = Initdb();
1496     if (code != PRSUCCESS)
1497         return code;
1498     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1499     if (code)
1500         return code;
1501     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1502     if (code)
1503         ABORT_WITH(tt, code);
1504     code = read_DbHeader(tt);
1505     if (code)
1506         ABORT_WITH(tt, code);
1507
1508     code = WhoIsThis(call, tt, cid);
1509     if (code)
1510         ABORT_WITH(tt, PRPERM);
1511     if (!AccessOK(tt, *cid, 0, 0, 0))
1512         ABORT_WITH(tt, PRPERM);
1513     if (((gflag & PRGRP) && (aid > 0)) || (!(gflag & PRGRP) && (aid < 0)))
1514         ABORT_WITH(tt, PRBADARG);
1515
1516     code = SetMax(tt, aid, gflag);
1517     if (code != PRSUCCESS)
1518         ABORT_WITH(tt, code);
1519
1520     code = ubik_EndTrans(tt);
1521     if (code)
1522         return code;
1523     return PRSUCCESS;
1524 }
1525
1526 afs_int32
1527 SPR_ListEntry(call, aid, aentry)
1528      struct rx_call *call;
1529      afs_int32 aid;
1530      struct prcheckentry *aentry;
1531 {
1532     afs_int32 code;
1533     afs_int32 cid = ANONYMOUSID;
1534
1535     code = listEntry(call, aid, aentry, &cid);
1536     osi_auditU(call, PTS_LstEntEvent, code, AUD_ID, aid, AUD_END);
1537     ViceLog(125, ("PTS_ListEntry: code %d cid %d aid %d", code, cid, aid));
1538     return code;
1539 }
1540
1541 afs_int32
1542 listEntry(call, aid, aentry, cid)
1543      struct rx_call *call;
1544      afs_int32 aid;
1545      struct prcheckentry *aentry;
1546      afs_int32 *cid;
1547 {
1548     register afs_int32 code;
1549     struct ubik_trans *tt;
1550     afs_int32 temp;
1551     struct prentry tentry;
1552
1553     code = Initdb();
1554     if (code != PRSUCCESS)
1555         return code;
1556     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1557     if (code)
1558         return code;
1559     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1560     if (code)
1561         ABORT_WITH(tt, code);
1562     code = read_DbHeader(tt);
1563     if (code)
1564         ABORT_WITH(tt, code);
1565
1566     code = WhoIsThis(call, tt, cid);
1567     if (code)
1568         ABORT_WITH(tt, PRPERM);
1569     temp = FindByID(tt, aid);
1570     if (!temp)
1571         ABORT_WITH(tt, PRNOENT);
1572     code = pr_ReadEntry(tt, 0, temp, &tentry);
1573     if (code != 0)
1574         ABORT_WITH(tt, code);
1575     if (!AccessOK(tt, *cid, &tentry, PRP_STATUS_MEM, PRP_STATUS_ANY))
1576         ABORT_WITH(tt, PRPERM);
1577
1578     aentry->flags = tentry.flags >> PRIVATE_SHIFT;
1579     if (aentry->flags == 0) {
1580         if (tentry.flags & PRGRP)
1581             aentry->flags = prp_group_default >> PRIVATE_SHIFT;
1582         else
1583             aentry->flags = prp_user_default >> PRIVATE_SHIFT;
1584     }
1585     aentry->owner = tentry.owner;
1586     aentry->id = tentry.id;
1587     strncpy(aentry->name, tentry.name, PR_MAXNAMELEN);
1588     aentry->creator = tentry.creator;
1589     aentry->ngroups = tentry.ngroups;
1590     aentry->nusers = tentry.nusers;
1591     aentry->count = tentry.count;
1592     memset(aentry->reserved, 0, sizeof(aentry->reserved));
1593     code = ubik_EndTrans(tt);
1594     if (code)
1595         return code;
1596     return PRSUCCESS;
1597 }
1598
1599 afs_int32
1600 SPR_ListEntries(call, flag, startindex, bulkentries, nextstartindex)
1601      struct rx_call *call;
1602      afs_int32 flag;
1603      afs_int32 startindex;
1604      prentries *bulkentries;
1605      afs_int32 *nextstartindex;
1606 {
1607     afs_int32 code;
1608     afs_int32 cid = ANONYMOUSID;
1609
1610     code = listEntries(call, flag, startindex, bulkentries, nextstartindex, &cid);
1611     osi_auditU(call, PTS_LstEntsEvent, code, AUD_LONG, flag, AUD_END);
1612     ViceLog(125, ("PTS_ListEntries: code %d cid %d flag %d", code, cid, flag));
1613     return code;
1614 }
1615
1616 afs_int32
1617 listEntries(call, flag, startindex, bulkentries, nextstartindex, cid)
1618      struct rx_call *call;
1619      afs_int32 flag;
1620      afs_int32 startindex;
1621      prentries *bulkentries;
1622      afs_int32 *nextstartindex;
1623      afs_int32 *cid;
1624 {
1625     afs_int32 code;
1626     struct ubik_trans *tt;
1627     afs_int32 i, eof, pos, maxentries, f;
1628     struct prentry tentry;
1629     afs_int32 pollcount = 0;
1630
1631     *nextstartindex = -1;
1632     bulkentries->prentries_val = 0;
1633     bulkentries->prentries_len = 0;
1634
1635     code = Initdb();
1636     if (code != PRSUCCESS)
1637         return code;
1638     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1639     if (code)
1640         return code;
1641     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1642     if (code)
1643         ABORT_WITH(tt, code);
1644     code = read_DbHeader(tt);
1645     if (code)
1646         ABORT_WITH(tt, code);
1647
1648     /* Make sure we are an authenticated caller and that we are on the
1649      * SYSADMIN list.
1650      */
1651     code = WhoIsThis(call, tt, cid);
1652     if (code)
1653         ABORT_WITH(tt, PRPERM);
1654     code = IsAMemberOf(tt, *cid, SYSADMINID);
1655     if (!code && !pr_noAuth)
1656         ABORT_WITH(tt, PRPERM);
1657
1658     eof = ntohl(cheader.eofPtr) - sizeof(cheader);
1659     maxentries = eof / sizeof(struct prentry);
1660     for (i = startindex; i < maxentries; i++) {
1661         pos = i * sizeof(struct prentry) + sizeof(cheader);
1662         code = pr_ReadEntry(tt, 0, pos, &tentry);
1663         if (code)
1664             goto done;
1665
1666         if (++pollcount > 50) {
1667             IOMGR_Poll();
1668             pollcount = 0;
1669         }
1670
1671         f = (tentry.flags & PRTYPE);
1672         if (((flag & PRUSERS) && (f == 0)) ||   /* User  entry */
1673             ((flag & PRGROUPS) && (f & PRGRP))) {       /* Group entry */
1674             code = put_prentries(&tentry, bulkentries);
1675             if (code == -1)
1676                 break;          /* Filled return array */
1677             if (code)
1678                 goto done;
1679         }
1680     }
1681     code = 0;
1682     if (i < maxentries)
1683         *nextstartindex = i;
1684
1685   done:
1686     if (code) {
1687         if (bulkentries->prentries_val)
1688             free(bulkentries->prentries_val);
1689         bulkentries->prentries_val = 0;
1690         bulkentries->prentries_len = 0;
1691         ABORT_WITH(tt, code);
1692     } else {
1693         code = ubik_EndTrans(tt);
1694     }
1695     if (code)
1696         return code;
1697     return PRSUCCESS;
1698 }
1699
1700 #define PR_MAXENTRIES 500
1701 afs_int32
1702 put_prentries(tentry, bulkentries)
1703      struct prentry *tentry;
1704      prentries *bulkentries;
1705 {
1706     struct prlistentries *entry;
1707
1708     if (bulkentries->prentries_val == 0) {
1709         bulkentries->prentries_len = 0;
1710         bulkentries->prentries_val =
1711             (struct prlistentries *)malloc(PR_MAXENTRIES *
1712                                            sizeof(struct prentry));
1713         if (!bulkentries->prentries_val) {
1714             return (PRNOMEM);
1715         }
1716     }
1717
1718     if (bulkentries->prentries_len >= PR_MAXENTRIES) {
1719         return (-1);
1720     }
1721
1722     entry = (struct prlistentries *)bulkentries->prentries_val;
1723     entry += bulkentries->prentries_len;
1724
1725     entry->flags = tentry->flags >> PRIVATE_SHIFT;
1726     if (entry->flags == 0) {
1727         entry->flags =
1728             ((tentry->
1729               flags & PRGRP) ? prp_group_default : prp_user_default) >>
1730             PRIVATE_SHIFT;
1731     }
1732     entry->owner = tentry->owner;
1733     entry->id = tentry->id;
1734     entry->creator = tentry->creator;
1735     entry->ngroups = tentry->ngroups;
1736     entry->nusers = tentry->nusers;
1737     entry->count = tentry->count;
1738     strncpy(entry->name, tentry->name, PR_MAXNAMELEN);
1739     memset(entry->reserved, 0, sizeof(entry->reserved));
1740     bulkentries->prentries_len++;
1741     return 0;
1742 }
1743
1744 afs_int32
1745 SPR_ChangeEntry(call, aid, name, oid, newid)
1746      struct rx_call *call;
1747      afs_int32 aid;
1748      char *name;
1749      afs_int32 oid;
1750      afs_int32 newid;
1751 {
1752     afs_int32 code;
1753     afs_int32 cid = ANONYMOUSID;
1754
1755     code = changeEntry(call, aid, name, oid, newid, &cid);
1756     osi_auditU(call, PTS_ChgEntEvent, code, AUD_ID, aid, AUD_STR, name,
1757                AUD_LONG, oid, AUD_LONG, newid, AUD_END);
1758     ViceLog(5, ("PTS_ChangeEntry: code %d cid %d aid %d name %s oid %d newid %d", code, cid, aid, name, oid, newid));
1759     return code;
1760 }
1761
1762 afs_int32
1763 changeEntry(call, aid, name, oid, newid, cid)
1764      struct rx_call *call;
1765      afs_int32 aid;
1766      char *name;
1767      afs_int32 oid;
1768      afs_int32 newid;
1769      afs_int32 *cid;
1770 {
1771     register afs_int32 code;
1772     struct ubik_trans *tt;
1773     afs_int32 pos;
1774
1775     if (!name)
1776         return PRPERM;
1777     stolower(name);
1778
1779     code = Initdb();
1780     if (code)
1781         return code;
1782     if (aid == ANYUSERID || aid == AUTHUSERID || aid == ANONYMOUSID
1783         || aid == SYSADMINID)
1784         return PRPERM;
1785     if (code != PRSUCCESS)
1786         return code;
1787     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1788     if (code)
1789         return code;
1790     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1791     if (code)
1792         ABORT_WITH(tt, code);
1793     code = read_DbHeader(tt);
1794     if (code)
1795         ABORT_WITH(tt, code);
1796
1797     code = WhoIsThis(call, tt, cid);
1798     if (code)
1799         ABORT_WITH(tt, PRPERM);
1800     pos = FindByID(tt, aid);
1801     if (!pos)
1802         ABORT_WITH(tt, PRNOENT);
1803     /* protection check in changeentry */
1804     code = ChangeEntry(tt, aid, *cid, name, oid, newid);
1805     if (code != PRSUCCESS)
1806         ABORT_WITH(tt, code);
1807
1808     code = ubik_EndTrans(tt);
1809     return code;
1810 }
1811
1812 afs_int32
1813 SPR_SetFieldsEntry(call, id, mask, flags, ngroups, nusers, spare1, spare2)
1814      struct rx_call *call;
1815      afs_int32 id;
1816      afs_int32 mask;            /* specify which fields to update */
1817      afs_int32 flags, ngroups, nusers;
1818      afs_int32 spare1, spare2;
1819 {
1820     afs_int32 code;
1821     afs_int32 cid = ANONYMOUSID;
1822
1823     code =
1824         setFieldsEntry(call, id, mask, flags, ngroups, nusers, spare1,
1825                        spare2, &cid);
1826     osi_auditU(call, PTS_SetFldEntEvent, code, AUD_ID, id, AUD_END);
1827     ViceLog(5, ("PTS_SetFieldsEntry: code %d cid %d id %d", code, cid, id));
1828     return code;
1829 }
1830
1831 afs_int32
1832 setFieldsEntry(call, id, mask, flags, ngroups, nusers, spare1, spare2, cid)
1833      struct rx_call *call;
1834      afs_int32 id;
1835      afs_int32 mask;            /* specify which fields to update */
1836      afs_int32 flags, ngroups, nusers;
1837      afs_int32 spare1, spare2;
1838      afs_int32 *cid;
1839 {
1840     register afs_int32 code;
1841     struct ubik_trans *tt;
1842     afs_int32 pos;
1843     struct prentry tentry;
1844     afs_int32 tflags;
1845
1846     if (mask == 0)
1847         return 0;               /* no-op */
1848     code = Initdb();
1849     if (code)
1850         return code;
1851     if (id == ANYUSERID || id == AUTHUSERID || id == ANONYMOUSID)
1852         return PRPERM;
1853     if (code != PRSUCCESS)
1854         return code;
1855     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1856     if (code)
1857         return code;
1858     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1859     if (code)
1860         ABORT_WITH(tt, code);
1861     code = read_DbHeader(tt);
1862     if (code)
1863         ABORT_WITH(tt, code);
1864
1865     code = WhoIsThis(call, tt, cid);
1866     if (code)
1867         ABORT_WITH(tt, PRPERM);
1868     pos = FindByID(tt, id);
1869     if (!pos)
1870         ABORT_WITH(tt, PRNOENT);
1871     code = pr_ReadEntry(tt, 0, pos, &tentry);
1872     if (code)
1873         ABORT_WITH(tt, code);
1874     tflags = tentry.flags;
1875
1876     if (mask & (PR_SF_NGROUPS | PR_SF_NUSERS)) {
1877         if (!AccessOK(tt, *cid, 0, 0, 0))
1878             ABORT_WITH(tt, PRPERM);
1879         if ((tflags & PRQUOTA) == 0) {  /* default if only setting one */
1880             tentry.ngroups = tentry.nusers = 20;
1881         }
1882     } else {
1883         if (!AccessOK(tt, *cid, &tentry, 0, 0))
1884             ABORT_WITH(tt, PRPERM);
1885     }
1886
1887     if (mask & 0xffff) {        /* if setting flag bits */
1888         afs_int32 flagsMask = mask & 0xffff;
1889         tflags &= ~(flagsMask << PRIVATE_SHIFT);
1890         tflags |= (flags & flagsMask) << PRIVATE_SHIFT;
1891         tflags |= PRACCESS;
1892     }
1893
1894     if (mask & PR_SF_NGROUPS) { /* setting group limit */
1895         if (ngroups < 0)
1896             ABORT_WITH(tt, PRBADARG);
1897         tentry.ngroups = ngroups;
1898         tflags |= PRQUOTA;
1899     }
1900
1901     if (mask & PR_SF_NUSERS) {  /* setting foreign user limit */
1902         if (nusers < 0)
1903             ABORT_WITH(tt, PRBADARG);
1904         tentry.nusers = nusers;
1905         tflags |= PRQUOTA;
1906     }
1907     tentry.flags = tflags;
1908
1909     code = pr_WriteEntry(tt, 0, pos, &tentry);
1910     if (code)
1911         ABORT_WITH(tt, code);
1912
1913     code = ubik_EndTrans(tt);
1914     return code;
1915 }
1916
1917 afs_int32
1918 SPR_ListElements(call, aid, alist, over)
1919      struct rx_call *call;
1920      afs_int32 aid;
1921      prlist *alist;
1922      afs_int32 *over;
1923 {
1924     afs_int32 code;
1925     afs_int32 cid = ANONYMOUSID;
1926
1927     code = listElements(call, aid, alist, over, &cid);
1928     osi_auditU(call, PTS_LstEleEvent, code, AUD_ID, aid, AUD_END);
1929     ViceLog(125, ("PTS_ListElements: code %d cid %d aid %d", code, cid, aid));
1930     return code;
1931 }
1932
1933 afs_int32
1934 listElements(call, aid, alist, over, cid)
1935      struct rx_call *call;
1936      afs_int32 aid;
1937      prlist *alist;
1938      afs_int32 *over;
1939      afs_int32 *cid;
1940 {
1941     register afs_int32 code;
1942     struct ubik_trans *tt;
1943     afs_int32 temp;
1944     struct prentry tentry;
1945
1946     *over = 0;
1947     alist->prlist_len = 0;
1948     alist->prlist_val = NULL;
1949
1950     code = Initdb();
1951     if (code != PRSUCCESS)
1952         return code;
1953     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1954     if (code)
1955         return code;
1956     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1957     if (code)
1958         ABORT_WITH(tt, code);
1959     code = read_DbHeader(tt);
1960     if (code)
1961         ABORT_WITH(tt, code);
1962
1963     code = WhoIsThis(call, tt, cid);
1964     if (code)
1965         ABORT_WITH(tt, PRPERM);
1966
1967     temp = FindByID(tt, aid);
1968     if (!temp)
1969         ABORT_WITH(tt, PRNOENT);
1970     code = pr_ReadEntry(tt, 0, temp, &tentry);
1971     if (code)
1972         ABORT_WITH(tt, code);
1973     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1974         ABORT_WITH(tt, PRPERM);
1975
1976     code = GetList(tt, &tentry, alist, 0);
1977     if (code != PRSUCCESS)
1978         ABORT_WITH(tt, code);
1979
1980     code = ubik_EndTrans(tt);
1981     return code;
1982 }
1983
1984
1985 afs_int32
1986 SPR_ListSuperGroups(call, aid, alist, over)
1987      struct rx_call *call;
1988      afs_int32 aid;
1989      prlist *alist;
1990      afs_int32 *over;
1991 {
1992 #if defined(SUPERGROUPS)
1993     afs_int32 code;
1994     afs_int32 cid = ANONYMOUSID;
1995
1996     code = listSuperGroups(call, aid, alist, over, &cid);
1997     osi_auditU(call, PTS_LstSGrps, code, AUD_ID, aid, AUD_END);
1998     ViceLog(125, ("PTS_ListSuperGroups: code %d cid %d aid %d", code, cid, aid));
1999     return code;
2000 #else
2001     return RXGEN_OPCODE;
2002 #endif
2003 }
2004
2005 #if defined(SUPERGROUPS)
2006 afs_int32
2007 listSuperGroups(call, aid, alist, over, cid)
2008      struct rx_call *call;
2009      afs_int32 aid;
2010      prlist *alist;
2011      afs_int32 *over;
2012      afs_int32 *cid;
2013 {
2014     register afs_int32 code;
2015     struct ubik_trans *tt;
2016     afs_int32 temp;
2017     struct prentry tentry;
2018
2019     alist->prlist_len = 0;
2020     alist->prlist_val = (afs_int32 *) 0;
2021
2022     code = Initdb();
2023     if (code != PRSUCCESS)
2024         goto done;
2025     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2026     if (code)
2027         goto done;
2028     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2029     if (code)
2030         ABORT_WITH(tt, code);
2031     code = WhoIsThis(call, tt, cid);
2032     if (code)
2033         ABORT_WITH(tt, PRPERM);
2034
2035     temp = FindByID(tt, aid);
2036     if (!temp)
2037         ABORT_WITH(tt, PRNOENT);
2038     code = pr_ReadEntry(tt, 0, temp, &tentry);
2039     if (code)
2040         ABORT_WITH(tt, code);
2041     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
2042         ABORT_WITH(tt, PRPERM);
2043
2044     code = GetSGList(tt, &tentry, alist);
2045     *over = 0;
2046     if (code == PRTOOMANY)
2047         *over = 1;
2048     else if (code != PRSUCCESS)
2049         ABORT_WITH(tt, code);
2050
2051     code = ubik_EndTrans(tt);
2052
2053   done:
2054     return code;
2055 }
2056
2057 #endif /* SUPERGROUPS */
2058
2059 /* 
2060  * SPR_ListOwned
2061  * List the entries owned by this id.  If the id is zero,
2062  * return the orphans list. This will return up to PR_MAXGROUPS
2063  * at a time with the lastP available to get the rest. The
2064  * maximum value is enforced in GetOwnedChain().
2065  */
2066 afs_int32
2067 SPR_ListOwned(call, aid, alist, lastP)
2068      struct rx_call *call;
2069      afs_int32 aid;
2070      prlist *alist;
2071      afs_int32 *lastP;
2072 {
2073     afs_int32 code;
2074     afs_int32 cid = ANONYMOUSID;
2075
2076     code = listOwned(call, aid, alist, lastP, &cid);
2077     osi_auditU(call, PTS_LstOwnEvent, code, AUD_ID, aid, AUD_END);
2078     ViceLog(125, ("PTS_ListOwned: code %d cid %d aid %d", code, cid, aid));
2079     return code;
2080 }
2081
2082 afs_int32
2083 listOwned(call, aid, alist, lastP, cid)
2084      struct rx_call *call;
2085      afs_int32 aid;
2086      prlist *alist;
2087      afs_int32 *lastP;
2088      afs_int32 *cid;
2089 {
2090     register afs_int32 code;
2091     struct ubik_trans *tt;
2092     struct prentry tentry;
2093     afs_int32 head = 0;
2094     afs_int32 start;
2095
2096     alist->prlist_len = 0;
2097     alist->prlist_val = NULL;
2098
2099     if (!lastP)
2100         return PRBADARG;
2101     start = *lastP;
2102     *lastP = 0;
2103
2104     code = Initdb();
2105     if (code != PRSUCCESS)
2106         return code;
2107     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2108     if (code)
2109         return code;
2110     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2111     if (code)
2112         ABORT_WITH(tt, code);
2113     code = read_DbHeader(tt);
2114     if (code)
2115         ABORT_WITH(tt, code);
2116
2117     code = WhoIsThis(call, tt, cid);
2118     if (code)
2119         ABORT_WITH(tt, PRPERM);
2120
2121     if (start) {
2122         code = pr_ReadEntry(tt, 0, start, &tentry);
2123         if (!code && (tentry.owner == aid))
2124             head = start;       /* pick up where we left off */
2125     }
2126
2127     if (!head) {
2128         if (aid) {
2129             afs_int32 loc = FindByID(tt, aid);
2130             if (loc == 0)
2131                 ABORT_WITH(tt, PRNOENT);
2132             code = pr_ReadEntry(tt, 0, loc, &tentry);
2133             if (code)
2134                 ABORT_WITH(tt, code);
2135
2136             if (!AccessOK(tt, *cid, &tentry, -1, PRP_OWNED_ANY))
2137                 ABORT_WITH(tt, PRPERM);
2138             head = tentry.owned;
2139         } else {
2140             if (!AccessOK(tt, *cid, 0, 0, 0))
2141                 ABORT_WITH(tt, PRPERM);
2142             head = ntohl(cheader.orphan);
2143         }
2144     }
2145
2146     code = GetOwnedChain(tt, &head, alist);
2147     if (code) {
2148         if (code == PRTOOMANY)
2149             *lastP = head;
2150         else
2151             ABORT_WITH(tt, code);
2152     }
2153
2154     code = ubik_EndTrans(tt);
2155     return code;
2156 }
2157
2158 afs_int32
2159 SPR_IsAMemberOf(call, uid, gid, flag)
2160      struct rx_call *call;
2161      afs_int32 uid;
2162      afs_int32 gid;
2163      afs_int32 *flag;
2164 {
2165     afs_int32 code;
2166     afs_int32 cid = ANONYMOUSID;
2167
2168     code = isAMemberOf(call, uid, gid, flag, &cid);
2169     osi_auditU(call, PTS_IsMemOfEvent, code, AUD_LONG, uid, AUD_LONG, gid,
2170                AUD_END);
2171     ViceLog(125, ("PTS_IsAMemberOf: code %d cid %d uid %d gid %d", code, cid, uid, gid));
2172     return code;
2173 }
2174
2175 afs_int32
2176 isAMemberOf(call, uid, gid, flag, cid)
2177      struct rx_call *call;
2178      afs_int32 uid;
2179      afs_int32 gid;
2180      afs_int32 *flag;
2181      afs_int32 *cid;
2182 {
2183     register afs_int32 code;
2184     struct ubik_trans *tt;
2185
2186     code = Initdb();
2187     if (code != PRSUCCESS)
2188         return code;
2189     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2190     if (code)
2191         return code;
2192     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2193     if (code)
2194         ABORT_WITH(tt, code);
2195     code = read_DbHeader(tt);
2196     if (code)
2197         ABORT_WITH(tt, code);
2198
2199     {
2200         afs_int32 uloc = FindByID(tt, uid);
2201         afs_int32 gloc = FindByID(tt, gid);
2202         struct prentry uentry, gentry;
2203
2204         if (!uloc || !gloc)
2205             ABORT_WITH(tt, PRNOENT);
2206         code = WhoIsThis(call, tt, cid);
2207         if (code)
2208             ABORT_WITH(tt, PRPERM);
2209         code = pr_ReadEntry(tt, 0, uloc, &uentry);
2210         if (code)
2211             ABORT_WITH(tt, code);
2212         code = pr_ReadEntry(tt, 0, gloc, &gentry);
2213         if (code)
2214             ABORT_WITH(tt, code);
2215 #if !defined(SUPERGROUPS)
2216         if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP))
2217             ABORT_WITH(tt, PRBADARG);
2218 #else
2219         if (!(gentry.flags & PRGRP))
2220             ABORT_WITH(tt, PRBADARG);
2221 #endif
2222         if (!AccessOK(tt, *cid, &uentry, 0, PRP_MEMBER_ANY)
2223             && !AccessOK(tt, *cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
2224             ABORT_WITH(tt, PRPERM);
2225     }
2226
2227     *flag = IsAMemberOf(tt, uid, gid);
2228     code = ubik_EndTrans(tt);
2229     return code;
2230 }
2231
2232
2233 static
2234 stolower(s)
2235      register char *s;
2236 {
2237     register int tc;
2238     while ((tc = *s)) {
2239         if (isupper(tc))
2240             *s = tolower(tc);
2241         s++;
2242     }
2243 }
2244
2245 #if IP_WILDCARDS
2246 afs_int32
2247 addWildCards(tt, alist, host)
2248      struct ubik_trans *tt;
2249      prlist *alist;
2250      afs_int32 host;
2251 {
2252     afs_int32 temp;
2253     struct prentry tentry;
2254     prlist wlist;
2255     unsigned wild = htonl(0xffffff00);
2256     struct in_addr iaddr;
2257     afs_int32 hostid;
2258     int size = 0, i, code;
2259     int added = 0;
2260
2261     while ((host = (host & wild))) {
2262         wild = htonl(ntohl(wild) << 8);
2263         iaddr.s_addr = host;
2264         code = NameToID(tt, inet_ntoa(iaddr), &hostid);
2265         if (code == PRSUCCESS && hostid != 0) {
2266             temp = FindByID(tt, hostid);
2267             if (temp) {
2268                 code = pr_ReadEntry(tt, 0, temp, &tentry);
2269                 if (code != PRSUCCESS)
2270                     continue;
2271             } else
2272                 continue;
2273         } else
2274             continue;
2275         wlist.prlist_len = 0;
2276         wlist.prlist_val = NULL;
2277
2278         code = GetList(tt, &tentry, &wlist, 0);
2279         if (code)
2280             return code;
2281         added += wlist.prlist_len;
2282         for (i = 0; i < wlist.prlist_len; i++) {
2283             if (!inCPS(*alist, wlist.prlist_val[i]))
2284                 if ((code = AddToPRList(alist, &size, wlist.prlist_val[i]))) {
2285                     free(wlist.prlist_val);
2286                     return (code);
2287                 }
2288         }
2289         if (wlist.prlist_val)
2290             free(wlist.prlist_val);
2291     }
2292     if (added)
2293         qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
2294     return 0;
2295 }
2296 #endif /* IP_WILDCARDS */
2297
2298
2299 afs_int32
2300 WhoIsThisWithName(acall, at, aid, aname)
2301      struct rx_call *acall;
2302      struct ubik_trans *at;
2303      afs_int32 *aid;
2304      char *aname;
2305 {
2306     /* aid is set to the identity of the caller, if known, else ANONYMOUSID */
2307     /* returns -1 and sets aid to ANONYMOUSID on any failure */
2308     register struct rx_connection *tconn;
2309     register afs_int32 code;
2310     char tcell[MAXKTCREALMLEN];
2311     char name[MAXKTCNAMELEN];
2312     char inst[MAXKTCNAMELEN];
2313     int ilen;
2314     char vname[256];
2315
2316     *aid = ANONYMOUSID;
2317     tconn = rx_ConnectionOf(acall);
2318     code = rx_SecurityClassOf(tconn);
2319     if (code == 0)
2320         return 0;
2321     else if (code == 1) {       /* vab class */
2322         goto done;              /* no longer supported */
2323     } else if (code == 2) {     /* kad class */
2324
2325         int clen;
2326         extern char *pr_realmName;
2327
2328         if ((code = rxkad_GetServerInfo(acall->conn, NULL, 0 /*was &exp */ ,
2329                                         name, inst, tcell, NULL)))
2330             goto done;
2331         strncpy(vname, name, sizeof(vname));
2332         if ((ilen = strlen(inst))) {
2333             if (strlen(vname) + 1 + ilen >= sizeof(vname))
2334                 goto done;
2335             strcat(vname, ".");
2336             strcat(vname, inst);
2337         }
2338         if ((clen = strlen(tcell))) {
2339
2340 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
2341             static char local_realm[AFS_REALM_SZ] = "";
2342             if (!local_realm[0]) {
2343                 if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
2344                     strncpy(local_realm, pr_realmName, AFS_REALM_SZ);
2345             }
2346 #endif
2347             if (
2348 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
2349                    strcasecmp(local_realm, tcell) &&
2350 #endif
2351                    strcasecmp(pr_realmName, tcell)) {
2352                 if (strlen(vname) + 1 + clen >= sizeof(vname))
2353                     goto done;
2354                 strcat(vname, "@");
2355                 strcat(vname, tcell);
2356                 lcstring(vname, vname, sizeof(vname));
2357                 code = NameToID(at, vname, aid);
2358                 strcpy(aname, vname);
2359                 return 2;
2360             }
2361         }
2362
2363         if (strcmp(AUTH_SUPERUSER, vname) == 0)
2364             *aid = SYSADMINID;  /* special case for the fileserver */
2365         else {
2366             lcstring(vname, vname, sizeof(vname));
2367             code = NameToID(at, vname, aid);
2368         }
2369     }
2370   done:
2371     if (code && !pr_noAuth)
2372         return -1;
2373     return 0;
2374 }