strerror \
sysconf \
sysctl \
+ tdestroy \
timegm \
])
OBJS= cellconfig.o keys.o ktc.o userok.o writeconfig.o authcon.o \
- acfg_errors.o ktc_errors.o token.xdr.o token.o
+ acfg_errors.o ktc_errors.o token.xdr.o token.o realms.o
KOBJS= cellconfig.o keys.o ktc.krb.o userok.o writeconfig.o authcon.o \
- acfg_errors.o ktc_errors.o token.xdr.o token.o
+ acfg_errors.o ktc_errors.o token.xdr.o token.o realms.o
LIBS=libauth.a \
${TOP_LIBDIR}/librxkad.a \
cellconfig.o: cellconfig.c ${INCLS}
copyauth.o: copyauth.c ${INCLS} AFS_component_version_number.o
setkey.o: setkey.c ${INCLS} AFS_component_version_number.o
+realms.o: realms.c ${INCLS}
CFLAGS_ktc.krb.o = -DAFS_KERBEROS_ENV
ktc.krb.o: ktc.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
+ $(OUT)\realms.obj \
$(OUT)\acfg_errors.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
+ $(OUT)\realms.obj \
$(OUT)\acfg_errors.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \
/* now read the fs keys, if possible */
code = _afsconf_LoadKeys(adir);
+ if (code) {
+ return code;
+ }
+ code = _afsconf_LoadRealms(adir);
return code;
}
}
_afsconf_FreeAllKeys(adir);
+ _afsconf_FreeRealms(adir);
/* reinit */
memset(adir, 0, sizeof(struct afsconf_dir));
afs_int32 timeCheck; /* time of last check for update */
struct afsconf_aliasentry *alias_entries; /* cell aliases */
afsconf_secflags securityFlags;
+ struct afsconf_realms *local_realms; /* local realms */
+ struct afsconf_realms *exclusions; /* excluded principals */
};
extern afs_int32 afsconf_FindService(const char *aname);
struct rx_identity **);
extern int afsconf_IsSuperIdentity(struct afsconf_dir *, struct rx_identity *);
+/* realms.c */
+extern int afsconf_SetLocalRealm(const char *realm);
+extern int afsconf_IsLocalRealmMatch(struct afsconf_dir *dir, afs_int32 * local,
+ const char *name, const char *instance,
+ const char *cell);
+
/* some well-known ports and their names; new additions to table in cellconfig.c, too */
#define AFSCONF_FILESERVICE "afs"
#define AFSCONF_FILEPORT 7000
extern void _afsconf_InitKeys(struct afsconf_dir *adir);
extern void _afsconf_FreeAllKeys(struct afsconf_dir *adir);
extern int _afsconf_GetLocalCell(struct afsconf_dir *adir, char **pname, int check);
+extern int _afsconf_LoadRealms(struct afsconf_dir *dir);
+extern void _afsconf_FreeRealms(struct afsconf_dir *dir);
--- /dev/null
+/*
+ * Copyright 2012, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
+#include <opr/queue.h>
+#include <afs/stds.h>
+#include <afs/pthread_glock.h>
+#include <afs/afsutil.h>
+#include <ctype.h>
+#include <search.h>
+#include "cellconfig.h"
+#include "internal.h"
+
+#define MAXLINESIZE 2047
+
+/* Can be set during initialization, overriding the krb.conf file. */
+static struct opr_queue *lrealms = NULL;
+
+/**
+ * Realm and exclusion list entries.
+ */
+struct afsconf_realm_entry {
+ struct opr_queue link; /**< linked list header */
+ char *value; /**< local realm or principal */
+};
+
+/**
+ * Realm and exclusion lists.
+ */
+struct afsconf_realms {
+ struct opr_queue list; /**< list of afsconf_realm_entry */
+ int time_read; /**< time when read from file */
+ void *tree; /**< for lookup */
+ int (*compare) (const void *, const void *); /**< compare entries */
+};
+
+static int
+compare_realms(const void *a, const void *b)
+{
+ return strcasecmp((char *)a, (char *)b);
+}
+
+static int
+compare_principals(const void *a, const void *b)
+{
+ return strcmp((char *)a, (char *)b);
+}
+
+/**
+ * Format the k4-style principal string.
+ *
+ * @param[out] pvname output buffer, must be freed by caller
+ * @param[in] name user name, required
+ * @param[in] inst user instance, optional
+ * @param[in] cell cell name, optional
+ *
+ * @return status
+ * @retval 0 success
+ * @retval EINVAL invalid arguments
+ * @retval E2BIG insufficient output buffer space
+ *
+ * @internal
+ */
+static int
+create_name(char **pvname, const char *name,
+ const char *inst, const char *cell)
+{
+ int code = 0;
+
+ if (!name || !*name) {
+ return EINVAL;
+ }
+ if (cell && *cell) {
+ if (inst && *inst) {
+ code = asprintf(pvname, "%s.%s@%s", name, inst, cell);
+ } else {
+ code = asprintf(pvname, "%s@%s", name, cell);
+ }
+ } else {
+ if (inst && *inst) {
+ code = asprintf(pvname, "%s.%s", name, inst);
+ } else {
+ code = asprintf(pvname, "%s", name);
+ }
+ }
+ return (code < 0 ? ENOMEM : 0);
+}
+
+/**
+ * Parse whitespace delimited values
+ *
+ * @param[in] buffer input string
+ * @param[out] result output string
+ * @param[in] size size of result buffer
+ *
+ * @return pointer to the next value
+ *
+ * @internal
+ */
+static char *
+parse_str(char *buffer, char *result, int size)
+{
+ int n = 0;
+
+ if (!buffer)
+ goto cleanup;
+
+ while (*buffer && isspace(*buffer))
+ buffer++;
+ while (*buffer && !isspace(*buffer)) {
+ if (n < size - 1) {
+ *result++ = *buffer++;
+ n++;
+ } else {
+ buffer++;
+ }
+ }
+
+ cleanup:
+ *result = '\0';
+ return buffer;
+}
+
+/**
+ * Add a new list element.
+ *
+ * Add the name element if not already present in the list.
+ * The names are case insensitive.
+ *
+ * @param[inout] list list of name elements
+ * @param[in] name name to add
+ *
+ * @return status
+ * @retval 0 success
+ * @retval ENOMEM unable to allocate new entry
+ *
+ * @internal
+ */
+static int
+add_entry(struct opr_queue *list, const char *name)
+{
+ struct afsconf_realm_entry *entry;
+
+ entry = malloc(sizeof(struct afsconf_realm_entry));
+ if (!entry) {
+ return ENOMEM;
+ }
+ entry->value = strdup(name);
+ opr_queue_Append(list, (struct opr_queue *)entry);
+ return 0;
+}
+
+/**
+ * Free all entries in a list.
+ *
+ * @param[in] list list of entries
+ *
+ * @return none
+ *
+ * @internal
+ */
+static void
+free_realm_entries(struct opr_queue *list)
+{
+ struct afsconf_realm_entry *entry;
+
+ while (!opr_queue_IsEmpty(list)) {
+ entry = opr_queue_First(list, struct afsconf_realm_entry, link);
+ opr_queue_Remove(&entry->link);
+ if (entry->value) {
+ free(entry->value);
+ }
+ free(entry);
+ }
+}
+
+#if HAVE_TDESTROY
+/**
+ * Placeholder for tdestroy.
+ */
+static void
+free_tree_node(void *nodep)
+{
+ return; /* empty */
+}
+#endif
+
+/**
+ * Delete all the entries from the search tree.
+ *
+ * @param[in] list list of entries
+ *
+ * @return none
+ *
+ * @internal
+ */
+/*static*/ void
+destroy_tree(struct afsconf_realms *entries)
+{
+ if (entries->tree) {
+#if HAVE_TDESTROY
+ tdestroy(entries->tree, free_tree_node);
+#else
+ struct opr_queue *cursor;
+ struct afsconf_realm_entry *entry;
+
+ for (opr_queue_Scan(&entries->list, cursor)) {
+ entry = opr_queue_Entry(cursor, struct afsconf_realm_entry, link);
+ tdelete(entry->value, &entries->tree, entries->compare);
+ }
+#endif
+ entries->tree = NULL;
+ }
+}
+
+/**
+ * Build a search tree from the list of entries.
+ *
+ * @param[in] list list of entries
+ *
+ * @return none
+ *
+ * @internal
+ */
+static void
+build_tree(struct afsconf_realms *entries)
+{
+ struct opr_queue *cursor;
+ struct afsconf_realm_entry *entry;
+
+ for (opr_queue_Scan(&entries->list, cursor)) {
+ entry = opr_queue_Entry(cursor, struct afsconf_realm_entry, link);
+ tsearch(entry->value, &entries->tree, entries->compare);
+ }
+}
+
+/**
+ * Read the list of local realms from a config file.
+ *
+ * @param[inout] dir config dir object
+ *
+ * @return status
+ *
+ * @internal
+ */
+static int
+read_local_realms(struct afsconf_realms *entries, const char *path)
+{
+ int code = 0;
+ char realm[AFS_REALM_SZ];
+ struct opr_queue temp;
+ char *filename = NULL;
+ struct stat tstat;
+ FILE *cnffile = NULL;
+ char *linebuf = NULL;
+ char *p;
+
+ opr_queue_Init(&temp);
+ code = asprintf(&filename, "%s/%s", path, AFSDIR_KCONF_FILE);
+ if (code < 0) {
+ code = ENOMEM;
+ goto done;
+ }
+ code = stat(filename, &tstat);
+ if (code < 0) {
+ code = (errno == ENOENT ? 0 : errno); /* this file is optional */
+ goto done;
+ }
+ if (tstat.st_mtime == entries->time_read) {
+ code = 0;
+ goto done;
+ }
+ entries->time_read = tstat.st_mtime;
+ if ((cnffile = fopen(filename, "r")) == NULL) {
+ code = (errno == ENOENT ? 0 : errno); /* this file is optional */
+ goto done;
+ }
+ linebuf = malloc(sizeof(char) * (MAXLINESIZE + 1));
+ if (!linebuf) {
+ code = ENOMEM;
+ goto done;
+ }
+ if (fgets(linebuf, MAXLINESIZE, cnffile) == NULL) {
+ code = errno;
+ goto done;
+ }
+ linebuf[MAXLINESIZE] = '\0';
+ for (p = linebuf; *p;) {
+ p = parse_str(p, realm, AFS_REALM_SZ);
+ if (*realm) {
+ code = add_entry(&temp, realm);
+ if (code) {
+ goto done;
+ }
+ }
+ }
+ destroy_tree(entries);
+ opr_queue_Swap(&temp, &entries->list);
+ build_tree(entries);
+
+ done:
+ free_realm_entries(&temp);
+ if (filename) {
+ free(filename);
+ }
+ if (linebuf) {
+ free(linebuf);
+ }
+ if (cnffile) {
+ fclose(cnffile);
+ }
+ return code;
+}
+
+/**
+ * Read the list of local exclusions from a config file.
+ *
+ * @param[inout] dir config dir object
+ *
+ * @return status
+ *
+ * @internal
+ */
+static int
+read_local_exclusions(struct afsconf_realms *entries, const char *path)
+{
+ int code = 0;
+ char *linebuf = NULL;
+ char *filename = NULL;
+ char name[256];
+ FILE *cnffile = NULL;
+ struct opr_queue temp;
+ struct stat tstat;
+
+ opr_queue_Init(&temp);
+ code = asprintf(&filename, "%s/%s", path, AFSDIR_KRB_EXCL_FILE);
+ if (code < 0) {
+ code = ENOMEM;
+ goto done;
+ }
+ code = stat(filename, &tstat);
+ if (code < 0) {
+ code = (errno == ENOENT ? 0 : errno); /* this file is optional */
+ goto done;
+ }
+ if (tstat.st_mtime == entries->time_read) {
+ code = 0;
+ goto done;
+ }
+ if ((cnffile = fopen(filename, "r")) == NULL) {
+ code = (errno != ENOENT ? errno : 0); /* this file is optional */
+ goto done;
+ }
+ linebuf = malloc(sizeof(char) * (MAXLINESIZE + 1));
+ if (!linebuf) {
+ code = ENOMEM;
+ goto done;
+ }
+ for (;;) {
+ if (fgets(linebuf, MAXLINESIZE, cnffile) == NULL) {
+ break;
+ }
+ linebuf[MAXLINESIZE] = '\0';
+ parse_str(linebuf, name, sizeof(name));
+ if (*name) {
+ code = add_entry(&temp, name);
+ if (code) {
+ goto done;
+ }
+ }
+ }
+ destroy_tree(entries);
+ opr_queue_Swap(&temp, &entries->list);
+ build_tree(entries);
+ done:
+ free_realm_entries(&temp);
+ if (filename) {
+ free(filename);
+ }
+ if (linebuf) {
+ free(linebuf);
+ }
+ if (cnffile) {
+ fclose(cnffile);
+ }
+ return code;
+}
+
+
+/**
+ * Free the local realms and exclusions lists.
+ *
+ * @param[in] dir afsconf dir object
+ *
+ * @return none
+ *
+ * @internal
+ */
+void
+_afsconf_FreeRealms(struct afsconf_dir *dir)
+{
+ if (dir) {
+ if (dir->local_realms) {
+ destroy_tree(dir->local_realms);
+ free_realm_entries(&dir->local_realms->list);
+ dir->local_realms = NULL;
+ }
+ if (dir->exclusions) {
+ destroy_tree(dir->exclusions);
+ free_realm_entries(&dir->exclusions->list);
+ dir->exclusions = NULL;
+ }
+ }
+}
+
+/**
+ * Load the local realms and exclusions lists.
+ *
+ * @param[in] dir afsconf dir object
+ *
+ * @return none
+ *
+ * @internal
+ */
+int
+_afsconf_LoadRealms(struct afsconf_dir *dir)
+{
+ int code = 0;
+ struct afsconf_realms *local_realms = NULL;
+ struct afsconf_realms *exclusions = NULL;
+
+ /* Create and load the list of local realms. */
+ local_realms = malloc(sizeof(struct afsconf_realms));
+ if (!local_realms) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(local_realms, 0, sizeof(struct afsconf_realms));
+ opr_queue_Init(&local_realms->list);
+ local_realms->compare = compare_realms;
+
+ if (!lrealms) {
+ code = read_local_realms(local_realms, dir->name);
+ if (code) {
+ goto cleanup;
+ }
+ } else {
+ struct opr_queue *cursor;
+ struct afsconf_realm_entry *entry;
+ for (opr_queue_Scan(lrealms, cursor)) {
+ entry = opr_queue_Entry(cursor, struct afsconf_realm_entry, link);
+ code = add_entry(&local_realms->list, entry->value);
+ if (code) {
+ goto cleanup;
+ }
+ }
+ build_tree(local_realms);
+ }
+
+ /* Create and load the list of excluded principals. */
+ exclusions = malloc(sizeof(struct afsconf_realms));
+ if (!exclusions) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(exclusions, 0, sizeof(struct afsconf_realms));
+ opr_queue_Init(&exclusions->list);
+ exclusions->compare = compare_principals;
+ code = read_local_exclusions(exclusions, dir->name);
+ if (code) {
+ goto cleanup;
+ }
+
+ dir->local_realms = local_realms;
+ dir->exclusions = exclusions;
+ return 0;
+
+ cleanup:
+ if (local_realms) {
+ destroy_tree(local_realms);
+ free_realm_entries(&local_realms->list);
+ }
+ if (exclusions) {
+ destroy_tree(dir->exclusions);
+ free_realm_entries(&exclusions->list);
+ }
+ return code;
+}
+
+/**
+ * Set a local realm, instead of retrieving the local realms from the
+ * configuration file krb.conf (if it exists). Maybe called multiple
+ * times during application initialization to set one or more local
+ * realms.
+ *
+ * @return status
+ * @retval 0 success
+ * @retval ENOMEM unable to allocate new entry
+ */
+int
+afsconf_SetLocalRealm(const char *realm)
+{
+ int code = 0;
+
+ LOCK_GLOBAL_MUTEX;
+ if (!lrealms) {
+ lrealms = malloc(sizeof(struct opr_queue));
+ if (!lrealms) {
+ code = ENOMEM;
+ goto done;
+ }
+ opr_queue_Init(lrealms);
+ }
+ code = add_entry(lrealms, realm);
+ done:
+ UNLOCK_GLOBAL_MUTEX;
+ return code;
+}
+
+/**
+ * Determine if a principal is local to this cell.
+ *
+ * @param[in] dir afsconf dir object
+ * @param[out] plocal set to 1 if user is local, 0 if foreign
+ * @param[in] name user name
+ * @param[in] inst user instance
+ * @param[in] cell user cell name
+ *
+ * @returns status
+ * @retval 0 success
+ * @retval ENOMEM unable to allocate memory
+ * @retval EINVAL invalid argument
+ */
+int
+afsconf_IsLocalRealmMatch(struct afsconf_dir *dir, afs_int32 * plocal,
+ const char *name, const char *inst,
+ const char *cell)
+{
+ int code = 0;
+ char *localcell = NULL;
+ char *tvname = NULL;
+ struct afsconf_realms *local_realms = NULL;
+ struct afsconf_realms *exclusions = NULL;
+
+ if (!name)
+ return EINVAL;
+
+ if (!cell || !*cell) {
+ *plocal = 1;
+ return code;
+ }
+
+ LOCK_GLOBAL_MUTEX;
+ code = _afsconf_GetLocalCell(dir, &localcell, 1);
+ if (code)
+ goto done;
+
+ /* Does the cell match the local cell name? */
+ if (strcasecmp(localcell, cell) == 0) {
+ *plocal = 1; /* cell matches the local cell name. */
+ goto done;
+ }
+
+ /* Does the cell match one of the local_realms? */
+ local_realms = dir->local_realms;
+ if (!tfind(cell, &local_realms->tree, local_realms->compare)) {
+ *plocal = 0; /* Cell name not found in local realms. */
+ goto done;
+ }
+
+ /* Local realm matches, make sure the principal is not in the
+ * exclusion list, if one. */
+ exclusions = dir->exclusions;
+ if (!exclusions->tree) {
+ *plocal = 1; /* Matches one of the local realms; no exclusions */
+ goto done;
+ }
+
+ /* Create a full principal name for the exclusion check. */
+ code = create_name(&tvname, name, inst, cell);
+ if (!code) {
+ if (tfind(tvname, &exclusions->tree, exclusions->compare)) {
+ *plocal = 0; /* name found in the exclusion list */
+ } else {
+ *plocal = 1; /* not in the exclusion list */
+ }
+ }
+ if (tvname)
+ free(tvname);
+
+ done:
+ UNLOCK_GLOBAL_MUTEX;
+
+ return code;
+}
ktc_errors.o \
acfg_errors.o \
token.o \
- token.xdr.o
+ token.xdr.o \
+ realms.o
KAUTHOBJS = \
kauth.xdr.o \
ptclient.o: ${PTSERVER}/ptclient.c
${AFS_CCRULE} -I../ptserver ${PTSERVER}/ptclient.c
+realms.o: ${AUTH}/realms.c
+ ${AFS_CCRULE} -I../auth ${AUTH}/realms.c
+
ptuser.o: ${PTSERVER}/ptuser.c
${AFS_CCRULE} -I../ptserver ${PTSERVER}/ptuser.c
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
+ $(OUT)\realms.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \
$(OUT)\keys.obj \
afsconf_GetExtendedCellInfo @151
afsconf_UpToDate @152
afsconf_SetSecurityFlags @153
+ afsconf_SetLocalRealm @154
+ afsconf_IsLocalRealmMatch @155
$(UOBJ)/authcon.o \
$(UOBJ)/cellconfig.o \
$(UOBJ)/keys.o \
+ $(UOBJ)/realms.o \
$(UOBJ)/client.o \
$(UOBJ)/acfg_errors.o \
$(UOBJ)/kaaux.o \
$(PICOBJ)/authcon.o \
$(PICOBJ)/cellconfig.o \
$(PICOBJ)/keys.o \
+ $(PICOBJ)/realms.o \
$(PICOBJ)/client.o \
$(PICOBJ)/acfg_errors.o \
$(PICOBJ)/kaaux.o \
$(WEBOBJ)/cellconfig.o \
$(WEBOBJ)/client.o \
$(WEBOBJ)/keys.o \
+ $(WEBOBJ)/realms.o \
$(WEBOBJ)/acfg_errors.o \
$(WEBOBJ)/kaaux.o \
$(WEBOBJ)/kalocalcell.o \
$(WEBOBJ)/cellconfig.o \
$(WEBOBJ)/client.o \
$(WEBOBJ)/keys.o \
+ $(WEBOBJ)/realms.o \
$(WEBOBJ)/acfg_errors.o \
$(WEBOBJ)/kaaux.o \
$(WEBOBJ)/kalocalcell.o \
$(JUAFS)/authcon.o \
$(JUAFS)/cellconfig.o \
$(JUAFS)/keys.o \
+ $(JUAFS)/realms.o \
$(JUAFS)/client.o \
$(JUAFS)/acfg_errors.o \
$(JUAFS)/kaaux.o \
$(CRULE1)
$(UOBJ)/casestrcpy.o: $(TOP_SRCDIR)/opr/casestrcpy.c
$(CRULE1)
+$(UOBJ)/realms.o: $(TOP_SRCDIR)/auth/realms.c
+ $(CRULE1)
$(UOBJ)/dirpath.o: $(TOP_SRCDIR)/util/dirpath.c
$(CRULE1)
$(UOBJ)/fileutil.o: $(TOP_SRCDIR)/util/fileutil.c
$(CRULEPIC)
$(PICOBJ)/casestrcpy.o: $(TOP_SRCDIR)/opr/casestrcpy.c
$(CRULEPIC)
+$(PICOBJ)/realms.o: $(TOP_SRCDIR)/auth/realms.c
+ $(CRULEPIC)
$(PICOBJ)/dirpath.o: $(TOP_SRCDIR)/util/dirpath.c
$(CRULEPIC)
$(PICOBJ)/fileutil.o: $(TOP_SRCDIR)/util/fileutil.c
$(CRULE2)
$(WEBOBJ)/casestrcpy.o: $(TOP_SRCDIR)/opr/casestrcpy.c
$(CRULE1)
+$(WEBOBJ)/realms.o: $(TOP_SRCDIR)/auth/realms.c
+ $(CRULE2)
$(WEBOBJ)/dirpath.o: $(TOP_SRCDIR)/util/dirpath.c
$(CRULE1)
$(WEBOBJ)/fileutil.o: $(TOP_SRCDIR)/util/fileutil.c
$(CRULE1)
$(JUAFS)/casestrcpy.o: $(TOP_SRCDIR)/opr/casestrcpy.c
$(CRULE1)
+$(JUAFS)/realms.o: $(TOP_SRCDIR)/auth/realms.c
+ $(CRULE1)
$(JUAFS)/dirpath.o: $(TOP_SRCDIR)/util/dirpath.c
$(CRULE1)
$(JUAFS)/fileutil.o: $(TOP_SRCDIR)/util/fileutil.c
ktc_errors.o \
acfg_errors.o \
token.xdr.o \
- token.o
+ token.o \
+ realms.o
KAUTHOBJS = \
kauth.xdr.o \
keys.o: ${AUTH}/keys.c
${AFS_CCRULE} -I../auth ${AUTH}/keys.c
+realms.o: ${AUTH}/realms.c
+ ${AFS_CCRULE} -I../auth ${AUTH}/realms.c
+
token.o: ${AUTH}/token.c
${AFS_CCRULE} -I../auth ${AUTH}/token.c
rx_Finalize @85
pr_End @86
pioctl_utf8 @87
+
+ afsconf_SetLocalRealm @88
+ afsconf_IsLocalRealmMatch @89
auth/keys
auth/superuser
auth/authcon
+auth/realms
cmd/command
opr/jhash
opr/queues
/superuser-t
/test.h
/writekeyfile
+/realms-t
include @TOP_OBJDIR@/src/config/Makefile.config
include @TOP_OBJDIR@/src/config/Makefile.pthread
-TESTS = authcon-t superuser-t keys-t
+TESTS = authcon-t superuser-t keys-t realms-t
MODULE_CFLAGS=-I$(srcdir)/.. -I$(srcdir)/../common/
keys-t: keys-t.o ../common/config.o
$(AFS_LDRULE) keys-t.o ../common/config.o $(MODULE_LIBS)
+realms-t: realms-t.o ../common/config.o
+ $(AFS_LDRULE) realms-t.o ../common/config.o $(MODULE_LIBS)
+
writekeyfile: writekeyfile.o
$(AFS_LDRULE) writekeyfile.o $(MODULE_LIBS)
--- /dev/null
+/*
+ * Copyright 2010, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#include <roken.h>
+
+#include <rx/rx.h>
+#include <rx/rxkad.h>
+#include <afs/cellconfig.h>
+
+#include <tap/basic.h>
+#include "common.h"
+
+extern int _afsconf_Touch(struct afsconf_dir *adir);
+
+int verbose = 0;
+
+#define LOCAL 1
+#define FOREIGN 0
+struct testcase {
+ char *name;
+ char *inst;
+ char *cell;
+ int expectedLocal;
+};
+
+/*
+ * test set 0
+ * cell: example.org
+ */
+struct testcase testset0[] = {
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "example.org", LOCAL},
+ {"jdoe", NULL, "EXAMPLE.ORG", LOCAL},
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "my.realm.org", FOREIGN},
+ {"jdoe", NULL, "MY.REALM.ORG", FOREIGN},
+ {"jdoe", NULL, "MY.OTHER.REALM.ORG", FOREIGN},
+ {"jdoe", "admin", NULL, LOCAL},
+ {"jdoe", "admin", "my.realm.org", FOREIGN},
+ {"jdoe", "admin", "MY.REALM.ORG", FOREIGN},
+ {"jdoe", "admin", "your.realm.org", FOREIGN},
+ {"jdoe", "admin", "YOUR.REALM.ORG", FOREIGN},
+ {"admin", NULL, "example.org", LOCAL},
+ {"admin", NULL, "my.realm.org", FOREIGN},
+ {"admin", NULL, "MY.REALM.ORG", FOREIGN},
+ {"admin", NULL, "MY.OTHER.REALM.ORG", FOREIGN},
+ {NULL},
+};
+
+/*
+ * test set 1
+ * cell: example.org
+ * local realms: MY.REALM.ORG, MY.OTHER.REALM.ORG
+ */
+struct testcase testset1[] = {
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "example.org", LOCAL},
+ {"jdoe", NULL, "EXAMPLE.ORG", LOCAL},
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "my.realm.org", LOCAL},
+ {"jdoe", NULL, "MY.REALM.ORG", LOCAL},
+ {"jdoe", NULL, "MY.OTHER.REALM.ORG", LOCAL},
+ {"jdoe", NULL, "SOME.REALM.ORG", FOREIGN},
+ {"jdoe", "admin", NULL, LOCAL},
+ {"jdoe", "admin", "my.realm.org", LOCAL},
+ {"jdoe", "admin", "MY.REALM.ORG", LOCAL},
+ {"jdoe", "admin", "MY.OTHER.REALM.ORG", LOCAL},
+ {"jdoe", "admin", "your.realm.org", FOREIGN},
+ {"jdoe", "admin", "YOUR.REALM.ORG", FOREIGN},
+ {"admin", NULL, "example.org", LOCAL},
+ {"admin", NULL, "my.realm.org", LOCAL},
+ {"admin", NULL, "MY.REALM.ORG", LOCAL},
+ {"admin", NULL, "MY.OTHER.REALM.ORG", LOCAL},
+ {NULL},
+};
+
+/*
+ * test set 2
+ * cell: example.org
+ * local realms: MY.REALM.ORG, MY.OTHER.REALM.ORG
+ * exclude: admin@MY.REALM.ORG
+ */
+struct testcase testset2[] = {
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "example.org", LOCAL},
+ {"jdoe", NULL, "EXAMPLE.ORG", LOCAL},
+ {"jdoe", NULL, NULL, LOCAL},
+ {"jdoe", NULL, "my.realm.org", LOCAL},
+ {"jdoe", NULL, "MY.REALM.ORG", LOCAL},
+ {"jdoe", NULL, "MY.OTHER.REALM.ORG", LOCAL},
+ {"jdoe", "admin", NULL, LOCAL},
+ {"jdoe", "admin", "my.realm.org", LOCAL},
+ {"jdoe", "admin", "MY.REALM.ORG", LOCAL},
+ {"jdoe", "admin", "MY.OTHER.REALM.ORG", LOCAL},
+ {"jdoe", "admin", "your.realm.org", FOREIGN},
+ {"jdoe", "admin", "YOUR.REALM.ORG", FOREIGN},
+ {"admin", NULL, "example.org", LOCAL},
+ {"admin", NULL, "my.realm.org", LOCAL},
+ {"admin", NULL, "MY.REALM.ORG", FOREIGN},
+ {"admin", NULL, "MY.OTHER.REALM.ORG", LOCAL},
+ {NULL},
+};
+
+struct testcase* testset[] = { testset0, testset1, testset2 };
+
+char *
+make_string(int len)
+{
+ char *s = malloc(len + 1);
+ if (!s) {
+ fprintf(stderr, "Failed to allocate string buffer.\n");
+ exit(1);
+ }
+ memset(s, 'x', len);
+ s[len] = '\0';
+ return s;
+}
+
+void
+run_tests(struct afsconf_dir *dir, int setnum, char *setname)
+{
+ struct testcase *t;
+ int code;
+
+ for (t = testset[setnum]; t->name; t++) {
+ afs_int32 local = -1;
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, t->name, t->inst, t->cell);
+ ok(code == 0, "%s: test case %s/%s/%s",
+ setname,
+ t->name ? t->name : "(null)",
+ t->inst ? t->inst : "(null)",
+ t->cell ? t->cell : "(null)");
+ if (code==0) {
+ ok(local == t->expectedLocal, "... expected %d, got %d", t->expectedLocal, local);
+ }
+ }
+}
+
+void
+run_edge_tests(struct afsconf_dir *dir)
+{
+ afs_int32 local = -1;
+ int code = 0;
+ char *name = "jdoe";
+ char *inst = "";
+ char *cell = "";
+
+ /* null argument checks */
+ code = afsconf_IsLocalRealmMatch(dir, &local, NULL, inst, cell);
+ ok(code == EINVAL, "null name: code=%d", code);
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, name, NULL, cell);
+ ok(code == 0, "null inst: code=%d", code);
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, name, inst, NULL);
+ ok(code == 0, "null cell: code=%d", code);
+
+ /* large ticket test */
+ name = make_string(64);
+ inst = make_string(64);
+ cell = make_string(64);
+ code = afsconf_IsLocalRealmMatch(dir, &local, name, inst, cell);
+ ok(code == 0, "name size 64: code=%d", code);
+ free(name);
+ free(inst);
+ free(cell);
+
+ name = make_string(255);
+ inst = NULL;
+ cell = "my.realm.org";
+ code = afsconf_IsLocalRealmMatch(dir, &local, name, inst, cell);
+ ok(code == 0, "name size 255: code=%d", code);
+ free(name);
+}
+
+void
+write_krb_conf(char *dirname, char *data)
+{
+ char *filename = NULL;
+ FILE *fp;
+
+ asnprintf(&filename, 256, "%s/%s", dirname, "krb.conf");
+ if ((fp = fopen(filename, "w")) == NULL) {
+ fprintf(stderr, "Unable to create test file %s\n", filename);
+ exit(1);
+ }
+ if (verbose) {
+ diag("writing to %s: %s", filename, data);
+ }
+ fprintf(fp, "%s\n", data);
+ fclose(fp);
+ free(filename);
+}
+
+void
+write_krb_excl(char *dirname)
+{
+ char *filename = NULL;
+ FILE *fp;
+ char *data;
+
+ asnprintf(&filename, 256, "%s/%s", dirname, "krb.excl");
+ if ((fp = fopen(filename, "w")) == NULL) {
+ fprintf(stderr, "Unable to create test file %s\n", filename);
+ exit(1);
+ }
+ data = "admin@MY.REALM.ORG";
+ if (verbose) {
+ diag("writing to %s: %s", filename, data);
+ }
+ fprintf(fp, "%s\n", data);
+ data = "admin@EXAMPLE.ORG";
+ if (verbose) {
+ diag("writing to %s: %s", filename, data);
+ }
+ fprintf(fp, "%s\n", data);
+ fclose(fp);
+ free(filename);
+}
+
+void
+update_csdb(char *dirname)
+{
+ char *filename = NULL;
+ FILE *fp;
+
+ asnprintf(&filename, 256, "%s/%s", dirname, "CellServDB");
+ if ((fp = fopen(filename, "a")) == NULL) {
+ fprintf(stderr, "Unable to create test file %s\n", filename);
+ exit(1);
+ }
+ fprintf(fp, "10.0.0.1 #bogus.example.org\n");
+ fclose(fp);
+ free(filename);
+}
+
+void
+test_edges(void)
+{
+ struct afsconf_dir *dir;
+ char *dirname;
+
+ /* run edge case tests */
+ dirname = afstest_BuildTestConfig();
+ dir = afsconf_Open(dirname);
+ if (dir == NULL) {
+ fprintf(stderr, "Unable to configure directory.\n");
+ exit(1);
+ }
+ run_edge_tests(dir);
+ afstest_UnlinkTestConfig(dirname);
+}
+
+void
+test_no_config_files(void)
+{
+ struct afsconf_dir *dir;
+ char *dirname;
+
+ /* run tests without config files */
+ dirname = afstest_BuildTestConfig();
+ dir = afsconf_Open(dirname);
+ if (dir == NULL) {
+ fprintf(stderr, "Unable to configure directory.\n");
+ exit(1);
+ }
+ run_tests(dir, 0, "no config");
+ afstest_UnlinkTestConfig(dirname);
+}
+
+void
+test_with_config_files(void)
+{
+ struct afsconf_dir *dir;
+ char *dirname;
+
+ /* run tests with config files */
+ dirname = afstest_BuildTestConfig();
+ write_krb_conf(dirname, "MY.REALM.ORG MY.OTHER.REALM.ORG");
+ write_krb_excl(dirname);
+ dir = afsconf_Open(dirname);
+ if (dir == NULL) {
+ fprintf(stderr, "Unable to configure directory.\n");
+ exit(1);
+ }
+ run_tests(dir, 2, "config");
+ afstest_UnlinkTestConfig(dirname);
+}
+
+void
+test_set_local_realms(void)
+{
+ struct afsconf_dir *dir;
+ char *dirname;
+
+ /* Simulate command line -realm option; overrides config file, if one.
+ * Multiple realms can be added. */
+ ok(afsconf_SetLocalRealm("MY.REALM.ORG") == 0, "set local realm MY.REALM.ORG");
+ ok(afsconf_SetLocalRealm("MY.OTHER.REALM.ORG") == 0, "set local realm MY.OTHER.REALM.ORG");
+
+ /* run tests without config files */
+ dirname = afstest_BuildTestConfig();
+ dir = afsconf_Open(dirname);
+ if (dir == NULL) {
+ fprintf(stderr, "Unable to configure directory.\n");
+ exit(1);
+ }
+ write_krb_conf(dirname, "SOME.REALM.ORG");
+ run_tests(dir, 1, "set realm test");
+ afstest_UnlinkTestConfig(dirname);
+}
+
+void
+test_update_config_files(void)
+{
+ int code;
+ struct afsconf_dir *dir;
+ char *dirname;
+ afs_int32 local = -1;
+
+ dirname = afstest_BuildTestConfig();
+ write_krb_conf(dirname, "SOME.REALM.ORG");
+ dir = afsconf_Open(dirname);
+ if (dir == NULL) {
+ fprintf(stderr, "Unable to configure directory.\n");
+ exit(1);
+ }
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, "jdoe", NULL, "SOME.REALM.ORG");
+ ok(code == 0 && local == 1, "before update: jdoe@SOME.REALM.ORG");
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, "jdoe", NULL, "MY.REALM.ORG");
+ ok(code == 0 && local == 0, "before update: admin@MY.REALM.ORG");
+
+ write_krb_conf(dirname, "MY.REALM.ORG MY.OTHER.REALM.ORG");
+ write_krb_excl(dirname);
+ update_csdb(dirname);
+ _afsconf_Touch(dir); /* forces reopen */
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, "jdoe", NULL, "MY.REALM.ORG");
+ ok(code == 0 && local == 1, "after update: jdoe@MY.REALM.ORG");
+
+ code = afsconf_IsLocalRealmMatch(dir, &local, "admin", NULL, "MY.REALM.ORG");
+ ok(code == 0 && local == 0, "after update: admin@MY.REALM.ORG");
+
+ afstest_UnlinkTestConfig(dirname);
+}
+
+int
+main(int argc, char **argv)
+{
+ plan(113);
+
+ test_edges();
+ test_no_config_files();
+ test_with_config_files();
+ test_update_config_files();
+ test_set_local_realms(); /* must be the last test */
+
+ return 0;
+}
unlinkConfigFile(dir, "CellServDB");
unlinkConfigFile(dir, "ThisCell");
unlinkConfigFile(dir, "UserList");
+ unlinkConfigFile(dir, "krb.conf");
+ unlinkConfigFile(dir, "krb.excl");
rmdir(dir);
}