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