+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.
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 \
# 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.
$(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:
(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)
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)
])
+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
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
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
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 \
# "-h $@", "-h lib$(LIBNAME).$(LIBMAJOR)", etc.
SONAME=@SONAME@
+
#
# rules to make various types of object files
#
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*)
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
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
+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
/* 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;
};
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__ */
/* #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;
#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 */
/* 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 */
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 *);
--- /dev/null
+#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
+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.
-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)+'
+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
/* 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"
+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.
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
+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
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
+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
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
+DEFINES=-DLIBDIR=\"$(KRB5_LIBDIR)\"
+
##DOS##BUILDTOP = ..\..\..
##DOS##PREFIXDIR=os
##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
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
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)
$(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 \
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): \
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
{
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);
}
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 */
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)))
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
ctx->profile = 0;
}
+ krb5int_close_plugin_dir (&ctx->libkrb5_plugins);
+
#ifdef _WIN32
WSACleanup();
#endif /* _WIN32 */
/*
* 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
#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;
}
{
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;
#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);
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,
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),
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;
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;
}
}
#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);
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);
}
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. */
*/
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)
#endif
#define dprint krb5int_debug_fprint
-static void
+ void
krb5int_debug_fprint (const char *fmt, ...)
{
#ifdef DEBUG
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':
#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);
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'.
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;
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) {
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);
}
}
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;
/* 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;
#include <com_err.h>
#define TEST
+#include "dnsglue.c"
+#include "dnssrv.c"
#include "locate_kdc.c"
enum {
{
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);
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);
}
}
}
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:
{
+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.
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
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
--- /dev/null
+2006-03-06 Ken Raeburn <raeburn@mit.edu>
+
+ * Makefile.in, configure.in, py-locate.c, python.exports,
+ locate-service.py: New files.
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+service_locator
+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
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 \
+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
PROG_RPATH=$(KRB5_LIBDIR)
LIBBASE=krb5support
-LIBMAJOR=0
+LIBMAJOR=1
LIBMINOR=0
LIBINITFUNC=krb5int_thread_support_init
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
$(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)
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
--- /dev/null
+/*
+ * 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;
+}