From: Ken Raeburn Date: Tue, 7 Mar 2006 20:45:24 +0000 (+0000) Subject: Merge from plugin branch X-Git-Tag: krb5-1.5-alpha1~189 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=8f09bfe9fa0e51c2bd1e2f533eb25655e88ca43b;p=krb5.git Merge from plugin branch 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 --- diff --git a/src/ChangeLog b/src/ChangeLog index dbc3ec788..8d40b20a9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +2006-03-06 Ken Raeburn + + * 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 * Makefile.in (clean-unix): Delete util/fakedest. diff --git a/src/Makefile.in b/src/Makefile.in index ff6c27768..7b0f53cc4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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) diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 46a70e69a..05452d19a 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -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) ]) diff --git a/src/config/ChangeLog b/src/config/ChangeLog index f61eef637..ca5704b2a 100644 --- a/src/config/ChangeLog +++ b/src/config/ChangeLog @@ -1,3 +1,18 @@ +2006-03-06 Ken Raeburn + + * 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 * win-pre.in, win-post.in: support for 64-bit Windows builds diff --git a/src/config/lib.in b/src/config/lib.in index 80f7b4182..40c245b08 100644 --- a/src/config/lib.in +++ b/src/config/lib.in @@ -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 diff --git a/src/config/libnover.in b/src/config/libnover.in index 3896e8462..09c42dcc8 100644 --- a/src/config/libnover.in +++ b/src/config/libnover.in @@ -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 diff --git a/src/config/pre.in b/src/config/pre.in index 2dcba6c2c..808b03f59 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -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 # diff --git a/src/config/shlib.conf b/src/config/shlib.conf index a7ec085c3..744d7ea05 100644 --- a/src/config/shlib.conf +++ b/src/config/shlib.conf @@ -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*) diff --git a/src/configure.in b/src/configure.in index 74985522d..63021d9f3 100644 --- a/src/configure.in +++ b/src/configure.in @@ -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 diff --git a/src/include/ChangeLog b/src/include/ChangeLog index 422de1cb5..9dad2a256 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,3 +1,24 @@ +2006-03-06 Ken Raeburn + + * 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 * win-mac.h: support for 64-bit Windows builds diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 3f8c60da7..bf068828e 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -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 index 000000000..a49c79ad2 --- /dev/null +++ b/src/include/k5-plugin.h @@ -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 diff --git a/src/include/krb5/ChangeLog b/src/include/krb5/ChangeLog index dcce9d0a7..bbc1d8b97 100644 --- a/src/include/krb5/ChangeLog +++ b/src/include/krb5/ChangeLog @@ -1,3 +1,8 @@ +2006-03-06 Ken Raeburn + + * Makefile.in (PROCESS_REPLACE): Use MODULE_DIR instead of + KRB5_DB_MODULE_DIR. + 2005-11-17 Ken Raeburn * Makefile.in (osconf.h): Always remove osconf.new. diff --git a/src/include/krb5/Makefile.in b/src/include/krb5/Makefile.in index 429b35515..7ef43d413 100644 --- a/src/include/krb5/Makefile.in +++ b/src/include/krb5/Makefile.in @@ -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)+' diff --git a/src/include/krb5/stock/ChangeLog b/src/include/krb5/stock/ChangeLog index cfa6cb4de..c341acea6 100644 --- a/src/include/krb5/stock/ChangeLog +++ b/src/include/krb5/stock/ChangeLog @@ -1,3 +1,9 @@ +2006-03-06 Ken Raeburn + + * osconf.h (DEFAULT_KDB_LIB_PATH): Add "/kdb" on end of + MODULEDIR. + (MODULE_PATH): New macro. + 2005-06-29 Ken Raeburn * osconf.h (DEFAULT_KDB_LIB_PATH): Use @MODULEDIR. Don't use a diff --git a/src/include/krb5/stock/osconf.h b/src/include/krb5/stock/osconf.h index 367109b11..03b2ce651 100644 --- a/src/include/krb5/stock/osconf.h +++ b/src/include/krb5/stock/osconf.h @@ -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" diff --git a/src/kadmin/testing/scripts/ChangeLog b/src/kadmin/testing/scripts/ChangeLog index 59a925093..a041b8532 100644 --- a/src/kadmin/testing/scripts/ChangeLog +++ b/src/kadmin/testing/scripts/ChangeLog @@ -1,3 +1,7 @@ +2006-03-06 Ken Raeburn + + * init_db: Change MODDIR setting to match new installation path. + 2005-08-16 Ken Raeburn * env-setup.shin: Export $libdir. diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db index 5ebacc091..93b6fa16e 100755 --- a/src/kadmin/testing/scripts/init_db +++ b/src/kadmin/testing/scripts/init_db @@ -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 diff --git a/src/lib/krb5/error_tables/ChangeLog b/src/lib/krb5/error_tables/ChangeLog index bb59895bf..e84f292d3 100644 --- a/src/lib/krb5/error_tables/ChangeLog +++ b/src/lib/krb5/error_tables/ChangeLog @@ -1,3 +1,7 @@ +2006-03-06 Ken Raeburn + + * krb5_err.et (KRB5_PLUGIN_NO_HANDLE): New error code. + 2006-01-27 Sam Hartman * kdb5_err.et: New error codes for plugin errors diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 1f2bfca53..865c838a6 100644 --- a/src/lib/krb5/error_tables/krb5_err.et +++ b/src/lib/krb5/error_tables/krb5_err.et @@ -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 diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index d9bda00a6..889a8f314 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,52 @@ +2006-03-06 Ken Raeburn + + * 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 * gmt_mktime.c, read_pwd.c: changes to support 64-bit builds diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in index 49690e41f..b58d40c1f 100644 --- a/src/lib/krb5/os/Makefile.in +++ b/src/lib/krb5/os/Makefile.in @@ -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): \ diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index f16a6e3e6..0a2f8e8db 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -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 diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c index 1d4e1d3ad..5f900b621 100644 --- a/src/lib/krb5/os/changepw.c +++ b/src/lib/krb5/os/changepw.c @@ -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;inaddrs;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))) diff --git a/src/lib/krb5/os/init_os_ctx.c b/src/lib/krb5/os/init_os_ctx.c index f4f9b690a..e91a05ff1 100644 --- a/src/lib/krb5/os/init_os_ctx.c +++ b/src/lib/krb5/os/init_os_ctx.c @@ -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 */ diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c index 50c889dd8..e751ca24d 100644 --- a/src/lib/krb5/os/locate_kdc.c +++ b/src/lib/krb5/os/locate_kdc.c @@ -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); } diff --git a/src/lib/krb5/os/send524.c b/src/lib/krb5/os/send524.c index 004d80348..09c9c9022 100644 --- a/src/lib/krb5/os/send524.c +++ b/src/lib/krb5/os/send524.c @@ -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) diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index e35c337d3..23e99d51c 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -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; diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c index 7d5d554fa..165366f5b 100644 --- a/src/lib/krb5/os/t_locate_kdc.c +++ b/src/lib/krb5/os/t_locate_kdc.c @@ -5,6 +5,8 @@ #include #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); } } diff --git a/src/lib/krb5/os/t_std_conf.c b/src/lib/krb5/os/t_std_conf.c index adaf6893d..04b75d7b8 100644 --- a/src/lib/krb5/os/t_std_conf.c +++ b/src/lib/krb5/os/t_std_conf.c @@ -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: { diff --git a/src/plugins/kdb/db2/ChangeLog b/src/plugins/kdb/db2/ChangeLog index c6461f9ad..df039d063 100644 --- a/src/plugins/kdb/db2/ChangeLog +++ b/src/plugins/kdb/db2/ChangeLog @@ -1,3 +1,9 @@ +2006-03-06 Ken Raeburn + + * Makefile.in (MODULE_INSTALL_DIR): New variable. + (DYNOBJ_LOADER_PROG, DYNOBJ_EXPLIBS_WITH_LOADER, + DYNOBJ_EXPDEPS_WITH_LOADER): Deleted. + 2006-01-25 Ken Raeburn * Makefile.in (DEFINES): New variable; define macro PLUGIN. diff --git a/src/plugins/kdb/db2/Makefile.in b/src/plugins/kdb/db2/Makefile.in index 06b037ce0..c40624f84 100644 --- a/src/plugins/kdb/db2/Makefile.in +++ b/src/plugins/kdb/db2/Makefile.in @@ -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 index 000000000..6824a2945 --- /dev/null +++ b/src/plugins/locate/python/ChangeLog @@ -0,0 +1,5 @@ +2006-03-06 Ken Raeburn + + * 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 index 000000000..46a83fede --- /dev/null +++ b/src/plugins/locate/python/Makefile.in @@ -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 index 000000000..34f8306b5 --- /dev/null +++ b/src/plugins/locate/python/configure.in @@ -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 index 000000000..53153be77 --- /dev/null +++ b/src/plugins/locate/python/locate-service.py @@ -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 index 000000000..a315e3555 --- /dev/null +++ b/src/plugins/locate/python/py-locate.c @@ -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 +#elif HAVE_PYTHON2_3_PYTHON_H +#include +#else +#error "Where's the Python header file?" +#endif +#include +#include +#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 index 000000000..60ff46e8d --- /dev/null +++ b/src/plugins/locate/python/python.exports @@ -0,0 +1 @@ +service_locator diff --git a/src/util/profile/ChangeLog b/src/util/profile/ChangeLog index cbb95706e..ea269e8e2 100644 --- a/src/util/profile/ChangeLog +++ b/src/util/profile/ChangeLog @@ -1,3 +1,7 @@ +2006-03-06 Ken Raeburn + + * Makefile.in (profile_tcl): Include $(LIBS). + 2005-10-21 Ken Raeburn * prof_file.c (profile_update_file_data): Drop test of diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in index 067007d84..a2d4814c8 100644 --- a/src/util/profile/Makefile.in +++ b/src/util/profile/Makefile.in @@ -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 \ diff --git a/src/util/support/ChangeLog b/src/util/support/ChangeLog index 7c3c3648e..4ec482f24 100644 --- a/src/util/support/ChangeLog +++ b/src/util/support/ChangeLog @@ -1,3 +1,11 @@ +2006-03-06 Ken Raeburn + + * 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 * Makefile.in: support for 64-bit Windows builds diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index 5abd3a27e..da71cad88 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -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) diff --git a/src/util/support/libkrb5support.exports b/src/util/support/libkrb5support.exports index d06911d53..1d7bc717f 100644 --- a/src/util/support/libkrb5support.exports +++ b/src/util/support/libkrb5support.exports @@ -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 index 000000000..bc93aa2b4 --- /dev/null +++ b/src/util/support/plugins.c @@ -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 + +#include +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 +#define NAMELEN(D) strlen((D)->d_name) +#else +#define dirent direct +#define NAMELEN(D) ((D)->d->namlen) +#if HAVE_SYS_NDIR_H +# include +#elif HAVE_SYS_DIR_H +# include +#elif HAVE_NDIR_H +# include +#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; +}