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