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