/*
Unix SMB/CIFS implementation.
Winbind ADS backend functions
Copyright (C) Andrew Tridgell 2001
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
Copyright (C) Gerald (Jerry) Carter 2004
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 "includes.h"
#include "winbindd.h"
#include "winbindd_ads.h"
#include "libsmb/namequery.h"
#include "rpc_client/rpc_client.h"
#include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "../libds/common/flags.h"
#include "ads.h"
#include "../libcli/ldap/ldap_ndr.h"
#include "../libcli/security/security.h"
#include "../libds/common/flag_mapping.h"
#include "libsmb/samlogon_cache.h"
#include "passdb.h"
#include "auth/credentials/credentials.h"
#ifdef HAVE_ADS
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
extern struct winbindd_methods reconnect_methods;
extern struct winbindd_methods msrpc_methods;
/**
* Check if cached connection can be reused. If the connection cannot
* be reused the ADS_STRUCT is freed and the pointer is set to NULL.
*/
static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
{
ADS_STRUCT *ads = *adsp;
if (ads != NULL) {
time_t expire;
time_t now = time(NULL);
expire = nt_time_to_unix(ads->auth.expire_time);
DBG_INFO("Current tickets expire in %" PRIu64 " seconds "
"(at %" PRIu64 ", time is now %" PRIu64 ")\n",
(uint64_t)expire - (uint64_t)now,
(uint64_t)expire,
(uint64_t)now);
if ( ads->config.realm && (expire > now)) {
return;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
DEBUG(7,("Deleting expired ads struct\n"));
TALLOC_FREE(ads);
*adsp = NULL;
}
}
}
static NTSTATUS ads_cached_connection_reconnect_creds(struct ads_struct *ads,
void *private_data,
TALLOC_CTX *mem_ctx,
struct cli_credentials **creds)
{
struct winbindd_domain *target_domain = NULL;
if (ads->server.realm != NULL) {
target_domain = find_domain_from_name_noinit(ads->server.realm);
}
if (target_domain == NULL && ads->server.workgroup != NULL) {
target_domain = find_domain_from_name_noinit(ads->server.workgroup);
}
if (target_domain == NULL) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
return winbindd_get_trust_credentials(target_domain,
mem_ctx,
false, /* netlogon */
false, /* ipc_fallback */
creds);
}
/**
* @brief Establish a connection to a DC
*
* @param[out] adsp ADS_STRUCT that will be created
* @param[in] target_domain target domain
* @param[in] ldap_server DNS name of server to connect to
* @param[in] creds credentials to use
* @param[in] auth_realm Realm of local domain for creating krb token
*
* @return ADS_STATUS
*/
static ADS_STATUS ads_cached_connection_connect(struct winbindd_domain *target_domain,
const char *ldap_server,
TALLOC_CTX *mem_ctx,
ADS_STRUCT **adsp)
{
TALLOC_CTX *tmp_ctx = talloc_stackframe();
const char *target_realm = target_domain->alt_name;
const char *target_dom_name = target_domain->name;
struct cli_credentials *creds = NULL;
ADS_STRUCT *ads;
ADS_STATUS status;
NTSTATUS ntstatus;
struct sockaddr_storage dc_ss;
fstring dc_name;
/* the machine acct password might have change - fetch it every time */
ntstatus = winbindd_get_trust_credentials(target_domain,
tmp_ctx,
false, /* netlogon */
false, /* ipc_fallback */
&creds);
if (!NT_STATUS_IS_OK(ntstatus)) {
status = ADS_ERROR_NT(ntstatus);
goto out;
}
ads = ads_init(tmp_ctx,
target_realm,
target_dom_name,
ldap_server,
ADS_SASL_SEAL);
if (!ads) {
DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
status = ADS_ERROR(LDAP_NO_MEMORY);
goto out;
}
ads_set_reconnect_fn(ads, ads_cached_connection_reconnect_creds, NULL);
/* Setup the server affinity cache. We don't reaally care
about the name. Just setup affinity and the KRB5_CONFIG
file. */
get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
status = ads_connect_creds(ads, creds);
if (!ADS_ERR_OK(status)) {
DEBUG(1,("ads_connect for domain %s failed: %s\n",
target_dom_name, ads_errstr(status)));
goto out;
}
*adsp = talloc_move(mem_ctx, &ads);
out:
TALLOC_FREE(tmp_ctx);
return status;
}
ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
TALLOC_CTX *mem_ctx,
ADS_STRUCT **adsp)
{
TALLOC_CTX *tmp_ctx = talloc_stackframe();
char *ldap_server = NULL;
struct winbindd_domain *wb_dom = NULL;
ADS_STATUS status;
if (IS_AD_DC) {
/*
* Make sure we n
|