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