auth: local realms configuration

Add krb.conf and krb.excl support to the auth cell configuration
library.  Provide a function to determine if the user is local to the
cell.  Provide a function to set the local realms during application
initialization.  These changes are intended to replace the functions
afs_krb_get_lrealm and afs_is_foreign_ticket_name.

Change-Id: Iba57e9ffc2c958f3a4565a9352ce172189276ce9
Reviewed-on: http://gerrit.openafs.org/5744
Reviewed-by: Derrick Brashear <shadow@dementix.org>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
This commit is contained in:
Michael Meffie 2012-02-28 08:50:33 -05:00 committed by Derrick Brashear
parent a3ff62857c
commit f8b759b63f
18 changed files with 1032 additions and 5 deletions

View File

@ -1432,6 +1432,7 @@ AC_CHECK_FUNCS([ \
strerror \
sysconf \
sysctl \
tdestroy \
timegm \
])

View File

@ -11,9 +11,9 @@ include @TOP_OBJDIR@/src/config/Makefile.lwp
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 \
@ -70,6 +70,7 @@ userok.o: userok.c ${INCLS}
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

View File

@ -41,6 +41,7 @@ AFSAUTH_LIBOBJS =\
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
$(OUT)\realms.obj \
$(OUT)\acfg_errors.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \
@ -67,6 +68,7 @@ AFSAUTH_KRB_LIBOBJS =\
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
$(OUT)\realms.obj \
$(OUT)\acfg_errors.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \

View File

@ -823,6 +823,10 @@ afsconf_OpenInternal(struct afsconf_dir *adir, char *cell,
/* now read the fs keys, if possible */
code = _afsconf_LoadKeys(adir);
if (code) {
return code;
}
code = _afsconf_LoadRealms(adir);
return code;
}
@ -1559,6 +1563,7 @@ afsconf_CloseInternal(struct afsconf_dir *adir)
}
_afsconf_FreeAllKeys(adir);
_afsconf_FreeRealms(adir);
/* reinit */
memset(adir, 0, sizeof(struct afsconf_dir));

View File

@ -97,6 +97,8 @@ 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);
@ -252,6 +254,12 @@ extern int afsconf_SuperIdentity(struct afsconf_dir *, struct rx_call *,
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

View File

@ -6,3 +6,5 @@ extern int _afsconf_LoadKeys(struct afsconf_dir *adir);
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);

603
src/auth/realms.c Normal file
View File

@ -0,0 +1,603 @@
/*
* 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;
}

View File

@ -35,7 +35,8 @@ AUTHOBJS = \
ktc_errors.o \
acfg_errors.o \
token.o \
token.xdr.o
token.xdr.o \
realms.o
KAUTHOBJS = \
kauth.xdr.o \
@ -228,6 +229,9 @@ rxkad_errs.o: ../rxkad/rxkad_errs.c
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

View File

@ -39,6 +39,7 @@ AUTHOBJS = \
$(OUT)\userok.obj \
$(OUT)\writeconfig.obj \
$(OUT)\authcon.obj \
$(OUT)\realms.obj \
$(OUT)\ktc_errors.obj \
$(OUT)\ktc_nt.obj \
$(OUT)\keys.obj \

View File

@ -152,3 +152,5 @@ EXPORTS
afsconf_GetExtendedCellInfo @151
afsconf_UpToDate @152
afsconf_SetSecurityFlags @153
afsconf_SetLocalRealm @154
afsconf_IsLocalRealmMatch @155

View File

@ -228,6 +228,7 @@ UAFSOBJ = \
$(UOBJ)/authcon.o \
$(UOBJ)/cellconfig.o \
$(UOBJ)/keys.o \
$(UOBJ)/realms.o \
$(UOBJ)/client.o \
$(UOBJ)/acfg_errors.o \
$(UOBJ)/kaaux.o \
@ -376,6 +377,7 @@ PICUAFSOBJ = \
$(PICOBJ)/authcon.o \
$(PICOBJ)/cellconfig.o \
$(PICOBJ)/keys.o \
$(PICOBJ)/realms.o \
$(PICOBJ)/client.o \
$(PICOBJ)/acfg_errors.o \
$(PICOBJ)/kaaux.o \
@ -525,6 +527,7 @@ AFSWEBOBJ = \
$(WEBOBJ)/cellconfig.o \
$(WEBOBJ)/client.o \
$(WEBOBJ)/keys.o \
$(WEBOBJ)/realms.o \
$(WEBOBJ)/acfg_errors.o \
$(WEBOBJ)/kaaux.o \
$(WEBOBJ)/kalocalcell.o \
@ -667,6 +670,7 @@ AFSWEBOBJKRB = \
$(WEBOBJ)/cellconfig.o \
$(WEBOBJ)/client.o \
$(WEBOBJ)/keys.o \
$(WEBOBJ)/realms.o \
$(WEBOBJ)/acfg_errors.o \
$(WEBOBJ)/kaaux.o \
$(WEBOBJ)/kalocalcell.o \
@ -812,6 +816,7 @@ JUAFSOBJ = \
$(JUAFS)/authcon.o \
$(JUAFS)/cellconfig.o \
$(JUAFS)/keys.o \
$(JUAFS)/realms.o \
$(JUAFS)/client.o \
$(JUAFS)/acfg_errors.o \
$(JUAFS)/kaaux.o \
@ -1105,6 +1110,8 @@ $(UOBJ)/keys.o: $(TOP_SRCDIR)/auth/keys.c
$(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
@ -1408,6 +1415,8 @@ $(PICOBJ)/keys.o: $(TOP_SRCDIR)/auth/keys.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
@ -1720,6 +1729,8 @@ $(WEBOBJ)/keys.o: $(TOP_SRCDIR)/auth/keys.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
@ -2018,6 +2029,8 @@ $(JUAFS)/keys.o: $(TOP_SRCDIR)/auth/keys.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

View File

@ -42,7 +42,8 @@ AUTHOBJS = \
ktc_errors.o \
acfg_errors.o \
token.xdr.o \
token.o
token.o \
realms.o
KAUTHOBJS = \
kauth.xdr.o \
@ -191,6 +192,9 @@ ktc.o: ${AUTH}/ktc.c
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

View File

@ -87,3 +87,6 @@ EXPORTS
rx_Finalize @85
pr_End @86
pioctl_utf8 @87
afsconf_SetLocalRealm @88
afsconf_IsLocalRealmMatch @89

View File

@ -3,6 +3,7 @@ util/exec-alt
auth/keys
auth/superuser
auth/authcon
auth/realms
cmd/command
opr/jhash
opr/queues

View File

@ -3,3 +3,4 @@
/superuser-t
/test.h
/writekeyfile
/realms-t

View File

@ -4,7 +4,7 @@ abs_top_builddir=@abs_top_builddir@
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/
@ -30,6 +30,9 @@ superuser-t: superuser-t.o ../common/config.o test.cs.o test.ss.o test.xdr.o
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)

371
tests/auth/realms-t.c Normal file
View File

@ -0,0 +1,371 @@
/*
* 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;
}

View File

@ -124,6 +124,8 @@ afstest_UnlinkTestConfig(char *dir)
unlinkConfigFile(dir, "CellServDB");
unlinkConfigFile(dir, "ThisCell");
unlinkConfigFile(dir, "UserList");
unlinkConfigFile(dir, "krb.conf");
unlinkConfigFile(dir, "krb.excl");
rmdir(dir);
}