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