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