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