Fix some of the fallout from having rxgen-fabricated prototypes.
[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, (afs_int32 *) 0, 0/*was &exp*/,
118              name, inst, tcell, (afs_int32 *) 0)))
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, aentry, PRP_STATUS_MEM, PRP_STATUS_ANY))
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 = (afs_int32 *)0;
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) size = 0;
528     aname->namelist_val = (prname *)malloc(size*PR_MAXNAMELEN);
529     aname->namelist_len = 0;
530     if (aname->namelist_val == 0) return PRNOMEM;
531     if (aid->idlist_len == 0) return 0;
532     if (size == 0) return PRTOOMANY;    /* rxgen will probably handle this */
533
534     code = Initdb();
535     if (code != PRSUCCESS) return code;
536     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
537     if (code) return code;
538     code = ubik_SetLock(tt,1,1,LOCKREAD);
539     if (code) ABORT_WITH(tt,code);
540     code = read_DbHeader(tt);
541     if (code) ABORT_WITH(tt,code);
542
543     for (i=0;i<aid->idlist_len;i++) {
544         code = IDToName(tt,aid->idlist_val[i],aname->namelist_val[i]);
545         if (code != PRSUCCESS)
546             sprintf(aname->namelist_val[i],"%d",aid->idlist_val[i]);
547         if (count++ > 50) IOMGR_Poll(), count = 0;
548     }
549     aname->namelist_len = aid->idlist_len;
550
551     code = ubik_EndTrans(tt);
552     if (code) return code;
553     return PRSUCCESS;
554 }
555
556 afs_int32 SPR_Delete (call, aid)
557   struct rx_call *call;
558   afs_int32 aid;
559 {
560   afs_int32 code;
561
562   code = Delete (call, aid);
563   osi_auditU (call, PTS_DelEvent, code, AUD_LONG, aid, AUD_END);
564   return code;
565 }
566
567 afs_int32 Delete (call, aid)
568   struct rx_call *call;
569   afs_int32 aid;
570 {
571     register afs_int32 code;
572     struct ubik_trans *tt;
573     afs_int32 cid;
574     struct prentry tentry;
575     afs_int32 loc, nptr;
576     int count;
577
578     code = Initdb();
579     if (code) return code;
580     if (code != PRSUCCESS) return code;
581     if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID ||
582         aid == ANONYMOUSID) return PRPERM;
583     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
584     if (code) return code;
585     code = ubik_SetLock(tt,1,1,LOCKWRITE);
586     if (code) ABORT_WITH(tt,code);
587     code = read_DbHeader(tt);
588     if (code) ABORT_WITH(tt,code);
589
590     code = WhoIsThis(call,tt,&cid);
591     if (code) ABORT_WITH(tt,PRPERM);
592
593     /* Read in entry to be deleted */
594     loc = FindByID (tt, aid);
595     if (loc == 0) ABORT_WITH(tt,PRNOENT);
596     code = pr_ReadEntry (tt, 0, loc, &tentry);
597     if (code) ABORT_WITH(tt,PRDBFAIL);
598
599     /* Do some access checking */
600     if (tentry.owner != cid &&
601         !IsAMemberOf (tt, cid, SYSADMINID) &&
602         !IsAMemberOf (tt, cid, tentry.owner) && !pr_noAuth)
603         ABORT_WITH(tt,PRPERM);
604
605     /* Delete each continuation block as a separate transaction so that no one
606      * transaction become to large to complete. */
607     nptr = tentry.next;
608     while (nptr != (afs_int32)NULL) {
609         struct contentry centry;
610         int i;
611
612         code = pr_ReadCoEntry(tt, 0, nptr, &centry);
613         if (code != 0) ABORT_WITH(tt,PRDBFAIL);
614         for (i=0;i<COSIZE;i++) {
615             if (centry.entries[i] == PRBADID) continue;
616             if (centry.entries[i] == 0) break;
617             code = RemoveFromEntry (tt, aid, centry.entries[i]);
618             if (code) ABORT_WITH(tt,code);
619             tentry.count--;             /* maintain count */
620             if ((i&3) == 0) IOMGR_Poll();
621         }
622         tentry.next = centry.next;      /* thread out this block */
623         code = FreeBlock (tt, nptr);    /* free continuation block */
624         if (code) ABORT_WITH(tt,code);
625         code = pr_WriteEntry (tt, 0, loc, &tentry); /* update main entry */
626         if (code) ABORT_WITH(tt,code);
627
628         /* end this trans and start a new one */
629         code = ubik_EndTrans(tt);
630         if (code) return code;
631         IOMGR_Poll();                   /* just to keep the connection alive */
632         code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
633         if (code) return code;
634         code = ubik_SetLock(tt,1,1,LOCKWRITE);
635         if (code) ABORT_WITH(tt,code);
636
637         /* re-read entry to get consistent uptodate info */
638         loc = FindByID (tt, aid);
639         if (loc == 0) ABORT_WITH(tt,PRNOENT);
640         code = pr_ReadEntry (tt, 0, loc, &tentry);
641         if (code) ABORT_WITH(tt,PRDBFAIL);
642
643         nptr = tentry.next;
644     }
645
646     /* Then move the owned chain, except possibly ourself to the orphan list.
647      * Because this list can be very long and so exceed the size of a ubik
648      * transaction, we start a new transaction every 50 entries. */
649     count = 0;
650     nptr = tentry.owned;
651     while (nptr != (afs_int32)NULL) {
652         struct prentry nentry;
653
654         code = pr_ReadEntry (tt, 0, nptr, &nentry);
655         if (code) ABORT_WITH(tt,PRDBFAIL);
656         nptr = tentry.owned = nentry.nextOwned; /* thread out */
657         
658         if (nentry.id != tentry.id) {   /* don't add us to orphan chain! */
659             code = AddToOrphan (tt, nentry.id);
660             if (code) ABORT_WITH(tt,code);
661             count++;
662             if ((count & 3) == 0) IOMGR_Poll();
663         }
664         if (count < 50) continue;
665         code = pr_WriteEntry (tt, 0, loc, &tentry); /* update main entry */
666         if (code) ABORT_WITH(tt,code);
667
668         /* end this trans and start a new one */
669         code = ubik_EndTrans(tt);
670         if (code) return code;
671         IOMGR_Poll();                   /* just to keep the connection alive */
672         code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
673         if (code) return code;
674         code = ubik_SetLock(tt,1,1,LOCKWRITE);
675         if (code) ABORT_WITH(tt,code);
676
677         /* re-read entry to get consistent uptodate info */
678         loc = FindByID (tt, aid);
679         if (loc == 0) ABORT_WITH(tt,PRNOENT);
680         code = pr_ReadEntry (tt, 0, loc, &tentry);
681         if (code) ABORT_WITH(tt,PRDBFAIL);
682
683         nptr = tentry.owned;
684     }
685
686     /* now do what's left of the deletion stuff */
687     code = DeleteEntry (tt, &tentry, loc);
688     if (code != PRSUCCESS) ABORT_WITH(tt,code);
689
690     code = ubik_EndTrans(tt);
691     if (code) return code;
692     return PRSUCCESS;
693 }
694
695 afs_int32 SPR_UpdateEntry (call, aid, name, uentry)
696   struct rx_call *call;
697   afs_int32 aid;
698   char *name;
699   struct PrUpdateEntry *uentry;
700 {
701     register afs_int32 code;
702     struct ubik_trans *tt;
703     afs_int32 cid;
704     struct prentry tentry;
705     afs_int32 loc, nptr;
706     int count, id=0;
707
708     code = Initdb();
709     if (code) return code;
710     if (code != PRSUCCESS) return code;
711     if (aid) {
712         id = aid;
713         if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID ||
714             aid == ANONYMOUSID) return PRPERM;
715     }
716     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
717     if (code) return code;
718     code = ubik_SetLock(tt,1,1,LOCKWRITE);
719     if (code) ABORT_WITH(tt,code);
720     code = read_DbHeader(tt);
721     if (code) ABORT_WITH(tt,code);
722
723     code = WhoIsThis(call,tt,&cid);
724     if (code) ABORT_WITH(tt,PRPERM);
725     code = IsAMemberOf (tt, cid, SYSADMINID);
726     if (!code && !pr_noAuth) ABORT_WITH(tt,PRPERM);
727
728     /* Read in entry to be deleted */
729     if (id) {
730         loc = FindByID (tt, aid);
731     } else {
732         loc = FindByName(tt, name, &tentry);
733     }
734     if (loc == 0) ABORT_WITH(tt,PRNOENT);
735     code = pr_ReadEntry (tt, 0, loc, &tentry);
736     if (code) ABORT_WITH(tt,PRDBFAIL);
737
738     if (uentry->Mask & PRUPDATE_NAMEHASH) {
739         int tloc;
740         code = RemoveFromNameHash(tt, tentry.name, &tloc);
741         if (code != PRSUCCESS) ABORT_WITH(tt,PRDBFAIL);
742         code = AddToNameHash(tt, tentry.name, loc);
743         if (code) ABORT_WITH(tt,code);
744     }
745
746     if (uentry->Mask & PRUPDATE_IDHASH) {
747         int tloc;
748         if (!id) id = tentry.id;
749         code = RemoveFromIDHash(tt, id, &tloc);
750         if (code != PRSUCCESS) ABORT_WITH(tt,PRDBFAIL);
751         code = AddToIDHash(tt, id, loc);
752         if (code) ABORT_WITH(tt,code);
753     }
754
755     code = ubik_EndTrans(tt);
756     if (code) return code;
757     return PRSUCCESS;
758 }
759
760 afs_int32 SPR_RemoveFromGroup (call,aid,gid)
761 struct rx_call *call;
762 afs_int32 aid;
763 afs_int32 gid;
764 {
765   afs_int32 code;
766
767   code = removeFromGroup (call,aid,gid);
768   osi_auditU (call, PTS_RmFmGrpEvent, code, AUD_LONG, gid, AUD_LONG, aid, AUD_END);
769   return code;
770 }
771
772 afs_int32 removeFromGroup (call,aid,gid)
773 struct rx_call *call;
774 afs_int32 aid;
775 afs_int32 gid;
776 {
777     register afs_int32 code;
778     struct ubik_trans *tt;
779     afs_int32 tempu;
780     afs_int32 tempg;
781     struct prentry uentry;
782     struct prentry gentry;
783     afs_int32 cid;
784
785     code = Initdb();
786     if (code != PRSUCCESS) return code;
787     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
788     if (code) return code;
789     code = ubik_SetLock(tt,1,1,LOCKWRITE);
790     if (code) ABORT_WITH(tt,code);
791     code = read_DbHeader(tt);
792     if (code) ABORT_WITH(tt,code);
793
794     code = WhoIsThis(call,tt,&cid);
795     if (code) ABORT_WITH(tt,PRPERM);
796     tempu = FindByID(tt,aid);
797     if (!tempu) ABORT_WITH(tt,PRNOENT);
798     tempg = FindByID(tt,gid);
799     if (!tempg) ABORT_WITH(tt,PRNOENT);
800     memset(&uentry, 0, sizeof(uentry));
801     memset(&gentry, 0, sizeof(gentry));
802     code = pr_ReadEntry(tt,0,tempu,&uentry);
803     if (code != 0) ABORT_WITH(tt,code);
804     code = pr_ReadEntry(tt,0,tempg,&gentry);
805     if (code != 0) ABORT_WITH(tt,code);
806     if (!(gentry.flags & PRGRP)) ABORT_WITH(tt,PRNOTGROUP);
807     if (uentry.flags & PRGRP) ABORT_WITH(tt,PRNOTUSER);
808     if (!AccessOK (tt, cid, &gentry, PRP_REMOVE_MEM, 0)) ABORT_WITH(tt,PRPERM);
809     code = RemoveFromEntry(tt,aid,gid);
810     if (code != PRSUCCESS) ABORT_WITH(tt,code);
811     code = RemoveFromEntry(tt,gid,aid);
812     if (code != PRSUCCESS) ABORT_WITH(tt,code);
813
814     code = ubik_EndTrans(tt);
815     if (code) return code;
816     return PRSUCCESS;
817 }
818
819
820 afs_int32 SPR_GetCPS (call, aid, alist, over)
821   struct rx_call *call;
822   afs_int32 aid;
823   prlist *alist;
824   afs_int32 *over;
825 {
826   afs_int32 code;
827
828   code = getCPS (call, aid, alist, over);
829   osi_auditU (call, PTS_GetCPSEvent, code, AUD_LONG, aid, AUD_END);
830   return code;
831 }
832
833 afs_int32 getCPS (call, aid, alist, over)
834   struct rx_call *call;
835   afs_int32 aid;
836   prlist *alist;
837   afs_int32 *over;
838 {
839     register afs_int32 code;
840     struct ubik_trans *tt;
841     afs_int32 temp;
842     afs_int32 cid;
843     struct prentry tentry;
844
845     *over = 0;
846     alist->prlist_len = 0;
847     alist->prlist_val = (afs_int32 *) 0;
848     code = Initdb();
849     if (code != PRSUCCESS) return code;
850     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
851     if (code) return code;
852     code = ubik_SetLock(tt,1,1,LOCKREAD);
853     if (code) ABORT_WITH(tt,code);
854     code = read_DbHeader(tt);
855     if (code) ABORT_WITH(tt,code);
856
857     temp = FindByID (tt, aid);
858     if (!temp) ABORT_WITH(tt,PRNOENT);
859     code = pr_ReadEntry (tt, 0, temp, &tentry);
860     if (code) ABORT_WITH(tt,code);
861
862     /* afs does authenticate now */
863     code = WhoIsThis (call, tt, &cid);
864     if (code || !AccessOK (tt, cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
865         ABORT_WITH(tt,PRPERM);
866         
867     code = GetList(tt, &tentry, alist, 1);
868     if (code != PRSUCCESS) ABORT_WITH(tt,code);
869
870     code = ubik_EndTrans(tt);
871     return code;
872 }
873
874
875 #ifdef IP_WILDCARDS
876 int inCPS (CPS,id)
877     prlist CPS;
878     afs_int32 id;
879 {
880     int i;
881  
882     for (i = (CPS.prlist_len-1) ; i >= 0; i--) {
883         if (CPS.prlist_val[i] == id) 
884             return(1);
885     }
886     return(0);
887 }
888 #endif /* IP_WILDCARDS */
889
890
891 afs_int32 SPR_GetCPS2 (call, aid, ahost, alist, over)
892   struct rx_call *call;
893   afs_int32 aid;
894   afs_int32 ahost;
895   prlist *alist;
896   afs_int32 *over;
897 {
898   afs_int32 code;
899
900   code = getCPS2 (call, aid, ahost, alist, over);
901   osi_auditU (call, PTS_GetCPS2Event, code, AUD_LONG, aid, AUD_HOST, ahost, AUD_END);
902   return code;
903 }
904
905 afs_int32 getCPS2 (call, aid, ahost, alist, over)
906   struct rx_call *call;
907   afs_int32 aid;
908   afs_int32 ahost;
909   prlist *alist;
910   afs_int32 *over;
911 {
912     register afs_int32 code;
913     struct ubik_trans *tt;
914     afs_int32 temp;
915     afs_int32 cid;
916     struct prentry tentry;
917     struct prentry host_tentry;
918     afs_int32 hostid;
919     int host_list = 0;
920     struct in_addr iaddr;
921 #if IP_WILDCARDS
922     extern afs_int32 addWildCards(); 
923 #endif /* IP_WILDCARDS */
924
925     *over = 0;
926     iaddr.s_addr = ntohl(ahost);
927     alist->prlist_len = 0;
928     alist->prlist_val = (afs_int32 *) 0;
929     code = Initdb();
930     if (code != PRSUCCESS) return code;
931     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
932     if (code) return code;
933     code = ubik_SetLock(tt,1,1,LOCKREAD);
934     if (code) ABORT_WITH(tt,code);
935     code = read_DbHeader(tt);
936     if (code) ABORT_WITH(tt,code);
937
938     if (aid != PRBADID) {
939         temp = FindByID(tt,aid);
940         if (!temp) ABORT_WITH(tt,PRNOENT);
941         code = pr_ReadEntry (tt, 0, temp, &tentry);
942         if (code) ABORT_WITH(tt,code);
943
944         /* afs does authenticate now */
945         code = WhoIsThis (call, tt, &cid);
946         if (code || !AccessOK (tt, cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
947             ABORT_WITH(tt,PRPERM);
948     }
949     code = NameToID(tt, inet_ntoa(iaddr),&hostid);
950     if (code == PRSUCCESS && hostid != 0) {
951             temp = FindByID(tt,hostid);
952             if (temp){
953                code = pr_ReadEntry (tt, 0, temp, &host_tentry);
954                if (code == PRSUCCESS)
955                   host_list = 1;
956                else
957                  fprintf(stderr,"pr_ReadEntry returned %d\n",code);
958             } else
959                 fprintf(stderr,"FindByID Failed -- Not found\n");
960     } 
961     if (host_list)
962         code = GetList2(tt, &tentry, &host_tentry, alist, 1);
963     else
964         code = GetList(tt, &tentry, alist, 1);
965 #if IP_WILDCARDS
966     if (!code)
967         code = addWildCards(tt,alist,ntohl(ahost));
968 #endif /* IP_WILDCARDS */
969     if (code != PRSUCCESS) ABORT_WITH(tt,code);
970
971     code = ubik_EndTrans(tt);
972     return code;
973 }
974
975
976 afs_int32 SPR_GetHostCPS (call, ahost, alist, over)
977   struct rx_call *call;
978   afs_int32 ahost;
979   prlist *alist;
980   afs_int32 *over;
981 {
982   afs_int32 code;
983
984   code = getHostCPS (call, ahost, alist, over);
985   osi_auditU (call, PTS_GetHCPSEvent, code, AUD_HOST, ahost, AUD_END);
986   return code;
987 }
988
989 afs_int32 getHostCPS (call, ahost, alist, over)
990   struct rx_call *call;
991   afs_int32 ahost;
992   prlist *alist;
993   afs_int32 *over;
994 {
995     register afs_int32 code, temp;
996     struct ubik_trans *tt;
997     struct prentry host_tentry;
998     afs_int32 hostid;
999     struct in_addr iaddr;
1000 #if IP_WILDCARDS
1001     extern afs_int32 addWildCards(); 
1002 #endif /* IP_WILDCARDS */
1003
1004     *over = 0;
1005     iaddr.s_addr = ntohl(ahost);
1006     alist->prlist_len = 0;
1007     alist->prlist_val = (afs_int32 *) 0;
1008     code = Initdb();
1009     if (code != PRSUCCESS) return code;
1010     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1011     if (code) return code;
1012     code = ubik_SetLock(tt,1,1,LOCKREAD);
1013     if (code) ABORT_WITH(tt,code);
1014     code = read_DbHeader(tt);
1015     if (code) ABORT_WITH(tt,code);
1016
1017     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1018     if (code == PRSUCCESS && hostid != 0) {
1019         temp = FindByID(tt,hostid);
1020         if (temp) {
1021             code = pr_ReadEntry (tt, 0, temp, &host_tentry);
1022             if (code == PRSUCCESS) {
1023                 code = GetList(tt, &host_tentry, alist, 0);
1024                 if (code) goto bad;
1025             } else 
1026                 fprintf(stderr,"pr_ReadEntry returned %d\n",code);
1027         } else 
1028             fprintf(stderr,"FindByID Failed -- Not found\n");
1029     } 
1030 #if IP_WILDCARDS
1031     code = addWildCards(tt,alist,ntohl(ahost));
1032 #endif /* IP_WILDCARDS */
1033 bad:
1034     if (code != PRSUCCESS) ABORT_WITH(tt,code);
1035
1036     code = ubik_EndTrans(tt);
1037     return code;
1038 }
1039
1040
1041 afs_int32 SPR_ListMax (call,uid,gid)
1042 struct rx_call *call;
1043 afs_int32 *uid;
1044 afs_int32 *gid;
1045 {
1046   afs_int32 code;
1047
1048   code = listMax(call,uid,gid);
1049   osi_auditU (call, PTS_LstMaxEvent, code, AUD_END);
1050   return code;
1051 }
1052
1053 afs_int32 listMax (call,uid,gid)
1054 struct rx_call *call;
1055 afs_int32 *uid;
1056 afs_int32 *gid;
1057 {
1058     register afs_int32 code;
1059     struct ubik_trans *tt;
1060
1061     code = Initdb();
1062     if (code != PRSUCCESS) return code;
1063     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1064     if (code) return code;
1065     code = ubik_SetLock(tt,1,1,LOCKREAD);
1066     if (code) ABORT_WITH(tt,code);
1067     code = read_DbHeader(tt);
1068     if (code) ABORT_WITH(tt,code);
1069
1070     code = GetMax(tt,uid,gid);
1071     if (code != PRSUCCESS) ABORT_WITH(tt,code);
1072
1073     code = ubik_EndTrans(tt);
1074     if (code) return code;
1075     return PRSUCCESS;
1076 }
1077
1078 afs_int32 SPR_SetMax (call,aid,gflag)
1079 struct rx_call *call;
1080 afs_int32 aid;
1081 afs_int32 gflag;
1082 {
1083   afs_int32 code;
1084
1085   code = setMax (call,aid,gflag);
1086   osi_auditU (call, PTS_SetMaxEvent, code, AUD_LONG, aid, AUD_LONG, gflag, AUD_END);
1087   return code;
1088 }
1089
1090 afs_int32 setMax (call,aid,gflag)
1091 struct rx_call *call;
1092 afs_int32 aid;
1093 afs_int32 gflag;
1094 {
1095     register afs_int32 code;
1096     struct ubik_trans *tt;
1097     afs_int32 cid;
1098
1099     code = Initdb();
1100     if (code != PRSUCCESS) return code;
1101     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
1102     if (code) return code;
1103     code = ubik_SetLock(tt,1,1,LOCKWRITE);
1104     if (code) ABORT_WITH(tt,code);
1105     code = read_DbHeader(tt);
1106     if (code) ABORT_WITH(tt,code);
1107
1108     code = WhoIsThis(call,tt,&cid);
1109     if (code) ABORT_WITH(tt,PRPERM);
1110     if (!AccessOK (tt, cid, 0, 0, 0)) ABORT_WITH(tt,PRPERM);
1111     if (((gflag & PRGRP) && (aid > 0)) || (!(gflag & PRGRP) && (aid < 0))) ABORT_WITH(tt,PRBADARG);
1112
1113     code = SetMax(tt,aid,gflag);
1114     if (code != PRSUCCESS) ABORT_WITH(tt,code);
1115
1116     code = ubik_EndTrans(tt);
1117     if (code) return code;
1118     return PRSUCCESS;
1119 }
1120
1121 afs_int32 SPR_ListEntry (call,aid,aentry)
1122 struct rx_call *call;
1123 afs_int32 aid;
1124 struct prcheckentry *aentry;
1125 {
1126   afs_int32 code;
1127
1128   code = listEntry (call,aid,aentry);
1129   osi_auditU (call, PTS_LstEntEvent, code, AUD_LONG, aid, AUD_END);
1130   return code;
1131 }
1132
1133 afs_int32 listEntry (call,aid,aentry)
1134 struct rx_call *call;
1135 afs_int32 aid;
1136 struct prcheckentry *aentry;
1137 {
1138     register afs_int32 code;
1139     struct ubik_trans *tt;
1140     afs_int32 cid;
1141     afs_int32 temp;
1142     struct prentry tentry;
1143
1144     code = Initdb();
1145     if (code != PRSUCCESS) return code;
1146     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1147     if (code) return code;
1148     code = ubik_SetLock(tt,1,1,LOCKREAD);
1149     if (code) ABORT_WITH(tt,code);
1150     code = read_DbHeader(tt);
1151     if (code) ABORT_WITH(tt,code);
1152
1153     code = WhoIsThis(call,tt,&cid);
1154     if (code) ABORT_WITH(tt,PRPERM);
1155     temp = FindByID(tt,aid);
1156     if (!temp) ABORT_WITH(tt,PRNOENT);
1157     code = pr_ReadEntry(tt, 0, temp, &tentry);
1158     if (code != 0) ABORT_WITH(tt,code);
1159     if (!AccessOK (tt, cid, &tentry, PRP_STATUS_MEM, PRP_STATUS_ANY))
1160         ABORT_WITH(tt,PRPERM);
1161
1162     aentry->flags = tentry.flags >> PRIVATE_SHIFT;
1163     if (aentry->flags == 0) {
1164         if (tentry.flags & PRGRP)
1165             aentry->flags = PRP_GROUP_DEFAULT >> PRIVATE_SHIFT;
1166         else aentry->flags = PRP_USER_DEFAULT >> PRIVATE_SHIFT;
1167     }
1168     aentry->owner = tentry.owner;
1169     aentry->id = tentry.id;
1170     strncpy(aentry->name,tentry.name,PR_MAXNAMELEN);
1171     aentry->creator = tentry.creator;
1172     aentry->ngroups = tentry.ngroups;
1173     aentry->nusers = tentry.nusers;
1174     aentry->count = tentry.count;
1175     memset(aentry->reserved, 0, sizeof(aentry->reserved));
1176     code = ubik_EndTrans(tt);
1177     if (code) return code;
1178     return PRSUCCESS;
1179 }
1180
1181 afs_int32 SPR_ListEntries(call, flag, startindex, bulkentries, nextstartindex)
1182   struct rx_call *call;
1183   afs_int32          flag;
1184   afs_int32          startindex;
1185   prentries      *bulkentries;
1186   afs_int32          *nextstartindex;
1187 {
1188   afs_int32 code;
1189
1190   code = listEntries(call, flag, startindex, bulkentries, nextstartindex);
1191   osi_auditU (call, PTS_LstEntsEvent, code, AUD_LONG, flag, AUD_END);
1192   return code;
1193 }
1194
1195 afs_int32 listEntries(call, flag, startindex, bulkentries, nextstartindex)
1196   struct rx_call *call;
1197   afs_int32          flag;
1198   afs_int32          startindex;
1199   prentries      *bulkentries;
1200   afs_int32          *nextstartindex;
1201 {
1202   afs_int32 code;
1203   struct ubik_trans *tt;
1204   afs_int32 cid;
1205   afs_int32 i, eof, pos, maxentries, f;
1206   struct prentry tentry;
1207   afs_int32 pollcount=0;
1208
1209   *nextstartindex = -1;
1210   bulkentries->prentries_val = 0;
1211   bulkentries->prentries_len = 0;
1212
1213   code = Initdb();
1214   if (code != PRSUCCESS) return code;
1215   code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1216   if (code) return code;
1217   code = ubik_SetLock(tt,1,1,LOCKREAD);
1218   if (code) ABORT_WITH(tt,code);
1219   code = read_DbHeader(tt);
1220   if (code) ABORT_WITH(tt,code);
1221
1222   /* Make sure we are an authenticated caller and that we are on the
1223    * SYSADMIN list.
1224    */
1225   code = WhoIsThis(call,tt,&cid);
1226   if (code) ABORT_WITH(tt,PRPERM);
1227   code = IsAMemberOf (tt, cid, SYSADMINID);
1228   if (!code && !pr_noAuth) ABORT_WITH(tt,PRPERM);
1229
1230   eof = ntohl(cheader.eofPtr) - sizeof(cheader);
1231   maxentries = eof / sizeof(struct prentry);
1232   for (i=startindex; i<maxentries; i++) {
1233      pos = i * sizeof(struct prentry) + sizeof(cheader);
1234      code = pr_ReadEntry (tt, 0, pos, &tentry);
1235      if (code) goto done;
1236
1237      if (++pollcount > 50) {
1238         IOMGR_Poll();
1239         pollcount = 0;
1240      }
1241
1242      f = (tentry.flags & PRTYPE);
1243      if ( ((flag & PRUSERS ) && (f == 0)   ) ||    /* User  entry */
1244           ((flag & PRGROUPS) && (f & PRGRP)) ) {   /* Group entry */
1245         code = put_prentries(&tentry, bulkentries);
1246         if (code == -1) break;   /* Filled return array */
1247         if (code) goto done;
1248      }
1249   }
1250   code = 0;
1251   if (i < maxentries)
1252      *nextstartindex = i;
1253
1254  done:
1255   if (code) {
1256      if (bulkentries->prentries_val)
1257         free(bulkentries->prentries_val);
1258      bulkentries->prentries_val = 0;
1259      bulkentries->prentries_len = 0;
1260      ABORT_WITH(tt, code);
1261   }
1262   else {
1263      code = ubik_EndTrans(tt);
1264   }
1265   if (code) return code;
1266   return PRSUCCESS;
1267 }
1268
1269 #define PR_MAXENTRIES 500
1270 afs_int32 put_prentries(tentry, bulkentries)
1271   struct prentry *tentry;
1272   prentries      *bulkentries;
1273 {
1274   struct prlistentries *entry;
1275
1276   if (bulkentries->prentries_val == 0) {
1277      bulkentries->prentries_len = 0;
1278      bulkentries->prentries_val = (struct prlistentries *)malloc(PR_MAXENTRIES * sizeof(struct prentry));
1279      if (!bulkentries->prentries_val) {
1280         return(PRNOMEM);
1281      }
1282   }
1283
1284   if (bulkentries->prentries_len >= PR_MAXENTRIES) {
1285      return(-1);
1286   }
1287
1288   entry  = (struct prlistentries *)bulkentries->prentries_val;
1289   entry += bulkentries->prentries_len;
1290
1291   entry->flags   = tentry->flags >> PRIVATE_SHIFT;
1292   if (entry->flags == 0) {
1293      entry->flags = ( (tentry->flags & PRGRP)?PRP_GROUP_DEFAULT
1294                                              :PRP_USER_DEFAULT ) >> PRIVATE_SHIFT;
1295   }
1296   entry->owner   = tentry->owner;
1297   entry->id      = tentry->id;
1298   entry->creator = tentry->creator;
1299   entry->ngroups = tentry->ngroups;
1300   entry->nusers  = tentry->nusers;
1301   entry->count   = tentry->count;
1302   strncpy(entry->name,tentry->name,PR_MAXNAMELEN);
1303   memset(entry->reserved, 0, sizeof(entry->reserved));
1304   bulkentries->prentries_len++;
1305   return 0;
1306 }
1307
1308 afs_int32 SPR_ChangeEntry (call,aid,name,oid,newid)
1309 struct rx_call *call;
1310 afs_int32 aid;
1311 char *name;
1312 afs_int32 oid;
1313 afs_int32 newid;
1314 {
1315   afs_int32 code;
1316
1317   code = changeEntry (call,aid,name,oid,newid);
1318   osi_auditU (call, PTS_ChgEntEvent, code, AUD_LONG, aid, AUD_STR,  name, 
1319                                                           AUD_LONG, oid, 
1320                                                           AUD_LONG, newid, AUD_END);
1321   return code;
1322 }
1323
1324 afs_int32 changeEntry (call,aid,name,oid,newid)
1325 struct rx_call *call;
1326 afs_int32 aid;
1327 char *name;
1328 afs_int32 oid;
1329 afs_int32 newid;
1330 {
1331     register afs_int32 code;
1332     struct ubik_trans *tt;
1333     afs_int32 pos;
1334     afs_int32 cid;
1335
1336     if (!name) return PRPERM;
1337     stolower(name);
1338
1339     code = Initdb();
1340     if (code) return code;
1341     if (aid == ANYUSERID || aid == AUTHUSERID || aid == ANONYMOUSID ||
1342         aid == SYSADMINID) return PRPERM;
1343     if (code != PRSUCCESS) return code;
1344     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
1345     if (code) return code;
1346     code = ubik_SetLock(tt,1,1,LOCKWRITE);
1347     if (code) ABORT_WITH(tt,code);
1348     code = read_DbHeader(tt);
1349     if (code) ABORT_WITH(tt,code);
1350
1351     code = WhoIsThis(call,tt,&cid);
1352     if (code) ABORT_WITH(tt,PRPERM);
1353     pos = FindByID(tt,aid);
1354     if (!pos) ABORT_WITH(tt,PRNOENT);
1355     /* protection check in changeentry */
1356     code = ChangeEntry(tt,aid,cid,name,oid,newid);
1357     if (code != PRSUCCESS) ABORT_WITH(tt,code);
1358
1359     code = ubik_EndTrans(tt);
1360     return code;
1361 }
1362
1363 afs_int32 SPR_SetFieldsEntry (call, id, mask, flags, ngroups, nusers, spare1, spare2)
1364   struct rx_call *call;
1365   afs_int32 id;
1366   afs_int32 mask;                               /* specify which fields to update */
1367   afs_int32 flags, ngroups, nusers;
1368   afs_int32 spare1, spare2;
1369 {
1370   afs_int32 code;
1371
1372   code = setFieldsEntry (call, id, mask, flags, ngroups, nusers, spare1, spare2);
1373   osi_auditU (call, PTS_SetFldEntEvent, code, AUD_LONG, id, AUD_END);
1374   return code;
1375 }
1376
1377 afs_int32 setFieldsEntry (call, id, mask, flags, ngroups, nusers, spare1, spare2)
1378   struct rx_call *call;
1379   afs_int32 id;
1380   afs_int32 mask;                               /* specify which fields to update */
1381   afs_int32 flags, ngroups, nusers;
1382   afs_int32 spare1, spare2;
1383 {
1384     register afs_int32 code;
1385     struct ubik_trans *tt;
1386     afs_int32 pos;
1387     afs_int32 cid;
1388     struct prentry tentry;
1389     afs_int32 tflags;
1390
1391     if (mask == 0) return 0;            /* no-op */
1392     code = Initdb();
1393     if (code) return code;
1394     if (id == ANYUSERID || id == AUTHUSERID || id == ANONYMOUSID)
1395         return PRPERM;
1396     if (code != PRSUCCESS) return code;
1397     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
1398     if (code) return code;
1399     code = ubik_SetLock(tt,1,1,LOCKWRITE);
1400     if (code) ABORT_WITH(tt,code);
1401     code = read_DbHeader(tt);
1402     if (code) ABORT_WITH(tt,code);
1403
1404     code = WhoIsThis(call,tt,&cid);
1405     if (code) ABORT_WITH(tt,PRPERM);
1406     pos = FindByID(tt,id);
1407     if (!pos) ABORT_WITH(tt,PRNOENT);
1408     code = pr_ReadEntry (tt, 0, pos, &tentry);
1409     if (code) ABORT_WITH(tt,code);
1410     tflags = tentry.flags;
1411
1412     if (mask & (PR_SF_NGROUPS | PR_SF_NUSERS)) {
1413         if (!AccessOK (tt, cid, 0, 0, 0)) ABORT_WITH(tt,PRPERM);
1414         if ((tflags & PRQUOTA) == 0) {  /* default if only setting one */
1415             tentry.ngroups = tentry.nusers = 20;
1416         }
1417     } else {
1418         if (!AccessOK (tt, cid, &tentry, 0, 0)) ABORT_WITH(tt,PRPERM);
1419     }
1420
1421     if (mask & 0xffff) {                /* if setting flag bits */
1422         afs_int32 flagsMask = mask & 0xffff;
1423         tflags &= ~(flagsMask << PRIVATE_SHIFT);
1424         tflags |= (flags & flagsMask) << PRIVATE_SHIFT;
1425         tflags |= PRACCESS;
1426     }
1427
1428     if (mask & PR_SF_NGROUPS) {         /* setting group limit */
1429         if (ngroups < 0) ABORT_WITH(tt,PRBADARG);
1430         tentry.ngroups = ngroups;
1431         tflags |= PRQUOTA;
1432     }
1433
1434     if (mask & PR_SF_NUSERS) {          /* setting foreign user limit */
1435         if (nusers < 0) ABORT_WITH(tt,PRBADARG);
1436         tentry.nusers = nusers;
1437         tflags |= PRQUOTA;
1438     }
1439     tentry.flags = tflags;
1440
1441     code = pr_WriteEntry (tt, 0, pos, &tentry);
1442     if (code) ABORT_WITH(tt,code);
1443
1444     code = ubik_EndTrans(tt);
1445     return code;
1446 }
1447
1448 afs_int32 SPR_ListElements (call, aid, alist, over)
1449   struct rx_call *call;
1450   afs_int32 aid;
1451   prlist *alist;
1452   afs_int32 *over;
1453 {
1454   afs_int32 code;
1455
1456   code = listElements (call, aid, alist, over);
1457   osi_auditU (call, PTS_LstEleEvent, code, AUD_LONG, aid, AUD_END);
1458   return code;
1459 }
1460
1461 afs_int32 listElements (call, aid, alist, over)
1462   struct rx_call *call;
1463   afs_int32 aid;
1464   prlist *alist;
1465   afs_int32 *over;
1466 {
1467     register afs_int32 code;
1468     struct ubik_trans *tt;
1469     afs_int32 cid;
1470     afs_int32 temp;
1471     struct prentry tentry;
1472
1473     *over = 0;
1474     alist->prlist_len = 0;
1475     alist->prlist_val = (afs_int32 *) 0;
1476
1477     code = Initdb();
1478     if (code != PRSUCCESS) return code;
1479     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1480     if (code) return code;
1481     code = ubik_SetLock(tt,1,1,LOCKREAD);
1482     if (code) ABORT_WITH(tt,code);
1483     code = read_DbHeader(tt);
1484     if (code) ABORT_WITH(tt,code);
1485
1486     code = WhoIsThis(call,tt,&cid);
1487     if (code) ABORT_WITH(tt,PRPERM);
1488
1489     temp = FindByID(tt,aid);
1490     if (!temp) ABORT_WITH(tt,PRNOENT);
1491     code = pr_ReadEntry (tt, 0, temp, &tentry);
1492     if (code) ABORT_WITH(tt,code);
1493     if (!AccessOK (tt, cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1494         ABORT_WITH(tt,PRPERM);
1495         
1496     code = GetList (tt, &tentry, alist, 0);
1497     if (code != PRSUCCESS) ABORT_WITH(tt,code);
1498
1499     code = ubik_EndTrans(tt);
1500     return code;
1501 }
1502
1503 /* 
1504  * SPR_ListOwned
1505  * List the entries owned by this id.  If the id is zero,
1506  * return the orphans list. This will return up to PR_MAXGROUPS
1507  * at a time with the lastP available to get the rest. The
1508  * maximum value is enforced in GetOwnedChain().
1509  */
1510 afs_int32 SPR_ListOwned (call, aid, alist, lastP)
1511   struct rx_call *call;
1512   afs_int32 aid;
1513   prlist *alist;
1514   afs_int32 *lastP;
1515 {
1516   afs_int32 code;
1517
1518   code = listOwned (call, aid, alist, lastP);
1519   osi_auditU (call, PTS_LstOwnEvent, code, AUD_LONG, aid, AUD_END);
1520   return code;
1521 }
1522
1523 afs_int32 listOwned (call, aid, alist, lastP)
1524   struct rx_call *call;
1525   afs_int32 aid;
1526   prlist *alist;
1527   afs_int32 *lastP;
1528 {
1529     register afs_int32 code;
1530     struct ubik_trans *tt;
1531     afs_int32 cid;
1532     struct prentry tentry;
1533     afs_int32 head=0;
1534     afs_int32 start;
1535
1536     alist->prlist_len = 0;
1537     alist->prlist_val = (afs_int32 *) 0;
1538
1539     if (!lastP) return PRBADARG;
1540     start = *lastP;
1541     *lastP = 0;
1542
1543     code = Initdb();
1544     if (code != PRSUCCESS) return code;
1545     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1546     if (code) return code;
1547     code = ubik_SetLock(tt,1,1,LOCKREAD);
1548     if (code) ABORT_WITH(tt,code);
1549     code = read_DbHeader(tt);
1550     if (code) ABORT_WITH(tt,code);
1551
1552     code = WhoIsThis(call,tt,&cid);
1553     if (code) ABORT_WITH(tt,PRPERM);
1554
1555     if (start) {
1556        code = pr_ReadEntry (tt, 0, start, &tentry);
1557        if (!code && (tentry.owner == aid))
1558           head = start;                      /* pick up where we left off */
1559     }
1560
1561     if (!head) {
1562        if (aid) {
1563           afs_int32 loc = FindByID (tt, aid);
1564           if (loc == 0) ABORT_WITH(tt,PRNOENT);
1565           code = pr_ReadEntry (tt, 0, loc, &tentry);
1566           if (code) ABORT_WITH(tt,code);
1567
1568           if (!AccessOK (tt, cid, &tentry, -1, PRP_OWNED_ANY))
1569              ABORT_WITH(tt,PRPERM);
1570           head = tentry.owned;
1571        } else {
1572           if (!AccessOK (tt, cid, 0, 0, 0)) ABORT_WITH(tt,PRPERM);
1573           head = ntohl(cheader.orphan);
1574        }
1575     }
1576
1577     code = GetOwnedChain (tt, &head, alist);
1578     if (code) {
1579        if (code == PRTOOMANY) *lastP = head;
1580        else  ABORT_WITH(tt,code);
1581     }
1582
1583     code = ubik_EndTrans(tt);
1584     return code;
1585 }
1586
1587 afs_int32 SPR_IsAMemberOf (call,uid,gid,flag)
1588 struct rx_call *call;
1589 afs_int32 uid;
1590 afs_int32 gid;
1591 afs_int32 *flag;
1592 {
1593   afs_int32 code;
1594
1595   code = isAMemberOf (call,uid,gid,flag);
1596   osi_auditU (call, PTS_IsMemOfEvent, code, AUD_LONG, uid, AUD_LONG, gid, AUD_END);
1597   return code;
1598 }
1599
1600 afs_int32 isAMemberOf (call,uid,gid,flag)
1601 struct rx_call *call;
1602 afs_int32 uid;
1603 afs_int32 gid;
1604 afs_int32 *flag;
1605 {
1606     register afs_int32 code;
1607     struct ubik_trans *tt;
1608
1609     code = Initdb();
1610     if (code != PRSUCCESS) return code;
1611     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
1612     if (code) return code;
1613     code = ubik_SetLock(tt,1,1,LOCKREAD);
1614     if (code) ABORT_WITH(tt,code);
1615     code = read_DbHeader(tt);
1616     if (code) ABORT_WITH(tt,code);
1617
1618     {   afs_int32 cid;
1619         afs_int32 uloc = FindByID (tt, uid);
1620         afs_int32 gloc = FindByID (tt, gid);
1621         struct prentry uentry, gentry;
1622
1623         if (!uloc || !gloc) ABORT_WITH(tt,PRNOENT);
1624         code = WhoIsThis(call, tt, &cid);
1625         if (code) ABORT_WITH(tt,PRPERM);
1626         code = pr_ReadEntry (tt, 0, uloc, &uentry);
1627         if (code) ABORT_WITH(tt,code);
1628         code = pr_ReadEntry (tt, 0, gloc, &gentry);
1629         if (code) ABORT_WITH(tt,code);
1630         if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP)) ABORT_WITH(tt,PRBADARG);
1631         if (!AccessOK (tt, cid, &uentry, 0, PRP_MEMBER_ANY) &&
1632             !AccessOK (tt, cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1633             ABORT_WITH(tt,PRPERM);
1634     }
1635         
1636     *flag = IsAMemberOf(tt,uid,gid);
1637     code = ubik_EndTrans(tt);
1638     return code;
1639 }
1640
1641
1642 static stolower(s)
1643 register char *s;
1644 {
1645     register int tc;
1646     while ((tc = *s)) {
1647         if (isupper(tc)) *s = tolower(tc);
1648         s++;
1649     }
1650 }
1651
1652 #if IP_WILDCARDS
1653 afs_int32 addWildCards(tt,alist,host)
1654     struct ubik_trans *tt;
1655     prlist *alist;
1656     afs_int32 host;
1657 {
1658     afs_int32 temp;
1659     struct prentry tentry;
1660     prlist wlist;
1661     unsigned wild = htonl(0xffffff00);
1662     struct in_addr iaddr;
1663     afs_int32 hostid;
1664     int size = 0, i, code;
1665     int added = 0;
1666  
1667     while ((host = (host & wild))) {
1668         wild = htonl ( ntohl(wild) << 8) ;
1669         iaddr.s_addr = host;
1670         code = NameToID(tt, inet_ntoa(iaddr),&hostid);
1671         if (code == PRSUCCESS && hostid != 0) {
1672             temp = FindByID(tt,hostid);
1673             if (temp){
1674                 code = pr_ReadEntry (tt, 0, temp, &tentry);
1675                 if (code != PRSUCCESS)
1676                     continue;
1677             } else
1678                 continue;
1679         } else
1680             continue;
1681         wlist.prlist_len = 0;
1682         wlist.prlist_val = (afs_int32 *) 0;
1683         
1684         code = GetList (tt, &tentry, &wlist, 0);
1685         if (code) return code;
1686         added +=  wlist.prlist_len;
1687         for (i=0; i< wlist.prlist_len; i++) {
1688             if (!inCPS(*alist,wlist.prlist_val[i]))
1689                 if ((code = AddToPRList (alist, &size, wlist.prlist_val[i] ))) {
1690                     free(wlist.prlist_val);
1691                     return(code);
1692                 }
1693         }
1694         if (wlist.prlist_val) free(wlist.prlist_val);
1695     } 
1696     if (added) 
1697         qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
1698     return 0;
1699 }
1700 #endif /* IP_WILDCARDS */
1701
1702
1703 afs_int32 WhoIsThisWithName(acall, at, aid, aname)
1704   struct rx_call *acall;
1705   struct ubik_trans *at;
1706   afs_int32 *aid;
1707   char *aname;
1708 {
1709     /* aid is set to the identity of the caller, if known, else ANONYMOUSID */
1710     /* returns -1 and sets aid to ANONYMOUSID on any failure */
1711     register struct rx_connection *tconn;
1712     register afs_int32 code;
1713     char tcell[MAXKTCREALMLEN];
1714     char name[MAXKTCNAMELEN];
1715     char inst[MAXKTCNAMELEN];
1716     int  ilen;
1717     char vname[256];
1718
1719     *aid = ANONYMOUSID;
1720     tconn = rx_ConnectionOf(acall);
1721     code = rx_SecurityClassOf(tconn);
1722     if (code == 0) return 0;
1723     else if (code == 1) {               /* vab class */
1724         goto done;                      /* no longer supported */
1725     }
1726     else if (code == 2) {               /* kad class */
1727
1728         int clen;
1729         extern char *pr_realmName;
1730
1731         if ((code = rxkad_GetServerInfo
1732             (acall->conn, (afs_int32 *) 0, 0/*was &exp*/,
1733              name, inst, tcell, (afs_int32 *) 0)))
1734             goto done;
1735         strncpy (vname, name, sizeof(vname));
1736         if ((ilen = strlen(inst))) {
1737             if (strlen(vname) + 1 + ilen >= sizeof(vname)) goto done;
1738             strcat (vname, ".");
1739             strcat (vname, inst);
1740         }
1741         if ( (clen = strlen(tcell))) {
1742
1743 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
1744             static char local_realm[AFS_REALM_SZ] = "";
1745             if (!local_realm[0]) {
1746                 if (afs_krb_get_lrealm(local_realm, 0) != 0/*KSUCCESS*/)
1747                     strncpy(local_realm, pr_realmName, AFS_REALM_SZ);
1748             }
1749 #endif
1750             if (
1751 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
1752                 strcasecmp (local_realm, tcell) &&
1753 #endif
1754                 strcasecmp (pr_realmName, tcell))
1755           {
1756             if (strlen(vname) + 1 + clen >= sizeof(vname)) goto done;
1757             strcat(vname,"@");
1758             strcat(vname,tcell);
1759             lcstring(vname, vname, sizeof(vname));
1760             code = NameToID(at,vname,aid); 
1761             strcpy(aname,vname);
1762             return 2;
1763           }
1764         }
1765
1766         if (strcmp (AUTH_SUPERUSER, vname) == 0)
1767             *aid = SYSADMINID;          /* special case for the fileserver */
1768         else {
1769             lcstring(vname, vname, sizeof(vname));
1770             code = NameToID(at,vname,aid);
1771         }
1772     }
1773   done:
1774     if (code && !pr_noAuth) return -1;
1775     return 0;
1776 }