AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config])
V5_AC_OUTPUT_MAKEFILE(.
- util util/support util/profile util/send-pr
+ util util/support util/profile util/profile/testmod util/send-pr
lib lib/kdb
retval = add_kdc_config_file(&files);
if (!retval) {
- retval = profile_init((const_profile_filespec_t *) files,
- &ctx->profile);
+ retval = profile_init_flags((const_profile_filespec_t *) files,
+ PROFILE_INIT_ALLOW_MODULE, &ctx->profile);
#ifdef KRB5_DNS_LOOKUP
/* if none of the filenames can be opened use an empty profile */
krb5_error_code retval = 0;
profile_t profile;
- retval = profile_init(filenames, &profile);
+ retval = profile_init_flags(filenames, PROFILE_INIT_ALLOW_MODULE,
+ &profile);
if (retval)
return retval;
mydir=util$(S)profile
BUILDTOP=$(REL)..$(S)..
+SUBDIRS=testmod
PROG_LIBPATH=-L$(TOPLIBD) $(TCL_LIBPATH) -L.
PROG_RPATH=$(KRB5_LIBDIR)$(TCL_RPATH)
KRB5_RUN_ENV=@KRB5_RUN_ENV@
LOCALINCLUDES=-I. $(TCL_INCLUDES)
# for tcl.h
-DEFINES=-DHAS_STDARG
+DEFINES=-DHAS_STDARG -DLIBDIR=\"$(KRB5_LIBDIR)\"
STLIBOBJS = \
prof_tree.o \
prof_err.c \
$(srcdir)/prof_init.c
-EXTRADEPSRCS=$(srcdir)/test_parse.c $(srcdir)/test_profile.c \
- $(srcdir)/test_vtable.c $(srcdir)/profile_tcl.c
+EXTRADEPSRCS=$(srcdir)/test_load.c $(srcdir)/test_parse.c \
+ $(srcdir)/test_profile.c $(srcdir)/test_vtable.c \
+ $(srcdir)/profile_tcl.c
DEPLIBS = $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
MLIBS = -lcom_err $(SUPPORT_LIB) $(LIBS)
test_vtable: test_vtable.$(OBJEXT) $(OBJS) $(DEPLIBS)
$(CC_LINK) -o test_vtable test_vtable.$(OBJEXT) $(OBJS) $(MLIBS)
+test_load: test_load.$(OBJEXT) $(SUPPORT_DEPLIB)
+ $(CC_LINK) -o test_load test_load.$(OBJEXT) $(OBJS) $(MLIBS)
+
+modtest.conf:
+ echo "module `pwd`/testmod/proftest$(DYNOBJEXT):teststring" > $@
+
.d: includes
# NEED TO FIX!!
-L../et -L../.. -lprofile $(TCL_LIBS) $(MLIBS)
clean-unix:: clean-libs clean-libobjs
- $(RM) $(PROGS) *.o *~ test_parse core prof_err.h \
- prof_err.c test_profile test_vtable profile.h profile_tcl
+ $(RM) $(PROGS) *.o *~ core prof_err.h profile.h prof_err.c
+ $(RM) test_load test_parse test_profile test_vtable profile_tcl
+ $(RM) modtest.conf
clean-windows::
$(RM) $(PROFILE_HDR)
-check-unix:: test_parse test_profile test_vtable
+check-unix:: test_parse test_profile test_vtable test_load modtest.conf
$(KRB5_RUN_ENV) $(VALGRIND) ./test_vtable
+ $(KRB5_RUN_ENV) $(VALGRIND) ./test_load
DO_TCL=@DO_TCL@
check-unix:: check-unix-tcl-$(DO_TCL)
#
prof_tree.so prof_tree.po $(OUTPRE)prof_tree.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_int.h prof_tree.c
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_int.h prof_tree.c
prof_file.so prof_file.po $(OUTPRE)prof_file.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_file.c prof_int.h
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_file.c prof_int.h
prof_parse.so prof_parse.po $(OUTPRE)prof_parse.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_int.h prof_parse.c
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_int.h prof_parse.c
prof_get.so prof_get.po $(OUTPRE)prof_get.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_get.c prof_int.h
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_get.c prof_int.h
prof_set.so prof_set.po $(OUTPRE)prof_set.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_int.h prof_set.c
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_int.h prof_set.c
prof_err.so prof_err.po $(OUTPRE)prof_err.$(OBJEXT): \
$(COM_ERR_DEPS) prof_err.c
prof_init.so prof_init.po $(OUTPRE)prof_init.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_init.c prof_int.h
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_init.c prof_int.h
+test_load.so test_load.po $(OUTPRE)test_load.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_int.h test_load.c
test_parse.so test_parse.po $(OUTPRE)test_parse.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h prof_int.h test_parse.c
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ prof_int.h test_parse.c
test_profile.so test_profile.po $(OUTPRE)test_profile.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ argv_parse.h prof_int.h test_profile.c
+test_vtable.so test_vtable.po $(OUTPRE)test_vtable.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
$(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h argv_parse.h prof_int.h \
- test_profile.c
+ $(top_srcdir)/include/k5-thread.h test_vtable.c
profile_tcl.so profile_tcl.po $(OUTPRE)profile_tcl.$(OBJEXT): \
$(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) profile_tcl.c
profile_get_subsection_names
profile_get_values
profile_init
+profile_init_flags
profile_init_path
+profile_init_vtable
profile_iterator
profile_iterator_create
profile_iterator_free
"Included profile directory could not be read"
error_code PROF_UNSUPPORTED, "Operation not supported on this profile"
error_code PROF_MAGIC_NODE_ITERATOR, "Bad magic value in profile iterator"
+error_code PROF_MODULE, "Unexpected module declaration in profile"
+error_code PROF_MODULE_SYNTAX,
+ "Invalid syntax of module declaration in profile"
+error_code PROF_MODULE_INVALID, "Invalid profile module"
end
}
errcode_t profile_open_file(const_profile_filespec_t filespec,
- prf_file_t *ret_prof)
+ prf_file_t *ret_prof, char **ret_modspec)
{
prf_file_t prf;
errcode_t retval;
if (data) {
data->refcount++;
(void) k5_mutex_unlock(&g_shared_trees_mutex);
- retval = profile_update_file_data(data);
+ retval = profile_update_file_data(data, NULL);
free(expanded_filename);
prf->data = data;
*ret_prof = prf;
return retval;
}
- retval = profile_update_file(prf);
+ retval = profile_update_file(prf, ret_modspec);
if (retval) {
profile_close_file(prf);
return retval;
return 0;
}
-errcode_t profile_update_file_data_locked(prf_data_t data)
+errcode_t profile_update_file_data_locked(prf_data_t data, char **ret_modspec)
{
errcode_t retval;
#ifdef HAVE_STAT
set_cloexec_file(f);
data->upd_serial++;
data->flags &= PROFILE_FILE_SHARED; /* FIXME same as '=' operator */
- retval = profile_parse_file(f, &data->root);
+ retval = profile_parse_file(f, &data->root, ret_modspec);
fclose(f);
if (retval) {
return retval;
return 0;
}
-errcode_t profile_update_file_data(prf_data_t data)
+errcode_t profile_update_file_data(prf_data_t data, char **ret_modspec)
{
errcode_t retval, retval2;
retval = k5_mutex_lock(&data->lock);
if (retval)
return retval;
- retval = profile_update_file_data_locked(data);
+ retval = profile_update_file_data_locked(data, ret_modspec);
retval2 = k5_mutex_unlock(&data->lock);
return retval ? retval : retval2;
}
#endif
typedef int32_t prof_int32;
-errcode_t KRB5_CALLCONV
-profile_init_vtable(struct profile_vtable *vtable, void *cbdata,
- profile_t *ret_profile)
+/* Create a vtable profile, possibly with a library handle. The new profile
+ * takes ownership of the handle refcount on success. */
+static errcode_t
+init_module(struct profile_vtable *vtable, void *cbdata,
+ prf_lib_handle_t handle, profile_t *ret_profile)
{
profile_t profile;
struct profile_vtable *vt_copy;
profile->vt = vt_copy;
profile->cbdata = cbdata;
+ profile->lib_handle = handle;
profile->magic = PROF_MAGIC_PROFILE;
*ret_profile = profile;
return 0;
}
+/* Parse modspec into the module path and residual string. */
+static errcode_t
+parse_modspec(const char *modspec, char **ret_path, char **ret_residual)
+{
+ const char *p, *prefix;
+ char *path, *residual;
+
+ *ret_path = *ret_residual = NULL;
+
+ p = strchr(modspec, ':');
+ if (p == NULL)
+ return PROF_MODULE_SYNTAX;
+
+ /* XXX Unix path handling for now. */
+ prefix = (*modspec == '/') ? "" : LIBDIR "/";
+ if (asprintf(&path, "%s%.*s", prefix, (int)(p - modspec), modspec) < 0)
+ return ENOMEM;
+
+ residual = strdup(p + 1);
+ if (residual == NULL) {
+ free(path);
+ return ENOMEM;
+ }
+
+ *ret_path = path;
+ *ret_residual = residual;
+ return 0;
+}
+
+/* Load a dynamic profile module as specified by modspec and create a vtable
+ * profile for it in *ret_profile. */
+static errcode_t
+init_load_module(const char *modspec, profile_t *ret_profile)
+{
+ char *modpath = NULL, *residual = NULL;
+ struct errinfo einfo = { 0 };
+ prf_lib_handle_t lib_handle = NULL;
+ struct plugin_file_handle *plhandle = NULL;
+ void *cbdata = NULL, (*fptr)();
+ int have_lock = 0, have_cbdata = 0;
+ struct profile_vtable vtable = { 1 }; /* Set minor_ver to 1, rest null. */
+ errcode_t err;
+ profile_module_init_fn initfn;
+
+ err = parse_modspec(modspec, &modpath, &residual);
+ if (err)
+ goto cleanup;
+
+ /* Allocate a reference-counted library handle container. */
+ lib_handle = malloc(sizeof(*lib_handle));
+ if (lib_handle == NULL)
+ goto cleanup;
+ err = k5_mutex_init(&lib_handle->lock);
+ if (err)
+ goto cleanup;
+ have_lock = 1;
+
+ /* Open the module and get its initializer. */
+ err = krb5int_open_plugin(modpath, &plhandle, &einfo);
+ if (err)
+ goto cleanup;
+ err = krb5int_get_plugin_func(plhandle, "profile_module_init", &fptr,
+ &einfo);
+ if (err == ENOENT)
+ err = PROF_MODULE_INVALID;
+ if (err)
+ goto cleanup;
+
+ /* Get the profile vtable and callback data pointer. */
+ initfn = (profile_module_init_fn)fptr;
+ err = (*initfn)(residual, &vtable, &cbdata);
+ if (err)
+ goto cleanup;
+ have_cbdata = 1;
+
+ /* Create a vtable profile with the information obtained. */
+ lib_handle->plugin_handle = plhandle;
+ lib_handle->refcount = 1;
+ err = init_module(&vtable, cbdata, lib_handle, ret_profile);
+
+cleanup:
+ free(modpath);
+ free(residual);
+ krb5int_clear_error(&einfo);
+ if (err) {
+ if (have_cbdata && vtable.cleanup)
+ vtable.cleanup(cbdata);
+ if (have_lock)
+ k5_mutex_destroy(&lib_handle->lock);
+ free(lib_handle);
+ if (plhandle)
+ krb5int_close_plugin(plhandle);
+ }
+ return err;
+}
+
errcode_t KRB5_CALLCONV
-profile_init(const_profile_filespec_t *files, profile_t *ret_profile)
+profile_init_flags(const_profile_filespec_t *files, int flags,
+ profile_t *ret_profile)
{
const_profile_filespec_t *fs;
profile_t profile;
prf_file_t new_file, last = 0;
errcode_t retval = 0, access_retval = 0;
+ char *modspec = NULL, **modspec_arg;
profile = malloc(sizeof(struct _profile_t));
if (!profile)
*/
if ( files && !PROFILE_LAST_FILESPEC(*files) ) {
for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
- retval = profile_open_file(*fs, &new_file);
+ /* Allow a module declaration if it is permitted by flags and this
+ * is the first file parsed. */
+ modspec_arg = ((flags & PROFILE_INIT_ALLOW_MODULE) && !last) ?
+ &modspec : NULL;
+ retval = profile_open_file(*fs, &new_file, modspec_arg);
+ if (retval == PROF_MODULE && modspec) {
+ /* Stop parsing files and load a dynamic module instead. */
+ free(profile);
+ retval = init_load_module(modspec, ret_profile);
+ free(modspec);
+ return retval;
+ }
/* if this file is missing, skip to the next */
if (retval == ENOENT) {
continue;
return 0;
}
+errcode_t KRB5_CALLCONV
+profile_init(const_profile_filespec_t *files, profile_t *ret_profile)
+{
+ return profile_init_flags(files, 0, ret_profile);
+}
+
+errcode_t KRB5_CALLCONV
+profile_init_vtable(struct profile_vtable *vtable, void *cbdata,
+ profile_t *ret_profile)
+{
+ return init_module(vtable, cbdata, NULL, ret_profile);
+}
+
+/* Copy a vtable profile. */
+static errcode_t
+copy_vtable_profile(profile_t profile, profile_t *ret_new_profile)
+{
+ errcode_t err;
+ void *cbdata;
+ profile_t new_profile;
+
+ *ret_new_profile = NULL;
+
+ if (profile->vt->copy) {
+ /* Make a copy of profile's cbdata for the new profile. */
+ err = profile->vt->copy(profile->cbdata, &cbdata);
+ if (err)
+ return err;
+ err = init_module(profile->vt, cbdata, profile->lib_handle,
+ &new_profile);
+ if (err && profile->vt->cleanup)
+ profile->vt->cleanup(cbdata);
+ } else {
+ /* Use the same cbdata as the old profile. */
+ err = init_module(profile->vt, profile->cbdata, profile->lib_handle,
+ &new_profile);
+ }
+ if (err)
+ return err;
+
+ /* Increment the refcount on the library handle if there is one. */
+ if (profile->lib_handle) {
+ err = k5_mutex_lock(&profile->lib_handle->lock);
+ if (err) {
+ /* Don't decrement the refcount we failed to increment. */
+ new_profile->lib_handle = NULL;
+ profile_abandon(new_profile);
+ return err;
+ }
+ profile->lib_handle->refcount++;
+ k5_mutex_unlock(&profile->lib_handle->lock);
+ }
+
+ *ret_new_profile = new_profile;
+ return 0;
+}
+
#define COUNT_LINKED_LIST(COUNT, PTYPE, START, FIELD) \
{ \
size_t cll_counter = 0; \
const_profile_filespec_t *files;
prf_file_t file;
errcode_t err;
- void *cbdata;
- /* For copies of vtable profiles, use the same vtable and perhaps a new
- * cbdata pointer. */
- if (old_profile->vt) {
- if (old_profile->vt->copy) {
- /* Make a copy of the cbdata for the new profile. */
- err = old_profile->vt->copy(old_profile->cbdata, &cbdata);
- if (err)
- return err;
- err = profile_init_vtable(old_profile->vt, cbdata, new_profile);
- if (err && old_profile->vt->cleanup)
- old_profile->vt->cleanup(cbdata);
- return err;
- } else {
- /* Use the same vtable and cbdata as the old profile. */
- return profile_init_vtable(old_profile->vt, old_profile->cbdata,
- new_profile);
- }
- }
+ if (old_profile->vt)
+ return copy_vtable_profile(old_profile, new_profile);
/* The fields we care about are read-only after creation, so
no locking is needed. */
/* cap the array */
filenames[i] = 0;
- retval = profile_init((const_profile_filespec_t *) filenames,
- ret_profile);
+ retval = profile_init_flags((const_profile_filespec_t *) filenames, 0,
+ ret_profile);
/* count back down and free the entries */
while(--i >= 0) free(filenames[i]);
profile_abandon(profile_t profile)
{
prf_file_t p, next;
+ errcode_t err;
if (!profile || profile->magic != PROF_MAGIC_PROFILE)
return;
if (profile->vt) {
if (profile->vt->cleanup)
profile->vt->cleanup(profile->cbdata);
+ if (profile->lib_handle) {
+ /* Decrement the refcount on the handle and maybe free it. */
+ err = k5_mutex_lock(&profile->lib_handle->lock);
+ if (!err && --profile->lib_handle->refcount == 0) {
+ krb5int_close_plugin(profile->lib_handle->plugin_handle);
+ free(profile->lib_handle);
+ }
+ }
free(profile->vt);
} else {
for (p = profile->first_file; p; p = next) {
return;
if (profile->vt) {
+ /* Flush the profile and then delegate to profile_abandon. */
if (profile->vt->flush)
profile->vt->flush(profile->cbdata);
- if (profile->vt->cleanup)
- profile->vt->cleanup(profile->cbdata);
- free(profile->vt);
+ profile_abandon(profile);
+ return;
} else {
for (p = profile->first_file; p; p = next) {
next = p->next;
#include "k5-thread.h"
#include "k5-platform.h"
+#include "k5-plugin.h"
#include "com_err.h"
#include "profile.h"
#define PROFILE_FILE_DIRTY 0x0002
#define PROFILE_FILE_SHARED 0x0004
+struct _prf_lib_handle_t {
+ k5_mutex_t lock;
+ int refcount;
+ struct plugin_file_handle *plugin_handle;
+};
+
+typedef struct _prf_lib_handle_t *prf_lib_handle_t;
+
/*
* This structure defines the high-level, user visible profile_t
* object, which is used as a handle by users who need to query some
/* If non-null, use vtable operations instead of native ones. */
struct profile_vtable *vt;
void *cbdata;
+ prf_lib_handle_t lib_handle;
};
/*
/* profile_parse.c */
errcode_t profile_parse_file
- (FILE *f, struct profile_node **root);
+ (FILE *f, struct profile_node **root, char **ret_modspec);
errcode_t profile_write_tree_file
(struct profile_node *root, FILE *dstfile);
errcode_t KRB5_CALLCONV profile_copy (profile_t, profile_t *);
errcode_t profile_open_file
- (const_profile_filespec_t file, prf_file_t *ret_prof);
+ (const_profile_filespec_t file, prf_file_t *ret_prof,
+ char **ret_modspec);
-#define profile_update_file(P) profile_update_file_data((P)->data)
+#define profile_update_file(P, M) profile_update_file_data((P)->data, M)
errcode_t profile_update_file_data
- (prf_data_t profile);
-#define profile_update_file_locked(P) profile_update_file_data_locked((P)->data)
+ (prf_data_t profile, char **ret_modspec);
+#define profile_update_file_locked(P, M) profile_update_file_data_locked((P)->data, M)
errcode_t profile_update_file_data_locked
- (prf_data_t data);
+ (prf_data_t data, char **ret_modspec);
#define profile_flush_file(P) (((P) && (P)->magic == PROF_MAGIC_FILE) ? profile_flush_file_data((P)->data) : PROF_MAGIC_FILE)
errcode_t profile_flush_file_data
struct profile_node *current_section;
};
-static errcode_t parse_file(FILE *f, struct parse_state *state);
+static errcode_t parse_file(FILE *f, struct parse_state *state,
+ char **ret_modspec);
static char *skip_over_blanks(char *cp)
{
fp = fopen(filename, "r");
if (fp == NULL)
return PROF_FAIL_INCLUDE_FILE;
- retval = parse_file(fp, &incstate);
+ retval = parse_file(fp, &incstate, NULL);
fclose(fp);
return retval;
}
#endif /* not _WIN32 */
}
-static errcode_t parse_line(char *line, struct parse_state *state)
+static errcode_t parse_line(char *line, struct parse_state *state,
+ char **ret_modspec)
{
char *cp;
}
switch (state->state) {
case STATE_INIT_COMMENT:
+ if (strncmp(line, "module", 6) == 0 && isspace(line[6])) {
+ /*
+ * If we are expecting a module declaration, fill in *ret_modspec
+ * and return PROF_MODULE, which will cause parsing to abort and
+ * the module to be loaded instead. If we aren't expecting a
+ * module declaration, return PROF_MODULE without filling in
+ * *ret_modspec, which will be treated as an ordinary error.
+ */
+ if (ret_modspec) {
+ cp = skip_over_blanks(line + 6);
+ strip_line(cp);
+ *ret_modspec = strdup(cp);
+ if (!*ret_modspec)
+ return ENOMEM;
+ }
+ return PROF_MODULE;
+ }
if (line[0] != '[')
return 0;
state->state = STATE_STD_LINE;
return 0;
}
-static errcode_t parse_file(FILE *f, struct parse_state *state)
+static errcode_t parse_file(FILE *f, struct parse_state *state,
+ char **ret_modspec)
{
#define BUF_SIZE 2048
char *bptr;
if (fgets(bptr, BUF_SIZE, f) == NULL)
break;
#ifndef PROFILE_SUPPORTS_FOREIGN_NEWLINES
- retval = parse_line(bptr, state);
+ retval = parse_line(bptr, state, ret_modspec);
if (retval) {
free (bptr);
return retval;
/* parse_line modifies contents of p */
newp = p + strlen (p) + 1;
- retval = parse_line (p, state);
+ retval = parse_line (p, state, ret_modspec);
if (retval) {
free (bptr);
return retval;
return 0;
}
-errcode_t profile_parse_file(FILE *f, struct profile_node **root)
+errcode_t profile_parse_file(FILE *f, struct profile_node **root,
+ char **ret_modspec)
{
struct parse_state state;
errcode_t retval;
if (retval)
return retval;
- retval = parse_file(f, &state);
+ retval = parse_file(f, &state, ret_modspec);
if (retval) {
profile_free_node(state.root_section);
return retval;
}
profile_unlock_global();
- retval = profile_update_file(file);
+ retval = profile_update_file(file, NULL);
return retval;
}
*ret_value =0;
return 0;
}
- if ((retval = profile_update_file_locked(iter->file))) {
+ if ((retval = profile_update_file_locked(iter->file, NULL))) {
k5_mutex_unlock(&iter->file->data->lock);
if (retval == ENOENT || retval == EACCES) {
/* XXX memory leak? */
typedef struct _profile_t *profile_t;
+/* Used by profile_init_flags(). */
+#define PROFILE_INIT_ALLOW_MODULE 0x0001 /* Allow module declaration */
+
/*
* Used by the profile iterator in prof_get.c
*/
long KRB5_CALLCONV profile_init
(const_profile_filespec_t *files, profile_t *ret_profile);
+long KRB5_CALLCONV profile_init_flags
+ (const_profile_filespec_t *files, int flags, profile_t *ret_profile);
+
long KRB5_CALLCONV profile_init_path
(const_profile_filespec_list_t filelist, profile_t *ret_profile);
(*profile_flush_fn)(void *cbdata);
struct profile_vtable {
- int minor_ver; /* Set this to 1. */
+ int minor_ver; /* Set to structure minor version (currently 1)
+ * if calling profile_init_vtable. */
/* Methods needed for a basic read-only non-iterable profile (cleanup is
* optional). */
long KRB5_CALLCONV profile_init_vtable
(struct profile_vtable *vtable, void *cbdata, profile_t *ret_profile);
+/*
+ * Dynamically loadable profile modules should define a function named
+ * "profile_module_init" matching the following signature. The function should
+ * initialize the methods of the provided vtable structure, stopping at the
+ * field corresponding to vtable->minor_ver. Do not change the value of
+ * vtable->minor_ver. Unimplemented methods can be left uninitialized. The
+ * function should supply a callback data pointer in *cb_ret; this pointer can
+ * be cleaned up via the vtable cleanup method.
+ */
+typedef long
+(*profile_module_init_fn)(const char *residual, struct profile_vtable *vtable,
+ void **cb_ret);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* util/profile/test_load.c - Test harness for loadable profile modules */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-platform.h"
+#include "profile.h"
+#include "prof_int.h"
+
+int
+main()
+{
+ profile_t pr, pr2;
+ const char *files[] = { "./modtest.conf", NULL };
+ char **values;
+
+ assert(profile_init_flags(files, PROFILE_INIT_ALLOW_MODULE, &pr) == 0);
+ assert(profile_copy(pr, &pr2) == 0);
+ assert(profile_get_values(pr, NULL, &values) == 0);
+ assert(strcmp(values[0], "teststring") == 0);
+ assert(strcmp(values[1], "0") == 0);
+ profile_free_list(values);
+ assert(profile_get_values(pr2, NULL, &values) == 0);
+ assert(strcmp(values[0], "teststring") == 0);
+ assert(strcmp(values[1], "1") == 0);
+ profile_release(pr);
+ profile_abandon(pr2);
+ profile_free_list(values);
+ return 0;
+}
exit(1);
}
- retval = profile_parse_file(f, &root);
+ retval = profile_parse_file(f, &root, NULL);
if (retval) {
printf("profile_parse_file error %s\n",
error_message((errcode_t) retval));
--- /dev/null
+mydir=util$(S)profile$(S)testmod
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+DEFS=@DEFS@
+
+LOCALINCLUDES = -I.. -I$(srcdir)/..
+
+LIBBASE=proftest
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+
+STOBJLISTS=OBJS.ST
+STLIBOBJS=testmod_main.o
+
+SRCS=$(srcdir)/testmod_main.c
+
+check-unix:: proftest$(DYNOBJEXT)
+clean-unix:: clean-libs clean-libobjs
+
+@libnover_frag@
+@libobj_frag@
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+testmod_main.so testmod_main.po $(OUTPRE)testmod_main.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h testmod_main.c
--- /dev/null
+profile_module_init
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* util/profile/proftest/test.c - Test dynamic profile module */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * This file implements a very simple profile module which just returns the
+ * residual string and the number of copies in response to any query. The full
+ * range of vtable profile operations is tested elsewhere.
+ */
+
+#include "k5-platform.h"
+#include "profile.h"
+
+struct data {
+ char *residual;
+ int gen;
+};
+
+static long
+get_values(void *cbdata, const char *const *names, char ***ret_values)
+{
+ struct data *d = cbdata;
+
+ *ret_values = calloc(3, sizeof(*ret_values));
+ (*ret_values)[0] = strdup(d->residual);
+ asprintf(&(*ret_values)[1], "%d", d->gen);
+ (*ret_values)[2] = NULL;
+ return 0;
+}
+
+static void
+free_values(void *cbdata, char **values)
+{
+ char **v;
+
+ for (v = values; *v; v++)
+ free(*v);
+ free(values);
+}
+
+static void
+cleanup(void *cbdata)
+{
+ struct data *d = cbdata;
+
+ free(d->residual);
+ free(d);
+}
+
+static long
+copy(void *cbdata, void **ret_cbdata)
+{
+ struct data *old_data = cbdata, *new_data;
+
+ new_data = malloc(sizeof(*new_data));
+ new_data->residual = strdup(old_data->residual);
+ new_data->gen = old_data->gen + 1;
+ *ret_cbdata = new_data;
+ return 0;
+}
+
+long
+profile_module_init(const char *residual, struct profile_vtable *vtable,
+ void **cb_ret);
+
+long
+profile_module_init(const char *residual, struct profile_vtable *vtable,
+ void **cb_ret)
+{
+ struct data *d;
+
+ d = malloc(sizeof(*d));
+ d->residual = strdup(residual);
+ d->gen = 0;
+ *cb_ret = d;
+
+ vtable->get_values = get_values;
+ vtable->free_values = free_values;
+ vtable->cleanup = cleanup;
+ vtable->copy = copy;
+ return 0;
+}