ptserver-procs-loglevels-20090603
[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 /*
11  *                      (3) function addToGroup
12  *
13  *                          1. Eliminate the code that tests for adding groups
14  *                             to groups. This is an error in normal AFS.
15  *                          2. If adding a group to a group call AddToSGEntry
16  *                             to add the id of the group it's a member of.
17  *                      
18  *                      (4) function Delete
19  *
20  *                          1. Print a messsage if an error is returned from
21  *                             FindByID() and PTDEBUG is defined. 
22  *                          2. If removing a group from a group call   
23  *                             RemoveFromSGEntry to remove the id of the  
24  *                             group it's a member of.            
25  *                          3. Remove supergroup continuation records.
26  *
27  *                      (5) function RemoveFromGroup 
28  *               
29  *                          1. Eliminate the code that tests for adding groups
30  *                             to groups. This is an error in normal AFS. 
31  *                          2. If removing a group from a group call 
32  *                             RemoveFromSGEntry to remove the id of the 
33  *                             group it's a member of.
34  *
35  *                      (6) Add new functions PR_ListSuperGroups and 
36  *                          listSuperGroups.
37  *                      
38  *                      (7) function isAMemberOf
39  *                      
40  *                          1. Allow groups to be members of groups.
41  *
42  *                      Transarc does not currently use opcodes past 520, but
43  *                      they *could* decide at any time to use more opcodes.
44  *                      If they did, then one part of our local mods,
45  *                      ListSupergroups, would break.  I've therefore
46  *                      renumbered it to 530, and put logic in to enable the
47  *                      old opcode to work (for now).
48  */
49
50 #include <afsconfig.h>
51 #include <afs/param.h>
52
53 RCSID
54     ("$Header$");
55
56 #include <afs/stds.h>
57 #include <ctype.h>
58 #include <stdio.h>
59 #include <lock.h>
60 #include <afs/afsutil.h>
61 #include <ubik.h>
62 #include <rx/xdr.h>
63 #include <rx/rx.h>
64 #include <rx/rxkad.h>
65 #include <afs/auth.h>
66 #ifdef AFS_NT40_ENV
67 #include <winsock2.h>
68 #else
69 #include <netinet/in.h>
70 #include <arpa/inet.h>
71 #endif
72 #include <string.h>
73 #include "ptserver.h"
74 #include "pterror.h"
75 #include "ptprototypes.h"
76 #include "afs/audit.h"
77
78 #ifdef AFS_ATHENA_STDENV
79 #include <krb.h>
80 #endif
81
82
83 #define IP_WILDCARDS    1       /* XXX Should be defined outside of here XXX */
84
85 extern int restricted;
86 extern struct ubik_dbase *dbase;
87 extern int pr_noAuth;
88 extern afs_int32 initd;
89 extern char *pr_realmName;
90 extern int prp_group_default;
91 extern int prp_user_default;
92
93 static afs_int32 iNewEntry(struct rx_call *call, char aname[], afs_int32 aid, 
94                            afs_int32 oid, afs_int32 *cid);
95 static afs_int32 newEntry(struct rx_call *call, char aname[], afs_int32 flag, 
96                           afs_int32 oid, afs_int32 *aid, afs_int32 *cid);       
97 static afs_int32 whereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos,
98                            afs_int32 *cid);
99 static afs_int32 dumpEntry(struct rx_call *call, afs_int32 apos, 
100                            struct prdebugentry *aentry, afs_int32 *cid);
101 static afs_int32 addToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid, 
102                             afs_int32 *cid);
103 static afs_int32 nameToID(struct rx_call *call, namelist *aname, idlist *aid);
104 static afs_int32 idToName(struct rx_call *call, idlist *aid, namelist *aname);
105 static afs_int32 Delete(struct rx_call *call, afs_int32 aid, afs_int32 *cid);
106 static afs_int32 UpdateEntry(struct rx_call *call, afs_int32 aid, char *name, 
107                              struct PrUpdateEntry *uentry, afs_int32 *cid);
108 static afs_int32 removeFromGroup(struct rx_call *call, afs_int32 aid, 
109                                  afs_int32 gid, afs_int32 *cid);
110 static afs_int32 getCPS(struct rx_call *call, afs_int32 aid, prlist *alist, 
111                         afs_int32 *over, afs_int32 *cid);
112 static afs_int32 getCPS2(struct rx_call *call, afs_int32 aid, afs_int32 ahost,
113                          prlist *alist, afs_int32 *over, afs_int32 *cid);
114 static afs_int32 getHostCPS(struct rx_call *call, afs_int32 ahost, 
115                             prlist *alist, afs_int32 *over);
116 static afs_int32 listMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid);
117 static afs_int32 setMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag, 
118                         afs_int32 *cid);
119 static afs_int32 listEntry(struct rx_call *call, afs_int32 aid, 
120                            struct prcheckentry *aentry, afs_int32 *cid);
121 static afs_int32 listEntries(struct rx_call *call, afs_int32 flag, 
122                              afs_int32 startindex, prentries *bulkentries, 
123                              afs_int32 *nextstartindex, afs_int32 *cid);
124 static afs_int32 put_prentries(struct prentry *tentry, prentries *bulkentries);
125 static afs_int32 changeEntry(struct rx_call *call, afs_int32 aid, char *name, 
126                              afs_int32 oid, afs_int32 newid, afs_int32 *cid);
127 static afs_int32 setFieldsEntry(struct rx_call *call, afs_int32 id, 
128                                 afs_int32 mask, afs_int32 flags, 
129                                 afs_int32 ngroups, afs_int32 nusers, 
130                                 afs_int32 spare1, afs_int32 spare2, 
131                                 afs_int32 *cid);
132 static afs_int32 listElements(struct rx_call *call, afs_int32 aid,
133                               prlist *alist, afs_int32 *over, afs_int32 *cid);
134 #if defined(SUPERGROUPS)
135 static afs_int32 listSuperGroups(struct rx_call *call, afs_int32 aid, 
136                                  prlist *alist, afs_int32 *over, 
137                                  afs_int32 *cid);
138 #endif
139 static afs_int32 listOwned(struct rx_call *call, afs_int32 aid, prlist *alist,
140                            afs_int32 *lastP, afs_int32 *cid);
141 static afs_int32 isAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid,
142                              afs_int32 *flag, afs_int32 *cid);
143 #if IP_WILDCARDS
144 static afs_int32 addWildCards(struct ubik_trans *tt, prlist *alist, 
145                               afs_int32 host);
146 #endif
147 static afs_int32 WhoIsThisWithName(struct rx_call *acall, 
148                                    struct ubik_trans *at, afs_int32 *aid, 
149                                    char *aname);
150
151 /* When abort, reset initd so that the header is read in on next call.
152  * Abort the transaction and return the code.
153  */
154 #define ABORT_WITH(tt,code) return(initd=0,ubik_AbortTrans(tt),code)
155
156 static int
157 CreateOK(struct ubik_trans *ut, afs_int32 cid, afs_int32 oid, afs_int32 flag, 
158          int admin)
159 {
160     if (restricted && !admin) 
161         return 0;
162
163     if (flag & PRFOREIGN) {
164         /* Foreign users are recognized by the '@' sign and 
165          * not by the PRFOREIGN flag.
166          */
167         return 0;
168     } else if (flag & PRGRP) {
169         /* Allow anonymous group creation only if owner specified
170          * and running noAuth.
171          */
172         if (cid == ANONYMOUSID) {
173             if ((oid == 0) || !pr_noAuth)
174                 return 0;
175         }
176     } else {                    /* creating a user */
177         if (!admin && !pr_noAuth)
178             return 0;
179     }
180     return 1;                   /* OK! */
181 }
182
183 afs_int32
184 WhoIsThis(struct rx_call *acall, struct ubik_trans *at, afs_int32 *aid)
185 {
186     int foreign = 0;
187     /* aid is set to the identity of the caller, if known, else ANONYMOUSID */
188     /* returns -1 and sets aid to ANONYMOUSID on any failure */
189     register struct rx_connection *tconn;
190     register afs_int32 code;
191     char tcell[MAXKTCREALMLEN];
192     char name[MAXKTCNAMELEN];
193     char inst[MAXKTCNAMELEN];
194     int ilen;
195     char vname[256];
196
197     *aid = ANONYMOUSID;
198     tconn = rx_ConnectionOf(acall);
199     code = rx_SecurityClassOf(tconn);
200     if (code == 0)
201         return 0;
202     else if (code == 1) {       /* vab class */
203         goto done;              /* no longer supported */
204     } else if (code == 2) {     /* kad class */
205         if ((code = rxkad_GetServerInfo(acall->conn, NULL, 0 /*was &exp */ ,
206                                         name, inst, tcell, NULL)))
207             goto done;
208 #if 0
209         /* This test is unnecessary, since rxkad_GetServerInfo already check.
210          * In addition, this is wrong since exp must be unsigned. */
211         if (exp < FT_ApproxTime())
212             goto done;
213 #endif
214         if (tcell[0])
215             foreign = afs_is_foreign_ticket_name(name,inst,tcell,pr_realmName);
216
217         strncpy(vname, name, sizeof(vname));
218         if ((ilen = strlen(inst))) {
219             if (strlen(vname) + 1 + ilen >= sizeof(vname))
220                 goto done;
221             strcat(vname, ".");
222             strcat(vname, inst);
223         }
224         if (foreign) {
225             if (strlen(vname) + strlen(tcell) + 1 >= sizeof(vname))
226                 goto done;
227             strcat(vname, "@");
228             strcat(vname, tcell);
229         }
230         if (strcmp(AUTH_SUPERUSER, vname) == 0)
231             *aid = SYSADMINID;  /* special case for the fileserver */
232         else {
233             lcstring(vname, vname, sizeof(vname));
234             code = NameToID(at, vname, aid);
235         }
236     }
237   done:
238     if (code && !pr_noAuth)
239         return -1;
240     return 0;
241 }
242
243 afs_int32
244 SPR_INewEntry(struct rx_call *call, char aname[], afs_int32 aid, afs_int32 oid)
245 {
246     afs_int32 code;
247     afs_int32 cid = ANONYMOUSID;
248
249     code = iNewEntry(call, aname, aid, oid, &cid);
250     osi_auditU(call, PTS_INewEntEvent, code, AUD_ID, aid, AUD_STR, aname,
251                AUD_ID, oid, AUD_END);
252     ViceLog(5, ("PTS_INewEntry: code %d cid %d aid %d aname %s oid %d\n", code, cid, aid, aname, oid));
253     return code;
254 }
255
256 static afs_int32
257 iNewEntry(struct rx_call *call, char aname[], afs_int32 aid, afs_int32 oid, 
258           afs_int32 *cid)
259 {
260     /* used primarily for conversion - not intended to be used as usual means
261      * of entering people into the database. */
262     struct ubik_trans *tt;
263     register afs_int32 code;
264     afs_int32 gflag = 0;
265     int admin;
266
267     stolower(aname);
268     code = Initdb();
269     if (code != PRSUCCESS)
270         return code;
271     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
272     if (code)
273         return code;
274     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
275     if (code)
276         ABORT_WITH(tt, code);
277     code = read_DbHeader(tt);
278     if (code)
279         ABORT_WITH(tt, code);
280
281     code = WhoIsThis(call, tt, cid);
282     if (code)
283         ABORT_WITH(tt, PRPERM);
284     admin = IsAMemberOf(tt, *cid, SYSADMINID);
285
286     /* first verify the id is good */
287     if (aid == 0)
288         ABORT_WITH(tt, PRPERM);
289     if (aid < 0) {
290         gflag |= PRGRP;
291         /* only sysadmin can reuse a group id */
292         if (!admin && !pr_noAuth && (aid != ntohl(cheader.maxGroup) - 1))
293             ABORT_WITH(tt, PRPERM);
294     }
295     if (FindByID(tt, aid))
296         ABORT_WITH(tt, PRIDEXIST);
297
298     /* check a few other things */
299     if (!CreateOK(tt, *cid, oid, gflag, admin))
300         ABORT_WITH(tt, PRPERM);
301
302     code = CreateEntry(tt, aname, &aid, 1, gflag, oid, *cid);
303     if (code != PRSUCCESS)
304         ABORT_WITH(tt, code);
305
306     /* finally, commit transaction */
307     code = ubik_EndTrans(tt);
308     if (code)
309         return code;
310     return PRSUCCESS;
311 }
312
313
314 afs_int32
315 SPR_NewEntry(struct rx_call *call, char aname[], afs_int32 flag, afs_int32 oid, 
316              afs_int32 *aid)
317 {
318     afs_int32 code;
319     afs_int32 cid = ANONYMOUSID;
320
321     code = newEntry(call, aname, flag, oid, aid, &cid);
322     osi_auditU(call, PTS_NewEntEvent, code, AUD_ID, *aid, AUD_STR, aname,
323                AUD_ID, oid, AUD_END);
324     ViceLog(5, ("PTS_NewEntry: code %d cid %d aid %d aname %s oid %d\n", code, cid, *aid, aname, oid));
325     return code;
326 }
327
328 static afs_int32
329 newEntry(struct rx_call *call, char aname[], afs_int32 flag, afs_int32 oid, 
330          afs_int32 *aid, afs_int32 *cid)
331 {
332     register afs_int32 code;
333     struct ubik_trans *tt;
334     int admin;
335     char cname[PR_MAXNAMELEN];
336     stolower(aname);
337     code = Initdb();
338     if (code)
339         return code;
340     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
341     if (code)
342         return code;
343     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
344     if (code)
345         ABORT_WITH(tt, code);
346     code = read_DbHeader(tt);
347     if (code)
348         ABORT_WITH(tt, code);
349
350     /* this is for cross-cell self registration. It is not added in the
351      * SPR_INewEntry because we want self-registration to only do 
352      * automatic id assignment.
353      */
354     code = WhoIsThisWithName(call, tt, cid, cname);
355     if (code != 2) {            /* 2 specifies that this is a foreign cell request */
356         if (code)
357             ABORT_WITH(tt, PRPERM);
358         admin = IsAMemberOf(tt, *cid, SYSADMINID);
359     } else {
360         admin = ((!restricted && !strcmp(aname, cname))) || IsAMemberOf(tt, *cid, SYSADMINID);
361         oid = *cid = SYSADMINID;
362     }
363     if (!CreateOK(tt, *cid, oid, flag, admin))
364         ABORT_WITH(tt, PRPERM);
365
366     code = CreateEntry(tt, aname, aid, 0, flag, oid, *cid);
367     if (code != PRSUCCESS)
368         ABORT_WITH(tt, code);
369
370     code = ubik_EndTrans(tt);
371     if (code)
372         return code;
373     return PRSUCCESS;
374 }
375
376
377
378 afs_int32
379 SPR_WhereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos)
380 {
381     afs_int32 code;
382     afs_int32 cid = ANONYMOUSID;
383
384     code = whereIsIt(call, aid, apos, &cid);
385     osi_auditU(call, PTS_WheIsItEvent, code, AUD_ID, aid, AUD_LONG, *apos,
386                AUD_END);
387     ViceLog(125, ("PTS_WhereIsIt: code %d cid %d aid %d apos %d\n", code, cid, aid, *apos));
388     return code;
389 }
390
391 static afs_int32
392 whereIsIt(struct rx_call *call, afs_int32 aid, afs_int32 *apos, afs_int32 *cid)
393 {
394     register afs_int32 code;
395     struct ubik_trans *tt;
396     afs_int32 temp;
397
398     code = Initdb();
399     if (code != PRSUCCESS)
400         return code;
401     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
402     if (code)
403         return code;
404     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
405     if (code)
406         ABORT_WITH(tt, code);
407     code = read_DbHeader(tt);
408     if (code)
409         ABORT_WITH(tt, code);
410
411     code = WhoIsThis(call, tt, cid);
412     if (code)
413         ABORT_WITH(tt, PRPERM);
414
415     temp = FindByID(tt, aid);
416     if (!temp)
417         ABORT_WITH(tt, PRNOENT);
418     *apos = temp;
419     code = ubik_EndTrans(tt);
420     if (code)
421         return code;
422     return PRSUCCESS;
423 }
424
425
426 afs_int32
427 SPR_DumpEntry(struct rx_call *call, afs_int32 apos, 
428               struct prdebugentry *aentry)
429 {
430     afs_int32 code;
431     afs_int32 cid = ANONYMOUSID;
432
433     code = dumpEntry(call, apos, aentry, &cid);
434     osi_auditU(call, PTS_DmpEntEvent, code, AUD_LONG, apos, AUD_END);
435     ViceLog(125, ("PTS_DumpEntry: code %d cid %d apos %d\n", code, cid, apos));
436     return code;
437 }
438
439 static afs_int32
440 dumpEntry(struct rx_call *call, afs_int32 apos, struct prdebugentry *aentry, 
441           afs_int32 *cid)
442 {
443     register afs_int32 code;
444     struct ubik_trans *tt;
445
446     code = Initdb();
447     if (code != PRSUCCESS)
448         return code;
449     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
450     if (code)
451         return code;
452     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
453     if (code)
454         ABORT_WITH(tt, code);
455     code = read_DbHeader(tt);
456     if (code)
457         ABORT_WITH(tt, code);
458
459     code = WhoIsThis(call, tt, cid);
460     if (code)
461         ABORT_WITH(tt, PRPERM);
462     code = pr_ReadEntry(tt, 0, apos, (struct prentry *)aentry);
463     if (code)
464         ABORT_WITH(tt, code);
465
466     if (!AccessOK(tt, *cid, 0, PRP_STATUS_MEM, 0))
467         ABORT_WITH(tt, PRPERM);
468
469     /* Since prdebugentry is in the form of a prentry not a coentry, we will
470      * return the coentry slots in network order where the string is. */
471 #if 0
472     if (aentry->flags & PRCONT) {       /* wrong type, get coentry instead */
473         code = pr_ReadCoEntry(tt, 0, apos, aentry);
474         if (code)
475             ABORT_WITH(tt, code);
476     }
477 #endif
478     code = ubik_EndTrans(tt);
479     if (code)
480         return code;
481     return PRSUCCESS;
482 }
483
484 afs_int32
485 SPR_AddToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid)
486 {
487     afs_int32 code;
488     afs_int32 cid = ANONYMOUSID;
489
490     code = addToGroup(call, aid, gid, &cid);
491     osi_auditU(call, PTS_AdToGrpEvent, code, AUD_ID, gid, AUD_ID, aid,
492                AUD_END);
493     ViceLog(5, ("PTS_AddToGroup: code %d cid %d gid %d aid %d\n", code, cid, gid, aid));
494     return code;
495 }
496
497 static afs_int32
498 addToGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid, afs_int32 *cid)
499 {
500     register afs_int32 code;
501     struct ubik_trans *tt;
502     afs_int32 tempu;
503     afs_int32 tempg;
504     struct prentry tentry;
505     struct prentry uentry;
506
507     code = Initdb();
508     if (code != PRSUCCESS)
509         return code;
510     if (gid == ANYUSERID || gid == AUTHUSERID)
511         return PRPERM;
512     if (aid == ANONYMOUSID)
513         return PRPERM;
514     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
515     if (code)
516         return code;
517     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
518     if (code)
519         ABORT_WITH(tt, code);
520     code = read_DbHeader(tt);
521     if (code)
522         ABORT_WITH(tt, code);
523
524     code = WhoIsThis(call, tt, cid);
525     if (code)
526         ABORT_WITH(tt, PRPERM);
527     tempu = FindByID(tt, aid);
528     if (!tempu)
529         ABORT_WITH(tt, PRNOENT);
530     memset(&uentry, 0, sizeof(uentry));
531     code = pr_ReadEntry(tt, 0, tempu, &uentry);
532     if (code != 0)
533         ABORT_WITH(tt, code);
534
535 #if !defined(SUPERGROUPS)
536     /* we don't allow groups as members of groups at present */
537     if (uentry.flags & PRGRP)
538         ABORT_WITH(tt, PRNOTUSER);
539 #endif
540
541     tempg = FindByID(tt, gid);
542     if (!tempg)
543         ABORT_WITH(tt, PRNOENT);
544     code = pr_ReadEntry(tt, 0, tempg, &tentry);
545     if (code != 0)
546         ABORT_WITH(tt, code);
547     /* make sure that this is a group */
548     if (!(tentry.flags & PRGRP))
549         ABORT_WITH(tt, PRNOTGROUP);
550     if (!AccessOK(tt, *cid, &tentry, PRP_ADD_MEM, PRP_ADD_ANY))
551         ABORT_WITH(tt, PRPERM);
552
553     code = AddToEntry(tt, &tentry, tempg, aid);
554     if (code != PRSUCCESS)
555         ABORT_WITH(tt, code);
556
557 #if defined(SUPERGROUPS)
558     if (uentry.flags & PRGRP)
559         code = AddToSGEntry(tt, &uentry, tempu, gid);   /* mod group to be in sg */
560     else
561 #endif
562         /* now, modify the user's entry as well */
563         code = AddToEntry(tt, &uentry, tempu, gid);
564     if (code != PRSUCCESS)
565         ABORT_WITH(tt, code);
566     code = ubik_EndTrans(tt);
567     if (code)
568         return code;
569     return PRSUCCESS;
570 }
571
572 afs_int32
573 SPR_NameToID(struct rx_call *call, namelist *aname, idlist *aid)
574 {
575     afs_int32 code;
576
577     code = nameToID(call, aname, aid);
578     osi_auditU(call, PTS_NmToIdEvent, code, AUD_END);
579     ViceLog(125, ("PTS_NameToID: code %d\n", code));
580     return code;
581 }
582
583 static afs_int32
584 nameToID(struct rx_call *call, namelist *aname, idlist *aid)
585 {
586     register afs_int32 code;
587     struct ubik_trans *tt;
588     afs_int32 i;
589     int size;
590     int count = 0;
591
592     /* Initialize return struct */
593     aid->idlist_len = 0;
594     aid->idlist_val = NULL;
595
596     size = aname->namelist_len;
597     if (size == 0)
598         return 0;
599     if (size < 0)
600         return PRTOOMANY;
601
602     aid->idlist_val = (afs_int32 *) malloc(size * sizeof(afs_int32));
603     if (!aid->idlist_val)
604         return PRNOMEM;
605
606     code = Initdb();
607     if (code != PRSUCCESS)
608         return code;
609     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
610     if (code)
611         return code;
612     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
613     if (code)
614         ABORT_WITH(tt, code);
615     code = read_DbHeader(tt);
616     if (code)
617         ABORT_WITH(tt, code);
618
619     for (i = 0; i < aname->namelist_len; i++) {
620         char vname[256];
621         char *nameinst, *cell;
622
623         strncpy(vname, aname->namelist_val[i], sizeof(vname));
624         vname[sizeof(vname)-1] ='\0';
625
626         nameinst = vname;
627         cell = strchr(vname, '@');
628         if (cell) {
629             *cell = '\0';
630             cell++;
631         }
632
633         if (cell && afs_is_foreign_ticket_name(nameinst,NULL,cell,pr_realmName))
634             code = NameToID(tt, aname->namelist_val[i], &aid->idlist_val[i]);
635         else 
636             code = NameToID(tt, nameinst, &aid->idlist_val[i]);
637
638         if (code != PRSUCCESS)
639             aid->idlist_val[i] = ANONYMOUSID;
640         osi_audit(PTS_NmToIdEvent, code, AUD_STR,
641                    aname->namelist_val[i], AUD_ID, aid->idlist_val[i], 
642                    AUD_END);
643         ViceLog(125, ("PTS_NameToID: code %d aname %s aid %d\n", code,
644                       aname->namelist_val[i], aid->idlist_val[i]));
645         if (count++ > 50) {
646 #ifndef AFS_PTHREAD_ENV
647             IOMGR_Poll();
648 #endif
649             count = 0;
650         }
651     }
652     aid->idlist_len = aname->namelist_len;
653
654     code = ubik_EndTrans(tt);
655     if (code)
656         return code;
657     return PRSUCCESS;
658 }
659
660 /*
661  * SPR_IDToName
662  * Given an array of ids, find the name for each of them.
663  * The array of ids and names is unlimited.
664  */
665 afs_int32
666 SPR_IDToName(struct rx_call *call, idlist *aid, namelist *aname)
667 {
668     afs_int32 code;
669
670     code = idToName(call, aid, aname);
671     osi_auditU(call, PTS_IdToNmEvent, code, AUD_END);
672     ViceLog(125, ("PTS_IDToName: code %d\n", code));
673     return code;
674 }
675
676 static afs_int32
677 idToName(struct rx_call *call, idlist *aid, namelist *aname)
678 {
679     register afs_int32 code;
680     struct ubik_trans *tt;
681     afs_int32 i;
682     int size;
683     int count = 0;
684
685     /* leave this first for rpc stub */
686     size = aid->idlist_len;
687     if (size == 0)
688         return 0;
689     if (size < 0)
690         return PRTOOMANY;
691     aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN);
692     aname->namelist_len = 0;
693     if (aname->namelist_val == 0)
694         return PRNOMEM;
695     if (aid->idlist_len == 0)
696         return 0;
697     if (size == 0)
698         return PRTOOMANY;       /* rxgen will probably handle this */
699
700     code = Initdb();
701     if (code != PRSUCCESS)
702         return code;
703     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
704     if (code)
705         return code;
706     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
707     if (code)
708         ABORT_WITH(tt, code);
709     code = read_DbHeader(tt);
710     if (code)
711         ABORT_WITH(tt, code);
712
713     for (i = 0; i < aid->idlist_len; i++) {
714         code = IDToName(tt, aid->idlist_val[i], aname->namelist_val[i]);
715         if (code != PRSUCCESS)
716             sprintf(aname->namelist_val[i], "%d", aid->idlist_val[i]);
717         osi_audit(PTS_IdToNmEvent, code, AUD_ID, aid->idlist_val[i],
718                   AUD_STR, aname->namelist_val[i], AUD_END);
719         ViceLog(125, ("PTS_idToName: code %d aid %d aname %s\n", code,
720                       aid->idlist_val[i], aname->namelist_val[i]));
721         if (count++ > 50) {
722 #ifndef AFS_PTHREAD_ENV
723             IOMGR_Poll();
724 #endif
725             count = 0;
726         }
727     }
728     aname->namelist_len = aid->idlist_len;
729
730     code = ubik_EndTrans(tt);
731     if (code)
732         return code;
733     return PRSUCCESS;
734 }
735
736 afs_int32
737 SPR_Delete(struct rx_call *call, afs_int32 aid)
738 {
739     afs_int32 code;
740     afs_int32 cid = ANONYMOUSID;
741
742     code = Delete(call, aid, &cid);
743     osi_auditU(call, PTS_DelEvent, code, AUD_ID, aid, AUD_END);
744     ViceLog(5, ("PTS_Delete: code %d cid %d aid %d\n", code, cid, aid));
745     return code;
746 }
747
748 static afs_int32
749 Delete(struct rx_call *call, afs_int32 aid, afs_int32 *cid)
750 {
751     register afs_int32 code;
752     struct ubik_trans *tt;
753     struct prentry tentry;
754     afs_int32 loc, nptr;
755     int count;
756
757     code = Initdb();
758     if (code)
759         return code;
760     if (code != PRSUCCESS)
761         return code;
762     if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
763         || aid == ANONYMOUSID)
764         return PRPERM;
765     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
766     if (code)
767         return code;
768     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
769     if (code)
770         ABORT_WITH(tt, code);
771     code = read_DbHeader(tt);
772     if (code)
773         ABORT_WITH(tt, code);
774
775     code = WhoIsThis(call, tt, cid);
776     if (code)
777         ABORT_WITH(tt, PRPERM);
778
779     /* Read in entry to be deleted */
780     loc = FindByID(tt, aid);
781     if (loc == 0)
782         ABORT_WITH(tt, PRNOENT);
783     code = pr_ReadEntry(tt, 0, loc, &tentry);
784     if (code)
785         ABORT_WITH(tt, PRDBFAIL);
786
787     /* Do some access checking */
788     if (tentry.owner != *cid && !IsAMemberOf(tt, *cid, SYSADMINID)
789         && !IsAMemberOf(tt, *cid, tentry.owner) && !pr_noAuth)
790         ABORT_WITH(tt, PRPERM);
791
792     /* Delete each continuation block as a separate transaction so that no one
793      * transaction become to large to complete. */
794     nptr = tentry.next;
795     while (nptr != (afs_int32) NULL) {
796         struct contentry centry;
797         int i;
798
799         code = pr_ReadCoEntry(tt, 0, nptr, &centry);
800         if (code != 0)
801             ABORT_WITH(tt, PRDBFAIL);
802         for (i = 0; i < COSIZE; i++) {
803             if (centry.entries[i] == PRBADID)
804                 continue;
805             if (centry.entries[i] == 0)
806                 break;
807 #if defined(SUPERGROUPS)
808             if (aid < 0 && centry.entries[i] < 0)       /* Supergroup */
809                 code = RemoveFromSGEntry(tt, aid, centry.entries[i]);
810             else
811 #endif
812                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
813             if (code)
814                 ABORT_WITH(tt, code);
815             tentry.count--;     /* maintain count */
816 #ifndef AFS_PTHREAD_ENV
817             if ((i & 3) == 0)
818                 IOMGR_Poll();
819 #endif
820         }
821         tentry.next = centry.next;      /* thread out this block */
822         code = FreeBlock(tt, nptr);     /* free continuation block */
823         if (code)
824             ABORT_WITH(tt, code);
825         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
826         if (code)
827             ABORT_WITH(tt, code);
828
829         /* end this trans and start a new one */
830         code = ubik_EndTrans(tt);
831         if (code)
832             return code;
833 #ifndef AFS_PTHREAD_ENV
834         IOMGR_Poll();           /* just to keep the connection alive */
835 #endif
836         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
837         if (code)
838             return code;
839         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
840         if (code)
841             ABORT_WITH(tt, code);
842
843         /* re-read entry to get consistent uptodate info */
844         loc = FindByID(tt, aid);
845         if (loc == 0)
846             ABORT_WITH(tt, PRNOENT);
847         code = pr_ReadEntry(tt, 0, loc, &tentry);
848         if (code)
849             ABORT_WITH(tt, PRDBFAIL);
850
851         nptr = tentry.next;
852     }
853
854 #if defined(SUPERGROUPS)
855     /* Delete each continuation block as a separate transaction
856      * so that no one transaction become too large to complete. */
857     {
858         struct prentryg *tentryg = (struct prentryg *)&tentry;
859         nptr = tentryg->nextsg;
860         while (nptr != NULL) {
861             struct contentry centry;
862             int i;
863
864             code = pr_ReadCoEntry(tt, 0, nptr, &centry);
865             if (code != 0)
866                 ABORT_WITH(tt, PRDBFAIL);
867             for (i = 0; i < COSIZE; i++) {
868                 if (centry.entries[i] == PRBADID)
869                     continue;
870                 if (centry.entries[i] == 0)
871                     break;
872                 code = RemoveFromEntry(tt, aid, centry.entries[i]);
873                 if (code)
874                     ABORT_WITH(tt, code);
875                 tentryg->countsg--;     /* maintain count */
876 #ifndef AFS_PTHREAD_ENV
877                 if ((i & 3) == 0)
878                     IOMGR_Poll();
879 #endif
880             }
881             tentryg->nextsg = centry.next;      /* thread out this block */
882             code = FreeBlock(tt, nptr); /* free continuation block */
883             if (code)
884                 ABORT_WITH(tt, code);
885             code = pr_WriteEntry(tt, 0, loc, &tentry);  /* update main entry */
886             if (code)
887                 ABORT_WITH(tt, code);
888
889             /* end this trans and start a new one */
890             code = ubik_EndTrans(tt);
891             if (code)
892                 return code;
893 #ifndef AFS_PTHREAD_ENV
894             IOMGR_Poll();       /* just to keep the connection alive */
895 #endif
896
897             code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
898             if (code)
899                 return code;
900             code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
901             if (code)
902                 ABORT_WITH(tt, code);
903
904             /* re-read entry to get consistent uptodate info */
905             loc = FindByID(tt, aid);
906             if (loc == 0)
907                 ABORT_WITH(tt, PRNOENT);
908             code = pr_ReadEntry(tt, 0, loc, &tentry);
909             if (code)
910                 ABORT_WITH(tt, PRDBFAIL);
911
912             nptr = tentryg->nextsg;
913         }
914     }
915
916 #endif /* SUPERGROUPS */
917
918     /* Then move the owned chain, except possibly ourself to the orphan list.
919      * Because this list can be very long and so exceed the size of a ubik
920      * transaction, we start a new transaction every 50 entries. */
921     count = 0;
922     nptr = tentry.owned;
923     while (nptr != (afs_int32) NULL) {
924         struct prentry nentry;
925
926         code = pr_ReadEntry(tt, 0, nptr, &nentry);
927         if (code)
928             ABORT_WITH(tt, PRDBFAIL);
929         nptr = tentry.owned = nentry.nextOwned; /* thread out */
930
931         if (nentry.id != tentry.id) {   /* don't add us to orphan chain! */
932             code = AddToOrphan(tt, nentry.id);
933             if (code)
934                 ABORT_WITH(tt, code);
935             count++;
936 #ifndef AFS_PTHREAD_ENV
937             if ((count & 3) == 0)
938                 IOMGR_Poll();
939 #endif
940         }
941         if (count < 50)
942             continue;
943         code = pr_WriteEntry(tt, 0, loc, &tentry);      /* update main entry */
944         if (code)
945             ABORT_WITH(tt, code);
946
947         /* end this trans and start a new one */
948         code = ubik_EndTrans(tt);
949         if (code)
950             return code;
951 #ifndef AFS_PTHREAD_ENV
952         IOMGR_Poll();           /* just to keep the connection alive */
953 #endif
954         code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
955         if (code)
956             return code;
957         code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
958         if (code)
959             ABORT_WITH(tt, code);
960
961         /* re-read entry to get consistent uptodate info */
962         loc = FindByID(tt, aid);
963         if (loc == 0)
964             ABORT_WITH(tt, PRNOENT);
965         code = pr_ReadEntry(tt, 0, loc, &tentry);
966         if (code)
967             ABORT_WITH(tt, PRDBFAIL);
968
969         nptr = tentry.owned;
970     }
971
972     /* now do what's left of the deletion stuff */
973     code = DeleteEntry(tt, &tentry, loc);
974     if (code != PRSUCCESS)
975         ABORT_WITH(tt, code);
976
977     code = ubik_EndTrans(tt);
978     if (code)
979         return code;
980     return PRSUCCESS;
981 }
982
983 afs_int32
984 SPR_UpdateEntry(struct rx_call *call, afs_int32 aid, char *name, 
985                 struct PrUpdateEntry *uentry)
986 {
987     afs_int32 code;
988     afs_int32 cid = ANONYMOUSID;
989
990     code = UpdateEntry(call, aid, name, uentry, &cid);
991     osi_auditU(call, PTS_UpdEntEvent, code, AUD_ID, aid, AUD_STR, name, AUD_END);
992     ViceLog(5, ("PTS_UpdateEntry: code %d cid %d aid %d name %s\n", code, cid, aid, name));
993     return code;
994 }
995
996 afs_int32
997 UpdateEntry(struct rx_call *call, afs_int32 aid, char *name, 
998             struct PrUpdateEntry *uentry, afs_int32 *cid)
999 {
1000     register afs_int32 code;
1001     struct ubik_trans *tt;
1002     struct prentry tentry;
1003     afs_int32 loc;
1004     int id = 0;
1005
1006     code = Initdb();
1007     if (code)
1008         return code;
1009     if (code != PRSUCCESS)
1010         return code;
1011     if (aid) {
1012         id = aid;
1013         if (aid == SYSADMINID || aid == ANYUSERID || aid == AUTHUSERID
1014             || aid == ANONYMOUSID)
1015             return PRPERM;
1016     }
1017     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1018     if (code)
1019         return code;
1020     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1021     if (code)
1022         ABORT_WITH(tt, code);
1023     code = read_DbHeader(tt);
1024     if (code)
1025         ABORT_WITH(tt, code);
1026
1027     code = WhoIsThis(call, tt, cid);
1028     if (code)
1029         ABORT_WITH(tt, PRPERM);
1030     code = IsAMemberOf(tt, *cid, SYSADMINID);
1031     if (!code && !pr_noAuth)
1032         ABORT_WITH(tt, PRPERM);
1033
1034     /* Read in entry to be deleted */
1035     if (id) {
1036         loc = FindByID(tt, aid);
1037     } else {
1038         loc = FindByName(tt, name, &tentry);
1039     }
1040     if (loc == 0)
1041         ABORT_WITH(tt, PRNOENT);
1042     code = pr_ReadEntry(tt, 0, loc, &tentry);
1043     if (code)
1044         ABORT_WITH(tt, PRDBFAIL);
1045
1046     if (uentry->Mask & PRUPDATE_NAMEHASH) {
1047         int tloc;
1048         code = RemoveFromNameHash(tt, tentry.name, &tloc);
1049         if (code != PRSUCCESS)
1050             ABORT_WITH(tt, PRDBFAIL);
1051         code = AddToNameHash(tt, tentry.name, loc);
1052         if (code)
1053             ABORT_WITH(tt, code);
1054     }
1055
1056     if (uentry->Mask & PRUPDATE_IDHASH) {
1057         int tloc;
1058         if (!id)
1059             id = tentry.id;
1060         code = RemoveFromIDHash(tt, id, &tloc);
1061         if (code != PRSUCCESS)
1062             ABORT_WITH(tt, PRDBFAIL);
1063         code = AddToIDHash(tt, id, loc);
1064         if (code)
1065             ABORT_WITH(tt, code);
1066     }
1067
1068     code = ubik_EndTrans(tt);
1069     if (code)
1070         return code;
1071     return PRSUCCESS;
1072 }
1073
1074 afs_int32
1075 SPR_RemoveFromGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid)
1076 {
1077     afs_int32 code;
1078     afs_int32 cid = ANONYMOUSID;
1079
1080     code = removeFromGroup(call, aid, gid, &cid);
1081     osi_auditU(call, PTS_RmFmGrpEvent, code, AUD_ID, gid, AUD_ID, aid,
1082                AUD_END);
1083     ViceLog(5, ("PTS_RemoveFromGroup: code %d cid %d gid %d aid %d\n", code, cid, gid, aid));
1084     return code;
1085 }
1086
1087 static afs_int32
1088 removeFromGroup(struct rx_call *call, afs_int32 aid, afs_int32 gid, 
1089                 afs_int32 *cid)
1090 {
1091     register afs_int32 code;
1092     struct ubik_trans *tt;
1093     afs_int32 tempu;
1094     afs_int32 tempg;
1095     struct prentry uentry;
1096     struct prentry gentry;
1097
1098     code = Initdb();
1099     if (code != PRSUCCESS)
1100         return code;
1101     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1102     if (code)
1103         return code;
1104     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1105     if (code)
1106         ABORT_WITH(tt, code);
1107     code = read_DbHeader(tt);
1108     if (code)
1109         ABORT_WITH(tt, code);
1110
1111     code = WhoIsThis(call, tt, cid);
1112     if (code)
1113         ABORT_WITH(tt, PRPERM);
1114     tempu = FindByID(tt, aid);
1115     if (!tempu)
1116         ABORT_WITH(tt, PRNOENT);
1117     tempg = FindByID(tt, gid);
1118     if (!tempg)
1119         ABORT_WITH(tt, PRNOENT);
1120     memset(&uentry, 0, sizeof(uentry));
1121     memset(&gentry, 0, sizeof(gentry));
1122     code = pr_ReadEntry(tt, 0, tempu, &uentry);
1123     if (code != 0)
1124         ABORT_WITH(tt, code);
1125     code = pr_ReadEntry(tt, 0, tempg, &gentry);
1126     if (code != 0)
1127         ABORT_WITH(tt, code);
1128     if (!(gentry.flags & PRGRP))
1129         ABORT_WITH(tt, PRNOTGROUP);
1130 #if !defined(SUPERGROUPS)
1131     if (uentry.flags & PRGRP)
1132         ABORT_WITH(tt, PRNOTUSER);
1133 #endif
1134     if (!AccessOK(tt, *cid, &gentry, PRP_REMOVE_MEM, 0))
1135         ABORT_WITH(tt, PRPERM);
1136     code = RemoveFromEntry(tt, aid, gid);
1137     if (code != PRSUCCESS)
1138         ABORT_WITH(tt, code);
1139 #if defined(SUPERGROUPS)
1140     if (!(uentry.flags & PRGRP))
1141 #endif
1142         code = RemoveFromEntry(tt, gid, aid);
1143 #if defined(SUPERGROUPS)
1144     else
1145         code = RemoveFromSGEntry(tt, gid, aid);
1146 #endif
1147     if (code != PRSUCCESS)
1148         ABORT_WITH(tt, code);
1149
1150     code = ubik_EndTrans(tt);
1151     if (code)
1152         return code;
1153     return PRSUCCESS;
1154 }
1155
1156
1157 afs_int32
1158 SPR_GetCPS(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *over)
1159 {
1160     afs_int32 code;
1161     afs_int32 cid = ANONYMOUSID;
1162
1163     code = getCPS(call, aid, alist, over, &cid);
1164     osi_auditU(call, PTS_GetCPSEvent, code, AUD_ID, aid, AUD_END);
1165     ViceLog(125, ("PTS_GetCPS: code %d cid %d aid %d\n", code, cid, aid));
1166     return code;
1167 }
1168
1169 static afs_int32
1170 getCPS(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *over, 
1171        afs_int32 *cid)
1172 {
1173     register afs_int32 code;
1174     struct ubik_trans *tt;
1175     afs_int32 temp;
1176     struct prentry tentry;
1177
1178     *over = 0;
1179     alist->prlist_len = 0;
1180     alist->prlist_val = NULL;
1181     code = Initdb();
1182     if (code != PRSUCCESS)
1183         return code;
1184     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1185     if (code)
1186         return code;
1187     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1188     if (code)
1189         ABORT_WITH(tt, code);
1190     code = read_DbHeader(tt);
1191     if (code)
1192         ABORT_WITH(tt, code);
1193
1194     temp = FindByID(tt, aid);
1195     if (!temp)
1196         ABORT_WITH(tt, PRNOENT);
1197     code = pr_ReadEntry(tt, 0, temp, &tentry);
1198     if (code)
1199         ABORT_WITH(tt, code);
1200
1201     /* afs does authenticate now */
1202     code = WhoIsThis(call, tt, cid);
1203     if (code || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1204         ABORT_WITH(tt, PRPERM);
1205
1206     code = GetList(tt, &tentry, alist, 1);
1207     if (code != PRSUCCESS)
1208         ABORT_WITH(tt, code);
1209
1210     code = ubik_EndTrans(tt);
1211     return code;
1212 }
1213
1214
1215 #ifdef IP_WILDCARDS
1216 int
1217 inCPS(prlist CPS, afs_int32 id)
1218 {
1219     int i;
1220
1221     for (i = (CPS.prlist_len - 1); i >= 0; i--) {
1222         if (CPS.prlist_val[i] == id)
1223             return (1);
1224     }
1225     return (0);
1226 }
1227 #endif /* IP_WILDCARDS */
1228
1229
1230 afs_int32
1231 SPR_GetCPS2(struct rx_call *call, afs_int32 aid, afs_int32 ahost, 
1232             prlist *alist, afs_int32 *over)
1233 {
1234     afs_int32 code;
1235     afs_int32 cid = ANONYMOUSID;
1236
1237     code = getCPS2(call, aid, ahost, alist, over, &cid);
1238     osi_auditU(call, PTS_GetCPS2Event, code, AUD_ID, aid, AUD_HOST, ahost,
1239                AUD_END);
1240     ViceLog(125, ("PTS_GetCPS2: code %d cid %d aid %d ahost %d\n", code, cid, aid, ahost));
1241     return code;
1242 }
1243
1244 static afs_int32
1245 getCPS2(struct rx_call *call, afs_int32 aid, afs_int32 ahost, prlist *alist, 
1246         afs_int32 *over, afs_int32 *cid)
1247 {
1248     register afs_int32 code;
1249     struct ubik_trans *tt;
1250     afs_int32 temp;
1251     struct prentry tentry;
1252     struct prentry host_tentry;
1253     afs_int32 hostid;
1254     int host_list = 0;
1255     struct in_addr iaddr;
1256
1257     *over = 0;
1258     iaddr.s_addr = ntohl(ahost);
1259     alist->prlist_len = 0;
1260     alist->prlist_val = NULL;
1261     code = Initdb();
1262     if (code != PRSUCCESS)
1263         return code;
1264     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1265     if (code)
1266         return code;
1267     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1268     if (code)
1269         ABORT_WITH(tt, code);
1270     code = read_DbHeader(tt);
1271     if (code)
1272         ABORT_WITH(tt, code);
1273
1274     if (aid != PRBADID) {
1275         temp = FindByID(tt, aid);
1276         if (!temp)
1277             ABORT_WITH(tt, PRNOENT);
1278         code = pr_ReadEntry(tt, 0, temp, &tentry);
1279         if (code)
1280             ABORT_WITH(tt, code);
1281
1282         /* afs does authenticate now */
1283         code = WhoIsThis(call, tt, cid);
1284         if (code
1285             || !AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1286             ABORT_WITH(tt, PRPERM);
1287     }
1288     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1289     if (code == PRSUCCESS && hostid != 0) {
1290         temp = FindByID(tt, hostid);
1291         if (temp) {
1292             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1293             if (code == PRSUCCESS)
1294                 host_list = 1;
1295             else
1296                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1297         } else
1298             fprintf(stderr, "FindByID Failed -- Not found\n");
1299     }
1300     if (host_list)
1301         code = GetList2(tt, &tentry, &host_tentry, alist, 1);
1302     else
1303         code = GetList(tt, &tentry, alist, 1);
1304 #if IP_WILDCARDS
1305     if (!code)
1306         code = addWildCards(tt, alist, ntohl(ahost));
1307 #endif /* IP_WILDCARDS */
1308     if (code != PRSUCCESS)
1309         ABORT_WITH(tt, code);
1310
1311     code = ubik_EndTrans(tt);
1312     return code;
1313 }
1314
1315
1316 afs_int32
1317 SPR_GetHostCPS(struct rx_call *call, afs_int32 ahost, prlist *alist, 
1318                afs_int32 *over)
1319 {
1320     afs_int32 code;
1321
1322     code = getHostCPS(call, ahost, alist, over);
1323     osi_auditU(call, PTS_GetHCPSEvent, code, AUD_HOST, ahost, AUD_END);
1324     ViceLog(125, ("PTS_GetHostCPS: code %d ahost %d\n", code, ahost));
1325     return code;
1326 }
1327
1328 afs_int32
1329 getHostCPS(struct rx_call *call, afs_int32 ahost, prlist *alist, 
1330            afs_int32 *over)
1331 {
1332     register afs_int32 code, temp;
1333     struct ubik_trans *tt;
1334     struct prentry host_tentry;
1335     afs_int32 hostid;
1336     struct in_addr iaddr;
1337
1338     *over = 0;
1339     iaddr.s_addr = ntohl(ahost);
1340     alist->prlist_len = 0;
1341     alist->prlist_val = NULL;
1342     code = Initdb();
1343     if (code != PRSUCCESS)
1344         return code;
1345     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1346     if (code)
1347         return code;
1348     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1349     if (code)
1350         ABORT_WITH(tt, code);
1351     code = read_DbHeader(tt);
1352     if (code)
1353         ABORT_WITH(tt, code);
1354
1355     code = NameToID(tt, inet_ntoa(iaddr), &hostid);
1356     if (code == PRSUCCESS && hostid != 0) {
1357         temp = FindByID(tt, hostid);
1358         if (temp) {
1359             code = pr_ReadEntry(tt, 0, temp, &host_tentry);
1360             if (code == PRSUCCESS) {
1361                 code = GetList(tt, &host_tentry, alist, 0);
1362                 if (code)
1363                     goto bad;
1364             } else
1365                 fprintf(stderr, "pr_ReadEntry returned %d\n", code);
1366         } else
1367             fprintf(stderr, "FindByID Failed -- Not found\n");
1368     }
1369 #if IP_WILDCARDS
1370     code = addWildCards(tt, alist, ntohl(ahost));
1371 #endif /* IP_WILDCARDS */
1372   bad:
1373     if (code != PRSUCCESS)
1374         ABORT_WITH(tt, code);
1375
1376     code = ubik_EndTrans(tt);
1377     return code;
1378 }
1379
1380
1381 afs_int32
1382 SPR_ListMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid)
1383 {
1384     afs_int32 code;
1385
1386     code = listMax(call, uid, gid);
1387     osi_auditU(call, PTS_LstMaxEvent, code, AUD_END);
1388     ViceLog(125, ("PTS_ListMax: code %d\n", code));
1389     return code;
1390 }
1391
1392 afs_int32
1393 listMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid)
1394 {
1395     register afs_int32 code;
1396     struct ubik_trans *tt;
1397
1398     code = Initdb();
1399     if (code != PRSUCCESS)
1400         return code;
1401     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1402     if (code)
1403         return code;
1404     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1405     if (code)
1406         ABORT_WITH(tt, code);
1407     code = read_DbHeader(tt);
1408     if (code)
1409         ABORT_WITH(tt, code);
1410
1411     code = GetMax(tt, uid, gid);
1412     if (code != PRSUCCESS)
1413         ABORT_WITH(tt, code);
1414
1415     code = ubik_EndTrans(tt);
1416     if (code)
1417         return code;
1418     return PRSUCCESS;
1419 }
1420
1421 afs_int32
1422 SPR_SetMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag)
1423 {
1424     afs_int32 code;
1425     afs_int32 cid = ANONYMOUSID;
1426
1427     code = setMax(call, aid, gflag, &cid);
1428     osi_auditU(call, PTS_SetMaxEvent, code, AUD_ID, aid, AUD_LONG, gflag,
1429                AUD_END);
1430     ViceLog(125, ("PTS_SetMax: code %d cid %d aid %d gflag %d\n", code, cid, aid, gflag));
1431     return code;
1432 }
1433
1434 static afs_int32
1435 setMax(struct rx_call *call, afs_int32 aid, afs_int32 gflag, afs_int32 *cid)
1436 {
1437     register afs_int32 code;
1438     struct ubik_trans *tt;
1439
1440     code = Initdb();
1441     if (code != PRSUCCESS)
1442         return code;
1443     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1444     if (code)
1445         return code;
1446     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1447     if (code)
1448         ABORT_WITH(tt, code);
1449     code = read_DbHeader(tt);
1450     if (code)
1451         ABORT_WITH(tt, code);
1452
1453     code = WhoIsThis(call, tt, cid);
1454     if (code)
1455         ABORT_WITH(tt, PRPERM);
1456     if (!AccessOK(tt, *cid, 0, 0, 0))
1457         ABORT_WITH(tt, PRPERM);
1458     if (((gflag & PRGRP) && (aid > 0)) || (!(gflag & PRGRP) && (aid < 0)))
1459         ABORT_WITH(tt, PRBADARG);
1460
1461     code = SetMax(tt, aid, gflag);
1462     if (code != PRSUCCESS)
1463         ABORT_WITH(tt, code);
1464
1465     code = ubik_EndTrans(tt);
1466     if (code)
1467         return code;
1468     return PRSUCCESS;
1469 }
1470
1471 afs_int32
1472 SPR_ListEntry(struct rx_call *call, afs_int32 aid, struct prcheckentry *aentry)
1473 {
1474     afs_int32 code;
1475     afs_int32 cid = ANONYMOUSID;
1476
1477     code = listEntry(call, aid, aentry, &cid);
1478     osi_auditU(call, PTS_LstEntEvent, code, AUD_ID, aid, AUD_END);
1479     ViceLog(125, ("PTS_ListEntry: code %d cid %d aid %d\n", code, cid, aid));
1480     return code;
1481 }
1482
1483 static afs_int32
1484 listEntry(struct rx_call *call, afs_int32 aid, struct prcheckentry *aentry, 
1485           afs_int32 *cid)
1486 {
1487     register afs_int32 code;
1488     struct ubik_trans *tt;
1489     afs_int32 temp;
1490     struct prentry tentry;
1491
1492     code = Initdb();
1493     if (code != PRSUCCESS)
1494         return code;
1495     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1496     if (code)
1497         return code;
1498     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1499     if (code)
1500         ABORT_WITH(tt, code);
1501     code = read_DbHeader(tt);
1502     if (code)
1503         ABORT_WITH(tt, code);
1504
1505     code = WhoIsThis(call, tt, cid);
1506     if (code)
1507         ABORT_WITH(tt, PRPERM);
1508     temp = FindByID(tt, aid);
1509     if (!temp)
1510         ABORT_WITH(tt, PRNOENT);
1511     code = pr_ReadEntry(tt, 0, temp, &tentry);
1512     if (code != 0)
1513         ABORT_WITH(tt, code);
1514     if (!AccessOK(tt, *cid, &tentry, PRP_STATUS_MEM, PRP_STATUS_ANY))
1515         ABORT_WITH(tt, PRPERM);
1516
1517     aentry->flags = tentry.flags >> PRIVATE_SHIFT;
1518     if (aentry->flags == 0) {
1519         if (tentry.flags & PRGRP)
1520             aentry->flags = prp_group_default >> PRIVATE_SHIFT;
1521         else
1522             aentry->flags = prp_user_default >> PRIVATE_SHIFT;
1523     }
1524     aentry->owner = tentry.owner;
1525     aentry->id = tentry.id;
1526     strncpy(aentry->name, tentry.name, PR_MAXNAMELEN);
1527     aentry->creator = tentry.creator;
1528     aentry->ngroups = tentry.ngroups;
1529     aentry->nusers = tentry.nusers;
1530     aentry->count = tentry.count;
1531     memset(aentry->reserved, 0, sizeof(aentry->reserved));
1532     code = ubik_EndTrans(tt);
1533     if (code)
1534         return code;
1535     return PRSUCCESS;
1536 }
1537
1538 afs_int32
1539 SPR_ListEntries(struct rx_call *call, afs_int32 flag, afs_int32 startindex, 
1540                 prentries *bulkentries, afs_int32 *nextstartindex)
1541 {
1542     afs_int32 code;
1543     afs_int32 cid = ANONYMOUSID;
1544
1545     code = listEntries(call, flag, startindex, bulkentries, nextstartindex, &cid);
1546     osi_auditU(call, PTS_LstEntsEvent, code, AUD_LONG, flag, AUD_END);
1547     ViceLog(125, ("PTS_ListEntries: code %d cid %d flag %d\n", code, cid, flag));
1548     return code;
1549 }
1550
1551 static afs_int32
1552 listEntries(struct rx_call *call, afs_int32 flag, afs_int32 startindex, 
1553             prentries *bulkentries, afs_int32 *nextstartindex, afs_int32 *cid)
1554 {
1555     afs_int32 code;
1556     struct ubik_trans *tt;
1557     afs_int32 i, eof, pos, maxentries, f;
1558     struct prentry tentry;
1559     afs_int32 pollcount = 0;
1560
1561     *nextstartindex = -1;
1562     bulkentries->prentries_val = 0;
1563     bulkentries->prentries_len = 0;
1564
1565     code = Initdb();
1566     if (code != PRSUCCESS)
1567         return code;
1568     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1569     if (code)
1570         return code;
1571     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1572     if (code)
1573         ABORT_WITH(tt, code);
1574     code = read_DbHeader(tt);
1575     if (code)
1576         ABORT_WITH(tt, code);
1577
1578     /* Make sure we are an authenticated caller and that we are on the
1579      * SYSADMIN list.
1580      */
1581     code = WhoIsThis(call, tt, cid);
1582     if (code)
1583         ABORT_WITH(tt, PRPERM);
1584     code = IsAMemberOf(tt, *cid, SYSADMINID);
1585     if (!code && !pr_noAuth)
1586         ABORT_WITH(tt, PRPERM);
1587
1588     eof = ntohl(cheader.eofPtr) - sizeof(cheader);
1589     maxentries = eof / sizeof(struct prentry);
1590     for (i = startindex; i < maxentries; i++) {
1591         pos = i * sizeof(struct prentry) + sizeof(cheader);
1592         code = pr_ReadEntry(tt, 0, pos, &tentry);
1593         if (code)
1594             goto done;
1595
1596         if (++pollcount > 50) {
1597 #ifndef AFS_PTHREAD_ENV
1598             IOMGR_Poll();
1599 #endif
1600             pollcount = 0;
1601         }
1602
1603         f = (tentry.flags & PRTYPE);
1604         if (((flag & PRUSERS) && (f == 0)) ||   /* User  entry */
1605             ((flag & PRGROUPS) && (f & PRGRP))) {       /* Group entry */
1606             code = put_prentries(&tentry, bulkentries);
1607             if (code == -1)
1608                 break;          /* Filled return array */
1609             if (code)
1610                 goto done;
1611         }
1612     }
1613     code = 0;
1614     if (i < maxentries)
1615         *nextstartindex = i;
1616
1617   done:
1618     if (code) {
1619         if (bulkentries->prentries_val)
1620             free(bulkentries->prentries_val);
1621         bulkentries->prentries_val = 0;
1622         bulkentries->prentries_len = 0;
1623         ABORT_WITH(tt, code);
1624     } else {
1625         code = ubik_EndTrans(tt);
1626     }
1627     if (code)
1628         return code;
1629     return PRSUCCESS;
1630 }
1631
1632 #define PR_MAXENTRIES 500
1633 static afs_int32
1634 put_prentries(struct prentry *tentry, prentries *bulkentries)
1635 {
1636     struct prlistentries *entry;
1637
1638     if (bulkentries->prentries_val == 0) {
1639         bulkentries->prentries_len = 0;
1640         bulkentries->prentries_val =
1641             (struct prlistentries *)malloc(PR_MAXENTRIES *
1642                                            sizeof(struct prentry));
1643         if (!bulkentries->prentries_val) {
1644             return (PRNOMEM);
1645         }
1646     }
1647
1648     if (bulkentries->prentries_len >= PR_MAXENTRIES) {
1649         return (-1);
1650     }
1651
1652     entry = (struct prlistentries *)bulkentries->prentries_val;
1653     entry += bulkentries->prentries_len;
1654
1655     entry->flags = tentry->flags >> PRIVATE_SHIFT;
1656     if (entry->flags == 0) {
1657         entry->flags =
1658             ((tentry->
1659               flags & PRGRP) ? prp_group_default : prp_user_default) >>
1660             PRIVATE_SHIFT;
1661     }
1662     entry->owner = tentry->owner;
1663     entry->id = tentry->id;
1664     entry->creator = tentry->creator;
1665     entry->ngroups = tentry->ngroups;
1666     entry->nusers = tentry->nusers;
1667     entry->count = tentry->count;
1668     strncpy(entry->name, tentry->name, PR_MAXNAMELEN);
1669     memset(entry->reserved, 0, sizeof(entry->reserved));
1670     bulkentries->prentries_len++;
1671     return 0;
1672 }
1673
1674 afs_int32
1675 SPR_ChangeEntry(struct rx_call *call, afs_int32 aid, char *name, afs_int32 oid, 
1676                 afs_int32 newid)
1677 {
1678     afs_int32 code;
1679     afs_int32 cid = ANONYMOUSID;
1680
1681     code = changeEntry(call, aid, name, oid, newid, &cid);
1682     osi_auditU(call, PTS_ChgEntEvent, code, AUD_ID, aid, AUD_STR, name,
1683                AUD_LONG, oid, AUD_LONG, newid, AUD_END);
1684     ViceLog(5, ("PTS_ChangeEntry: code %d cid %d aid %d name %s oid %d newid %d\n", code, cid, aid, name, oid, newid));
1685     return code;
1686 }
1687
1688 static afs_int32
1689 changeEntry(struct rx_call *call, afs_int32 aid, char *name, afs_int32 oid, 
1690             afs_int32 newid, afs_int32 *cid)
1691 {
1692     register afs_int32 code;
1693     struct ubik_trans *tt;
1694     afs_int32 pos;
1695
1696     if (!name)
1697         return PRPERM;
1698     stolower(name);
1699
1700     code = Initdb();
1701     if (code)
1702         return code;
1703     if (aid == ANYUSERID || aid == AUTHUSERID || aid == ANONYMOUSID
1704         || aid == SYSADMINID)
1705         return PRPERM;
1706     if (code != PRSUCCESS)
1707         return code;
1708     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1709     if (code)
1710         return code;
1711     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1712     if (code)
1713         ABORT_WITH(tt, code);
1714     code = read_DbHeader(tt);
1715     if (code)
1716         ABORT_WITH(tt, code);
1717
1718     code = WhoIsThis(call, tt, cid);
1719     if (code)
1720         ABORT_WITH(tt, PRPERM);
1721     pos = FindByID(tt, aid);
1722     if (!pos)
1723         ABORT_WITH(tt, PRNOENT);
1724     /* protection check in changeentry */
1725     code = ChangeEntry(tt, aid, *cid, name, oid, newid);
1726     if (code != PRSUCCESS)
1727         ABORT_WITH(tt, code);
1728
1729     code = ubik_EndTrans(tt);
1730     return code;
1731 }
1732
1733 afs_int32
1734 SPR_SetFieldsEntry(struct rx_call *call, 
1735                    afs_int32 id, 
1736                    afs_int32 mask, /* specify which fields to update */ 
1737                    afs_int32 flags, afs_int32 ngroups, afs_int32 nusers, 
1738                    afs_int32 spare1, afs_int32 spare2)
1739 {
1740     afs_int32 code;
1741     afs_int32 cid = ANONYMOUSID;
1742
1743     code =
1744         setFieldsEntry(call, id, mask, flags, ngroups, nusers, spare1,
1745                        spare2, &cid);
1746     osi_auditU(call, PTS_SetFldEntEvent, code, AUD_ID, id, AUD_END);
1747     ViceLog(5, ("PTS_SetFieldsEntry: code %d cid %d id %d\n", code, cid, id));
1748     return code;
1749 }
1750
1751 static afs_int32
1752 setFieldsEntry(struct rx_call *call, 
1753                afs_int32 id, 
1754                afs_int32 mask, /* specify which fields to update */ 
1755                afs_int32 flags, afs_int32 ngroups, afs_int32 nusers, 
1756                afs_int32 spare1, afs_int32 spare2, afs_int32 *cid)
1757 {
1758     register afs_int32 code;
1759     struct ubik_trans *tt;
1760     afs_int32 pos;
1761     struct prentry tentry;
1762     afs_int32 tflags;
1763
1764     if (mask == 0)
1765         return 0;               /* no-op */
1766     code = Initdb();
1767     if (code)
1768         return code;
1769     if (id == ANYUSERID || id == AUTHUSERID || id == ANONYMOUSID)
1770         return PRPERM;
1771     if (code != PRSUCCESS)
1772         return code;
1773     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1774     if (code)
1775         return code;
1776     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1777     if (code)
1778         ABORT_WITH(tt, code);
1779     code = read_DbHeader(tt);
1780     if (code)
1781         ABORT_WITH(tt, code);
1782
1783     code = WhoIsThis(call, tt, cid);
1784     if (code)
1785         ABORT_WITH(tt, PRPERM);
1786     pos = FindByID(tt, id);
1787     if (!pos)
1788         ABORT_WITH(tt, PRNOENT);
1789     code = pr_ReadEntry(tt, 0, pos, &tentry);
1790     if (code)
1791         ABORT_WITH(tt, code);
1792     tflags = tentry.flags;
1793
1794     if (mask & (PR_SF_NGROUPS | PR_SF_NUSERS)) {
1795         if (!AccessOK(tt, *cid, 0, 0, 0))
1796             ABORT_WITH(tt, PRPERM);
1797         if ((tflags & PRQUOTA) == 0) {  /* default if only setting one */
1798             tentry.ngroups = tentry.nusers = 20;
1799         }
1800     } else {
1801         if (!AccessOK(tt, *cid, &tentry, 0, 0))
1802             ABORT_WITH(tt, PRPERM);
1803     }
1804
1805     if (mask & 0xffff) {        /* if setting flag bits */
1806         afs_int32 flagsMask = mask & 0xffff;
1807         tflags &= ~(flagsMask << PRIVATE_SHIFT);
1808         tflags |= (flags & flagsMask) << PRIVATE_SHIFT;
1809         tflags |= PRACCESS;
1810     }
1811
1812     if (mask & PR_SF_NGROUPS) { /* setting group limit */
1813         if (ngroups < 0)
1814             ABORT_WITH(tt, PRBADARG);
1815         tentry.ngroups = ngroups;
1816         tflags |= PRQUOTA;
1817     }
1818
1819     if (mask & PR_SF_NUSERS) {  /* setting foreign user limit */
1820         if (nusers < 0)
1821             ABORT_WITH(tt, PRBADARG);
1822         tentry.nusers = nusers;
1823         tflags |= PRQUOTA;
1824     }
1825     tentry.flags = tflags;
1826
1827     code = pr_WriteEntry(tt, 0, pos, &tentry);
1828     if (code)
1829         ABORT_WITH(tt, code);
1830
1831     code = ubik_EndTrans(tt);
1832     return code;
1833 }
1834
1835 afs_int32
1836 SPR_ListElements(struct rx_call *call, afs_int32 aid, prlist *alist, 
1837                  afs_int32 *over)
1838 {
1839     afs_int32 code;
1840     afs_int32 cid = ANONYMOUSID;
1841
1842     code = listElements(call, aid, alist, over, &cid);
1843     osi_auditU(call, PTS_LstEleEvent, code, AUD_ID, aid, AUD_END);
1844     ViceLog(125, ("PTS_ListElements: code %d cid %d aid %d\n", code, cid, aid));
1845     return code;
1846 }
1847
1848 static afs_int32
1849 listElements(struct rx_call *call, afs_int32 aid, prlist *alist, 
1850              afs_int32 *over, afs_int32 *cid)
1851 {
1852     register afs_int32 code;
1853     struct ubik_trans *tt;
1854     afs_int32 temp;
1855     struct prentry tentry;
1856
1857     *over = 0;
1858     alist->prlist_len = 0;
1859     alist->prlist_val = NULL;
1860
1861     code = Initdb();
1862     if (code != PRSUCCESS)
1863         return code;
1864     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1865     if (code)
1866         return code;
1867     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1868     if (code)
1869         ABORT_WITH(tt, code);
1870     code = read_DbHeader(tt);
1871     if (code)
1872         ABORT_WITH(tt, code);
1873
1874     code = WhoIsThis(call, tt, cid);
1875     if (code)
1876         ABORT_WITH(tt, PRPERM);
1877
1878     temp = FindByID(tt, aid);
1879     if (!temp)
1880         ABORT_WITH(tt, PRNOENT);
1881     code = pr_ReadEntry(tt, 0, temp, &tentry);
1882     if (code)
1883         ABORT_WITH(tt, code);
1884     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1885         ABORT_WITH(tt, PRPERM);
1886
1887     code = GetList(tt, &tentry, alist, 0);
1888     if (code != PRSUCCESS)
1889         ABORT_WITH(tt, code);
1890
1891     code = ubik_EndTrans(tt);
1892     return code;
1893 }
1894
1895
1896 afs_int32
1897 SPR_ListSuperGroups(struct rx_call *call, afs_int32 aid, prlist *alist, 
1898                     afs_int32 *over)
1899 {
1900 #if defined(SUPERGROUPS)
1901     afs_int32 code;
1902     afs_int32 cid = ANONYMOUSID;
1903
1904     code = listSuperGroups(call, aid, alist, over, &cid);
1905     osi_auditU(call, PTS_LstSGrps, code, AUD_ID, aid, AUD_END);
1906     ViceLog(125, ("PTS_ListSuperGroups: code %d cid %d aid %d\n", code, cid, aid));
1907     return code;
1908 #else
1909     return RXGEN_OPCODE;
1910 #endif
1911 }
1912
1913 #if defined(SUPERGROUPS)
1914 static afs_int32
1915 listSuperGroups(struct rx_call *call, afs_int32 aid, prlist *alist, 
1916                 afs_int32 *over, afs_int32 *cid)
1917 {
1918     register afs_int32 code;
1919     struct ubik_trans *tt;
1920     afs_int32 temp;
1921     struct prentry tentry;
1922
1923     alist->prlist_len = 0;
1924     alist->prlist_val = (afs_int32 *) 0;
1925
1926     code = Initdb();
1927     if (code != PRSUCCESS)
1928         goto done;
1929     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1930     if (code)
1931         goto done;
1932     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1933     if (code)
1934         ABORT_WITH(tt, code);
1935     code = WhoIsThis(call, tt, cid);
1936     if (code)
1937         ABORT_WITH(tt, PRPERM);
1938
1939     temp = FindByID(tt, aid);
1940     if (!temp)
1941         ABORT_WITH(tt, PRNOENT);
1942     code = pr_ReadEntry(tt, 0, temp, &tentry);
1943     if (code)
1944         ABORT_WITH(tt, code);
1945     if (!AccessOK(tt, *cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
1946         ABORT_WITH(tt, PRPERM);
1947
1948     code = GetSGList(tt, &tentry, alist);
1949     *over = 0;
1950     if (code == PRTOOMANY)
1951         *over = 1;
1952     else if (code != PRSUCCESS)
1953         ABORT_WITH(tt, code);
1954
1955     code = ubik_EndTrans(tt);
1956
1957   done:
1958     return code;
1959 }
1960
1961 #endif /* SUPERGROUPS */
1962
1963 /* 
1964  * SPR_ListOwned
1965  * List the entries owned by this id.  If the id is zero,
1966  * return the orphans list. This will return up to PR_MAXGROUPS
1967  * at a time with the lastP available to get the rest. The
1968  * maximum value is enforced in GetOwnedChain().
1969  */
1970 afs_int32
1971 SPR_ListOwned(struct rx_call *call, afs_int32 aid, prlist *alist, 
1972               afs_int32 *lastP)
1973 {
1974     afs_int32 code;
1975     afs_int32 cid = ANONYMOUSID;
1976
1977     code = listOwned(call, aid, alist, lastP, &cid);
1978     osi_auditU(call, PTS_LstOwnEvent, code, AUD_ID, aid, AUD_END);
1979     ViceLog(125, ("PTS_ListOwned: code %d cid %d aid %d\n", code, cid, aid));
1980     return code;
1981 }
1982
1983 afs_int32
1984 listOwned(struct rx_call *call, afs_int32 aid, prlist *alist, afs_int32 *lastP, 
1985           afs_int32 *cid)
1986 {
1987     register afs_int32 code;
1988     struct ubik_trans *tt;
1989     struct prentry tentry;
1990     afs_int32 head = 0;
1991     afs_int32 start;
1992
1993     alist->prlist_len = 0;
1994     alist->prlist_val = NULL;
1995
1996     if (!lastP)
1997         return PRBADARG;
1998     start = *lastP;
1999     *lastP = 0;
2000
2001     code = Initdb();
2002     if (code != PRSUCCESS)
2003         return code;
2004     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2005     if (code)
2006         return code;
2007     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2008     if (code)
2009         ABORT_WITH(tt, code);
2010     code = read_DbHeader(tt);
2011     if (code)
2012         ABORT_WITH(tt, code);
2013
2014     code = WhoIsThis(call, tt, cid);
2015     if (code)
2016         ABORT_WITH(tt, PRPERM);
2017
2018     if (start) {
2019         code = pr_ReadEntry(tt, 0, start, &tentry);
2020         if (!code && (tentry.owner == aid))
2021             head = start;       /* pick up where we left off */
2022     }
2023
2024     if (!head) {
2025         if (aid) {
2026             afs_int32 loc = FindByID(tt, aid);
2027             if (loc == 0)
2028                 ABORT_WITH(tt, PRNOENT);
2029             code = pr_ReadEntry(tt, 0, loc, &tentry);
2030             if (code)
2031                 ABORT_WITH(tt, code);
2032
2033             if (!AccessOK(tt, *cid, &tentry, -1, PRP_OWNED_ANY))
2034                 ABORT_WITH(tt, PRPERM);
2035             head = tentry.owned;
2036         } else {
2037             if (!AccessOK(tt, *cid, 0, 0, 0))
2038                 ABORT_WITH(tt, PRPERM);
2039             head = ntohl(cheader.orphan);
2040         }
2041     }
2042
2043     code = GetOwnedChain(tt, &head, alist);
2044     if (code) {
2045         if (code == PRTOOMANY)
2046             *lastP = head;
2047         else
2048             ABORT_WITH(tt, code);
2049     }
2050
2051     code = ubik_EndTrans(tt);
2052     return code;
2053 }
2054
2055 afs_int32
2056 SPR_IsAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid, 
2057                 afs_int32 *flag)
2058 {
2059     afs_int32 code;
2060     afs_int32 cid = ANONYMOUSID;
2061
2062     code = isAMemberOf(call, uid, gid, flag, &cid);
2063     osi_auditU(call, PTS_IsMemOfEvent, code, AUD_LONG, uid, AUD_LONG, gid,
2064                AUD_END);
2065     ViceLog(125, ("PTS_IsAMemberOf: code %d cid %d uid %d gid %d\n", code, cid, uid, gid));
2066     return code;
2067 }
2068
2069 static afs_int32
2070 isAMemberOf(struct rx_call *call, afs_int32 uid, afs_int32 gid, afs_int32 *flag,
2071             afs_int32 *cid)
2072 {
2073     register afs_int32 code;
2074     struct ubik_trans *tt;
2075
2076     code = Initdb();
2077     if (code != PRSUCCESS)
2078         return code;
2079     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
2080     if (code)
2081         return code;
2082     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
2083     if (code)
2084         ABORT_WITH(tt, code);
2085     code = read_DbHeader(tt);
2086     if (code)
2087         ABORT_WITH(tt, code);
2088
2089     {
2090         afs_int32 uloc = FindByID(tt, uid);
2091         afs_int32 gloc = FindByID(tt, gid);
2092         struct prentry uentry, gentry;
2093
2094         if (!uloc || !gloc)
2095             ABORT_WITH(tt, PRNOENT);
2096         code = WhoIsThis(call, tt, cid);
2097         if (code)
2098             ABORT_WITH(tt, PRPERM);
2099         code = pr_ReadEntry(tt, 0, uloc, &uentry);
2100         if (code)
2101             ABORT_WITH(tt, code);
2102         code = pr_ReadEntry(tt, 0, gloc, &gentry);
2103         if (code)
2104             ABORT_WITH(tt, code);
2105 #if !defined(SUPERGROUPS)
2106         if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP))
2107             ABORT_WITH(tt, PRBADARG);
2108 #else
2109         if (!(gentry.flags & PRGRP))
2110             ABORT_WITH(tt, PRBADARG);
2111 #endif
2112         if (!AccessOK(tt, *cid, &uentry, 0, PRP_MEMBER_ANY)
2113             && !AccessOK(tt, *cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
2114             ABORT_WITH(tt, PRPERM);
2115     }
2116
2117     *flag = IsAMemberOf(tt, uid, gid);
2118     code = ubik_EndTrans(tt);
2119     return code;
2120 }
2121
2122 #if IP_WILDCARDS
2123 static afs_int32
2124 addWildCards(struct ubik_trans *tt, prlist *alist, afs_int32 host)
2125 {
2126     afs_int32 temp;
2127     struct prentry tentry;
2128     prlist wlist;
2129     unsigned wild = htonl(0xffffff00);
2130     struct in_addr iaddr;
2131     afs_int32 hostid;
2132     int size = 0, i, code;
2133     int added = 0;
2134
2135     while ((host = (host & wild))) {
2136         wild = htonl(ntohl(wild) << 8);
2137         iaddr.s_addr = host;
2138         code = NameToID(tt, inet_ntoa(iaddr), &hostid);
2139         if (code == PRSUCCESS && hostid != 0) {
2140             temp = FindByID(tt, hostid);
2141             if (temp) {
2142                 code = pr_ReadEntry(tt, 0, temp, &tentry);
2143                 if (code != PRSUCCESS)
2144                     continue;
2145             } else
2146                 continue;
2147         } else
2148             continue;
2149         wlist.prlist_len = 0;
2150         wlist.prlist_val = NULL;
2151
2152         code = GetList(tt, &tentry, &wlist, 0);
2153         if (code)
2154             return code;
2155         added += wlist.prlist_len;
2156         for (i = 0; i < wlist.prlist_len; i++) {
2157             if (!inCPS(*alist, wlist.prlist_val[i]))
2158                 if ((code = AddToPRList(alist, &size, wlist.prlist_val[i]))) {
2159                     free(wlist.prlist_val);
2160                     return (code);
2161                 }
2162         }
2163         if (wlist.prlist_val)
2164             free(wlist.prlist_val);
2165     }
2166     if (added)
2167         qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
2168     return 0;
2169 }
2170 #endif /* IP_WILDCARDS */
2171
2172 static afs_int32
2173 WhoIsThisWithName(struct rx_call *acall, struct ubik_trans *at, afs_int32 *aid, 
2174                   char *aname)
2175 {
2176     /* aid is set to the identity of the caller, if known, else ANONYMOUSID */
2177     /* returns -1 and sets aid to ANONYMOUSID on any failure */
2178     register struct rx_connection *tconn;
2179     register afs_int32 code;
2180     char tcell[MAXKTCREALMLEN];
2181     char name[MAXKTCNAMELEN];
2182     char inst[MAXKTCNAMELEN];
2183     int ilen;
2184     char vname[256];
2185
2186     *aid = ANONYMOUSID;
2187     tconn = rx_ConnectionOf(acall);
2188     code = rx_SecurityClassOf(tconn);
2189     if (code == 0)
2190         return 0;
2191     else if (code == 1) {       /* vab class */
2192         goto done;              /* no longer supported */
2193     } else if (code == 2) {     /* kad class */
2194
2195         int clen;
2196
2197         if ((code = rxkad_GetServerInfo(acall->conn, NULL, 0 /*was &exp */ ,
2198                                         name, inst, tcell, NULL)))
2199             goto done;
2200
2201
2202         strncpy(vname, name, sizeof(vname));
2203         if ((ilen = strlen(inst))) {
2204             if (strlen(vname) + 1 + ilen >= sizeof(vname))
2205                 goto done;
2206             strcat(vname, ".");
2207             strcat(vname, inst);
2208         }
2209         if ((clen = strlen(tcell))) {
2210             int foreign = afs_is_foreign_ticket_name(name,inst,tcell,pr_realmName);
2211
2212             if (foreign) {
2213                 if (strlen(vname) + 1 + clen >= sizeof(vname))
2214                     goto done;
2215                 strcat(vname, "@");
2216                 strcat(vname, tcell);
2217                 lcstring(vname, vname, sizeof(vname));
2218                 code = NameToID(at, vname, aid);
2219                 strcpy(aname, vname);
2220                 return 2;
2221             }
2222         }
2223
2224         if (strcmp(AUTH_SUPERUSER, vname) == 0)
2225             *aid = SYSADMINID;  /* special case for the fileserver */
2226         else {
2227             lcstring(vname, vname, sizeof(vname));
2228             code = NameToID(at, vname, aid);
2229         }
2230     }
2231   done:
2232     if (code && !pr_noAuth)
2233         return -1;
2234     return 0;
2235 }