summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/adcli.xml22
-rw-r--r--library/adenroll.c148
-rw-r--r--library/adenroll.h4
-rw-r--r--tools/computer.c13
4 files changed, 175 insertions, 12 deletions
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 324ce06..93e1520 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -426,6 +426,17 @@ Password for Administrator:
be used to specific an alternative location with the
help of an absolute path.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--ldap-passwd</option></term>
+ <listitem><para>Use LDAP add/mod operations to set the
+ machine account password instead of Kerberos. This
+ might help in some situations where Kerberos fails or
+ is unreliable. But please note that 'Change password'
+ or 'Reset password' permissions or similar might be
+ needed to make the LDAP operation work. Additionally
+ there will be no read-only domain controller (RODC)
+ support as there is with Kerberos.</para></listitem>
+ </varlistentry>
</variablelist>
<para>If supported on the AD side the
@@ -621,6 +632,17 @@ $ adcli update --login-ccache=/tmp/krbcc_123
be used to specific an alternative location with the
help of an absolute path.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--ldap-passwd</option></term>
+ <listitem><para>Use LDAP add/mod operations to set the
+ machine account password instead of Kerberos. This
+ might help in some situations where Kerberos fails or
+ is unreliable. But please note that 'Change password'
+ or 'Rest password' permissions or similar might be
+ needed to make the LDAP operation work. Additionally
+ there will be no read-only domain controller (RODC)
+ support as there is with Kerberos.</para></listitem>
+ </varlistentry>
</variablelist>
<para>If supported on the AD side the
diff --git a/library/adenroll.c b/library/adenroll.c
index ef60e2c..123fb79 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -43,6 +43,8 @@
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <iconv.h>
+#include <lber.h>
#ifndef SAMBA_DATA_TOOL
#define SAMBA_DATA_TOOL "/usr/bin/net"
@@ -880,9 +882,72 @@ get_del_mods_for_attrs (adcli_enroll *enroll, int mod_op)
return mods;
}
+static struct berval *get_unicode_pwd (char *pwd)
+{
+ iconv_t cd;
+ size_t s;
+ char *in = NULL;
+ char *in_ptr;
+ size_t in_size;
+ size_t len;
+ char *out = NULL;
+ char *out_ptr;
+ size_t out_size;
+ struct berval *bv = NULL;
+
+ if (pwd == NULL) {
+ return NULL;
+ }
+
+ if (asprintf (&in, "\"%s\"",pwd) < 0) {
+ return NULL;
+ }
+ in_ptr = in;
+ len = in_size = strlen (in);
+
+ out_size = 2*in_size;
+ out = malloc (out_size * sizeof (char));
+ out_ptr = out;
+
+ cd = iconv_open ("UTF-16LE", "UTF-8");
+ if (cd == (iconv_t) -1 ) {
+ goto done;
+ }
+
+ s = iconv (cd, &in_ptr, &in_size, &out_ptr, &out_size);
+ if (s == (size_t) -1 || out_size != 0) {
+ goto done;
+ }
+
+ s = iconv (cd, NULL, NULL, &out_ptr, &out_size);
+ if (s == (size_t) -1) {
+ goto done;
+ }
+
+ if (iconv_close (cd) != 0) {
+ goto done;
+ }
+
+ bv = malloc (sizeof(struct berval));
+ if (bv == NULL) {
+ goto done;
+ }
+
+ bv->bv_len = 2*len;
+ bv->bv_val = out;
+
+done:
+ free (in);
+ if (bv == NULL) {
+ free (out);
+ }
+
+ return bv;
+}
+
static adcli_result
create_computer_account (adcli_enroll *enroll,
- LDAP *ldap)
+ LDAP *ldap, int ldap_passwd)
{
char *vals_objectClass[] = { enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", NULL };
LDAPMod objectClass = { LDAP_MOD_ADD, "objectClass", { vals_objectClass, } };
@@ -905,6 +970,8 @@ create_computer_account (adcli_enroll *enroll,
LDAPMod servicePrincipalName = { LDAP_MOD_ADD, "servicePrincipalName", { enroll->service_principals, } };
char *vals_description[] = { enroll->description, NULL };
LDAPMod description = { LDAP_MOD_ADD, "description", { vals_description, }, };
+ struct berval *vals_unicodePwd[] = { NULL, NULL };
+ LDAPMod unicodePwd = { LDAP_MOD_ADD | LDAP_MOD_BVALUES, "unicodePwd", { NULL, } };
char *val = NULL;
@@ -927,12 +994,23 @@ create_computer_account (adcli_enroll *enroll,
&userPrincipalName,
&servicePrincipalName,
&description,
+ &unicodePwd,
NULL
};
size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *);
LDAPMod **mods;
+ if (ldap_passwd) {
+ _adcli_info ("Trying to set %s password with LDAP", s_or_c (enroll));
+
+ vals_unicodePwd[0] = get_unicode_pwd (enroll->computer_password);
+ if (vals_unicodePwd[0] == NULL) {
+ return ADCLI_ERR_FAIL;
+ }
+ unicodePwd.mod_vals.modv_bvals = vals_unicodePwd;
+ }
+
if (adcli_enroll_get_trusted_for_delegation (enroll)) {
uac |= UAC_TRUSTED_FOR_DELEGATION;
}
@@ -943,6 +1021,7 @@ create_computer_account (adcli_enroll *enroll,
}
if (asprintf (&uac_str, "%d", uac) < 0) {
+ ber_bvfree (vals_unicodePwd[0]);
return_val_if_reached (ADCLI_ERR_UNEXPECTED);
}
vals_userAccountControl[0] = uac_str;
@@ -950,6 +1029,7 @@ create_computer_account (adcli_enroll *enroll,
ret = calculate_enctypes (enroll, &val);
if (ret != ADCLI_SUCCESS) {
free (uac_str);
+ ber_bvfree (vals_unicodePwd[0]);
return ret;
}
vals_supportedEncryptionTypes[0] = val;
@@ -979,6 +1059,7 @@ create_computer_account (adcli_enroll *enroll,
mods[m] = NULL;
ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
+ ber_bvfree (vals_unicodePwd[0]);
ldap_mods_free (extra_mods, 1);
free (mods);
free (uac_str);
@@ -1290,7 +1371,7 @@ get_service_account_name_from_ldap (adcli_enroll *enroll, LDAPMessage *results)
static adcli_result
locate_or_create_computer_account (adcli_enroll *enroll,
- int allow_overwrite)
+ int allow_overwrite, int ldap_passwd)
{
LDAPMessage *results = NULL;
LDAPMessage *entry = NULL;
@@ -1352,7 +1433,7 @@ locate_or_create_computer_account (adcli_enroll *enroll,
res = validate_computer_account (enroll, allow_overwrite, entry != NULL);
if (res == ADCLI_SUCCESS && entry == NULL)
- res = create_computer_account (enroll, ldap);
+ res = create_computer_account (enroll, ldap, ldap_passwd);
/* Service account already exists, just continue and update the
* password */
@@ -1367,6 +1448,47 @@ locate_or_create_computer_account (adcli_enroll *enroll,
}
static adcli_result
+set_password_with_ldap (adcli_enroll *enroll)
+{
+ LDAP *ldap;
+ int ret;
+ struct berval *vals_unicodePwd[] = { NULL, NULL };
+ LDAPMod unicodePwd = { LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, "unicodePwd", { NULL, } };
+
+ LDAPMod *all_mods[] = {
+ &unicodePwd,
+ NULL
+ };
+
+ ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ return_unexpected_if_fail (ldap != NULL);
+
+ vals_unicodePwd[0] = get_unicode_pwd (enroll->computer_password);
+ return_unexpected_if_fail (vals_unicodePwd[0] != NULL);
+ unicodePwd.mod_vals.modv_bvals = vals_unicodePwd;
+
+ _adcli_info ("Trying to set %s password with LDAP", s_or_c (enroll));
+
+ ret = ldap_modify_ext_s (ldap, enroll->computer_dn, all_mods, NULL, NULL);
+ ber_bvfree (vals_unicodePwd[0]);
+
+ if (ret == LDAP_INSUFFICIENT_ACCESS || ret == LDAP_OBJECT_CLASS_VIOLATION ||
+ ret == LDAP_UNWILLING_TO_PERFORM || ret == LDAP_CONSTRAINT_VIOLATION) {
+ return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
+ "Insufficient permissions to set password for: %s",
+ enroll->computer_dn);
+
+ } else if (ret != LDAP_SUCCESS) {
+ return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
+ "Couldn't set password for: %s",
+ enroll->computer_dn);
+ }
+
+ _adcli_info ("Set password for: %s", enroll->computer_dn);
+ return ADCLI_SUCCESS;
+}
+
+static adcli_result
set_password_with_user_creds (adcli_enroll *enroll)
{
krb5_error_code code;
@@ -1390,6 +1512,8 @@ set_password_with_user_creds (adcli_enroll *enroll)
memset (&result_string, 0, sizeof (result_string));
memset (&result_code_string, 0, sizeof (result_code_string));
+ _adcli_info ("Trying to set %s password with Kerberos", s_or_c (enroll));
+
code = krb5_set_password_using_ccache (k5, ccache, enroll->computer_password,
enroll->computer_principal, &result_code,
&result_code_string, &result_string);
@@ -1452,6 +1576,8 @@ set_password_with_computer_creds (adcli_enroll *enroll)
k5 = adcli_conn_get_krb5_context (enroll->conn);
return_unexpected_if_fail (k5 != NULL);
+ _adcli_info ("Trying to change %s password with Kerberos", s_or_c (enroll));
+
code = _adcli_kinit_computer_creds (enroll->conn, "kadmin/changepw", NULL, &creds);
if (code != 0) {
_adcli_err ("Couldn't get change password ticket for %s account: %s: %s",
@@ -1506,8 +1632,12 @@ set_password_with_computer_creds (adcli_enroll *enroll)
}
static adcli_result
-set_computer_password (adcli_enroll *enroll)
+set_computer_password (adcli_enroll *enroll, int ldap_passwd)
{
+ if (ldap_passwd) {
+ return set_password_with_ldap (enroll);
+ }
+
if (adcli_conn_get_login_type (enroll->conn) == ADCLI_LOGIN_COMPUTER_ACCOUNT)
return set_password_with_computer_creds (enroll);
else
@@ -2434,7 +2564,7 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
adcli_enroll_set_kvno (enroll, 0);
}
- res = set_computer_password (enroll);
+ res = set_computer_password (enroll, flags & ADCLI_ENROLL_LDAP_PASSWD);
if (res != ADCLI_SUCCESS)
return res;
}
@@ -2587,7 +2717,8 @@ adcli_enroll_join (adcli_enroll *enroll,
return res;
/* This is where it really happens */
- res = locate_or_create_computer_account (enroll, flags & ADCLI_ENROLL_ALLOW_OVERWRITE);
+ res = locate_or_create_computer_account (enroll, flags & ADCLI_ENROLL_ALLOW_OVERWRITE,
+ flags & ADCLI_ENROLL_LDAP_PASSWD);
if (res != ADCLI_SUCCESS)
return res;
@@ -2769,8 +2900,7 @@ adcli_enroll_delete (adcli_enroll *enroll,
}
adcli_result
-adcli_enroll_password (adcli_enroll *enroll,
- adcli_enroll_flags password_flags)
+adcli_enroll_password (adcli_enroll *enroll)
{
adcli_result res = ADCLI_SUCCESS;
LDAP *ldap;
@@ -2809,7 +2939,7 @@ adcli_enroll_password (adcli_enroll *enroll,
}
}
- return set_computer_password (enroll);
+ return set_computer_password (enroll, 0);
}
adcli_enroll *
diff --git a/library/adenroll.h b/library/adenroll.h
index e3ada33..da2adc5 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -31,6 +31,7 @@ typedef enum {
ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2,
ADCLI_ENROLL_PASSWORD_VALID = 1 << 3,
ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 4,
+ ADCLI_ENROLL_LDAP_PASSWD = 1 << 5,
} adcli_enroll_flags;
typedef struct _adcli_enroll adcli_enroll;
@@ -54,8 +55,7 @@ adcli_result adcli_enroll_show_computer_attribute (adcli_enroll *enroll);
adcli_result adcli_enroll_delete (adcli_enroll *enroll,
adcli_enroll_flags delete_flags);
-adcli_result adcli_enroll_password (adcli_enroll *enroll,
- adcli_enroll_flags password_flags);
+adcli_result adcli_enroll_password (adcli_enroll *enroll);
adcli_enroll * adcli_enroll_new (adcli_conn *conn);
diff --git a/tools/computer.c b/tools/computer.c
index dffeecb..58ade1f 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -118,6 +118,7 @@ typedef enum {
opt_delattr,
opt_use_ldaps,
opt_account_disable,
+ opt_ldap_passwd,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -169,6 +170,7 @@ static adcli_tool_desc common_usages[] = {
{ opt_add_samba_data, "add domain SID and computer account password\n"
"to the Samba specific configuration database" },
{ opt_samba_data_tool, "Absolute path to the tool used for add-samba-data" },
+ { opt_ldap_passwd, "Use LDAP add/mod operation to set/change password" },
{ opt_verbose, "show verbose progress and failure messages", },
{ 0 },
};
@@ -360,6 +362,7 @@ parse_option (Option opt,
case opt_show_password:
case opt_one_time_password:
case opt_add_samba_data:
+ case opt_ldap_passwd:
assert (0 && "not reached");
break;
}
@@ -426,6 +429,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
{ "samba-data-tool", required_argument, 0, opt_samba_data_tool },
+ { "ldap-passwd", no_argument, NULL, opt_ldap_passwd },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -457,6 +461,9 @@ adcli_tool_computer_join (adcli_conn *conn,
case opt_add_samba_data:
flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
break;
+ case opt_ldap_passwd:
+ flags |= ADCLI_ENROLL_LDAP_PASSWD;
+ break;
case 'h':
case '?':
case ':':
@@ -554,6 +561,7 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
{ "samba-data-tool", required_argument, 0, opt_samba_data_tool },
+ { "ldap-passwd", no_argument, NULL, opt_ldap_passwd },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -581,6 +589,9 @@ adcli_tool_computer_update (adcli_conn *conn,
case opt_add_samba_data:
flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
break;
+ case opt_ldap_passwd:
+ flags |= ADCLI_ENROLL_LDAP_PASSWD;
+ break;
case 'h':
case '?':
case ':':
@@ -916,7 +927,7 @@ adcli_tool_computer_reset (adcli_conn *conn,
parse_fqdn_or_name (enroll, argv[0]);
adcli_enroll_reset_computer_password (enroll);
- res = adcli_enroll_password (enroll, 0);
+ res = adcli_enroll_password (enroll);
if (res != ADCLI_SUCCESS) {
warnx ("resetting %s in %s domain failed: %s", argv[0],
adcli_conn_get_domain_name (conn),