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