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