diff options
Diffstat (limited to 'src/lib/krb5')
-rw-r--r-- | src/lib/krb5/error_tables/ChangeLog | 4 | ||||
-rw-r--r-- | src/lib/krb5/error_tables/krb5_err.et | 2 | ||||
-rw-r--r-- | src/lib/krb5/os/ChangeLog | 49 | ||||
-rw-r--r-- | src/lib/krb5/os/Makefile.in | 21 | ||||
-rw-r--r-- | src/lib/krb5/os/accessor.c | 1 | ||||
-rw-r--r-- | src/lib/krb5/os/changepw.c | 19 | ||||
-rw-r--r-- | src/lib/krb5/os/init_os_ctx.c | 5 | ||||
-rw-r--r-- | src/lib/krb5/os/locate_kdc.c | 397 | ||||
-rw-r--r-- | src/lib/krb5/os/send524.c | 12 | ||||
-rw-r--r-- | src/lib/krb5/os/sendto_kdc.c | 99 | ||||
-rw-r--r-- | src/lib/krb5/os/t_locate_kdc.c | 8 | ||||
-rw-r--r-- | src/lib/krb5/os/t_std_conf.c | 2 |
12 files changed, 442 insertions, 177 deletions
diff --git a/src/lib/krb5/error_tables/ChangeLog b/src/lib/krb5/error_tables/ChangeLog index bb59895bfc..e84f292d35 100644 --- a/src/lib/krb5/error_tables/ChangeLog +++ b/src/lib/krb5/error_tables/ChangeLog @@ -1,3 +1,7 @@ +2006-03-06 Ken Raeburn <raeburn@mit.edu> + + * krb5_err.et (KRB5_PLUGIN_NO_HANDLE): New error code. + 2006-01-27 Sam Hartman <hartmans@mit.edu> * kdb5_err.et: New error codes for plugin errors diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 1f2bfca53c..865c838a62 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 d9bda00a64..889a8f314b 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,52 @@ +2006-03-06 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (DEFINES): New variable. + (t_locate_kdc.o): Depend on dnssrv.c and dnsglue.c too. + + * init_os_ctx.c (krb5_os_init_context): Initialize new fields. + (krb5_os_free_context): Close opened plugin files. + + * locate_kdc.c: Include k5-plugin.h. + (get_port): Deleted. + (grow_addrlist): Update for new fields in structure. + (krb5int_free_addrlist): Call the free function in the structure, + if the function pointer is non-null. + (add_addrinfo_to_list): Update for new fields. Shorten up debug + output. + (call_freeaddrinfo): New function. + (krb5int_add_host_to_list): Update for new fields. + (prof_locate_server, dns_locate_server): New functions, broken out + from krb5int_locate_server; use the new enum type for service + choice. + (objdir): New variable. + (struct module_callback_data): New struct. + (module_callback, module_locate_server): New functions. + (krb5int_locate_server): Use the above method-specific locator + functions. Change argument list to take enum and not multiple + strings and numbers. + (krb5_locate_kdc): Updated for new interface. + + * send524.c (krb5int_524_sendto_kdc): Update for new locate_server + interface. + * changepw.c (krb5_locate_kpasswd): Likewise. + (krb5_change_set_password): Update for new fields. + + * accessor.c (krb5int_accessor): Don't fill in locate_server + field. + + * t_locate_kdc.c: Include dnsglue.c and dnssrv.c. + (print_addrs): Update for new fields. + * t_std_conf.c (test_locate_kdc): Update for new fields. + + * sendto_kdc.c (krb5int_debug_fprint): No longer static. Print + more info. + (krb5int_print_addrlist): New function. + (merge_addrlists): Update for new fields. + (in_addrlist): New function. + (krb5_sendto_kdc): Use it. Update for new fields. + (krb5int_sendto): Update for new fields. Print more info when + debugging. + 2006-02-24 Jeffrey Altman <jaltman@mit.edu> * gmt_mktime.c, read_pwd.c: changes to support 64-bit builds diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in index 49690e41fb..b58d40c1f9 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 f16a6e3e60..0a2f8e8db4 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 1d4e1d3ada..5f900b6216 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;i<addrlist->naddrs;i++ ) { - struct addrinfo *a = addrlist->addrs[i]; + struct addrinfo *a = addrlist->addrs[i].ai; if (a->ai_family == AF_INET) sa2sin (a->ai_addr)->sin_port = htons(DEFAULT_KPASSWD_PORT); } @@ -157,11 +155,11 @@ krb5_change_set_password( struct timeval timeout; /* XXX Now the locate_ functions can return IPv6 addresses. */ - if (al.addrs[i]->ai_family != AF_INET) + if (al.addrs[i].ai->ai_family != AF_INET) continue; tried_one = 1; - if (connect(s2, al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen) == SOCKET_ERROR) { + if (connect(s2, al.addrs[i].ai->ai_addr, al.addrs[i].ai->ai_addrlen) == SOCKET_ERROR) { if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH) continue; /* try the next addr */ @@ -243,7 +241,8 @@ krb5_change_set_password( if ((cc = sendto(s1, chpw_req.data, (GETSOCKNAME_ARG3_TYPE) chpw_req.length, 0, - al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen)) != chpw_req.length) + al.addrs[i].ai->ai_addr, al.addrs[i].ai->ai_addrlen)) + != chpw_req.length) { if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))) diff --git a/src/lib/krb5/os/init_os_ctx.c b/src/lib/krb5/os/init_os_ctx.c index f4f9b690a0..e91a05ff1c 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 50c889dd8f..e751ca24d0 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 004d803486..09c9c90228 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 e35c337d36..23e99d51c9 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 7d5d554fab..165366f5be 100644 --- a/src/lib/krb5/os/t_locate_kdc.c +++ b/src/lib/krb5/os/t_locate_kdc.c @@ -5,6 +5,8 @@ #include <com_err.h> #define TEST +#include "dnsglue.c" +#include "dnssrv.c" #include "locate_kdc.c" enum { @@ -43,14 +45,14 @@ void print_addrs (void) { int i; - struct addrinfo **addrs = al.addrs; int naddrs = al.naddrs; printf ("%d addresses:\n", naddrs); for (i = 0; i < naddrs; i++) { int err; + struct addrinfo *ai = al.addrs[i].ai; char hostbuf[NI_MAXHOST], srvbuf[NI_MAXSERV]; - err = getnameinfo (addrs[i]->ai_addr, addrs[i]->ai_addrlen, + err = getnameinfo (ai->ai_addr, ai->ai_addrlen, hostbuf, sizeof (hostbuf), srvbuf, sizeof (srvbuf), NI_NUMERICHOST | NI_NUMERICSERV); @@ -59,7 +61,7 @@ void print_addrs (void) i, err, gai_strerror (err)); else printf ("%2d: address %s\t%s\tport %s\n", i, hostbuf, - stypename (addrs[i]->ai_socktype), srvbuf); + stypename (ai->ai_socktype), srvbuf); } } diff --git a/src/lib/krb5/os/t_std_conf.c b/src/lib/krb5/os/t_std_conf.c index adaf6893db..04b75d7b80 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: { |