Blame library/adconn.c

Packit Service 6d40f9
/*
Packit Service 6d40f9
 * adcli
Packit Service 6d40f9
 *
Packit Service 6d40f9
 * Copyright (C) 2012 Red Hat Inc.
Packit Service 6d40f9
 *
Packit Service 6d40f9
 * This program is free software; you can redistribute it and/or modify
Packit Service 6d40f9
 * it under the terms of the GNU Lesser General Public License as
Packit Service 6d40f9
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 6d40f9
 * the License, or (at your option) any later version.
Packit Service 6d40f9
 *
Packit Service 6d40f9
 * This program is distributed in the hope that it will be useful, but
Packit Service 6d40f9
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6d40f9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6d40f9
 * Lesser General Public License for more details.
Packit Service 6d40f9
 *
Packit Service 6d40f9
 * You should have received a copy of the GNU Lesser General Public
Packit Service 6d40f9
 * License along with this program; if not, write to the Free Software
Packit Service 6d40f9
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
Packit Service 6d40f9
 * MA 02110-1301 USA
Packit Service 6d40f9
 *
Packit Service 6d40f9
 * Author: Stef Walter <stefw@gnome.org>
Packit Service 6d40f9
 */
Packit Service 6d40f9
Packit Service 6d40f9
#include "config.h"
Packit Service 6d40f9
Packit Service 6d40f9
#include "adcli.h"
Packit Service 6d40f9
#include "adprivate.h"
Packit Service 6d40f9
#include "addisco.h"
Packit Service 6d40f9
Packit Service 6d40f9
#include <gssapi/gssapi_krb5.h>
Packit Service 6d40f9
#include <krb5/krb5.h>
Packit Service 6d40f9
#include <ldap.h>
Packit Service 6d40f9
#include <sasl/sasl.h>
Packit Service 6d40f9
Packit Service 6d40f9
#include <sys/types.h>
Packit Service 6d40f9
#include <sys/socket.h>
Packit Service 6d40f9
#include <sys/stat.h>
Packit Service 6d40f9
Packit Service 6d40f9
#include <assert.h>
Packit Service 6d40f9
#include <errno.h>
Packit Service 6d40f9
#include <netdb.h>
Packit Service 6d40f9
#include <stdio.h>
Packit Service 6d40f9
#include <stdlib.h>
Packit Service 6d40f9
#include <string.h>
Packit Service 6d40f9
#include <unistd.h>
Packit Service 6d40f9
Packit Service 6d40f9
struct _adcli_conn_ctx {
Packit Service 6d40f9
	int refs;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Input/output params */
Packit Service 6d40f9
	char *user_name;
Packit Service 6d40f9
	char *user_password;
Packit Service 6d40f9
	char *computer_name;
Packit Service 6d40f9
	char *computer_password;
Packit Service 6d40f9
	char *login_ccache_name;
Packit Service 6d40f9
	int login_ccache_name_is_krb5;
Packit Service 6d40f9
	char *login_keytab_name;
Packit Service 6d40f9
	int login_keytab_name_is_krb5;
Packit Service 6d40f9
	adcli_login_type login_type;
Packit Service 6d40f9
	int logins_allowed;
Packit Service 6d40f9
Packit Service 6d40f9
	char *krb5_conf_dir;
Packit Service 6d40f9
	char *krb5_conf_snippet;
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_password_func password_func;
Packit Service 6d40f9
	adcli_destroy_func password_destroy;
Packit Service 6d40f9
	void *password_data;
Packit Service 6d40f9
Packit Service 6d40f9
	char *host_fqdn;
Packit Service 6d40f9
	char *domain_name;
Packit Service 6d40f9
	char *domain_realm;
Packit Service 6d40f9
	char *domain_controller;
Packit Service aa0613
	bool use_ldaps;
Packit Service 6d40f9
	char *canonical_host;
Packit Service 6d40f9
	char *domain_short;
Packit Service db24d4
	char *domain_sid;
Packit Service 6d40f9
	adcli_disco *domain_disco;
Packit Service 6d40f9
	char *default_naming_context;
Packit Service 6d40f9
	char *configuration_naming_context;
Packit Service 6d40f9
	char **supported_capabilities;
Packit Service 811121
	char **supported_sasl_mechs;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Connect state */
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	int ldap_authenticated;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_ccache ccache;
Packit Service 6d40f9
	krb5_keytab keytab;
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service c68da5
static char *try_to_get_fqdn (const char *host_name)
Packit Service c68da5
{
Packit Service c68da5
	int ret;
Packit Service c68da5
	char *fqdn = NULL;
Packit Service c68da5
	struct addrinfo *res;
Packit Service c68da5
	struct addrinfo hints;
Packit Service c68da5
Packit Service c68da5
	memset (&hints, 0, sizeof (struct addrinfo));
Packit Service c68da5
	hints.ai_socktype = SOCK_DGRAM;
Packit Service c68da5
	hints.ai_flags = AI_CANONNAME;
Packit Service c68da5
Packit Service c68da5
	ret = getaddrinfo (host_name, NULL, &hints, &res;;
Packit Service c68da5
	if (ret != 0) {
Packit Service c68da5
		_adcli_err ("Failed to find FQDN: %s", gai_strerror (ret));
Packit Service c68da5
		return NULL;
Packit Service c68da5
	}
Packit Service c68da5
Packit Service c68da5
	fqdn = strdup (res->ai_canonname);
Packit Service c68da5
Packit Service c68da5
	freeaddrinfo (res);
Packit Service c68da5
Packit Service c68da5
	return fqdn;
Packit Service c68da5
}
Packit Service c68da5
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_host_fqdn (adcli_result res,
Packit Service 6d40f9
                  adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char hostname[HOST_NAME_MAX + 1];
Packit Service c68da5
	char *fqdn = NULL;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->host_fqdn) {
Packit Service 6d40f9
		_adcli_info ("Using fully qualified name: %s", conn->host_fqdn);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	ret = gethostname (hostname, sizeof (hostname));
Packit Service 6d40f9
	if (ret < 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't get local hostname: %s", strerror (errno));
Packit Service 6d40f9
		return ADCLI_ERR_UNEXPECTED;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service c68da5
	if (strchr (hostname, '.') == NULL) {
Packit Service c68da5
		fqdn = try_to_get_fqdn (hostname);
Packit Service c68da5
	}
Packit Service c68da5
	conn->host_fqdn = fqdn != NULL ? fqdn : strdup (hostname);
Packit Service 6d40f9
	return_unexpected_if_fail (conn->host_fqdn != NULL);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
disco_dance_if_necessary (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (conn->domain_disco)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->domain_controller)
Packit Service 6d40f9
		adcli_disco_host (conn->domain_controller, &conn->domain_disco);
Packit Service 6d40f9
Packit Service 6d40f9
	else if (conn->domain_name)
Packit Service 6d40f9
		adcli_disco_domain (conn->domain_name, &conn->domain_disco);
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->domain_disco) {
Packit Service 6d40f9
		if (!conn->domain_short && conn->domain_disco->domain_short) {
Packit Service 6d40f9
			conn->domain_short = strdup (conn->domain_disco->domain_short);
Packit Service 6d40f9
			return_if_fail (conn->domain_short != NULL);
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
no_more_disco (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (conn->domain_disco)
Packit Service 6d40f9
		adcli_disco_free (conn->domain_disco);
Packit Service 6d40f9
	conn->domain_disco = NULL;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_domain_and_host (adcli_result res,
Packit Service 6d40f9
                        adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	const char *dom;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->domain_name) {
Packit Service 6d40f9
		_adcli_info ("Using domain name: %s", conn->domain_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn->host_fqdn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	disco_dance_if_necessary (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->domain_disco && conn->domain_disco->domain) {
Packit Service 6d40f9
		conn->domain_name = strdup (conn->domain_disco->domain);
Packit Service 6d40f9
		return_unexpected_if_fail (conn->domain_name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		_adcli_info ("Discovered domain name: %s", conn->domain_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the FQDN minus the last part */
Packit Service 6d40f9
	dom = strchr (conn->host_fqdn, '.');
Packit Service 6d40f9
Packit Service 6d40f9
	/* If no dot, or dot is first or last, then fail */
Packit Service 6d40f9
	if (dom == NULL || dom == conn->host_fqdn || dom[1] == '\0') {
Packit Service 6d40f9
		_adcli_err ("Couldn't determine the domain name from host name: %s",
Packit Service 6d40f9
		            conn->host_fqdn);
Packit Service 6d40f9
		return ADCLI_ERR_FAIL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->domain_name = strdup (dom + 1);
Packit Service 6d40f9
	return_unexpected_if_fail (conn->domain_name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Calculated domain name from host fqdn: %s",
Packit Service 6d40f9
	             conn->domain_name);
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
char *
Packit Service 6d40f9
_adcli_calc_netbios_name (const char *host_fqdn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	const char *dom;
Packit Service 6d40f9
	char *computer_name;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the FQDN minus the last part */
Packit Service 6d40f9
	dom = strchr (host_fqdn, '.');
Packit Service 6d40f9
Packit Service 6d40f9
	/* If dot is first then fail */
Packit Service 6d40f9
	if (dom == host_fqdn) {
Packit Service 6d40f9
		_adcli_err ("Couldn't determine the computer account name from host name: %s",
Packit Service 6d40f9
		            host_fqdn);
Packit Service 6d40f9
		return NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (dom == NULL) {
Packit Service 6d40f9
		computer_name = strdup (host_fqdn);
Packit Service 6d40f9
		return_val_if_fail (computer_name != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		computer_name = strndup (host_fqdn, dom - host_fqdn);
Packit Service 6d40f9
		return_val_if_fail (computer_name != NULL, NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_str_up (computer_name);
Packit Service 6d40f9
	if (strlen (computer_name) > 15) {
Packit Service 6d40f9
		computer_name[15] = 0;
Packit Service 6d40f9
		_adcli_info ("Truncated computer account name from fqdn: %s", computer_name);
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_info ("Calculated computer account name from fqdn: %s", computer_name);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return computer_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_computer_name (adcli_result res,
Packit Service 6d40f9
                      adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->computer_name) {
Packit Service 6d40f9
		_adcli_info ("Using computer account name: %s", conn->computer_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn->host_fqdn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	conn->computer_name = _adcli_calc_netbios_name (conn->host_fqdn);
Packit Service 6d40f9
	if (conn->computer_name == NULL)
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_domain_realm (adcli_result res,
Packit Service 6d40f9
                     adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->domain_realm) {
Packit Service 6d40f9
		_adcli_info ("Using domain realm: %s", conn->domain_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->domain_realm = strdup (conn->domain_name);
Packit Service 6d40f9
	return_unexpected_if_fail (conn->domain_realm != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_str_up (conn->domain_realm);
Packit Service 6d40f9
	_adcli_info ("Calculated domain realm from name: %s",
Packit Service 6d40f9
	             conn->domain_realm);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_user_password (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (conn->login_ccache_name != NULL ||
Packit Service 6d40f9
	    conn->user_password != NULL)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->password_func) {
Packit Service 6d40f9
		conn->user_password = (conn->password_func) (ADCLI_LOGIN_USER_ACCOUNT,
Packit Service 6d40f9
		                                             conn->user_name, 0,
Packit Service 6d40f9
		                                             conn->password_data);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->user_password == NULL) {
Packit Service 6d40f9
		_adcli_err ("No admin password or credential cache specified");
Packit Service 6d40f9
		return ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
char *
Packit Service 6d40f9
_adcli_calc_reset_password (const char *computer_name)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *password;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (computer_name != NULL);
Packit Service 6d40f9
	password = strdup (computer_name);
Packit Service 6d40f9
	return_val_if_fail (password != NULL, NULL);
Packit Service 6d40f9
	_adcli_str_down (password);
Packit Service 6d40f9
Packit Service 6d40f9
	return password;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
handle_kinit_krb5_code (adcli_conn *conn,
Packit Service 6d40f9
                        adcli_login_type type,
Packit Service 6d40f9
                        const char *name,
Packit Service 6d40f9
                        krb5_error_code code)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (code == 0) {
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (code == ENOMEM) {
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (code == KRB5KDC_ERR_PREAUTH_FAILED ||
Packit Service 6d40f9
	           code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN ||
Packit Service 6d40f9
	           code == KRB5KDC_ERR_KEY_EXP ||
Packit Service 6d40f9
	           code == KRB5KDC_ERR_CLIENT_REVOKED ||
Packit Service 6d40f9
	           code == KRB5KDC_ERR_POLICY ||
Packit Service 6d40f9
	           code == KRB5KDC_ERR_ETYPE_NOSUPP ||
Packit Service 6d40f9
	           code == KRB5_PREAUTH_FAILED) {
Packit Service 6d40f9
		if (type == ADCLI_LOGIN_COMPUTER_ACCOUNT) {
Packit Service 6d40f9
			_adcli_err ("Couldn't authenticate as machine account: %s: %s",
Packit Service 6d40f9
			            name, krb5_get_error_message (conn->k5, code));
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			_adcli_err ("Couldn't authenticate as: %s: %s",
Packit Service 6d40f9
			            name, krb5_get_error_message (conn->k5, code));
Packit Service 6d40f9
		}
Packit Service 6d40f9
		return ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		if (type == ADCLI_LOGIN_COMPUTER_ACCOUNT) {
Packit Service 6d40f9
			_adcli_err ("Couldn't get kerberos ticket for machine account: %s: %s",
Packit Service 6d40f9
			            name, krb5_get_error_message (conn->k5, code));
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			_adcli_err ("Couldn't get kerberos ticket for: %s: %s",
Packit Service 6d40f9
			            name, krb5_get_error_message (conn->k5, code));
Packit Service 6d40f9
		}
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
clear_krb5_conf_snippet (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (conn->krb5_conf_snippet) {
Packit Service 6d40f9
		if (unlink (conn->krb5_conf_snippet) < 0) {
Packit Service 6d40f9
			_adcli_warn ("Couldn't remove krb5.conf snippet file: %s: %s",
Packit Service 6d40f9
			             conn->krb5_conf_snippet, strerror (errno));
Packit Service 6d40f9
		}
Packit Service 6d40f9
		free (conn->krb5_conf_snippet);
Packit Service 6d40f9
		conn->krb5_conf_snippet = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
setup_krb5_conf_snippet (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *filename;
Packit Service 6d40f9
	char *snippet;
Packit Service 6d40f9
	char *controller;
Packit Service 6d40f9
	int errn;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
	int fd;
Packit Service 6d40f9
	mode_t old_mask;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!conn->krb5_conf_dir)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Already written out the conf snippet */
Packit Service 6d40f9
	if (conn->krb5_conf_snippet)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	clear_krb5_conf_snippet (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&filename, "%s/adcli-krb5-conf-XXXXXX", conn->krb5_conf_dir) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	if (strchr (conn->domain_controller, ':')) {
Packit Service 6d40f9
		if (asprintf (&controller, "[%s]", conn->domain_controller) < 0)
Packit Service 6d40f9
			controller = NULL;
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		controller = strdup (conn->domain_controller);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (controller != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&snippet, "[realms]\n"
Packit Service 6d40f9
	                        "  %s = {\n"
Packit Service 6d40f9
	                        "    kdc = %s:88\n"
Packit Service 6d40f9
	                        "    master_kdc = %s:88\n"
Packit Service 6d40f9
	                        "    kpasswd_server = %s\n"
Packit Service 6d40f9
	                        "  }\n"
Packit Service 6d40f9
	                        "[domain_realm]\n"
Packit Service 6d40f9
	                        "  %s = %s\n"
Packit Service 6d40f9
	                        "  %s = %s\n",
Packit Service 6d40f9
	              conn->domain_realm, controller, controller, controller,
Packit Service 6d40f9
	              conn->canonical_host, conn->domain_realm,
Packit Service 6d40f9
	              conn->domain_controller, conn->domain_realm) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	old_mask = umask (0177);
Packit Service 6d40f9
	fd = mkstemp (filename);
Packit Service 6d40f9
	umask (old_mask);
Packit Service 6d40f9
	if (fd < 0) {
Packit Service 6d40f9
		_adcli_warn ("Couldn't create krb5.conf snippet file in: %s: %s",
Packit Service 6d40f9
		             conn->krb5_conf_dir, strerror (errno));
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		conn->krb5_conf_snippet = filename;
Packit Service 6d40f9
		ret = _adcli_write_all (fd, snippet, -1);
Packit Service 6d40f9
		errn = errno;
Packit Service 6d40f9
Packit Service 6d40f9
		if (ret >= 0) {
Packit Service 6d40f9
			ret = close (fd);
Packit Service 6d40f9
			errn = errno;
Packit Service 6d40f9
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			close (fd);
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		if (ret < 0) {
Packit Service 6d40f9
			_adcli_warn ("Couldn't write krb5.conf snippet file in: %s: %s",
Packit Service 6d40f9
			             filename, strerror (errn));
Packit Service 6d40f9
			clear_krb5_conf_snippet (conn);
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			_adcli_info ("Wrote out krb5.conf snippet to %s", filename);
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (controller);
Packit Service 6d40f9
	free (snippet);
Packit Service 6d40f9
Packit Service 6d40f9
	/* This shouldn't stop joining */
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
/*
Packit Service 6d40f9
 * HACK: This is to work around a bug in krb5 where if an empty password
Packit Service 6d40f9
 * preauth will fail unless a prompter is present.
Packit Service 6d40f9
 */
Packit Service 6d40f9
static krb5_error_code
Packit Service 6d40f9
null_prompter (krb5_context context,
Packit Service 6d40f9
               void *data,
Packit Service 6d40f9
               const char *name,
Packit Service 6d40f9
               const char *banner,
Packit Service 6d40f9
               int num_prompts,
Packit Service 6d40f9
               krb5_prompt prompts[])
Packit Service 6d40f9
{
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	for (i = 0; i < num_prompts; i++)
Packit Service 6d40f9
		prompts[i].reply->length = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	return 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_error_code
Packit Service 6d40f9
_adcli_kinit_computer_creds (adcli_conn *conn,
Packit Service 6d40f9
                             const char *in_tkt_service,
Packit Service 6d40f9
                             krb5_ccache ccache,
Packit Service 6d40f9
                             krb5_creds *creds)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_get_init_creds_opt *opt;
Packit Service 6d40f9
	krb5_principal principal;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_creds dummy;
Packit Service 6d40f9
	char *new_password;
Packit Service 6d40f9
	const char *password;
Packit Service 6d40f9
	char *sam;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&sam, "%s$", conn->computer_name) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached();
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_krb5_build_principal (k5, sam, conn->domain_realm, &principal);
Packit Service 6d40f9
	return_val_if_fail (code == 0, code);
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_get_init_creds_opt_alloc (k5, &opt;;
Packit Service 6d40f9
	return_val_if_fail (code == 0, code);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ccache) {
Packit Service 6d40f9
		code = krb5_get_init_creds_opt_set_out_ccache (k5, opt, ccache);
Packit Service 6d40f9
		return_val_if_fail (code == 0, code);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&dummy, 0, sizeof (dummy));
Packit Service 6d40f9
	if (!creds)
Packit Service 6d40f9
		creds = &dummy;
Packit Service 6d40f9
Packit Service 6d40f9
	password = conn->computer_password;
Packit Service 6d40f9
	new_password = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * Note that we only prompt for computer account passwords if
Packit Service 6d40f9
	 * explicitly requested.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->keytab) {
Packit Service 6d40f9
		code = krb5_get_init_creds_keytab (k5, creds, principal, conn->keytab,
Packit Service 6d40f9
		                                   0, (char *)in_tkt_service, opt);
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		if (!password && conn->password_func &&
Packit Service 6d40f9
		    conn->logins_allowed == ADCLI_LOGIN_COMPUTER_ACCOUNT) {
Packit Service 6d40f9
			new_password = (conn->password_func) (ADCLI_LOGIN_COMPUTER_ACCOUNT,
Packit Service 6d40f9
			                                      sam, 0, conn->password_data);
Packit Service 6d40f9
			password = new_password;
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		if (password == NULL) {
Packit Service 6d40f9
			new_password = _adcli_calc_reset_password (conn->computer_name);
Packit Service 6d40f9
			password = new_password;
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		code = krb5_get_init_creds_password (k5, creds, principal, (char *)password,
Packit Service 6d40f9
		                                     null_prompter, NULL, 0, (char *)in_tkt_service, opt);
Packit Service 6d40f9
Packit Service 6d40f9
		if (code == 0 && new_password) {
Packit Service 6d40f9
			_adcli_password_free (conn->computer_password);
Packit Service 6d40f9
			conn->computer_password = new_password;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_principal (k5, principal);
Packit Service 6d40f9
	krb5_get_init_creds_opt_free (k5, opt);
Packit Service 6d40f9
	krb5_free_cred_contents (k5, &dummy);
Packit Service 6d40f9
Packit Service 6d40f9
	free (sam);
Packit Service 6d40f9
	return code;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_error_code
Packit Service 6d40f9
_adcli_kinit_user_creds (adcli_conn *conn,
Packit Service 6d40f9
                         const char *in_tkt_service,
Packit Service 6d40f9
                         krb5_ccache ccache,
Packit Service 6d40f9
                         krb5_creds *creds)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_get_init_creds_opt *opt;
Packit Service 6d40f9
	krb5_principal principal;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_creds dummy;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_parse_name (k5, conn->user_name, &principal);
Packit Service 6d40f9
	return_val_if_fail (code == 0, code);
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_get_init_creds_opt_alloc (k5, &opt;;
Packit Service 6d40f9
	return_val_if_fail (code == 0, code);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ccache) {
Packit Service 6d40f9
		code = krb5_get_init_creds_opt_set_out_ccache (k5, opt, ccache);
Packit Service 6d40f9
		return_val_if_fail (code == 0, code);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&dummy, 0, sizeof (dummy));
Packit Service 6d40f9
	if (!creds)
Packit Service 6d40f9
		creds = &dummy;
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_get_init_creds_password (k5, creds, principal,
Packit Service 6d40f9
	                                     conn->user_password, null_prompter, NULL,
Packit Service 6d40f9
	                                     0, (char *)in_tkt_service, opt);
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_principal (k5, principal);
Packit Service 6d40f9
	krb5_get_init_creds_opt_free (k5, opt);
Packit Service 6d40f9
	krb5_free_cred_contents (k5, &dummy);
Packit Service 6d40f9
Packit Service 6d40f9
	return code;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
kinit_with_computer_credentials (adcli_conn *conn,
Packit Service 6d40f9
                                 krb5_ccache ccache)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	int use_default;
Packit Service 6d40f9
Packit Service 6d40f9
	use_default = (conn->computer_password == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_kinit_computer_creds (conn, NULL, ccache, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code == 0) {
Packit Service 6d40f9
		_adcli_info ("Authenticated as %scomputer account: %s",
Packit Service 6d40f9
		             use_default ? "default/reset " : "", conn->computer_name);
Packit Service 6d40f9
Packit Service 6d40f9
		conn->login_type = ADCLI_LOGIN_COMPUTER_ACCOUNT;
Packit Service 6d40f9
		res = ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		res = handle_kinit_krb5_code (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT,
Packit Service 6d40f9
		                              conn->computer_name, code);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
kinit_with_user_credentials (adcli_conn *conn,
Packit Service 6d40f9
                             krb5_ccache ccache)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Build out the admin principal name */
Packit Service 6d40f9
	if (!conn->user_name) {
Packit Service 6d40f9
		if (asprintf (&conn->user_name, "Administrator@%s", conn->domain_realm) < 0)
Packit Service 6d40f9
			return_unexpected_if_reached ();
Packit Service 6d40f9
	} else if (strchr (conn->user_name, '@') == NULL) {
Packit Service 6d40f9
		if (asprintf (&name, "%s@%s", conn->user_name, conn->domain_realm) < 0)
Packit Service 6d40f9
			return_unexpected_if_reached ();
Packit Service 6d40f9
		free (conn->user_name);
Packit Service 6d40f9
		conn->user_name = name;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	res = ensure_user_password (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_kinit_user_creds (conn, NULL, ccache, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code == 0) {
Packit Service 6d40f9
		conn->login_type = ADCLI_LOGIN_USER_ACCOUNT;
Packit Service 6d40f9
		_adcli_info ("Authenticated as user: %s", conn->user_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return handle_kinit_krb5_code (conn, ADCLI_LOGIN_USER_ACCOUNT, conn->user_name, code);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
prep_kerberos_and_kinit (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	int logged_in = 0;
Packit Service 6d40f9
	krb5_ccache ccache;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->login_ccache_name != NULL) {
Packit Service 6d40f9
		if (!conn->ccache) {
Packit Service 6d40f9
Packit Service 6d40f9
			/*
Packit Service 6d40f9
			 * If we already have a kerberos ccache file, just open it. This
Packit Service 6d40f9
			 * serves two purposes:
Packit Service 6d40f9
			 * a) We want to make sure it's present, so we can provide more
Packit Service 6d40f9
			 *    intelligible messages than ldap_sasl_interactive_bind_s()
Packit Service 6d40f9
			 * b) We want to have the ccache member populated so we can use
Packit Service 6d40f9
			 *    it in other operations such as changing the computer password.
Packit Service 6d40f9
			 */
Packit Service 6d40f9
Packit Service 6d40f9
			if (strcmp (conn->login_ccache_name, "") == 0) {
Packit Service 6d40f9
				code = krb5_cc_default (conn->k5, &conn->ccache);
Packit Service 6d40f9
				if (code == 0) {
Packit Service 6d40f9
					free (conn->login_ccache_name);
Packit Service 6d40f9
					conn->login_ccache_name = NULL;
Packit Service 6d40f9
					code = krb5_cc_get_full_name (conn->k5, conn->ccache,
Packit Service 6d40f9
					                              &conn->login_ccache_name);
Packit Service 6d40f9
					conn->login_ccache_name_is_krb5 = 1;
Packit Service 6d40f9
					return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
				}
Packit Service 6d40f9
			} else {
Packit Service 6d40f9
				code = krb5_cc_resolve (conn->k5, conn->login_ccache_name, &conn->ccache);
Packit Service 6d40f9
			}
Packit Service 6d40f9
Packit Service 6d40f9
			if (code != 0) {
Packit Service 6d40f9
				_adcli_err ("Couldn't open kerberos credential cache: %s: %s",
Packit Service 6d40f9
				            conn->login_ccache_name, krb5_get_error_message (NULL, code));
Packit Service 6d40f9
				return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->login_keytab_name != NULL) {
Packit Service 6d40f9
		if (!conn->keytab) {
Packit Service 6d40f9
			res = _adcli_krb5_open_keytab (conn->k5, conn->login_keytab_name, &conn->keytab);
Packit Service 6d40f9
			if (res != ADCLI_SUCCESS) {
Packit Service 6d40f9
				if (res == ADCLI_ERR_FAIL)
Packit Service 6d40f9
					res = ADCLI_ERR_CONFIG;
Packit Service 6d40f9
				return res;
Packit Service 6d40f9
			}
Packit Service 6d40f9
Packit Service 6d40f9
			if (strcmp (conn->login_keytab_name, "") == 0) {
Packit Service 6d40f9
				free (conn->login_keytab_name);
Packit Service 6d40f9
				conn->login_keytab_name = malloc (MAX_KEYTAB_NAME_LEN);
Packit Service 6d40f9
				code = krb5_kt_get_name (conn->k5, conn->keytab,
Packit Service 6d40f9
				                         conn->login_keytab_name, MAX_KEYTAB_NAME_LEN);
Packit Service 6d40f9
				conn->login_keytab_name_is_krb5 = 1;
Packit Service 6d40f9
				return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Initialize the credential cache */
Packit Service 6d40f9
	code = krb5_cc_new_unique (conn->k5, "MEMORY", NULL, &ccache);
Packit Service 6d40f9
	return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * Should we try to connect with computer account default password?
Packit Service 6d40f9
	 * This is the password set by 'Reset Accuont' on a computer object.
Packit Service 6d40f9
	 * If the caller explicitly specified a login name or password, then
Packit Service 6d40f9
	 * go straight to that.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->logins_allowed & ADCLI_LOGIN_COMPUTER_ACCOUNT) {
Packit Service 6d40f9
		res = kinit_with_computer_credentials (conn, ccache);
Packit Service 6d40f9
		logged_in = (res == ADCLI_SUCCESS);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use login credentials */
Packit Service 6d40f9
	if (!logged_in && (conn->logins_allowed & ADCLI_LOGIN_USER_ACCOUNT)) {
Packit Service 6d40f9
		res = kinit_with_user_credentials (conn, ccache);
Packit Service 6d40f9
		logged_in = (res == ADCLI_SUCCESS);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (logged_in) {
Packit Service 6d40f9
		code = krb5_cc_get_full_name (conn->k5, ccache,
Packit Service 6d40f9
		                              &conn->login_ccache_name);
Packit Service 6d40f9
		return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
		conn->ccache = ccache;
Packit Service 6d40f9
		conn->login_ccache_name_is_krb5 = 1;
Packit Service 6d40f9
		ccache = NULL;
Packit Service 6d40f9
		res = ADCLI_SUCCESS;
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		res = ADCLI_ERR_FAIL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (ccache != NULL)
Packit Service 6d40f9
		krb5_cc_close (conn->k5, ccache);
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
/* Not included in ldap.h but documented */
Packit Service 6d40f9
int ldap_init_fd (ber_socket_t fd, int proto, LDAP_CONST char *url, struct ldap **ldp);
Packit Service 6d40f9
Packit Service 6d40f9
static LDAP *
Packit Service 6d40f9
connect_to_address (const char *host,
Packit Service aa0613
                    const char *canonical_host,
Packit Service aa0613
                    bool use_ldaps)
Packit Service 6d40f9
{
Packit Service 6d40f9
	struct addrinfo *res = NULL;
Packit Service 6d40f9
	struct addrinfo *ai;
Packit Service 6d40f9
	struct addrinfo hints;
Packit Service 6d40f9
	LDAP *ldap = NULL;
Packit Service 6d40f9
	int error = 0;
Packit Service 6d40f9
	char *url;
Packit Service 6d40f9
	int sock;
Packit Service 6d40f9
	int rc;
Packit Service aa0613
	int opt_rc;
Packit Service aa0613
	const char *port = "389";
Packit Service aa0613
	const char *proto = "ldap";
Packit Service aa0613
	const char *errmsg = NULL;
Packit Service aa0613
Packit Service aa0613
	if (use_ldaps) {
Packit Service aa0613
		port = "636";
Packit Service aa0613
		proto = "ldaps";
Packit Service aa0613
		_adcli_info ("Using LDAPS to connect to %s", host);
Packit Service aa0613
	}
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&hints, '\0', sizeof(hints));
Packit Service 6d40f9
#ifdef AI_ADDRCONFIG
Packit Service 6d40f9
	hints.ai_flags |= AI_ADDRCONFIG;
Packit Service 6d40f9
#endif
Packit Service 6d40f9
	hints.ai_socktype = SOCK_STREAM;
Packit Service 6d40f9
	hints.ai_protocol = IPPROTO_TCP;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!canonical_host)
Packit Service 6d40f9
		canonical_host = host;
Packit Service 6d40f9
Packit Service aa0613
	rc = getaddrinfo (host, port, &hints, &res;;
Packit Service 6d40f9
	if (rc != 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't resolve host name: %s: %s", host, gai_strerror (rc));
Packit Service 6d40f9
		return NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	for (ai = res; ai != NULL; ai = ai->ai_next) {
Packit Service 6d40f9
		/* coverity[overwrite_var] */
Packit Service 6d40f9
		sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
Packit Service 6d40f9
		if (sock < 0) {
Packit Service 6d40f9
			error = errno;
Packit Service 6d40f9
		} else if (connect (sock, ai->ai_addr, ai->ai_addrlen) < 0) {
Packit Service 6d40f9
			error = errno;
Packit Service 6d40f9
			close (sock);
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			error = 0;
Packit Service aa0613
			if (asprintf (&url, "%s://%s", proto, canonical_host) < 0)
Packit Service 6d40f9
				return_val_if_reached (NULL);
Packit Service 6d40f9
			rc = ldap_init_fd (sock, 1, url, &ldap);
Packit Service 6d40f9
			free (url);
Packit Service 6d40f9
Packit Service 6d40f9
			if (rc != LDAP_SUCCESS) {
Packit Service 6d40f9
				_adcli_err ("Couldn't initialize LDAP connection: %s:",
Packit Service 6d40f9
				            ldap_err2string (rc));
Packit Service 6d40f9
				break;
Packit Service 6d40f9
			}
Packit Service aa0613
Packit Service aa0613
			if (use_ldaps) {
Packit Service aa0613
				rc = ldap_install_tls (ldap);
Packit Service aa0613
				if (rc != LDAP_SUCCESS) {
Packit Service aa0613
					opt_rc = ldap_get_option (ldap,
Packit Service aa0613
					                          LDAP_OPT_DIAGNOSTIC_MESSAGE,
Packit Service aa0613
					                          (void *) &errmsg);
Packit Service aa0613
					if (opt_rc != LDAP_SUCCESS) {
Packit Service aa0613
						errmsg = NULL;
Packit Service aa0613
					}
Packit Service aa0613
					_adcli_err ("Couldn't initialize TLS [%s]: %s",
Packit Service aa0613
					            ldap_err2string (rc),
Packit Service aa0613
					            errmsg == NULL ? "- no details -"
Packit Service aa0613
					                           : errmsg);
Packit Service aa0613
					ldap_unbind_ext_s (ldap, NULL, NULL);
Packit Service aa0613
					ldap = NULL;
Packit Service aa0613
					break;
Packit Service aa0613
				}
Packit Service aa0613
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!ldap && error)
Packit Service 6d40f9
		_adcli_err ("Couldn't connect to host: %s: %s", host, strerror (error));
Packit Service 6d40f9
Packit Service 6d40f9
	freeaddrinfo (res);
Packit Service 6d40f9
	/* coverity[leaked_handle] - the socket is carried inside the ldap struct */
Packit Service 6d40f9
	return ldap;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
connect_and_lookup_naming (adcli_conn *conn,
Packit Service 6d40f9
                           adcli_disco *disco)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *canonical_host;
Packit Service 6d40f9
	LDAPMessage *results;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
	int ver;
Packit Service 6d40f9
Packit Service 6d40f9
	char *attrs[] = {
Packit Service 6d40f9
		"defaultNamingContext",
Packit Service 6d40f9
		"configurationNamingContext",
Packit Service 6d40f9
		"supportedCapabilities",
Packit Service 811121
		"supportedSASLMechanisms",
Packit Service 6d40f9
		NULL
Packit Service 6d40f9
	};
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn->ldap == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	canonical_host = disco->host_name;
Packit Service 6d40f9
	if (!canonical_host)
Packit Service 6d40f9
		canonical_host = disco->host_addr;
Packit Service 6d40f9
Packit Service aa0613
	ldap = connect_to_address (disco->host_addr, canonical_host,
Packit Service aa0613
	                           adcli_conn_get_use_ldaps (conn));
Packit Service 6d40f9
	if (ldap == NULL)
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	ver = LDAP_VERSION3;
Packit Service 6d40f9
	if (ldap_set_option (ldap, LDAP_OPT_PROTOCOL_VERSION, &ver) != 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	if (ldap_set_option (ldap, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) != 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	/* Don't force GSSAPI to use reverse DNS */
Packit Service 6d40f9
	if (ldap_set_option (ldap, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON) != 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * We perform this lookup whether or not we want to lookup the
Packit Service 6d40f9
	 * naming context, as it also connects to the LDAP server.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, "", LDAP_SCOPE_BASE, "(objectClass=*)",
Packit Service 6d40f9
	                         attrs, 0, NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
	if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		res = _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                  "Couldn't connect to LDAP server: %s", disco->host_addr);
Packit Service 6d40f9
		ldap_unbind_ext_s (ldap, NULL, NULL);
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->default_naming_context == NULL) {
Packit Service 6d40f9
		conn->default_naming_context = _adcli_ldap_parse_value (ldap, results,
Packit Service 6d40f9
		                                                        "defaultNamingContext");
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->configuration_naming_context == NULL) {
Packit Service 6d40f9
		conn->configuration_naming_context = _adcli_ldap_parse_value (ldap, results,
Packit Service 6d40f9
		                                                              "configurationNamingContext");
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->supported_capabilities == NULL) {
Packit Service 6d40f9
		conn->supported_capabilities = _adcli_ldap_parse_values (ldap, results,
Packit Service 6d40f9
		                                                         "supportedCapabilities");
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 811121
	if (conn->supported_sasl_mechs == NULL) {
Packit Service 811121
		conn->supported_sasl_mechs = _adcli_ldap_parse_values (ldap, results,
Packit Service 811121
		                                                       "supportedSASLMechanisms");
Packit Service 811121
	}
Packit Service 811121
Packit Service 6d40f9
	ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->default_naming_context == NULL) {
Packit Service 6d40f9
		_adcli_err ("No valid LDAP naming context on domain controller: %s", disco->host_addr);
Packit Service 6d40f9
		ldap_unbind_ext_s (ldap, NULL, NULL);
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->configuration_naming_context == NULL) {
Packit Service 6d40f9
		if (asprintf (&conn->configuration_naming_context,
Packit Service 6d40f9
		              "CN=Configuration,%s", conn->default_naming_context))
Packit Service 6d40f9
			return_unexpected_if_reached ();
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->ldap = ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	free (conn->canonical_host);
Packit Service 6d40f9
	conn->canonical_host = strdup (canonical_host);
Packit Service 6d40f9
	return_unexpected_if_fail (conn->canonical_host != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_conn_set_domain_controller (conn, disco->host_addr);
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static int
Packit Service 6d40f9
sasl_interact (LDAP *ld,
Packit Service 6d40f9
               unsigned flags,
Packit Service 6d40f9
               void *defaults,
Packit Service 6d40f9
               void *interact)
Packit Service 6d40f9
{
Packit Service 6d40f9
	sasl_interact_t *in = (sasl_interact_t *)interact;
Packit Service 6d40f9
	return_val_if_fail (ld != NULL, LDAP_PARAM_ERROR);
Packit Service 6d40f9
Packit Service 6d40f9
	while (in->id != SASL_CB_LIST_END) {
Packit Service 6d40f9
		switch (in->id) {
Packit Service 6d40f9
		case SASL_CB_GETREALM:
Packit Service 6d40f9
		case SASL_CB_USER:
Packit Service 6d40f9
		case SASL_CB_PASS:
Packit Service 6d40f9
			if (in->defresult)
Packit Service 6d40f9
				in->result = in->defresult;
Packit Service 6d40f9
			else
Packit Service 6d40f9
				in->result = "";
Packit Service 6d40f9
			in->len = strlen (in->result);
Packit Service 6d40f9
			break;
Packit Service 6d40f9
		case SASL_CB_AUTHNAME:
Packit Service 6d40f9
			if (in->defresult)
Packit Service 6d40f9
				in->result = in->defresult;
Packit Service 6d40f9
			else
Packit Service 6d40f9
				in->result = "";
Packit Service 6d40f9
			in->len = strlen (in->result);
Packit Service 6d40f9
			break;
Packit Service 6d40f9
		case SASL_CB_NOECHOPROMPT:
Packit Service 6d40f9
		case SASL_CB_ECHOPROMPT:
Packit Service 6d40f9
			return LDAP_UNAVAILABLE;
Packit Service 6d40f9
		}
Packit Service 6d40f9
		in++;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return LDAP_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_disco *
Packit Service 6d40f9
desperate_for_disco (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_disco *disco;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!conn->domain_name || !conn->domain_controller)
Packit Service 6d40f9
		return NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	disco = calloc (1, sizeof (adcli_disco));
Packit Service 6d40f9
	return_val_if_fail (disco != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	disco->domain = strdup (conn->domain_name);
Packit Service 6d40f9
	return_val_if_fail (disco->domain != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	disco->host_addr = strdup (conn->domain_controller);
Packit Service 6d40f9
	return_val_if_fail (disco->host_addr, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	disco->host_name = strdup (conn->domain_controller);
Packit Service 6d40f9
	return_val_if_fail (disco->host_name, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	assert (adcli_disco_usable (disco) != ADCLI_DISCO_UNUSABLE);
Packit Service 6d40f9
	return disco;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
connect_to_directory (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_ERR_UNEXPECTED;
Packit Service 6d40f9
	adcli_disco *disco;
Packit Service 6d40f9
	int had_any = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->ldap)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	disco_dance_if_necessary (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	if (!conn->domain_disco)
Packit Service 6d40f9
		conn->domain_disco = desperate_for_disco (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	for (disco = conn->domain_disco; disco != NULL; disco = disco->next) {
Packit Service 6d40f9
		if (!adcli_disco_usable (disco))
Packit Service 6d40f9
			continue;
Packit Service 6d40f9
		res = connect_and_lookup_naming (conn, disco);
Packit Service 6d40f9
		if (res == ADCLI_SUCCESS || res == ADCLI_ERR_UNEXPECTED)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
		had_any = 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!had_any) {
Packit Service 6d40f9
		_adcli_err ("Couldn't find usable domain controller to connect to");
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
authenticate_to_directory (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	OM_uint32 status;
Packit Service 6d40f9
	OM_uint32 minor;
Packit Service 6d40f9
	ber_len_t ssf;
Packit Service 6d40f9
	int ret;
Packit Service 811121
	const char *mech = "GSSAPI";
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->ldap_authenticated)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (conn->ldap);
Packit Service 6d40f9
	assert (conn->login_ccache_name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Sets the credential cache GSSAPI to use (for this thread) */
Packit Service 6d40f9
	status = gss_krb5_ccache_name (&minor, conn->login_ccache_name, NULL);
Packit Service 6d40f9
	return_unexpected_if_fail (status == 0);
Packit Service 6d40f9
Packit Service aa0613
	if (adcli_conn_get_use_ldaps (conn)) {
Packit Service aa0613
		/* do not use SASL encryption on LDAPS connection */
Packit Service aa0613
		ssf = 0;
Packit Service aa0613
		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf;;
Packit Service aa0613
		return_unexpected_if_fail (ret == 0);
Packit Service aa0613
		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MAX, &ssf;;
Packit Service aa0613
		return_unexpected_if_fail (ret == 0);
Packit Service aa0613
	} else {
Packit Service aa0613
		/* Clumsily tell ldap + cyrus-sasl that we want encryption */
Packit Service aa0613
		ssf = 1;
Packit Service aa0613
		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf;;
Packit Service aa0613
		return_unexpected_if_fail (ret == 0);
Packit Service aa0613
	}
Packit Service ef9e0c
Packit Service aa0613
	/* There are issues with cryrus-sasl and GSS-SPNEGO with TLS even if
Packit Service aa0613
	 * ssf_max is set to 0. To be on the safe side GSS-SPNEGO is only used
Packit Service aa0613
	 * without LDAPS. */
Packit Service aa0613
	if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")
Packit Service aa0613
	                     && !adcli_conn_get_use_ldaps (conn)) {
Packit Service 811121
		mech =  "GSS-SPNEGO";
Packit Service 811121
	}
Packit Service aa0613
	_adcli_info ("Using %s for SASL bind", mech);
Packit Service 811121
Packit Service 811121
	ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL,
Packit Service 6d40f9
	                                    LDAP_SASL_QUIET, sasl_interact, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Clear the credential cache GSSAPI to use (for this thread) */
Packit Service 6d40f9
	status = gss_krb5_ccache_name (&minor, NULL, NULL);
Packit Service 6d40f9
	return_unexpected_if_fail (status == 0);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret != 0) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (conn->ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Couldn't authenticate to active directory");
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->ldap_authenticated = 1;
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
lookup_short_name (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *attrs[] = { "nETBIOSName", NULL, };
Packit Service 6d40f9
	LDAPMessage *results;
Packit Service 6d40f9
	char *partition_dn;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	char *filter;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	free (conn->domain_short);
Packit Service 6d40f9
	conn->domain_short = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&partition_dn, "CN=Partitions,%s", conn->configuration_naming_context) < 0)
Packit Service 6d40f9
		return_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	value = _adcli_ldap_escape_filter (conn->default_naming_context);
Packit Service 6d40f9
	return_if_fail (value != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&filter, "(&(nCName=%s)(nETBIOSName=*))", value) < 0)
Packit Service 6d40f9
		return_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (conn->ldap, partition_dn, LDAP_SCOPE_ONELEVEL,
Packit Service 6d40f9
	                         filter, attrs, 0, NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	free (partition_dn);
Packit Service 6d40f9
	free (filter);
Packit Service 6d40f9
	free (value);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
		conn->domain_short = _adcli_ldap_parse_value (conn->ldap, results, "nETBIOSName");
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
		if (conn->domain_short)
Packit Service 6d40f9
			_adcli_info ("Looked up short domain name: %s", conn->domain_short);
Packit Service 6d40f9
		else
Packit Service 6d40f9
			_adcli_err ("No short domain name found");
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_ldap_handle_failure (conn->ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                            "Couldn't lookup domain short name");
Packit Service 6d40f9
	}
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service db24d4
lookup_domain_sid (adcli_conn *conn)
Packit Service db24d4
{
Packit Service db24d4
	char *attrs[] = { "objectSid", NULL, };
Packit Service db24d4
	LDAPMessage *results;
Packit Service db24d4
	int ret;
Packit Service db24d4
Packit Service db24d4
	free (conn->domain_sid);
Packit Service db24d4
	conn->domain_sid = NULL;
Packit Service db24d4
Packit Service db24d4
	ret = ldap_search_ext_s (conn->ldap, conn->default_naming_context, LDAP_SCOPE_BASE,
Packit Service db24d4
	                         NULL, attrs, 0, NULL, NULL, NULL, -1, &results);
Packit Service db24d4
	if (ret == LDAP_SUCCESS) {
Packit Service db24d4
		conn->domain_sid = _adcli_ldap_parse_sid (conn->ldap, results, "objectSid");
Packit Service db24d4
		ldap_msgfree (results);
Packit Service db24d4
Packit Service db24d4
		if (conn->domain_sid)
Packit Service db24d4
			_adcli_info ("Looked up domain SID: %s", conn->domain_sid);
Packit Service db24d4
		else
Packit Service db24d4
			_adcli_err ("No domain SID found");
Packit Service db24d4
	} else {
Packit Service db24d4
		_adcli_ldap_handle_failure (conn->ldap, ADCLI_ERR_DIRECTORY,
Packit Service db24d4
		                            "Couldn't lookup domain SID");
Packit Service db24d4
	}
Packit Service db24d4
}
Packit Service db24d4
Packit Service db24d4
static void
Packit Service 6d40f9
conn_clear_state (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	conn->ldap_authenticated = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->ldap)
Packit Service 6d40f9
		ldap_unbind_ext_s (conn->ldap, NULL, NULL);
Packit Service 6d40f9
	conn->ldap = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	free (conn->canonical_host);
Packit Service 6d40f9
	conn->canonical_host = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->ccache)
Packit Service 6d40f9
		krb5_cc_close (conn->k5, conn->ccache);
Packit Service 6d40f9
	conn->ccache = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->keytab)
Packit Service 6d40f9
		krb5_kt_close (conn->k5, conn->keytab);
Packit Service 6d40f9
	conn->keytab = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->k5)
Packit Service 6d40f9
		krb5_free_context (conn->k5);
Packit Service 6d40f9
	conn->k5 = NULL;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_conn_discover (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
Packit Service 6d40f9
	/* Basic discovery and figuring out conn params */
Packit Service 6d40f9
	res = ensure_host_fqdn (res, conn);
Packit Service 6d40f9
	res = ensure_domain_and_host (res, conn);
Packit Service 6d40f9
	res = ensure_computer_name (res, conn);
Packit Service 6d40f9
	res = ensure_domain_realm (res, conn);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_conn_connect (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* - Connect to LDAP server */
Packit Service 6d40f9
	res = connect_to_directory (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Guarantee consistency and communication with one dc */
Packit Service 6d40f9
	res = setup_krb5_conf_snippet (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (conn->k5 == NULL);
Packit Service 6d40f9
	res = _adcli_krb5_init_context (&conn->k5);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Login with admin credentials now, setup login ccache */
Packit Service 6d40f9
	res = prep_kerberos_and_kinit (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* - And finally authenticate */
Packit Service 6d40f9
	res = authenticate_to_directory (conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	lookup_short_name (conn);
Packit Service db24d4
	lookup_domain_sid (conn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_conn *
Packit Service 6d40f9
adcli_conn_new (const char *domain_name)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_conn *conn;
Packit Service 6d40f9
Packit Service 6d40f9
	conn = calloc (1, sizeof (adcli_conn));
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	conn->refs = 1;
Packit Service 6d40f9
	conn->logins_allowed = ADCLI_LOGIN_COMPUTER_ACCOUNT | ADCLI_LOGIN_USER_ACCOUNT;
Packit Service 6d40f9
	adcli_conn_set_domain_name (conn, domain_name);
Packit Service aa0613
	adcli_conn_set_use_ldaps (conn, false);
Packit Service 6d40f9
	return conn;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
conn_free (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	free (conn->domain_name);
Packit Service 6d40f9
	free (conn->domain_realm);
Packit Service 6d40f9
	free (conn->domain_controller);
Packit Service 6d40f9
	free (conn->domain_short);
Packit Service 6d40f9
	free (conn->default_naming_context);
Packit Service 6d40f9
	free (conn->configuration_naming_context);
Packit Service 6d40f9
	_adcli_strv_free (conn->supported_capabilities);
Packit Service 811121
	_adcli_strv_free (conn->supported_sasl_mechs);
Packit Service 6d40f9
Packit Service 6d40f9
	free (conn->computer_name);
Packit Service 6d40f9
	free (conn->host_fqdn);
Packit Service 6d40f9
	free (conn->krb5_conf_dir);
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->krb5_conf_snippet) {
Packit Service 6d40f9
		unlink (conn->krb5_conf_snippet);
Packit Service 6d40f9
		free (conn->krb5_conf_snippet);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_conn_set_login_user (conn, NULL);
Packit Service 6d40f9
	adcli_conn_set_user_password (conn, NULL);
Packit Service 6d40f9
	adcli_conn_set_password_func (conn, NULL, NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	conn_clear_state (conn);
Packit Service 6d40f9
	no_more_disco (conn);
Packit Service 6d40f9
Packit Service 6d40f9
	free (conn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_conn *
Packit Service 6d40f9
adcli_conn_ref (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	conn->refs++;
Packit Service 6d40f9
	return conn;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_unref (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (conn == NULL)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	if (--(conn->refs) > 0)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	conn_free (conn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_host_fqdn (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->host_fqdn;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_host_fqdn (adcli_conn *conn,
Packit Service 6d40f9
                          const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->host_fqdn, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_computer_name (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->computer_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_computer_name (adcli_conn *conn,
Packit Service 6d40f9
                              const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->computer_name, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_computer_password (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->computer_password;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_computer_password (adcli_conn *conn,
Packit Service 6d40f9
                                  const char *password)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *newval = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (password) {
Packit Service 6d40f9
		newval = strdup (password);
Packit Service 6d40f9
		return_if_fail (newval != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->computer_password)
Packit Service 6d40f9
		_adcli_password_free (conn->computer_password);
Packit Service 6d40f9
Packit Service 6d40f9
	conn->computer_password = newval;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_domain_name (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->domain_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_domain_name (adcli_conn *conn,
Packit Service 6d40f9
                            const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->domain_name, value);
Packit Service 6d40f9
	no_more_disco (conn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_domain_realm (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->domain_realm;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_domain_realm (adcli_conn *conn,
Packit Service 6d40f9
                             const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->domain_realm, value);
Packit Service 6d40f9
	no_more_disco (conn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_domain_controller (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->domain_controller;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_domain_controller (adcli_conn *conn,
Packit Service 6d40f9
                                  const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->domain_controller, value);
Packit Service 6d40f9
	no_more_disco (conn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service aa0613
bool
Packit Service aa0613
adcli_conn_get_use_ldaps (adcli_conn *conn)
Packit Service aa0613
{
Packit Service aa0613
	return_val_if_fail (conn != NULL, NULL);
Packit Service aa0613
	return conn->use_ldaps;
Packit Service aa0613
}
Packit Service aa0613
Packit Service aa0613
void
Packit Service aa0613
adcli_conn_set_use_ldaps (adcli_conn *conn, bool value)
Packit Service aa0613
{
Packit Service aa0613
	return_if_fail (conn != NULL);
Packit Service aa0613
	conn->use_ldaps = value;
Packit Service aa0613
}
Packit Service aa0613
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_domain_short (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->domain_short;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 315950
const char *
Packit Service 315950
adcli_conn_get_domain_sid (adcli_conn *conn)
Packit Service 315950
{
Packit Service 315950
	return_val_if_fail (conn != NULL, NULL);
Packit Service 315950
	return conn->domain_sid;
Packit Service 315950
}
Packit Service 315950
Packit Service 315950
Packit Service 6d40f9
LDAP *
Packit Service 6d40f9
adcli_conn_get_ldap_connection (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->ldap;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_context
Packit Service 6d40f9
adcli_conn_get_krb5_context (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return_val_if_fail (conn->k5 != NULL, NULL);
Packit Service 6d40f9
	return conn->k5;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 715b9a
void
Packit Service 715b9a
adcli_conn_set_krb5_context (adcli_conn *conn,
Packit Service 715b9a
                             krb5_context k5)
Packit Service 715b9a
{
Packit Service 715b9a
	return_if_fail (conn != NULL);
Packit Service 715b9a
Packit Service 715b9a
	if (conn->k5 != NULL) {
Packit Service 715b9a
		krb5_free_context (conn->k5);
Packit Service 715b9a
	}
Packit Service 715b9a
Packit Service 715b9a
	conn->k5 = k5;
Packit Service 715b9a
}
Packit Service 715b9a
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_login_user (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->user_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_login_user (adcli_conn *conn,
Packit Service 6d40f9
                           const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->user_name, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_user_password (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->user_password;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_user_password (adcli_conn *conn,
Packit Service 6d40f9
                               const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->user_password, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_password_func (adcli_conn *conn,
Packit Service 6d40f9
                              adcli_password_func password_func,
Packit Service 6d40f9
                              void *data,
Packit Service 6d40f9
                              adcli_destroy_func destroy_data)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->password_destroy)
Packit Service 6d40f9
		(conn->password_destroy) (conn->password_data);
Packit Service 6d40f9
	conn->password_func = password_func;
Packit Service 6d40f9
	conn->password_data = data;
Packit Service 6d40f9
	conn->password_destroy = destroy_data;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_login_type
Packit Service 6d40f9
adcli_conn_get_login_type (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, ADCLI_LOGIN_UNKNOWN);
Packit Service 6d40f9
	return conn->login_type;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_login_type
Packit Service 6d40f9
adcli_conn_get_allowed_login_types (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, ADCLI_LOGIN_UNKNOWN);
Packit Service 6d40f9
	return conn->logins_allowed;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_allowed_login_types (adcli_conn *conn,
Packit Service 6d40f9
                                    adcli_login_type types)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	conn->logins_allowed = types;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_ccache
Packit Service 6d40f9
adcli_conn_get_login_ccache (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->ccache;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_login_ccache_name (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->login_ccache_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_login_ccache_name (adcli_conn *conn,
Packit Service 6d40f9
                                  const char *ccname)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *newval = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ccname) {
Packit Service 6d40f9
		newval = strdup (ccname);
Packit Service 6d40f9
		return_if_fail (newval != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->login_ccache_name) {
Packit Service 6d40f9
		if (conn->login_ccache_name_is_krb5)
Packit Service 6d40f9
			krb5_free_string (conn->k5, conn->login_ccache_name);
Packit Service 6d40f9
		else
Packit Service 6d40f9
			free (conn->login_ccache_name);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->ccache) {
Packit Service 6d40f9
		krb5_cc_close (conn->k5, conn->ccache);
Packit Service 6d40f9
		conn->ccache = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->login_ccache_name = newval;
Packit Service 6d40f9
	conn->login_ccache_name_is_krb5 = 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_login_keytab_name (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->login_keytab_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_login_keytab_name (adcli_conn *conn,
Packit Service 6d40f9
                                  const char *ktname)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *newval = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ktname) {
Packit Service 6d40f9
		newval = strdup (ktname);
Packit Service 6d40f9
		return_if_fail (newval != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->login_keytab_name) {
Packit Service 6d40f9
		if (conn->login_keytab_name_is_krb5)
Packit Service 6d40f9
			krb5_free_string (conn->k5, conn->login_keytab_name);
Packit Service 6d40f9
		else
Packit Service 6d40f9
			free (conn->login_keytab_name);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (conn->keytab) {
Packit Service 6d40f9
		krb5_kt_close (conn->k5, conn->keytab);
Packit Service 6d40f9
		conn->keytab = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	conn->login_keytab_name = newval;
Packit Service 6d40f9
	conn->login_keytab_name_is_krb5 = 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_default_naming_context (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return conn->default_naming_context;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_conn_get_krb5_conf_dir (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
	return conn->krb5_conf_dir;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_conn_set_krb5_conf_dir (adcli_conn *conn,
Packit Service 6d40f9
                              const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (conn != NULL);
Packit Service 6d40f9
	_adcli_str_set (&conn->krb5_conf_dir, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
int
Packit Service 6d40f9
adcli_conn_server_has_capability (adcli_conn *conn,
Packit Service 6d40f9
                                  const char *capability)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, 0);
Packit Service 6d40f9
	return_val_if_fail (capability != NULL, 0);
Packit Service 6d40f9
Packit Service 6d40f9
	if (!conn->supported_capabilities)
Packit Service 6d40f9
		return 0;
Packit Service 6d40f9
Packit Service 6d40f9
	for (i = 0; conn->supported_capabilities[i] != NULL; i++) {
Packit Service 6d40f9
		if (strcmp (capability, conn->supported_capabilities[i]) == 0)
Packit Service 6d40f9
			return 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return 0;
Packit Service 6d40f9
}
Packit Service b1a9da
Packit Service 811121
bool
Packit Service 811121
adcli_conn_server_has_sasl_mech (adcli_conn *conn,
Packit Service 811121
                                 const char *mech)
Packit Service 811121
{
Packit Service 811121
	int i;
Packit Service 811121
Packit Service 811121
	return_val_if_fail (conn != NULL, false);
Packit Service 811121
	return_val_if_fail (mech != NULL, false);
Packit Service 811121
Packit Service 811121
	if (!conn->supported_sasl_mechs)
Packit Service 811121
		return false;
Packit Service 811121
Packit Service 811121
	for (i = 0; conn->supported_sasl_mechs[i] != NULL; i++) {
Packit Service 811121
		if (strcasecmp (mech, conn->supported_sasl_mechs[i]) == 0)
Packit Service 811121
			return true;
Packit Service 811121
	}
Packit Service 811121
Packit Service 811121
	return false;
Packit Service 811121
}
Packit Service 811121
Packit Service b1a9da
bool adcli_conn_is_writeable (adcli_conn *conn)
Packit Service b1a9da
{
Packit Service 8aa259
	disco_dance_if_necessary (conn);
Packit Service 8aa259
Packit Service 8aa259
	if (conn->domain_disco == NULL) {
Packit Service 8aa259
		return false;
Packit Service 8aa259
	}
Packit Service 8aa259
Packit Service 8aa259
	return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
Packit Service b1a9da
}