1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-18 17:57:55 +03:00
samba-mirror/source/nsswitch/winbind_krb5_locator.c
Jeremy Allison 4a56b697b6 Move to protocol independent code in most of lib/util_sock.c
We don't use gethostbyname any more except in one case where
we're looking for host aliases (I don't know how to do that
with getaddrinfo yet). New function should be getaddrinfo().
Next step will be fixing lib/access.c, and then changing
libsmb/namequery.c to cope with IPv6 address returns.
Jeremy.
2007-10-15 16:11:48 -07:00

394 lines
8.2 KiB
C

/*
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "nsswitch/winbind_client.h"
#ifndef DEBUG_KRB5
#undef DEBUG_KRB5
#endif
#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
#include <krb5/locate_plugin.h>
#ifndef KRB5_PLUGIN_NO_HANDLE
#define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
#endif
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;
}
#ifdef DEBUG_KRB5
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";
}
#endif
/**
* 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:
return KRB5_PLUGIN_NO_HANDLE;
default:
return EINVAL;
}
switch (family) {
case AF_UNSPEC:
case AF_INET:
break;
case AF_INET6: /* not yet */
return KRB5_PLUGIN_NO_HANDLE;
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 = NULL;
int ret;
int count = 3;
while (count) {
ret = getaddrinfo(name, service, in, &out);
if (ret == 0) {
break;
}
if (ret == EAI_AGAIN) {
count--;
continue;
}
#ifdef DEBUG_KRB5
fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
"getaddrinfo failed: %s (%d)\n",
(unsigned int)getpid(), gai_strerror(ret), ret);
#endif
return KRB5_PLUGIN_NO_HANDLE;
}
ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
#ifdef DEBUG_KRB5
if (ret) {
fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
"failed to call callback: %s (%d)\n",
(unsigned int)getpid(), error_message(ret), ret);
}
#endif
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)
{
return 0;
}
/**
* PUBLIC INTERFACE: close locate
*
* @param private_data pointer to private data
*
* @return void.
*/
void smb_krb5_locator_close(void *private_data)
{
return;
}
static bool ask_winbind(const char *realm, char **dcname)
{
NSS_STATUS status;
struct winbindd_request request;
struct winbindd_response response;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.flags = 0x40020600;
/* DS_KDC_REQUIRED |
DS_IS_DNS_NAME |
DS_RETURN_DNS_NAME |
DS_IP_REQUIRED */
strncpy(request.domain_name, realm,
sizeof(request.domain_name)-1);
status = winbindd_request_response(WINBINDD_DSGETDCNAME,
&request, &response);
if (status != NSS_STATUS_SUCCESS) {
#ifdef DEBUG_KRB5
fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: failed with: %s\n",
(unsigned int)getpid(), nss_err_str(status));
#endif
return false;
}
*dcname = strdup(response.data.dc_name);
if (!*dcname) {
return false;
}
return true;
}
/**
* 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)
{
krb5_error_code ret;
struct addrinfo aihints;
char *kdc_name = NULL;
const char *service = get_service_from_locate_service_type(svc);
ZERO_STRUCT(aihints);
#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
ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype,
family);
if (ret) {
#ifdef DEBUG_KRB5
fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
"returning ret: %s (%d)\n",
(unsigned int)getpid(), error_message(ret), ret);
#endif
return ret;
}
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
goto failed;
}
} else {
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;
}
}
#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;
ret = smb_krb5_locator_call_cbfunc(kdc_name,
service,
&aihints,
cbfunc, cbdata);
SAFE_FREE(kdc_name);
return ret;
failed:
return KRB5_PLUGIN_NO_HANDLE;
}
#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