Blame library/adenroll.c

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