2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
20 #include <afs/cellconfig.h>
21 #include <afs/afsutil.h>
22 #include <afs/com_err.h>
28 struct ubik_client *pruclient = 0;
29 static afs_int32 lastLevel; /* security level pruclient, if any */
31 static char *whoami = "libprot";
34 #define ID_HASH_SIZE 1024
35 #define ID_STACK_SIZE 1024
38 * Hash table chain of user and group ids.
46 * Hash table of user and group ids.
49 afs_uint32 userEntries; /**< number of user id entries hashed */
50 afs_uint32 groupEntries; /**< number of group id entries hashed */
51 struct idchain *hash[ID_HASH_SIZE];
55 * Allocate a new id hash table.
58 AllocateIdHash(struct idhash **aidhash)
60 struct idhash *idhash;
62 idhash = calloc(1, sizeof(struct idhash));
74 FreeIdHash(struct idhash *idhash)
77 struct idchain *chain;
80 for (index = 0; index < ID_HASH_SIZE; index++) {
81 for (chain = idhash->hash[index]; chain; chain = next) {
90 * Indicate if group/user id is already hashed, and
93 * @returns whether id is present
94 * @retval >0 id is already present in the hash
95 * @retval 0 id was not found and was inserted into the hash
96 * @retval <0 error encountered
99 FindId(struct idhash *idhash, afs_int32 id)
102 struct idchain *chain;
103 struct idchain *newChain;
105 index = abs(id) % ID_HASH_SIZE;
106 for (chain = idhash->hash[index]; chain; chain = chain->next) {
107 if (chain->id == id) {
112 /* Insert this id but return not found. */
113 newChain = malloc(sizeof(struct idchain));
118 newChain->next = idhash->hash[index];
119 idhash->hash[index] = newChain;
121 idhash->groupEntries++;
123 idhash->userEntries++;
130 * Create an idlist from the ids in the hash.
133 CreateIdList(struct idhash *idhash, idlist * alist, afs_int32 select)
135 struct idchain *chain;
136 afs_int32 entries = 0;
140 if (select & PRGROUPS) {
141 entries += idhash->groupEntries;
143 if (select & PRUSERS) {
144 entries += idhash->userEntries;
147 alist->idlist_len = 0;
148 alist->idlist_val = NULL;
152 alist->idlist_len = entries;
153 alist->idlist_val = malloc(sizeof(afs_int32) * entries);
154 if (!alist->idlist_val) {
158 for (i = 0, index = 0; index < ID_HASH_SIZE; index++) {
159 for (chain = idhash->hash[index]; chain; chain = chain->next) {
161 if (select & PRGROUPS) {
162 alist->idlist_val[i++] = chain->id;
165 if (select & PRUSERS) {
166 alist->idlist_val[i++] = chain->id;
175 pr_Initialize(IN afs_int32 secLevel, IN const char *confDir, IN char *cell)
178 struct rx_connection *serverconns[MAXSERVERS];
179 struct rx_securityClass *sc = NULL;
180 static struct afsconf_dir *tdir = NULL; /* only do this once */
181 static char tconfDir[100] = "";
182 static char tcell[64] = "";
185 static struct afsconf_cell info;
188 afs_int32 gottdir = 0;
189 afs_int32 refresh = 0;
191 initialize_PT_error_table();
192 initialize_RXK_error_table();
193 initialize_ACFG_error_table();
194 initialize_KTC_error_table();
198 tdir = afsconf_Open(confDir);
200 if (confDir && strcmp(confDir, ""))
202 "%s: Could not open configuration directory: %s.\n",
206 "%s: No configuration directory specified.\n",
212 code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
215 "libprot: Could not get local cell. [%d]\n", code);
221 if (tdir == NULL || strcmp(confDir, tconfDir) || strcmp(cell, tcell)) {
223 * force re-evaluation. we either don't have an afsconf_dir,
224 * the directory has changed or the cell has changed.
226 if (tdir && !gottdir) {
235 strncpy(tconfDir, confDir, sizeof(tconfDir));
236 strncpy(tcell, cell, sizeof(tcell));
239 tdir = afsconf_Open(confDir);
241 if (confDir && strcmp(confDir, ""))
243 "libprot: Could not open configuration directory: %s.\n",
247 "libprot: No configuration directory specified.\n");
251 code = afsconf_GetCellInfo(tdir, cell, "afsprot", &info);
253 fprintf(stderr, "libprot: Could not locate cell %s in %s/%s\n",
254 cell, confDir, AFSDIR_CELLSERVDB_FILE);
259 /* If we already have a client and it is at the security level we
260 * want, don't get a new one. Unless the security level is 2 in
261 * which case we will get one (and re-read the key file).
263 if (pruclient && (lastLevel == secLevel) && (secLevel != 2)) {
269 fprintf(stderr, "libprot: Could not initialize rx.\n");
273 /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
274 * to force use of the KeyFile. secLevel == 0 implies -noauth was
277 /* If secLevel is two assume we're on a file server and use
278 * ClientAuthSecure if possible. */
279 code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
281 afs_com_err(whoami, code, "(calling client secure)\n");
282 } else if (secLevel > 0) {
285 secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
287 code = afsconf_ClientAuthToken(&info, secFlags, &sc, &scIndex, NULL);
289 afs_com_err(whoami, code, "(getting token)");
296 sc = rxnull_NewClientSecurityObject();
297 scIndex = RX_SECIDX_NULL;
300 if ((scIndex == RX_SECIDX_NULL) && (secLevel != 0))
302 "%s: Could not get afs tokens, running unauthenticated\n",
305 memset(serverconns, 0, sizeof(serverconns)); /* terminate list!!! */
306 for (i = 0; i < info.numServers; i++)
308 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
309 info.hostAddr[i].sin_port, PRSRV, sc,
312 code = ubik_ClientInit(serverconns, &pruclient);
314 afs_com_err(whoami, code, "ubik client init failed.");
319 code = rxs_Release(sc);
329 code = ubik_ClientDestroy(pruclient);
336 * Make sure that arg is a proper C string that fits in a prname.
337 * If strnlen(arg, PR_MAXNAMELEN) == PR_MAXNAMELEN, then arg either
338 * doesn't have a terminating NUL or is too long, and we can't tell
339 * which one in the current API. This code has always assumed that
340 * the names presented to it are valid C strings, but for robustness
341 * we can't depend on the server side guaranteeing that. Unfortunately,
342 * the wire protocol uses a vector[PR_MAXNAMELEN] of char, so XDR will
343 * not automatically fix up strings generated by the server.
345 * The inequality is just belt-and-suspenders and should be impossible.
347 static_inline int check_length(prname arg)
349 if (strnlen(arg, PR_MAXNAMELEN) >= PR_MAXNAMELEN)
350 return PRNAMETOOLONG;
355 pr_CreateUser(prname name, afs_int32 *id)
359 code = check_length(name);
364 code = ubik_PR_INewEntry(pruclient, 0, name, *id, 0);
366 code = ubik_PR_NewEntry(pruclient, 0, name, 0, 0, id);
372 pr_CreateGroup(prname name, prname owner, afs_int32 *id)
378 code = check_length(name);
381 /* pr_SNameToId will check owner's length. */
384 code = pr_SNameToId(owner, &oid);
387 if (oid == ANONYMOUSID)
392 code = ubik_PR_INewEntry(pruclient, 0, name, *id, oid);
394 code = ubik_PR_NewEntry(pruclient, 0, name, flags, oid, id);
400 pr_Delete(prname name)
405 /* pr_SNameToId both checks the length of name and lowercases it. */
406 code = pr_SNameToId(name, &id);
409 if (id == ANONYMOUSID)
411 code = ubik_PR_Delete(pruclient, 0, id);
416 pr_DeleteByID(afs_int32 id)
420 code = ubik_PR_Delete(pruclient, 0, id);
425 pr_AddToGroup(prname user, prname group)
431 code = check_length(user);
434 code = check_length(group);
437 lnames.namelist_len = 2;
438 lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
439 strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
440 strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
443 code = pr_NameToId(&lnames, &lids);
446 /* if here, still could be missing an entry */
447 if (lids.idlist_len != 2) {
451 if (lids.idlist_val[0] == ANONYMOUSID
452 || lids.idlist_val[1] == ANONYMOUSID) {
457 ubik_PR_AddToGroup(pruclient, 0, lids.idlist_val[0],
460 if (lnames.namelist_val)
461 free(lnames.namelist_val);
463 xdr_free((xdrproc_t) xdr_idlist, &lids);
468 pr_RemoveUserFromGroup(prname user, prname group)
474 code = check_length(user);
477 code = check_length(group);
480 lnames.namelist_len = 2;
481 lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
482 strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
483 strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
486 code = pr_NameToId(&lnames, &lids);
490 if (lids.idlist_len != 2) {
494 if (lids.idlist_val[0] == ANONYMOUSID
495 || lids.idlist_val[1] == ANONYMOUSID) {
500 ubik_PR_RemoveFromGroup(pruclient, 0, lids.idlist_val[0],
503 if (lnames.namelist_val)
504 free(lnames.namelist_val);
506 xdr_free((xdrproc_t) xdr_idlist, &lids);
512 pr_NameToId(namelist *names, idlist *ids)
517 for (i = 0; i < names->namelist_len; i++) {
518 code = check_length(names->namelist_val[i]);
521 stolower(names->namelist_val[i]);
523 code = ubik_PR_NameToID(pruclient, 0, names, ids);
528 pr_SNameToId(prname name, afs_int32 *id)
534 code = check_length(name);
539 lnames.namelist_len = 1;
540 lnames.namelist_val = malloc(PR_MAXNAMELEN);
542 strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN);
543 code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
544 if (lids.idlist_val) {
545 *id = *lids.idlist_val;
546 xdr_free((xdrproc_t) xdr_idlist, &lids);
547 } else if (code == 0) {
550 if (lnames.namelist_val)
551 free(lnames.namelist_val);
556 * Like ubik_PR_IDToName, but enforces that the output prnames are
557 * interpretable as C strings (i.e., NUL-terminated).
560 string_PR_IDToName(struct ubik_client *client, afs_int32 flags,
561 idlist *ids, namelist *names)
566 code = ubik_PR_IDToName(client, flags, ids, names);
569 for (i = 0; i < names->namelist_len; i++) {
570 code = check_length(names->namelist_val[i]);
579 pr_IdToName(idlist *ids, namelist *names)
581 return string_PR_IDToName(pruclient, 0, ids, names);
585 pr_SIdToName(afs_int32 id, prname name)
592 lids.idlist_val = malloc(sizeof(afs_int32));
593 *lids.idlist_val = id;
594 lnames.namelist_len = 0;
595 lnames.namelist_val = 0;
596 code = pr_IdToName(&lids, &lnames);
597 if (lnames.namelist_val)
598 strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN);
603 free(lids.idlist_val);
605 xdr_free((xdrproc_t) xdr_namelist, &lnames);
611 pr_GetCPS(afs_int32 id, prlist *CPS)
617 code = ubik_PR_GetCPS(pruclient, 0, id, CPS, &over);
618 if (code != PRSUCCESS)
621 /* do something about this, probably make a new call */
622 /* don't forget there's a hard limit in the interface */
623 fprintf(stderr, "membership list for id %d exceeds display limit\n",
630 pr_GetCPS2(afs_int32 id, afs_uint32 host, prlist *CPS)
636 code = ubik_PR_GetCPS2(pruclient, 0, id, host, CPS, &over);
637 if (code != PRSUCCESS)
640 /* do something about this, probably make a new call */
641 /* don't forget there's a hard limit in the interface */
642 fprintf(stderr, "membership list for id %d exceeds display limit\n",
649 pr_GetHostCPS(afs_uint32 host, prlist *CPS)
655 code = ubik_PR_GetHostCPS(pruclient, 0, host, CPS, &over);
656 if (code != PRSUCCESS)
659 /* do something about this, probably make a new call */
660 /* don't forget there's a hard limit in the interface */
662 "membership list for host id %d exceeds display limit\n",
669 pr_ListMembers(prname group, namelist *lnames)
675 memset(lnames, 0, sizeof(namelist));
677 /* pr_SNameToId checks the length of group. */
678 code = pr_SNameToId(group, &gid);
681 if (gid == ANONYMOUSID)
683 code = pr_IDListMembers(gid, lnames);
686 for (i = 0; i < lnames->namelist_len; i++) {
687 code = check_length(lnames->namelist_val[i]);
695 pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP)
701 alist.prlist_len = 0;
702 alist.prlist_val = 0;
703 code = ubik_PR_ListOwned(pruclient, 0, oid, &alist, moreP);
707 /* Remain backwards compatible when moreP was a T/F bit */
708 fprintf(stderr, "membership list for id %d exceeds display limit\n",
712 lids = (idlist *) &alist;
713 code = pr_IdToName(lids, lnames);
715 xdr_free((xdrproc_t) xdr_prlist, &alist);
724 pr_IDListMembers(afs_int32 gid, namelist *lnames)
731 alist.prlist_len = 0;
732 alist.prlist_val = 0;
733 code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
737 fprintf(stderr, "membership list for id %d exceeds display limit\n",
740 lids = (idlist *) &alist;
741 code = pr_IdToName(lids, lnames);
743 xdr_free((xdrproc_t) xdr_prlist, &alist);
751 pr_IDListExpandedMembers(afs_int32 aid, namelist * lnames)
758 struct idhash *members = NULL;
759 afs_int32 *stack = NULL;
760 afs_int32 maxstack = ID_STACK_SIZE;
761 int n = 0; /* number of ids stacked */
765 code = AllocateIdHash(&members);
769 stack = malloc(sizeof(afs_int32) * maxstack);
777 gid = stack[--n]; /* pop next group id */
778 alist.prlist_len = 0;
779 alist.prlist_val = NULL;
780 if (firstpass || aid < 0) {
782 code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
784 code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
785 if (code == RXGEN_OPCODE) {
786 alist.prlist_len = 0;
787 alist.prlist_val = NULL;
788 code = 0; /* server does not support supergroups. */
795 "membership list for id %d exceeds display limit\n", gid);
797 for (i = 0; i < alist.prlist_len; i++) {
801 id = alist.prlist_val[i];
802 found = FindId(members, id);
805 xdr_free((xdrproc_t) xdr_prlist, &alist);
808 if (found == 0 && id < 0) {
809 if (n == maxstack) { /* need more stack space */
812 tmp = realloc(stack, maxstack * sizeof(afs_int32));
815 xdr_free((xdrproc_t) xdr_prlist, &alist);
820 stack[n++] = id; /* push group id */
823 xdr_free((xdrproc_t) xdr_prlist, &alist);
826 code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS));
829 } else if (lids.idlist_len == 0) {
830 /* Avoid the RPC when there's nothing to look up. */
831 lnames->namelist_len = 0;
832 lnames->namelist_val = NULL;
835 code = pr_IdToName(&lids, lnames);
836 free(lids.idlist_val);
847 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
851 code = ubik_PR_ListEntry(pruclient, 0, id, aentry);
854 return check_length(aentry->name);
858 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
862 prentries bulkentries;
866 *nextstartindex = -1;
867 bulkentries.prentries_val = 0;
868 bulkentries.prentries_len = 0;
871 ubik_PR_ListEntries(pruclient, 0, flag, startindex,
872 &bulkentries, nextstartindex);
875 for (i = 0; i < bulkentries.prentries_len; i++) {
876 /* XXX should we try to return all the other entries? */
877 code = check_length(bulkentries.prentries_val[i].name);
884 xdr_free((xdrproc_t)xdr_prentries, &bulkentries);
886 *nentries = bulkentries.prentries_len;
887 *entries = bulkentries.prentries_val;
893 pr_CheckEntryByName(prname name, afs_int32 *id, prname owner, prname creator)
895 /* struct prcheckentry returns other things, which aren't useful to show at this time. */
897 struct prcheckentry aentry;
899 /* pr_SNameToId will check name's length. */
900 code = pr_SNameToId(name, id);
903 if (*id == ANONYMOUSID)
905 code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry);
908 /* this should be done in one RPC, but I'm lazy. */
909 code = pr_SIdToName(aentry.owner, owner);
912 code = pr_SIdToName(aentry.creator, creator);
919 pr_CheckEntryById(prname name, afs_int32 id, prname owner, prname creator)
921 /* struct prcheckentry returns other things, which aren't useful to show at this time. */
923 struct prcheckentry aentry;
925 /* XXX ListEntry RPC gives us the name back so should avoid extra RPC */
926 code = pr_SIdToName(id, name);
929 if (id == ANONYMOUSID)
931 code = ubik_PR_ListEntry(pruclient, 0, id, &aentry);
934 /* this should be done in one RPC, but I'm lazy. */
935 code = pr_SIdToName(aentry.owner, owner);
938 code = pr_SIdToName(aentry.creator, creator);
945 pr_ChangeEntry(prname oldname, prname newname, afs_int32 *newid, prname newowner)
951 /* pr_SNameToId takes care of length checks for us. */
952 code = pr_SNameToId(oldname, &id);
955 if (id == ANONYMOUSID)
957 if (newowner && *newowner) {
958 code = pr_SNameToId(newowner, &oid);
961 if (oid == ANONYMOUSID)
965 code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid);
967 code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0);
972 pr_IsAMemberOf(prname uname, prname gname, afs_int32 *flag)
978 code = check_length(uname);
981 code = check_length(gname);
986 lnames.namelist_len = 2;
987 lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
988 strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
989 strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
992 code = pr_NameToId(&lnames, &lids);
994 if (lnames.namelist_val)
995 free(lnames.namelist_val);
996 xdr_free((xdrproc_t) xdr_idlist, &lids);
999 if (lids.idlist_len != 2) {
1000 free(lnames.namelist_val);
1001 xdr_free((xdrproc_t) xdr_idlist, &lids);
1005 ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0],
1006 lids.idlist_val[1], flag);
1007 if (lnames.namelist_val)
1008 free(lnames.namelist_val);
1009 xdr_free((xdrproc_t) xdr_idlist, &lids);
1014 pr_ListMaxUserId(afs_int32 *mid)
1018 code = ubik_PR_ListMax(pruclient, 0, mid, &gid);
1023 pr_SetMaxUserId(afs_int32 mid)
1027 code = ubik_PR_SetMax(pruclient, 0, mid, flag);
1032 pr_ListMaxGroupId(afs_int32 *mid)
1036 code = ubik_PR_ListMax(pruclient, 0, &id, mid);
1041 pr_SetMaxGroupId(afs_int32 mid)
1047 code = ubik_PR_SetMax(pruclient, 0, mid, flag);
1052 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
1057 ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups,
1063 pr_ListSuperGroups(afs_int32 gid, namelist * lnames)
1070 alist.prlist_len = 0;
1071 alist.prlist_val = 0;
1072 code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over);
1076 fprintf(stderr, "supergroup list for id %d exceeds display limit\n",
1079 lids = (idlist *) & alist;
1080 code = pr_IdToName(lids, lnames);
1082 xdr_free((xdrproc_t) xdr_prlist, &alist);