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