Blame library/adenroll.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 "adenroll.h"
Packit Service 6d40f9
#include "adprivate.h"
Packit Service 6d40f9
#include "seq.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
Packit Service 6d40f9
#include <assert.h>
Packit Service 6d40f9
#include <ctype.h>
Packit Service 6d40f9
#include <errno.h>
Packit Service 6d40f9
#include <netdb.h>
Packit Service 6d40f9
#include <stdio.h>
Packit Service 6d40f9
#include <unistd.h>
Packit Service a8fee9
#include <sys/stat.h>
Packit Service a8fee9
#include <fcntl.h>
Packit Service 6d40f9
Packit Service a61006
#ifndef SAMBA_DATA_TOOL
Packit Service a61006
#define SAMBA_DATA_TOOL "/usr/bin/net"
Packit Service a61006
#endif
Packit Service a61006
Packit Service a8fee9
static krb5_enctype v60_later_enctypes_fips[] = {
Packit Service a8fee9
	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
Packit Service a8fee9
	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
Packit Service a8fee9
	0
Packit Service a8fee9
};
Packit Service a8fee9
Packit Service 6d40f9
static krb5_enctype v60_later_enctypes[] = {
Packit Service 6d40f9
	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
Packit Service 6d40f9
	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
Packit Service 6d40f9
	ENCTYPE_DES3_CBC_SHA1,
Packit Service 6d40f9
	ENCTYPE_ARCFOUR_HMAC,
Packit Service 6d40f9
	ENCTYPE_DES_CBC_MD5,
Packit Service 6d40f9
	ENCTYPE_DES_CBC_CRC,
Packit Service 6d40f9
	0
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service 6d40f9
static krb5_enctype v51_earlier_enctypes[] = {
Packit Service 6d40f9
	ENCTYPE_DES_CBC_CRC,
Packit Service 6d40f9
	ENCTYPE_DES_CBC_MD5,
Packit Service 6d40f9
	ENCTYPE_ARCFOUR_HMAC,
Packit Service 6d40f9
	0
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service 8ee766
/* Some constants for the userAccountControl AD LDAP attribute, see e.g.
Packit Service 8ee766
 * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
Packit Service 8ee766
 * for details. */
Packit Service 8ee766
#define UAC_WORKSTATION_TRUST_ACCOUNT  0x1000
Packit Service 8ee766
#define UAC_DONT_EXPIRE_PASSWORD      0x10000
Packit Service 8ee766
#define UAC_TRUSTED_FOR_DELEGATION    0x80000
Packit Service 8ee766
Packit Service 6d40f9
struct _adcli_enroll {
Packit Service 6d40f9
	int refs;
Packit Service 6d40f9
	adcli_conn *conn;
Packit Service 6d40f9
Packit Service 6d40f9
	char *host_fqdn;
Packit Service 6d40f9
	int host_fqdn_explicit;
Packit Service 6d40f9
	char *computer_name;
Packit Service 6d40f9
	int computer_name_explicit;
Packit Service 6d40f9
	char *computer_sam;
Packit Service 6d40f9
	char *computer_password;
Packit Service 6d40f9
	int computer_password_explicit;
Packit Service 6d40f9
	int reset_password;
Packit Service 6d40f9
	krb5_principal computer_principal;
Packit Service 6d40f9
Packit Service 6d40f9
	char *domain_ou;
Packit Service 6d40f9
	int domain_ou_validated;
Packit Service 6d40f9
	int domain_ou_explicit;
Packit Service 6d40f9
	char *computer_dn;
Packit Service 6d40f9
	char *computer_container;
Packit Service 6d40f9
	LDAPMessage *computer_attributes;
Packit Service 6d40f9
Packit Service 6d40f9
	char **service_names;
Packit Service 6d40f9
	char **service_principals;
Packit Service 6d40f9
	int service_principals_explicit;
Packit Service 6d40f9
Packit Service 6213b5
	char **service_principals_to_add;
Packit Service 6213b5
	char **service_principals_to_remove;
Packit Service 6213b5
Packit Service 6d40f9
	char *user_principal;
Packit Service 6d40f9
	int user_princpal_generate;
Packit Service 6d40f9
Packit Service 6d40f9
	char *os_name;
Packit Service 268540
	int os_name_explicit;
Packit Service 6d40f9
	char *os_version;
Packit Service 268540
	int os_version_explicit;
Packit Service 6d40f9
	char *os_service_pack;
Packit Service 268540
	int os_service_pack_explicit;
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_kvno kvno;
Packit Service 6d40f9
	char *keytab_name;
Packit Service 6d40f9
	int keytab_name_is_krb5;
Packit Service 6d40f9
	krb5_keytab keytab;
Packit Service 6d40f9
	krb5_principal *keytab_principals;
Packit Service 6d40f9
	krb5_enctype *keytab_enctypes;
Packit Service 6d40f9
	int keytab_enctypes_explicit;
Packit Service 6d40f9
	unsigned int computer_password_lifetime;
Packit Service 6d40f9
	int computer_password_lifetime_explicit;
Packit Service a61006
	char *samba_data_tool;
Packit Service 8ee766
	bool trusted_for_delegation;
Packit Service 268540
	int trusted_for_delegation_explicit;
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_host_fqdn (adcli_result res,
Packit Service 6d40f9
                  adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	const char *fqdn;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->host_fqdn) {
Packit Service 6d40f9
		_adcli_info ("Using fully qualified name: %s",
Packit Service 6d40f9
		             enroll->host_fqdn);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->host_fqdn_explicit) {
Packit Service 6d40f9
		_adcli_info ("Not setting fully qualified name");
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* By default use our actual host name discovered during connecting */
Packit Service 6d40f9
	fqdn = adcli_conn_get_host_fqdn (enroll->conn);
Packit Service 6d40f9
	_adcli_str_set (&enroll->host_fqdn, fqdn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
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_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_name) {
Packit Service 6d40f9
		_adcli_info ("Enrolling computer name: %s",
Packit Service 6d40f9
		             enroll->computer_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->host_fqdn) {
Packit Service 6d40f9
		_adcli_err ("No host name from which to determine the computer name");
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->computer_name = _adcli_calc_netbios_name (enroll->host_fqdn);
Packit Service 6d40f9
	if (enroll->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
static adcli_result
Packit Service 6d40f9
ensure_computer_sam (adcli_result res,
Packit Service 6d40f9
                     adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_sam);
Packit Service 6d40f9
	enroll->computer_sam = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&enroll->computer_sam, "%s$", enroll->computer_name) < 0)
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_sam != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_principal)
Packit Service 6d40f9
		krb5_free_principal (k5, enroll->computer_principal);
Packit Service 6d40f9
	enroll->computer_principal = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_krb5_build_principal (k5, enroll->computer_sam,
Packit Service 6d40f9
	                                    adcli_conn_get_domain_realm (enroll->conn),
Packit Service 6d40f9
	                                    &enroll->computer_principal);
Packit Service 6d40f9
	return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static int
Packit Service 6d40f9
filter_password_chars (char *password,
Packit Service 6d40f9
                       int length)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int i, j;
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * The MS documentation says their servers only use ASCII characters
Packit Service 6d40f9
	 * between 32 and 122 inclusive. We do that as well, and filter out
Packit Service 6d40f9
	 * all other random characters. We also remove certain characters
Packit Service 6d40f9
	 * special for use in a shell.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
	for (i = 0, j = 0; i < length; i++) {
Packit Service 6d40f9
		if (password[i] >= 32 && password[i] <= 122 &&
Packit Service 6d40f9
		    strchr (" !'\"$`", password[i]) == NULL)
Packit Service 6d40f9
			password[j++] = password[i];
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* return the number of valid characters remaining */
Packit Service 6d40f9
	return j;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static char *
Packit Service 6d40f9
generate_host_password  (adcli_enroll *enroll,
Packit Service 6d40f9
                         size_t length)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *password;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_data buffer;
Packit Service 6d40f9
	int at;
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_val_if_fail (k5 != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	password = malloc (length + 1);
Packit Service 6d40f9
	return_val_if_fail (password != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	at = 0;
Packit Service 6d40f9
	while (at != length) {
Packit Service 6d40f9
		buffer.length = length - at;
Packit Service 6d40f9
		buffer.data = password + at;
Packit Service 6d40f9
Packit Service 6d40f9
		code = krb5_c_random_make_octets (k5, &buffer);
Packit Service 6d40f9
		return_val_if_fail (code == 0, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		at += filter_password_chars (buffer.data, buffer.length);
Packit Service 6d40f9
		assert (at <= length);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* This null termination works around a bug in krb5 */
Packit Service 6d40f9
	password[length] = '\0';
Packit Service 6d40f9
	return password;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_computer_password (adcli_result res,
Packit Service 6d40f9
                      adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	const int length = 120;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_password)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->reset_password) {
Packit Service 6d40f9
		assert (enroll->computer_name != NULL);
Packit Service 6d40f9
		enroll->computer_password = _adcli_calc_reset_password (enroll->computer_name);
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_password != NULL);
Packit Service 6d40f9
		_adcli_info ("Using default reset computer password");
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		enroll->computer_password = generate_host_password (enroll, length);
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_password != NULL);
Packit Service 6d40f9
		_adcli_info ("Generated %d character computer password", length);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service ea525b
ensure_default_service_names (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int length = 0;
Packit Service 6d40f9
Packit Service ea525b
	if (enroll->service_names != NULL) {
Packit Service ea525b
		length = seq_count (enroll->service_names);
Packit Service 6d40f9
Packit Service ea525b
		/* Make sure there is no entry with an unexpected case. AD
Packit Service ea525b
		 * would not care but since the client side is case-sensitive
Packit Service ea525b
		 * we should make sure we use the expected spelling. */
Packit Service ea525b
		seq_remove_unsorted (enroll->service_names,
Packit Service ea525b
		                     &length, "host",
Packit Service ea525b
		                     (seq_compar)strcasecmp, free);
Packit Service ea525b
		seq_remove_unsorted (enroll->service_names,
Packit Service ea525b
		                     &length, "RestrictedKrbHost",
Packit Service ea525b
		                     (seq_compar)strcasecmp, free);
Packit Service ea525b
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* The default ones specified by MS */
Packit Service 6d40f9
	enroll->service_names = _adcli_strv_add (enroll->service_names,
Packit Service 6d40f9
	                                         strdup ("host"), &length);
Packit Service 6d40f9
	enroll->service_names = _adcli_strv_add (enroll->service_names,
Packit Service 6d40f9
	                                         strdup ("RestrictedKrbHost"), &length);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service ea525b
ensure_service_names (adcli_result res,
Packit Service ea525b
                      adcli_enroll *enroll)
Packit Service ea525b
{
Packit Service ea525b
	if (res != ADCLI_SUCCESS)
Packit Service ea525b
		return res;
Packit Service ea525b
Packit Service ea525b
	if (enroll->service_names || enroll->service_principals)
Packit Service ea525b
		return ADCLI_SUCCESS;
Packit Service ea525b
Packit Service ea525b
	return ensure_default_service_names (enroll);
Packit Service ea525b
}
Packit Service ea525b
Packit Service ea525b
static adcli_result
Packit Service f6a102
add_service_names_to_service_principals (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
	int length = 0;
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service f6a102
	if (enroll->service_principals != NULL) {
Packit Service f6a102
		length = seq_count (enroll->service_principals);
Packit Service f6a102
	}
Packit Service f6a102
Packit Service f6a102
	for (i = 0; enroll->service_names[i] != NULL; i++) {
Packit Service f6a102
		if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
Packit Service f6a102
			return_unexpected_if_reached ();
Packit Service e72923
		enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service e72923
		                                                     name, &length, false);
Packit Service f6a102
Packit Service f6a102
		if (enroll->host_fqdn) {
Packit Service f6a102
			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
Packit Service f6a102
				return_unexpected_if_reached ();
Packit Service e72923
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service e72923
			                                                     name, &length, false);
Packit Service f6a102
		}
Packit Service f6a102
	}
Packit Service f6a102
Packit Service f6a102
	return ADCLI_SUCCESS;
Packit Service f6a102
}
Packit Service f6a102
Packit Service f6a102
static adcli_result
Packit Service 6213b5
add_and_remove_service_principals (adcli_enroll *enroll)
Packit Service 6213b5
{
Packit Service 6213b5
	int length = 0;
Packit Service 6213b5
	size_t c;
Packit Service 6213b5
	const char **list;
Packit Service 6213b5
Packit Service 6213b5
	if (enroll->service_principals != NULL) {
Packit Service 6213b5
		length = seq_count (enroll->service_principals);
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	list = adcli_enroll_get_service_principals_to_add (enroll);
Packit Service 6213b5
	if (list != NULL) {
Packit Service 6213b5
		for (c = 0; list[c] != NULL; c++) {
Packit Service e72923
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service e72923
			                                                     strdup (list[c]),
Packit Service e72923
			                                                     &length, false);
Packit Service 6213b5
			if (enroll->service_principals == NULL) {
Packit Service 6213b5
				return ADCLI_ERR_UNEXPECTED;
Packit Service 6213b5
			}
Packit Service 6213b5
		}
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	list = adcli_enroll_get_service_principals_to_remove (enroll);
Packit Service 6213b5
	if (list != NULL) {
Packit Service 6213b5
		for (c = 0; list[c] != NULL; c++) {
Packit Service 6213b5
			/* enroll->service_principals typically refects the
Packit Service 6213b5
			 * order of the principal in the keytabm so it is not
Packit Service 6213b5
			 * ordered. */
Packit Service 6213b5
			_adcli_strv_remove_unsorted (enroll->service_principals,
Packit Service 6213b5
			                             list[c], &length);
Packit Service 6213b5
		}
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	return ADCLI_SUCCESS;
Packit Service 6213b5
}
Packit Service 6213b5
Packit Service 6213b5
static adcli_result
Packit Service f6a102
ensure_service_principals (adcli_result res,
Packit Service f6a102
                           adcli_enroll *enroll)
Packit Service f6a102
{
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->keytab_principals == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->service_principals) {
Packit Service 6d40f9
		assert (enroll->service_names != NULL);
Packit Service 6213b5
		res = add_service_names_to_service_principals (enroll);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6213b5
	if (res == ADCLI_SUCCESS) {
Packit Service 6213b5
		res = add_and_remove_service_principals (enroll);
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service e99966
static void enroll_clear_keytab_principals (adcli_enroll *enroll)
Packit Service e99966
{
Packit Service e99966
	krb5_context k5;
Packit Service e99966
	size_t c;
Packit Service e99966
Packit Service e99966
	if (enroll->keytab_principals) {
Packit Service e99966
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service e99966
		return_if_fail (k5 != NULL);
Packit Service e99966
Packit Service e99966
		for (c = 0; enroll->keytab_principals[c] != NULL; c++)
Packit Service e99966
			krb5_free_principal (k5, enroll->keytab_principals[c]);
Packit Service e99966
Packit Service e99966
		free (enroll->keytab_principals);
Packit Service e99966
		enroll->keytab_principals = NULL;
Packit Service e99966
	}
Packit Service e99966
Packit Service e99966
	return;
Packit Service e99966
}
Packit Service e99966
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_keytab_principals (adcli_result res,
Packit Service 6d40f9
                          adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	int count;
Packit Service 6d40f9
	int at, i;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Prepare the principals we're going to add to the keytab */
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll->service_principals);
Packit Service 6d40f9
	count = _adcli_strv_len (enroll->service_principals);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service e99966
	enroll_clear_keytab_principals (enroll);
Packit Service 6d40f9
	enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
Packit Service f6a102
	return_unexpected_if_fail (enroll->keytab_principals != NULL);
Packit Service 6d40f9
	at = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	/* First add the principal for the computer account name */
Packit Service 6d40f9
	code = krb5_copy_principal (k5, enroll->computer_principal,
Packit Service 6d40f9
	                            &enroll->keytab_principals[at++]);
Packit Service 6d40f9
	return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Next, optionally add the user principal */
Packit Service 6d40f9
	if (enroll->user_principal) {
Packit Service 6d40f9
		code = krb5_parse_name (k5, enroll->user_principal,
Packit Service 6d40f9
		                        &enroll->keytab_principals[at++]);
Packit Service 6d40f9
		if (code != 0) {
Packit Service 6d40f9
			if (code != 0) {
Packit Service 6d40f9
				_adcli_err ("Couldn't parse kerberos user principal: %s: %s",
Packit Service 6d40f9
				            enroll->user_principal,
Packit Service 6d40f9
				            krb5_get_error_message (k5, code));
Packit Service 6d40f9
				return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Now add the principals for all the various services */
Packit Service 6d40f9
Packit Service 6d40f9
	for (i = 0; i < count; i++) {
Packit Service 6d40f9
		code = _adcli_krb5_build_principal (k5, enroll->service_principals[i],
Packit Service 6d40f9
		                                    adcli_conn_get_domain_realm (enroll->conn),
Packit Service 6d40f9
		                                    &enroll->keytab_principals[at++]);
Packit Service 6d40f9
		if (code != 0) {
Packit Service 6d40f9
			_adcli_err ("Couldn't parse kerberos service principal: %s: %s",
Packit Service 6d40f9
			            enroll->service_principals[i],
Packit Service 6d40f9
			            krb5_get_error_message (k5, code));
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_user_principal (adcli_result res,
Packit Service 6d40f9
                       adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->user_princpal_generate) {
Packit Service 6d40f9
		name = strdup (enroll->computer_name);
Packit Service 6d40f9
		return_unexpected_if_fail (name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		_adcli_str_down (name);
Packit Service 6d40f9
Packit Service 6d40f9
		assert (enroll->user_principal == NULL);
Packit Service 6d40f9
		if (asprintf (&enroll->user_principal, "host/%s@%s",
Packit Service 6d40f9
		              name, adcli_conn_get_domain_realm (enroll->conn)) < 0)
Packit Service 6d40f9
			return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
		free (name);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->user_principal)
Packit Service 6d40f9
		_adcli_info ("With user principal: %s", enroll->user_principal);
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
lookup_computer_container (adcli_enroll *enroll,
Packit Service 6d40f9
                           LDAP *ldap)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *attrs[] = { "wellKnownObjects", NULL };
Packit Service 6d40f9
	char *prefix = "B:32:AA312825768811D1ADED00C04FD8D5CD:";
Packit Service 6d40f9
	int prefix_len;
Packit Service 6d40f9
	LDAPMessage *results;
Packit Service 6d40f9
	const char *base;
Packit Service 6d40f9
	char **values;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_container)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	base = enroll->domain_ou;
Packit Service 6d40f9
	if (base == NULL)
Packit Service 6d40f9
		base = adcli_conn_get_default_naming_context (enroll->conn);
Packit Service 6d40f9
	assert (base != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE,
Packit Service 6d40f9
	                         "(objectClass=*)", attrs, 0, NULL, NULL,
Packit Service 6d40f9
	                         NULL, -1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_NO_SUCH_OBJECT && enroll->domain_ou) {
Packit Service 6d40f9
		_adcli_err ("The organizational unit does not exist: %s", enroll->domain_ou);
Packit Service 6d40f9
		return enroll->domain_ou_explicit ? ADCLI_ERR_CONFIG : ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't lookup computer container: %s", base);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	values = _adcli_ldap_parse_values (ldap, results, "wellKnownObjects");
Packit Service 6d40f9
	ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
	prefix_len = strlen (prefix);
Packit Service 6d40f9
	for (i = 0; values && values[i]; i++) {
Packit Service 6d40f9
		if (strncmp (values[i], prefix, prefix_len) == 0) {
Packit Service 6d40f9
			enroll->computer_container = strdup (values[i] + prefix_len);
Packit Service 6d40f9
			return_unexpected_if_fail (enroll->computer_container != NULL);
Packit Service 6d40f9
			_adcli_info ("Found well known computer container at: %s",
Packit Service 6d40f9
			             enroll->computer_container);
Packit Service 6d40f9
			break;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_strv_free (values);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Try harder */
Packit Service 6d40f9
	if (!enroll->computer_container) {
Packit Service 6d40f9
		ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE,
Packit Service 6d40f9
		                         "(&(objectClass=container)(cn=Computers))",
Packit Service 6d40f9
		                         attrs, 0, NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
		if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
			enroll->computer_container = _adcli_ldap_parse_dn (ldap, results);
Packit Service 6d40f9
			if (enroll->computer_container) {
Packit Service 6d40f9
				_adcli_info ("Well known computer container not "
Packit Service 6d40f9
				             "found, but found suitable one at: %s",
Packit Service 6d40f9
				             enroll->computer_container);
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->computer_container && enroll->domain_ou) {
Packit Service 6d40f9
		_adcli_warn ("Couldn't find a computer container in the ou, "
Packit Service 6d40f9
		             "creating computer account directly in: %s", enroll->domain_ou);
Packit Service 6d40f9
		enroll->computer_container = strdup (enroll->domain_ou);
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_container != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->computer_container) {
Packit Service 6d40f9
		_adcli_err ("Couldn't find location to create computer accounts");
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
calculate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                            LDAP *ldap)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_dn == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Now need to find or validate the computer container */
Packit Service 6d40f9
	res = lookup_computer_container (enroll, ldap);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_container);
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_dn);
Packit Service 6d40f9
	enroll->computer_dn = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&enroll->computer_dn, "CN=%s,%s", enroll->computer_name, enroll->computer_container) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Calculated computer account: %s", enroll->computer_dn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6596aa
calculate_enctypes (adcli_enroll *enroll, char **enctype)
Packit Service 6596aa
{
Packit Service 6596aa
	char *value = NULL;
Packit Service 6596aa
	krb5_enctype *read_enctypes;
Packit Service 7e2b15
	krb5_enctype *new_enctypes;
Packit Service 6596aa
	char *new_value = NULL;
Packit Service 6596aa
	int is_2008_or_later;
Packit Service 6596aa
	LDAP *ldap;
Packit Service 6596aa
Packit Service 6596aa
	*enctype = NULL;
Packit Service 6596aa
	/*
Packit Service 6596aa
	 * Because we're using a keytab we want the server to be aware of the
Packit Service 6596aa
	 * encryption types supported on the client, because we can't dynamically
Packit Service 6596aa
	 * use a new one that's thrown at us.
Packit Service 6596aa
	 *
Packit Service 6596aa
	 * If the encryption types are not explicitly set by the caller of this
Packit Service 6596aa
	 * library, then see if the account already has some encryption types
Packit Service 6596aa
	 * marked on it.
Packit Service 6596aa
	 *
Packit Service 6596aa
	 * If not, write our default set to the account.
Packit Service 6596aa
	 *
Packit Service 6596aa
	 * Note that Windows 2003 and earlier have a standard set of encryption
Packit Service 6596aa
	 * types, and no msDS-supportedEncryptionTypes attribute.
Packit Service 6596aa
	 */
Packit Service 6596aa
Packit Service 6596aa
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6596aa
	return_unexpected_if_fail (ldap != NULL);
Packit Service 6596aa
Packit Service 6596aa
	is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
Packit Service 6596aa
Packit Service 6596aa
	/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
Packit Service 137482
	if (is_2008_or_later && enroll->computer_attributes != NULL) {
Packit Service 6596aa
		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
Packit Service 6596aa
		                                 "msDS-supportedEncryptionTypes");
Packit Service 6596aa
Packit Service 6596aa
		if (!enroll->keytab_enctypes_explicit && value != NULL) {
Packit Service 6596aa
			read_enctypes = _adcli_krb5_parse_enctypes (value);
Packit Service 6596aa
			if (read_enctypes == NULL) {
Packit Service 6596aa
				_adcli_warn ("Invalid or unsupported encryption types are set on "
Packit Service 6596aa
				             "the computer account (%s).", value);
Packit Service 6596aa
			} else {
Packit Service 6596aa
				free (enroll->keytab_enctypes);
Packit Service 6596aa
				enroll->keytab_enctypes = read_enctypes;
Packit Service 6596aa
			}
Packit Service 6596aa
		}
Packit Service 6596aa
Packit Service 6596aa
	/* In 2003 or earlier, standard set of enc types */
Packit Service 6596aa
	} else {
Packit Service 6596aa
		value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
Packit Service 6596aa
	}
Packit Service 6596aa
Packit Service 7e2b15
	new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 7e2b15
	if (new_enctypes == NULL) {
Packit Service 7e2b15
		_adcli_warn ("No permitted encryption type found.");
Packit Service 7e2b15
		return ADCLI_ERR_UNEXPECTED;
Packit Service 7e2b15
	}
Packit Service 7e2b15
Packit Service 7e2b15
	new_value = _adcli_krb5_format_enctypes (new_enctypes);
Packit Service 7e2b15
	krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes);
Packit Service 6596aa
	if (new_value == NULL) {
Packit Service 6596aa
		free (value);
Packit Service 6596aa
		_adcli_warn ("The encryption types desired are not available in active directory");
Packit Service 6596aa
		return ADCLI_ERR_CONFIG;
Packit Service 6596aa
	}
Packit Service 6596aa
Packit Service 6596aa
	/* If we already have this value, then don't need to update */
Packit Service 6596aa
	if (value && strcmp (new_value, value) == 0) {
Packit Service 6596aa
		free (value);
Packit Service 6596aa
		free (new_value);
Packit Service 6596aa
		return ADCLI_SUCCESS;
Packit Service 6596aa
	}
Packit Service 6596aa
	free (value);
Packit Service 6596aa
Packit Service 6596aa
	if (!is_2008_or_later) {
Packit Service 6596aa
		free (new_value);
Packit Service 6596aa
		_adcli_warn ("Server does not support setting encryption types");
Packit Service 6596aa
		return ADCLI_SUCCESS;
Packit Service 6596aa
	}
Packit Service 6596aa
Packit Service 6596aa
	*enctype = new_value;
Packit Service 6596aa
	return ADCLI_SUCCESS;
Packit Service 6596aa
}
Packit Service 6596aa
Packit Service 6596aa
static adcli_result
Packit Service 6d40f9
create_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                         LDAP *ldap)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *vals_objectClass[] = { "computer", NULL };
Packit Service 6d40f9
	LDAPMod objectClass = { LDAP_MOD_ADD, "objectClass", { vals_objectClass, } };
Packit Service 6d40f9
	char *vals_sAMAccountName[] = { enroll->computer_sam, NULL };
Packit Service 6d40f9
	LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } };
Packit Service 6d40f9
	char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
Packit Service 137482
	LDAPMod userAccountControl = { LDAP_MOD_ADD, "userAccountControl", { vals_userAccountControl, } };
Packit Service 137482
	char *vals_supportedEncryptionTypes[] = { NULL, NULL };
Packit Service 137482
	LDAPMod encTypes = { LDAP_MOD_ADD, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
Packit Service 137482
	char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
Packit Service 137482
	LDAPMod dNSHostName = { LDAP_MOD_ADD, "dNSHostName", { vals_dNSHostName, } };
Packit Service 137482
	char *vals_operatingSystem[] = { enroll->os_name, NULL };
Packit Service 137482
	LDAPMod operatingSystem = { LDAP_MOD_ADD, "operatingSystem", { vals_operatingSystem, } };
Packit Service 137482
	char *vals_operatingSystemVersion[] = { enroll->os_version, NULL };
Packit Service 137482
	LDAPMod operatingSystemVersion = { LDAP_MOD_ADD, "operatingSystemVersion", { vals_operatingSystemVersion, } };
Packit Service 137482
	char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
Packit Service 137482
	LDAPMod operatingSystemServicePack = { LDAP_MOD_ADD, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
Packit Service 137482
	char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
Packit Service 137482
	LDAPMod userPrincipalName = { LDAP_MOD_ADD, "userPrincipalName", { vals_userPrincipalName, }, };
Packit Service 137482
	LDAPMod servicePrincipalName = { LDAP_MOD_ADD, "servicePrincipalName", { enroll->service_principals, } };
Packit Service 137482
Packit Service 137482
	char *val = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	int ret;
Packit Service 137482
	size_t c;
Packit Service 137482
	size_t m;
Packit Service 6d40f9
Packit Service 137482
	LDAPMod *all_mods[] = {
Packit Service 6d40f9
		&objectClass,
Packit Service 6d40f9
		&sAMAccountName,
Packit Service 6d40f9
		&userAccountControl,
Packit Service 137482
		&encTypes,
Packit Service 137482
		&dNSHostName,
Packit Service 137482
		&operatingSystem,
Packit Service 137482
		&operatingSystemVersion,
Packit Service 137482
		&operatingSystemServicePack,
Packit Service 137482
		&userPrincipalName,
Packit Service 137482
		&servicePrincipalName,
Packit Service 137482
		NULL
Packit Service 6d40f9
	};
Packit Service 6d40f9
Packit Service 137482
	size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *);
Packit Service 137482
	LDAPMod *mods[mods_count];
Packit Service 137482
Packit Service 8ee766
	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
Packit Service 8ee766
		vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
Packit Service 8ee766
	}
Packit Service 8ee766
Packit Service 137482
	ret = calculate_enctypes (enroll, &val;;
Packit Service 137482
	if (ret != ADCLI_SUCCESS) {
Packit Service 137482
		return ret;
Packit Service 137482
	}
Packit Service 137482
	vals_supportedEncryptionTypes[0] = val;
Packit Service 137482
Packit Service 137482
	m = 0;
Packit Service 137482
	for (c = 0; c < mods_count - 1; c++) {
Packit Service 137482
		/* Skip empty LDAP sttributes */
Packit Service 137482
		if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
Packit Service 137482
			mods[m++] = all_mods[c];
Packit Service 137482
		}
Packit Service 137482
	}
Packit Service 137482
	mods[m] = NULL;
Packit Service 137482
Packit Service 6d40f9
	ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 137482
	free (val);
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * Hand to head. This is really dumb... AD returns
Packit Service 6d40f9
	 * OBJECT_CLASS_VIOLATION when the 'admin' account doesn't have
Packit Service 6d40f9
	 * enough permission to create this computer account.
Packit Service 6d40f9
	 *
Packit Service 6d40f9
	 * Additionally LDAP_UNWILLING_TO_PERFORM and LDAP_CONSTRAINT_VIOLATION
Packit Service 6d40f9
	 * are seen on various Windows Servers as responses to this case.
Packit Service 6d40f9
	 *
Packit Service 6d40f9
	 * TODO: Perhaps some missing attributes are auto-generated when
Packit Service 6d40f9
	 * the administrative credentials have sufficient permissions, and
Packit Service 6d40f9
	 * those missing attributes cause the object class violation. However
Packit Service 6d40f9
	 * I've tried to screw around with this, and can't find the missing
Packit Service 6d40f9
	 * attributes. They may be hidden, like unicodePwd.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_INSUFFICIENT_ACCESS || ret == LDAP_OBJECT_CLASS_VIOLATION ||
Packit Service 6d40f9
	    ret == LDAP_UNWILLING_TO_PERFORM || ret == LDAP_CONSTRAINT_VIOLATION) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Insufficient permissions to modify computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't create computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Created computer account: %s", enroll->computer_dn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static int
Packit Service 6d40f9
filter_for_necessary_updates (adcli_enroll *enroll,
Packit Service 6d40f9
                              LDAP *ldap,
Packit Service 6d40f9
                              LDAPMessage *entry,
Packit Service 6d40f9
                              LDAPMod **mods)
Packit Service 6d40f9
{
Packit Service 6d40f9
	struct berval **vals;
Packit Service 6d40f9
	int match;
Packit Service 6d40f9
	int out;
Packit Service 6d40f9
	int in;
Packit Service 6d40f9
Packit Service 6d40f9
	for (in = 0, out = 0; mods[in] != NULL; in++) {
Packit Service 6d40f9
		match = 0;
Packit Service 6d40f9
Packit Service 6d40f9
		/* Never update these attributes */
Packit Service 6d40f9
		if (strcasecmp (mods[in]->mod_type, "objectClass") == 0)
Packit Service 6d40f9
			continue;
Packit Service 6d40f9
Packit Service 6d40f9
		/* If no entry, then no filtering */
Packit Service 6d40f9
		if (entry != NULL) {
Packit Service 6d40f9
			vals = ldap_get_values_len (ldap, entry, mods[in]->mod_type);
Packit Service 6d40f9
			if (vals != NULL) {
Packit Service 6d40f9
				match = _adcli_ldap_have_in_mod (mods[in], vals);
Packit Service 6d40f9
				ldap_value_free_len (vals);
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		if (!match)
Packit Service 6d40f9
			mods[out++] = mods[in];
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	mods[out] = NULL;
Packit Service 6d40f9
	return out;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
validate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                           int allow_overwrite,
Packit Service 6d40f9
                           int already_exists)
Packit Service 6d40f9
{
Packit Service 6d40f9
	assert (enroll->computer_dn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (already_exists && !allow_overwrite) {
Packit Service 6d40f9
		_adcli_err ("The computer account %s already exists",
Packit Service 6d40f9
		            enroll->computer_name);
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Do we have an explicitly requested ou? */
Packit Service 6d40f9
	if (enroll->domain_ou && enroll->domain_ou_explicit && already_exists) {
Packit Service 6d40f9
		if (!_adcli_ldap_dn_has_ancestor (enroll->computer_dn, enroll->domain_ou)) {
Packit Service 6d40f9
			_adcli_err ("The computer account %s already exists, "
Packit Service 6d40f9
			            "but is not in the desired organizational unit.",
Packit Service 6d40f9
			            enroll->computer_name);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
delete_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                         LDAP *ldap)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_delete_ext_s (ldap, enroll->computer_dn, NULL, NULL);
Packit Service 6d40f9
	if (ret == LDAP_INSUFFICIENT_ACCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Insufficient permissions to delete computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't delete computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_info ("Deleted computer account at: %s", enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
locate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                         LDAP *ldap,
Packit Service 6d40f9
                         LDAPMessage **rresults,
Packit Service 6d40f9
                         LDAPMessage **rentry)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *attrs[] = { "1.1", NULL };
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	const char *base;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	char *filter;
Packit Service 6d40f9
	char *dn;
Packit Service 6d40f9
	int ret = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	/* If we don't yet know our computer dn, then try and find it */
Packit Service 6d40f9
	value = _adcli_ldap_escape_filter (enroll->computer_sam);
Packit Service 6d40f9
	return_unexpected_if_fail (value != NULL);
Packit Service 6d40f9
	if (asprintf (&filter, "(&(objectClass=computer)(sAMAccountName=%s))", value) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
	free (value);
Packit Service 6d40f9
Packit Service 6d40f9
	base = adcli_conn_get_default_naming_context (enroll->conn);
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_SUB, filter, attrs, 0,
Packit Service 6d40f9
	                         NULL, NULL, NULL, 1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	free (filter);
Packit Service 6d40f9
Packit Service 6d40f9
	/* ldap_search_ext_s() can return results *and* an error. */
Packit Service 6d40f9
	if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
		entry = ldap_first_entry (ldap, results);
Packit Service 6d40f9
Packit Service 6d40f9
		/* If we found a computer account, make note of dn */
Packit Service 6d40f9
		if (entry) {
Packit Service 6d40f9
			dn = ldap_get_dn (ldap, entry);
Packit Service 6d40f9
			free (enroll->computer_dn);
Packit Service 6d40f9
			enroll->computer_dn = strdup (dn);
Packit Service 6d40f9
			return_unexpected_if_fail (enroll->computer_dn != NULL);
Packit Service 6d40f9
			_adcli_info ("Found computer account for %s at: %s",
Packit Service 6d40f9
			             enroll->computer_sam, dn);
Packit Service 6d40f9
			ldap_memfree (dn);
Packit Service 6d40f9
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			ldap_msgfree (results);
Packit Service 6d40f9
			results = NULL;
Packit Service 6d40f9
			_adcli_info ("Computer account for %s does not exist",
Packit Service 6d40f9
			             enroll->computer_sam);
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't lookup computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_sam);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (rresults)
Packit Service 6d40f9
		*rresults = results;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
	if (rentry) {
Packit Service 6d40f9
		assert (rresults != NULL);
Packit Service 6d40f9
		*rentry = entry;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
load_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                       LDAP *ldap,
Packit Service 6d40f9
                       LDAPMessage **rresults,
Packit Service 6d40f9
                       LDAPMessage **rentry)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *attrs[] = { "1.1", NULL };
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, enroll->computer_dn, LDAP_SCOPE_BASE,
Packit Service 6d40f9
	                         "(objectClass=computer)", attrs, 0,
Packit Service 6d40f9
	                         NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
		entry = ldap_first_entry (ldap, results);
Packit Service 6d40f9
		if (entry) {
Packit Service 6d40f9
			_adcli_info ("Found computer account for %s at: %s",
Packit Service 6d40f9
			             enroll->computer_sam, enroll->computer_dn);
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret == LDAP_NO_SUCH_OBJECT) {
Packit Service 6d40f9
		results = entry = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't check computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (rresults)
Packit Service 6d40f9
		*rresults = results;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
	if (rentry) {
Packit Service 6d40f9
		assert (rresults != NULL);
Packit Service 6d40f9
		*rentry = entry;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
locate_or_create_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                                   int allow_overwrite)
Packit Service 6d40f9
{
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	int searched = 0;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Try to find the computer account */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service 6d40f9
		res = locate_computer_account (enroll, ldap, &results, &entry);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
		searched = 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Next try and come up with where we think it should be */
Packit Service 6d40f9
	if (enroll->computer_dn == NULL) {
Packit Service 6d40f9
		res = calculate_computer_account (enroll, ldap);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_dn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Have we seen an account yet? */
Packit Service 6d40f9
	if (!searched) {
Packit Service 6d40f9
		res = load_computer_account (enroll, ldap, &results, &entry);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	res = validate_computer_account (enroll, allow_overwrite, entry != NULL);
Packit Service 6d40f9
	if (res == ADCLI_SUCCESS && entry == NULL)
Packit Service 6d40f9
		res = create_computer_account (enroll, ldap);
Packit Service 6d40f9
Packit Service 6d40f9
	if (results)
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
set_password_with_user_creds (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_ccache ccache;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_data result_string = { 0, };
Packit Service 6d40f9
	krb5_data result_code_string = { 0, };
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	int result_code;
Packit Service 6d40f9
	char *message;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_password != NULL);
Packit Service 6d40f9
	assert (enroll->computer_principal != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ccache = adcli_conn_get_login_ccache (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (ccache != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&result_string, 0, sizeof (result_string));
Packit Service 6d40f9
	memset (&result_code_string, 0, sizeof (result_code_string));
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_set_password_using_ccache (k5, ccache, enroll->computer_password,
Packit Service 6d40f9
	                                       enroll->computer_principal, &result_code,
Packit Service 6d40f9
	                                       &result_code_string, &result_string);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code != 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't set password for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		/* TODO: Parse out these values */
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (result_code != 0) {
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		if (krb5_chpw_message (k5, &result_string, &message) != 0)
Packit Service 6d40f9
			message = NULL;
Packit Service 6d40f9
#else
Packit Service 6d40f9
		message = NULL;
Packit Service 6d40f9
		if (result_string.length)
Packit Service 6d40f9
			message = _adcli_str_dupn (result_string.data, result_string.length);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
		_adcli_err ("Cannot set computer password: %.*s%s%s",
Packit Service 6d40f9
		            (int)result_code_string.length, result_code_string.data,
Packit Service 6d40f9
		            message ? ": " : "", message ? message : "");
Packit Service 6d40f9
		res = ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		krb5_free_string (k5, message);
Packit Service 6d40f9
#else
Packit Service 6d40f9
		free (message);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_info ("Set computer password");
Packit Service 75a4ad
		if (enroll->kvno > 0) {
Packit Service 75a4ad
			enroll->kvno++;
Packit Service 75a4ad
			_adcli_info ("kvno incremented to %d", enroll->kvno);
Packit Service 75a4ad
		}
Packit Service 6d40f9
		res = ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_string);
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_code_string);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
set_password_with_computer_creds (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_creds creds;
Packit Service 6d40f9
	krb5_data result_string = { 0, };
Packit Service 6d40f9
	krb5_data result_code_string = { 0, };
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	int result_code;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	char *message;
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&creds, 0, sizeof (creds));
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_kinit_computer_creds (enroll->conn, "kadmin/changepw", NULL, &creds);
Packit Service 6d40f9
	if (code != 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't get change password ticket for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_change_password (k5, &creds, enroll->computer_password,
Packit Service 6d40f9
	                             &result_code, &result_code_string, &result_string);
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_cred_contents (k5, &creds);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code != 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't change password for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		/* TODO: Parse out these values */
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (result_code != 0) {
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		if (krb5_chpw_message (k5, &result_string, &message) != 0)
Packit Service 6d40f9
			message = NULL;
Packit Service 6d40f9
#else
Packit Service 6d40f9
		message = NULL;
Packit Service 6d40f9
		if (result_string.length)
Packit Service 6d40f9
			message = _adcli_str_dupn (result_string.data, result_string.length);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
		_adcli_err ("Cannot change computer password: %.*s%s%s",
Packit Service 6d40f9
		            (int)result_code_string.length, result_code_string.data,
Packit Service 6d40f9
		            message ? ": " : "", message ? message : "");
Packit Service 6d40f9
		res = ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		krb5_free_string (k5, message);
Packit Service 6d40f9
#else
Packit Service 6d40f9
		free (message);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_info ("Changed computer password");
Packit Service 6d40f9
		if (enroll->kvno > 0) {
Packit Service 6d40f9
			enroll->kvno++;
Packit Service 6d40f9
		        _adcli_info ("kvno incremented to %d", enroll->kvno);
Packit Service 6d40f9
		}
Packit Service 6d40f9
		res = ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_string);
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_code_string);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
set_computer_password (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (adcli_conn_get_login_type (enroll->conn) == ADCLI_LOGIN_COMPUTER_ACCOUNT)
Packit Service 6d40f9
		return set_password_with_computer_creds (enroll);
Packit Service 6d40f9
	else
Packit Service 6d40f9
		return set_password_with_user_creds (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
retrieve_computer_account (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	unsigned long kvno;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	char *end;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	char *attrs[] =  {
Packit Service 6d40f9
		"msDS-KeyVersionNumber",
Packit Service 6d40f9
		"msDS-supportedEncryptionTypes",
Packit Service 6d40f9
		"dNSHostName",
Packit Service 6d40f9
		"servicePrincipalName",
Packit Service 6d40f9
		"operatingSystem",
Packit Service 6d40f9
		"operatingSystemVersion",
Packit Service 6d40f9
		"operatingSystemServicePack",
Packit Service 6d40f9
		"pwdLastSet",
Packit Service 8ee766
		"userAccountControl",
Packit Service 6d40f9
		NULL,
Packit Service 6d40f9
	};
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_dn != NULL);
Packit Service 6d40f9
	assert (enroll->computer_attributes == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, enroll->computer_dn, LDAP_SCOPE_BASE,
Packit Service 6d40f9
	                         "(objectClass=*)", attrs, 0, NULL, NULL, NULL, -1,
Packit Service 6d40f9
	                         &enroll->computer_attributes);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't retrieve computer account info: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Update the kvno */
Packit Service 6d40f9
	if (enroll->kvno == 0) {
Packit Service 6d40f9
		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "msDS-KeyVersionNumber");
Packit Service 6d40f9
		if (value != NULL) {
Packit Service 6d40f9
			kvno = strtoul (value, &end, 10);
Packit Service 6d40f9
			if (end == NULL || *end != '\0') {
Packit Service 6d40f9
				_adcli_err ("Invalid kvno '%s' for computer account in directory: %s",
Packit Service 6d40f9
				            value, enroll->computer_dn);
Packit Service 6d40f9
				res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
			} else {
Packit Service 6d40f9
				enroll->kvno = kvno;
Packit Service 6d40f9
Packit Service 6d40f9
				_adcli_info ("Retrieved kvno '%s' for computer account in directory: %s",
Packit Service 6d40f9
				             value, enroll->computer_dn);
Packit Service 6d40f9
			}
Packit Service 6d40f9
Packit Service 6d40f9
			free (value);
Packit Service 6d40f9
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			/* Apparently old AD didn't have this attribute, use zero */
Packit Service 6d40f9
			enroll->kvno = 0;
Packit Service 6d40f9
Packit Service 6d40f9
			_adcli_info ("No kvno found for computer account in directory: %s",
Packit Service 6d40f9
			             enroll->computer_dn);
Packit Service 6d40f9
		}
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
update_and_calculate_enctypes (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *vals_supportedEncryptionTypes[] = { NULL, NULL };
Packit Service 6d40f9
	LDAPMod mod = { LDAP_MOD_REPLACE, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
Packit Service 6d40f9
	LDAPMod *mods[2] = { &mod, NULL };
Packit Service 6d40f9
	char *new_value;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (ldap != NULL);
Packit Service 6d40f9
Packit Service 6596aa
	ret = calculate_enctypes (enroll, &new_value);
Packit Service 6596aa
	if (ret != ADCLI_SUCCESS) {
Packit Service 6d40f9
		free (new_value);
Packit Service 6596aa
		return ret;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6596aa
	if (new_value == NULL) {
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	vals_supportedEncryptionTypes[0] = new_value;
Packit Service 6d40f9
Packit Service 6d40f9
	if (filter_for_necessary_updates (enroll, ldap, enroll->computer_attributes, mods) == 0)
Packit Service 6d40f9
		ret = 0;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	free (new_value);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_INSUFFICIENT_ACCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Insufficient permissions to set encryption types on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't set encryption types on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
update_computer_attribute (adcli_enroll *enroll,
Packit Service 6d40f9
                           LDAP *ldap,
Packit Service 6d40f9
                           LDAPMod **mods)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	char *string;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	/* See if there are any changes to be made? */
Packit Service 6d40f9
	if (filter_for_necessary_updates (enroll, ldap, enroll->computer_attributes, mods) == 0)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	string = _adcli_ldap_mods_to_string (mods);
Packit Service 6d40f9
	return_unexpected_if_fail (string != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Modifying computer account: %s", string);
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		_adcli_warn ("Couldn't set %s on computer account: %s: %s",
Packit Service 6d40f9
		             string, enroll->computer_dn, ldap_err2string (ret));
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (string);
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 8ee766
static char *get_user_account_control (adcli_enroll *enroll)
Packit Service 8ee766
{
Packit Service 8ee766
	uint32_t uac = 0;
Packit Service 8ee766
	unsigned long attr_val;
Packit Service 8ee766
	char *uac_str;
Packit Service 8ee766
	LDAP *ldap;
Packit Service 8ee766
	char *end;
Packit Service 8ee766
Packit Service 8ee766
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 8ee766
	return_val_if_fail (ldap != NULL, NULL);
Packit Service 8ee766
Packit Service 8ee766
	uac_str = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "userAccountControl");
Packit Service 8ee766
	if (uac_str != NULL) {
Packit Service 8ee766
Packit Service 8ee766
		attr_val = strtoul (uac_str, &end, 10);
Packit Service 8ee766
		if (*end != '\0' || attr_val > UINT32_MAX) {
Packit Service 8ee766
			_adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0",
Packit Service 8ee766
			            uac_str, enroll->computer_dn);
Packit Service 8ee766
		} else {
Packit Service 8ee766
			uac = attr_val;
Packit Service 8ee766
		}
Packit Service 8ee766
		free (uac_str);
Packit Service 8ee766
	}
Packit Service 8ee766
Packit Service 8ee766
	if (uac == 0) {
Packit Service 8ee766
		uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD;
Packit Service 8ee766
	}
Packit Service 8ee766
Packit Service 8ee766
	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
Packit Service 8ee766
		uac |= UAC_TRUSTED_FOR_DELEGATION;
Packit Service 8ee766
	} else {
Packit Service 8ee766
		uac &= ~(UAC_TRUSTED_FOR_DELEGATION);
Packit Service 8ee766
	}
Packit Service 8ee766
Packit Service 8ee766
	if (asprintf (&uac_str, "%d", uac) < 0) {
Packit Service 8ee766
		return_val_if_reached (NULL);
Packit Service 8ee766
	}
Packit Service 8ee766
Packit Service 8ee766
	return uac_str;
Packit Service 8ee766
}
Packit Service 8ee766
Packit Service 6d40f9
static void
Packit Service 6d40f9
update_computer_account (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int res = 0;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	return_if_fail (ldap != NULL);
Packit Service 6d40f9
Packit Service 268540
	/* Only update attributes which are explicitly given on the command
Packit Service 268540
	 * line. Otherwise 'adcli update' must be always called with the same
Packit Service 268540
	 * set of options to make sure existing attributes are not deleted or
Packit Service 268540
	 * overwritten with different values. */
Packit Service 268540
	if (enroll->host_fqdn_explicit) {
Packit Service 6d40f9
		char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
Packit Service 6d40f9
		LDAPMod dNSHostName = { LDAP_MOD_REPLACE, "dNSHostName", { vals_dNSHostName, } };
Packit Service 6d40f9
		LDAPMod *mods[] = { &dNSHostName, NULL };
Packit Service 6d40f9
Packit Service 6d40f9
		res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 268540
	if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) {
Packit Service 8ee766
		char *vals_userAccountControl[] = { NULL , NULL };
Packit Service 6d40f9
		LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
Packit Service 6d40f9
		LDAPMod *mods[] = { &userAccountControl, NULL };
Packit Service 6d40f9
Packit Service 8ee766
		vals_userAccountControl[0] = get_user_account_control (enroll);
Packit Service 8ee766
		if (vals_userAccountControl[0] != NULL) {
Packit Service 8ee766
			res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 8ee766
		} else {
Packit Service 8ee766
			_adcli_warn ("Cannot update userAccountControl");
Packit Service 8ee766
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (res == ADCLI_SUCCESS) {
Packit Service 6d40f9
		char *vals_operatingSystem[] = { enroll->os_name, NULL };
Packit Service 6d40f9
		LDAPMod operatingSystem = { LDAP_MOD_REPLACE, "operatingSystem", { vals_operatingSystem, } };
Packit Service 6d40f9
		char *vals_operatingSystemVersion[] = { enroll->os_version, NULL };
Packit Service 6d40f9
		LDAPMod operatingSystemVersion = { LDAP_MOD_REPLACE, "operatingSystemVersion", { vals_operatingSystemVersion, } };
Packit Service 6d40f9
		char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
Packit Service 6d40f9
		LDAPMod operatingSystemServicePack = { LDAP_MOD_REPLACE, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
Packit Service 268540
		LDAPMod *mods[] = { NULL, NULL, NULL, NULL };
Packit Service 268540
		size_t c = 0;
Packit Service 6d40f9
Packit Service 268540
		if (enroll->os_name_explicit) {
Packit Service 268540
			mods[c++] = &operatingSystem;
Packit Service 268540
		}
Packit Service 268540
		if (enroll->os_version_explicit) {
Packit Service 268540
			mods[c++] = &operatingSystemVersion;
Packit Service 268540
		}
Packit Service 268540
		if (enroll->os_service_pack_explicit) {
Packit Service 268540
			mods[c++] = &operatingSystemServicePack;
Packit Service 268540
		}
Packit Service 268540
Packit Service 268540
		if (c != 0) {
Packit Service 268540
			res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 268540
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service f6a102
	if (res == ADCLI_SUCCESS && enroll->user_principal != NULL && !enroll->user_princpal_generate) {
Packit Service 6d40f9
		char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
Packit Service 6d40f9
		LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
Packit Service 6d40f9
		LDAPMod *mods[] = { &userPrincipalName, NULL, };
Packit Service 6d40f9
Packit Service 6d40f9
		res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != 0)
Packit Service 6d40f9
		_adcli_info ("Updated existing computer account: %s", enroll->computer_dn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
update_service_principals (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	LDAPMod servicePrincipalName = { LDAP_MOD_REPLACE, "servicePrincipalName", { enroll->service_principals, } };
Packit Service 6d40f9
	LDAPMod *mods[] = { &servicePrincipalName, NULL, };
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* See if there are any changes to be made? */
Packit Service 6d40f9
	if (filter_for_necessary_updates (enroll, ldap, enroll->computer_attributes, mods) == 0)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 6d40f9
	if (ret == LDAP_INSUFFICIENT_ACCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Insufficient permissions to set service principals on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't set service principals on computer account %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_host_keytab (adcli_result res,
Packit Service 6d40f9
                    adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->keytab)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	res = _adcli_krb5_open_keytab (k5, enroll->keytab_name, &enroll->keytab);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->keytab_name) {
Packit Service 6d40f9
		name = malloc (MAX_KEYTAB_NAME_LEN + 1);
Packit Service 6d40f9
		return_unexpected_if_fail (name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		code = krb5_kt_get_name (k5, enroll->keytab, name, MAX_KEYTAB_NAME_LEN + 1);
Packit Service 6d40f9
		return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
		enroll->keytab_name = name;
Packit Service 6d40f9
		enroll->keytab_name_is_krb5 = 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Using keytab: %s", enroll->keytab_name);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static krb5_boolean
Packit Service 6d40f9
load_keytab_entry (krb5_context k5,
Packit Service 6d40f9
                   krb5_keytab_entry *entry,
Packit Service 6d40f9
                   void *data)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_enroll *enroll = data;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_principal principal;
Packit Service 6d40f9
	const char *realm;
Packit Service 6d40f9
	size_t len;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Skip over any entry without a principal or realm */
Packit Service 6d40f9
	principal = entry->principal;
Packit Service 6d40f9
	if (!principal || !principal->realm.length)
Packit Service 6d40f9
		return TRUE;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the first keytab entry as realm */
Packit Service 6d40f9
	realm = adcli_conn_get_domain_realm (enroll->conn);
Packit Service 6d40f9
	if (!realm) {
Packit Service 6d40f9
		value = _adcli_str_dupn (principal->realm.data, principal->realm.length);
Packit Service 6d40f9
		adcli_conn_set_domain_realm (enroll->conn, value);
Packit Service 6d40f9
		_adcli_info ("Found realm in keytab: %s", value);
Packit Service 6d40f9
		realm = adcli_conn_get_domain_realm (enroll->conn);
Packit Service 6d40f9
		free (value);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Only look at entries that match the realm */
Packit Service 6d40f9
	len = strlen (realm);
Packit Service 6d40f9
	if (principal->realm.length != len && strncmp (realm, principal->realm.data, len) != 0)
Packit Service 6d40f9
		return TRUE;
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_unparse_name_flags (k5, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
Packit Service 6d40f9
	return_val_if_fail (code == 0, FALSE);
Packit Service 6d40f9
Packit Service 6d40f9
	len = strlen (name);
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->service_principals_explicit) {
Packit Service 6d40f9
		if (!_adcli_strv_has (enroll->service_principals, name) && strchr (name, '/')) {
Packit Service 6d40f9
			value = strdup (name);
Packit Service 6d40f9
			return_val_if_fail (value != NULL, FALSE);
Packit Service 6d40f9
			_adcli_info ("Found service principal in keytab: %s", value);
Packit Service e72923
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, value, NULL, false);
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->host_fqdn_explicit && !enroll->computer_name_explicit) {
Packit Service 6d40f9
Packit Service 6d40f9
		/* Automatically use the netbios name */
Packit Service e64910
		if (!enroll->computer_name && len > 1 &&
Packit Service 6d40f9
		    _adcli_str_has_suffix (name, "$") && !strchr (name, '/')) {
Packit Service 6d40f9
			enroll->computer_name = name;
Packit Service 6d40f9
			name[len - 1] = '\0';
Packit Service 6d40f9
			_adcli_info ("Found computer name in keytab: %s", name);
Packit Service 6d40f9
			name = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
		} else if (!enroll->host_fqdn && _adcli_str_has_prefix (name, "host/") && strchr (name, '.')) {
Packit Service 6d40f9
			/* Skip host/ prefix */
Packit Service 235f23
			enroll->host_fqdn = strdup (name + 5);
Packit Service 235f23
			return_val_if_fail (enroll->host_fqdn != NULL, FALSE);
Packit Service 235f23
			_adcli_info ("Found host qualified name in keytab: %s", enroll->host_fqdn);
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (name);
Packit Service 6d40f9
	return TRUE;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
load_host_keytab (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_keytab keytab;
Packit Service 6d40f9
Packit Service 6d40f9
	res = _adcli_krb5_init_context (&k5;;
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	res = _adcli_krb5_open_keytab (k5, enroll->keytab_name, &keytab);
Packit Service 6d40f9
	if (res == ADCLI_SUCCESS) {
Packit Service 6d40f9
		code = _adcli_krb5_keytab_enumerate (k5, keytab, load_keytab_entry, enroll);
Packit Service 6d40f9
		if (code != 0) {
Packit Service 6d40f9
			_adcli_err ("Couldn't enumerate keytab: %s: %s",
Packit Service 6d40f9
		                    enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 6d40f9
			res = ADCLI_ERR_FAIL;
Packit Service 6d40f9
		}
Packit Service 6d40f9
		krb5_kt_close (k5, keytab);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_context (k5);
Packit Service 3bcf73
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
typedef struct {
Packit Service 6d40f9
	krb5_kvno kvno;
Packit Service 6d40f9
	krb5_principal principal;
Packit Service 6d40f9
	int matched;
Packit Service 6d40f9
} match_principal_kvno;
Packit Service 6d40f9
Packit Service 6d40f9
static krb5_boolean
Packit Service 6d40f9
match_principal_and_kvno (krb5_context k5,
Packit Service 6d40f9
                          krb5_keytab_entry *entry,
Packit Service 6d40f9
                          void *data)
Packit Service 6d40f9
{
Packit Service 6d40f9
	match_principal_kvno *closure = data;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (closure->principal);
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * Don't match entries with kvno - 1 so that existing sessions
Packit Service 6d40f9
	 * will still work.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
Packit Service 6d40f9
	if (entry->vno + 1 == closure->kvno)
Packit Service 6d40f9
		return 0;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Is this the principal we're looking for? */
Packit Service 6d40f9
	if (krb5_principal_compare (k5, entry->principal, closure->principal)) {
Packit Service 6d40f9
		closure->matched = 1;
Packit Service 6d40f9
		return 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
#define DEFAULT_SALT 1
Packit Service 6d40f9
Packit Service 6d40f9
static krb5_data *
Packit Service 6d40f9
build_principal_salts (adcli_enroll *enroll,
Packit Service 6d40f9
                       krb5_context k5,
Packit Service 6d40f9
                       krb5_principal principal)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_data *salts;
Packit Service 6d40f9
	const int count = 3;
Packit Service 6d40f9
	int i = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	salts = calloc (count, sizeof (krb5_data));
Packit Service 6d40f9
	return_val_if_fail (salts != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Build up the salts, first a standard kerberos salt */
Packit Service 6d40f9
	code = krb5_principal2salt (k5, principal, &salts[i++]);
Packit Service 6d40f9
	return_val_if_fail (code == 0, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Then a Windows 2003 computer account salt */
Packit Service 6d40f9
	code = _adcli_krb5_w2k3_salt (k5, principal, enroll->computer_name, &salts[i++]);
Packit Service 6d40f9
	return_val_if_fail (code == 0, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* And lastly a null salt */
Packit Service 6d40f9
	salts[i++].data = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (count == i);
Packit Service 6d40f9
	return salts;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
free_principal_salts (krb5_context k5,
Packit Service 6d40f9
                      krb5_data *salts)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	for (i = 0; salts[i].data != NULL; i++)
Packit Service 6d40f9
		krb5_free_data_contents (k5, salts + i);
Packit Service 6d40f9
Packit Service 6d40f9
	free (salts);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6213b5
remove_principal_from_keytab (adcli_enroll *enroll,
Packit Service 6213b5
                              krb5_context k5,
Packit Service 6213b5
                              const char *principal_name)
Packit Service 6213b5
{
Packit Service 6213b5
	krb5_error_code code;
Packit Service 6213b5
	krb5_principal principal;
Packit Service 6213b5
	match_principal_kvno closure;
Packit Service 6213b5
Packit Service 6da924
	code = _adcli_krb5_build_principal (k5, principal_name,
Packit Service 6da924
	                                    adcli_conn_get_domain_realm (enroll->conn),
Packit Service 6da924
	                                    &principal);
Packit Service 6213b5
	if (code != 0) {
Packit Service 6213b5
		_adcli_err ("Couldn't parse principal: %s: %s",
Packit Service 6213b5
		            principal_name, krb5_get_error_message (k5, code));
Packit Service 6213b5
		return ADCLI_ERR_FAIL;
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	closure.kvno = enroll->kvno;
Packit Service 6213b5
	closure.principal = principal;
Packit Service 6213b5
	closure.matched = 0;
Packit Service 6213b5
Packit Service 6213b5
	code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
Packit Service 6213b5
	                                 match_principal_and_kvno, &closure);
Packit Service 6213b5
	krb5_free_principal (k5, principal);
Packit Service 6213b5
Packit Service 6213b5
	if (code != 0) {
Packit Service 6213b5
		_adcli_err ("Couldn't update keytab: %s: %s",
Packit Service 6213b5
		            enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 6213b5
		return ADCLI_ERR_FAIL;
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6213b5
	return ADCLI_SUCCESS;
Packit Service 6213b5
}
Packit Service 6213b5
Packit Service 6213b5
static adcli_result
Packit Service 6d40f9
add_principal_to_keytab (adcli_enroll *enroll,
Packit Service 6d40f9
                         krb5_context k5,
Packit Service 6d40f9
                         krb5_principal principal,
Packit Service 6d40f9
                         const char *principal_name,
Packit Service f6a102
                         int *which_salt,
Packit Service f6a102
                         adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	match_principal_kvno closure;
Packit Service 6d40f9
	krb5_data password;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_data *salts;
Packit Service 6d40f9
	krb5_enctype *enctypes;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Remove old stuff from the keytab for this principal */
Packit Service 6d40f9
Packit Service 6d40f9
	closure.kvno = enroll->kvno;
Packit Service 6d40f9
	closure.principal = principal;
Packit Service 6d40f9
	closure.matched = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
Packit Service 6d40f9
	                                 match_principal_and_kvno, &closure);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code != 0) {
Packit Service 6d40f9
		_adcli_err ("Couldn't update keytab: %s: %s",
Packit Service 6d40f9
		            enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		return ADCLI_ERR_FAIL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (closure.matched) {
Packit Service 6d40f9
		_adcli_info ("Cleared old entries from keytab: %s",
Packit Service 6d40f9
		             enroll->keytab_name);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 7e2b15
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 7e2b15
	if (enctypes == NULL) {
Packit Service 7e2b15
		_adcli_warn ("No permitted encryption type found.");
Packit Service 7e2b15
		return ADCLI_ERR_UNEXPECTED;
Packit Service 7e2b15
	}
Packit Service 6d40f9
Packit Service f6a102
	if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
Packit Service f6a102
		code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
Packit Service f6a102
		                                        enroll->kvno, enctypes);
Packit Service f6a102
	} else {
Packit Service 6d40f9
Packit Service f6a102
		password.data = enroll->computer_password;
Packit Service f6a102
		password.length = strlen (enroll->computer_password);
Packit Service 6d40f9
Packit Service f6a102
		/*
Packit Service f6a102
		 * So we need to discover which salt to use. As a side effect we are
Packit Service f6a102
		 * also testing that our account works.
Packit Service f6a102
		 */
Packit Service f6a102
Packit Service f6a102
		salts = build_principal_salts (enroll, k5, principal);
Packit Service 7e2b15
		if (salts == NULL) {
Packit Service 7e2b15
			krb5_free_enctypes (k5, enctypes);
Packit Service 7e2b15
			return ADCLI_ERR_UNEXPECTED;
Packit Service 7e2b15
		}
Packit Service f6a102
Packit Service f6a102
		if (*which_salt < 0) {
Packit Service f6a102
			code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
Packit Service f6a102
			                                         enctypes, salts, which_salt);
Packit Service f6a102
			if (code != 0) {
Packit Service f6a102
				_adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
Packit Service f6a102
				             principal_name, krb5_get_error_message (k5, code));
Packit Service f6a102
				*which_salt = DEFAULT_SALT;
Packit Service f6a102
			} else {
Packit Service f6a102
				assert (*which_salt >= 0);
Packit Service f6a102
				_adcli_info ("Discovered which keytab salt to use");
Packit Service f6a102
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service f6a102
		code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
Packit Service f6a102
		                                       enroll->kvno, &password, enctypes, &salts[*which_salt]);
Packit Service 6d40f9
Packit Service f6a102
		free_principal_salts (k5, salts);
Packit Service 3bcf73
	}
Packit Service 7e2b15
	krb5_free_enctypes (k5, enctypes);
Packit Service 6d40f9
Packit Service 3bcf73
	if (code != 0) {
Packit Service 3bcf73
		_adcli_err ("Couldn't add keytab entries: %s: %s",
Packit Service 3bcf73
		            enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 3bcf73
		return ADCLI_ERR_FAIL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Added the entries to the keytab: %s: %s",
Packit Service 6d40f9
	             principal_name, enroll->keytab_name);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service f6a102
update_keytab_for_principals (adcli_enroll *enroll,
Packit Service f6a102
                              adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	int which_salt = -1;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->keytab_principals != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	for (i = 0; enroll->keytab_principals[i] != 0; i++) {
Packit Service 6d40f9
		if (krb5_unparse_name (k5, enroll->keytab_principals[i], &name) != 0)
Packit Service 6d40f9
			name = "";
Packit Service 6d40f9
		res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i],
Packit Service f6a102
		                               name, &which_salt, flags);
Packit Service 6d40f9
		krb5_free_unparsed_name (k5, name);
Packit Service 6d40f9
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6213b5
	if (enroll->service_principals_to_remove != NULL) {
Packit Service 6213b5
		for (i = 0; enroll->service_principals_to_remove[i] != NULL; i++) {
Packit Service 6213b5
			res = remove_principal_from_keytab (enroll, k5,
Packit Service 6213b5
			                                    enroll->service_principals_to_remove[i]);
Packit Service 6213b5
			if (res != ADCLI_SUCCESS) {
Packit Service 6213b5
				_adcli_warn ("Failed to remove %s from keytab.",
Packit Service 6213b5
				             enroll->service_principals_to_remove[i]);
Packit Service 6213b5
			}
Packit Service 6213b5
		}
Packit Service 6213b5
	}
Packit Service 6213b5
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 3226d7
static adcli_result
Packit Service 3226d7
update_samba_data (adcli_enroll *enroll)
Packit Service 3226d7
{
Packit Service 3226d7
	int ret;
Packit Service a61006
	char *argv_pw[] = { NULL, "changesecretpw", "-i", "-f", NULL };
Packit Service a61006
	char *argv_sid[] = { NULL, "setdomainsid", NULL, NULL };
Packit Service a61006
Packit Service a61006
	argv_pw[0] = (char *) adcli_enroll_get_samba_data_tool (enroll);
Packit Service a61006
	if (argv_pw[0] ==NULL) {
Packit Service a61006
		_adcli_err ("Samba data tool not available.");
Packit Service a61006
		return ADCLI_ERR_FAIL;
Packit Service a61006
	}
Packit Service a61006
	argv_sid[0] = argv_pw[0];
Packit Service 3226d7
Packit Service a61006
	_adcli_info ("Trying to set Samba secret.");
Packit Service 3226d7
	ret = _adcli_call_external_program (argv_pw[0], argv_pw,
Packit Service 3226d7
	                                    enroll->computer_password, NULL, NULL);
Packit Service 3226d7
	if (ret != ADCLI_SUCCESS) {
Packit Service a61006
		_adcli_err ("Failed to set Samba computer account password.");
Packit Service 3226d7
	}
Packit Service 3226d7
Packit Service 3226d7
	argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
Packit Service 3226d7
	if (argv_sid[2] == NULL) {
Packit Service a61006
		_adcli_err ("Domain SID not available.");
Packit Service 3226d7
	} else {
Packit Service a61006
		_adcli_info ("Trying to set domain SID %s for Samba.",
Packit Service 3226d7
		             argv_sid[2]);
Packit Service 3226d7
		ret = _adcli_call_external_program (argv_sid[0], argv_sid,
Packit Service 3226d7
		                                    NULL, NULL, NULL);
Packit Service 3226d7
		if (ret != ADCLI_SUCCESS) {
Packit Service a61006
			_adcli_err ("Failed to set Samba domain SID.");
Packit Service 3226d7
		}
Packit Service 3226d7
	}
Packit Service 3226d7
Packit Service 3226d7
	return ret;
Packit Service 3226d7
}
Packit Service 3226d7
Packit Service 6d40f9
static void
Packit Service 6d40f9
enroll_clear_state (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
Packit Service e99966
	enroll_clear_keytab_principals (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->keytab) {
Packit Service 6d40f9
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
		return_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		krb5_kt_close (k5, enroll->keytab);
Packit Service 6d40f9
		enroll->keytab = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_sam);
Packit Service 6d40f9
	enroll->computer_sam = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_principal) {
Packit Service 6d40f9
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
		return_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		krb5_free_principal (k5, enroll->computer_principal);
Packit Service 6d40f9
		enroll->computer_principal = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->computer_password_explicit) {
Packit Service 6d40f9
		free (enroll->computer_password);
Packit Service 6d40f9
		enroll->computer_password = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_dn);
Packit Service 6d40f9
	enroll->computer_dn = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_container);
Packit Service 6d40f9
	enroll->computer_container = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->service_principals_explicit) {
Packit Service 6d40f9
		_adcli_strv_free (enroll->service_principals);
Packit Service 6d40f9
		enroll->service_principals = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->user_princpal_generate) {
Packit Service 6d40f9
		free (enroll->user_principal);
Packit Service 6d40f9
		enroll->user_principal = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->kvno = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_attributes) {
Packit Service 6d40f9
		ldap_msgfree (enroll->computer_attributes);
Packit Service 6d40f9
		enroll->computer_attributes = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->domain_ou_explicit) {
Packit Service 6d40f9
		free (enroll->domain_ou);
Packit Service 6d40f9
		enroll->domain_ou = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_prepare (adcli_enroll *enroll,
Packit Service 6d40f9
                      adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
Packit Service 6d40f9
	/* Basic discovery and figuring out enroll params */
Packit Service 6d40f9
	res = ensure_host_fqdn (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_name (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_sam (res, enroll);
Packit Service 6d40f9
	res = ensure_user_principal (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_password (res, enroll);
Packit Service 6d40f9
	if (!(flags & ADCLI_ENROLL_NO_KEYTAB))
Packit Service 6d40f9
		res = ensure_host_keytab (res, enroll);
Packit Service 6d40f9
	res = ensure_service_names (res, enroll);
Packit Service 6d40f9
	res = ensure_service_principals (res, enroll);
Packit Service 6d40f9
	res = ensure_keytab_principals (res, enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 9e68ad
add_server_side_service_principals (adcli_enroll *enroll)
Packit Service 9e68ad
{
Packit Service 9e68ad
	char **spn_list;
Packit Service 9e68ad
	LDAP *ldap;
Packit Service 9e68ad
	size_t c;
Packit Service 9e68ad
	int length = 0;
Packit Service 9e68ad
	adcli_result res;
Packit Service 9e68ad
Packit Service 9e68ad
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 9e68ad
	assert (ldap != NULL);
Packit Service 9e68ad
Packit Service 9e68ad
	spn_list = _adcli_ldap_parse_values (ldap, enroll->computer_attributes,
Packit Service 9e68ad
	                                     "servicePrincipalName");
Packit Service 9e68ad
	if (spn_list == NULL) {
Packit Service 9e68ad
		return ADCLI_SUCCESS;
Packit Service 9e68ad
	}
Packit Service 9e68ad
Packit Service 9e68ad
	if (enroll->service_principals != NULL) {
Packit Service 9e68ad
		length = seq_count (enroll->service_principals);
Packit Service 9e68ad
	}
Packit Service 9e68ad
Packit Service 9e68ad
	for (c = 0; spn_list[c] != NULL; c++) {
Packit Service 9e68ad
		_adcli_info ("Checking %s", spn_list[c]);
Packit Service 9e68ad
		if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
Packit Service 9e68ad
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service f3e799
			                                                     strdup (spn_list[c]),
Packit Service f3e799
			                                                     &length, false);
Packit Service 9e68ad
			assert (enroll->service_principals != NULL);
Packit Service 9e68ad
			_adcli_info ("   Added %s", spn_list[c]);
Packit Service 9e68ad
		}
Packit Service 9e68ad
	}
Packit Service 9e68ad
	_adcli_strv_free (spn_list);
Packit Service 9e68ad
Packit Service 9e68ad
	res = ensure_keytab_principals (ADCLI_SUCCESS, enroll);
Packit Service 9e68ad
	if (res != ADCLI_SUCCESS) {
Packit Service 9e68ad
		return res;
Packit Service 9e68ad
	}
Packit Service 9e68ad
Packit Service 9e68ad
	return ADCLI_SUCCESS;
Packit Service 9e68ad
}
Packit Service 9e68ad
Packit Service 9e68ad
static adcli_result
Packit Service 6d40f9
enroll_join_or_update_tasks (adcli_enroll *enroll,
Packit Service 6d40f9
		             adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 966232
	krb5_kvno old_kvno = -1;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!(flags & ADCLI_ENROLL_PASSWORD_VALID)) {
Packit Service 966232
Packit Service 966232
		/* Handle kvno changes for read-only domain controllers
Packit Service 966232
		 * (RODC). Since the actual password change does not happen on
Packit Service 966232
		 * the RODC the kvno change has to be replicated back which
Packit Service 966232
		 * might take some time. So we check the kvno before and after
Packit Service 966232
		 * the change if we are connected to a RODC and increment the
Packit Service 966232
		 * kvno if needed. */
Packit Service 966232
		if (!adcli_conn_is_writeable (enroll->conn)) {
Packit Service 966232
			if (enroll->computer_attributes == NULL) {
Packit Service 966232
				res = retrieve_computer_account (enroll);
Packit Service 966232
				if (res != ADCLI_SUCCESS)
Packit Service 966232
					return res;
Packit Service 966232
			}
Packit Service 966232
			old_kvno = adcli_enroll_get_kvno (enroll);
Packit Service 966232
			_adcli_info ("Found old kvno '%d'", old_kvno);
Packit Service 966232
Packit Service 966232
			ldap_msgfree (enroll->computer_attributes);
Packit Service 966232
			enroll->computer_attributes = NULL;
Packit Service 966232
			adcli_enroll_set_kvno (enroll, 0);
Packit Service 966232
		}
Packit Service 966232
Packit Service 6d40f9
		res = set_computer_password (enroll);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* kvno is not needed if no keytab */
Packit Service 6d40f9
	if (flags & ADCLI_ENROLL_NO_KEYTAB)
Packit Service 6d40f9
		enroll->kvno = -1;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Get information about the computer account if needed */
Packit Service 6d40f9
	if (enroll->computer_attributes == NULL) {
Packit Service 6d40f9
		res = retrieve_computer_account (enroll);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 966232
	/* Handle kvno changes for read-only domain controllers (RODC) */
Packit Service 966232
	if (!adcli_conn_is_writeable (enroll->conn) && old_kvno != -1 &&
Packit Service 966232
	    adcli_enroll_get_kvno (enroll) != 0 &&
Packit Service 966232
	    adcli_enroll_get_kvno (enroll) == old_kvno) {
Packit Service 966232
		enroll->kvno++;
Packit Service 966232
		_adcli_info ("No kvno change detected on read-only DC,  kvno "
Packit Service 966232
		             "will be incremented by 1 to '%d'", enroll->kvno);
Packit Service 966232
	}
Packit Service 966232
Packit Service 6d40f9
	/* We ignore failures of setting these fields */
Packit Service 6d40f9
	update_and_calculate_enctypes (enroll);
Packit Service 6d40f9
	update_computer_account (enroll);
Packit Service f6a102
Packit Service 9e68ad
	res = add_server_side_service_principals (enroll);
Packit Service 9e68ad
	if (res != ADCLI_SUCCESS) {
Packit Service 9e68ad
		return res;
Packit Service 9e68ad
	}
Packit Service 9e68ad
Packit Service f6a102
	/* service_names is only set from input on the command line, so no
Packit Service f6a102
	 * additional check for explicit is needed here */
Packit Service f6a102
	if (enroll->service_names != NULL) {
Packit Service f6a102
		res = add_service_names_to_service_principals (enroll);
Packit Service f6a102
		if (res != ADCLI_SUCCESS) {
Packit Service f6a102
			return res;
Packit Service f6a102
		}
Packit Service f6a102
		res = ensure_keytab_principals (res, enroll);
Packit Service f6a102
		if (res != ADCLI_SUCCESS) {
Packit Service f6a102
			return res;
Packit Service f6a102
		}
Packit Service f6a102
	}
Packit Service f6a102
Packit Service 6d40f9
	update_service_principals (enroll);
Packit Service 6d40f9
Packit Service 3226d7
	if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
Packit Service 3226d7
		res = update_samba_data (enroll);
Packit Service 3226d7
		if (res != ADCLI_SUCCESS) {
Packit Service 3226d7
			_adcli_info ("Failed to add Samba specific data, smbd "
Packit Service 3226d7
			             "or winbindd might not work as "
Packit Service 3226d7
			             "expected.\n");
Packit Service 3226d7
		}
Packit Service 3226d7
	}
Packit Service 3226d7
Packit Service 6d40f9
	if (flags & ADCLI_ENROLL_NO_KEYTAB)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * Salting in the keytab is wild, we need to autodetect the format
Packit Service 6d40f9
	 * that we use for salting.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
Packit Service f6a102
	return update_keytab_for_principals (enroll, flags);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_join (adcli_enroll *enroll,
Packit Service 6d40f9
                   adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (enroll->conn);
Packit Service ea525b
	if (res != ADCLI_SUCCESS)
Packit Service ea525b
		return res;
Packit Service ea525b
Packit Service ea525b
	res = ensure_default_service_names (enroll);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_enroll_prepare (enroll, flags);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* This is where it really happens */
Packit Service 6d40f9
	res = locate_or_create_computer_account (enroll, flags & ADCLI_ENROLL_ALLOW_OVERWRITE);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	return enroll_join_or_update_tasks (enroll, flags);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_load (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
Packit Service 6d40f9
	/* Load default info from keytab */
Packit Service 6d40f9
	res = load_host_keytab (enroll);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_name)
Packit Service 6d40f9
		enroll->computer_name_explicit = 1;
Packit Service 6d40f9
	if (enroll->host_fqdn)
Packit Service 6d40f9
		enroll->host_fqdn_explicit = 1;
Packit Service 6d40f9
	if (enroll->service_principals)
Packit Service 6d40f9
		enroll->service_principals_explicit = 1;
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_update (adcli_enroll *enroll,
Packit Service 6d40f9
		     adcli_enroll_flags flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (enroll->conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_enroll_prepare (enroll, flags);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Find the computer dn */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service 6d40f9
		res = locate_computer_account (enroll, ldap, NULL, NULL);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
		if (!enroll->computer_dn) {
Packit Service 6d40f9
			_adcli_err ("No computer account for %s exists", enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Get information about the computer account */
Packit Service 6d40f9
	res = retrieve_computer_account (enroll);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	value = _adcli_ldap_parse_value (ldap,
Packit Service 6d40f9
	                                 enroll->computer_attributes,
Packit Service 6d40f9
	                                 "pwdLastSet");
Packit Service 6d40f9
Packit Service 6d40f9
	if (_adcli_check_nt_time_string_lifetime (value,
Packit Service 6d40f9
	                adcli_enroll_get_computer_password_lifetime (enroll))) {
Packit Service f6a102
		/* Do not update keytab if neither new service principals have
Packit Service 6213b5
                 * to be added or deleted nor the user principal has to be changed. */
Packit Service 6213b5
		if (enroll->service_names == NULL
Packit Service 6213b5
		              && (enroll->user_principal == NULL || enroll->user_princpal_generate)
Packit Service 6213b5
		              && enroll->service_principals_to_add == NULL
Packit Service 6213b5
		              && enroll->service_principals_to_remove == NULL) {
Packit Service f6a102
			flags |= ADCLI_ENROLL_NO_KEYTAB;
Packit Service f6a102
		}
Packit Service 6d40f9
		flags |= ADCLI_ENROLL_PASSWORD_VALID;
Packit Service 6d40f9
	}
Packit Service 6d40f9
	free (value);
Packit Service 6d40f9
Packit Service 6d40f9
	return enroll_join_or_update_tasks (enroll, flags);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_delete (adcli_enroll *enroll,
Packit Service 6d40f9
                     adcli_enroll_flags delete_flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (enroll->conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Basic discovery and figuring out enroll params */
Packit Service 6d40f9
	res = ensure_host_fqdn (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_name (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_sam (res, enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Find the computer dn */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service 6d40f9
		res = locate_computer_account (enroll, ldap, NULL, NULL);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
		if (!enroll->computer_dn) {
Packit Service 6d40f9
			_adcli_err ("No computer account for %s exists",
Packit Service 6d40f9
			            enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return delete_computer_account (enroll, ldap);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_password (adcli_enroll *enroll,
Packit Service 6d40f9
                       adcli_enroll_flags password_flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (enroll->conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Basic discovery and figuring out enroll params */
Packit Service 6d40f9
	res = ensure_host_fqdn (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_name (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_sam (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_password (res, enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Find the computer dn */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service 6d40f9
		res = locate_computer_account (enroll, ldap, NULL, NULL);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
		if (!enroll->computer_dn) {
Packit Service 6d40f9
			_adcli_err ("No computer account for %s exists",
Packit Service 6d40f9
			            enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return set_computer_password (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_enroll *
Packit Service 6d40f9
adcli_enroll_new (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_enroll *enroll;
Packit Service 6d40f9
	const char *value;
Packit Service 6d40f9
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll = calloc (1, sizeof (adcli_enroll));
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->conn = adcli_conn_ref (conn);
Packit Service 6d40f9
	enroll->refs = 1;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the latter sections of host triple as OS name */
Packit Service 6d40f9
	value = strchr (HOST_TRIPLET, '-');
Packit Service 6d40f9
	if (value == NULL)
Packit Service 6d40f9
		value = HOST_TRIPLET;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		value++;
Packit Service 6d40f9
	enroll->os_name = strdup (value);
Packit Service 6d40f9
	return_val_if_fail (enroll->os_name != NULL, NULL);
Packit Service 6d40f9
Packit Service a61006
	enroll->samba_data_tool = strdup (SAMBA_DATA_TOOL);
Packit Service a61006
	return_val_if_fail (enroll->samba_data_tool != NULL, NULL);
Packit Service a61006
Packit Service 6d40f9
	return enroll;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_enroll *
Packit Service 6d40f9
adcli_enroll_ref (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	enroll->refs++;
Packit Service 6d40f9
	return enroll;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static void
Packit Service 6d40f9
enroll_free (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (enroll == NULL)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_sam);
Packit Service 6d40f9
	free (enroll->domain_ou);
Packit Service 6d40f9
	free (enroll->computer_dn);
Packit Service 6d40f9
	free (enroll->keytab_enctypes);
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->os_name);
Packit Service 6d40f9
	free (enroll->os_version);
Packit Service 6d40f9
	free (enroll->os_service_pack);
Packit Service a61006
	free (enroll->samba_data_tool);
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->user_principal);
Packit Service 6d40f9
	_adcli_strv_free (enroll->service_names);
Packit Service 6d40f9
	_adcli_strv_free (enroll->service_principals);
Packit Service 6d40f9
	_adcli_password_free (enroll->computer_password);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_enroll_set_keytab_name (enroll, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_conn_unref (enroll->conn);
Packit Service 6d40f9
	free (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_unref (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (enroll == NULL)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	if (--(enroll->refs) > 0)
Packit Service 6d40f9
		return;
Packit Service 6d40f9
Packit Service 6d40f9
	enroll_free (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_host_fqdn (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->host_fqdn;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_host_fqdn (adcli_enroll *enroll,
Packit Service 6d40f9
                            const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_str_set (&enroll->host_fqdn, value);
Packit Service 6d40f9
	enroll->host_fqdn_explicit = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_computer_name (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->computer_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_computer_name (adcli_enroll *enroll,
Packit Service 6d40f9
                                const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_str_set (&enroll->computer_name, value);
Packit Service 6d40f9
	enroll->computer_name_explicit = (value != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_domain_ou (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->domain_ou;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_domain_ou (adcli_enroll *enroll,
Packit Service 6d40f9
                            const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->domain_ou_validated = 0;
Packit Service 6d40f9
	_adcli_str_set (&enroll->domain_ou, value);
Packit Service 6d40f9
	enroll->domain_ou_explicit = (value != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_computer_dn (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->computer_dn;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_computer_dn (adcli_enroll *enroll,
Packit Service 6d40f9
                              const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_str_set (&enroll->computer_dn, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_computer_password (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->computer_password;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_computer_password (adcli_enroll *enroll,
Packit Service 6d40f9
                                    const char *password)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *newval = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	return_if_fail (enroll != 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 (enroll->computer_password)
Packit Service 6d40f9
		_adcli_password_free (enroll->computer_password);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->computer_password = newval;
Packit Service 6d40f9
	enroll->computer_password_explicit = (newval != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_reset_computer_password (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_password_free (enroll->computer_password);
Packit Service 6d40f9
	enroll->computer_password = NULL;
Packit Service 6d40f9
	enroll->computer_password_explicit = 0;
Packit Service 6d40f9
	enroll->reset_password = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char **
Packit Service 6d40f9
adcli_enroll_get_service_names (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ensure_service_names (ADCLI_SUCCESS, enroll) != ADCLI_SUCCESS)
Packit Service 6d40f9
		return_val_if_reached (NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	return (const char **)enroll->service_names;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_service_names (adcli_enroll *enroll,
Packit Service 6d40f9
                                const char **value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_strv_set (&enroll->service_names, value);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_add_service_name (adcli_enroll *enroll,
Packit Service 6d40f9
                               const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	return_if_fail (value != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->service_names = _adcli_strv_add (enroll->service_names, strdup (value), NULL);
Packit Service 6d40f9
	return_if_fail (enroll->service_names != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char **
Packit Service 6d40f9
adcli_enroll_get_service_principals  (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return (const char **)enroll->service_principals;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_service_principals (adcli_enroll *enroll,
Packit Service 6d40f9
                                     const char **value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_strv_set (&enroll->service_principals, value);
Packit Service 6d40f9
	enroll->service_principals_explicit = (value != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_kvno
Packit Service 6d40f9
adcli_enroll_get_kvno (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, 0);
Packit Service 6d40f9
	return enroll->kvno;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_kvno (adcli_enroll *enroll,
Packit Service 6d40f9
                       krb5_kvno value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	enroll->kvno = value;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
krb5_keytab
Packit Service 6d40f9
adcli_enroll_get_keytab (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->keytab;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_keytab_name (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->keytab_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_keytab_name (adcli_enroll *enroll,
Packit Service 6d40f9
                              const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	char *newval = NULL;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->keytab_name) {
Packit Service 6d40f9
		if (enroll->keytab_name_is_krb5) {
Packit Service 6d40f9
			k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
			return_if_fail (k5 != NULL);
Packit Service 6d40f9
			krb5_free_string (k5, enroll->keytab_name);
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			free (enroll->keytab_name);
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->keytab) {
Packit Service 6d40f9
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
		return_if_fail (k5 != NULL);
Packit Service 6d40f9
		krb5_kt_close (k5, enroll->keytab);
Packit Service 6d40f9
		enroll->keytab = NULL;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (value) {
Packit Service 6d40f9
		newval = strdup (value);
Packit Service 6d40f9
		return_if_fail (newval != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->keytab_name = newval;
Packit Service 6d40f9
	enroll->keytab_name_is_krb5 = 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service a8fee9
#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled"
Packit Service a8fee9
Packit Service a8fee9
static bool adcli_fips_enabled (void)
Packit Service a8fee9
{
Packit Service a8fee9
	int fd;
Packit Service a8fee9
	ssize_t len;
Packit Service a8fee9
	char buf[8];
Packit Service a8fee9
Packit Service a8fee9
	fd = open (PROC_SYS_FIPS, O_RDONLY);
Packit Service a8fee9
	if (fd != -1) {
Packit Service a8fee9
		len = read (fd, buf, sizeof (buf));
Packit Service a8fee9
		close (fd);
Packit Service a8fee9
		/* Assume FIPS in enabled if PROC_SYS_FIPS contains a
Packit Service a8fee9
		 * non-0 value. */
Packit Service a8fee9
		if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) {
Packit Service a8fee9
			return true;
Packit Service a8fee9
		}
Packit Service a8fee9
	}
Packit Service a8fee9
Packit Service a8fee9
	return false;
Packit Service a8fee9
}
Packit Service a8fee9
Packit Service 6d40f9
krb5_enctype *
Packit Service 6d40f9
adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	if (enroll->keytab_enctypes)
Packit Service 6d40f9
		return enroll->keytab_enctypes;
Packit Service 6d40f9
Packit Service 6d40f9
	if (adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID))
Packit Service a8fee9
		if (adcli_fips_enabled ()) {
Packit Service a8fee9
			return v60_later_enctypes_fips;
Packit Service a8fee9
		} else {
Packit Service a8fee9
			return v60_later_enctypes;
Packit Service a8fee9
		}
Packit Service 6d40f9
	else
Packit Service 6d40f9
		return v51_earlier_enctypes;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 10ea8b
krb5_enctype *
Packit Service 10ea8b
adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
Packit Service 10ea8b
{
Packit Service 10ea8b
	krb5_enctype *cur_enctypes;
Packit Service 10ea8b
	krb5_enctype *permitted_enctypes;
Packit Service 10ea8b
	krb5_enctype *new_enctypes;
Packit Service 10ea8b
	krb5_error_code code;
Packit Service 10ea8b
	krb5_context k5;
Packit Service 10ea8b
	size_t c;
Packit Service 10ea8b
	size_t p;
Packit Service 10ea8b
	size_t n;
Packit Service 10ea8b
Packit Service 10ea8b
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 10ea8b
	cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll);
Packit Service 10ea8b
Packit Service 10ea8b
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 10ea8b
	return_val_if_fail (k5 != NULL, NULL);
Packit Service 10ea8b
Packit Service 10ea8b
	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
Packit Service 10ea8b
	return_val_if_fail (code == 0, NULL);
Packit Service 10ea8b
Packit Service 10ea8b
	for (c = 0; cur_enctypes[c] != 0; c++);
Packit Service 10ea8b
Packit Service 10ea8b
	new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
Packit Service 10ea8b
	return_val_if_fail (new_enctypes != NULL, NULL);
Packit Service 10ea8b
Packit Service 10ea8b
	n = 0;
Packit Service 10ea8b
	for (c = 0; cur_enctypes[c] != 0; c++) {
Packit Service 10ea8b
		for (p = 0; permitted_enctypes[p] != 0; p++) {
Packit Service 10ea8b
			if (cur_enctypes[c] == permitted_enctypes[p]) {
Packit Service 10ea8b
				new_enctypes[n++] = cur_enctypes[c];
Packit Service 10ea8b
				break;
Packit Service 10ea8b
			}
Packit Service 10ea8b
		}
Packit Service 10ea8b
		if (permitted_enctypes[p] == 0) {
Packit Service 10ea8b
			_adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]);
Packit Service 10ea8b
		}
Packit Service 10ea8b
	}
Packit Service 10ea8b
Packit Service 10ea8b
	krb5_free_enctypes (k5, permitted_enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	return new_enctypes;
Packit Service 10ea8b
}
Packit Service 10ea8b
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll,
Packit Service 6d40f9
                                  krb5_enctype *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_enctype *newval = NULL;
Packit Service 6d40f9
	int len;
Packit Service 6d40f9
Packit Service 6d40f9
	if (value) {
Packit Service 6d40f9
		for (len = 0; value[len] != 0; len++);
Packit Service 6d40f9
		newval = malloc (sizeof (krb5_enctype) * (len + 1));
Packit Service 6d40f9
		return_if_fail (newval != NULL);
Packit Service 6d40f9
		memcpy (newval, value, sizeof (krb5_enctype) * (len + 1));
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->keytab_enctypes);
Packit Service 6d40f9
	enroll->keytab_enctypes = newval;
Packit Service 6d40f9
	enroll->keytab_enctypes_explicit = (newval != NULL);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_os_name (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->os_name;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_os_name (adcli_enroll *enroll,
Packit Service 6d40f9
                          const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	if (value && value[0] == '\0')
Packit Service 6d40f9
		value = NULL;
Packit Service 6d40f9
	_adcli_str_set (&enroll->os_name, value);
Packit Service 268540
	enroll->os_name_explicit = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_os_version (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->os_version;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_os_version (adcli_enroll *enroll,
Packit Service 6d40f9
                             const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	if (value && value[0] == '\0')
Packit Service 6d40f9
		value = NULL;
Packit Service 6d40f9
	_adcli_str_set (&enroll->os_version, value);
Packit Service 268540
	enroll->os_version_explicit = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_os_service_pack (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->os_service_pack;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_os_service_pack (adcli_enroll *enroll,
Packit Service 6d40f9
                                  const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	if (value && value[0] == '\0')
Packit Service 6d40f9
		value = NULL;
Packit Service 6d40f9
	_adcli_str_set (&enroll->os_service_pack, value);
Packit Service 268540
	enroll->os_service_pack_explicit = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
const char *
Packit Service 6d40f9
adcli_enroll_get_user_principal (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
	return enroll->user_principal;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_user_principal (adcli_enroll *enroll,
Packit Service 6d40f9
                                 const char *value)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_str_set (&enroll->user_principal, value);
Packit Service 6d40f9
	enroll->user_princpal_generate = 0;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_auto_user_principal (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	_adcli_str_set (&enroll->user_principal, NULL);
Packit Service 6d40f9
	enroll->user_princpal_generate = 1;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
#define DEFAULT_HOST_PW_LIFETIME 30
Packit Service 6d40f9
Packit Service 6d40f9
unsigned int
Packit Service 6d40f9
adcli_enroll_get_computer_password_lifetime (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, DEFAULT_HOST_PW_LIFETIME);
Packit Service 6d40f9
	if (enroll->computer_password_lifetime_explicit) {
Packit Service 6d40f9
		return enroll->computer_password_lifetime;
Packit Service 6d40f9
	}
Packit Service 6d40f9
	return DEFAULT_HOST_PW_LIFETIME;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
void
Packit Service 6d40f9
adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
Packit Service 6d40f9
                                   unsigned int lifetime)
Packit Service 6d40f9
{
Packit Service 6d40f9
	return_if_fail (enroll != NULL);
Packit Service 6d40f9
	enroll->computer_password_lifetime = lifetime;
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->computer_password_lifetime_explicit = 1;
Packit Service 6d40f9
}
Packit Service a61006
Packit Service a61006
void
Packit Service a61006
adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, const char *value)
Packit Service a61006
{
Packit Service a61006
	return_if_fail (enroll != NULL);
Packit Service a61006
	if (value != NULL && value[0] != '\0') {
Packit Service a61006
		_adcli_str_set (&enroll->samba_data_tool, value);
Packit Service a61006
	}
Packit Service a61006
}
Packit Service a61006
Packit Service a61006
const char *
Packit Service a61006
adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
Packit Service a61006
{
Packit Service a61006
	return_val_if_fail (enroll != NULL, NULL);
Packit Service a61006
	return enroll->samba_data_tool;
Packit Service a61006
}
Packit Service 8ee766
Packit Service 8ee766
bool
Packit Service 8ee766
adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll)
Packit Service 8ee766
{
Packit Service 8ee766
	return_val_if_fail (enroll != NULL, false);
Packit Service 8ee766
Packit Service 8ee766
	return enroll->trusted_for_delegation;
Packit Service 8ee766
}
Packit Service 8ee766
Packit Service 8ee766
void
Packit Service 8ee766
adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
Packit Service 8ee766
                                         bool value)
Packit Service 8ee766
{
Packit Service 8ee766
	return_if_fail (enroll != NULL);
Packit Service 8ee766
Packit Service 8ee766
	enroll->trusted_for_delegation = value;
Packit Service 268540
	enroll->trusted_for_delegation_explicit = 1;
Packit Service 8ee766
}
Packit Service 6213b5
Packit Service 6213b5
const char **
Packit Service 6213b5
adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
Packit Service 6213b5
{
Packit Service 6213b5
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6213b5
Packit Service 6213b5
	return (const char **)enroll->service_principals_to_add;
Packit Service 6213b5
}
Packit Service 6213b5
Packit Service 6213b5
void
Packit Service 6213b5
adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
Packit Service 6213b5
                                           const char *value)
Packit Service 6213b5
{
Packit Service 6213b5
	return_if_fail (enroll != NULL);
Packit Service 6213b5
	return_if_fail (value != NULL);
Packit Service 6213b5
Packit Service 6213b5
	enroll->service_principals_to_add = _adcli_strv_add (enroll->service_principals_to_add,
Packit Service 6213b5
							    strdup (value), NULL);
Packit Service 6213b5
	return_if_fail (enroll->service_principals_to_add != NULL);
Packit Service 6213b5
}
Packit Service 6213b5
Packit Service 6213b5
const char **
Packit Service 6213b5
adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll)
Packit Service 6213b5
{
Packit Service 6213b5
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6213b5
Packit Service 6213b5
	return (const char **)enroll->service_principals_to_remove;
Packit Service 6213b5
}
Packit Service 6213b5
Packit Service 6213b5
void
Packit Service 6213b5
adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
Packit Service 6213b5
                                              const char *value)
Packit Service 6213b5
{
Packit Service 6213b5
	return_if_fail (enroll != NULL);
Packit Service 6213b5
	return_if_fail (value != NULL);
Packit Service 6213b5
Packit Service 6213b5
	enroll->service_principals_to_remove = _adcli_strv_add (enroll->service_principals_to_remove,
Packit Service 6213b5
							    strdup (value), NULL);
Packit Service 6213b5
	return_if_fail (enroll->service_principals_to_remove != NULL);
Packit Service 6213b5
}
Packit Service 10ea8b
Packit Service 10ea8b
#ifdef ADENROLL_TESTS
Packit Service 10ea8b
Packit Service 10ea8b
#include "test.h"
Packit Service 10ea8b
Packit Service 10ea8b
static void
Packit Service 10ea8b
test_adcli_enroll_get_permitted_keytab_enctypes (void)
Packit Service 10ea8b
{
Packit Service 10ea8b
	krb5_enctype *enctypes;
Packit Service 10ea8b
	krb5_error_code code;
Packit Service 10ea8b
	krb5_enctype *permitted_enctypes;
Packit Service 10ea8b
	krb5_enctype check_enctypes[3] = { 0 };
Packit Service 10ea8b
	adcli_conn *conn;
Packit Service 10ea8b
	adcli_enroll *enroll;
Packit Service 10ea8b
	adcli_result res;
Packit Service 10ea8b
	krb5_context k5;
Packit Service 10ea8b
	size_t c;
Packit Service 10ea8b
Packit Service 10ea8b
	conn = adcli_conn_new ("test.dom");
Packit Service 10ea8b
	assert_ptr_not_null (conn);
Packit Service 10ea8b
Packit Service 10ea8b
	enroll = adcli_enroll_new (conn);
Packit Service 10ea8b
	assert_ptr_not_null (enroll);
Packit Service 10ea8b
Packit Service 10ea8b
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL);
Packit Service 10ea8b
	assert_ptr_eq (enctypes, NULL);
Packit Service 10ea8b
Packit Service 10ea8b
	/* krb5 context missing */
Packit Service 10ea8b
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 10ea8b
	assert_ptr_eq (enctypes, NULL);
Packit Service 10ea8b
Packit Service 10ea8b
	/* check that all permitted enctypes can pass */
Packit Service 10ea8b
	res = _adcli_krb5_init_context (&k5;;
Packit Service 10ea8b
	assert_num_eq (res, ADCLI_SUCCESS);
Packit Service 10ea8b
Packit Service 10ea8b
	adcli_conn_set_krb5_context (conn, k5);
Packit Service 10ea8b
Packit Service 10ea8b
	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
Packit Service 10ea8b
	assert_num_eq (code, 0);
Packit Service 10ea8b
	assert_ptr_not_null (permitted_enctypes);
Packit Service 10ea8b
	assert_num_cmp (permitted_enctypes[0], !=, 0);
Packit Service 10ea8b
Packit Service 10ea8b
	adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 10ea8b
	assert_ptr_not_null (enctypes);
Packit Service 10ea8b
	for (c = 0; permitted_enctypes[c] != 0; c++) {
Packit Service 10ea8b
		assert_num_eq (enctypes[c], permitted_enctypes[c]);
Packit Service 10ea8b
	}
Packit Service 10ea8b
	assert_num_eq (enctypes[c], 0);
Packit Service 10ea8b
	krb5_free_enctypes (k5, enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	/* check that ENCTYPE_UNKNOWN is filtered out */
Packit Service 10ea8b
	check_enctypes[0] = permitted_enctypes[0];
Packit Service 10ea8b
	check_enctypes[1] = ENCTYPE_UNKNOWN;
Packit Service 10ea8b
	check_enctypes[2] = 0;
Packit Service 10ea8b
	adcli_enroll_set_keytab_enctypes (enroll, check_enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 10ea8b
	assert_ptr_not_null (enctypes);
Packit Service 10ea8b
	assert_num_eq (enctypes[0], permitted_enctypes[0]);
Packit Service 10ea8b
	assert_num_eq (enctypes[1], 0);
Packit Service 10ea8b
	krb5_free_enctypes (k5, enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	krb5_free_enctypes (k5, permitted_enctypes);
Packit Service 10ea8b
Packit Service 10ea8b
	adcli_enroll_unref (enroll);
Packit Service 10ea8b
	adcli_conn_unref (conn);
Packit Service 10ea8b
}
Packit Service 10ea8b
Packit Service 10ea8b
int
Packit Service 10ea8b
main (int argc,
Packit Service 10ea8b
      char *argv[])
Packit Service 10ea8b
{
Packit Service 10ea8b
	test_func (test_adcli_enroll_get_permitted_keytab_enctypes,
Packit Service 10ea8b
	           "/attrs/adcli_enroll_get_permitted_keytab_enctypes");
Packit Service 10ea8b
	return test_run (argc, argv);
Packit Service 10ea8b
}
Packit Service 10ea8b
Packit Service 10ea8b
#endif /* ADENROLL_TESTS */