/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <syslog.h>
#include <synch.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <resolv.h>
#include <netdb.h>
#include <assert.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlsvc.h>
#include <lsalib.h>
#include <mlsvc.h>
/*
* DC Locator
*/
typedef struct smb_dclocator {
static void *smb_ddiscover_service(void *);
static void smb_ddiscover_enum_trusted(char *, char *, smb_domainex_t *);
static void smb_domainex_free(smb_domainex_t *);
static void smb_set_krb5_realm(char *);
/*
* ===================================================================
* API to initialize DC locator thread, trigger DC discovery, and
* ===================================================================
*/
/*
* Initialization of the DC locator thread.
* Returns 0 on success, an error number if thread creation fails.
*/
int
smb_dclocator_init(void)
{
int rc;
(void) pthread_attr_init(&tattr);
(void) pthread_attr_destroy(&tattr);
return (rc);
}
/*
* This is the entry point for discovering a domain controller for the
* specified domain. Called during join domain, and then periodically
* by smbd_dc_update (the "DC monitor" thread).
*
* The actual work of discovering a DC is handled by DC locator thread.
* All we do here is signal the request and wait for a DC or a timeout.
*
* Input parameters:
* domain - domain to be discovered (can either be NetBIOS or DNS domain)
*
* Output parameter:
* dp - on success, dp will be filled with the discovered DC and domain
* information.
*
*/
{
int rc;
return (B_FALSE);
}
sizeof (smb_dclocator.sdl_domain));
}
if (!smb_dclocator.sdl_locate) {
}
while (smb_dclocator.sdl_locate) {
goto out;
}
}
if (smb_dclocator.sdl_status != 0) {
goto out;
}
dp = &domain_info;
out:
return (rv);
}
/*
* Tell the domain discovery service to run again now,
* and assume changed configuration (i.e. a new DC).
* Like the first part of smb_locate_dc().
*
* Note: This is called from the service refresh handler
* and the door handler to tell the ddiscover thread to
* request the new DC from idmap. Therefore, we must not
* trigger a new idmap discovery run from here, or that
* would start a ping-pong match.
*/
/* ARGSUSED */
void
{
}
if (!smb_dclocator.sdl_locate) {
}
}
/*
* Called by our client-side threads after they fail to connect to
* the DC given to them by smb_locate_dc(). This is often called
* after some delay, because the connection timeout delays these
* threads for a while, so it's quite common that the DC locator
* service has already started looking for a new DC. These late
* notifications should not continually restart the DC locator.
*/
void
{
/*
* The "bad" DC is no longer the current one.
* Probably a late "bad DC" report.
*/
goto out;
}
if (smb_dclocator.sdl_bad_dc) {
/* Someone already marked the current DC as "bad". */
goto out;
}
/*
* Mark the current DC as "bad" and let the DC Locator
* run again if it's not already.
*/
/* In-line smb_ddiscover_kick */
if (!smb_dclocator.sdl_locate) {
}
out:
}
/*
* If domain discovery is running, wait for it to finish.
*/
int
smb_ddiscover_wait(void)
{
int rc = 0;
if (smb_dclocator.sdl_locate) {
}
return (rc);
}
/*
* ==========================================================
* DC discovery functions
* ==========================================================
*/
/*
* This is the domain and DC discovery service: it gets woken up whenever
* there is need to locate a domain controller.
*
* Upon success, the SMB domain cache will be populated with the discovered
* DC and domain info.
*/
/*ARGSUSED*/
static void *
{
for (;;) {
/*
* Wait to be signaled for work by one of:
* smb_locate_dc(), smb_ddiscover_refresh(),
* smb_ddiscover_bad_dc()
*/
while (!sdl->sdl_locate)
if (!smb_config_getbool(SMB_CI_DOMAIN_MEMB)) {
"not a domain member");
goto wait_again;
}
/*
* Want to know if these change below.
* Note: mutex held here
*/
if (bad_dc) {
/*
* Need to clear the current DC name or
* ddiscover_bad_dc will keep setting bad_dc
*/
}
/*
* Clear the cached DC now so that we'll ask idmap again.
* If our current DC gave us errors, force rediscovery.
*/
/*
* Search for the DC, save the result.
*/
if (status == 0)
if (status == 0)
/*
* Run again if either of cfg_chg or bad_dc
* was turned on during smb_ddiscover_main().
* Note: mutex held here.
*/
if (sdl->sdl_bad_dc) {
"restart because bad_dc was set");
goto find_again;
}
if (sdl->sdl_cfg_chg) {
"restart because cfg_chg was set");
goto find_again;
}
}
/*NOTREACHED*/
return (NULL);
}
/*
* Discovers a domain controller for the specified domain via DNS.
* After the domain controller is discovered successfully primary and
* trusted domain infromation will be queried using RPC queries.
*
* Caller should zero out *dxi before calling, and after a
* successful return should call: smb_domain_save()
*/
{
if (domain[0] == '\0') {
return (NT_STATUS_INTERNAL_ERROR);
}
if (smb_domain_start_update() != SMB_DOMAIN_SUCCESS) {
return (NT_STATUS_INTERNAL_ERROR);
}
if (status != 0) {
goto out;
}
if (status != 0) {
"smb_ddiscover_main can't get domain info (%s)",
goto out;
}
out:
/* Don't need the trusted domain list anymore. */
return (status);
}
/*
* Obtain primary and trusted domain information using LSA queries.
*
* domain - either NetBIOS or fully-qualified domain name
*/
static uint32_t
{
/* If we must return failure, use this first one. */
if (ret == NT_STATUS_SUCCESS)
goto success;
if (tmp == NT_STATUS_SUCCESS)
goto success;
if (tmp == NT_STATUS_SUCCESS)
goto success;
/* All of the above failed. */
return (ret);
return (NT_STATUS_SUCCESS);
}
/*
* Obtain trusted domains information using LSA queries.
*
* domain - either NetBIOS or fully-qualified domain name.
*/
static void
{
if (status != NT_STATUS_SUCCESS)
}
/*
* If the domain to be discovered matches the current domain (i.e the
* value of either domain or fqdn configuration), then get the primary
* domain information from SMF.
*/
static uint32_t
{
if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
return (NT_STATUS_UNSUCCESSFUL);
if (SMB_IS_FQDN(domain))
else
if (use)
}
static void
{
}
static void
{
(void) unsetenv("KRB5_DEFAULT_REALM");
return;
}
/* In case krb5.conf is not configured, set the default realm. */
(void) smb_strupr(realm);
}