Don't cast the return from realloc()
[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 #include <afs/opr.h>
16
17 #include <rx/rx.h>
18 #include <rx/xdr.h>
19 #include <afs/auth.h>
20 #include <afs/cellconfig.h>
21 #include <afs/afsutil.h>
22 #include <afs/com_err.h>
23
24 #include "ptclient.h"
25 #include "ptuser.h"
26 #include "pterror.h"
27
28 #ifdef UKERNEL
29 # include "afs_usrops.h"
30 #endif
31
32 struct ubik_client *pruclient = 0;
33 static afs_int32 lastLevel;     /* security level pruclient, if any */
34
35 static char *whoami = "libprot";
36
37
38 #define ID_HASH_SIZE 1024
39 #define ID_STACK_SIZE 1024
40
41 /**
42  * Hash table chain of user and group ids.
43  */
44 struct idchain {
45     struct idchain *next;
46     afs_int32 id;
47 };
48
49 /**
50  * Hash table of user and group ids.
51  */
52 struct idhash {
53     afs_uint32 userEntries;         /**< number of user id entries hashed */
54     afs_uint32 groupEntries;        /**< number of group id entries hashed */
55     struct idchain *hash[ID_HASH_SIZE];
56 };
57
58 /**
59  * Allocate a new id hash table.
60  */
61 static afs_int32
62 AllocateIdHash(struct idhash **aidhash)
63 {
64     struct idhash *idhash;
65
66     idhash = calloc(1, sizeof(struct idhash));
67     if (!idhash) {
68        return ENOMEM;
69     }
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 = realloc(stack, maxstack * sizeof(afs_int32));
742                     if (!tmp) {
743                         code = ENOMEM;
744                         xdr_free((xdrproc_t) xdr_prlist, &alist);
745                         goto done;
746                     }
747                     stack = tmp;
748                 }
749                 stack[n++] = id;        /* push group id */
750             }
751         }
752         xdr_free((xdrproc_t) xdr_prlist, &alist);
753     }
754
755     code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS));
756     if (code) {
757         goto done;
758     }
759     code = pr_IdToName(&lids, lnames);
760     if (lids.idlist_len)
761         free(lids.idlist_val);
762
763   done:
764     if (stack)
765         free(stack);
766     if (members)
767         FreeIdHash(members);
768     return code;
769 }
770
771 int
772 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
773 {
774     afs_int32 code;
775
776     code = ubik_PR_ListEntry(pruclient, 0, id, aentry);
777     return code;
778 }
779
780 afs_int32
781 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
782 {
783     afs_int32 code;
784     prentries bulkentries;
785
786     *nentries = 0;
787     *entries = NULL;
788     *nextstartindex = -1;
789     bulkentries.prentries_val = 0;
790     bulkentries.prentries_len = 0;
791
792     code =
793         ubik_PR_ListEntries(pruclient, 0, flag, startindex,
794                   &bulkentries, nextstartindex);
795     *nentries = bulkentries.prentries_len;
796     *entries = bulkentries.prentries_val;
797     return code;
798 }
799
800 int
801 pr_CheckEntryByName(char *name, afs_int32 *id, char *owner, char *creator)
802 {
803     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
804     afs_int32 code;
805     struct prcheckentry aentry;
806
807     code = pr_SNameToId(name, id);
808     if (code)
809         return code;
810     if (*id == ANONYMOUSID)
811         return PRNOENT;
812     code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry);
813     if (code)
814         return code;
815     /* this should be done in one RPC, but I'm lazy. */
816     code = pr_SIdToName(aentry.owner, owner);
817     if (code)
818         return code;
819     code = pr_SIdToName(aentry.creator, creator);
820     if (code)
821         return code;
822     return PRSUCCESS;
823 }
824
825 int
826 pr_CheckEntryById(char *name, afs_int32 id, char *owner, char *creator)
827 {
828     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
829     afs_int32 code;
830     struct prcheckentry aentry;
831
832     code = pr_SIdToName(id, name);
833     if (code)
834         return code;
835     if (id == ANONYMOUSID)
836         return PRNOENT;
837     code = ubik_PR_ListEntry(pruclient, 0, id, &aentry);
838     if (code)
839         return code;
840     /* this should be done in one RPC, but I'm lazy. */
841     code = pr_SIdToName(aentry.owner, owner);
842     if (code)
843         return code;
844     code = pr_SIdToName(aentry.creator, creator);
845     if (code)
846         return code;
847     return PRSUCCESS;
848 }
849
850 int
851 pr_ChangeEntry(char *oldname, char *newname, afs_int32 *newid, char *newowner)
852 {
853     afs_int32 code;
854     afs_int32 id;
855     afs_int32 oid = 0;
856
857     code = pr_SNameToId(oldname, &id);
858     if (code)
859         return code;
860     if (id == ANONYMOUSID)
861         return PRNOENT;
862     if (newowner && *newowner) {
863         code = pr_SNameToId(newowner, &oid);
864         if (code)
865             return code;
866         if (oid == ANONYMOUSID)
867             return PRNOENT;
868     }
869     if (newid)
870         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid);
871     else
872         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0);
873     return code;
874 }
875
876 int
877 pr_IsAMemberOf(char *uname, char *gname, afs_int32 *flag)
878 {
879     afs_int32 code;
880     namelist lnames;
881     idlist lids;
882
883     stolower(uname);
884     stolower(gname);
885     lnames.namelist_len = 2;
886     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
887     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
888     strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
889     lids.idlist_val = 0;
890     lids.idlist_len = 0;
891     code = pr_NameToId(&lnames, &lids);
892     if (code) {
893         if (lnames.namelist_val)
894             free(lnames.namelist_val);
895         xdr_free((xdrproc_t) xdr_idlist, &lids);
896         return code;
897     }
898     code =
899         ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0],
900                   lids.idlist_val[1], flag);
901     if (lnames.namelist_val)
902         free(lnames.namelist_val);
903     xdr_free((xdrproc_t) xdr_idlist, &lids);
904     return code;
905 }
906
907 int
908 pr_ListMaxUserId(afs_int32 *mid)
909 {
910     afs_int32 code;
911     afs_int32 gid;
912     code = ubik_PR_ListMax(pruclient, 0, mid, &gid);
913     return code;
914 }
915
916 int
917 pr_SetMaxUserId(afs_int32 mid)
918 {
919     afs_int32 code;
920     afs_int32 flag = 0;
921     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
922     return code;
923 }
924
925 int
926 pr_ListMaxGroupId(afs_int32 *mid)
927 {
928     afs_int32 code;
929     afs_int32 id;
930     code = ubik_PR_ListMax(pruclient, 0, &id, mid);
931     return code;
932 }
933
934 int
935 pr_SetMaxGroupId(afs_int32 mid)
936 {
937     afs_int32 code;
938     afs_int32 flag = 0;
939
940     flag |= PRGRP;
941     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
942     return code;
943 }
944
945 afs_int32
946 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
947 {
948     afs_int32 code;
949
950     code =
951         ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups,
952                   nusers, 0, 0);
953     return code;
954 }
955
956 int
957 pr_ListSuperGroups(afs_int32 gid, namelist * lnames)
958 {
959     afs_int32 code;
960     prlist alist;
961     idlist *lids;
962     afs_int32 over;
963
964     alist.prlist_len = 0;
965     alist.prlist_val = 0;
966     code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
967     if (code)
968         return code;
969     if (over) {
970         fprintf(stderr, "supergroup list for id %d exceeds display limit\n",
971                 gid);
972     }
973     lids = (idlist *) & alist;
974     code = pr_IdToName(lids, lnames);
975
976     xdr_free((xdrproc_t) xdr_prlist, &alist);
977     return code;
978 }