63e57303a1b1695febea64ab261c09eecb58235d
[openafs.git] / src / ptserver / ptuser.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 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <rx/rx.h>
17 #include <rx/xdr.h>
18 #include <afs/auth.h>
19 #include <afs/cellconfig.h>
20 #include <afs/afsutil.h>
21 #include <afs/com_err.h>
22
23 #include "ptclient.h"
24 #include "ptuser.h"
25 #include "pterror.h"
26
27 #ifdef UKERNEL
28 # include "afs_usrops.h"
29 #endif
30
31 struct ubik_client *pruclient = 0;
32 static afs_int32 lastLevel;     /* security level pruclient, if any */
33
34 static char *whoami = "libprot";
35
36
37 #define ID_HASH_SIZE 1024
38 #define ID_STACK_SIZE 1024
39
40 /**
41  * Hash table chain of user and group ids.
42  */
43 struct idchain {
44     struct idchain *next;
45     afs_int32 id;
46 };
47
48 /**
49  * Hash table of user and group ids.
50  */
51 struct idhash {
52     afs_uint32 userEntries;         /**< number of user id entries hashed */
53     afs_uint32 groupEntries;        /**< number of group id entries hashed */
54     struct idchain *hash[ID_HASH_SIZE];
55 };
56
57 /**
58  * Allocate a new id hash table.
59  */
60 static afs_int32
61 AllocateIdHash(struct idhash **aidhash)
62 {
63     struct idhash *idhash;
64
65     idhash = (struct idhash *)malloc(sizeof(struct idhash));
66     if (!idhash) {
67        return ENOMEM;
68     }
69     memset((void *)idhash, 0, sizeof(struct idhash));
70     *aidhash = idhash;
71     return 0;
72 }
73
74 /**
75  * Free the id hash.
76  */
77 static void
78 FreeIdHash(struct idhash *idhash)
79 {
80     int index;
81     struct idchain *chain;
82     struct idchain *next;
83
84     for (index = 0; index < ID_HASH_SIZE; index++) {
85        for (chain = idhash->hash[index]; chain; chain = next) {
86            next = chain->next;
87            free(chain);
88        }
89     }
90     free(idhash);
91 }
92
93 /**
94  * Indicate if group/user id is already hashed, and
95  * if not insert it.
96  *
97  * @returns whether id is present
98  *   @retval >0 id is already present in the hash
99  *   @retval 0  id was not found and was inserted into the hash
100  *   @retval <0 error encountered
101  */
102 static afs_int32
103 FindId(struct idhash *idhash, afs_int32 id)
104 {
105     afs_int32 index;
106     struct idchain *chain;
107     struct idchain *newChain;
108
109     index = abs(id) % ID_HASH_SIZE;
110     for (chain = idhash->hash[index]; chain; chain = chain->next) {
111         if (chain->id == id) {
112             return 1;
113         }
114     }
115
116     /* Insert this id but return not found. */
117     newChain = (struct idchain *)malloc(sizeof(struct idchain));
118     if (!newChain) {
119         return ENOMEM;
120     } else {
121         newChain->id = id;
122         newChain->next = idhash->hash[index];
123         idhash->hash[index] = newChain;
124         if (id < 0) {
125             idhash->groupEntries++;
126         } else {
127             idhash->userEntries++;
128         }
129     }
130     return 0;
131 }
132
133 /**
134  * Create an idlist from the ids in the hash.
135  */
136 static afs_int32
137 CreateIdList(struct idhash *idhash, idlist * alist, afs_int32 select)
138 {
139     struct idchain *chain;
140     afs_int32 entries = 0;
141     int index;
142     int i;
143
144     if (select & PRGROUPS) {
145         entries += idhash->groupEntries;
146     }
147     if (select & PRUSERS) {
148         entries += idhash->userEntries;
149     }
150
151     alist->idlist_len = entries;
152     alist->idlist_val = (afs_int32 *) malloc(sizeof(afs_int32) * entries);
153     if (!alist->idlist_val) {
154         return ENOMEM;
155     }
156
157     for (i = 0, index = 0; index < ID_HASH_SIZE; index++) {
158         for (chain = idhash->hash[index]; chain; chain = chain->next) {
159             if (chain->id < 0) {
160                 if (select & PRGROUPS) {
161                     alist->idlist_val[i++] = chain->id;
162                 }
163             } else {
164                 if (select & PRUSERS) {
165                     alist->idlist_val[i++] = chain->id;
166                 }
167             }
168         }
169     }
170     return 0;
171 }
172
173 afs_int32
174 pr_Initialize(IN afs_int32 secLevel, IN const char *confDir, IN char *cell)
175 {
176     afs_int32 code;
177     struct rx_connection *serverconns[MAXSERVERS];
178     struct rx_securityClass *sc = NULL;
179     static struct afsconf_dir *tdir = (struct afsconf_dir *)NULL;       /* only do this once */
180     static char tconfDir[100] = "";
181     static char tcell[64] = "";
182     afs_int32 scIndex;
183     afs_int32 secFlags;
184     static struct afsconf_cell info;
185     afs_int32 i;
186 #if !defined(UKERNEL)
187     char cellstr[64];
188 #endif
189     afs_int32 gottdir = 0;
190     afs_int32 refresh = 0;
191
192     initialize_PT_error_table();
193     initialize_RXK_error_table();
194     initialize_ACFG_error_table();
195     initialize_KTC_error_table();
196
197 #if defined(UKERNEL)
198     if (!cell) {
199         cell = afs_LclCellName;
200     }
201 #else /* defined(UKERNEL) */
202     if (!cell) {
203         if (!tdir)
204             tdir = afsconf_Open(confDir);
205         if (!tdir) {
206             if (confDir && strcmp(confDir, ""))
207                 fprintf(stderr,
208                         "%s: Could not open configuration directory: %s.\n",
209                         whoami, confDir);
210             else
211                 fprintf(stderr,
212                         "%s: No configuration directory specified.\n",
213                         whoami);
214             return -1;
215         }
216         gottdir = 1;
217
218         code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
219         if (code) {
220             fprintf(stderr,
221                      "libprot: Could not get local cell. [%d]\n", code);
222             return code;
223         }
224         cell = cellstr;
225     }
226 #endif /* defined(UKERNEL) */
227
228     if (tdir == NULL || strcmp(confDir, tconfDir) || strcmp(cell, tcell)) {
229         /*
230          * force re-evaluation.  we either don't have an afsconf_dir,
231          * the directory has changed or the cell has changed.
232          */
233         if (tdir && !gottdir) {
234             afsconf_Close(tdir);
235             tdir = (struct afsconf_dir *)NULL;
236         }
237         pruclient = (struct ubik_client *)NULL;
238         refresh = 1;
239     }
240
241     if (refresh) {
242         strncpy(tconfDir, confDir, sizeof(tconfDir));
243         strncpy(tcell, cell, sizeof(tcell));
244
245 #if defined(UKERNEL)
246         tdir = afs_cdir;
247 #else /* defined(UKERNEL) */
248         if (!gottdir)
249             tdir = afsconf_Open(confDir);
250         if (!tdir) {
251             if (confDir && strcmp(confDir, ""))
252                 fprintf(stderr,
253                         "libprot: Could not open configuration directory: %s.\n",
254                         confDir);
255             else
256                 fprintf(stderr,
257                         "libprot: No configuration directory specified.\n");
258             return -1;
259         }
260 #endif /* defined(UKERNEL) */
261
262         code = afsconf_GetCellInfo(tdir, cell, "afsprot", &info);
263         if (code) {
264             fprintf(stderr, "libprot: Could not locate cell %s in %s/%s\n",
265                     cell, confDir, AFSDIR_CELLSERVDB_FILE);
266             return code;
267         }
268     }
269
270     /* If we already have a client and it is at the security level we
271      * want, don't get a new one. Unless the security level is 2 in
272      * which case we will get one (and re-read the key file).
273      */
274     if (pruclient && (lastLevel == secLevel) && (secLevel != 2)) {
275         return 0;
276     }
277
278     code = rx_Init(0);
279     if (code) {
280         fprintf(stderr, "libprot:  Could not initialize rx.\n");
281         return code;
282     }
283
284     /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
285      * to force use of the KeyFile.  secLevel == 0 implies -noauth was
286      * specified. */
287     if (secLevel == 2) {
288         /* If secLevel is two assume we're on a file server and use
289          * ClientAuthSecure if possible. */
290         code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
291         if (code)
292             afs_com_err(whoami, code, "(calling client secure)\n");
293     } else if (secLevel > 0) {
294         secFlags = 0;
295         if (secLevel > 1)
296             secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
297
298         code = afsconf_ClientAuthToken(&info, secFlags, &sc, &scIndex, NULL);
299         if (code) {
300             afs_com_err(whoami, code, "(getting token)");
301             if (secLevel > 1)
302                 return code;
303         }
304     }
305
306     if (sc == NULL) {
307         sc = rxnull_NewClientSecurityObject();
308         scIndex = RX_SECIDX_NULL;
309     }
310
311     if ((scIndex == RX_SECIDX_NULL) && (secLevel != 0))
312         fprintf(stderr,
313                 "%s: Could not get afs tokens, running unauthenticated\n",
314                 whoami);
315
316     memset(serverconns, 0, sizeof(serverconns));        /* terminate list!!! */
317     for (i = 0; i < info.numServers; i++)
318         serverconns[i] =
319             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
320                              info.hostAddr[i].sin_port, PRSRV, sc,
321                              scIndex);
322
323     code = ubik_ClientInit(serverconns, &pruclient);
324     if (code) {
325         afs_com_err(whoami, code, "ubik client init failed.");
326         return code;
327     }
328     lastLevel = scIndex;
329
330     code = rxs_Release(sc);
331     return code;
332 }
333
334 int
335 pr_End(void)
336 {
337     int code = 0;
338
339     if (pruclient) {
340         code = ubik_ClientDestroy(pruclient);
341         pruclient = 0;
342     }
343     return code;
344 }
345
346
347
348 int
349 pr_CreateUser(char name[PR_MAXNAMELEN], afs_int32 *id)
350 {
351     afs_int32 code;
352
353     stolower(name);
354     if (*id) {
355         code = ubik_PR_INewEntry(pruclient, 0, name, *id, 0);
356         return code;
357     } else {
358         code = ubik_PR_NewEntry(pruclient, 0, name, 0, 0, id);
359         return code;
360     }
361
362 }
363
364 int
365 pr_CreateGroup(char name[PR_MAXNAMELEN], char owner[PR_MAXNAMELEN], afs_int32 *id)
366 {
367     afs_int32 code;
368     afs_int32 oid = 0;
369     afs_int32 flags = 0;
370
371     stolower(name);
372     if (owner) {
373         code = pr_SNameToId(owner, &oid);
374         if (code)
375             return code;
376         if (oid == ANONYMOUSID)
377             return PRNOENT;
378     }
379     flags |= PRGRP;
380     if (*id) {
381         code = ubik_PR_INewEntry(pruclient, 0, name, *id, oid);
382         return code;
383     } else {
384         code = ubik_PR_NewEntry(pruclient, 0, name, flags, oid, id);
385         return code;
386     }
387 }
388
389 int
390 pr_Delete(char *name)
391 {
392     afs_int32 code;
393     afs_int32 id;
394
395     stolower(name);
396     code = pr_SNameToId(name, &id);
397     if (code)
398         return code;
399     if (id == ANONYMOUSID)
400         return PRNOENT;
401     code = ubik_PR_Delete(pruclient, 0, id);
402     return code;
403 }
404
405 int
406 pr_DeleteByID(afs_int32 id)
407 {
408     afs_int32 code;
409
410     code = ubik_PR_Delete(pruclient, 0, id);
411     return code;
412 }
413
414 int
415 pr_AddToGroup(char *user, char *group)
416 {
417     afs_int32 code;
418     namelist lnames;
419     idlist lids;
420
421     lnames.namelist_len = 2;
422     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
423     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
424     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
425     lids.idlist_val = 0;
426     lids.idlist_len = 0;
427     code = pr_NameToId(&lnames, &lids);
428     if (code)
429         goto done;
430     /* if here, still could be missing an entry */
431     if (lids.idlist_val[0] == ANONYMOUSID
432         || lids.idlist_val[1] == ANONYMOUSID) {
433         code = PRNOENT;
434         goto done;
435     }
436     code =
437         ubik_PR_AddToGroup(pruclient, 0, lids.idlist_val[0],
438                   lids.idlist_val[1]);
439   done:
440     if (lnames.namelist_val)
441         free(lnames.namelist_val);
442
443     xdr_free((xdrproc_t) xdr_idlist, &lids);
444     return code;
445 }
446
447 int
448 pr_RemoveUserFromGroup(char *user, char *group)
449 {
450     afs_int32 code;
451     namelist lnames;
452     idlist lids;
453
454     lnames.namelist_len = 2;
455     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
456     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
457     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
458     lids.idlist_val = 0;
459     lids.idlist_len = 0;
460     code = pr_NameToId(&lnames, &lids);
461     if (code)
462         goto done;
463
464     if (lids.idlist_val[0] == ANONYMOUSID
465         || lids.idlist_val[1] == ANONYMOUSID) {
466         code = PRNOENT;
467         goto done;
468     }
469     code =
470         ubik_PR_RemoveFromGroup(pruclient, 0, lids.idlist_val[0],
471                   lids.idlist_val[1]);
472   done:
473     if (lnames.namelist_val)
474         free(lnames.namelist_val);
475
476     xdr_free((xdrproc_t) xdr_idlist, &lids);
477
478     return code;
479 }
480
481 int
482 pr_NameToId(namelist *names, idlist *ids)
483 {
484     afs_int32 code;
485     afs_int32 i;
486
487     for (i = 0; i < names->namelist_len; i++)
488         stolower(names->namelist_val[i]);
489     code = ubik_PR_NameToID(pruclient, 0, names, ids);
490     return code;
491 }
492
493 int
494 pr_SNameToId(char name[PR_MAXNAMELEN], afs_int32 *id)
495 {
496     namelist lnames;
497     idlist lids;
498     afs_int32 code;
499
500     lids.idlist_len = 0;
501     lids.idlist_val = 0;
502     lnames.namelist_len = 1;
503     lnames.namelist_val = malloc(PR_MAXNAMELEN);
504     stolower(name);
505     strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN);
506     code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
507     if (lids.idlist_val) {
508         *id = *lids.idlist_val;
509         xdr_free((xdrproc_t) xdr_idlist, &lids);
510     }
511     if (lnames.namelist_val)
512         free(lnames.namelist_val);
513     return code;
514 }
515
516 int
517 pr_IdToName(idlist *ids, namelist *names)
518 {
519     afs_int32 code;
520
521     code = ubik_PR_IDToName(pruclient, 0, ids, names);
522     return code;
523 }
524
525 int
526 pr_SIdToName(afs_int32 id, char name[PR_MAXNAMELEN])
527 {
528     namelist lnames;
529     idlist lids;
530     afs_int32 code;
531
532     lids.idlist_len = 1;
533     lids.idlist_val = malloc(sizeof(afs_int32));
534     *lids.idlist_val = id;
535     lnames.namelist_len = 0;
536     lnames.namelist_val = 0;
537     code = ubik_PR_IDToName(pruclient, 0, &lids, &lnames);
538
539     if (lnames.namelist_val)
540         strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN);
541
542     if (lids.idlist_val)
543         free(lids.idlist_val);
544
545     xdr_free((xdrproc_t) xdr_namelist, &lnames);
546
547     return code;
548 }
549
550 int
551 pr_GetCPS(afs_int32 id, prlist *CPS)
552 {
553     afs_int32 code;
554     afs_int32 over;
555
556     over = 0;
557     code = ubik_PR_GetCPS(pruclient, 0, id, CPS, &over);
558     if (code != PRSUCCESS)
559         return code;
560     if (over) {
561         /* do something about this, probably make a new call */
562         /* don't forget there's a hard limit in the interface */
563         fprintf(stderr, "membership list for id %d exceeds display limit\n",
564                 id);
565     }
566     return 0;
567 }
568
569 int
570 pr_GetCPS2(afs_int32 id, afs_uint32 host, prlist *CPS)
571 {
572     afs_int32 code;
573     afs_int32 over;
574
575     over = 0;
576     code = ubik_PR_GetCPS2(pruclient, 0, id, host, CPS, &over);
577     if (code != PRSUCCESS)
578         return code;
579     if (over) {
580         /* do something about this, probably make a new call */
581         /* don't forget there's a hard limit in the interface */
582         fprintf(stderr, "membership list for id %d exceeds display limit\n",
583                 id);
584     }
585     return 0;
586 }
587
588 int
589 pr_GetHostCPS(afs_uint32 host, prlist *CPS)
590 {
591     afs_int32 code;
592     afs_int32 over;
593
594     over = 0;
595     code = ubik_PR_GetHostCPS(pruclient, 0, host, CPS, &over);
596     if (code != PRSUCCESS)
597         return code;
598     if (over) {
599         /* do something about this, probably make a new call */
600         /* don't forget there's a hard limit in the interface */
601         fprintf(stderr,
602                 "membership list for host id %d exceeds display limit\n",
603                 host);
604     }
605     return 0;
606 }
607
608 int
609 pr_ListMembers(char *group, namelist *lnames)
610 {
611     afs_int32 code;
612     afs_int32 gid;
613
614     code = pr_SNameToId(group, &gid);
615     if (code)
616         return code;
617     if (gid == ANONYMOUSID)
618         return PRNOENT;
619     code = pr_IDListMembers(gid, lnames);
620     return code;
621 }
622
623 int
624 pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP)
625 {
626     afs_int32 code;
627     prlist alist;
628     idlist *lids;
629
630     alist.prlist_len = 0;
631     alist.prlist_val = 0;
632     code = ubik_PR_ListOwned(pruclient, 0, oid, &alist, moreP);
633     if (code)
634         return code;
635     if (*moreP == 1) {
636         /* Remain backwards compatible when moreP was a T/F bit */
637         fprintf(stderr, "membership list for id %d exceeds display limit\n",
638                 oid);
639         *moreP = 0;
640     }
641     lids = (idlist *) &alist;
642     code = pr_IdToName(lids, lnames);
643
644     xdr_free((xdrproc_t) xdr_prlist, &alist);
645
646     if (code)
647         return code;
648
649     return PRSUCCESS;
650 }
651
652 int
653 pr_IDListMembers(afs_int32 gid, namelist *lnames)
654 {
655     afs_int32 code;
656     prlist alist;
657     idlist *lids;
658     afs_int32 over;
659
660     alist.prlist_len = 0;
661     alist.prlist_val = 0;
662     code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
663     if (code)
664         return code;
665     if (over) {
666         fprintf(stderr, "membership list for id %d exceeds display limit\n",
667                 gid);
668     }
669     lids = (idlist *) &alist;
670     code = pr_IdToName(lids, lnames);
671
672     xdr_free((xdrproc_t) xdr_prlist, &alist);
673
674     if (code)
675         return code;
676     return PRSUCCESS;
677 }
678
679 int
680 pr_IDListExpandedMembers(afs_int32 aid, namelist * lnames)
681 {
682     afs_int32 code;
683     afs_int32 gid;
684     idlist lids;
685     prlist alist;
686     afs_int32 over;
687     struct idhash *members = NULL;
688     afs_int32 *stack = NULL;
689     afs_int32 maxstack = ID_STACK_SIZE;
690     int n = 0;                  /* number of ids stacked */
691     int i;
692     int firstpass = 1;
693
694     code = AllocateIdHash(&members);
695     if (code) {
696         return code;
697     }
698     stack = (afs_int32 *) malloc(sizeof(afs_int32) * maxstack);
699     if (!stack) {
700         code = ENOMEM;
701         goto done;
702     }
703
704     stack[n++] = aid;
705     while (n) {
706         gid = stack[--n];       /* pop next group id */
707         alist.prlist_len = 0;
708         alist.prlist_val = NULL;
709         if (firstpass || aid < 0) {
710             firstpass = 0;
711             code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
712         } else {
713             code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
714             if (code == RXGEN_OPCODE) {
715                 alist.prlist_len = 0;
716                 alist.prlist_val = NULL;
717                 code = 0; /* server does not support supergroups. */
718             }
719         }
720         if (code)
721             goto done;
722         if (over) {
723             fprintf(stderr,
724                     "membership list for id %d exceeds display limit\n", gid);
725         }
726         for (i = 0; i < alist.prlist_len; i++) {
727             afs_int32 found;
728             afs_int32 id;
729
730             id = alist.prlist_val[i];
731             found = FindId(members, id);
732             if (found < 0) {
733                 code = found;
734                 xdr_free((xdrproc_t) xdr_prlist, &alist);
735                 goto done;
736             }
737             if (found == 0 && id < 0) {
738                 if (n == maxstack) {    /* need more stack space */
739                     afs_int32 *tmp;
740                     maxstack += n;
741                     tmp =
742                         (afs_int32 *) realloc(stack,
743                                               maxstack * sizeof(afs_int32));
744                     if (!tmp) {
745                         code = ENOMEM;
746                         xdr_free((xdrproc_t) xdr_prlist, &alist);
747                         goto done;
748                     }
749                     stack = tmp;
750                 }
751                 stack[n++] = id;        /* push group id */
752             }
753         }
754         xdr_free((xdrproc_t) xdr_prlist, &alist);
755     }
756
757     code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS));
758     if (code) {
759         goto done;
760     }
761     code = pr_IdToName(&lids, lnames);
762     if (lids.idlist_len)
763         free(lids.idlist_val);
764
765   done:
766     if (stack)
767         free(stack);
768     if (members)
769         FreeIdHash(members);
770     return code;
771 }
772
773 int
774 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
775 {
776     afs_int32 code;
777
778     code = ubik_PR_ListEntry(pruclient, 0, id, aentry);
779     return code;
780 }
781
782 afs_int32
783 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
784 {
785     afs_int32 code;
786     prentries bulkentries;
787
788     *nentries = 0;
789     *entries = NULL;
790     *nextstartindex = -1;
791     bulkentries.prentries_val = 0;
792     bulkentries.prentries_len = 0;
793
794     code =
795         ubik_PR_ListEntries(pruclient, 0, flag, startindex,
796                   &bulkentries, nextstartindex);
797     *nentries = bulkentries.prentries_len;
798     *entries = bulkentries.prentries_val;
799     return code;
800 }
801
802 int
803 pr_CheckEntryByName(char *name, afs_int32 *id, char *owner, char *creator)
804 {
805     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
806     afs_int32 code;
807     struct prcheckentry aentry;
808
809     code = pr_SNameToId(name, id);
810     if (code)
811         return code;
812     if (*id == ANONYMOUSID)
813         return PRNOENT;
814     code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry);
815     if (code)
816         return code;
817     /* this should be done in one RPC, but I'm lazy. */
818     code = pr_SIdToName(aentry.owner, owner);
819     if (code)
820         return code;
821     code = pr_SIdToName(aentry.creator, creator);
822     if (code)
823         return code;
824     return PRSUCCESS;
825 }
826
827 int
828 pr_CheckEntryById(char *name, afs_int32 id, char *owner, char *creator)
829 {
830     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
831     afs_int32 code;
832     struct prcheckentry aentry;
833
834     code = pr_SIdToName(id, name);
835     if (code)
836         return code;
837     if (id == ANONYMOUSID)
838         return PRNOENT;
839     code = ubik_PR_ListEntry(pruclient, 0, id, &aentry);
840     if (code)
841         return code;
842     /* this should be done in one RPC, but I'm lazy. */
843     code = pr_SIdToName(aentry.owner, owner);
844     if (code)
845         return code;
846     code = pr_SIdToName(aentry.creator, creator);
847     if (code)
848         return code;
849     return PRSUCCESS;
850 }
851
852 int
853 pr_ChangeEntry(char *oldname, char *newname, afs_int32 *newid, char *newowner)
854 {
855     afs_int32 code;
856     afs_int32 id;
857     afs_int32 oid = 0;
858
859     code = pr_SNameToId(oldname, &id);
860     if (code)
861         return code;
862     if (id == ANONYMOUSID)
863         return PRNOENT;
864     if (newowner && *newowner) {
865         code = pr_SNameToId(newowner, &oid);
866         if (code)
867             return code;
868         if (oid == ANONYMOUSID)
869             return PRNOENT;
870     }
871     if (newid)
872         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid);
873     else
874         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0);
875     return code;
876 }
877
878 int
879 pr_IsAMemberOf(char *uname, char *gname, afs_int32 *flag)
880 {
881     afs_int32 code;
882     namelist lnames;
883     idlist lids;
884
885     stolower(uname);
886     stolower(gname);
887     lnames.namelist_len = 2;
888     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
889     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
890     strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
891     lids.idlist_val = 0;
892     lids.idlist_len = 0;
893     code = pr_NameToId(&lnames, &lids);
894     if (code) {
895         if (lnames.namelist_val)
896             free(lnames.namelist_val);
897         xdr_free((xdrproc_t) xdr_idlist, &lids);
898         return code;
899     }
900     code =
901         ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0],
902                   lids.idlist_val[1], flag);
903     if (lnames.namelist_val)
904         free(lnames.namelist_val);
905     xdr_free((xdrproc_t) xdr_idlist, &lids);
906     return code;
907 }
908
909 int
910 pr_ListMaxUserId(afs_int32 *mid)
911 {
912     afs_int32 code;
913     afs_int32 gid;
914     code = ubik_PR_ListMax(pruclient, 0, mid, &gid);
915     return code;
916 }
917
918 int
919 pr_SetMaxUserId(afs_int32 mid)
920 {
921     afs_int32 code;
922     afs_int32 flag = 0;
923     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
924     return code;
925 }
926
927 int
928 pr_ListMaxGroupId(afs_int32 *mid)
929 {
930     afs_int32 code;
931     afs_int32 id;
932     code = ubik_PR_ListMax(pruclient, 0, &id, mid);
933     return code;
934 }
935
936 int
937 pr_SetMaxGroupId(afs_int32 mid)
938 {
939     afs_int32 code;
940     afs_int32 flag = 0;
941
942     flag |= PRGRP;
943     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
944     return code;
945 }
946
947 afs_int32
948 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
949 {
950     afs_int32 code;
951
952     code =
953         ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups,
954                   nusers, 0, 0);
955     return code;
956 }
957
958 int
959 pr_ListSuperGroups(afs_int32 gid, namelist * lnames)
960 {
961     afs_int32 code;
962     prlist alist;
963     idlist *lids;
964     afs_int32 over;
965
966     alist.prlist_len = 0;
967     alist.prlist_val = 0;
968     code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
969     if (code)
970         return code;
971     if (over) {
972         fprintf(stderr, "supergroup list for id %d exceeds display limit\n",
973                 gid);
974     }
975     lids = (idlist *) & alist;
976     code = pr_IdToName(lids, lnames);
977
978     xdr_free((xdrproc_t) xdr_prlist, &alist);
979     return code;
980 }