2007-08-24 15:50:12 +00:00
/*
2007-03-13 16:04:17 +00:00
Unix SMB / CIFS implementation .
kerberos locator plugin
2008-09-27 03:11:59 +02:00
Copyright ( C ) Guenther Deschner 2007 - 2008
2007-08-24 15:50:12 +00:00
2007-03-13 16:04:17 +00:00
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
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2007-03-13 16:04:17 +00:00
( at your option ) any later version .
2007-08-24 15:50:12 +00:00
2007-03-13 16:04:17 +00:00
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 .
2007-08-24 15:50:12 +00:00
2007-03-13 16:04:17 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-03-13 16:04:17 +00:00
*/
2007-08-28 15:26:59 +00:00
# include "nsswitch/winbind_client.h"
2008-10-07 18:54:08 +02:00
# include "libwbclient/wbclient.h"
2007-08-28 15:26:59 +00:00
# ifndef DEBUG_KRB5
# undef DEBUG_KRB5
# endif
2007-03-13 16:04:17 +00:00
# if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
2018-11-20 14:06:48 +01:00
# ifdef HAVE_COM_ERR_H
2009-11-26 10:15:45 +01:00
# include <com_err.h>
# endif
# include <krb5.h>
2007-03-13 16:04:17 +00:00
# include <krb5/locate_plugin.h>
2007-08-29 10:12:43 +00:00
# ifndef KRB5_PLUGIN_NO_HANDLE
# define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
# endif
2007-03-13 16:04:17 +00:00
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 ;
}
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
2007-03-13 16:04:17 +00:00
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 " ;
2008-02-05 13:44:22 -08:00
# if defined(HAVE_IPV6)
2007-03-13 16:04:17 +00:00
case AF_INET6 :
return " AF_INET6 " ;
2007-10-24 14:16:54 -07:00
# endif
2007-03-13 16:04:17 +00:00
default :
break ;
}
return " unknown " ;
}
2007-08-28 15:26:59 +00:00
# endif
2007-03-13 16:04:17 +00:00
/**
* Check input parameters , return KRB5_PLUGIN_NO_HANDLE for unsupported ones
*
2007-08-24 15:50:12 +00:00
* @ param svc
2007-03-13 16:04:17 +00:00
* @ 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 :
return KRB5_PLUGIN_NO_HANDLE ;
default :
return EINVAL ;
}
switch ( family ) {
case AF_UNSPEC :
case AF_INET :
2008-02-05 13:44:22 -08:00
# if defined(HAVE_IPV6)
case AF_INET6 :
2007-10-24 14:16:54 -07:00
# endif
2014-02-13 13:19:26 +00:00
break ;
2007-03-13 16:04:17 +00:00
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 .
*/
2007-08-24 15:50:12 +00:00
static krb5_error_code smb_krb5_locator_call_cbfunc ( const char * name ,
2007-03-13 16:04:17 +00:00
const char * service ,
struct addrinfo * in ,
int ( * cbfunc ) ( void * , int , struct sockaddr * ) ,
void * cbdata )
{
2007-10-15 16:11:48 -07:00
struct addrinfo * out = NULL ;
2012-04-25 11:28:37 -07:00
int ret = 0 ;
struct addrinfo * res = NULL ;
2007-03-13 16:04:17 +00:00
int count = 3 ;
while ( count ) {
ret = getaddrinfo ( name , service , in , & out ) ;
if ( ret = = 0 ) {
break ;
}
2011-02-10 15:55:50 +01:00
if ( ( ret = = EAI_AGAIN ) & & ( count > 1 ) ) {
2007-03-13 16:04:17 +00:00
count - - ;
continue ;
}
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" getaddrinfo failed: %s (%d) \n " ,
( unsigned int ) getpid ( ) , gai_strerror ( ret ) , ret ) ;
# endif
2007-03-13 16:04:17 +00:00
return KRB5_PLUGIN_NO_HANDLE ;
}
2012-04-25 11:28:37 -07:00
for ( res = out ; res ; res = res - > ai_next ) {
if ( ! res - > ai_addr | | res - > ai_addrlen = = 0 ) {
continue ;
}
ret = cbfunc ( cbdata , res - > ai_socktype , res - > ai_addr ) ;
if ( ret ) {
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
2012-04-25 11:28:37 -07:00
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" failed to call callback: %s (%d) \n " ,
( unsigned int ) getpid ( ) , error_message ( ret ) , ret ) ;
2007-08-28 15:26:59 +00:00
# endif
2012-04-25 11:28:37 -07:00
break ;
}
}
2007-03-13 16:04:17 +00:00
2012-04-25 11:28:37 -07:00
if ( out ) {
freeaddrinfo ( out ) ;
}
2007-03-13 16:04:17 +00:00
return ret ;
}
/**
* PUBLIC INTERFACE : locate init
*
* @ param context krb5_context
* @ param privata_data pointer to private data pointer
*
* @ return krb5_error_code .
*/
2008-07-30 17:47:40 +02:00
static krb5_error_code smb_krb5_locator_init ( krb5_context context ,
void * * private_data )
2007-03-13 16:04:17 +00:00
{
return 0 ;
}
/**
* PUBLIC INTERFACE : close locate
*
* @ param private_data pointer to private data
*
* @ return void .
*/
2008-07-30 17:47:40 +02:00
static void smb_krb5_locator_close ( void * private_data )
2007-03-13 16:04:17 +00:00
{
2007-08-28 15:26:59 +00:00
return ;
}
2007-03-13 16:04:17 +00:00
2007-09-13 14:14:02 +00:00
static bool ask_winbind ( const char * realm , char * * dcname )
2007-08-28 15:26:59 +00:00
{
2008-10-07 18:54:08 +02:00
wbcErr wbc_status ;
2008-09-27 03:11:59 +02:00
const char * dc = NULL ;
2008-10-07 18:54:08 +02:00
struct wbcDomainControllerInfoEx * dc_info = NULL ;
uint32_t flags ;
2007-08-28 15:26:59 +00:00
2008-10-07 18:54:08 +02:00
flags = WBC_LOOKUP_DC_KDC_REQUIRED |
WBC_LOOKUP_DC_IS_DNS_NAME |
2012-04-25 11:28:37 -07:00
WBC_LOOKUP_DC_RETURN_DNS_NAME ;
2007-08-28 15:26:59 +00:00
2008-10-07 18:54:08 +02:00
wbc_status = wbcLookupDomainControllerEx ( realm , NULL , NULL , flags , & dc_info ) ;
2007-08-28 15:26:59 +00:00
2008-10-07 18:54:08 +02:00
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: failed with: %s \n " ,
2008-10-07 18:54:08 +02:00
( unsigned int ) getpid ( ) , wbcErrorString ( wbc_status ) ) ;
2007-08-28 15:26:59 +00:00
# endif
2007-09-13 14:14:02 +00:00
return false ;
2007-08-28 15:26:59 +00:00
}
2008-10-07 18:54:08 +02:00
if ( ! dc & & dc_info - > dc_unc ) {
dc = dc_info - > dc_unc ;
2008-09-27 03:11:59 +02:00
if ( dc [ 0 ] = = ' \\ ' ) dc + + ;
if ( dc [ 0 ] = = ' \\ ' ) dc + + ;
}
if ( ! dc ) {
2008-10-07 18:54:08 +02:00
wbcFreeMemory ( dc_info ) ;
2008-09-27 03:11:59 +02:00
return false ;
}
* dcname = strdup ( dc ) ;
2007-08-28 15:26:59 +00:00
if ( ! * dcname ) {
2008-10-07 18:54:08 +02:00
wbcFreeMemory ( dc_info ) ;
2007-09-13 14:14:02 +00:00
return false ;
2007-08-28 15:26:59 +00:00
}
2008-10-07 18:54:08 +02:00
wbcFreeMemory ( dc_info ) ;
2007-09-13 14:14:02 +00:00
return true ;
2007-03-13 16:04:17 +00:00
}
/**
* 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 .
*/
2008-07-30 17:47:40 +02:00
static 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 )
2007-03-13 16:04:17 +00:00
{
krb5_error_code ret ;
struct addrinfo aihints ;
2007-08-28 15:26:59 +00:00
char * kdc_name = NULL ;
2007-08-24 15:50:12 +00:00
const char * service = get_service_from_locate_service_type ( svc ) ;
2007-03-13 16:04:17 +00:00
2007-08-28 15:26:59 +00:00
ZERO_STRUCT ( aihints ) ;
2007-03-13 16:04:17 +00:00
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: called for '%s' "
" svc: '%s' (%d) "
" socktype: '%s' (%d), family: '%s' (%d) \n " ,
( unsigned int ) getpid ( ) , realm ,
locate_service_type_name ( svc ) , svc ,
socktype_name ( socktype ) , socktype ,
family_name ( family ) , family ) ;
# endif
2007-08-24 15:50:12 +00:00
ret = smb_krb5_locator_lookup_sanity_check ( svc , realm , socktype ,
family ) ;
2007-03-13 16:04:17 +00:00
if ( ret ) {
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" returning ret: %s (%d) \n " ,
( unsigned int ) getpid ( ) , error_message ( ret ) , ret ) ;
# endif
2007-03-13 16:04:17 +00:00
return ret ;
}
2007-08-28 15:26:59 +00:00
if ( ! winbind_env_set ( ) ) {
if ( ! ask_winbind ( realm , & kdc_name ) ) {
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" failed to query winbindd \n " ,
( unsigned int ) getpid ( ) ) ;
# endif
2007-08-28 16:39:03 +00:00
goto failed ;
2007-03-13 16:04:17 +00:00
}
2007-08-28 15:26:59 +00:00
} else {
2007-08-31 12:18:21 +00:00
const char * env = NULL ;
char * var = NULL ;
if ( asprintf ( & var , " %s_%s " ,
WINBINDD_LOCATOR_KDC_ADDRESS , realm ) = = - 1 ) {
goto failed ;
}
env = getenv ( var ) ;
if ( ! env ) {
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" failed to get kdc from env %s \n " ,
( unsigned int ) getpid ( ) , var ) ;
# endif
free ( var ) ;
goto failed ;
}
free ( var ) ;
kdc_name = strdup ( env ) ;
if ( ! kdc_name ) {
goto failed ;
}
2007-03-13 16:04:17 +00:00
}
2007-08-28 15:26:59 +00:00
# ifdef DEBUG_KRB5
fprintf ( stderr , " [%5u]: smb_krb5_locator_lookup: "
" got '%s' for '%s' from winbindd \n " , ( unsigned int ) getpid ( ) ,
kdc_name , realm ) ;
# endif
aihints . ai_family = family ;
aihints . ai_socktype = socktype ;
2007-03-13 16:04:17 +00:00
2007-08-28 15:26:59 +00:00
ret = smb_krb5_locator_call_cbfunc ( kdc_name ,
service ,
& aihints ,
cbfunc , cbdata ) ;
SAFE_FREE ( kdc_name ) ;
2007-03-16 15:48:07 +00:00
2007-03-13 16:04:17 +00:00
return ret ;
2007-08-28 16:39:03 +00:00
failed :
return KRB5_PLUGIN_NO_HANDLE ;
2007-03-13 16:04:17 +00:00
}
# 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 = {
2019-11-11 13:08:28 -07:00
. minor_version = 0 ,
. init = smb_krb5_locator_init ,
. fini = smb_krb5_locator_close ,
2019-11-11 13:37:25 -07:00
# ifdef KRB5_PLUGIN_LOCATE_VERSION_2
. old_lookup = smb_krb5_locator_lookup ,
# else
2019-11-11 13:08:28 -07:00
. lookup = smb_krb5_locator_lookup ,
2019-11-11 13:37:25 -07:00
# endif
2007-03-13 16:04:17 +00:00
} ;
# endif