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