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