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 57f75d
#include <sys/stat.h>
Packit Service 57f75d
#include <fcntl.h>
Packit Service a8fee9
Packit Service bff25d
#ifndef SAMBA_DATA_TOOL
Packit Service bff25d
#define SAMBA_DATA_TOOL "/usr/bin/net"
Packit Service bff25d
#endif
Packit Service bff25d
Packit Service 57f75d
static krb5_enctype v60_later_enctypes_fips[] = {
Packit Service 57f75d
	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
Packit Service 57f75d
	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
Packit Service 57f75d
	0
Packit Service 57f75d
};
Packit Service 57f75d
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 147c59
static char *default_ad_ldap_attrs[] =  {
Packit Service 147c59
	"sAMAccountName",
Packit Service 147c59
	"userPrincipalName",
Packit Service 147c59
	"msDS-KeyVersionNumber",
Packit Service 147c59
	"msDS-supportedEncryptionTypes",
Packit Service 147c59
	"dNSHostName",
Packit Service 147c59
	"servicePrincipalName",
Packit Service 147c59
	"operatingSystem",
Packit Service 147c59
	"operatingSystemVersion",
Packit Service 147c59
	"operatingSystemServicePack",
Packit Service 147c59
	"pwdLastSet",
Packit Service 147c59
	"userAccountControl",
Packit Service 0a8a87
	"description",
Packit Service 147c59
	NULL,
Packit Service 147c59
};
Packit Service 147c59
Packit Service 9b2c4a
/* Some constants for the userAccountControl AD LDAP attribute, see e.g.
Packit Service 9b2c4a
 * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
Packit Service 9b2c4a
 * for details. */
Packit Service 9b2c4a
#define UAC_WORKSTATION_TRUST_ACCOUNT  0x1000
Packit Service 9b2c4a
#define UAC_DONT_EXPIRE_PASSWORD      0x10000
Packit Service 9b2c4a
#define UAC_TRUSTED_FOR_DELEGATION    0x80000
Packit Service 9b2c4a
Packit Service 6d40f9
struct _adcli_enroll {
Packit Service 6d40f9
	int refs;
Packit Service 6d40f9
	adcli_conn *conn;
Packit Service 6d40f9
Packit Service 6d40f9
	char *host_fqdn;
Packit Service 6d40f9
	int host_fqdn_explicit;
Packit Service 6d40f9
	char *computer_name;
Packit Service 6d40f9
	int computer_name_explicit;
Packit Service 6d40f9
	char *computer_sam;
Packit Service 6d40f9
	char *computer_password;
Packit Service 6d40f9
	int computer_password_explicit;
Packit Service 6d40f9
	int reset_password;
Packit Service 6d40f9
	krb5_principal computer_principal;
Packit Service 6d40f9
Packit Service 6d40f9
	char *domain_ou;
Packit Service 6d40f9
	int domain_ou_validated;
Packit Service 6d40f9
	int domain_ou_explicit;
Packit Service 6d40f9
	char *computer_dn;
Packit Service 6d40f9
	char *computer_container;
Packit Service 6d40f9
	LDAPMessage *computer_attributes;
Packit Service 6d40f9
Packit Service 6d40f9
	char **service_names;
Packit Service 6d40f9
	char **service_principals;
Packit Service 6d40f9
	int service_principals_explicit;
Packit Service 6d40f9
Packit Service 69847a
	char **service_principals_to_add;
Packit Service 69847a
	char **service_principals_to_remove;
Packit Service 69847a
Packit Service 6d40f9
	char *user_principal;
Packit Service 6d40f9
	int user_princpal_generate;
Packit Service 6d40f9
Packit Service 6d40f9
	char *os_name;
Packit Service 9bfb60
	int os_name_explicit;
Packit Service 6d40f9
	char *os_version;
Packit Service 9bfb60
	int os_version_explicit;
Packit Service 6d40f9
	char *os_service_pack;
Packit Service 9bfb60
	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 bff25d
	char *samba_data_tool;
Packit Service 9b2c4a
	bool trusted_for_delegation;
Packit Service 9bfb60
	int trusted_for_delegation_explicit;
Packit Service 0a8a87
	char *description;
Packit Service 6d40f9
};
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_host_fqdn (adcli_result res,
Packit Service 6d40f9
                  adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	const char *fqdn;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->host_fqdn) {
Packit Service 6d40f9
		_adcli_info ("Using fully qualified name: %s",
Packit Service 6d40f9
		             enroll->host_fqdn);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->host_fqdn_explicit) {
Packit Service 6d40f9
		_adcli_info ("Not setting fully qualified name");
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* By default use our actual host name discovered during connecting */
Packit Service 6d40f9
	fqdn = adcli_conn_get_host_fqdn (enroll->conn);
Packit Service 6d40f9
	_adcli_str_set (&enroll->host_fqdn, fqdn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_computer_name (adcli_result res,
Packit Service 6d40f9
                      adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_name) {
Packit Service bc2650
		_adcli_info ("Enrolling computer name: %s",
Packit Service 6d40f9
		             enroll->computer_name);
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->host_fqdn) {
Packit Service bc2650
		_adcli_err ("No host name from which to determine the computer name");
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->computer_name = _adcli_calc_netbios_name (enroll->host_fqdn);
Packit Service 6d40f9
	if (enroll->computer_name == NULL)
Packit Service 6d40f9
		return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_computer_sam (adcli_result res,
Packit Service 6d40f9
                     adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_sam);
Packit Service 6d40f9
	enroll->computer_sam = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&enroll->computer_sam, "%s$", enroll->computer_name) < 0)
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_sam != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_principal)
Packit Service 6d40f9
		krb5_free_principal (k5, enroll->computer_principal);
Packit Service 6d40f9
	enroll->computer_principal = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	code = _adcli_krb5_build_principal (k5, enroll->computer_sam,
Packit Service 6d40f9
	                                    adcli_conn_get_domain_realm (enroll->conn),
Packit Service 6d40f9
	                                    &enroll->computer_principal);
Packit Service 6d40f9
	return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static int
Packit Service 6d40f9
filter_password_chars (char *password,
Packit Service 6d40f9
                       int length)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int i, j;
Packit Service 6d40f9
Packit Service 6d40f9
	/*
Packit Service 6d40f9
	 * The MS documentation says their servers only use ASCII characters
Packit Service 6d40f9
	 * between 32 and 122 inclusive. We do that as well, and filter out
Packit Service 6d40f9
	 * all other random characters. We also remove certain characters
Packit Service 6d40f9
	 * special for use in a shell.
Packit Service 6d40f9
	 */
Packit Service 6d40f9
	for (i = 0, j = 0; i < length; i++) {
Packit Service 6d40f9
		if (password[i] >= 32 && password[i] <= 122 &&
Packit Service 6d40f9
		    strchr (" !'\"$`", password[i]) == NULL)
Packit Service 6d40f9
			password[j++] = password[i];
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* return the number of valid characters remaining */
Packit Service 6d40f9
	return j;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static char *
Packit Service 6d40f9
generate_host_password  (adcli_enroll *enroll,
Packit Service bc2650
                         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 bc2650
		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 bc2650
		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 31bfe2
ensure_default_service_names (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	int length = 0;
Packit Service 6d40f9
Packit Service 31bfe2
	if (enroll->service_names != NULL) {
Packit Service 31bfe2
		length = seq_count (enroll->service_names);
Packit Service 6d40f9
Packit Service 31bfe2
		/* Make sure there is no entry with an unexpected case. AD
Packit Service 31bfe2
		 * would not care but since the client side is case-sensitive
Packit Service 31bfe2
		 * we should make sure we use the expected spelling. */
Packit Service 31bfe2
		seq_remove_unsorted (enroll->service_names,
Packit Service 31bfe2
		                     &length, "host",
Packit Service 31bfe2
		                     (seq_compar)strcasecmp, free);
Packit Service 31bfe2
		seq_remove_unsorted (enroll->service_names,
Packit Service 31bfe2
		                     &length, "RestrictedKrbHost",
Packit Service 31bfe2
		                     (seq_compar)strcasecmp, free);
Packit Service 31bfe2
	}
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 31bfe2
ensure_service_names (adcli_result res,
Packit Service 31bfe2
                      adcli_enroll *enroll)
Packit Service 31bfe2
{
Packit Service 31bfe2
	if (res != ADCLI_SUCCESS)
Packit Service 31bfe2
		return res;
Packit Service 31bfe2
Packit Service 31bfe2
	if (enroll->service_names || enroll->service_principals)
Packit Service 31bfe2
		return ADCLI_SUCCESS;
Packit Service 31bfe2
Packit Service 31bfe2
	return ensure_default_service_names (enroll);
Packit Service 31bfe2
}
Packit Service 31bfe2
Packit Service 31bfe2
static adcli_result
Packit Service 005b26
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 005b26
	if (enroll->service_principals != NULL) {
Packit Service 005b26
		length = seq_count (enroll->service_principals);
Packit Service 005b26
	}
Packit Service 005b26
Packit Service 005b26
	for (i = 0; enroll->service_names[i] != NULL; i++) {
Packit Service 005b26
		if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
Packit Service 005b26
			return_unexpected_if_reached ();
Packit Service 67a0b3
		enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service 67a0b3
		                                                     name, &length, false);
Packit Service 005b26
Packit Service 005b26
		if (enroll->host_fqdn) {
Packit Service 005b26
			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
Packit Service 005b26
				return_unexpected_if_reached ();
Packit Service 67a0b3
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service 67a0b3
			                                                     name, &length, false);
Packit Service 005b26
		}
Packit Service 005b26
	}
Packit Service 005b26
Packit Service 005b26
	return ADCLI_SUCCESS;
Packit Service 005b26
}
Packit Service 005b26
Packit Service 005b26
static adcli_result
Packit Service 69847a
add_and_remove_service_principals (adcli_enroll *enroll)
Packit Service 69847a
{
Packit Service 69847a
	int length = 0;
Packit Service 69847a
	size_t c;
Packit Service 69847a
	const char **list;
Packit Service 69847a
Packit Service 69847a
	if (enroll->service_principals != NULL) {
Packit Service 69847a
		length = seq_count (enroll->service_principals);
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	list = adcli_enroll_get_service_principals_to_add (enroll);
Packit Service 69847a
	if (list != NULL) {
Packit Service 69847a
		for (c = 0; list[c] != NULL; c++) {
Packit Service 67a0b3
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service 67a0b3
			                                                     strdup (list[c]),
Packit Service 67a0b3
			                                                     &length, false);
Packit Service 69847a
			if (enroll->service_principals == NULL) {
Packit Service 69847a
				return ADCLI_ERR_UNEXPECTED;
Packit Service 69847a
			}
Packit Service 69847a
		}
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	list = adcli_enroll_get_service_principals_to_remove (enroll);
Packit Service 69847a
	if (list != NULL) {
Packit Service 69847a
		for (c = 0; list[c] != NULL; c++) {
Packit Service 69847a
			/* enroll->service_principals typically refects the
Packit Service 69847a
			 * order of the principal in the keytabm so it is not
Packit Service 69847a
			 * ordered. */
Packit Service 69847a
			_adcli_strv_remove_unsorted (enroll->service_principals,
Packit Service 69847a
			                             list[c], &length);
Packit Service 69847a
		}
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	return ADCLI_SUCCESS;
Packit Service 69847a
}
Packit Service 69847a
Packit Service 69847a
static adcli_result
Packit Service 005b26
ensure_service_principals (adcli_result res,
Packit Service 005b26
                           adcli_enroll *enroll)
Packit Service 005b26
{
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 69847a
		res = add_service_names_to_service_principals (enroll);
Packit Service e99966
	}
Packit Service e99966
Packit Service 69847a
	if (res == ADCLI_SUCCESS) {
Packit Service 69847a
		res = add_and_remove_service_principals (enroll);
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	return res;
Packit Service e99966
}
Packit Service e99966
Packit Service 847a9a
static void enroll_clear_keytab_principals (adcli_enroll *enroll)
Packit Service 847a9a
{
Packit Service 847a9a
	krb5_context k5;
Packit Service 847a9a
	size_t c;
Packit Service 847a9a
Packit Service 847a9a
	if (enroll->keytab_principals) {
Packit Service 847a9a
		k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 847a9a
		return_if_fail (k5 != NULL);
Packit Service 847a9a
Packit Service 847a9a
		for (c = 0; enroll->keytab_principals[c] != NULL; c++)
Packit Service 847a9a
			krb5_free_principal (k5, enroll->keytab_principals[c]);
Packit Service 847a9a
Packit Service 847a9a
		free (enroll->keytab_principals);
Packit Service 847a9a
		enroll->keytab_principals = NULL;
Packit Service 847a9a
	}
Packit Service 847a9a
Packit Service 847a9a
	return;
Packit Service 847a9a
}
Packit Service 847a9a
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 bc2650
	int count;
Packit Service 6d40f9
	int at, i;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Prepare the principals we're going to add to the keytab */
Packit Service 6d40f9
Packit Service bc2650
	return_unexpected_if_fail (enroll->service_principals);
Packit Service bc2650
	count = _adcli_strv_len (enroll->service_principals);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 847a9a
	enroll_clear_keytab_principals (enroll);
Packit Service 6d40f9
	enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
Packit Service 005b26
	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 bc2650
	char *attrs[] = { "wellKnownObjects", NULL };
Packit Service bc2650
	char *prefix = "B:32:AA312825768811D1ADED00C04FD8D5CD:";
Packit Service 6d40f9
	int prefix_len;
Packit Service 6d40f9
	LDAPMessage *results;
Packit Service 6d40f9
	const char *base;
Packit Service 6d40f9
	char **values;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
	int i;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->computer_container)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	base = enroll->domain_ou;
Packit Service 6d40f9
	if (base == NULL)
Packit Service 6d40f9
		base = adcli_conn_get_default_naming_context (enroll->conn);
Packit Service 6d40f9
	assert (base != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE,
Packit Service 6d40f9
	                         "(objectClass=*)", attrs, 0, NULL, NULL,
Packit Service 6d40f9
	                         NULL, -1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_NO_SUCH_OBJECT && enroll->domain_ou) {
Packit Service 6d40f9
		_adcli_err ("The organizational unit does not exist: %s", enroll->domain_ou);
Packit Service 6d40f9
		return enroll->domain_ou_explicit ? ADCLI_ERR_CONFIG : ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service bc2650
		                                   "Couldn't lookup computer container: %s", base);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service bc2650
	values = _adcli_ldap_parse_values (ldap, results, "wellKnownObjects");
Packit Service 6d40f9
	ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
	prefix_len = strlen (prefix);
Packit Service 6d40f9
	for (i = 0; values && values[i]; i++) {
Packit Service 6d40f9
		if (strncmp (values[i], prefix, prefix_len) == 0) {
Packit Service 6d40f9
			enroll->computer_container = strdup (values[i] + prefix_len);
Packit Service 6d40f9
			return_unexpected_if_fail (enroll->computer_container != NULL);
Packit Service bc2650
			_adcli_info ("Found well known computer container at: %s",
Packit Service bc2650
			             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 bc2650
		ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE,
Packit Service bc2650
		                         "(&(objectClass=container)(cn=Computers))",
Packit Service 6d40f9
		                         attrs, 0, NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
		if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
			enroll->computer_container = _adcli_ldap_parse_dn (ldap, results);
Packit Service 6d40f9
			if (enroll->computer_container) {
Packit Service bc2650
				_adcli_info ("Well known computer container not "
Packit Service 6d40f9
				             "found, but found suitable one at: %s",
Packit Service 6d40f9
				             enroll->computer_container);
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->computer_container && enroll->domain_ou) {
Packit Service 6d40f9
		_adcli_warn ("Couldn't find a computer container in the ou, "
Packit Service 6d40f9
		             "creating computer account directly in: %s", enroll->domain_ou);
Packit Service 6d40f9
		enroll->computer_container = strdup (enroll->domain_ou);
Packit Service 6d40f9
		return_unexpected_if_fail (enroll->computer_container != NULL);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->computer_container) {
Packit Service bc2650
		_adcli_err ("Couldn't find location to create computer accounts");
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
calculate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                            LDAP *ldap)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_dn == NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Now need to find or validate the computer container */
Packit Service 6d40f9
	res = lookup_computer_container (enroll, ldap);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_container);
Packit Service 6d40f9
Packit Service 6d40f9
	free (enroll->computer_dn);
Packit Service 6d40f9
	enroll->computer_dn = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	if (asprintf (&enroll->computer_dn, "CN=%s,%s", enroll->computer_name, enroll->computer_container) < 0)
Packit Service 6d40f9
		return_unexpected_if_reached ();
Packit Service 6d40f9
Packit Service bc2650
	_adcli_info ("Calculated computer account: %s", enroll->computer_dn);
Packit Service 6596aa
	return ADCLI_SUCCESS;
Packit Service 6596aa
}
Packit Service 6596aa
Packit Service 6596aa
static adcli_result
Packit Service 41f7a6
calculate_enctypes (adcli_enroll *enroll, char **enctype)
Packit Service 41f7a6
{
Packit Service 41f7a6
	char *value = NULL;
Packit Service 41f7a6
	krb5_enctype *read_enctypes;
Packit Service ae0400
	krb5_enctype *new_enctypes;
Packit Service 41f7a6
	char *new_value = NULL;
Packit Service 41f7a6
	int is_2008_or_later;
Packit Service 41f7a6
	LDAP *ldap;
Packit Service 41f7a6
Packit Service 41f7a6
	*enctype = NULL;
Packit Service 41f7a6
	/*
Packit Service 41f7a6
	 * Because we're using a keytab we want the server to be aware of the
Packit Service 41f7a6
	 * encryption types supported on the client, because we can't dynamically
Packit Service 41f7a6
	 * use a new one that's thrown at us.
Packit Service 41f7a6
	 *
Packit Service 41f7a6
	 * If the encryption types are not explicitly set by the caller of this
Packit Service 41f7a6
	 * library, then see if the account already has some encryption types
Packit Service 41f7a6
	 * marked on it.
Packit Service 41f7a6
	 *
Packit Service 41f7a6
	 * If not, write our default set to the account.
Packit Service 41f7a6
	 *
Packit Service 41f7a6
	 * Note that Windows 2003 and earlier have a standard set of encryption
Packit Service 41f7a6
	 * types, and no msDS-supportedEncryptionTypes attribute.
Packit Service 41f7a6
	 */
Packit Service 41f7a6
Packit Service 41f7a6
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 41f7a6
	return_unexpected_if_fail (ldap != NULL);
Packit Service 41f7a6
Packit Service 41f7a6
	is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
Packit Service 41f7a6
Packit Service 41f7a6
	/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
Packit Service a7d2df
	if (is_2008_or_later && enroll->computer_attributes != NULL) {
Packit Service 41f7a6
		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
Packit Service 41f7a6
		                                 "msDS-supportedEncryptionTypes");
Packit Service 41f7a6
Packit Service 41f7a6
		if (!enroll->keytab_enctypes_explicit && value != NULL) {
Packit Service 41f7a6
			read_enctypes = _adcli_krb5_parse_enctypes (value);
Packit Service 41f7a6
			if (read_enctypes == NULL) {
Packit Service 41f7a6
				_adcli_warn ("Invalid or unsupported encryption types are set on "
Packit Service 41f7a6
				             "the computer account (%s).", value);
Packit Service 41f7a6
			} else {
Packit Service 41f7a6
				free (enroll->keytab_enctypes);
Packit Service 41f7a6
				enroll->keytab_enctypes = read_enctypes;
Packit Service 41f7a6
			}
Packit Service 41f7a6
		}
Packit Service 41f7a6
Packit Service 41f7a6
	/* In 2003 or earlier, standard set of enc types */
Packit Service 41f7a6
	} else {
Packit Service 41f7a6
		value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
Packit Service 41f7a6
	}
Packit Service 41f7a6
Packit Service ae0400
	new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service ae0400
	if (new_enctypes == NULL) {
Packit Service ae0400
		_adcli_warn ("No permitted encryption type found.");
Packit Service ae0400
		return ADCLI_ERR_UNEXPECTED;
Packit Service ae0400
	}
Packit Service ae0400
Packit Service ae0400
	new_value = _adcli_krb5_format_enctypes (new_enctypes);
Packit Service ae0400
	krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes);
Packit Service 41f7a6
	if (new_value == NULL) {
Packit Service 41f7a6
		free (value);
Packit Service 41f7a6
		_adcli_warn ("The encryption types desired are not available in active directory");
Packit Service 41f7a6
		return ADCLI_ERR_CONFIG;
Packit Service 41f7a6
	}
Packit Service 41f7a6
Packit Service 41f7a6
	/* If we already have this value, then don't need to update */
Packit Service 41f7a6
	if (value && strcmp (new_value, value) == 0) {
Packit Service 41f7a6
		free (value);
Packit Service 41f7a6
		free (new_value);
Packit Service 41f7a6
		return ADCLI_SUCCESS;
Packit Service 41f7a6
	}
Packit Service 41f7a6
	free (value);
Packit Service 41f7a6
Packit Service 41f7a6
	if (!is_2008_or_later) {
Packit Service 41f7a6
		free (new_value);
Packit Service 41f7a6
		_adcli_warn ("Server does not support setting encryption types");
Packit Service 41f7a6
		return ADCLI_SUCCESS;
Packit Service 41f7a6
	}
Packit Service 41f7a6
Packit Service 41f7a6
	*enctype = new_value;
Packit Service 41f7a6
	return ADCLI_SUCCESS;
Packit Service 41f7a6
}
Packit Service 41f7a6
Packit Service 41f7a6
static adcli_result
Packit Service 6d40f9
create_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                         LDAP *ldap)
Packit Service 6d40f9
{
Packit Service bc2650
	char *vals_objectClass[] = { "computer", NULL };
Packit Service 6d40f9
	LDAPMod objectClass = { LDAP_MOD_ADD, "objectClass", { vals_objectClass, } };
Packit Service 6d40f9
	char *vals_sAMAccountName[] = { enroll->computer_sam, NULL };
Packit Service 6d40f9
	LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } };
Packit Service 6d40f9
	char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
Packit Service a7d2df
	LDAPMod userAccountControl = { LDAP_MOD_ADD, "userAccountControl", { vals_userAccountControl, } };
Packit Service a7d2df
	char *vals_supportedEncryptionTypes[] = { NULL, NULL };
Packit Service a7d2df
	LDAPMod encTypes = { LDAP_MOD_ADD, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
Packit Service a7d2df
	char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
Packit Service a7d2df
	LDAPMod dNSHostName = { LDAP_MOD_ADD, "dNSHostName", { vals_dNSHostName, } };
Packit Service a7d2df
	char *vals_operatingSystem[] = { enroll->os_name, NULL };
Packit Service a7d2df
	LDAPMod operatingSystem = { LDAP_MOD_ADD, "operatingSystem", { vals_operatingSystem, } };
Packit Service a7d2df
	char *vals_operatingSystemVersion[] = { enroll->os_version, NULL };
Packit Service a7d2df
	LDAPMod operatingSystemVersion = { LDAP_MOD_ADD, "operatingSystemVersion", { vals_operatingSystemVersion, } };
Packit Service a7d2df
	char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
Packit Service a7d2df
	LDAPMod operatingSystemServicePack = { LDAP_MOD_ADD, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
Packit Service a7d2df
	char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
Packit Service a7d2df
	LDAPMod userPrincipalName = { LDAP_MOD_ADD, "userPrincipalName", { vals_userPrincipalName, }, };
Packit Service a7d2df
	LDAPMod servicePrincipalName = { LDAP_MOD_ADD, "servicePrincipalName", { enroll->service_principals, } };
Packit Service 0a8a87
	char *vals_description[] = { enroll->description, NULL };
Packit Service 0a8a87
	LDAPMod description = { LDAP_MOD_ADD, "description", { vals_description, }, };
Packit Service a7d2df
Packit Service a7d2df
	char *val = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	int ret;
Packit Service a7d2df
	size_t c;
Packit Service a7d2df
	size_t m;
Packit Service 6d40f9
Packit Service a7d2df
	LDAPMod *all_mods[] = {
Packit Service 6d40f9
		&objectClass,
Packit Service 6d40f9
		&sAMAccountName,
Packit Service 6d40f9
		&userAccountControl,
Packit Service a7d2df
		&encTypes,
Packit Service a7d2df
		&dNSHostName,
Packit Service a7d2df
		&operatingSystem,
Packit Service a7d2df
		&operatingSystemVersion,
Packit Service a7d2df
		&operatingSystemServicePack,
Packit Service a7d2df
		&userPrincipalName,
Packit Service a7d2df
		&servicePrincipalName,
Packit Service 0a8a87
		&description,
Packit Service a7d2df
		NULL
Packit Service 6d40f9
	};
Packit Service 6d40f9
Packit Service a7d2df
	size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *);
Packit Service a7d2df
	LDAPMod *mods[mods_count];
Packit Service a7d2df
Packit Service 9b2c4a
	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
Packit Service 9b2c4a
		vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
Packit Service 9b2c4a
	}
Packit Service 9b2c4a
Packit Service a7d2df
	ret = calculate_enctypes (enroll, &val;;
Packit Service a7d2df
	if (ret != ADCLI_SUCCESS) {
Packit Service a7d2df
		return ret;
Packit Service a7d2df
	}
Packit Service a7d2df
	vals_supportedEncryptionTypes[0] = val;
Packit Service a7d2df
Packit Service a7d2df
	m = 0;
Packit Service a7d2df
	for (c = 0; c < mods_count - 1; c++) {
Packit Service a7d2df
		/* Skip empty LDAP sttributes */
Packit Service a7d2df
		if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
Packit Service a7d2df
			mods[m++] = all_mods[c];
Packit Service a7d2df
		}
Packit Service a7d2df
	}
Packit Service a7d2df
	mods[m] = NULL;
Packit Service a7d2df
Packit Service 6d40f9
	ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service a7d2df
	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 bc2650
	_adcli_info ("Created computer account: %s", enroll->computer_dn);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static int
Packit Service 6d40f9
filter_for_necessary_updates (adcli_enroll *enroll,
Packit Service 6d40f9
                              LDAP *ldap,
Packit Service 6d40f9
                              LDAPMessage *entry,
Packit Service 6d40f9
                              LDAPMod **mods)
Packit Service 6d40f9
{
Packit Service 6d40f9
	struct berval **vals;
Packit Service 6d40f9
	int match;
Packit Service 6d40f9
	int out;
Packit Service 6d40f9
	int in;
Packit Service 6d40f9
Packit Service 6d40f9
	for (in = 0, out = 0; mods[in] != NULL; in++) {
Packit Service 6d40f9
		match = 0;
Packit Service 6d40f9
Packit Service 6d40f9
		/* Never update these attributes */
Packit Service 6d40f9
		if (strcasecmp (mods[in]->mod_type, "objectClass") == 0)
Packit Service 6d40f9
			continue;
Packit Service 6d40f9
Packit Service 6d40f9
		/* If no entry, then no filtering */
Packit Service 6d40f9
		if (entry != NULL) {
Packit Service 6d40f9
			vals = ldap_get_values_len (ldap, entry, mods[in]->mod_type);
Packit Service 6d40f9
			if (vals != NULL) {
Packit Service 6d40f9
				match = _adcli_ldap_have_in_mod (mods[in], vals);
Packit Service 6d40f9
				ldap_value_free_len (vals);
Packit Service 6d40f9
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
		if (!match)
Packit Service 6d40f9
			mods[out++] = mods[in];
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	mods[out] = NULL;
Packit Service 6d40f9
	return out;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
validate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                           int allow_overwrite,
Packit Service 6d40f9
                           int already_exists)
Packit Service 6d40f9
{
Packit Service 6d40f9
	assert (enroll->computer_dn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (already_exists && !allow_overwrite) {
Packit Service bc2650
		_adcli_err ("The computer account %s already exists",
Packit Service bc2650
		            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 bc2650
			_adcli_err ("The computer account %s already exists, "
Packit Service 6d40f9
			            "but is not in the desired organizational unit.",
Packit Service bc2650
			            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 bc2650
		_adcli_info ("Deleted computer account at: %s", enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
locate_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                         LDAP *ldap,
Packit Service 6d40f9
                         LDAPMessage **rresults,
Packit Service 6d40f9
                         LDAPMessage **rentry)
Packit Service 6d40f9
{
Packit Service bc2650
	char *attrs[] = { "1.1", NULL };
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	const char *base;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	char *filter;
Packit Service 6d40f9
	char *dn;
Packit Service 6d40f9
	int ret = 0;
Packit Service 6d40f9
Packit Service 6d40f9
	/* If we don't yet know our computer dn, then try and find it */
Packit Service bc2650
	value = _adcli_ldap_escape_filter (enroll->computer_sam);
Packit Service bc2650
	return_unexpected_if_fail (value != NULL);
Packit Service bc2650
	if (asprintf (&filter, "(&(objectClass=computer)(sAMAccountName=%s))", value) < 0)
Packit Service bc2650
		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 bc2650
		/* If we found a computer account, make note of dn */
Packit Service 6d40f9
		if (entry) {
Packit Service 6d40f9
			dn = ldap_get_dn (ldap, entry);
Packit Service 6d40f9
			free (enroll->computer_dn);
Packit Service 6d40f9
			enroll->computer_dn = strdup (dn);
Packit Service 6d40f9
			return_unexpected_if_fail (enroll->computer_dn != NULL);
Packit Service bc2650
			_adcli_info ("Found computer account for %s at: %s",
Packit Service bc2650
			             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 bc2650
			_adcli_info ("Computer account for %s does not exist",
Packit Service bc2650
			             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 bc2650
		                                   "Couldn't lookup computer account: %s",
Packit Service bc2650
		                                   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 bc2650
	char *attrs[] = { "1.1", NULL };
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_search_ext_s (ldap, enroll->computer_dn, LDAP_SCOPE_BASE,
Packit Service 6d40f9
	                         "(objectClass=computer)", attrs, 0,
Packit Service 6d40f9
	                         NULL, NULL, NULL, -1, &results);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret == LDAP_SUCCESS) {
Packit Service 6d40f9
		entry = ldap_first_entry (ldap, results);
Packit Service 6d40f9
		if (entry) {
Packit Service bc2650
			_adcli_info ("Found computer account for %s at: %s",
Packit Service 6d40f9
			             enroll->computer_sam, enroll->computer_dn);
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret == LDAP_NO_SUCH_OBJECT) {
Packit Service 6d40f9
		results = entry = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't check computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	if (rresults)
Packit Service 6d40f9
		*rresults = results;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
	if (rentry) {
Packit Service 6d40f9
		assert (rresults != NULL);
Packit Service 6d40f9
		*rentry = entry;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
locate_or_create_computer_account (adcli_enroll *enroll,
Packit Service 6d40f9
                                   int allow_overwrite)
Packit Service 6d40f9
{
Packit Service 6d40f9
	LDAPMessage *results = NULL;
Packit Service 6d40f9
	LDAPMessage *entry = NULL;
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	int searched = 0;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Try to find the computer account */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service bc2650
		res = locate_computer_account (enroll, ldap, &results, &entry);
Packit Service 81ddb4
		if (res != ADCLI_SUCCESS)
Packit Service 81ddb4
			return res;
Packit Service 81ddb4
		searched = 1;
Packit Service 81ddb4
	}
Packit Service 81ddb4
Packit Service 6d40f9
	/* Next try and come up with where we think it should be */
Packit Service 6d40f9
	if (enroll->computer_dn == NULL) {
Packit Service 6d40f9
		res = calculate_computer_account (enroll, ldap);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_dn != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Have we seen an account yet? */
Packit Service 6d40f9
	if (!searched) {
Packit Service 6d40f9
		res = load_computer_account (enroll, ldap, &results, &entry);
Packit Service 6d40f9
		if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
			return res;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	res = validate_computer_account (enroll, allow_overwrite, entry != NULL);
Packit Service 6d40f9
	if (res == ADCLI_SUCCESS && entry == NULL)
Packit Service 6d40f9
		res = create_computer_account (enroll, ldap);
Packit Service 6d40f9
Packit Service 6d40f9
	if (results)
Packit Service 6d40f9
		ldap_msgfree (results);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
set_password_with_user_creds (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_ccache ccache;
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_data result_string = { 0, };
Packit Service 6d40f9
	krb5_data result_code_string = { 0, };
Packit Service 6d40f9
	adcli_result res;
Packit Service 6d40f9
	int result_code;
Packit Service 6d40f9
	char *message;
Packit Service 6d40f9
Packit Service 6d40f9
	assert (enroll->computer_password != NULL);
Packit Service 6d40f9
	assert (enroll->computer_principal != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	ccache = adcli_conn_get_login_ccache (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (ccache != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	memset (&result_string, 0, sizeof (result_string));
Packit Service 6d40f9
	memset (&result_code_string, 0, sizeof (result_code_string));
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_set_password_using_ccache (k5, ccache, enroll->computer_password,
Packit Service 6d40f9
	                                       enroll->computer_principal, &result_code,
Packit Service 6d40f9
	                                       &result_code_string, &result_string);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code != 0) {
Packit Service bc2650
		_adcli_err ("Couldn't set password for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		/* TODO: Parse out these values */
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (result_code != 0) {
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		if (krb5_chpw_message (k5, &result_string, &message) != 0)
Packit Service 6d40f9
			message = NULL;
Packit Service 6d40f9
#else
Packit Service 6d40f9
		message = NULL;
Packit Service 6d40f9
		if (result_string.length)
Packit Service 6d40f9
			message = _adcli_str_dupn (result_string.data, result_string.length);
Packit Service 6d40f9
#endif
Packit Service bc2650
		_adcli_err ("Cannot set computer password: %.*s%s%s",
Packit Service 6d40f9
		            (int)result_code_string.length, result_code_string.data,
Packit Service 6d40f9
		            message ? ": " : "", message ? message : "");
Packit Service 6d40f9
		res = ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		krb5_free_string (k5, message);
Packit Service 6d40f9
#else
Packit Service 6d40f9
		free (message);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
	} else {
Packit Service bc2650
		_adcli_info ("Set computer password");
Packit Service 2c0c8a
		if (enroll->kvno > 0) {
Packit Service 2c0c8a
			enroll->kvno++;
Packit Service 2c0c8a
			_adcli_info ("kvno incremented to %d", enroll->kvno);
Packit Service 2c0c8a
		}
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 bc2650
		_adcli_err ("Couldn't get change password ticket for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		return ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_change_password (k5, &creds, enroll->computer_password,
Packit Service 6d40f9
	                             &result_code, &result_code_string, &result_string);
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_cred_contents (k5, &creds);
Packit Service 6d40f9
Packit Service 6d40f9
	if (code != 0) {
Packit Service bc2650
		_adcli_err ("Couldn't change password for computer account: %s: %s",
Packit Service 6d40f9
		            enroll->computer_sam, krb5_get_error_message (k5, code));
Packit Service 6d40f9
		/* TODO: Parse out these values */
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (result_code != 0) {
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		if (krb5_chpw_message (k5, &result_string, &message) != 0)
Packit Service 6d40f9
			message = NULL;
Packit Service 6d40f9
#else
Packit Service 6d40f9
		message = NULL;
Packit Service 6d40f9
		if (result_string.length)
Packit Service 6d40f9
			message = _adcli_str_dupn (result_string.data, result_string.length);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
		_adcli_err ("Cannot change computer password: %.*s%s%s",
Packit Service 6d40f9
		            (int)result_code_string.length, result_code_string.data,
Packit Service 6d40f9
		            message ? ": " : "", message ? message : "");
Packit Service 6d40f9
		res = ADCLI_ERR_CREDENTIALS;
Packit Service 6d40f9
#ifdef HAVE_KRB5_CHPW_MESSAGE
Packit Service 6d40f9
		krb5_free_string (k5, message);
Packit Service 6d40f9
#else
Packit Service 6d40f9
		free (message);
Packit Service 6d40f9
#endif
Packit Service 6d40f9
	} else {
Packit Service 6d40f9
		_adcli_info ("Changed computer password");
Packit Service 6d40f9
		if (enroll->kvno > 0) {
Packit Service 6d40f9
			enroll->kvno++;
Packit Service 6d40f9
		        _adcli_info ("kvno incremented to %d", enroll->kvno);
Packit Service 6d40f9
		}
Packit Service 6d40f9
		res = ADCLI_SUCCESS;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_string);
Packit Service 6d40f9
	krb5_free_data_contents (k5, &result_code_string);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
set_computer_password (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	if (adcli_conn_get_login_type (enroll->conn) == ADCLI_LOGIN_COMPUTER_ACCOUNT)
Packit Service 6d40f9
		return set_password_with_computer_creds (enroll);
Packit Service 6d40f9
	else
Packit Service 6d40f9
		return set_password_with_user_creds (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
retrieve_computer_account (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	unsigned long kvno;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	char *end;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	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 147c59
	                         "(objectClass=*)", default_ad_ldap_attrs,
Packit Service 147c59
	                         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 bc2650
		                                   "Couldn't retrieve computer account info: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Update the kvno */
Packit Service 6d40f9
	if (enroll->kvno == 0) {
Packit Service 6d40f9
		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "msDS-KeyVersionNumber");
Packit Service 6d40f9
		if (value != NULL) {
Packit Service 6d40f9
			kvno = strtoul (value, &end, 10);
Packit Service 6d40f9
			if (end == NULL || *end != '\0') {
Packit Service bc2650
				_adcli_err ("Invalid kvno '%s' for computer account in directory: %s",
Packit Service bc2650
				            value, enroll->computer_dn);
Packit Service 6d40f9
				res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
Packit Service 6d40f9
			} else {
Packit Service 6d40f9
				enroll->kvno = kvno;
Packit Service 6d40f9
Packit Service bc2650
				_adcli_info ("Retrieved kvno '%s' for computer account in directory: %s",
Packit Service bc2650
				             value, enroll->computer_dn);
Packit Service 6d40f9
			}
Packit Service 6d40f9
Packit Service 6d40f9
			free (value);
Packit Service 6d40f9
Packit Service 6d40f9
		} else {
Packit Service 6d40f9
			/* Apparently old AD didn't have this attribute, use zero */
Packit Service 6d40f9
			enroll->kvno = 0;
Packit Service 6d40f9
Packit Service bc2650
			_adcli_info ("No kvno found for computer account in directory: %s",
Packit Service bc2650
			             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 bc2650
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service bc2650
	return_unexpected_if_fail (ldap != NULL);
Packit Service bc2650
Packit Service 41f7a6
	ret = calculate_enctypes (enroll, &new_value);
Packit Service 41f7a6
	if (ret != ADCLI_SUCCESS) {
Packit Service bc2650
		free (new_value);
Packit Service 41f7a6
		return ret;
Packit Service bc2650
	}
Packit Service bc2650
Packit Service 41f7a6
	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 bc2650
		                                   "Insufficient permissions to set encryption types on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service bc2650
		                                   "Couldn't set encryption types on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
update_computer_attribute (adcli_enroll *enroll,
Packit Service 6d40f9
                           LDAP *ldap,
Packit Service 6d40f9
                           LDAPMod **mods)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	char *string;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	/* See if there are any changes to be made? */
Packit Service 6d40f9
	if (filter_for_necessary_updates (enroll, ldap, enroll->computer_attributes, mods) == 0)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	string = _adcli_ldap_mods_to_string (mods);
Packit Service 6d40f9
	return_unexpected_if_fail (string != NULL);
Packit Service 6d40f9
Packit Service bc2650
	_adcli_info ("Modifying computer account: %s", string);
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	if (ret != LDAP_SUCCESS) {
Packit Service bc2650
		_adcli_warn ("Couldn't set %s on computer account: %s: %s",
Packit Service bc2650
		             string, enroll->computer_dn, ldap_err2string (ret));
Packit Service 6d40f9
		res = ADCLI_ERR_DIRECTORY;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	free (string);
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 9b2c4a
static char *get_user_account_control (adcli_enroll *enroll)
Packit Service 9b2c4a
{
Packit Service 9b2c4a
	uint32_t uac = 0;
Packit Service 9b2c4a
	unsigned long attr_val;
Packit Service 9b2c4a
	char *uac_str;
Packit Service 9b2c4a
	LDAP *ldap;
Packit Service 9b2c4a
	char *end;
Packit Service 9b2c4a
Packit Service 9b2c4a
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 9b2c4a
	return_val_if_fail (ldap != NULL, NULL);
Packit Service 9b2c4a
Packit Service 9b2c4a
	uac_str = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "userAccountControl");
Packit Service 9b2c4a
	if (uac_str != NULL) {
Packit Service 9b2c4a
Packit Service 9b2c4a
		attr_val = strtoul (uac_str, &end, 10);
Packit Service 9b2c4a
		if (*end != '\0' || attr_val > UINT32_MAX) {
Packit Service 9b2c4a
			_adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0",
Packit Service 9b2c4a
			            uac_str, enroll->computer_dn);
Packit Service 9b2c4a
		} else {
Packit Service 9b2c4a
			uac = attr_val;
Packit Service 9b2c4a
		}
Packit Service 9b2c4a
		free (uac_str);
Packit Service 9b2c4a
	}
Packit Service 9b2c4a
Packit Service 9b2c4a
	if (uac == 0) {
Packit Service 9b2c4a
		uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD;
Packit Service 9b2c4a
	}
Packit Service 9b2c4a
Packit Service 9b2c4a
	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
Packit Service 9b2c4a
		uac |= UAC_TRUSTED_FOR_DELEGATION;
Packit Service 9b2c4a
	} else {
Packit Service 9b2c4a
		uac &= ~(UAC_TRUSTED_FOR_DELEGATION);
Packit Service 9b2c4a
	}
Packit Service 9b2c4a
Packit Service 9b2c4a
	if (asprintf (&uac_str, "%d", uac) < 0) {
Packit Service 9b2c4a
		return_val_if_reached (NULL);
Packit Service 9b2c4a
	}
Packit Service 9b2c4a
Packit Service 9b2c4a
	return uac_str;
Packit Service 9b2c4a
}
Packit Service 9b2c4a
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 1c0212
	char *value = NULL;
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 9bfb60
	/* Only update attributes which are explicitly given on the command
Packit Service 1c0212
	 * line or not set in the existing AD object. Otherwise 'adcli update'
Packit Service 1c0212
	 * must be always called with the same set of options to make sure
Packit Service 1c0212
	 * existing attributes are not deleted or overwritten with different
Packit Service 1c0212
	 * values. */
Packit Service 1c0212
	if (enroll->computer_attributes != NULL) {
Packit Service 1c0212
		value = _adcli_ldap_parse_value (ldap,
Packit Service 1c0212
		                                 enroll->computer_attributes,
Packit Service 1c0212
		                                 "dNSHostName");
Packit Service 1c0212
	}
Packit Service 1c0212
	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 1c0212
	free (value);
Packit Service 6d40f9
Packit Service 9bfb60
	if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) {
Packit Service 9b2c4a
		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 9b2c4a
		vals_userAccountControl[0] = get_user_account_control (enroll);
Packit Service 9b2c4a
		if (vals_userAccountControl[0] != NULL) {
Packit Service 9b2c4a
			res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 9b2c4a
		} else {
Packit Service 9b2c4a
			_adcli_warn ("Cannot update userAccountControl");
Packit Service 9b2c4a
		}
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 9bfb60
		LDAPMod *mods[] = { NULL, NULL, NULL, NULL };
Packit Service 9bfb60
		size_t c = 0;
Packit Service 6d40f9
Packit Service 9bfb60
		if (enroll->os_name_explicit) {
Packit Service 9bfb60
			mods[c++] = &operatingSystem;
Packit Service 9bfb60
		}
Packit Service 9bfb60
		if (enroll->os_version_explicit) {
Packit Service 9bfb60
			mods[c++] = &operatingSystemVersion;
Packit Service 9bfb60
		}
Packit Service 9bfb60
		if (enroll->os_service_pack_explicit) {
Packit Service 9bfb60
			mods[c++] = &operatingSystemServicePack;
Packit Service 9bfb60
		}
Packit Service 9bfb60
Packit Service 9bfb60
		if (c != 0) {
Packit Service 9bfb60
			res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 9bfb60
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 005b26
	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 0a8a87
	if (res == ADCLI_SUCCESS && enroll->description != NULL) {
Packit Service 0a8a87
		char *vals_description[] = { enroll->description, NULL };
Packit Service 0a8a87
		LDAPMod description = { LDAP_MOD_REPLACE, "description", { vals_description, }, };
Packit Service 0a8a87
		LDAPMod *mods[] = { &description, NULL, };
Packit Service 0a8a87
Packit Service 0a8a87
		res |= update_computer_attribute (enroll, ldap, mods);
Packit Service 0a8a87
	}
Packit Service 0a8a87
Packit Service 6d40f9
	if (res != 0)
Packit Service 6d40f9
		_adcli_info ("Updated existing computer account: %s", enroll->computer_dn);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
update_service_principals (adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	LDAPMod servicePrincipalName = { LDAP_MOD_REPLACE, "servicePrincipalName", { enroll->service_principals, } };
Packit Service 6d40f9
	LDAPMod *mods[] = { &servicePrincipalName, NULL, };
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
	int ret;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* See if there are any changes to be made? */
Packit Service 6d40f9
	if (filter_for_necessary_updates (enroll, ldap, enroll->computer_attributes, mods) == 0)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
Packit Service 6d40f9
	if (ret == LDAP_INSUFFICIENT_ACCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
Packit Service 6d40f9
		                                   "Insufficient permissions to set service principals on computer account: %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
Packit Service 6d40f9
	} else if (ret != LDAP_SUCCESS) {
Packit Service 6d40f9
		return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
Packit Service 6d40f9
		                                   "Couldn't set service principals on computer account %s",
Packit Service 6d40f9
		                                   enroll->computer_dn);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 6d40f9
ensure_host_keytab (adcli_result res,
Packit Service 6d40f9
                    adcli_enroll *enroll)
Packit Service 6d40f9
{
Packit Service 6d40f9
	krb5_context k5;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (enroll->keytab)
Packit Service 6d40f9
		return ADCLI_SUCCESS;
Packit Service 6d40f9
Packit Service 6d40f9
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 6d40f9
	return_unexpected_if_fail (k5 != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	res = _adcli_krb5_open_keytab (k5, enroll->keytab_name, &enroll->keytab);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->keytab_name) {
Packit Service 6d40f9
		name = malloc (MAX_KEYTAB_NAME_LEN + 1);
Packit Service 6d40f9
		return_unexpected_if_fail (name != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
		code = krb5_kt_get_name (k5, enroll->keytab, name, MAX_KEYTAB_NAME_LEN + 1);
Packit Service 6d40f9
		return_unexpected_if_fail (code == 0);
Packit Service 6d40f9
Packit Service 6d40f9
		enroll->keytab_name = name;
Packit Service 6d40f9
		enroll->keytab_name_is_krb5 = 1;
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	_adcli_info ("Using keytab: %s", enroll->keytab_name);
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static krb5_boolean
Packit Service 6d40f9
load_keytab_entry (krb5_context k5,
Packit Service 6d40f9
                   krb5_keytab_entry *entry,
Packit Service 6d40f9
                   void *data)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_enroll *enroll = data;
Packit Service 6d40f9
	krb5_error_code code;
Packit Service 6d40f9
	krb5_principal principal;
Packit Service 6d40f9
	const char *realm;
Packit Service 6d40f9
	size_t len;
Packit Service 6d40f9
	char *value;
Packit Service 6d40f9
	char *name;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Skip over any entry without a principal or realm */
Packit Service 6d40f9
	principal = entry->principal;
Packit Service 6d40f9
	if (!principal || !principal->realm.length)
Packit Service 6d40f9
		return TRUE;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the first keytab entry as realm */
Packit Service 6d40f9
	realm = adcli_conn_get_domain_realm (enroll->conn);
Packit Service 6d40f9
	if (!realm) {
Packit Service 6d40f9
		value = _adcli_str_dupn (principal->realm.data, principal->realm.length);
Packit Service 6d40f9
		adcli_conn_set_domain_realm (enroll->conn, value);
Packit Service 6d40f9
		_adcli_info ("Found realm in keytab: %s", value);
Packit Service 6d40f9
		realm = adcli_conn_get_domain_realm (enroll->conn);
Packit Service 6d40f9
		free (value);
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Only look at entries that match the realm */
Packit Service 6d40f9
	len = strlen (realm);
Packit Service 6d40f9
	if (principal->realm.length != len && strncmp (realm, principal->realm.data, len) != 0)
Packit Service 6d40f9
		return TRUE;
Packit Service 6d40f9
Packit Service 6d40f9
	code = krb5_unparse_name_flags (k5, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
Packit Service 6d40f9
	return_val_if_fail (code == 0, FALSE);
Packit Service 6d40f9
Packit Service 6d40f9
	len = strlen (name);
Packit Service 6d40f9
Packit Service 6d40f9
	if (!enroll->service_principals_explicit) {
Packit Service 6d40f9
		if (!_adcli_strv_has (enroll->service_principals, name) && strchr (name, '/')) {
Packit Service 6d40f9
			value = strdup (name);
Packit Service 6d40f9
			return_val_if_fail (value != NULL, FALSE);
Packit Service 6d40f9
			_adcli_info ("Found service principal in keytab: %s", value);
Packit Service 67a0b3
			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 749b60
		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 bc2650
			_adcli_info ("Found computer name in keytab: %s", name);
Packit Service 6d40f9
			name = NULL;
Packit Service 6d40f9
Packit Service 6d40f9
		} else if (!enroll->host_fqdn && _adcli_str_has_prefix (name, "host/") && strchr (name, '.')) {
Packit Service 6d40f9
			/* Skip host/ prefix */
Packit Service f9c0b4
			enroll->host_fqdn = strdup (name + 5);
Packit Service f9c0b4
			return_val_if_fail (enroll->host_fqdn != NULL, FALSE);
Packit Service f9c0b4
			_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 573db5
	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 69847a
remove_principal_from_keytab (adcli_enroll *enroll,
Packit Service 69847a
                              krb5_context k5,
Packit Service 69847a
                              const char *principal_name)
Packit Service 69847a
{
Packit Service 69847a
	krb5_error_code code;
Packit Service 69847a
	krb5_principal principal;
Packit Service 69847a
	match_principal_kvno closure;
Packit Service 69847a
Packit Service bc8145
	code = _adcli_krb5_build_principal (k5, principal_name,
Packit Service bc8145
	                                    adcli_conn_get_domain_realm (enroll->conn),
Packit Service bc8145
	                                    &principal);
Packit Service 69847a
	if (code != 0) {
Packit Service 69847a
		_adcli_err ("Couldn't parse principal: %s: %s",
Packit Service 69847a
		            principal_name, krb5_get_error_message (k5, code));
Packit Service 69847a
		return ADCLI_ERR_FAIL;
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	closure.kvno = enroll->kvno;
Packit Service 69847a
	closure.principal = principal;
Packit Service 69847a
	closure.matched = 0;
Packit Service 69847a
Packit Service 69847a
	code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
Packit Service 69847a
	                                 match_principal_and_kvno, &closure);
Packit Service 69847a
	krb5_free_principal (k5, principal);
Packit Service 69847a
Packit Service 69847a
	if (code != 0) {
Packit Service 69847a
		_adcli_err ("Couldn't update keytab: %s: %s",
Packit Service 69847a
		            enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 69847a
		return ADCLI_ERR_FAIL;
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 69847a
	return ADCLI_SUCCESS;
Packit Service 69847a
}
Packit Service 69847a
Packit Service 69847a
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 005b26
                         int *which_salt,
Packit Service 005b26
                         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 ae0400
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service ae0400
	if (enctypes == NULL) {
Packit Service ae0400
		_adcli_warn ("No permitted encryption type found.");
Packit Service ae0400
		return ADCLI_ERR_UNEXPECTED;
Packit Service ae0400
	}
Packit Service 6d40f9
Packit Service 005b26
	if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
Packit Service 005b26
		code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
Packit Service 005b26
		                                        enroll->kvno, enctypes);
Packit Service 005b26
	} else {
Packit Service f6a102
Packit Service 005b26
		password.data = enroll->computer_password;
Packit Service 005b26
		password.length = strlen (enroll->computer_password);
Packit Service f6a102
Packit Service 005b26
		/*
Packit Service 005b26
		 * So we need to discover which salt to use. As a side effect we are
Packit Service 005b26
		 * also testing that our account works.
Packit Service 005b26
		 */
Packit Service 005b26
Packit Service 005b26
		salts = build_principal_salts (enroll, k5, principal);
Packit Service ae0400
		if (salts == NULL) {
Packit Service ae0400
			krb5_free_enctypes (k5, enctypes);
Packit Service ae0400
			return ADCLI_ERR_UNEXPECTED;
Packit Service ae0400
		}
Packit Service 005b26
Packit Service 005b26
		if (*which_salt < 0) {
Packit Service 005b26
			code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
Packit Service 005b26
			                                         enctypes, salts, which_salt);
Packit Service 005b26
			if (code != 0) {
Packit Service 005b26
				_adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
Packit Service 005b26
				             principal_name, krb5_get_error_message (k5, code));
Packit Service 005b26
				*which_salt = DEFAULT_SALT;
Packit Service 005b26
			} else {
Packit Service 005b26
				assert (*which_salt >= 0);
Packit Service 005b26
				_adcli_info ("Discovered which keytab salt to use");
Packit Service 005b26
			}
Packit Service 6d40f9
		}
Packit Service 6d40f9
Packit Service 005b26
		code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
Packit Service 005b26
		                                       enroll->kvno, &password, enctypes, &salts[*which_salt]);
Packit Service 6d40f9
Packit Service 005b26
		free_principal_salts (k5, salts);
Packit Service 573db5
	}
Packit Service ae0400
	krb5_free_enctypes (k5, enctypes);
Packit Service 6d40f9
Packit Service 573db5
	if (code != 0) {
Packit Service 573db5
		_adcli_err ("Couldn't add keytab entries: %s: %s",
Packit Service 573db5
		            enroll->keytab_name, krb5_get_error_message (k5, code));
Packit Service 573db5
		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 005b26
update_keytab_for_principals (adcli_enroll *enroll,
Packit Service 005b26
                              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 005b26
		                               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 69847a
	if (enroll->service_principals_to_remove != NULL) {
Packit Service 69847a
		for (i = 0; enroll->service_principals_to_remove[i] != NULL; i++) {
Packit Service 69847a
			res = remove_principal_from_keytab (enroll, k5,
Packit Service 69847a
			                                    enroll->service_principals_to_remove[i]);
Packit Service 69847a
			if (res != ADCLI_SUCCESS) {
Packit Service 69847a
				_adcli_warn ("Failed to remove %s from keytab.",
Packit Service 69847a
				             enroll->service_principals_to_remove[i]);
Packit Service 69847a
			}
Packit Service 69847a
		}
Packit Service 69847a
	}
Packit Service 69847a
Packit Service 6d40f9
	return ADCLI_SUCCESS;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 2cc99b
static adcli_result
Packit Service 2cc99b
update_samba_data (adcli_enroll *enroll)
Packit Service 2cc99b
{
Packit Service 2cc99b
	int ret;
Packit Service bff25d
	char *argv_pw[] = { NULL, "changesecretpw", "-i", "-f", NULL };
Packit Service bff25d
	char *argv_sid[] = { NULL, "setdomainsid", NULL, NULL };
Packit Service bff25d
Packit Service bff25d
	argv_pw[0] = (char *) adcli_enroll_get_samba_data_tool (enroll);
Packit Service bff25d
	if (argv_pw[0] ==NULL) {
Packit Service bff25d
		_adcli_err ("Samba data tool not available.");
Packit Service bff25d
		return ADCLI_ERR_FAIL;
Packit Service bff25d
	}
Packit Service bff25d
	argv_sid[0] = argv_pw[0];
Packit Service 2cc99b
Packit Service bff25d
	_adcli_info ("Trying to set Samba secret.");
Packit Service 2cc99b
	ret = _adcli_call_external_program (argv_pw[0], argv_pw,
Packit Service 2cc99b
	                                    enroll->computer_password, NULL, NULL);
Packit Service 2cc99b
	if (ret != ADCLI_SUCCESS) {
Packit Service bff25d
		_adcli_err ("Failed to set Samba computer account password.");
Packit Service 2cc99b
	}
Packit Service 2cc99b
Packit Service 2cc99b
	argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
Packit Service 2cc99b
	if (argv_sid[2] == NULL) {
Packit Service bff25d
		_adcli_err ("Domain SID not available.");
Packit Service 2cc99b
	} else {
Packit Service bff25d
		_adcli_info ("Trying to set domain SID %s for Samba.",
Packit Service 2cc99b
		             argv_sid[2]);
Packit Service 2cc99b
		ret = _adcli_call_external_program (argv_sid[0], argv_sid,
Packit Service 2cc99b
		                                    NULL, NULL, NULL);
Packit Service 2cc99b
		if (ret != ADCLI_SUCCESS) {
Packit Service bff25d
			_adcli_err ("Failed to set Samba domain SID.");
Packit Service 2cc99b
		}
Packit Service 2cc99b
	}
Packit Service 2cc99b
Packit Service 2cc99b
	return ret;
Packit Service 2cc99b
}
Packit Service 2cc99b
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 bc2650
Packit Service 847a9a
	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 bc2650
	/* Basic discovery and figuring out enroll params */
Packit Service bc2650
	res = ensure_host_fqdn (res, enroll);
Packit Service bc2650
	res = ensure_computer_name (res, enroll);
Packit Service bc2650
	res = ensure_computer_sam (res, enroll);
Packit Service bc2650
	res = ensure_user_principal (res, enroll);
Packit Service bc2650
	res = ensure_computer_password (res, enroll);
Packit Service bc2650
	if (!(flags & ADCLI_ENROLL_NO_KEYTAB))
Packit Service 6d40f9
		res = ensure_host_keytab (res, enroll);
Packit Service bc2650
	res = ensure_service_names (res, enroll);
Packit Service bc2650
	res = ensure_service_principals (res, enroll);
Packit Service bc2650
	res = ensure_keytab_principals (res, enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	return res;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
static adcli_result
Packit Service 43a98f
add_server_side_service_principals (adcli_enroll *enroll)
Packit Service 43a98f
{
Packit Service 43a98f
	char **spn_list;
Packit Service 43a98f
	LDAP *ldap;
Packit Service 43a98f
	size_t c;
Packit Service 43a98f
	int length = 0;
Packit Service 43a98f
	adcli_result res;
Packit Service 43a98f
Packit Service 43a98f
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 43a98f
	assert (ldap != NULL);
Packit Service 43a98f
Packit Service 43a98f
	spn_list = _adcli_ldap_parse_values (ldap, enroll->computer_attributes,
Packit Service 43a98f
	                                     "servicePrincipalName");
Packit Service 43a98f
	if (spn_list == NULL) {
Packit Service 43a98f
		return ADCLI_SUCCESS;
Packit Service 43a98f
	}
Packit Service 43a98f
Packit Service 43a98f
	if (enroll->service_principals != NULL) {
Packit Service 43a98f
		length = seq_count (enroll->service_principals);
Packit Service 43a98f
	}
Packit Service 43a98f
Packit Service 43a98f
	for (c = 0; spn_list[c] != NULL; c++) {
Packit Service 43a98f
		_adcli_info ("Checking %s", spn_list[c]);
Packit Service 43a98f
		if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
Packit Service 43a98f
			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
Packit Service eea44b
			                                                     strdup (spn_list[c]),
Packit Service eea44b
			                                                     &length, false);
Packit Service 43a98f
			assert (enroll->service_principals != NULL);
Packit Service 43a98f
			_adcli_info ("   Added %s", spn_list[c]);
Packit Service 43a98f
		}
Packit Service 43a98f
	}
Packit Service 43a98f
	_adcli_strv_free (spn_list);
Packit Service 43a98f
Packit Service 43a98f
	res = ensure_keytab_principals (ADCLI_SUCCESS, enroll);
Packit Service 43a98f
	if (res != ADCLI_SUCCESS) {
Packit Service 43a98f
		return res;
Packit Service 43a98f
	}
Packit Service 43a98f
Packit Service 43a98f
	return ADCLI_SUCCESS;
Packit Service 43a98f
}
Packit Service 43a98f
Packit Service 43a98f
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 26d6ed
	krb5_kvno old_kvno = -1;
Packit Service 6d40f9
Packit Service 6d40f9
	if (!(flags & ADCLI_ENROLL_PASSWORD_VALID)) {
Packit Service 26d6ed
Packit Service 26d6ed
		/* Handle kvno changes for read-only domain controllers
Packit Service 26d6ed
		 * (RODC). Since the actual password change does not happen on
Packit Service 26d6ed
		 * the RODC the kvno change has to be replicated back which
Packit Service 26d6ed
		 * might take some time. So we check the kvno before and after
Packit Service 26d6ed
		 * the change if we are connected to a RODC and increment the
Packit Service 26d6ed
		 * kvno if needed. */
Packit Service 26d6ed
		if (!adcli_conn_is_writeable (enroll->conn)) {
Packit Service 26d6ed
			if (enroll->computer_attributes == NULL) {
Packit Service 26d6ed
				res = retrieve_computer_account (enroll);
Packit Service 26d6ed
				if (res != ADCLI_SUCCESS)
Packit Service 26d6ed
					return res;
Packit Service 26d6ed
			}
Packit Service 26d6ed
			old_kvno = adcli_enroll_get_kvno (enroll);
Packit Service 26d6ed
			_adcli_info ("Found old kvno '%d'", old_kvno);
Packit Service 26d6ed
Packit Service 26d6ed
			ldap_msgfree (enroll->computer_attributes);
Packit Service 26d6ed
			enroll->computer_attributes = NULL;
Packit Service 26d6ed
			adcli_enroll_set_kvno (enroll, 0);
Packit Service 26d6ed
		}
Packit Service 26d6ed
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 26d6ed
	/* Handle kvno changes for read-only domain controllers (RODC) */
Packit Service 26d6ed
	if (!adcli_conn_is_writeable (enroll->conn) && old_kvno != -1 &&
Packit Service 26d6ed
	    adcli_enroll_get_kvno (enroll) != 0 &&
Packit Service 26d6ed
	    adcli_enroll_get_kvno (enroll) == old_kvno) {
Packit Service 26d6ed
		enroll->kvno++;
Packit Service 26d6ed
		_adcli_info ("No kvno change detected on read-only DC,  kvno "
Packit Service 26d6ed
		             "will be incremented by 1 to '%d'", enroll->kvno);
Packit Service 26d6ed
	}
Packit Service 26d6ed
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 005b26
Packit Service 43a98f
	res = add_server_side_service_principals (enroll);
Packit Service 43a98f
	if (res != ADCLI_SUCCESS) {
Packit Service 43a98f
		return res;
Packit Service 43a98f
	}
Packit Service 43a98f
Packit Service 005b26
	/* service_names is only set from input on the command line, so no
Packit Service 005b26
	 * additional check for explicit is needed here */
Packit Service 005b26
	if (enroll->service_names != NULL) {
Packit Service 005b26
		res = add_service_names_to_service_principals (enroll);
Packit Service 005b26
		if (res != ADCLI_SUCCESS) {
Packit Service 005b26
			return res;
Packit Service 005b26
		}
Packit Service 005b26
		res = ensure_keytab_principals (res, enroll);
Packit Service 005b26
		if (res != ADCLI_SUCCESS) {
Packit Service 005b26
			return res;
Packit Service 005b26
		}
Packit Service 005b26
	}
Packit Service 005b26
Packit Service 6d40f9
	update_service_principals (enroll);
Packit Service 6d40f9
Packit Service 2cc99b
	if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
Packit Service 2cc99b
		res = update_samba_data (enroll);
Packit Service 2cc99b
		if (res != ADCLI_SUCCESS) {
Packit Service 2cc99b
			_adcli_info ("Failed to add Samba specific data, smbd "
Packit Service 2cc99b
			             "or winbindd might not work as "
Packit Service 2cc99b
			             "expected.\n");
Packit Service 2cc99b
		}
Packit Service 2cc99b
	}
Packit Service 2cc99b
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 005b26
	return update_keytab_for_principals (enroll, flags);
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 31bfe2
	if (res != ADCLI_SUCCESS)
Packit Service 31bfe2
		return res;
Packit Service 31bfe2
Packit Service 31bfe2
	res = ensure_default_service_names (enroll);
Packit Service ea525b
	if (res != ADCLI_SUCCESS)
Packit Service ea525b
		return res;
Packit Service ea525b
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 147c59
adcli_enroll_read_computer_account (adcli_enroll *enroll,
Packit Service 147c59
		                    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 bc2650
		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 bc2650
			_adcli_err ("No computer account for %s exists", enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	/* Get information about the computer account */
Packit Service 147c59
	return retrieve_computer_account (enroll);
Packit Service 147c59
}
Packit Service 147c59
Packit Service 147c59
adcli_result
Packit Service 147c59
adcli_enroll_update (adcli_enroll *enroll,
Packit Service 147c59
		     adcli_enroll_flags flags)
Packit Service 147c59
{
Packit Service 147c59
	adcli_result res = ADCLI_SUCCESS;
Packit Service 147c59
	LDAP *ldap;
Packit Service 147c59
	char *value;
Packit Service 147c59
Packit Service 147c59
	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 005b26
		/* Do not update keytab if neither new service principals have
Packit Service 69847a
                 * to be added or deleted nor the user principal has to be changed. */
Packit Service 69847a
		if (enroll->service_names == NULL
Packit Service 69847a
		              && (enroll->user_principal == NULL || enroll->user_princpal_generate)
Packit Service 69847a
		              && enroll->service_principals_to_add == NULL
Packit Service 69847a
		              && enroll->service_principals_to_remove == NULL) {
Packit Service 005b26
			flags |= ADCLI_ENROLL_NO_KEYTAB;
Packit Service 005b26
		}
Packit Service 6d40f9
		flags |= ADCLI_ENROLL_PASSWORD_VALID;
Packit Service 6d40f9
	}
Packit Service 6d40f9
	free (value);
Packit Service 6d40f9
Packit Service 6d40f9
	return enroll_join_or_update_tasks (enroll, flags);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 147c59
adcli_enroll_show_computer_attribute (adcli_enroll *enroll)
Packit Service 147c59
{
Packit Service 147c59
	LDAP *ldap;
Packit Service 147c59
	size_t c;
Packit Service 147c59
	char **vals;
Packit Service 147c59
	size_t v;
Packit Service 147c59
Packit Service 147c59
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 147c59
	assert (ldap != NULL);
Packit Service 147c59
Packit Service 147c59
	for (c = 0; default_ad_ldap_attrs[c] != NULL; c++) {
Packit Service 147c59
		vals = _adcli_ldap_parse_values (ldap,
Packit Service 147c59
		                                 enroll->computer_attributes,
Packit Service 147c59
		                                 default_ad_ldap_attrs[c]);
Packit Service 147c59
		printf ("%s:\n", default_ad_ldap_attrs[c]);
Packit Service 147c59
		if (vals == NULL) {
Packit Service 147c59
			printf (" - not set -\n");
Packit Service 147c59
		} else {
Packit Service 147c59
			for (v = 0; vals[v] != NULL; v++) {
Packit Service 147c59
				printf (" %s\n", vals[v]);
Packit Service 147c59
			}
Packit Service 147c59
		}
Packit Service 147c59
		_adcli_strv_free (vals);
Packit Service 147c59
	}
Packit Service 147c59
Packit Service 147c59
	return ADCLI_SUCCESS;
Packit Service 147c59
}
Packit Service 147c59
Packit Service 147c59
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 bc2650
		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 bc2650
			_adcli_err ("No computer account for %s exists",
Packit Service 6d40f9
			            enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return delete_computer_account (enroll, ldap);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_result
Packit Service 6d40f9
adcli_enroll_password (adcli_enroll *enroll,
Packit Service 6d40f9
                       adcli_enroll_flags password_flags)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_result res = ADCLI_SUCCESS;
Packit Service 6d40f9
	LDAP *ldap;
Packit Service 6d40f9
Packit Service 6d40f9
	return_unexpected_if_fail (enroll != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	adcli_clear_last_error ();
Packit Service 6d40f9
	enroll_clear_state (enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	res = adcli_conn_discover (enroll->conn);
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Basic discovery and figuring out enroll params */
Packit Service 6d40f9
	res = ensure_host_fqdn (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_name (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_sam (res, enroll);
Packit Service 6d40f9
	res = ensure_computer_password (res, enroll);
Packit Service 6d40f9
Packit Service 6d40f9
	if (res != ADCLI_SUCCESS)
Packit Service 6d40f9
		return res;
Packit Service 6d40f9
Packit Service 6d40f9
	ldap = adcli_conn_get_ldap_connection (enroll->conn);
Packit Service 6d40f9
	assert (ldap != NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	/* Find the computer dn */
Packit Service 6d40f9
	if (!enroll->computer_dn) {
Packit Service bc2650
		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 bc2650
			_adcli_err ("No computer account for %s exists",
Packit Service 6d40f9
			            enroll->computer_sam);
Packit Service 6d40f9
			return ADCLI_ERR_CONFIG;
Packit Service 6d40f9
		}
Packit Service 6d40f9
	}
Packit Service 6d40f9
Packit Service 6d40f9
	return set_computer_password (enroll);
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 6d40f9
adcli_enroll *
Packit Service 6d40f9
adcli_enroll_new (adcli_conn *conn)
Packit Service 6d40f9
{
Packit Service 6d40f9
	adcli_enroll *enroll;
Packit Service 6d40f9
	const char *value;
Packit Service 6d40f9
Packit Service 6d40f9
	return_val_if_fail (conn != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll = calloc (1, sizeof (adcli_enroll));
Packit Service 6d40f9
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 6d40f9
Packit Service 6d40f9
	enroll->conn = adcli_conn_ref (conn);
Packit Service 6d40f9
	enroll->refs = 1;
Packit Service 6d40f9
Packit Service 6d40f9
	/* Use the latter sections of host triple as OS name */
Packit Service 6d40f9
	value = strchr (HOST_TRIPLET, '-');
Packit Service 6d40f9
	if (value == NULL)
Packit Service 6d40f9
		value = HOST_TRIPLET;
Packit Service 6d40f9
	else
Packit Service 6d40f9
		value++;
Packit Service 6d40f9
	enroll->os_name = strdup (value);
Packit Service 6d40f9
	return_val_if_fail (enroll->os_name != NULL, NULL);
Packit Service 6d40f9
Packit Service bff25d
	enroll->samba_data_tool = strdup (SAMBA_DATA_TOOL);
Packit Service bff25d
	return_val_if_fail (enroll->samba_data_tool != NULL, NULL);
Packit Service bff25d
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 bff25d
	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 57f75d
#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled"
Packit Service 57f75d
Packit Service 57f75d
static bool adcli_fips_enabled (void)
Packit Service 57f75d
{
Packit Service 57f75d
	int fd;
Packit Service 57f75d
	ssize_t len;
Packit Service 57f75d
	char buf[8];
Packit Service 57f75d
Packit Service 57f75d
	fd = open (PROC_SYS_FIPS, O_RDONLY);
Packit Service 57f75d
	if (fd != -1) {
Packit Service 57f75d
		len = read (fd, buf, sizeof (buf));
Packit Service 57f75d
		close (fd);
Packit Service 57f75d
		/* Assume FIPS in enabled if PROC_SYS_FIPS contains a
Packit Service 57f75d
		 * non-0 value. */
Packit Service 57f75d
		if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) {
Packit Service 57f75d
			return true;
Packit Service 57f75d
		}
Packit Service 57f75d
	}
Packit Service 57f75d
Packit Service 57f75d
	return false;
Packit Service 57f75d
}
Packit Service 57f75d
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 57f75d
		if (adcli_fips_enabled ()) {
Packit Service 57f75d
			return v60_later_enctypes_fips;
Packit Service 57f75d
		} else {
Packit Service 57f75d
			return v60_later_enctypes;
Packit Service 57f75d
		}
Packit Service 6d40f9
	else
Packit Service 6d40f9
		return v51_earlier_enctypes;
Packit Service 6d40f9
}
Packit Service 6d40f9
Packit Service 08e264
krb5_enctype *
Packit Service 08e264
adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
Packit Service 08e264
{
Packit Service 08e264
	krb5_enctype *cur_enctypes;
Packit Service 08e264
	krb5_enctype *permitted_enctypes;
Packit Service 08e264
	krb5_enctype *new_enctypes;
Packit Service 08e264
	krb5_error_code code;
Packit Service 08e264
	krb5_context k5;
Packit Service 08e264
	size_t c;
Packit Service 08e264
	size_t p;
Packit Service 08e264
	size_t n;
Packit Service 08e264
Packit Service 08e264
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 08e264
	cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll);
Packit Service 08e264
Packit Service 08e264
	k5 = adcli_conn_get_krb5_context (enroll->conn);
Packit Service 08e264
	return_val_if_fail (k5 != NULL, NULL);
Packit Service 08e264
Packit Service 08e264
	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
Packit Service 08e264
	return_val_if_fail (code == 0, NULL);
Packit Service 08e264
Packit Service 08e264
	for (c = 0; cur_enctypes[c] != 0; c++);
Packit Service 08e264
Packit Service 08e264
	new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
Packit Service 2f663e
	if (new_enctypes == NULL) {
Packit Service 2f663e
		krb5_free_enctypes (k5, permitted_enctypes);
Packit Service 2f663e
		return NULL;
Packit Service 2f663e
	}
Packit Service 08e264
Packit Service 08e264
	n = 0;
Packit Service 08e264
	for (c = 0; cur_enctypes[c] != 0; c++) {
Packit Service 08e264
		for (p = 0; permitted_enctypes[p] != 0; p++) {
Packit Service 08e264
			if (cur_enctypes[c] == permitted_enctypes[p]) {
Packit Service 08e264
				new_enctypes[n++] = cur_enctypes[c];
Packit Service 08e264
				break;
Packit Service 08e264
			}
Packit Service 08e264
		}
Packit Service 08e264
		if (permitted_enctypes[p] == 0) {
Packit Service 08e264
			_adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]);
Packit Service 08e264
		}
Packit Service 08e264
	}
Packit Service 08e264
Packit Service 08e264
	krb5_free_enctypes (k5, permitted_enctypes);
Packit Service 08e264
Packit Service 08e264
	return new_enctypes;
Packit Service 08e264
}
Packit Service 08e264
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 9bfb60
	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 9bfb60
	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 9bfb60
	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 bff25d
Packit Service bff25d
void
Packit Service bff25d
adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, const char *value)
Packit Service bff25d
{
Packit Service bff25d
	return_if_fail (enroll != NULL);
Packit Service bff25d
	if (value != NULL && value[0] != '\0') {
Packit Service bff25d
		_adcli_str_set (&enroll->samba_data_tool, value);
Packit Service bff25d
	}
Packit Service bff25d
}
Packit Service bff25d
Packit Service bff25d
const char *
Packit Service bff25d
adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
Packit Service bff25d
{
Packit Service bff25d
	return_val_if_fail (enroll != NULL, NULL);
Packit Service bff25d
	return enroll->samba_data_tool;
Packit Service bff25d
}
Packit Service 9b2c4a
Packit Service 9b2c4a
bool
Packit Service 9b2c4a
adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll)
Packit Service 9b2c4a
{
Packit Service 9b2c4a
	return_val_if_fail (enroll != NULL, false);
Packit Service 9b2c4a
Packit Service 9b2c4a
	return enroll->trusted_for_delegation;
Packit Service 9b2c4a
}
Packit Service 9b2c4a
Packit Service 9b2c4a
void
Packit Service 9b2c4a
adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
Packit Service 9b2c4a
                                         bool value)
Packit Service 9b2c4a
{
Packit Service 9b2c4a
	return_if_fail (enroll != NULL);
Packit Service 9b2c4a
Packit Service 9b2c4a
	enroll->trusted_for_delegation = value;
Packit Service 9bfb60
	enroll->trusted_for_delegation_explicit = 1;
Packit Service 9b2c4a
}
Packit Service 69847a
Packit Service 0a8a87
void
Packit Service 0a8a87
adcli_enroll_set_description (adcli_enroll *enroll, const char *value)
Packit Service 0a8a87
{
Packit Service 0a8a87
	return_if_fail (enroll != NULL);
Packit Service 0a8a87
	if (value != NULL && value[0] != '\0') {
Packit Service 0a8a87
		_adcli_str_set (&enroll->description, value);
Packit Service 0a8a87
	}
Packit Service 0a8a87
}
Packit Service 0a8a87
Packit Service 0a8a87
const char *
Packit Service 0a8a87
adcli_enroll_get_desciption (adcli_enroll *enroll)
Packit Service 0a8a87
{
Packit Service 0a8a87
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 0a8a87
	return enroll->description;
Packit Service 0a8a87
}
Packit Service 0a8a87
Packit Service 69847a
const char **
Packit Service 69847a
adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
Packit Service 69847a
{
Packit Service 69847a
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 69847a
Packit Service 69847a
	return (const char **)enroll->service_principals_to_add;
Packit Service 69847a
}
Packit Service 69847a
Packit Service 69847a
void
Packit Service 69847a
adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
Packit Service 69847a
                                           const char *value)
Packit Service 69847a
{
Packit Service 69847a
	return_if_fail (enroll != NULL);
Packit Service 69847a
	return_if_fail (value != NULL);
Packit Service 69847a
Packit Service 69847a
	enroll->service_principals_to_add = _adcli_strv_add (enroll->service_principals_to_add,
Packit Service 69847a
							    strdup (value), NULL);
Packit Service 69847a
	return_if_fail (enroll->service_principals_to_add != NULL);
Packit Service 69847a
}
Packit Service 69847a
Packit Service 69847a
const char **
Packit Service 69847a
adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll)
Packit Service 69847a
{
Packit Service 69847a
	return_val_if_fail (enroll != NULL, NULL);
Packit Service 69847a
Packit Service 69847a
	return (const char **)enroll->service_principals_to_remove;
Packit Service 69847a
}
Packit Service 69847a
Packit Service 69847a
void
Packit Service 69847a
adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
Packit Service 69847a
                                              const char *value)
Packit Service 69847a
{
Packit Service 69847a
	return_if_fail (enroll != NULL);
Packit Service 69847a
	return_if_fail (value != NULL);
Packit Service 69847a
Packit Service 69847a
	enroll->service_principals_to_remove = _adcli_strv_add (enroll->service_principals_to_remove,
Packit Service 69847a
							    strdup (value), NULL);
Packit Service 69847a
	return_if_fail (enroll->service_principals_to_remove != NULL);
Packit Service 69847a
}
Packit Service 08e264
Packit Service 08e264
#ifdef ADENROLL_TESTS
Packit Service 08e264
Packit Service 08e264
#include "test.h"
Packit Service 08e264
Packit Service 08e264
static void
Packit Service 08e264
test_adcli_enroll_get_permitted_keytab_enctypes (void)
Packit Service 08e264
{
Packit Service 08e264
	krb5_enctype *enctypes;
Packit Service 08e264
	krb5_error_code code;
Packit Service 08e264
	krb5_enctype *permitted_enctypes;
Packit Service 08e264
	krb5_enctype check_enctypes[3] = { 0 };
Packit Service 08e264
	adcli_conn *conn;
Packit Service 08e264
	adcli_enroll *enroll;
Packit Service 08e264
	adcli_result res;
Packit Service 08e264
	krb5_context k5;
Packit Service 08e264
	size_t c;
Packit Service 08e264
Packit Service 08e264
	conn = adcli_conn_new ("test.dom");
Packit Service 08e264
	assert_ptr_not_null (conn);
Packit Service 08e264
Packit Service 08e264
	enroll = adcli_enroll_new (conn);
Packit Service 08e264
	assert_ptr_not_null (enroll);
Packit Service 08e264
Packit Service 08e264
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL);
Packit Service 08e264
	assert_ptr_eq (enctypes, NULL);
Packit Service 08e264
Packit Service 08e264
	/* krb5 context missing */
Packit Service 08e264
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 08e264
	assert_ptr_eq (enctypes, NULL);
Packit Service 08e264
Packit Service 08e264
	/* check that all permitted enctypes can pass */
Packit Service 08e264
	res = _adcli_krb5_init_context (&k5;;
Packit Service 08e264
	assert_num_eq (res, ADCLI_SUCCESS);
Packit Service 08e264
Packit Service 08e264
	adcli_conn_set_krb5_context (conn, k5);
Packit Service 08e264
Packit Service 08e264
	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
Packit Service 08e264
	assert_num_eq (code, 0);
Packit Service 08e264
	assert_ptr_not_null (permitted_enctypes);
Packit Service 08e264
	assert_num_cmp (permitted_enctypes[0], !=, 0);
Packit Service 08e264
Packit Service 08e264
	adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes);
Packit Service 08e264
Packit Service 08e264
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 08e264
	assert_ptr_not_null (enctypes);
Packit Service 08e264
	for (c = 0; permitted_enctypes[c] != 0; c++) {
Packit Service 08e264
		assert_num_eq (enctypes[c], permitted_enctypes[c]);
Packit Service 08e264
	}
Packit Service 08e264
	assert_num_eq (enctypes[c], 0);
Packit Service 08e264
	krb5_free_enctypes (k5, enctypes);
Packit Service 08e264
Packit Service 08e264
	/* check that ENCTYPE_UNKNOWN is filtered out */
Packit Service 08e264
	check_enctypes[0] = permitted_enctypes[0];
Packit Service 08e264
	check_enctypes[1] = ENCTYPE_UNKNOWN;
Packit Service 08e264
	check_enctypes[2] = 0;
Packit Service 08e264
	adcli_enroll_set_keytab_enctypes (enroll, check_enctypes);
Packit Service 08e264
Packit Service 08e264
	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
Packit Service 08e264
	assert_ptr_not_null (enctypes);
Packit Service 08e264
	assert_num_eq (enctypes[0], permitted_enctypes[0]);
Packit Service 08e264
	assert_num_eq (enctypes[1], 0);
Packit Service 08e264
	krb5_free_enctypes (k5, enctypes);
Packit Service 08e264
Packit Service 08e264
	krb5_free_enctypes (k5, permitted_enctypes);
Packit Service 08e264
Packit Service 08e264
	adcli_enroll_unref (enroll);
Packit Service 08e264
	adcli_conn_unref (conn);
Packit Service 08e264
}
Packit Service 08e264
Packit Service 08e264
int
Packit Service 08e264
main (int argc,
Packit Service 08e264
      char *argv[])
Packit Service 08e264
{
Packit Service 08e264
	test_func (test_adcli_enroll_get_permitted_keytab_enctypes,
Packit Service 08e264
	           "/attrs/adcli_enroll_get_permitted_keytab_enctypes");
Packit Service 08e264
	return test_run (argc, argv);
Packit Service 08e264
}
Packit Service 08e264
Packit Service 08e264
#endif /* ADENROLL_TESTS */