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