Blame library/adenroll.c

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