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 82e05e
/* The following list containst all attributes handled by adcli, some are
Packit Service 82e05e
 * read-only and the others can be written as well. To properly document the
Packit Service 82e05e
 * required permissions each attribute which adcli tries to modify should have
Packit Service 82e05e
 * a comment starting with ':ADPermissions:' and the related permissions in AD
Packit Service 82e05e
 * on the same line. Multiple permissions can be seperated with a '*'. For all
Packit Service 82e05e
 * other attribute a suitable comment is very welcome. */
Packit Service 362609
static char *default_ad_ldap_attrs[] =  {
Packit Service 82e05e
	"sAMAccountName", /* Only set during creation */
Packit Service 82e05e
	"userPrincipalName",   /* :ADPermissions: Read/Write userPrincipal Name */
Packit Service 82e05e
	"msDS-KeyVersionNumber", /* Manages by AD */
Packit Service 82e05e
	"msDS-supportedEncryptionTypes", /* :ADPermissions: Read/Write msDS-SupportedEncryptionTypes */
Packit Service 82e05e
	"dNSHostName", /* :ADPermissions: Read/Write dNSHostName * Read and write DNS host name attributes * Validated write to DNS host name */
Packit Service 82e05e
	"servicePrincipalName", /* :ADPermissions: Read/Write servicePrincipalName * Validated write to service principal name */
Packit Service 82e05e
	"operatingSystem", /* :ADPermissions: Read/Write Operating System */
Packit Service 82e05e
	"operatingSystemVersion", /* :ADPermissions: Read/Write Operating System Version */
Packit Service 82e05e
	"operatingSystemServicePack", /* :ADPermissions: Read/Write operatingSystemServicePack */
Packit Service 82e05e
	"pwdLastSet", /* Managed by AD */
Packit Service 82e05e
	"userAccountControl", /* :ADPermissions: Read/Write userAccountControl */
Packit Service 82e05e
	"description", /* :ADPermissions: Read/Write Description */
Packit Service 362609
	NULL,
Packit Service 362609
};
Packit Service 362609
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 1b4be8
	bool is_service;
Packit Service 1b4be8
	bool is_service_explicit;
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 18e697
	char *description;
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service f19c3e
static const char *
Packit Service f19c3e
s_or_c (adcli_enroll *enroll)
Packit Service f19c3e
{
Packit Service f19c3e
	return enroll->is_service ? "service" : "computer";
Packit Service f19c3e
}
Packit Service f19c3e
Packit Service 86276f
static void
Packit Service 86276f
check_if_service (adcli_enroll *enroll,
Packit Service 86276f
                  LDAP *ldap,
Packit Service 86276f
                  LDAPMessage *results)
Packit Service 86276f
{
Packit Service 86276f
	char **objectclasses = NULL;
Packit Service 86276f
Packit Service 86276f
	objectclasses = _adcli_ldap_parse_values (ldap, results, "objectClass");
Packit Service 86276f
	enroll->is_service = _adcli_strv_has_ex (objectclasses,
Packit Service 86276f
	                                         "msDS-ManagedServiceAccount",
Packit Service 86276f
	                                         strcasecmp) == 1 ? true : false;
Packit Service 86276f
	_adcli_strv_free (objectclasses);
Packit Service 86276f
}
Packit Service 86276f
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 f19c3e
		_adcli_info ("Enrolling %s name: %s",
Packit Service f19c3e
		             s_or_c (enroll),
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 f19c3e
		_adcli_err ("No host name from which to determine the %s name",
Packit Service f19c3e
		            s_or_c (enroll));
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 86276f
	int count = 0;
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 86276f
	if (!enroll->is_service) {
Packit Service 86276f
		return_unexpected_if_fail (enroll->service_principals);
Packit Service 86276f
		count = _adcli_strv_len (enroll->service_principals);
Packit Service 86276f
	}
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 86276f
	char *attrs[] = { enroll->is_service ? "otherWellKnownObjects"
Packit Service 86276f
	                                     : "wellKnownObjects", NULL };
Packit Service 86276f
	const char *prefix = enroll->is_service ? "B:32:1EB93889E40C45DF9F0C64D23BBB6237:"
Packit Service 86276f
	                                        : "B:32:AA312825768811D1ADED00C04FD8D5CD:";
Packit Service 86276f
	const char *filter = enroll->is_service ? "(&(objectClass=container)(cn=Managed Service Accounts))"
Packit Service 86276f
	                                        : "(&(objectClass=container)(cn=Computers))";
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 f19c3e
		                                   "Couldn't lookup %s container: %s",
Packit Service f19c3e
		                                   s_or_c (enroll), base);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 86276f
	values = _adcli_ldap_parse_values (ldap, results, attrs[0]);
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 f19c3e
			_adcli_info ("Found well known %s container at: %s",
Packit Service f19c3e
			             s_or_c (enroll), 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 86276f
		ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE, filter,
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 f19c3e
				_adcli_info ("Well known %s container not "
Packit Service 6d40f9
				             "found, but found suitable one at: %s",
Packit Service f19c3e
				             s_or_c (enroll),
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 f19c3e
		_adcli_err ("Couldn't find location to create %s accounts",
Packit Service f19c3e
		            s_or_c (enroll));
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 f19c3e
	_adcli_info ("Calculated %s account: %s",
Packit Service f19c3e
	             s_or_c (enroll), 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 86276f
	char *vals_objectClass[] = { enroll->is_service ? "msDS-ManagedServiceAccount" : "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 18e697
	char *vals_description[] = { enroll->description, NULL };
Packit Service 18e697
	LDAPMod description = { LDAP_MOD_ADD, "description", { vals_description, }, };
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 18e697
		&description,
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 86276f
		if (all_mods[c]->mod_vals.modv_strvals != NULL && 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 f19c3e
	_adcli_info ("Created %s account: %s", s_or_c (enroll),
Packit Service f19c3e
	                                       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 f19c3e
		_adcli_err ("The %s account %s already exists",
Packit Service f19c3e
		            s_or_c (enroll), 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 f19c3e
			_adcli_err ("The %s account %s already exists, "
Packit Service 6d40f9
			            "but is not in the desired organizational unit.",
Packit Service f19c3e
			            s_or_c (enroll), 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 f19c3e
		_adcli_info ("Deleted %s account at: %s", s_or_c (enroll),
Packit Service f19c3e
		                                          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 86276f
	char *attrs[] = { "objectClass", 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 86276f
	if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))",
Packit Service 86276f
	              enroll->is_service ? "msDS-ManagedServiceAccount" : "computer",
Packit Service 86276f
	              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 86276f
		/* If we found a computer/service account, make note of dn */
Packit Service 6d40f9
		if (entry) {
Packit Service 86276f
			if (!enroll->is_service_explicit) {
Packit Service 86276f
				check_if_service ( enroll, ldap, results);
Packit Service 86276f
			}
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 f19c3e
			_adcli_info ("Found %s account for %s at: %s",
Packit Service f19c3e
			             s_or_c (enroll), 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 f19c3e
			_adcli_info ("A %s account for %s does not exist",
Packit Service f19c3e
			             s_or_c (enroll), 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 f19c3e
		                                   "Couldn't lookup %s account: %s",
Packit Service f19c3e
		                                   s_or_c (enroll),
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 86276f
	char *attrs[] = { "objectClass", 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 f19c3e
			check_if_service (enroll, ldap, results);
Packit Service f19c3e
			_adcli_info ("Found %s account for %s at: %s",
Packit Service f19c3e
			             s_or_c (enroll),
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 86276f
	/* Service account already exists, just continue and update the
Packit Service 86276f
	 * password */
Packit Service 86276f
	if (enroll->is_service && entry != NULL) {
Packit Service 86276f
		res = ADCLI_SUCCESS;
Packit Service 86276f
	}
Packit Service 86276f
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 f19c3e
		_adcli_err ("Couldn't set password for %s account: %s: %s",
Packit Service f19c3e
		            s_or_c (enroll),
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 f19c3e
		_adcli_err ("Cannot set %s password: %.*s%s%s",
Packit Service f19c3e
		            s_or_c (enroll),
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 f19c3e
		_adcli_info ("Set %s password", s_or_c (enroll));
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 f19c3e
		_adcli_err ("Couldn't get change password ticket for %s account: %s: %s",
Packit Service f19c3e
		            s_or_c (enroll),
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 f19c3e
		_adcli_err ("Couldn't change password for %s account: %s: %s",
Packit Service f19c3e
		            s_or_c (enroll),
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
	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 362609
	                         "(objectClass=*)", default_ad_ldap_attrs,
Packit Service 362609
	                         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 f19c3e
		                                   "Couldn't retrieve %s account info: %s",
Packit Service f19c3e
		                                   s_or_c (enroll),
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 f19c3e
				_adcli_err ("Invalid kvno '%s' for %s account in directory: %s",
Packit Service f19c3e
				            value, s_or_c (enroll), 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 f19c3e
				_adcli_info ("Retrieved kvno '%s' for %s account in directory: %s",
Packit Service f19c3e
				             value, s_or_c (enroll), 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 f19c3e
			_adcli_info ("No kvno found for %s account in directory: %s",
Packit Service f19c3e
			             s_or_c (enroll), 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 f19c3e
		                                   "Insufficient permissions to set encryption types on %s account: %s",
Packit Service f19c3e
		                                   s_or_c (enroll),
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 f19c3e
		                                   "Couldn't set encryption types on %s account: %s",
Packit Service f19c3e
		                                   s_or_c (enroll),
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 f19c3e
	_adcli_info ("Modifying %s account: %s", s_or_c (enroll), 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 f19c3e
		_adcli_warn ("Couldn't set %s on %s account: %s: %s",
Packit Service f19c3e
		             string, s_or_c (enroll), enroll->computer_dn,
Packit Service f19c3e
		             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 f19c3e
			_adcli_warn ("Invalid userAccountControl '%s' for %s account in directory: %s, assuming 0",
Packit Service f19c3e
			            uac_str, s_or_c (enroll), 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 1007aa
	char *value = NULL;
Packit Service 6d40f9
Packit Service 86276f
	/* No updates for service accounts */
Packit Service 86276f
	if (enroll->is_service) {
Packit Service 86276f
		return;
Packit Service 86276f
	}
Packit Service 86276f
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 1007aa
	 * line or not set in the existing AD object. Otherwise 'adcli update'
Packit Service 1007aa
	 * must be always called with the same set of options to make sure
Packit Service 1007aa
	 * existing attributes are not deleted or overwritten with different
Packit Service 1007aa
	 * values. */
Packit Service 1007aa
	if (enroll->computer_attributes != NULL) {
Packit Service 1007aa
		value = _adcli_ldap_parse_value (ldap,
Packit Service 1007aa
		                                 enroll->computer_attributes,
Packit Service 1007aa
		                                 "dNSHostName");
Packit Service 1007aa
	}
Packit Service 1007aa
	if (enroll->host_fqdn_explicit || value == NULL ) {
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 1007aa
	free (value);
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 18e697
	if (res == ADCLI_SUCCESS && enroll->description != NULL) {
Packit Service 18e697
		char *vals_description[] = { enroll->description, NULL };
Packit Service 18e697
		LDAPMod description = { LDAP_MOD_REPLACE, "description", { vals_description, }, };
Packit Service 18e697
		LDAPMod *mods[] = { &description, NULL, };
Packit Service 18e697
Packit Service 18e697
		res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 18e697
	}
Packit Service 18e697
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 86276f
	/* No updates for service accounts */
Packit Service 86276f
	if (enroll->is_service) {
Packit Service 86276f
		return ADCLI_SUCCESS;
Packit Service 86276f
	}
Packit Service 86276f
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 f19c3e
			_adcli_info ("Found %s name in keytab: %s",
Packit Service f19c3e
			             s_or_c (enroll), name);
Packit Service 86276f
			adcli_conn_set_computer_name (enroll->conn,
Packit Service 86276f
			                              enroll->computer_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 86276f
	if (enroll->is_service) {
Packit Service 86276f
		/* Ensure basic params for service accounts */
Packit Service 86276f
		res = ensure_computer_sam (res, enroll);
Packit Service 86276f
		res = ensure_computer_password (res, enroll);
Packit Service 6d40f9
		res = ensure_host_keytab (res, enroll);
Packit Service 86276f
		res = ensure_keytab_principals (res, enroll);
Packit Service 86276f
	} else {
Packit Service 86276f
		/* Basic discovery and figuring out enroll params */
Packit Service 86276f
		res = ensure_host_fqdn (res, enroll);
Packit Service 86276f
		res = ensure_computer_name (res, enroll);
Packit Service 86276f
		res = ensure_computer_sam (res, enroll);
Packit Service 86276f
		res = ensure_user_principal (res, enroll);
Packit Service 86276f
		res = ensure_computer_password (res, enroll);
Packit Service 86276f
		if (!(flags & ADCLI_ENROLL_NO_KEYTAB))
Packit Service 86276f
			res = ensure_host_keytab (res, enroll);
Packit Service 86276f
		res = ensure_service_names (res, enroll);
Packit Service 86276f
		res = ensure_service_principals (res, enroll);
Packit Service 86276f
		res = ensure_keytab_principals (res, enroll);
Packit Service 86276f
	}
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 86276f
static adcli_result
Packit Service 86276f
adcli_enroll_add_description_for_service_account (adcli_enroll *enroll)
Packit Service 86276f
{
Packit Service 86276f
	const char *fqdn;
Packit Service 86276f
	char *desc;
Packit Service 86276f
Packit Service 86276f
	fqdn = adcli_conn_get_host_fqdn (enroll->conn);
Packit Service 86276f
	return_unexpected_if_fail (fqdn != NULL);
Packit Service 86276f
	if (asprintf (&desc, "Please do not edit, Service account for %s, "
Packit Service 86276f
	                     "managed by adcli.", fqdn) < 0) {
Packit Service 86276f
		return_unexpected_if_reached ();
Packit Service 86276f
	}
Packit Service 86276f
Packit Service 86276f
	adcli_enroll_set_description (enroll, desc);
Packit Service 86276f
	free (desc);
Packit Service 86276f
Packit Service 86276f
	return ADCLI_SUCCESS;
Packit Service 86276f
}
Packit Service 86276f
Packit Service 86276f
static adcli_result
Packit Service 86276f
adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll)
Packit Service 86276f
{
Packit Service 86276f
	krb5_context k5;
Packit Service 86276f
	krb5_error_code code;
Packit Service 86276f
	char def_keytab_name[MAX_KEYTAB_NAME_LEN];
Packit Service 86276f
	char *lc_dom_name;
Packit Service 86276f
	int ret;
Packit Service 86276f
Packit Service 86276f
	if (adcli_enroll_get_keytab_name (enroll) == NULL) {
Packit Service 86276f
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 86276f
		return_unexpected_if_fail (k5 != NULL);
Packit Service 86276f
Packit Service 86276f
		code = krb5_kt_default_name (k5, def_keytab_name,
Packit Service 86276f
		                             sizeof (def_keytab_name));
Packit Service 86276f
		return_unexpected_if_fail (code == 0);
Packit Service 86276f
Packit Service 86276f
		lc_dom_name = strdup (adcli_conn_get_domain_name (enroll->conn));
Packit Service 86276f
		return_unexpected_if_fail (lc_dom_name != NULL);
Packit Service 86276f
		_adcli_str_down (lc_dom_name);
Packit Service 86276f
Packit Service 86276f
Packit Service 86276f
		ret = asprintf (&enroll->keytab_name, "%s.%s", def_keytab_name,
Packit Service 86276f
		                                             lc_dom_name);
Packit Service 86276f
		free (lc_dom_name);
Packit Service 86276f
		return_unexpected_if_fail (ret > 0);
Packit Service 86276f
	}
Packit Service 86276f
Packit Service 86276f
	_adcli_info ("Using service account keytab: %s", enroll->keytab_name);
Packit Service 86276f
Packit Service 86276f
	return ADCLI_SUCCESS;
Packit Service 86276f
}
Packit Service 86276f
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 86276f
	if (enroll->is_service) {
Packit Service 86276f
		res = adcli_enroll_add_description_for_service_account (enroll);
Packit Service 86276f
		if (res == ADCLI_SUCCESS) {
Packit Service 86276f
			res = adcli_enroll_add_keytab_for_service_account (enroll);
Packit Service 86276f
		}
Packit Service 86276f
	} else {
Packit Service 86276f
		res = ensure_default_service_names (enroll);
Packit Service 86276f
	}
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 362609
adcli_enroll_read_computer_account (adcli_enroll *enroll,
Packit Service 362609
		                    adcli_enroll_flags 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
	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 f19c3e
			_adcli_err ("No %s account for %s exists",
Packit Service f19c3e
			            s_or_c (enroll), 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 362609
	return retrieve_computer_account (enroll);
Packit Service 362609
}
Packit Service 362609
Packit Service 362609
adcli_result
Packit Service 362609
adcli_enroll_update (adcli_enroll *enroll,
Packit Service 362609
		     adcli_enroll_flags flags)
Packit Service 362609
{
Packit Service 362609
	adcli_result res = ADCLI_SUCCESS;
Packit Service 362609
	LDAP *ldap;
Packit Service 362609
	char *value;
Packit Service 362609
Packit Service 362609
	res = adcli_enroll_read_computer_account (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
	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 86276f
	/* We only support password changes for service accounts */
Packit Service 86276f
	if (enroll->is_service && (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
Packit Service 86276f
		return ADCLI_SUCCESS;
Packit Service 86276f
	}
Packit Service 86276f
Packit Service 6d40f9
	return enroll_join_or_update_tasks (enroll, flags);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 362609
adcli_enroll_show_computer_attribute (adcli_enroll *enroll)
Packit Service 362609
{
Packit Service 362609
	LDAP *ldap;
Packit Service 362609
	size_t c;
Packit Service 362609
	char **vals;
Packit Service 362609
	size_t v;
Packit Service 362609
Packit Service 362609
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 362609
	assert (ldap != NULL);
Packit Service 362609
Packit Service 362609
	for (c = 0; default_ad_ldap_attrs[c] != NULL; c++) {
Packit Service 362609
		vals = _adcli_ldap_parse_values (ldap,
Packit Service 362609
		                                 enroll->computer_attributes,
Packit Service 362609
		                                 default_ad_ldap_attrs[c]);
Packit Service 362609
		printf ("%s:\n", default_ad_ldap_attrs[c]);
Packit Service 362609
		if (vals == NULL) {
Packit Service 362609
			printf (" - not set -\n");
Packit Service 362609
		} else {
Packit Service 362609
			for (v = 0; vals[v] != NULL; v++) {
Packit Service 362609
				printf (" %s\n", vals[v]);
Packit Service 362609
			}
Packit Service 362609
		}
Packit Service 362609
		_adcli_strv_free (vals);
Packit Service 362609
	}
Packit Service 362609
Packit Service 362609
	return ADCLI_SUCCESS;
Packit Service 362609
}
Packit Service 362609
Packit Service 362609
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 f19c3e
			_adcli_err ("No %s account for %s exists",
Packit Service f19c3e
			            s_or_c (enroll),
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 f19c3e
			_adcli_err ("No %s account for %s exists",
Packit Service f19c3e
			            s_or_c (enroll),
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 bb63eb
	if (new_enctypes == NULL) {
Packit Service bb63eb
		krb5_free_enctypes (k5, permitted_enctypes);
Packit Service bb63eb
		return NULL;
Packit Service bb63eb
	}
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 18e697
void
Packit Service 18e697
adcli_enroll_set_description (adcli_enroll *enroll, const char *value)
Packit Service 18e697
{
Packit Service 18e697
	return_if_fail (enroll != NULL);
Packit Service 18e697
	if (value != NULL && value[0] != '\0') {
Packit Service 18e697
		_adcli_str_set (&enroll->description, value);
Packit Service 18e697
	}
Packit Service 18e697
}
Packit Service 18e697
Packit Service 18e697
const char *
Packit Service 18e697
adcli_enroll_get_desciption (adcli_enroll *enroll)
Packit Service 18e697
{
Packit Service 18e697
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 18e697
	return enroll->description;
Packit Service 18e697
}
Packit Service 18e697
Packit Service 1b4be8
void
Packit Service 1b4be8
adcli_enroll_set_is_service (adcli_enroll *enroll, bool value)
Packit Service 1b4be8
{
Packit Service 1b4be8
	return_if_fail (enroll != NULL);
Packit Service 1b4be8
Packit Service 1b4be8
	enroll->is_service = value;
Packit Service 1b4be8
	enroll->is_service_explicit = true;
Packit Service 1b4be8
}
Packit Service 1b4be8
Packit Service 1b4be8
bool
Packit Service 1b4be8
adcli_enroll_get_is_service (adcli_enroll *enroll)
Packit Service 1b4be8
{
Packit Service 1b4be8
	return enroll->is_service;
Packit Service 1b4be8
}
Packit Service 1b4be8
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 */