1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

r21822: Adding experimental krb5 lib locator plugin.

This is a starting point and may get changed. Basically we need follow the
exact same path to detect (K)DCs like other Samba tools/winbind do. In
particular with regard to the server affinity cache and the site-awarness for
DNS SRV lookups.

To compile just call "make bin/smb_krb5_locator.so", copy to
/usr/lib/plugin/krb5/ (Heimdal HEAD) or /usr/lib/krb5/plugins/libkrb5/ (MIT)
and you should immediately be able to kinit to your AD domain without having
your REALM with kdc or kpasswd directives defined in /etc/krb5.conf at all.

Tested with todays Heimdal HEAD and MIT krb5 1.5.

Guenther
This commit is contained in:
Günther Deschner 2007-03-13 16:04:17 +00:00 committed by Gerald (Jerry) Carter
parent 4efc7b4598
commit 34ae610bd5
3 changed files with 399 additions and 0 deletions

View File

@ -844,6 +844,10 @@ LDBADD_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbadd.o
LDBDEL_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbdel.o
LDBMODIFY_OBJ = $(LDB_CMDLINE_OBJ) lib/ldb/tools/ldbmodify.o
SMB_KRB5_LOCATOR_OBJ1 = libads/smb_krb5_locator.o
SMB_KRB5_LOCATOR_OBJ = $(SMB_KRB5_LOCATOR_OBJ1) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
$(LIBNMB_OBJ) $(RPC_PARSE_OBJ1) $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(DOSERR_OBJ)
POPT_OBJ=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
@ -1370,6 +1374,12 @@ bin/winbindd@EXEEXT@: proto_exists $(WINBINDD_OBJ) @BUILD_POPT@ bin/.dummy
$(LDAP_LIBS) $(KRB5LIBS) $(LIBS) \
@SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@
@SMB_KRB5_LOCATOR@: $(SMB_KRB5_LOCATOR_OBJ)
@echo "Linking $@"
@$(SHLD) $(LDSHFLAGS) -o $@ $(SMB_KRB5_LOCATOR_OBJ) \
$(LDAP_LIBS) $(LIBS) -lcom_err \
@SONAMEFLAG@`basename $@`
bin/pam_winbind.@SHLIBEXT@: $(PAM_WINBIND_OBJ) bin/.dummy
@echo "Linking shared library $@"
@$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_WINBIND_OBJ) -lpam @INIPARSERLIBS@ $(GPLIBS) \

View File

@ -3446,6 +3446,7 @@ if test x"$with_ads_support" != x"no"; then
CPPFLAGS=$ac_save_CPPFLAGS
LDFLAGS=$ac_save_LDFLAGS
fi
AC_CHECK_HEADERS(krb5/locate_plugin.h)
fi
# Now we have determined whether we really want ADS support
@ -5624,6 +5625,8 @@ WINBIND_WINS_NSS="nsswitch/libnss_wins.$SHLIBEXT"
WINBIND_NSS_LDSHFLAGS=$LDSHFLAGS
NSSSONAMEVERSIONSUFFIX=""
SMB_KRB5_LOCATOR="bin/smb_krb5_locator.$SHLIBEXT"
case "$host_os" in
*linux*)
NSSSONAMEVERSIONSUFFIX=".2"
@ -5693,6 +5696,8 @@ AC_SUBST(WINBIND_NSS_EXTRA_OBJS)
AC_SUBST(WINBIND_NSS_EXTRA_LIBS)
AC_SUBST(NSSSONAMEVERSIONSUFFIX)
AC_SUBST(SMB_KRB5_LOCATOR)
# Check the setting of --with-winbind
AC_ARG_WITH(winbind,

View File

@ -0,0 +1,384 @@
/*
Unix SMB/CIFS implementation.
kerberos locator plugin
Copyright (C) Guenther Deschner 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
#include <krb5/locate_plugin.h>
static const char *get_service_from_locate_service_type(enum locate_service_type svc)
{
switch (svc) {
case locate_service_kdc:
case locate_service_master_kdc:
return "88";
case locate_service_kadmin:
case locate_service_krb524:
/* not supported */
return NULL;
case locate_service_kpasswd:
return "464";
default:
break;
}
return NULL;
}
static const char *locate_service_type_name(enum locate_service_type svc)
{
switch (svc) {
case locate_service_kdc:
return "locate_service_kdc";
case locate_service_master_kdc:
return "locate_service_master_kdc";
case locate_service_kadmin:
return "locate_service_kadmin";
case locate_service_krb524:
return "locate_service_krb524";
case locate_service_kpasswd:
return "locate_service_kpasswd";
default:
break;
}
return NULL;
}
static const char *socktype_name(int socktype)
{
switch (socktype) {
case SOCK_STREAM:
return "SOCK_STREAM";
case SOCK_DGRAM:
return "SOCK_DGRAM";
default:
break;
}
return "unknown";
}
static const char *family_name(int family)
{
switch (family) {
case AF_UNSPEC:
return "AF_UNSPEC";
case AF_INET:
return "AF_INET";
case AF_INET6:
return "AF_INET6";
default:
break;
}
return "unknown";
}
/**
* Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
*
* @param svc
* @param realm string
* @param socktype integer
* @param family integer
*
* @return integer.
*/
static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
const char *realm,
int socktype,
int family)
{
if (!realm || strlen(realm) == 0) {
return EINVAL;
}
switch (svc) {
case locate_service_kdc:
case locate_service_master_kdc:
case locate_service_kpasswd:
break;
case locate_service_kadmin:
case locate_service_krb524:
#ifdef KRB5_PLUGIN_NO_HANDLE
return KRB5_PLUGIN_NO_HANDLE;
#else
return KRB5_KDC_UNREACH; /* Heimdal */
#endif
default:
return EINVAL;
}
switch (family) {
case AF_UNSPEC:
case AF_INET:
break;
case AF_INET6: /* not yet */
#ifdef KRB5_PLUGIN_NO_HANDLE
return KRB5_PLUGIN_NO_HANDLE;
#else
return KRB5_KDC_UNREACH; /* Heimdal */
#endif
default:
return EINVAL;
}
switch (socktype) {
case SOCK_STREAM:
case SOCK_DGRAM:
case 0: /* Heimdal uses that */
break;
default:
return EINVAL;
}
return 0;
}
/**
* Try to get addrinfo for a given host and call the krb5 callback
*
* @param name string
* @param service string
* @param in struct addrinfo hint
* @param cbfunc krb5 callback function
* @param cbdata void pointer cbdata
*
* @return krb5_error_code.
*/
static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
const char *service,
struct addrinfo *in,
int (*cbfunc)(void *, int, struct sockaddr *),
void *cbdata)
{
struct addrinfo *out;
int ret;
int count = 3;
while (count) {
ret = getaddrinfo(name, service, in, &out);
if (ret == 0) {
break;
}
if (ret == EAI_AGAIN) {
count--;
continue;
}
DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n",
gai_strerror(ret), ret));
#ifdef KRB5_PLUGIN_NO_HANDLE
return KRB5_PLUGIN_NO_HANDLE;
#else
return KRB5_KDC_UNREACH; /* Heimdal */
#endif
}
ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
if (ret) {
DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n",
error_message(ret), ret));
}
freeaddrinfo(out);
return ret;
}
/**
* PUBLIC INTERFACE: locate init
*
* @param context krb5_context
* @param privata_data pointer to private data pointer
*
* @return krb5_error_code.
*/
krb5_error_code smb_krb5_locator_init(krb5_context context,
void **private_data)
{
setup_logging("smb_krb5_locator", True);
load_case_tables();
lp_load(dyn_CONFIGFILE,True,False,False,True);
DEBUG(10,("smb_krb5_locator_init: called\n"));
return 0;
}
/**
* PUBLIC INTERFACE: close locate
*
* @param private_data pointer to private data
*
* @return void.
*/
void smb_krb5_locator_close(void *private_data)
{
DEBUG(10,("smb_krb5_locator_close: called\n"));
gfree_all();
}
/**
* PUBLIC INTERFACE: locate lookup
*
* @param private_data pointer to private data
* @param svc enum locate_service_type.
* @param realm string
* @param socktype integer
* @param family integer
* @param cbfunc callback function to send back entries
* @param cbdata void pointer to cbdata
*
* @return krb5_error_code.
*/
krb5_error_code smb_krb5_locator_lookup(void *private_data,
enum locate_service_type svc,
const char *realm,
int socktype,
int family,
int (*cbfunc)(void *, int, struct sockaddr *),
void *cbdata)
{
NTSTATUS status;
krb5_error_code ret;
char *sitename = NULL;
struct ip_service *ip_list;
int count = 0;
struct addrinfo aihints;
char *saf_name = NULL;
int i;
DEBUG(10,("smb_krb5_locator_lookup: called for\n"));
DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n",
locate_service_type_name(svc), svc, realm));
DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n",
socktype_name(socktype), socktype,
family_name(family), family));
ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family);
if (ret) {
DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n",
error_message(ret), ret));
return ret;
}
/* first try to fetch from SAF cache */
saf_name = saf_fetch(realm);
if (!saf_name || strlen(saf_name) == 0) {
DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n",
realm));
goto find_kdc;
}
DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n",
saf_name, realm));
ZERO_STRUCT(aihints);
aihints.ai_family = family;
aihints.ai_socktype = socktype;
ret = smb_krb5_locator_call_cbfunc(saf_name,
get_service_from_locate_service_type(svc),
&aihints,
cbfunc, cbdata);
if (ret) {
return ret;
}
return 0;
find_kdc:
/* now try to find via site-aware DNS SRV query */
sitename = sitename_fetch(realm);
status = get_kdc_list(realm, sitename, &ip_list, &count);
/* if we didn't found any KDCs on our site go to the main list */
if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) {
ip_list = NULL;
SAFE_FREE(sitename);
status = get_kdc_list(realm, NULL, &ip_list, &count);
}
SAFE_FREE(sitename);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n",
nt_errstr(status),
error_message(nt_status_to_krb5(status))));
#ifdef KRB5_PLUGIN_NO_HANDLE
return KRB5_PLUGIN_NO_HANDLE;
#else
return KRB5_KDC_UNREACH; /* Heimdal */
#endif
}
for (i=0; i<count; i++) {
const char *host = NULL;
const char *port = NULL;
ZERO_STRUCT(aihints);
aihints.ai_family = family;
aihints.ai_socktype = socktype;
host = inet_ntoa(ip_list[i].ip);
port = get_service_from_locate_service_type(svc);
ret = smb_krb5_locator_call_cbfunc(host,
port,
&aihints,
cbfunc, cbdata);
if (ret) {
/* got error */
break;
}
}
return ret;
}
#ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
#define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
#else
#define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
#endif
const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
0, /* version */
smb_krb5_locator_init,
smb_krb5_locator_close,
smb_krb5_locator_lookup,
};
#endif