0ac9049bbfb8e599c544c32a059b08941181b5e9
[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         /* If secLevel is two assume we're on a file server and use
298          * ClientAuthSecure if possible. */
299         code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
300         if (code)
301             afs_com_err(whoami, code, "(calling client secure)\n");
302     } else if (secLevel > 0) {
303         secFlags = 0;
304         if (secLevel > 1)
305             secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
306
307         code = afsconf_ClientAuthToken(&info, secFlags, &sc, &scIndex, NULL);
308         if (code) {
309             afs_com_err(whoami, code, "(getting token)");
310             if (secLevel > 1)
311                 return code;
312         }
313     }
314
315     if (sc == NULL) {
316         sc = rxnull_NewClientSecurityObject();
317         scIndex = RX_SECIDX_NULL;
318     }
319
320     if ((scIndex == RX_SECIDX_NULL) && (secLevel != 0))
321         fprintf(stderr,
322                 "%s: Could not get afs tokens, running unauthenticated\n",
323                 whoami);
324
325     memset(serverconns, 0, sizeof(serverconns));        /* terminate list!!! */
326     for (i = 0; i < info.numServers; i++)
327         serverconns[i] =
328             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
329                              info.hostAddr[i].sin_port, PRSRV, sc,
330                              scIndex);
331
332     code = ubik_ClientInit(serverconns, &pruclient);
333     if (code) {
334         afs_com_err(whoami, code, "ubik client init failed.");
335         return code;
336     }
337     lastLevel = scIndex;
338
339     code = rxs_Release(sc);
340     return code;
341 }
342
343 int
344 pr_End(void)
345 {
346     int code = 0;
347
348     if (pruclient) {
349         code = ubik_ClientDestroy(pruclient);
350         pruclient = 0;
351     }
352     return code;
353 }
354
355
356
357 int
358 pr_CreateUser(char name[PR_MAXNAMELEN], afs_int32 *id)
359 {
360     afs_int32 code;
361
362     stolower(name);
363     if (*id) {
364         code = ubik_PR_INewEntry(pruclient, 0, name, *id, 0);
365         return code;
366     } else {
367         code = ubik_PR_NewEntry(pruclient, 0, name, 0, 0, id);
368         return code;
369     }
370
371 }
372
373 int
374 pr_CreateGroup(char name[PR_MAXNAMELEN], char owner[PR_MAXNAMELEN], afs_int32 *id)
375 {
376     afs_int32 code;
377     afs_int32 oid = 0;
378     afs_int32 flags = 0;
379
380     stolower(name);
381     if (owner) {
382         code = pr_SNameToId(owner, &oid);
383         if (code)
384             return code;
385         if (oid == ANONYMOUSID)
386             return PRNOENT;
387     }
388     flags |= PRGRP;
389     if (*id) {
390         code = ubik_PR_INewEntry(pruclient, 0, name, *id, oid);
391         return code;
392     } else {
393         code = ubik_PR_NewEntry(pruclient, 0, name, flags, oid, id);
394         return code;
395     }
396 }
397
398 int
399 pr_Delete(char *name)
400 {
401     afs_int32 code;
402     afs_int32 id;
403
404     stolower(name);
405     code = pr_SNameToId(name, &id);
406     if (code)
407         return code;
408     if (id == ANONYMOUSID)
409         return PRNOENT;
410     code = ubik_PR_Delete(pruclient, 0, id);
411     return code;
412 }
413
414 int
415 pr_DeleteByID(afs_int32 id)
416 {
417     afs_int32 code;
418
419     code = ubik_PR_Delete(pruclient, 0, id);
420     return code;
421 }
422
423 int
424 pr_AddToGroup(char *user, char *group)
425 {
426     afs_int32 code;
427     namelist lnames;
428     idlist lids;
429
430     lnames.namelist_len = 2;
431     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
432     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
433     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
434     lids.idlist_val = 0;
435     lids.idlist_len = 0;
436     code = pr_NameToId(&lnames, &lids);
437     if (code)
438         goto done;
439     /* if here, still could be missing an entry */
440     if (lids.idlist_val[0] == ANONYMOUSID
441         || lids.idlist_val[1] == ANONYMOUSID) {
442         code = PRNOENT;
443         goto done;
444     }
445     code =
446         ubik_PR_AddToGroup(pruclient, 0, lids.idlist_val[0],
447                   lids.idlist_val[1]);
448   done:
449     if (lnames.namelist_val)
450         free(lnames.namelist_val);
451
452     xdr_free((xdrproc_t) xdr_idlist, &lids);
453     return code;
454 }
455
456 int
457 pr_RemoveUserFromGroup(char *user, char *group)
458 {
459     afs_int32 code;
460     namelist lnames;
461     idlist lids;
462
463     lnames.namelist_len = 2;
464     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
465     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
466     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
467     lids.idlist_val = 0;
468     lids.idlist_len = 0;
469     code = pr_NameToId(&lnames, &lids);
470     if (code)
471         goto done;
472
473     if (lids.idlist_val[0] == ANONYMOUSID
474         || lids.idlist_val[1] == ANONYMOUSID) {
475         code = PRNOENT;
476         goto done;
477     }
478     code =
479         ubik_PR_RemoveFromGroup(pruclient, 0, lids.idlist_val[0],
480                   lids.idlist_val[1]);
481   done:
482     if (lnames.namelist_val)
483         free(lnames.namelist_val);
484
485     xdr_free((xdrproc_t) xdr_idlist, &lids);
486
487     return code;
488 }
489
490 int
491 pr_NameToId(namelist *names, idlist *ids)
492 {
493     afs_int32 code;
494     afs_int32 i;
495
496     for (i = 0; i < names->namelist_len; i++)
497         stolower(names->namelist_val[i]);
498     code = ubik_PR_NameToID(pruclient, 0, names, ids);
499     return code;
500 }
501
502 int
503 pr_SNameToId(char name[PR_MAXNAMELEN], afs_int32 *id)
504 {
505     namelist lnames;
506     idlist lids;
507     afs_int32 code;
508
509     lids.idlist_len = 0;
510     lids.idlist_val = 0;
511     lnames.namelist_len = 1;
512     lnames.namelist_val = malloc(PR_MAXNAMELEN);
513     stolower(name);
514     strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN);
515     code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
516     if (lids.idlist_val) {
517         *id = *lids.idlist_val;
518         xdr_free((xdrproc_t) xdr_idlist, &lids);
519     }
520     if (lnames.namelist_val)
521         free(lnames.namelist_val);
522     return code;
523 }
524
525 int
526 pr_IdToName(idlist *ids, namelist *names)
527 {
528     afs_int32 code;
529
530     code = ubik_PR_IDToName(pruclient, 0, ids, names);
531     return code;
532 }
533
534 int
535 pr_SIdToName(afs_int32 id, char name[PR_MAXNAMELEN])
536 {
537     namelist lnames;
538     idlist lids;
539     afs_int32 code;
540
541     lids.idlist_len = 1;
542     lids.idlist_val = malloc(sizeof(afs_int32));
543     *lids.idlist_val = id;
544     lnames.namelist_len = 0;
545     lnames.namelist_val = 0;
546     code = ubik_PR_IDToName(pruclient, 0, &lids, &lnames);
547
548     if (lnames.namelist_val)
549         strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN);
550
551     if (lids.idlist_val)
552         free(lids.idlist_val);
553
554     xdr_free((xdrproc_t) xdr_namelist, &lnames);
555
556     return code;
557 }
558
559 int
560 pr_GetCPS(afs_int32 id, prlist *CPS)
561 {
562     afs_int32 code;
563     afs_int32 over;
564
565     over = 0;
566     code = ubik_PR_GetCPS(pruclient, 0, id, CPS, &over);
567     if (code != PRSUCCESS)
568         return code;
569     if (over) {
570         /* do something about this, probably make a new call */
571         /* don't forget there's a hard limit in the interface */
572         fprintf(stderr, "membership list for id %d exceeds display limit\n",
573                 id);
574     }
575     return 0;
576 }
577
578 int
579 pr_GetCPS2(afs_int32 id, afs_uint32 host, prlist *CPS)
580 {
581     afs_int32 code;
582     afs_int32 over;
583
584     over = 0;
585     code = ubik_PR_GetCPS2(pruclient, 0, id, host, CPS, &over);
586     if (code != PRSUCCESS)
587         return code;
588     if (over) {
589         /* do something about this, probably make a new call */
590         /* don't forget there's a hard limit in the interface */
591         fprintf(stderr, "membership list for id %d exceeds display limit\n",
592                 id);
593     }
594     return 0;
595 }
596
597 int
598 pr_GetHostCPS(afs_uint32 host, prlist *CPS)
599 {
600     afs_int32 code;
601     afs_int32 over;
602
603     over = 0;
604     code = ubik_PR_GetHostCPS(pruclient, 0, host, CPS, &over);
605     if (code != PRSUCCESS)
606         return code;
607     if (over) {
608         /* do something about this, probably make a new call */
609         /* don't forget there's a hard limit in the interface */
610         fprintf(stderr,
611                 "membership list for host id %d exceeds display limit\n",
612                 host);
613     }
614     return 0;
615 }
616
617 int
618 pr_ListMembers(char *group, namelist *lnames)
619 {
620     afs_int32 code;
621     afs_int32 gid;
622
623     code = pr_SNameToId(group, &gid);
624     if (code)
625         return code;
626     if (gid == ANONYMOUSID)
627         return PRNOENT;
628     code = pr_IDListMembers(gid, lnames);
629     return code;
630 }
631
632 int
633 pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP)
634 {
635     afs_int32 code;
636     prlist alist;
637     idlist *lids;
638
639     alist.prlist_len = 0;
640     alist.prlist_val = 0;
641     code = ubik_PR_ListOwned(pruclient, 0, oid, &alist, moreP);
642     if (code)
643         return code;
644     if (*moreP == 1) {
645         /* Remain backwards compatible when moreP was a T/F bit */
646         fprintf(stderr, "membership list for id %d exceeds display limit\n",
647                 oid);
648         *moreP = 0;
649     }
650     lids = (idlist *) &alist;
651     code = pr_IdToName(lids, lnames);
652
653     xdr_free((xdrproc_t) xdr_prlist, &alist);
654
655     if (code)
656         return code;
657
658     return PRSUCCESS;
659 }
660
661 int
662 pr_IDListMembers(afs_int32 gid, namelist *lnames)
663 {
664     afs_int32 code;
665     prlist alist;
666     idlist *lids;
667     afs_int32 over;
668
669     alist.prlist_len = 0;
670     alist.prlist_val = 0;
671     code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
672     if (code)
673         return code;
674     if (over) {
675         fprintf(stderr, "membership list for id %d exceeds display limit\n",
676                 gid);
677     }
678     lids = (idlist *) &alist;
679     code = pr_IdToName(lids, lnames);
680
681     xdr_free((xdrproc_t) xdr_prlist, &alist);
682
683     if (code)
684         return code;
685     return PRSUCCESS;
686 }
687
688 int
689 pr_IDListExpandedMembers(afs_int32 aid, namelist * lnames)
690 {
691     afs_int32 code;
692     afs_int32 gid;
693     idlist lids;
694     prlist alist;
695     afs_int32 over;
696     struct idhash *members = NULL;
697     afs_int32 *stack = NULL;
698     afs_int32 maxstack = ID_STACK_SIZE;
699     int n = 0;                  /* number of ids stacked */
700     int i;
701     int firstpass = 1;
702
703     code = AllocateIdHash(&members);
704     if (code) {
705         return code;
706     }
707     stack = (afs_int32 *) malloc(sizeof(afs_int32) * maxstack);
708     if (!stack) {
709         code = ENOMEM;
710         goto done;
711     }
712
713     stack[n++] = aid;
714     while (n) {
715         gid = stack[--n];       /* pop next group id */
716         alist.prlist_len = 0;
717         alist.prlist_val = NULL;
718         if (firstpass || aid < 0) {
719             firstpass = 0;
720             code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
721         } else {
722             code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
723             if (code == RXGEN_OPCODE) {
724                 alist.prlist_len = 0;
725                 alist.prlist_val = NULL;
726                 code = 0; /* server does not support supergroups. */
727             }
728         }
729         if (code)
730             goto done;
731         if (over) {
732             fprintf(stderr,
733                     "membership list for id %d exceeds display limit\n", gid);
734         }
735         for (i = 0; i < alist.prlist_len; i++) {
736             afs_int32 found;
737             afs_int32 id;
738
739             id = alist.prlist_val[i];
740             found = FindId(members, id);
741             if (found < 0) {
742                 code = found;
743                 xdr_free((xdrproc_t) xdr_prlist, &alist);
744                 goto done;
745             }
746             if (found == 0 && id < 0) {
747                 if (n == maxstack) {    /* need more stack space */
748                     afs_int32 *tmp;
749                     maxstack += n;
750                     tmp =
751                         (afs_int32 *) realloc(stack,
752                                               maxstack * sizeof(afs_int32));
753                     if (!tmp) {
754                         code = ENOMEM;
755                         xdr_free((xdrproc_t) xdr_prlist, &alist);
756                         goto done;
757                     }
758                     stack = tmp;
759                 }
760                 stack[n++] = id;        /* push group id */
761             }
762         }
763         xdr_free((xdrproc_t) xdr_prlist, &alist);
764     }
765
766     code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS));
767     if (code) {
768         goto done;
769     }
770     code = pr_IdToName(&lids, lnames);
771     if (lids.idlist_len)
772         free(lids.idlist_val);
773
774   done:
775     if (stack)
776         free(stack);
777     if (members)
778         FreeIdHash(members);
779     return code;
780 }
781
782 int
783 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
784 {
785     afs_int32 code;
786
787     code = ubik_PR_ListEntry(pruclient, 0, id, aentry);
788     return code;
789 }
790
791 afs_int32
792 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
793 {
794     afs_int32 code;
795     prentries bulkentries;
796
797     *nentries = 0;
798     *entries = NULL;
799     *nextstartindex = -1;
800     bulkentries.prentries_val = 0;
801     bulkentries.prentries_len = 0;
802
803     code =
804         ubik_PR_ListEntries(pruclient, 0, flag, startindex,
805                   &bulkentries, nextstartindex);
806     *nentries = bulkentries.prentries_len;
807     *entries = bulkentries.prentries_val;
808     return code;
809 }
810
811 int
812 pr_CheckEntryByName(char *name, afs_int32 *id, char *owner, char *creator)
813 {
814     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
815     afs_int32 code;
816     struct prcheckentry aentry;
817
818     code = pr_SNameToId(name, id);
819     if (code)
820         return code;
821     if (*id == ANONYMOUSID)
822         return PRNOENT;
823     code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry);
824     if (code)
825         return code;
826     /* this should be done in one RPC, but I'm lazy. */
827     code = pr_SIdToName(aentry.owner, owner);
828     if (code)
829         return code;
830     code = pr_SIdToName(aentry.creator, creator);
831     if (code)
832         return code;
833     return PRSUCCESS;
834 }
835
836 int
837 pr_CheckEntryById(char *name, afs_int32 id, char *owner, char *creator)
838 {
839     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
840     afs_int32 code;
841     struct prcheckentry aentry;
842
843     code = pr_SIdToName(id, name);
844     if (code)
845         return code;
846     if (id == ANONYMOUSID)
847         return PRNOENT;
848     code = ubik_PR_ListEntry(pruclient, 0, id, &aentry);
849     if (code)
850         return code;
851     /* this should be done in one RPC, but I'm lazy. */
852     code = pr_SIdToName(aentry.owner, owner);
853     if (code)
854         return code;
855     code = pr_SIdToName(aentry.creator, creator);
856     if (code)
857         return code;
858     return PRSUCCESS;
859 }
860
861 int
862 pr_ChangeEntry(char *oldname, char *newname, afs_int32 *newid, char *newowner)
863 {
864     afs_int32 code;
865     afs_int32 id;
866     afs_int32 oid = 0;
867
868     code = pr_SNameToId(oldname, &id);
869     if (code)
870         return code;
871     if (id == ANONYMOUSID)
872         return PRNOENT;
873     if (newowner && *newowner) {
874         code = pr_SNameToId(newowner, &oid);
875         if (code)
876             return code;
877         if (oid == ANONYMOUSID)
878             return PRNOENT;
879     }
880     if (newid)
881         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid);
882     else
883         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0);
884     return code;
885 }
886
887 int
888 pr_IsAMemberOf(char *uname, char *gname, afs_int32 *flag)
889 {
890     afs_int32 code;
891     namelist lnames;
892     idlist lids;
893
894     stolower(uname);
895     stolower(gname);
896     lnames.namelist_len = 2;
897     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
898     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
899     strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
900     lids.idlist_val = 0;
901     lids.idlist_len = 0;
902     code = pr_NameToId(&lnames, &lids);
903     if (code) {
904         if (lnames.namelist_val)
905             free(lnames.namelist_val);
906         xdr_free((xdrproc_t) xdr_idlist, &lids);
907         return code;
908     }
909     code =
910         ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0],
911                   lids.idlist_val[1], flag);
912     if (lnames.namelist_val)
913         free(lnames.namelist_val);
914     xdr_free((xdrproc_t) xdr_idlist, &lids);
915     return code;
916 }
917
918 int
919 pr_ListMaxUserId(afs_int32 *mid)
920 {
921     afs_int32 code;
922     afs_int32 gid;
923     code = ubik_PR_ListMax(pruclient, 0, mid, &gid);
924     return code;
925 }
926
927 int
928 pr_SetMaxUserId(afs_int32 mid)
929 {
930     afs_int32 code;
931     afs_int32 flag = 0;
932     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
933     return code;
934 }
935
936 int
937 pr_ListMaxGroupId(afs_int32 *mid)
938 {
939     afs_int32 code;
940     afs_int32 id;
941     code = ubik_PR_ListMax(pruclient, 0, &id, mid);
942     return code;
943 }
944
945 int
946 pr_SetMaxGroupId(afs_int32 mid)
947 {
948     afs_int32 code;
949     afs_int32 flag = 0;
950
951     flag |= PRGRP;
952     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
953     return code;
954 }
955
956 afs_int32
957 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
958 {
959     afs_int32 code;
960
961     code =
962         ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups,
963                   nusers, 0, 0);
964     return code;
965 }
966
967 int
968 pr_ListSuperGroups(afs_int32 gid, namelist * lnames)
969 {
970     afs_int32 code;
971     prlist alist;
972     idlist *lids;
973     afs_int32 over;
974
975     alist.prlist_len = 0;
976     alist.prlist_val = 0;
977     code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
978     if (code)
979         return code;
980     if (over) {
981         fprintf(stderr, "supergroup list for id %d exceeds display limit\n",
982                 gid);
983     }
984     lids = (idlist *) & alist;
985     code = pr_IdToName(lids, lnames);
986
987     xdr_free((xdrproc_t) xdr_prlist, &alist);
988     return code;
989 }