Merge from plugin branch
authorKen Raeburn <raeburn@mit.edu>
Tue, 7 Mar 2006 20:45:24 +0000 (20:45 +0000)
committerKen Raeburn <raeburn@mit.edu>
Tue, 7 Mar 2006 20:45:24 +0000 (20:45 +0000)
Add plugin support:
- plugin routines in support library (may break windows build!)
- plugin support in KDC location code
- sample Python-based plugin for KDC location, not built without
  tweaking sources
- changed service location interface to use an enum instead of passing
  profile string and DNS strings and port numbers
- changed pathnames for plugin locations, including kdb back end
- remove locate_service from accessor API

Also, do build shared libraries for Darwin just like any other UNIX box.

Not present yet:
- use new plugin interface for kdb back end
- Windows support
- Mac bundle support (but dlopen support works)
- search path for libkrb5 plugins (only one hard-coded directory for now)
- sorting of plugin collections for predictable ordering

See the various ChangeLogs for specifics.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17706 dc483132-0cff-0310-8789-dd5450dbe970

44 files changed:
src/ChangeLog
src/Makefile.in
src/aclocal.m4
src/config/ChangeLog
src/config/lib.in
src/config/libnover.in
src/config/pre.in
src/config/shlib.conf
src/configure.in
src/include/ChangeLog
src/include/k5-int.h
src/include/k5-plugin.h [new file with mode: 0644]
src/include/krb5/ChangeLog
src/include/krb5/Makefile.in
src/include/krb5/stock/ChangeLog
src/include/krb5/stock/osconf.h
src/kadmin/testing/scripts/ChangeLog
src/kadmin/testing/scripts/init_db
src/lib/krb5/error_tables/ChangeLog
src/lib/krb5/error_tables/krb5_err.et
src/lib/krb5/os/ChangeLog
src/lib/krb5/os/Makefile.in
src/lib/krb5/os/accessor.c
src/lib/krb5/os/changepw.c
src/lib/krb5/os/init_os_ctx.c
src/lib/krb5/os/locate_kdc.c
src/lib/krb5/os/send524.c
src/lib/krb5/os/sendto_kdc.c
src/lib/krb5/os/t_locate_kdc.c
src/lib/krb5/os/t_std_conf.c
src/plugins/kdb/db2/ChangeLog
src/plugins/kdb/db2/Makefile.in
src/plugins/locate/python/ChangeLog [new file with mode: 0644]
src/plugins/locate/python/Makefile.in [new file with mode: 0644]
src/plugins/locate/python/configure.in [new file with mode: 0644]
src/plugins/locate/python/locate-service.py [new file with mode: 0644]
src/plugins/locate/python/py-locate.c [new file with mode: 0644]
src/plugins/locate/python/python.exports [new file with mode: 0644]
src/util/profile/ChangeLog
src/util/profile/Makefile.in
src/util/support/ChangeLog
src/util/support/Makefile.in
src/util/support/libkrb5support.exports
src/util/support/plugins.c [new file with mode: 0644]

index dbc3ec788650315678736b1efcc42e6c1cda5389..8d40b20a91bf3dffce3b900e683f95612ea2acbf 100644 (file)
@@ -1,3 +1,15 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * configure.in: Don't check for dlopen here.  Call
+       AC_HEADER_DIRENT.  Remove one of the checks for unistd.h.
+
+       * Makefile.in (update-autoconf-h): Build everything in include/krb5.
+       (INSTALLMKDIRS): Add KRB5_LIBKRB5_MODULE_DIR.
+
+       * aclocal.m4 (KRB5_AC_FIND_DLOPEN): Define USE_DLOPEN if found.
+
+       * plugins/locate/python: New directory.
+
 2006-03-02  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in (clean-unix): Delete util/fakedest.
index ff6c277681e07ba752391545d7d649cdc5f2a9af..7b0f53cc4d5b8b5806cb0e15c3a99131eb6abaf4 100644 (file)
@@ -3,6 +3,7 @@ datadir=@datadir@
 thisconfigdir=.
 myfulldir=.
 mydir=.
+# Don't build sample by default: plugins/locate/python 
 SUBDIRS=util include lib @krb524@ kdc kadmin slave clients \
        plugins/kdb/db2 \
        appl tests \
@@ -23,7 +24,7 @@ all-unix:: krb5-config
 # that autoconf.h is up to date before going into any of the subdirectories.
 all-prerecurse: update-autoconf-h
 update-autoconf-h:
-       (cd include && $(MAKE) krb5/autoconf.h)
+       (cd include/krb5 && $(MAKE) all)
 
 ##DOS##!if 0
 # This makefile doesn't use lib.in, but we still need shlib.conf here.
@@ -67,6 +68,7 @@ INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \
                $(ADMIN_MANDIR) $(SERVER_MANDIR) $(CLIENT_MANDIR) \
                $(FILE_MANDIR) $(KRB5_LIBDIR) $(KRB5_INCDIR) \
                $(KRB5_DB_MODULE_DIR) \
+               $(KRB5_LIBKRB5_MODULE_DIR) \
                $(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR)
 
 install-strip:
@@ -98,6 +100,8 @@ fake-install:
        (w=`pwd`; cd lib && $(MAKE) install DESTDIR="$$w/util/fakedest")
        (w=`pwd`; cd plugins/kdb/db2 && $(MAKE) install DESTDIR="$$w/util/fakedest")
 
+#      (w=`pwd`; cd plugins/locate/python && $(MAKE) install DESTDIR="$$w/util/fakedest")
+
 TAGS: $(SRCS)
        etags $(SRCS)
 
index 46a70e69adfa8794a42bba03f0160c0bbce4afc6..05452d19a0732f12117868cded9f4f5728fcfe76 100644 (file)
@@ -159,8 +159,9 @@ fi
 
 dnl find dlopen
 AC_DEFUN([KRB5_AC_FIND_DLOPEN],[
-AC_CHECK_LIB(dl, dlopen, DL_LIB=-ldl)
-AC_CHECK_LIB(ld, main, DL_LIB=-lld)
+AC_CHECK_LIB(dl, dlopen,[DL_LIB=-ldl
+AC_DEFINE(USE_DLOPEN,1,[Define if dlopen should be used])])
+dnl AC_CHECK_LIB(ld, main, DL_LIB=-lld)
 AC_SUBST(DL_LIB)
 ])
 
index f61eef637f9396fffc6bf2dbe16a00f6ec526c3e..ca5704b2a24fa66dff9b01b421b3a60af381c8c7 100644 (file)
@@ -1,3 +1,18 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * shlib.conf (*-*-darwin*): Update MAKE_DYNOBJ_COMMAND, LDCOMBINE,
+       and LDCOMBINE_TAIL to create dynamically loadable bundles.  Don't
+       set DYNOBJ_EXPDEPS or DYNOBJ_EXPFLAGS.  Don't force static-only
+       builds.
+
+       * libnover.in (install-shared): Use MODULE_INSTALL_DIR instead of
+       KRB5_DB_MODULE_DIR.
+
+       * pre.in (MODULE_DIR, KRB5_LIBKRB5_MODULE_DIR): New variables.
+       (KRB5_DB_MODULE_DIR): Define in terms of MODULE_DIR.
+
+       * lib.in (darwin.exports): New target.
+
 2006-02-24  Jeffrey Altman <jaltman@mit.edu>
 
        * win-pre.in, win-post.in: support for 64-bit Windows builds
index 80f7b41825ded15c8117cbf3decb63e3550aab2f..40c245b083d4686efa2f54d949292c43ef05a51d 100644 (file)
@@ -59,6 +59,10 @@ binutils.versions: $(SHLIB_EXPORT_FILE) Makefile
        echo >> binutils.versions "};"
        echo >> binutils.versions "HIDDEN { local: __*; _rest*; _save*; *; };"
 
+darwin.exports: $(SHLIB_EXPORT_FILE) Makefile
+       sed > darwin-exports.tmp < $(SHLIB_EXPORT_FILE) "s/^/_/"
+       $(MV) darwin-exports.tmp darwin.exports
+
 osf1.exports: $(SHLIB_EXPORT_FILE) Makefile
        $(RM) osf1.tmp osf1.exports
        sed "s/^/-exported_symbol /" < $(SHLIB_EXPORT_FILE) > osf1.tmp
index 3896e8462c2c12cbf3ac92bcba1fef0f54bd2d03..09c42dcc86a13f6b074c16d5153bcf44e500c158 100644 (file)
@@ -92,8 +92,8 @@ clean-libs:
 
 install-libs: $(LIBINSTLIST)
 install-shared:
-       $(RM) $(DESTDIR)$(KRB5_DB_MODULE_DIR)/$(LIBBASE)$(DYNOBJEXT)
-       $(INSTALL_SHLIB) $(LIBBASE)$(DYNOBJEXT) $(DESTDIR)$(KRB5_DB_MODULE_DIR)
+       $(RM) $(DESTDIR)$(MODULE_INSTALL_DIR)/$(LIBBASE)$(DYNOBJEXT)
+       $(INSTALL_SHLIB) $(LIBBASE)$(DYNOBJEXT) $(DESTDIR)$(MODULE_INSTALL_DIR)
 
 Makefile: $(SRCTOP)/config/libnover.in
 $(thisconfigdir)/config.status: $(SRCTOP)/config/shlib.conf
index 2dcba6c2c066e52818385af331f38b17ba514b9b..808b03f5943c120f50d1a8572afac42f7ebb14d2 100644 (file)
@@ -205,7 +205,9 @@ FILE_MANDIR = $(KRB5MANROOT)/man5
 KRB5_LIBDIR = @libdir@
 KRB5_SHLIBDIR = @libdir@$(SHLIB_TAIL_COMP)
 KRB5_INCDIR = @includedir@
-KRB5_DB_MODULE_DIR = @libdir@/db-modules
+MODULE_DIR = @libdir@/krb5/plugins
+KRB5_DB_MODULE_DIR = $(MODULE_DIR)/kdb
+KRB5_LIBKRB5_MODULE_DIR = $(MODULE_DIR)/libkrb5
 KRB5_INCSUBDIRS = \
        $(KRB5_INCDIR)/gssapi \
        $(KRB5_INCDIR)/kerberosIV \
@@ -530,6 +532,7 @@ LDCOMBINE=@LDCOMBINE@
 # "-h $@", "-h lib$(LIBNAME).$(LIBMAJOR)", etc.
 SONAME=@SONAME@
 
+
 #
 # rules to make various types of object files
 #
index a7ec085c327bcd94c5649beb0f1af058ab0b5df3..744d7ea053db3d8c817bb3be988c18f3b4a729df 100644 (file)
@@ -281,19 +281,16 @@ mips-*-netbsd*)
        SHLIBEXT=.dylib
        DYNOBJEXT=.so
        SHLIB_EXPORT_FILE_DEP=darwin.exports
-       DYNOBJ_EXPDEPS='$(DYNOBJ_EXPDEPS_WITH_LOADER)'
-       DYNOBJ_EXPFLAGS='$(SHLIB_DIRS) $(DYNOBJ_EXPLIBS_WITH_LOADER)'
-       MAKE_DYNOBJ_COMMAND='$(CC) -bundle $(CFLAGS) -bundle_loader $(DYNOBJ_LOADER_PROG) $(LDFLAGS) -o $@ $$objlist $(DYNOBJ_EXPFLAGS) -exported_symbols_list darwin.exports'
-       LDCOMBINE='$(CC) -undefined warning -dynamiclib -compatibility_version $(LIBMAJOR) -current_version $(LIBMAJOR).$(LIBMINOR) -install_name "$(KRB5_LIBDIR)/$(LIBPREFIX)$(LIBBASE)$(SHLIBVEXT)" $(CFLAGS) $(LDFLAGS)'
+       MAKE_DYNOBJ_COMMAND='$(CC) -bundle $(CFLAGS) $(LDFLAGS) -o $@ $$objlist $(DYNOBJ_EXPFLAGS) -exported_symbols_list darwin.exports'
+       LDCOMBINE='$(CC) -undefined error -dynamiclib -compatibility_version $(LIBMAJOR) -current_version $(LIBMAJOR).$(LIBMINOR) -install_name "$(KRB5_LIBDIR)/$(LIBPREFIX)$(LIBBASE)$(SHLIBVEXT)" $(CFLAGS) $(LDFLAGS)'
+       # The -dylib_file option tells the linker where to find indirect dependent
+       # libraries, without adding them to the dependency list.  We need this because
+       # the direct dependent libraries contain the pathname where the indirect
+       # dependent libraries will be installed (but haven't been yet).
+       LDCOMBINE_TAIL='-dylib_file "$(KRB5_LIBDIR)/libkrb5support.1.0.dylib":$(TOPLIBD)/libkrb5support.1.0.dylib'
        CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -dynamic $(CFLAGS) $(LDFLAGS)'
        CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
        RUN_ENV='DYLD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export DYLD_LIBRARY_PATH;'
-       # We need some changes for *all* library builds on Darwin, too.
-       # (Well, the KfM builds which generate .dylib files, at least.
-       # They might not be needed for "dumb" UNIX builds with static
-       # libraries, that just happen to be done on Darwin.)
-       enable_static=yes
-       enable_shared=no
        ;;
 
 *-*-solaris*)
index 74985522dda256820e6cb8e7627971cf3d93e211..63021d9f34bf759a21be8d61e698fce564670cba 100644 (file)
@@ -130,7 +130,8 @@ AC_PROG_INSTALL
 AC_PROG_AWK
 AC_PROG_LEX
 AC_C_CONST
-AC_CHECK_FUNCS(strdup setvbuf inet_ntoa inet_aton seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv gethostbyname2 getifaddrs gmtime_r localtime_r pthread_mutex_lock sched_yield dlopen bswap16 bswap64 mkstemp)
+AC_HEADER_DIRENT
+AC_CHECK_FUNCS(strdup setvbuf inet_ntoa inet_aton seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv gethostbyname2 getifaddrs gmtime_r localtime_r pthread_mutex_lock sched_yield bswap16 bswap64 mkstemp)
 AC_HEADER_STDARG
 AC_CHECK_HEADERS(unistd.h paths.h regex.h regexp.h regexpr.h fcntl.h memory.h ifaddrs.h sys/filio.h sched.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h)
 dnl bswap_16 is a macro in byteswap.h under GNU libc
@@ -320,7 +321,7 @@ AC_CHECK_HEADER(termios.h,dnl
   AC_DEFINE(POSIX_TERMIOS,1,[Define if termios.h exists and tcsetattr exists]))])
 dnl
 KRB5_SIGTYPE
-AC_CHECK_HEADERS(stdlib.h string.h stddef.h unistd.h sys/types.h sys/file.h sys/param.h sys/stat.h sys/time.h netinet/in.h sys/uio.h sys/filio.h sys/select.h time.h paths.h)
+AC_CHECK_HEADERS(stdlib.h string.h stddef.h sys/types.h sys/file.h sys/param.h sys/stat.h sys/time.h netinet/in.h sys/uio.h sys/filio.h sys/select.h time.h paths.h)
 AC_HEADER_STDARG
 KRB5_AC_INET6
 dnl
index 422de1cb5ba1735c24a067e939564b2715b5f067..9dad2a2564c9983be04fb06c7ac9297d631b15fb 100644 (file)
@@ -1,3 +1,24 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * k5-plugin.h: New file.
+       * k5-int.h: Include k5-plugin.h.
+       (struct plugin_file_handle): Declare.
+       (struct plugin_dir_handle): Define.
+       (PLUGIN_DIR_INIT, PLUGIN_DIR_OPEN): New macros.
+       (krb5int_open_plugin, krb5int_close_plugin,
+       krb5int_get_plugin_data, krb5int_get_plugin_func,
+       krb5int_open_plugin_dir, krb5int_close_plugin_dir,
+       krb5int_get_plugin_dir_data, krb5int_get_plugin_dir_func,
+       krb5int_free_plugin_dir_data, krb5int_free_plugin_dir_func):
+       Declare.
+       (struct _krb5_context): Add fields for holding some plugin data.
+       (KRB5INT_ACCESS_STRUCT_VERSION): Bump.
+       (struct _krb5int_access): Remove locate_server field.
+       (struct addrlist): Use an undefined struct tag if fake-addrinfo.h
+       hasn't been included yet.  Add free-function and callback pointer
+       fields.
+       (krb5int_locate_server): Update prototype.
+
 2006-02-24  Jeffrey Altman <jaltman@mit.edu>
 
        * win-mac.h: support for 64-bit Windows builds
index 3f8c60da7c29cb425d8abb65da84d9d48e439f69..bf068828e8e3d86a22c177ac032c675cc68a1862 100644 (file)
@@ -517,7 +517,15 @@ krb5_error_code krb5_os_hostaddr
 /* N.B.: You need to include fake-addrinfo.h *before* k5-int.h if you're
    going to use this structure.  */
 struct addrlist {
-    struct addrinfo **addrs;
+    struct {
+#ifdef FAI_DEFINED
+       struct addrinfo *ai;
+#else
+       struct undefined_addrinfo *ai;
+#endif
+       void (*freefn)(void *);
+       void *data;
+    } *addrs;
     int naddrs;
     int space;
 };
@@ -527,24 +535,11 @@ extern int krb5int_grow_addrlist (struct addrlist *, int);
 extern int krb5int_add_host_to_list (struct addrlist *, const char *,
                                     int, int, int, int);
 
+#include "k5-plugin.h"
 krb5_error_code
-krb5int_locate_server (krb5_context,
-                      const krb5_data *realm,
-                      struct addrlist *,
-                      /* Only meaningful for kdc, really...  */
-                      int want_masters,
-                      /* look up [realms]->$realm->$name in krb5.conf */
-                      const char *profilename,
-                      /* SRV record lookup */
-                      const char *dnsname,
-                      int is_stream_service,
-                      /* Port numbers, in network order!  For profile
-                         version only, DNS code gets port numbers
-                         itself.  Use 0 for dflport2 if there's no
-                         secondary port (most common, except kdc
-                         case).  */
-                      int dflport1, int dflport2,
-                      int family);
+krb5int_locate_server (krb5_context, const krb5_data *realm,
+                      struct addrlist *, enum locate_service_type svc,
+                      int sockettype, int family);
 
 #endif /* KRB5_LIBOS_PROTO__ */
 
@@ -1015,6 +1010,38 @@ void KRB5_CALLCONV krb5_free_pa_enc_ts
 /* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
 #include "com_err.h"
 
+struct plugin_file_handle;     /* opaque */
+
+struct plugin_dir_handle {
+    /* This points to a list of plugin_file_handle structs, terminated
+       by one passing NULL_HANDLE.  */
+    struct plugin_file_handle *files;
+};
+#define PLUGIN_DIR_INIT(P) ((P)->files = NULL)
+#define PLUGIN_DIR_OPEN(P) ((P)->files != NULL)
+
+krb5_error_code KRB5_CALLCONV
+krb5int_open_plugin (const char *, struct plugin_file_handle **);
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_data (struct plugin_file_handle *, const char *, void **);
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_func (struct plugin_file_handle *, const char *,
+                        void (**)());
+
+void KRB5_CALLCONV
+krb5int_close_plugin (struct plugin_file_handle *);
+
+krb5_error_code KRB5_CALLCONV krb5int_open_plugin_dir (const char *, struct plugin_dir_handle *);
+void KRB5_CALLCONV krb5int_close_plugin_dir (struct plugin_dir_handle *);
+void KRB5_CALLCONV krb5int_free_plugin_dir_data (void **);
+krb5_error_code KRB5_CALLCONV krb5int_get_plugin_dir_data (struct plugin_dir_handle *,
+                                                          const char *, void ***);
+void KRB5_CALLCONV krb5int_free_plugin_dir_func (void (**)(void));
+krb5_error_code KRB5_CALLCONV krb5int_get_plugin_dir_func (struct plugin_dir_handle *,
+                                                          const char *, void (***)(void));
+
 struct _krb5_context {
        krb5_magic      magic;
        krb5_enctype    *in_tkt_ktypes;
@@ -1066,6 +1093,11 @@ struct _krb5_context {
 #ifdef KRB5_DNS_LOOKUP
         krb5_boolean    profile_in_memory;
 #endif /* KRB5_DNS_LOOKUP */
+
+    /* locate_kdc module stuff */
+    struct plugin_dir_handle libkrb5_plugins;
+    struct krb5plugin_service_locate_ftable *vtbl;
+    void (**locate_fptrs)(void);
 };
 
 /* could be used in a table to find an etype and initialize a block */
@@ -1661,7 +1693,7 @@ void krb5int_free_srv_dns_data(struct srv_dns_entry *);
 /* To keep happy libraries which are (for now) accessing internal stuff */
 
 /* Make sure to increment by one when changing the struct */
-#define KRB5INT_ACCESS_STRUCT_VERSION 9
+#define KRB5INT_ACCESS_STRUCT_VERSION 10
 
 #ifndef ANAME_SZ
 struct ktext;                  /* from krb.h, for krb524 support */
@@ -1675,10 +1707,6 @@ typedef struct _krb5int_access {
                                   unsigned int icount, const krb5_data *input,
                                   krb5_data *output);
     /* service location and communication */
-    krb5_error_code (*locate_server) (krb5_context, const krb5_data *,
-                                     struct addrlist *, int,
-                                     const char *, const char *,
-                                     int, int, int, int);
     krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg,
                                   const struct addrlist *, krb5_data *reply,
                                   struct sockaddr *, socklen_t *, int *);
diff --git a/src/include/k5-plugin.h b/src/include/k5-plugin.h
new file mode 100644 (file)
index 0000000..a49c79a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef K5_PLUGIN_H_INCLUDED
+#define K5_PLUGIN_H_INCLUDED
+#include "krb5.h"
+
+enum locate_service_type {
+    locate_service_kdc = 1,
+    locate_service_master_kdc,
+    locate_service_kadmin,
+    locate_service_krb524,
+    locate_service_kpasswd
+};
+
+struct krb5plugin_service_locate_ftable {
+    int vmajor, vminor;
+    /* Per-context setup and teardown.  Returned void* blob is
+       private to the plugin.  */
+    krb5_error_code (*init)(krb5_context, void **);
+    void (*fini)(void *);
+    /* Callback function returns non-zero if the plugin function
+       should quit and return; this may be because of an error, or may
+       indicate we've already contacted the service, whatever.  The
+       lookup function should only return an error if it detects a
+       problem, not if the callback function tells it to quit.  */
+    krb5_error_code (*lookup)(void *,
+                             enum locate_service_type svc, const char *realm,
+                             int socktype, int family,
+                             int (*cbfunc)(void *,int,struct sockaddr *),
+                             void *cbdata);
+};
+#endif
index dcce9d0a71ee491e56f1cecceb4625b603f7e505..bbc1d8b976c1acb6f10d354027156ec424d303e5 100644 (file)
@@ -1,3 +1,8 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * Makefile.in (PROCESS_REPLACE): Use MODULE_DIR instead of
+       KRB5_DB_MODULE_DIR.
+
 2005-11-17  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in (osconf.h): Always remove osconf.new.
index 429b355156486d28394ad76339975b4dcf2a0e4a..7ef43d413fb009753b938275859ed6820700cf1e 100644 (file)
@@ -47,7 +47,7 @@ PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \
                  -e "s+@BINDIR+$(BINDIR)+" \
                  -e "s+@LIBDIR+$(LIBDIR)+" \
                  -e "s+@SBINDIR+$(SBINDIR)+" \
-                 -e "s+@MODULEDIR+$(KRB5_DB_MODULE_DIR)+" \
+                 -e "s+@MODULEDIR+$(MODULE_DIR)+" \
        -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \
        -e 's+@SYSCONFDIR+$(SYSCONFDIR)+' 
 
index cfa6cb4de3dc22a673c22bad8dc02d50b7330ebb..c341acea63073e9423ee2c878433ba0d8669e330 100644 (file)
@@ -1,3 +1,9 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * osconf.h (DEFAULT_KDB_LIB_PATH): Add "/kdb" on end of
+       MODULEDIR.
+       (MODULE_PATH): New macro.
+
 2005-06-29  Ken Raeburn  <raeburn@mit.edu>
 
        * osconf.h (DEFAULT_KDB_LIB_PATH): Use @MODULEDIR.  Don't use a
index 367109b11706d3933f726f9c21161697d9f0ca43..03b2ce651d60a1502c2b2d834c3e1dc0a0602b3f 100644 (file)
@@ -63,7 +63,9 @@
 /* Location of KDC profile */
 #define        DEFAULT_KDC_PROFILE     "@LOCALSTATEDIR/krb5kdc/kdc.conf"
 #define        KDC_PROFILE_ENV         "KRB5_KDC_PROFILE"
-#define DEFAULT_KDB_LIB_PATH   { "@MODULEDIR", NULL }
+
+#define DEFAULT_KDB_LIB_PATH   { "@MODULEDIR/kdb", NULL }
+#define MODULE_PATH            "@MODULEDIR"
 
 #define        DEFAULT_KDC_ENCTYPE     ENCTYPE_DES3_CBC_SHA1
 #define KDCRCACHE              "dfl:krb5kdc_rcache"
index 59a925093a933078df43aeb616336c0e4584433a..a041b85326d15414cf20c841754a4210470f507a 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * init_db: Change MODDIR setting to match new installation path.
+
 2005-08-16  Ken Raeburn  <raeburn@mit.edu>
 
        * env-setup.shin: Export $libdir.
index 5ebacc0919ee999e202485549881fb2ebf5c4c65..93b6fa16e0ca030ea8dd49fa2315a802b31693b4 100755 (executable)
@@ -27,7 +27,7 @@ IROOT=$TOP/..
 ADMIN=$TOP/dbutil
 BIN=$IROOT/bin
 ETC=$IROOT/etc
-MODDIR=$TOP/../util/fakedest$libdir/db-modules
+MODDIR=$TOP/../util/fakedest$libdir/krb5/plugins/kdb
 SBIN=$TOP/keytab:$TOP/server
 DUMMY=${REALM=SECURE-TEST.OV.COM}; export REALM
 
index bb59895bfce3743ec19546a4868df0c782875815..e84f292d3518693b50cc65b6a03db700a6dfaf0b 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * krb5_err.et (KRB5_PLUGIN_NO_HANDLE): New error code.
+
 2006-01-27  Sam Hartman  <hartmans@mit.edu>
 
        * kdb5_err.et: New error codes  for plugin errors
index 1f2bfca53c7a35b2c54dfb0cfcd828576d638a16..865c838a62a6d82a5dff7945cba7d39f3697bbcd 100644 (file)
@@ -342,4 +342,6 @@ error_code KRB5_CC_READONLY,    "Ccache function not supported: read-only ccache
 error_code KRB5_CC_NOSUPP,      "Ccache function not supported: not implemented"
 
 error_code KRB5_DELTAT_BADFORMAT,      "Invalid format of Kerberos lifetime or clock skew string"
+
+error_code KRB5_PLUGIN_NO_HANDLE,      "Supplied data not handled by this plugin"
 end
index d9bda00a64a3aca0db63185c07e76e210c247869..889a8f314bc45cb427ec826e9f62793313d7da3d 100644 (file)
@@ -1,3 +1,52 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * Makefile.in (DEFINES): New variable.
+       (t_locate_kdc.o): Depend on dnssrv.c and dnsglue.c too.
+
+       * init_os_ctx.c (krb5_os_init_context): Initialize new fields.
+       (krb5_os_free_context): Close opened plugin files.
+
+       * locate_kdc.c: Include k5-plugin.h.
+       (get_port): Deleted.
+       (grow_addrlist): Update for new fields in structure.
+       (krb5int_free_addrlist): Call the free function in the structure,
+       if the function pointer is non-null.
+       (add_addrinfo_to_list): Update for new fields.  Shorten up debug
+       output.
+       (call_freeaddrinfo): New function.
+       (krb5int_add_host_to_list): Update for new fields.
+       (prof_locate_server, dns_locate_server): New functions, broken out
+       from krb5int_locate_server; use the new enum type for service
+       choice.
+       (objdir): New variable.
+       (struct module_callback_data): New struct.
+       (module_callback, module_locate_server): New functions.
+       (krb5int_locate_server): Use the above method-specific locator
+       functions.  Change argument list to take enum and not multiple
+       strings and numbers.
+       (krb5_locate_kdc): Updated for new interface.
+
+       * send524.c (krb5int_524_sendto_kdc): Update for new locate_server
+       interface.
+       * changepw.c (krb5_locate_kpasswd): Likewise.
+       (krb5_change_set_password): Update for new fields.
+
+       * accessor.c (krb5int_accessor): Don't fill in locate_server
+       field.
+
+       * t_locate_kdc.c: Include dnsglue.c and dnssrv.c.
+       (print_addrs): Update for new fields.
+       * t_std_conf.c (test_locate_kdc): Update for new fields.
+
+       * sendto_kdc.c (krb5int_debug_fprint): No longer static.  Print
+       more info.
+       (krb5int_print_addrlist): New function.
+       (merge_addrlists): Update for new fields.
+       (in_addrlist): New function.
+       (krb5_sendto_kdc): Use it.  Update for new fields.
+       (krb5int_sendto): Update for new fields.  Print more info when
+       debugging.
+
 2006-02-24  Jeffrey Altman <jaltman@mit.edu>
 
        * gmt_mktime.c, read_pwd.c: changes to support 64-bit builds
index 49690e41fb23ef1a33d55410144aa50c0a81b2a7..b58d40c1f9c374bac13a5480019aa3c5cc6daac1 100644 (file)
@@ -6,6 +6,8 @@ KRB5_RUN_ENV = @KRB5_RUN_ENV@
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
+DEFINES=-DLIBDIR=\"$(KRB5_LIBDIR)\"
+
 ##DOS##BUILDTOP = ..\..\..
 ##DOS##PREFIXDIR=os
 ##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
@@ -163,7 +165,7 @@ shared:
 TEST_PROGS= t_std_conf t_an_to_ln t_locate_kdc
 
 T_STD_CONF_OBJS= t_std_conf.o def_realm.o get_krbhst.o realm_dom.o \
-               hst_realm.o init_os_ctx.o locate_kdc.o dnsglue.o 
+               hst_realm.o init_os_ctx.o locate_kdc.o dnsglue.o
 
 T_AN_TO_LN_OBJS = t_an_to_ln.o an_to_ln.o 
 
@@ -187,9 +189,8 @@ t_localaddr: localaddr.c
 t_locate_kdc: t_locate_kdc.o
        $(CC_LINK) $(ALL_CFLAGS) -o t_locate_kdc t_locate_kdc.o \
                $(KRB5_BASE_LIBS)
-t_locate_kdc.o: t_locate_kdc.c locate_kdc.c
+t_locate_kdc.o: t_locate_kdc.c locate_kdc.c dnssrv.c dnsglue.c
 $(OUTPRE)t_locate_kdc.exe: $(OUTPRE)t_locate_kdc.obj \
-               $(OUTPRE)dnssrv.obj $(OUTPRE)dnsglue.obj \
                $(KLIB) $(PLIB) $(CLIB) $(SLIB)
        link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib $(DNSLIBS)
 
@@ -415,7 +416,7 @@ locate_kdc.so locate_kdc.po $(OUTPRE)locate_kdc.$(OBJEXT): \
   $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
   $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
   $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
-  $(SRCTOP)/include/krb5/kdb.h os-proto.h
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h $(SRCTOP)/include/k5-plugin.h
 lock_file.so lock_file.po $(OUTPRE)lock_file.$(OBJEXT): \
   lock_file.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
   $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
@@ -540,12 +541,12 @@ t_gifconf.so t_gifconf.po $(OUTPRE)t_gifconf.$(OBJEXT): \
   t_gifconf.c
 t_locate_kdc.so t_locate_kdc.po $(OUTPRE)t_locate_kdc.$(OBJEXT): \
   t_locate_kdc.c $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
-  $(COM_ERR_DEPS) locate_kdc.c $(SRCTOP)/include/fake-addrinfo.h \
-  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
-  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/k5-int.h \
-  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5.h \
-  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/krb5/kdb.h \
-  os-proto.h
+  $(COM_ERR_DEPS) dnsglue.c dnsglue.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h dnssrv.c locate_kdc.c \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/k5-plugin.h
 t_realm_iter.so t_realm_iter.po $(OUTPRE)t_realm_iter.$(OBJEXT): \
   t_realm_iter.c $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS)
 t_std_conf.so t_std_conf.po $(OUTPRE)t_std_conf.$(OBJEXT): \
index f16a6e3e60d598e33d7bdacf045687f741e2a0e0..0a2f8e8db4601d442a5bacb7d83e531b9372a6d5 100644 (file)
@@ -38,7 +38,6 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version)
     internals_temp.krb5_hmac = krb5_hmac;
     internals_temp.md5_hash_provider = &krb5int_hash_md5;
     internals_temp.arcfour_enc_provider = &krb5int_enc_arcfour;
-    internals_temp.locate_server = &krb5int_locate_server;
     internals_temp.sendto_udp = &krb5int_sendto;
     internals_temp.add_host_to_list = krb5int_add_host_to_list;
 #ifdef KRB5_DNS_LOOKUP
index 1d4e1d3adae65a1452ec1b09daa3cc83a05a90e0..5f900b6216ae87fc11d23ee65853aa923d1125ec 100644 (file)
@@ -50,19 +50,17 @@ krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
 {
     krb5_error_code code;
 
-    code = krb5int_locate_server (context, realm, addrlist, 0,
-                                 "kpasswd_server", "_kpasswd", 0,
-                                 htons(DEFAULT_KPASSWD_PORT), 0, 0);
+    code = krb5int_locate_server (context, realm, addrlist,
+                                 locate_service_kpasswd, 0, 0);
     if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
-       code = krb5int_locate_server (context, realm, addrlist, 0,
-                                     "admin_server", "_kerberos-adm", 1,
-                                     DEFAULT_KPASSWD_PORT, 0, 0);
+       code = krb5int_locate_server (context, realm, addrlist,
+                                     locate_service_kadmin, 1, 0);
        if (!code) {
            /* Success with admin_server but now we need to change the
               port number to use DEFAULT_KPASSWD_PORT.  */
            int i;
            for ( i=0;i<addrlist->naddrs;i++ ) {
-               struct addrinfo *a = addrlist->addrs[i];
+               struct addrinfo *a = addrlist->addrs[i].ai;
                if (a->ai_family == AF_INET)
                    sa2sin (a->ai_addr)->sin_port = htons(DEFAULT_KPASSWD_PORT);
            }
@@ -157,11 +155,11 @@ krb5_change_set_password(
        struct timeval timeout;
 
        /* XXX Now the locate_ functions can return IPv6 addresses.  */
-       if (al.addrs[i]->ai_family != AF_INET)
+       if (al.addrs[i].ai->ai_family != AF_INET)
            continue;
 
        tried_one = 1;
-       if (connect(s2, al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen) == SOCKET_ERROR) {
+       if (connect(s2, al.addrs[i].ai->ai_addr, al.addrs[i].ai->ai_addrlen) == SOCKET_ERROR) {
            if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
                continue; /* try the next addr */
 
@@ -243,7 +241,8 @@ krb5_change_set_password(
 
        if ((cc = sendto(s1, chpw_req.data, 
                         (GETSOCKNAME_ARG3_TYPE) chpw_req.length, 0,
-                        al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen)) != chpw_req.length)
+                        al.addrs[i].ai->ai_addr, al.addrs[i].ai->ai_addrlen))
+           != chpw_req.length)
        {
            if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
                             (SOCKET_ERRNO == EHOSTUNREACH)))
index f4f9b690a085e8f717f757629e96f2dd27f80239..e91a05ff1cf3aacbe98b0cc18331ef5e351fc552 100644 (file)
@@ -355,6 +355,9 @@ krb5_os_init_context(krb5_context ctx)
        os_ctx->os_flags = 0;
        os_ctx->default_ccname = 0;
 
+       ctx->vtbl = 0;
+       PLUGIN_DIR_INIT(&ctx->libkrb5_plugins);
+
        retval = os_init_paths(ctx);
        /*
         * If there's an error in the profile, return an error.  Just
@@ -478,6 +481,8 @@ krb5_os_free_context(krb5_context ctx)
            ctx->profile = 0;
        }
 
+       krb5int_close_plugin_dir (&ctx->libkrb5_plugins);
+
 #ifdef _WIN32
         WSACleanup();
 #endif /* _WIN32 */
index 50c889dd8ffbbc4135c31b2dfd1a930723e08ce0..e751ca24d075cb8271e4c94c588287f87233a6c6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lib/krb5/os/locate_kdc.c
  *
- * Copyright 1990,2000,2001,2002,2003,2004 Massachusetts Institute of Technology.
+ * Copyright 1990,2000,2001,2002,2003,2004,2006 Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -100,52 +100,23 @@ _krb5_use_dns_realm(krb5_context context)
 
 #endif /* KRB5_DNS_LOOKUP */
 
-static int get_port (const char *service, int stream, int defalt)
-{
-#if 0 /* Only used for "kerberos" and "kerberos-sec", and we want the
-        right port numbers even on the OSes that botch the entries in
-        /etc/services.  So don't bother with the lookup, except maybe
-        to produce a warning.  */
-    struct addrinfo hints = { 0 };
-    struct addrinfo *ai;
-    int err;
-
-    hints.ai_family = PF_INET;
-    hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM;
-    err = getaddrinfo (NULL, service, &hints, &ai);
-    if (err == 0 && ai != 0) {
-       if (ai->ai_addr->sa_family == AF_INET) {
-           int port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
-           freeaddrinfo (ai);
-           return port;
-       }
-       freeaddrinfo (ai);
-    }
-#endif
-    /* Any error - don't complain, just use default.  */
-    return htons (defalt);
-}
-
 int
 krb5int_grow_addrlist (struct addrlist *lp, int nmore)
 {
     int i;
     int newspace = lp->space + nmore;
-    size_t newsize = newspace * sizeof (struct addrlist);
-    struct addrinfo **newaddrs;
-
-    /* NULL check a concession to SunOS4 compatibility for now; not
-       required for pure ANSI support.  */
-    if (lp->addrs)
-       newaddrs = realloc (lp->addrs, newsize);
-    else
-       newaddrs = malloc (newsize);
+    size_t newsize = newspace * sizeof (*lp->addrs);
+    void *newaddrs;
 
+    newaddrs = realloc (lp->addrs, newsize);
     if (newaddrs == NULL)
        return errno;
-    for (i = lp->space; i < newspace; i++)
-       newaddrs[i] = NULL;
     lp->addrs = newaddrs;
+    for (i = lp->space; i < newspace; i++) {
+       lp->addrs[i].ai = NULL;
+       lp->addrs[i].freefn = NULL;
+       lp->addrs[i].data = NULL;
+    }
     lp->space = newspace;
     return 0;
 }
@@ -158,7 +129,8 @@ krb5int_free_addrlist (struct addrlist *lp)
 {
     int i;
     for (i = 0; i < lp->naddrs; i++)
-       freeaddrinfo (lp->addrs[i]);
+       if (lp->addrs[i].freefn)
+           (lp->addrs[i].freefn)(lp->addrs[i].data);
     free (lp->addrs);
     lp->addrs = NULL;
     lp->naddrs = lp->space = 0;
@@ -214,26 +186,23 @@ static inline void Tprintf(const char *fmt, ...)
 #endif
 }
 
-static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a)
+#if 0
+extern void krb5int_debug_fprint(const char *, ...);
+#define dprint krb5int_debug_fprint
+#define print_addrlist krb5int_print_addrlist
+extern void print_addrlist (const struct addrlist *a);
+#else
+static inline void dprint(const char *fmt, ...) { }
+static inline void print_addrlist(const struct addrlist *a) { }
+#endif
+
+static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a,
+                                void (*freefn)(void *), void *data)
 {
     int err;
 
-    switch (a->ai_socktype) {
-    case SOCK_DGRAM:
-       Tprintf("\tdgram\n");
-       break;
-    case SOCK_STREAM:
-       Tprintf("\tstream\n");
-       break;
-    case SOCK_RAW:
-       Tprintf("\traw\n");
-       break;
-    case 0:
-       break;
-    default:
-       Tprintf("\tsocket type %d\n", a->ai_socktype);
-       break;
-    }
+    dprint("\tadding %p=%A to %p (naddrs=%d space=%d)\n", a, a, lp,
+          lp->naddrs, lp->space);
 
     if (lp->naddrs == lp->space) {
        err = grow_list (lp, 1);
@@ -242,14 +211,27 @@ static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a)
            return err;
        }
     }
-    lp->addrs[lp->naddrs++] = a;
-    a->ai_next = 0;
-    Tprintf ("count is now %d\n", lp->naddrs);
+    Tprintf("setting element %d\n", lp->naddrs);
+    lp->addrs[lp->naddrs].ai = a;
+    lp->addrs[lp->naddrs].freefn = freefn;
+    lp->addrs[lp->naddrs].data = data;
+    lp->naddrs++;
+    Tprintf ("\tcount is now %d: ", lp->naddrs);
+    print_addrlist(lp);
+    Tprintf("\n");
     return 0;
 }
 
 #define add_host_to_list krb5int_add_host_to_list
 
+static void call_freeaddrinfo(void *data)
+{
+    /* Strict interpretation of the C standard says we can't assume
+       that the ABI for f(void*) and f(struct foo *) will be
+       compatible.  Use this stub just to be paranoid.  */
+    freeaddrinfo(data);
+}
+
 int
 krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
                          int port, int secport,
@@ -258,6 +240,7 @@ krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
     struct addrinfo *addrs, *a, *anext, hint;
     int err;
     char portbuf[10], secportbuf[10];
+    void (*freefn)(void *);
 
     Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n",
             hostname, ntohs (port), ntohs (secport),
@@ -277,10 +260,11 @@ krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
                 hostname, portbuf, err, gai_strerror (err));
        return translate_ai_error (err);
     }
+    freefn = call_freeaddrinfo;
     anext = 0;
-    for (a = addrs; a != 0 && err == 0; a = anext) {
+    for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) {
        anext = a->ai_next;
-       err = add_addrinfo_to_list (lp, a);
+       err = add_addrinfo_to_list (lp, a, freefn, a);
     }
     if (err || secport == 0)
        goto egress;
@@ -294,13 +278,13 @@ krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
        err = translate_ai_error (err);
        goto egress;
     }
-    for (a = addrs; a != 0 && err == 0; a = anext) {
+    freefn = call_freeaddrinfo;
+    for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) {
        anext = a->ai_next;
-       err = add_addrinfo_to_list (lp, a);
+       err = add_addrinfo_to_list (lp, a, freefn, a);
     }
 egress:
-    if (anext)
-       freeaddrinfo (anext);
+    /* XXX Memory leaks possible here if add_addrinfo_to_list fails.  */
     return err;
 }
 
@@ -559,58 +543,260 @@ krb5_locate_srv_dns_1 (const krb5_data *realm,
 }
 #endif
 
+#include "k5-plugin.h"
+
+static const char objdir[] = LIBDIR "/krb5/plugins/libkrb5";
+
+struct module_callback_data {
+    int out_of_mem;
+    struct addrlist *lp;
+};
+
+static int
+module_callback (void *cbdata, int socktype, struct sockaddr *sa)
+{
+    struct module_callback_data *d = cbdata;
+    struct {
+       struct addrinfo ai;
+       union {
+           struct sockaddr_in sin;
+           struct sockaddr_in6 sin6;
+       } u;
+    } *x;
+
+    if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+       return 0;
+    if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+       return 0;
+    x = malloc (sizeof (*x));
+    if (x == 0) {
+       d->out_of_mem = 1;
+       return 1;
+    }
+    memset(x, 0, sizeof (*x));
+    x->ai.ai_addr = (struct sockaddr *) &x->u;
+    x->ai.ai_socktype = socktype;
+    x->ai.ai_family = sa->sa_family;
+    if (sa->sa_family == AF_INET) {
+       x->u.sin = *(struct sockaddr_in *)sa;
+       x->ai.ai_addrlen = sizeof(struct sockaddr_in);
+    }
+    if (sa->sa_family == AF_INET6) {
+       x->u.sin6 = *(struct sockaddr_in6 *)sa;
+       x->ai.ai_addrlen = sizeof(struct sockaddr_in6);
+    }
+    if (add_addrinfo_to_list (d->lp, &x->ai, free, x) != 0) {
+       /* Assumes only error is ENOMEM.  */
+       d->out_of_mem = 1;
+       return 1;
+    }
+    return 0;
+}
+
+static krb5_error_code
+module_locate_server (krb5_context ctx, const krb5_data *realm,
+                     struct addrlist *addrlist,
+                     enum locate_service_type svc, int socktype, int family)
+{
+    struct krb5plugin_service_locate_result *res = NULL;
+    krb5_error_code code;
+    struct krb5plugin_service_locate_ftable *vtbl = NULL;
+    void **ptrs;
+    int i;
+    struct module_callback_data cbdata = { 0, addrlist };
+
+    Tprintf("in module_locate_server\n");
+    if (!PLUGIN_DIR_OPEN (&ctx->libkrb5_plugins)) {
+       code = krb5int_open_plugin_dir (objdir, &ctx->libkrb5_plugins);
+       if (code)
+           return KRB5_PLUGIN_NO_HANDLE;
+    }
+
+    code = krb5int_get_plugin_dir_data (&ctx->libkrb5_plugins, "service_locator", &ptrs);
+    if (code) {
+       Tprintf("error looking up plugin symbols: %s\n", error_message(code));
+       return KRB5_PLUGIN_NO_HANDLE;
+    }
+
+    for (i = 0; ptrs[i]; i++) {
+       void *blob;
+
+       vtbl = ptrs[i];
+       Tprintf("element %d is %p\n", i, ptrs[i]);
+
+       /* For now, don't keep the plugin data alive.  For long-lived
+          contexts, it may be desirable to change that later.  */
+       code = vtbl->init(ctx, &blob);
+       if (code)
+           continue;
+
+       code = vtbl->lookup(blob, svc, realm->data, socktype, family,
+                           module_callback, &cbdata);
+       vtbl->fini(blob);
+       if (code == KRB5_PLUGIN_NO_HANDLE) {
+           /* Module passes, keep going.  */
+           /* XXX */
+           Tprintf("plugin doesn't handle this realm (KRB5_PLUGIN_NO_HANDLE)\n");
+           continue;
+       }
+       if (code != 0) {
+           /* Module encountered an actual error.  */
+           Tprintf("plugin lookup routine returned error %d: %s\n",
+                   code, error_message(code));
+           krb5int_free_plugin_dir_data (ptrs);
+           return code;
+       }
+       break;
+    }
+    if (ptrs[i] == NULL) {
+       Tprintf("ran off end of plugin list\n");
+       krb5int_free_plugin_dir_data (ptrs);
+       return KRB5_PLUGIN_NO_HANDLE;
+    }
+    Tprintf("stopped with plugin #%d, res=%p\n", i, res);
+
+    /* Got something back, yippee.  */
+    Tprintf("now have %d addrs in list %p\n", addrlist->naddrs, addrlist);
+    print_addrlist(addrlist);
+    krb5int_free_plugin_dir_data (ptrs);
+    return 0;
+}
+
+static krb5_error_code
+prof_locate_server (krb5_context context, const krb5_data *realm,
+                   struct addrlist *addrlist,
+                   enum locate_service_type svc, int socktype, int family)
+{
+    const char *profname;
+    int dflport1, dflport2 = 0;
+    struct servent *serv;
+
+    switch (svc) {
+    case locate_service_kdc:
+       profname = "kdc";
+       /* We used to use /etc/services for these, but enough systems
+          have old, crufty, wrong settings that this is probably
+          better.  */
+    kdc_ports:
+       dflport1 = htons(KRB5_DEFAULT_PORT);
+       dflport2 = htons(KRB5_DEFAULT_SEC_PORT);
+       break;
+    case locate_service_master_kdc:
+       profname = "master_kdc";
+       goto kdc_ports;
+    case locate_service_kadmin:
+       profname = "admin_server";
+       dflport1 = htons(DEFAULT_KADM5_PORT);
+       break;
+    case locate_service_krb524:
+       profname = "krb524_server";
+       serv = getservbyname(KRB524_SERVICE, "udp");
+       dflport1 = serv ? serv->s_port : htons (KRB524_PORT);
+       break;
+    case locate_service_kpasswd:
+       profname = "kpasswd_server";
+       dflport1 = htons(DEFAULT_KPASSWD_PORT);
+       break;
+    default:
+       return EBUSY;           /* XXX */
+    }
+
+    return krb5_locate_srv_conf_1 (context, realm, profname, addrlist,
+                                  0, socktype,
+                                  dflport1, dflport2, family);
+}
+
+static krb5_error_code
+dns_locate_server (krb5_context context, const krb5_data *realm,
+                  struct addrlist *addrlist,
+                  enum locate_service_type svc, int socktype, int family)
+{
+    const char *dnsname;
+    int use_dns = _krb5_use_dns_kdc(context);
+    krb5_error_code code;
+
+    if (!use_dns)
+       return KRB5_PLUGIN_NO_HANDLE;
+
+    switch (svc) {
+    case locate_service_kdc:
+       dnsname = "_kerberos";
+       break;
+    case locate_service_master_kdc:
+       dnsname = "_kerberos-master";
+       break;
+    case locate_service_kadmin:
+       dnsname = "_kerberos-adm";
+       break;
+    case locate_service_krb524:
+       dnsname = "_krb524";
+       break;
+    case locate_service_kpasswd:
+       dnsname = "_kpasswd";
+       break;
+    default:
+       return KRB5_PLUGIN_NO_HANDLE;
+    }
+
+    code = 0;
+    if (socktype == SOCK_DGRAM || socktype == 0) {
+       code = krb5_locate_srv_dns_1(realm, dnsname, "_udp", addrlist, family);
+       if (code)
+           Tprintf("dns udp lookup returned error %d\n", code);
+    }
+    if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
+       code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp", addrlist, family);
+       if (code)
+           Tprintf("dns tcp lookup returned error %d\n", code);
+    }
+    return code;
+}
+
 /*
- * Wrapper function for the two backends
+ * Wrapper function for the various backends
  */
 
 krb5_error_code
 krb5int_locate_server (krb5_context context, const krb5_data *realm,
                       struct addrlist *addrlist,
-                      int get_masters,
-                      const char *profname, const char *dnsname,
-                      int socktype,
-                      /* network order port numbers! */
-                      int dflport1, int dflport2,
-                      int family)
+                      enum locate_service_type svc,
+                      int socktype, int family)
 {
     krb5_error_code code;
     struct addrlist al = ADDRLIST_INIT;
 
     *addrlist = al;
 
+    code = module_locate_server(context, realm, &al, svc, socktype, family);
+    Tprintf("module_locate_server returns %d\n", code);
+    if (code != KRB5_PLUGIN_NO_HANDLE) {
+       *addrlist = al;
+       return code;
+    }
+
     /*
-     * We always try the local file first
+     * We always try the local file before DNS
      */
 
-    code = krb5_locate_srv_conf_1(context, realm, profname, &al, get_masters,
-                                 socktype, dflport1, dflport2, family);
+    code = prof_locate_server(context, realm, &al, svc, socktype, family);
+
+    /* We could put more heuristics here, like looking up a hostname
+       of "kerberos."+REALM, etc.  */
 
 #ifdef KRB5_DNS_LOOKUP
-    if (code && dnsname != 0) {
-       int use_dns = _krb5_use_dns_kdc(context);
-       if (use_dns) {
-           code = 0;
-           if (socktype == SOCK_DGRAM || socktype == 0) {
-               code = krb5_locate_srv_dns_1(realm, dnsname, "_udp",
-                                            &al, family);
-               if (code)
-                   Tprintf("dns udp lookup returned error %d\n", code);
-           }
-           if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
-               code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp",
-                                            &al, family);
-               if (code)
-                   Tprintf("dns tcp lookup returned error %d\n", code);
-           }
-       }
+    if (code) {
+       krb5_error_code code2;
+       code2 = dns_locate_server(context, realm, &al, svc, socktype, family);
+       if (code2 != KRB5_PLUGIN_NO_HANDLE)
+           code = code2;
     }
 #endif /* KRB5_DNS_LOOKUP */
     if (code == 0)
        Tprintf ("krb5int_locate_server found %d addresses\n",
                 al.naddrs);
     else
-       Tprintf ("krb5int_locate_server returning error code %d\n",
-                code);
+       Tprintf ("krb5int_locate_server returning error code %d/%s\n",
+                code, error_message(code));
     if (code != 0) {
        if (al.space)
            free_list (&al);
@@ -630,24 +816,9 @@ krb5_locate_kdc(krb5_context context, const krb5_data *realm,
                struct addrlist *addrlist,
                int get_masters, int socktype, int family)
 {
-    int udpport, sec_udpport;
-
-    udpport = get_port (KDC_PORTNAME, 0, KRB5_DEFAULT_PORT);
-    if (socktype == SOCK_STREAM)
-       sec_udpport = 0;
-    else {
-       sec_udpport = get_port (KDC_SECONDARY_PORTNAME, 0,
-                               (udpport == htons (KRB5_DEFAULT_PORT)
-                                ? KRB5_DEFAULT_SEC_PORT
-                                : KRB5_DEFAULT_PORT));
-       if (sec_udpport == udpport)
-           sec_udpport = 0;
-    }
-
-    return krb5int_locate_server(context, realm, addrlist, 0,
-                                get_masters ? "master_kdc" : "kdc",
+    return krb5int_locate_server(context, realm, addrlist,
                                 (get_masters
-                                 ? "_kerberos-master"
-                                 : "_kerberos"),
-                                socktype, udpport, sec_udpport, family);
+                                 ? locate_service_master_kdc
+                                 : locate_service_kdc),
+                                socktype, family);
 }
index 004d80348688b399c2469a90eac10613e7592bcb..09c9c90228c5c0dbbd8127147b974398f02bbe48 100644 (file)
@@ -77,10 +77,8 @@ krb5int_524_sendto_kdc (context, message, realm, reply, addr, addrlen)
     serv = getservbyname(KRB524_SERVICE, "udp");
     port = serv ? serv->s_port : htons (KRB524_PORT);
 
-    retval = krb5int_locate_server(context, realm, &al, 0,
-                                  "krb524_server", "_krb524",
-                                  SOCK_DGRAM, port,
-                                  0, PF_INET);
+    retval = krb5int_locate_server(context, realm, &al, locate_service_krb524,
+                                  SOCK_DGRAM, PF_INET);
     if (retval == KRB5_REALM_CANT_RESOLVE || retval == KRB5_REALM_UNKNOWN) {
        /* Fallback heuristic: Assume krb524 port on every KDC might
           work.  */
@@ -90,9 +88,9 @@ krb5int_524_sendto_kdc (context, message, realm, reply, addr, addrlen)
         */
        if (retval == 0)
            for (i = 0; i < al.naddrs; i++) {
-               al.addrs[i]->ai_socktype = SOCK_DGRAM;
-               if (al.addrs[i]->ai_family == AF_INET)
-                   sa2sin (al.addrs[i]->ai_addr)->sin_port = port;
+               al.addrs[i].ai->ai_socktype = SOCK_DGRAM;
+               if (al.addrs[i].ai->ai_family == AF_INET)
+                   sa2sin (al.addrs[i].ai->ai_addr)->sin_port = port;
            }
     }
     if (retval)
index e35c337d360fe67480f8ac74f5eafed8de16fb6d..23e99d51c9dcc21438dab70b6d193907dd851533 100644 (file)
@@ -93,7 +93,7 @@ void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = 0;
 #endif
 
 #define dprint krb5int_debug_fprint
-static void
+ void
 krb5int_debug_fprint (const char *fmt, ...)
 {
 #ifdef DEBUG
@@ -198,18 +198,22 @@ krb5int_debug_fprint (const char *fmt, ...)
        case 'A':
            /* %A => addrinfo */
            ai = va_arg(args, struct addrinfo *);
+           if (ai->ai_socktype == SOCK_DGRAM)
+               strcpy(tmpbuf, "dgram");
+           else if (ai->ai_socktype == SOCK_STREAM)
+               strcpy(tmpbuf, "stream");
+           else
+               sprintf(tmpbuf, "socktype%d", ai->ai_socktype);
            if (0 != getnameinfo (ai->ai_addr, ai->ai_addrlen,
                                  addrbuf, sizeof (addrbuf),
                                  portbuf, sizeof (portbuf),
-                                 NI_NUMERICHOST | NI_NUMERICSERV))
-               strcpy (addrbuf, "??"), strcpy (portbuf, "??");
-           sprintf(tmpbuf, "%s %s.%s",
-                   (ai->ai_socktype == SOCK_DGRAM
-                    ? "udp"
-                    : ai->ai_socktype == SOCK_STREAM
-                    ? "tcp"
-                    : "???"),
-                   addrbuf, portbuf);
+                                 NI_NUMERICHOST | NI_NUMERICSERV)) {
+               if (ai->ai_addr->sa_family == AF_UNSPEC)
+                   strcpy(tmpbuf + strlen(tmpbuf), " AF_UNSPEC");
+               else
+                   sprintf(tmpbuf + strlen(tmpbuf), " af%d", ai->ai_addr->sa_family);
+           } else
+               sprintf(tmpbuf + strlen(tmpbuf), " %s.%s", addrbuf, portbuf);
            putstr(tmpbuf);
            break;
        case 'D':
@@ -224,17 +228,30 @@ krb5int_debug_fprint (const char *fmt, ...)
 #endif
 }
 
+#define print_addrlist krb5int_print_addrlist
+static void
+print_addrlist (const struct addrlist *a)
+{
+    int i;
+    dprint("%d{", a->naddrs);
+    for (i = 0; i < a->naddrs; i++)
+       dprint("%s%p=%A", i ? "," : "", (void*)a->addrs[i].ai, a->addrs[i].ai);
+    dprint("}");
+}
+
 static int
 merge_addrlists (struct addrlist *dest, struct addrlist *src)
 {
+    /* Wouldn't it be nice if we could filter out duplicates?  The
+       alloc/free handling makes that pretty difficult though.  */
     int err, i;
 
     dprint("merging addrlists:\n\tlist1: ");
     for (i = 0; i < dest->naddrs; i++)
-       dprint(" %A", dest->addrs[i]);
+       dprint(" %A", dest->addrs[i].ai);
     dprint("\n\tlist2: ");
     for (i = 0; i < src->naddrs; i++)
-       dprint(" %A", src->addrs[i]);
+       dprint(" %A", src->addrs[i].ai);
     dprint("\n");
 
     err = krb5int_grow_addrlist (dest, src->naddrs);
@@ -242,19 +259,33 @@ merge_addrlists (struct addrlist *dest, struct addrlist *src)
        return err;
     for (i = 0; i < src->naddrs; i++) {
        dest->addrs[dest->naddrs + i] = src->addrs[i];
-       src->addrs[i] = 0;
+       src->addrs[i].ai = 0;
+       src->addrs[i].freefn = 0;
     }
     dest->naddrs += i;
     src->naddrs = 0;
 
     dprint("\tout:   ");
     for (i = 0; i < dest->naddrs; i++)
-       dprint(" %A", dest->addrs[i]);
+       dprint(" %A", dest->addrs[i].ai);
     dprint("\n");
 
     return 0;
 }
 
+static int
+in_addrlist (struct addrinfo *thisaddr, struct addrlist *list)
+{
+    int i;
+    for (i = 0; i < list->naddrs; i++) {
+       if (thisaddr->ai_addrlen == list->addrs[i].ai->ai_addrlen
+           && !memcmp(thisaddr->ai_addr, list->addrs[i].ai->ai_addr,
+                      thisaddr->ai_addrlen))
+           return 1;
+    }
+    return 0;
+}
+
 /*
  * send the formatted request 'message' to a KDC for realm 'realm' and
  * return the response (if any) in 'reply'.
@@ -271,7 +302,7 @@ krb5_sendto_kdc (krb5_context context, const krb5_data *message,
                 const krb5_data *realm, krb5_data *reply,
                 int *use_master, int tcp_only)
 {
-    krb5_error_code retval;
+    krb5_error_code retval, retval2;
     struct addrlist addrs;
     int socktype1 = 0, socktype2 = 0, addr_used;
 
@@ -321,12 +352,23 @@ krb5_sendto_kdc (krb5_context context, const krb5_data *message,
     if (socktype2) {
        struct addrlist addrs2;
 
-       retval = krb5_locate_kdc(context, realm, &addrs2, *use_master,
-                                socktype2, 0);
+       retval2 = krb5_locate_kdc(context, realm, &addrs2, *use_master,
+                                 socktype2, 0);
+#if 0
+       if (retval2 == 0) {
+           (void) merge_addrlists(&addrs, &addrs2);
+           krb5int_free_addrlist(&addrs2);
+           retval = 0;
+       } else if (retval == KRB5_REALM_CANT_RESOLVE) {
+           retval = retval2;
+       }
+#else
+       retval = retval2;
        if (retval == 0) {
            (void) merge_addrlists(&addrs, &addrs2);
            krb5int_free_addrlist(&addrs2);
        }
+#endif
     }
 
     if (addrs.naddrs > 0) {
@@ -340,20 +382,11 @@ krb5_sendto_kdc (krb5_context context, const krb5_data *message,
             if (*use_master == 0) {
                 struct addrlist addrs3;
                 retval = krb5_locate_kdc(context, realm, &addrs3, 1, 
-                                         addrs.addrs[addr_used]->ai_socktype,
-                                         addrs.addrs[addr_used]->ai_family);
+                                         addrs.addrs[addr_used].ai->ai_socktype,
+                                         addrs.addrs[addr_used].ai->ai_family);
                 if (retval == 0) {
-                    int i;
-                    for (i = 0; i < addrs3.naddrs; i++) {
-                        if (addrs.addrs[addr_used]->ai_addrlen ==
-                            addrs3.addrs[i]->ai_addrlen &&
-                            memcmp(addrs.addrs[addr_used]->ai_addr,
-                                   addrs3.addrs[i]->ai_addr,
-                                   addrs.addrs[addr_used]->ai_addrlen) == 0) {
-                            *use_master = 1;
-                            break;
-                        }
-                    }
+                   if (in_addrlist(addrs.addrs[addr_used].ai, &addrs3))
+                       *use_master = 1;
                     krb5int_free_addrlist (&addrs3);
                 }
             }
@@ -1039,7 +1072,9 @@ krb5int_sendto (krb5_context context, const krb5_data *message,
     unsigned char message_len_buf[4];
     char *udpbuf = 0;
 
-    dprint("krb5int_sendto(message=%d@%p)\n", message->length, message->data);
+    dprint("krb5int_sendto(message=%d@%p, addrlist=", message->length, message->data);
+    print_addrlist(addrs);
+    dprint(")\n");
 
     reply->data = 0;
     reply->length = 0;
@@ -1075,7 +1110,7 @@ krb5int_sendto (krb5_context context, const krb5_data *message,
 
     /* Set up connections.  */
     for (host = 0; host < n_conns; host++) {
-       retval = setup_connection (&conns[host], addrs->addrs[host],
+       retval = setup_connection (&conns[host], addrs->addrs[host].ai,
                                   message, message_len_buf, &udpbuf);
        if (retval)
            continue;
index 7d5d554fabcf4f0dacd44b927dd2c930ac512f2d..165366f5be82374d1ec44f74443e3cd9bd85f611 100644 (file)
@@ -5,6 +5,8 @@
 #include <com_err.h>
 
 #define TEST
+#include "dnsglue.c"
+#include "dnssrv.c"
 #include "locate_kdc.c"
 
 enum {
@@ -43,14 +45,14 @@ void print_addrs (void)
 {
     int i;
 
-    struct addrinfo **addrs = al.addrs;
     int naddrs = al.naddrs;
 
     printf ("%d addresses:\n", naddrs);
     for (i = 0; i < naddrs; i++) {
        int err;
+       struct addrinfo *ai = al.addrs[i].ai;
        char hostbuf[NI_MAXHOST], srvbuf[NI_MAXSERV];
-       err = getnameinfo (addrs[i]->ai_addr, addrs[i]->ai_addrlen,
+       err = getnameinfo (ai->ai_addr, ai->ai_addrlen,
                           hostbuf, sizeof (hostbuf),
                           srvbuf, sizeof (srvbuf),
                           NI_NUMERICHOST | NI_NUMERICSERV);
@@ -59,7 +61,7 @@ void print_addrs (void)
                    i, err, gai_strerror (err));
        else
            printf ("%2d: address %s\t%s\tport %s\n", i, hostbuf,
-                   stypename (addrs[i]->ai_socktype), srvbuf);
+                   stypename (ai->ai_socktype), srvbuf);
     }
 }
 
index adaf6893db80d555996d4ec1ac361b85aaa4d731..04b75d7b802556f1b968b12e914623f5bd04099c 100644 (file)
@@ -113,7 +113,7 @@ static void test_locate_kdc(krb5_context ctx, char *realm)
        }
        printf("krb_locate_kdc(%s) returned:", realm);
        for (i=0; i < addrs.naddrs; i++) {
-           struct addrinfo *ai = addrs.addrs[i];
+           struct addrinfo *ai = addrs.addrs[i].ai;
            switch (ai->ai_family) {
            case AF_INET:
            {
index c6461f9ad8fc1ec494e070477c03fc7e4587882d..df039d06371b0cab731a2c735f5c95d5790242f9 100644 (file)
@@ -1,3 +1,9 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * Makefile.in (MODULE_INSTALL_DIR): New variable.
+       (DYNOBJ_LOADER_PROG, DYNOBJ_EXPLIBS_WITH_LOADER,
+       DYNOBJ_EXPDEPS_WITH_LOADER): Deleted.
+
 2006-01-25  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in (DEFINES): New variable; define macro PLUGIN.
index 06b037ce0e5013eb5a4faa6e7082f3e68f3c58c8..c40624f8491701c6e2abd712d9333d65be837525 100644 (file)
@@ -6,6 +6,7 @@ KRB5_RUN_ENV = @KRB5_RUN_ENV@
 KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
+MODULE_INSTALL_DIR = $(KRB5_DB_MODULE_DIR)
 
 LOCALINCLUDES = -I../../../lib/kdb -I$(srcdir)/../../../lib/kdb
 DEFINES = -DPLUGIN
@@ -63,10 +64,6 @@ STLIBOBJS= \
        pol_xdr.o \
        db2_exp.o
 
-DYNOBJ_LOADER_PROG = $(BUILDTOP)/kdc/krb5kdc
-DYNOBJ_EXPLIBS_WITH_LOADER = -lgssrpc $(KDB5_DB_LIB)
-DYNOBJ_EXPDEPS_WITH_LOADER = $(GSSRPC_DEPLIBS)
-
 all-unix:: $(LIBBASE)$(SO_EXT)
 install-unix:: install-libs
 clean-unix:: clean-libs clean-libobjs
diff --git a/src/plugins/locate/python/ChangeLog b/src/plugins/locate/python/ChangeLog
new file mode 100644 (file)
index 0000000..6824a29
--- /dev/null
@@ -0,0 +1,5 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * Makefile.in, configure.in, py-locate.c, python.exports,
+       locate-service.py: New files.
+
diff --git a/src/plugins/locate/python/Makefile.in b/src/plugins/locate/python/Makefile.in
new file mode 100644 (file)
index 0000000..46a83fe
--- /dev/null
@@ -0,0 +1,42 @@
+thisconfigdir=.
+myfulldir=plugins/locate/python
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+LIBBASE=python
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/locate/python
+MODULE_INSTALL_DIR = $(KRB5_LIBKRB5_MODULE_DIR)
+
+SHLIB_EXPDEPS=
+SHLIB_EXPLIBS= -lpython2.3
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+SRCS= \
+       $(srcdir)/py-locate.c
+STOBJLISTS=OBJS.ST
+STLIBOBJS= py-locate.o
+
+all-unix:: $(LIBBASE)$(SO_EXT)
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+# @libnover_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+py-locate.so py-locate.po $(OUTPRE)py-locate.$(OBJEXT): \
+  py-locate.c $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/k5-plugin.h
diff --git a/src/plugins/locate/python/configure.in b/src/plugins/locate/python/configure.in
new file mode 100644 (file)
index 0000000..34f8306
--- /dev/null
@@ -0,0 +1,10 @@
+K5_AC_INIT(configure.in)
+enable_shared=yes
+build_dynobj=yes
+CONFIG_RULES
+AC_CHECK_HEADERS(Python.h python2.3/Python.h)
+dnl AC_CHECK_LIB(python2.3)
+
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/plugins/locate/python/locate-service.py b/src/plugins/locate/python/locate-service.py
new file mode 100644 (file)
index 0000000..53153be
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright 2006 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.
+
+# possible return values:
+#  False: request not handled by this script, try another means
+#  empty list: no server available, e.g., TCP KDC in realm with only UDP
+#  ordered list of (ip-addr-string, port-number-or-string, socket-type)
+#
+# Field ip-addr-string is a numeric representation of the IPv4 or IPv6
+# address.  Field port-number-or-string is, for example, "88" or 88.  The
+# socket type is also expressed numerically, SOCK_DGRAM or SOCK_STREAM.
+# It must agree with the supplied socktype value if that is non-zero, but
+# zero must not be used in the returned list.
+#
+# service enum values: kdc=1, master_kdc, kadmin, krb524, kpasswd
+
+from socket import getaddrinfo, SOCK_STREAM, SOCK_DGRAM, AF_INET, AF_INET6
+def locate1 (service, realm, socktype, family):
+   if (service == 1 or service == 2) and realm == "ATHENA.MIT.EDU":
+      if socktype == SOCK_STREAM: return []
+      socktype = SOCK_DGRAM
+      result = []
+      hlist = (("kerberos.mit.edu", 88), ("kerberos-1.mit.edu", 88),
+              ("some-random-name-that-does-not-exist.mit.edu", 12345),
+              ("kerberos.mit.edu", 750))
+      if service == 2: hlist = (hlist[0],)
+      for (hname,hport) in hlist:
+        try:
+           alist = getaddrinfo(hname, hport, family, socktype)
+           for a in alist:
+              (fam, stype, proto, canonname, sa) = a
+              if fam == AF_INET or fam == AF_INET6:
+                 addr = sa[0]
+                 port = sa[1]
+                 result = result + [(addr, port, stype)]
+        except Exception, inst:
+#           print "getaddrinfo error for " + hname + ":", inst
+           pass  # Enh, this is just a demo.
+      return result
+   if realm == "BOBO.MIT.EDU": return []
+   return False
+
+verbose = 0
+servicenames = { 1: "kdc", 2: "master_kdc", 3: "kadmin", 4: "krb524", 5: "kpasswd" }
+socktypenames = { SOCK_STREAM: "STREAM", SOCK_DGRAM: "DGRAM" }
+familynames = { 0: "UNSPEC", AF_INET: "INET", AF_INET6: "INET6" }
+
+def locate (service, realm, socktype, family):
+   socktypename = socktype
+   if socktype in socktypenames: socktypename = "%s(%d)" % (socktypenames[socktype], socktype)
+   familyname = family
+   if family in familynames: familyname = "%s(%d)" % (familynames[family], family)
+   servicename = service
+   if service in servicenames: servicename = "%s(%d)" % (servicenames[service], service)
+   if verbose: print "locate called with service", servicename, "realm", realm, "socktype", socktypename, "family", familyname
+   result = locate1 (service, realm, socktype, family)
+   if verbose: print "locate result is", result
+   return result
diff --git a/src/plugins/locate/python/py-locate.c b/src/plugins/locate/python/py-locate.c
new file mode 100644 (file)
index 0000000..a315e35
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * plugins/locate/python/py-locate.c
+ *
+ * Copyright 2006 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 is a demo module.  The error checking is incomplete, there's
+   no exception handling, and it wouldn't surprise me in the least if
+   there are more bugs in the refcount maintenance.
+
+   But it will demonstrate (1) the plugin interface for locating a KDC
+   or other Kerberos-related service, and (2) that it's possible for
+   these plugins to call out to scripts in various languages for
+   prototyping or whatever.
+
+   Some notes:
+
+   If delayed initialization is not done, and the script is executed
+   when this module is loaded, loading other Python modules may not
+   work, if they include object code referencing the Python symbols.
+   Under glibc at least, it appears that the symbols of this module
+   aren't available to random dlopen/dlsym calls until loading
+   finishes, including the initialization routine.  It's completely
+   logical -- in fact, I'd be concerned if it were otherwise.  But not
+   obvious if you're not thinking about it.
+
+   This module seems rather sensitive to bugs in the Python code.  If
+   it's not correct, you may get core dumps, Python GC errors, etc.
+   Probably more signs of bugs in this code.
+
+   All of the -1 returns should be cleaned up and made to return
+   real error codes, with appropriate output if debugging is enabled.
+
+   Blah.  */
+
+/* Include Python.h before autoconf.h, because our autoconf.h seems
+   to confuse Python's headers.  */
+#if HAVE_PYTHON_H
+#include <Python.h>
+#elif HAVE_PYTHON2_3_PYTHON_H
+#include <python2.3/Python.h>
+#else
+#error "Where's the Python header file?"
+#endif
+#include <autoconf.h>
+#include <errno.h>
+#include "k5-int.h"
+
+#include "k5-plugin.h"
+
+#define LIBDIR                 "/tmp" /* should be imported from configure */
+#define SCRIPT_PATH            LIBDIR "/krb5/locate-service.py"
+#define LOOKUP_FUNC_NAME       "locate"
+
+static PyObject *locatefn;
+
+MAKE_INIT_FUNCTION(my_init);
+MAKE_FINI_FUNCTION(my_fini);
+
+#define F      (strchr(__FILE__, '/') ? 1 + strrchr(__FILE__, '/') : __FILE__)
+
+int
+my_init (void)
+{
+    PyObject *mainmodule;
+    FILE *f;
+
+    Py_Initialize ();
+//    fprintf(stderr, "trying to load %s\n", SCRIPT_PATH);
+    f = fopen(SCRIPT_PATH, "r");
+    if (f == NULL)
+       return -1;
+    PyRun_SimpleFile (f, SCRIPT_PATH);
+    fclose(f);
+    mainmodule = PyModule_GetDict(PyImport_AddModule("__main__"));
+    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
+    locatefn = PyDict_GetItemString (mainmodule, LOOKUP_FUNC_NAME);
+    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
+    /* Don't DECREF mainmodule, it's sometimes causing crashes.  */
+    if (locatefn == 0)
+       return -1;
+    if (!PyCallable_Check (locatefn)) {
+       Py_DECREF (locatefn);
+       locatefn = 0;
+       return -1;
+    }
+    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
+    return 0;
+}
+
+void
+my_fini (void)
+{
+//    fprintf(stderr, "%s:%d: Python module finalization\n", F, __LINE__);
+    if (! INITIALIZER_RAN (my_init))
+       return;
+    Py_DECREF (locatefn);
+    locatefn = 0;
+    Py_Finalize ();
+}
+
+static krb5_error_code
+ctxinit (krb5_context ctx, void **blobptr)
+{
+    /* If we wanted to create a separate Python interpreter instance,
+       look up the pathname of the script in the config file used for
+       the current krb5_context, and load the script in that
+       interpreter, this would be a good place for it; the blob could
+       be allocated to hold the reference to the interpreter
+       instance.  */
+    *blobptr = 0;
+    return 0;
+}
+
+static void
+ctxfini (void *blob)
+{
+}
+
+/* Special return codes:
+
+   0: We set a (possibly empty) set of server locations in the result
+   field.  If the server location set is empty, that means there
+   aren't any servers, *not* that we should try the krb5.conf file or
+   DNS or something.
+
+   KRB5_PLUGIN_NO_HANDLE: This realm or service isn't handled here,
+   try some other means.
+
+   Other: Some error happened here.  It may be reported, if the
+   service can't be located by other means.  (In this implementation,
+   the catch-all error code returned in a bunch of places is -1, which
+   isn't going to be very useful to the caller.)  */
+
+static krb5_error_code
+lookup (void *blob, enum locate_service_type svc, const char *realm,
+       int socktype, int family,
+       int (*cbfunc)(void *, int, struct sockaddr *), void *cbdata)
+{
+    PyObject *py_result, *svcarg, *realmarg, *arglist;
+    int listsize, i, x;
+    struct addrinfo aihints, *airesult;
+    int thissocktype;
+
+//    fprintf(stderr, "%s:%d: lookup(%d,%s,%d,%d)\n", F, __LINE__,
+//         svc, realm, socktype, family);
+    i = CALL_INIT_FUNCTION (my_init);
+    if (i) {
+       fprintf(stderr, "%s:%d: module initialization failed %d\n",
+               F, __LINE__, i);
+       return i;
+    }
+    if (locatefn == 0)
+       return KRB5_PLUGIN_NO_HANDLE;
+    svcarg = PyInt_FromLong (svc);
+    /* error? */
+    realmarg = PyString_FromString ((char *) realm);
+    /* error? */
+    arglist = PyTuple_New (4);
+    /* error? */
+
+    PyTuple_SetItem (arglist, 0, svcarg);
+    PyTuple_SetItem (arglist, 1, realmarg);
+    PyTuple_SetItem (arglist, 2, PyInt_FromLong (socktype));
+    PyTuple_SetItem (arglist, 3, PyInt_FromLong (family));
+    /* references handed off, no decref */
+
+    py_result = PyObject_CallObject (locatefn, arglist);
+    Py_DECREF (arglist);
+    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
+    if (py_result == 0) {
+       fprintf(stderr, "%s:%d: returned null object\n", F, __LINE__);
+       return -1;
+    }
+    if (py_result == Py_False)
+       return KRB5_PLUGIN_NO_HANDLE;
+    if (! PyList_Check (py_result)) {
+       Py_DECREF (py_result);
+       fprintf(stderr, "%s:%d: returned non-list, non-False\n", F, __LINE__);
+       return -1;
+    }
+    listsize = PyList_Size (py_result);
+    /* allocate */
+    memset(&aihints, 0, sizeof(aihints));
+    aihints.ai_flags = AI_NUMERICHOST;
+    aihints.ai_family = family;
+    for (i = 0; i < listsize; i++) {
+       PyObject *answer, *field;
+       char *hoststr, *portstr, portbuf[3*sizeof(long) + 4];
+       int cbret;
+
+       answer = PyList_GetItem (py_result, i);
+       if (! PyTuple_Check (answer)) {
+           fprintf(stderr, "%s:%d: item %d non-tuple\n", F, __LINE__, i);
+           /* leak?  */
+           return -1;
+       }
+       if (PyTuple_Size (answer) != 3) {
+           fprintf(stderr, "%s:%d: item %d tuple size %d should be 3\n", F, __LINE__, i,
+                   PyTuple_Size (answer));
+           /* leak?  */
+           return -1;
+       }
+       field = PyTuple_GetItem (answer, 0);
+       if (! PyString_Check (field)) {
+           /* leak?  */
+           fprintf(stderr, "%s:%d: item %d first component not a string\n", F, __LINE__, i);
+           return -1;
+       }
+       hoststr = PyString_AsString (field);
+       field = PyTuple_GetItem (answer, 1);
+       if (PyString_Check (field)) {
+           portstr = PyString_AsString (field);
+       } else if (PyInt_Check (field)) {
+           sprintf(portbuf, "%ld", PyInt_AsLong (field));
+           portstr = portbuf;
+       } else {
+           fprintf(stderr, "%s:%d: item %d second component neither string nor int\n",
+                   F, __LINE__, i);
+           /* leak?  */
+           return -1;
+       }
+       field = PyTuple_GetItem (answer, 2);
+       if (! PyInt_Check (field)) {
+           fprintf(stderr, "%s:%d: item %d third component not int\n", F, __LINE__, i);
+           /* leak?  */
+           return -1;
+       }
+       thissocktype = PyInt_AsLong (field);
+       switch (thissocktype) {
+       case SOCK_STREAM:
+       case SOCK_DGRAM:
+           /* okay */
+           if (socktype != 0 && socktype != thissocktype) {
+               fprintf(stderr, "%s:%d: item %d socket type %d should be %d\n",
+                       F, __LINE__, i, thissocktype, socktype);
+               /* leak?  */
+               return -1;
+           }
+           break;
+       default:
+           /* 0 is not acceptable */
+           fprintf(stderr, "%s:%d: item %d socket type %d invalid\n", F, __LINE__, i,
+                   thissocktype);
+           /* leak?  */
+           return -1;
+       }
+       aihints.ai_socktype = thissocktype;
+       x = getaddrinfo (hoststr, portstr, &aihints, &airesult);
+       if (x != 0)
+           continue;
+       cbret = cbfunc(cbdata, airesult->ai_socktype, airesult->ai_addr);
+       freeaddrinfo(airesult);
+       if (cbret != 0)
+           break;
+    }
+    Py_DECREF (py_result);
+    return 0;
+}
+
+const struct krb5plugin_service_locate_ftable service_locator = {
+    /* version */
+    1, 0,
+    /* functions */
+    ctxinit, ctxfini, lookup,
+};
diff --git a/src/plugins/locate/python/python.exports b/src/plugins/locate/python/python.exports
new file mode 100644 (file)
index 0000000..60ff46e
--- /dev/null
@@ -0,0 +1 @@
+service_locator
index cbb95706e7897cd9547722a4c9d9a264618be548..ea269e8e285d7d001761c2ad71d5f633ee3fa1c0 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * Makefile.in (profile_tcl): Include $(LIBS).
+
 2005-10-21  Ken Raeburn  <raeburn@mit.edu>
 
        * prof_file.c (profile_update_file_data): Drop test of
index 067007d848a797f9ee2e4edae490787ff4df2168..a2d4814c8cc4dbeb95ace3fef479faced6786f91 100644 (file)
@@ -119,7 +119,7 @@ profile_tcl.o: $(srcdir)/profile_tcl.c profile.h
 profile_tcl: profile_tcl.o libprofile.a
        $(CC_LINK) -o profile_tcl profile_tcl.o \
                $(TCL_MAYBE_RPATH) \
-               -L../et -L../.. libprofile.a $(DEPLIBS) $(TCL_LIBS)
+               -L../et -L../.. libprofile.a $(DEPLIBS) $(TCL_LIBS) $(LIBS)
 
 clean-unix:: clean-libs clean-libobjs
        $(RM) $(PROGS) *.o *~ test_parse core prof_err.h \
index 7c3c3648ee357929824c057b9643bfc1a31faabf..4ec482f24323c0d0e518b54d8cddd394cae194c2 100644 (file)
@@ -1,3 +1,11 @@
+2006-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+       * plugins.c: New file.
+       * Makefile.in (LIBMAJOR): Update to 1.
+       (STLIBOBJS, LIBOBJS): Add new file.
+       (SHLIB_EXPLIBS): Add $(DL_LIB).
+       * libkrb5support.exports: Add new functions.
+
 2006-02-24  Jeffrey Altman <jaltman@mit.edu>
 
        * Makefile.in: support for 64-bit Windows builds
index 5abd3a27ee2c3eaa47c122f7c59b98b8f71d3388..da71cad8858ba9d8569b6b01cf7faa8867b4e52f 100644 (file)
@@ -18,7 +18,7 @@ PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
 LIBBASE=krb5support
-LIBMAJOR=0
+LIBMAJOR=1
 LIBMINOR=0
 
 LIBINITFUNC=krb5int_thread_support_init
@@ -27,11 +27,13 @@ LIBFINIFUNC=krb5int_thread_support_fini
 STLIBOBJS= \
        threads.o \
        init-addrinfo.o \
+       plugins.o \
        fake-addrinfo.o
 
 LIBOBJS= \
        $(OUTPRE)threads.$(OBJEXT) \
        $(OUTPRE)init-addrinfo.$(OBJEXT) \
+       $(OUTPRE)plugins.$(OBJEXT) \
        $(OUTPRE)fake-addrinfo.$(OBJEXT)
 
 STOBJLISTS=OBJS.ST
@@ -46,7 +48,7 @@ SRCS=\
        $(srcdir)/fake-addrinfo.c
 SHLIB_EXPDEPS =
 # Add -lm if dumping thread stats, for sqrt.
-SHLIB_EXPLIBS= $(LIBS)
+SHLIB_EXPLIBS= $(LIBS) $(DL_LIB)
 SHLIB_DIRS=
 SHLIB_RDIRS=$(KRB5_LIBDIR)
 
index d06911d5333627cc49ae57e41e6eab2db8560669..1d7bc717f7d805f600745cbea7ff56e2f1adaae2 100644 (file)
@@ -11,6 +11,16 @@ krb5int_gai_strerror
 krb5int_getnameinfo
 krb5int_in6addr_any
 krb5int_pthread_loaded
+krb5int_open_plugin
+krb5int_close_plugin
+krb5int_get_plugin_data
+krb5int_get_plugin_func
+krb5int_open_plugin_dir
+krb5int_close_plugin_dir
+krb5int_get_plugin_dir_data
+krb5int_get_plugin_dir_func
+krb5int_free_plugin_dir_data
+krb5int_free_plugin_dir_func
 krb5int_mutex_alloc
 krb5int_mutex_free
 krb5int_mutex_lock
diff --git a/src/util/support/plugins.c b/src/util/support/plugins.c
new file mode 100644 (file)
index 0000000..bc93aa2
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * util/support/plugins.c
+ *
+ * Copyright 2006 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.
+ * 
+ *
+ * Plugin module support, and shims around dlopen/whatever.
+ */
+
+#include "k5-int.h"
+#include <dlfcn.h>
+
+#include <stdarg.h>
+static void Tprintf (const char *fmt, ...)
+{
+#ifdef DEBUG
+    va_list va;
+    va_start (va, fmt);
+    vfprintf (stderr, fmt, va);
+    va_end (va);
+#endif
+}
+
+struct plugin_file_handle {
+#if 1
+    void *dlhandle;
+#define NULL_HANDLE(X) ((X)->dlhandle == NULL)
+#define MAKE_NULL_HANDLE(X) ((X)->dlhandle = NULL)
+/* #elif _WIN32 ... */
+#else
+    char dummy;
+#define NULL_HANDLE(X) (1)
+#define MAKE_NULL_HANDLE(X) (0)
+#endif
+};
+
+krb5_error_code KRB5_CALLCONV
+krb5int_open_plugin (const char *filename, struct plugin_file_handle **h)
+{
+    struct plugin_file_handle *htmp;
+    void *handle;
+
+    handle = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+    if (handle == NULL) {
+       const char *e;
+       e = dlerror();
+       /* XXX copy and save away */
+       return ENOENT;          /* XXX */
+    }
+    htmp = malloc (sizeof (*htmp));
+    if (htmp == NULL) {
+       int err = errno;
+       dlclose(handle);
+       return err;
+    }
+    *h = htmp;
+    htmp->dlhandle = handle;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_data (struct plugin_file_handle *h, const char *csymname,
+                        void **ptr)
+{
+    void *sym;
+    /* XXX Do we need to add a leading "_" to the symbol name on any
+       modern platforms?  */
+    sym = dlsym(h->dlhandle, csymname);
+    if (sym == NULL) {
+       const char *e;
+       e = dlerror();
+       return ENOENT;
+    }
+    *ptr = sym;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_func (struct plugin_file_handle *h, const char *csymname,
+                        void (**ptr)())
+{
+    /* This code should do for any systems where function and data
+       symbols are handled the same.  Note that this means there's no
+       function version of (say) dlsym, *and* the symbol-prefix
+       handling is the same for both data and functions.  (And the
+       casting we do here works, etc.)  */
+    void *dptr;
+    krb5_error_code err;
+
+    err = krb5int_get_plugin_data (h, csymname, &dptr);
+    if (err == 0)
+       *ptr = (void (*)()) dptr;
+    return err;
+}
+
+void KRB5_CALLCONV
+krb5int_close_plugin (struct plugin_file_handle *h)
+{
+    dlclose(h->dlhandle);
+    h->dlhandle = NULL;
+    free (h);
+}
+
+/* autoconf docs suggest using this preference order */
+#if HAVE_DIRENT_H || USE_DIRENT_H
+#include <dirent.h>
+#define NAMELEN(D) strlen((D)->d_name)
+#else
+#define dirent direct
+#define NAMELEN(D) ((D)->d->namlen)
+#if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+#elif HAVE_SYS_DIR_H
+# include <sys/dir.h>
+#elif HAVE_NDIR_H
+# include <ndir.h>
+#endif
+#endif
+
+krb5_error_code KRB5_CALLCONV
+krb5int_open_plugin_dir (const char *dirname,
+                        struct plugin_dir_handle *dirhandle)
+{
+    /* Q: Should names be sorted in some way first?  */
+    DIR *dir;
+    struct dirent *d;
+    struct plugin_file_handle *h, *newh, handle;
+    int nh;
+    int error = 0;
+    char path[MAXPATHLEN];
+
+    h = NULL;
+    nh = 0;
+    Tprintf("opening plugin directory '%s' to scan...\n", dirname);
+    dir = opendir(dirname);
+    if (dir == NULL) {
+       error = errno;
+       Tprintf("-> error %d/%s\n", error, strerror(error));
+       if (error == ENOENT)
+           return 0;
+       return error;
+    }
+    do {
+       size_t len;
+       struct stat statbuf;
+
+       d = readdir (dir);
+       if (d == NULL)
+           break;
+       len = NAMELEN(d);
+       if (strlen(dirname) + len + 2 > sizeof(path))
+           continue;
+       sprintf(path, "%s/%*s", dirname, (int) len, d->d_name);
+       /* Optimization: Linux includes a file type field in the
+          directory structure.  */
+       if (stat(path, &statbuf) < 0) {
+           Tprintf("stat(%s): %s\n", path, strerror(errno));
+           continue;
+       }
+       if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
+           Tprintf("stat(%s): not a regular file\n", path);
+           continue;
+       }
+       Tprintf("trying to dlopen '%s'\n", path);
+       handle.dlhandle = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+       if (handle.dlhandle == NULL) {
+           const char *e = dlerror();
+           Tprintf("dlopen error: %s\n", e);
+           /* dlerror(); */
+           continue;
+       } else {
+           Tprintf("dlopen succeeds: %p\n", handle.dlhandle);
+       }
+       newh = realloc (h, (nh+1) * sizeof(*h));
+       if (newh == NULL) {
+           int i;
+       close_and_return_errno:
+           error = errno;
+           for (i = 0; i < nh; i++)
+               dlclose(h[i].dlhandle);
+           free(h);
+           return error;
+       }
+       h = newh;
+       h[nh] = handle;
+       nh++;
+    } while (1);
+    Tprintf("done scanning plugin directory\n");
+    newh = realloc (h, (nh+1) * sizeof(*h));
+    if (newh == NULL)
+       goto close_and_return_errno;
+    h = newh;
+    MAKE_NULL_HANDLE (&h[nh]);
+    dirhandle->files = h;
+    return 0;
+}
+
+void KRB5_CALLCONV
+krb5int_close_plugin_dir (struct plugin_dir_handle *dirhandle)
+{
+    struct plugin_file_handle *h;
+    if (dirhandle->files == NULL)
+       return;
+    for (h = dirhandle->files; !NULL_HANDLE (h); h++) {
+       dlclose (h->dlhandle);
+    }
+    free(dirhandle->files);
+    dirhandle->files = NULL;
+}
+
+void KRB5_CALLCONV
+krb5int_free_plugin_dir_data (void **ptrs)
+{
+    /* Nothing special to be done per pointer.  */
+    free(ptrs);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_dir_data (struct plugin_dir_handle *dirhandle,
+                            const char *symname,
+                            void ***ptrs)
+{
+    void **p, **newp, *sym;
+    int count, i, err;
+
+    if (dirhandle == NULL) {
+       *ptrs = 0;
+       return 0;
+    }
+
+    /* XXX Do we need to add a leading "_" to the symbol name on any
+       modern platforms?  */
+
+    Tprintf("get_plugin_data_sym(%s)\n", symname);
+    p = 0;
+    count = 0;
+    for (i = 0; !NULL_HANDLE (&dirhandle->files[i]); i++) {
+       Tprintf("  -> dlsym(%p,%s)\n", dirhandle->files[i].dlhandle, symname);
+       sym = dlsym(dirhandle->files[i].dlhandle, symname);
+       if (sym == NULL) {
+           const char *e = dlerror();
+           Tprintf("    -> %s\n", e);
+           continue;
+       } else {
+           Tprintf("    -> %p\n", sym);
+       }
+       newp = realloc (p, (count+1) * sizeof(*p));
+       if (newp == NULL) {
+       realloc_failure:
+           err = errno;
+           free(p);
+           return err;
+       }
+       p = newp;
+       p[count] = sym;
+       count++;
+    }
+    newp = realloc(p, (count+1) * sizeof(*p));
+    if (newp == NULL)
+       goto realloc_failure;
+    p = newp;
+    p[count] = NULL;
+    *ptrs = p;
+    {
+       i = 0;
+       do {
+           Tprintf("  p[%d] = %p\n", i, p[i]);
+       } while (p[i++]);
+    }
+    return 0;
+}
+
+void KRB5_CALLCONV
+krb5int_free_plugin_dir_func (void (**ptrs)(void))
+{
+    /* Nothing special to be done per pointer.  */
+    free(ptrs);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle,
+                            const char *symname,
+                            void (***ptrs)(void))
+{
+    void (**p)(void), (**newp)(void), (*sym)(void);
+    int count, i, err;
+
+    if (dirhandle == NULL) {
+       *ptrs = 0;
+       return 0;
+    }
+
+    /* XXX Do we need to add a leading "_" to the symbol name on any
+       modern platforms?  */
+
+    p = 0;
+    count = 0;
+    for (i = 0; !NULL_HANDLE (&dirhandle->files[i]); i++) {
+       sym = (void(*)(void)) dlsym(dirhandle->files[i].dlhandle, symname);
+       if (sym == NULL)
+           continue;
+       newp = realloc (p, (count+1) * sizeof(*p));
+       if (newp == NULL) {
+       realloc_failure:
+           err = errno;
+           free(p);
+           return err;
+       }
+       p = newp;
+       p[count] = sym;
+       count++;
+    }
+    newp = realloc(p, (count+1) * sizeof(*p));
+    if (newp == NULL)
+       goto realloc_failure;
+    p[count] = NULL;
+    *ptrs = p;
+    return 0;
+}