mirror of
https://github.com/samba-team/samba.git
synced 2025-02-25 17:57:42 +03:00
s3:libads: Remove ads_keytab_create_default & friends
BUG: https://bugzilla.samba.org/show_bug.cgi?id=6750 Signed-off-by: Pavel Filipenský <pfilipensky@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
parent
ad6a91ba74
commit
c10c49b3f0
@ -1936,116 +1936,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a keytab entry for the given principal
|
||||
*
|
||||
* @param[in] context The krb5 context to use.
|
||||
*
|
||||
* @param[in] keytab The keytab to add the entry to.
|
||||
*
|
||||
* @param[in] kvno The kvno to use.
|
||||
*
|
||||
* @param[in] princ_s The principal as a string.
|
||||
*
|
||||
* @param[in] salt_principal The salt principal to salt the password with.
|
||||
* Only needed for keys which support salting.
|
||||
* If no salt is used set no_salt to false and
|
||||
* pass NULL here.
|
||||
*
|
||||
* @param[in] enctype The encryption type of the keytab entry.
|
||||
*
|
||||
* @param[in] password The password of the keytab entry.
|
||||
*
|
||||
* @retval 0 on Success
|
||||
*
|
||||
* @return A corresponding KRB5 error code.
|
||||
*
|
||||
* @see smb_krb5_kt_open()
|
||||
*/
|
||||
krb5_error_code smb_krb5_kt_add_password(krb5_context context,
|
||||
krb5_keytab keytab,
|
||||
krb5_kvno kvno,
|
||||
const char *princ_s,
|
||||
const char *salt_principal,
|
||||
krb5_enctype enctype,
|
||||
krb5_data *password)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_keytab_entry kt_entry;
|
||||
krb5_principal princ = NULL;
|
||||
krb5_keyblock *keyp;
|
||||
krb5_principal salt_princ = NULL;
|
||||
|
||||
ZERO_STRUCT(kt_entry);
|
||||
|
||||
ret = smb_krb5_parse_name(context, princ_s, &princ);
|
||||
if (ret) {
|
||||
DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
|
||||
"failed (%s)\n", princ_s, error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Seek and delete old keytab entries */
|
||||
ret = smb_krb5_kt_seek_and_delete_old_entries(context,
|
||||
keytab,
|
||||
true, /* keep_old_kvno */
|
||||
kvno,
|
||||
true, /* enctype_only */
|
||||
enctype,
|
||||
princ_s,
|
||||
princ,
|
||||
false); /* flush */
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we get here, we have deleted all the old entries with kvno's
|
||||
* not equal to the current kvno-1. */
|
||||
|
||||
keyp = KRB5_KT_KEY(&kt_entry);
|
||||
|
||||
/* Now add keytab entries for all encryption types */
|
||||
ret = smb_krb5_parse_name(context, salt_principal, &salt_princ);
|
||||
if (ret) {
|
||||
DBG_WARNING("krb5_parse_name(%s) failed (%s)\n",
|
||||
salt_principal, error_message(ret));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = smb_krb5_create_key_from_string(context,
|
||||
salt_princ,
|
||||
NULL,
|
||||
password,
|
||||
enctype,
|
||||
keyp);
|
||||
krb5_free_principal(context, salt_princ);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
kt_entry.principal = princ;
|
||||
kt_entry.vno = kvno;
|
||||
|
||||
DEBUG(3, (__location__ ": adding keytab entry for (%s) with "
|
||||
"encryption type (%d) and version (%d)\n",
|
||||
princ_s, enctype, kt_entry.vno));
|
||||
ret = samba_krb5_kt_add_entry(context, keytab, &kt_entry);
|
||||
krb5_free_keyblock_contents(context, keyp);
|
||||
ZERO_STRUCT(kt_entry);
|
||||
if (ret) {
|
||||
DEBUG(1, (__location__ ": adding entry to keytab "
|
||||
"failed (%s)\n", error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (princ) {
|
||||
krb5_free_principal(context, princ);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE) && \
|
||||
defined(HAVE_KRB5_GET_CREDS_OPT_ALLOC) && \
|
||||
defined(HAVE_KRB5_GET_CREDS)
|
||||
|
@ -392,13 +392,6 @@ krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
|
||||
const char *princ_s,
|
||||
krb5_principal princ,
|
||||
bool flush);
|
||||
krb5_error_code smb_krb5_kt_add_password(krb5_context context,
|
||||
krb5_keytab keytab,
|
||||
krb5_kvno kvno,
|
||||
const char *princ_s,
|
||||
const char *salt_principal,
|
||||
krb5_enctype enctype,
|
||||
krb5_data *password);
|
||||
|
||||
krb5_error_code smb_krb5_get_credentials(krb5_context context,
|
||||
krb5_ccache ccache,
|
||||
|
@ -62,11 +62,7 @@ void ads_disp_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct security_descripto
|
||||
|
||||
/* The following definitions come from libads/kerberos_keytab.c */
|
||||
|
||||
int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc,
|
||||
bool update_ads);
|
||||
int ads_keytab_delete_entry(ADS_STRUCT *ads, const char *srvPrinc);
|
||||
int ads_keytab_flush(ADS_STRUCT *ads);
|
||||
int ads_keytab_create_default(ADS_STRUCT *ads);
|
||||
int ads_keytab_list(const char *keytab_name);
|
||||
|
||||
/* The following definitions come from libads/net_ads_setspn.c */
|
||||
@ -107,8 +103,6 @@ char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit);
|
||||
char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid);
|
||||
ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
|
||||
const char *name, const char **vals);
|
||||
uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name);
|
||||
uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name);
|
||||
|
||||
bool ads_element_in_array(const char **el_array, size_t num_el, const char *el);
|
||||
|
||||
@ -144,14 +138,7 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
|
||||
const char *extended_dn,
|
||||
enum ads_extended_dn_flags flags,
|
||||
struct dom_sid *sid);
|
||||
char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
|
||||
ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
|
||||
ADS_STRUCT *ads,
|
||||
const char *machine_name,
|
||||
char ***hostnames_array,
|
||||
size_t *num_hostnames);
|
||||
char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
|
||||
bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
|
||||
ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
|
||||
uint32_t account_type, const char *org_unit);
|
||||
ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname);
|
||||
|
@ -1000,514 +1000,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool fill_default_spns(TALLOC_CTX *ctx, const char *machine_name,
|
||||
const char *my_fqdn, const char *spn,
|
||||
const char ***spns)
|
||||
{
|
||||
char *psp1, *psp2;
|
||||
|
||||
if (*spns == NULL) {
|
||||
*spns = talloc_zero_array(ctx, const char*, 3);
|
||||
if (*spns == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
psp1 = talloc_asprintf(ctx,
|
||||
"%s/%s",
|
||||
spn,
|
||||
machine_name);
|
||||
if (psp1 == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlower_m(&psp1[strlen(spn) + 1])) {
|
||||
return false;
|
||||
}
|
||||
(*spns)[0] = psp1;
|
||||
|
||||
psp2 = talloc_asprintf(ctx,
|
||||
"%s/%s",
|
||||
spn,
|
||||
my_fqdn);
|
||||
if (psp2 == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlower_m(&psp2[strlen(spn) + 1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*spns)[1] = psp2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ads_set_machine_account_spns(TALLOC_CTX *ctx,
|
||||
ADS_STRUCT *ads,
|
||||
const char *service_or_spn,
|
||||
const char *my_fqdn)
|
||||
{
|
||||
const char **spn_names = NULL;
|
||||
ADS_STATUS aderr;
|
||||
struct spn_struct* spn_struct = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
/* SPN should have '/' */
|
||||
tmp = strchr_m(service_or_spn, '/');
|
||||
if (tmp != NULL) {
|
||||
spn_struct = parse_spn(ctx, service_or_spn);
|
||||
if (spn_struct == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DBG_INFO("Attempting to add/update '%s'\n", service_or_spn);
|
||||
|
||||
if (spn_struct != NULL) {
|
||||
spn_names = talloc_zero_array(ctx, const char*, 2);
|
||||
spn_names[0] = service_or_spn;
|
||||
} else {
|
||||
bool ok;
|
||||
|
||||
ok = fill_default_spns(ctx,
|
||||
lp_netbios_name(),
|
||||
my_fqdn,
|
||||
service_or_spn,
|
||||
&spn_names);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
aderr = ads_add_service_principal_names(ads,
|
||||
lp_netbios_name(),
|
||||
spn_names);
|
||||
if (!ADS_ERR_OK(aderr)) {
|
||||
DBG_WARNING("Failed to add service principal name.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create kerberos principal(s) from SPN or service name.
|
||||
*/
|
||||
static bool service_or_spn_to_kerberos_princ(TALLOC_CTX *ctx,
|
||||
const char *service_or_spn,
|
||||
const char *my_fqdn,
|
||||
char **p_princ_s,
|
||||
char **p_short_princ_s)
|
||||
{
|
||||
char *princ_s = NULL;
|
||||
char *short_princ_s = NULL;
|
||||
const char *service = service_or_spn;
|
||||
const char *host = my_fqdn;
|
||||
struct spn_struct* spn_struct = NULL;
|
||||
char *tmp = NULL;
|
||||
bool ok = true;
|
||||
|
||||
/* SPN should have '/' */
|
||||
tmp = strchr_m(service_or_spn, '/');
|
||||
if (tmp != NULL) {
|
||||
spn_struct = parse_spn(ctx, service_or_spn);
|
||||
if (spn_struct == NULL) {
|
||||
ok = false;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (spn_struct != NULL) {
|
||||
service = spn_struct->serviceclass;
|
||||
host = spn_struct->host;
|
||||
}
|
||||
princ_s = talloc_asprintf(ctx, "%s/%s@%s",
|
||||
service,
|
||||
host, lp_realm());
|
||||
if (princ_s == NULL) {
|
||||
ok = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (spn_struct == NULL) {
|
||||
short_princ_s = talloc_asprintf(ctx, "%s/%s@%s",
|
||||
service, lp_netbios_name(),
|
||||
lp_realm());
|
||||
if (short_princ_s == NULL) {
|
||||
ok = false;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
*p_princ_s = princ_s;
|
||||
*p_short_princ_s = short_princ_s;
|
||||
out:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int add_kt_entry_etypes(krb5_context context, TALLOC_CTX *tmpctx,
|
||||
ADS_STRUCT *ads, const char *salt_princ_s,
|
||||
krb5_keytab keytab, krb5_kvno kvno,
|
||||
const char *srvPrinc, const char *my_fqdn,
|
||||
krb5_data *password, bool update_ads)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
char *princ_s = NULL;
|
||||
char *short_princ_s = NULL;
|
||||
krb5_enctype enctypes[4] = {
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
ENCTYPE_ARCFOUR_HMAC,
|
||||
0
|
||||
};
|
||||
size_t i;
|
||||
|
||||
/* Construct our principal */
|
||||
if (strchr_m(srvPrinc, '@')) {
|
||||
/* It's a fully-named principal. */
|
||||
princ_s = talloc_asprintf(tmpctx, "%s", srvPrinc);
|
||||
if (!princ_s) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
|
||||
/* It's the machine account, as used by smbclient clients. */
|
||||
princ_s = talloc_asprintf(tmpctx, "%s@%s",
|
||||
srvPrinc, lp_realm());
|
||||
if (!princ_s) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* It's a normal service principal. Add the SPN now so that we
|
||||
* can obtain credentials for it and double-check the salt value
|
||||
* used to generate the service's keys. */
|
||||
|
||||
if (!service_or_spn_to_kerberos_princ(tmpctx,
|
||||
srvPrinc,
|
||||
my_fqdn,
|
||||
&princ_s,
|
||||
&short_princ_s)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* According to http://support.microsoft.com/kb/326985/en-us,
|
||||
certain principal names are automatically mapped to the
|
||||
host/... principal in the AD account.
|
||||
So only create these in the keytab, not in AD. --jerry */
|
||||
|
||||
if (update_ads && !strequal(srvPrinc, "cifs") &&
|
||||
!strequal(srvPrinc, "host")) {
|
||||
if (!ads_set_machine_account_spns(tmpctx,
|
||||
ads,
|
||||
srvPrinc,
|
||||
my_fqdn)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; enctypes[i]; i++) {
|
||||
|
||||
/* add the fqdn principal to the keytab */
|
||||
ret = smb_krb5_kt_add_password(context,
|
||||
keytab,
|
||||
kvno,
|
||||
princ_s,
|
||||
salt_princ_s,
|
||||
enctypes[i],
|
||||
password);
|
||||
if (ret) {
|
||||
DBG_WARNING("Failed to add entry to keytab\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* add the short principal name if we have one */
|
||||
if (short_princ_s) {
|
||||
ret = smb_krb5_kt_add_password(context,
|
||||
keytab,
|
||||
kvno,
|
||||
short_princ_s,
|
||||
salt_princ_s,
|
||||
enctypes[i],
|
||||
password);
|
||||
if (ret) {
|
||||
DBG_WARNING("Failed to add short entry to keytab\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Adds a single service principal, i.e. 'host' to the system keytab
|
||||
***********************************************************************/
|
||||
|
||||
int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
krb5_context context = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_data password;
|
||||
krb5_kvno kvno;
|
||||
char *salt_princ_s = NULL;
|
||||
char *password_s = NULL;
|
||||
char *my_fqdn;
|
||||
TALLOC_CTX *tmpctx = NULL;
|
||||
char **hostnames_array = NULL;
|
||||
size_t num_hostnames = 0;
|
||||
|
||||
ret = smb_krb5_init_context_common(&context);
|
||||
if (ret) {
|
||||
DBG_ERR("kerberos init context failed (%s)\n",
|
||||
error_message(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ads_keytab_open(context, &keytab);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* retrieve the password */
|
||||
if (!secrets_init()) {
|
||||
DBG_WARNING("secrets_init failed\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
|
||||
if (!password_s) {
|
||||
DBG_WARNING("failed to fetch machine password\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
ZERO_STRUCT(password);
|
||||
password.data = password_s;
|
||||
password.length = strlen(password_s);
|
||||
|
||||
/* we need the dNSHostName value here */
|
||||
tmpctx = talloc_init(__location__);
|
||||
if (!tmpctx) {
|
||||
DBG_ERR("talloc_init() failed!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
|
||||
if (!my_fqdn) {
|
||||
DBG_ERR("unable to determine machine account's dns name in "
|
||||
"AD!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* make sure we have a single instance of the computer account */
|
||||
if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
|
||||
DBG_ERR("unable to determine machine account's short name in "
|
||||
"AD!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
|
||||
if (kvno == -1) {
|
||||
/* -1 indicates failure, everything else is OK */
|
||||
DBG_WARNING("ads_get_machine_kvno failed to determine the "
|
||||
"system's kvno.\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
salt_princ_s = kerberos_secrets_fetch_salt_princ();
|
||||
if (salt_princ_s == NULL) {
|
||||
DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab,
|
||||
kvno, srvPrinc, my_fqdn, &password,
|
||||
update_ads);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads,
|
||||
lp_netbios_name(),
|
||||
&hostnames_array,
|
||||
&num_hostnames))) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num_hostnames; i++) {
|
||||
|
||||
ret = add_kt_entry_etypes(context, tmpctx, ads,
|
||||
salt_princ_s, keytab,
|
||||
kvno, srvPrinc,
|
||||
hostnames_array[i],
|
||||
&password, update_ads);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
SAFE_FREE(salt_princ_s);
|
||||
TALLOC_FREE(tmpctx);
|
||||
|
||||
if (keytab) {
|
||||
krb5_kt_close(context, keytab);
|
||||
}
|
||||
if (context) {
|
||||
krb5_free_context(context);
|
||||
}
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Delete a single service principal, i.e. 'host' from the system keytab
|
||||
***********************************************************************/
|
||||
|
||||
int ads_keytab_delete_entry(ADS_STRUCT *ads, const char *srvPrinc)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
krb5_error_code ret = 0;
|
||||
krb5_context context = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
char *princ_s = NULL;
|
||||
krb5_principal princ = NULL;
|
||||
char *short_princ_s = NULL;
|
||||
krb5_principal short_princ = NULL;
|
||||
bool ok;
|
||||
|
||||
ret = smb_krb5_init_context_common(&context);
|
||||
if (ret) {
|
||||
DBG_ERR("kerberos init context failed (%s)\n",
|
||||
error_message(ret));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ads_keytab_open(context, &keytab);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Construct our principal */
|
||||
if (strchr_m(srvPrinc, '@')) {
|
||||
/* It's a fully-named principal. */
|
||||
princ_s = talloc_asprintf(frame, "%s", srvPrinc);
|
||||
if (!princ_s) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
|
||||
/* It's the machine account, as used by smbclient clients. */
|
||||
princ_s = talloc_asprintf(frame, "%s@%s",
|
||||
srvPrinc, lp_realm());
|
||||
if (!princ_s) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* It's a normal service principal.
|
||||
*/
|
||||
char *my_fqdn = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
/*
|
||||
* SPN should have '/' otherwise we
|
||||
* need to fallback and find our dnshostname
|
||||
*/
|
||||
tmp = strchr_m(srvPrinc, '/');
|
||||
if (tmp == NULL) {
|
||||
my_fqdn = ads_get_dnshostname(ads, frame, lp_netbios_name());
|
||||
if (!my_fqdn) {
|
||||
DBG_ERR("unable to determine machine account's dns name in "
|
||||
"AD!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ok = service_or_spn_to_kerberos_princ(frame,
|
||||
srvPrinc,
|
||||
my_fqdn,
|
||||
&princ_s,
|
||||
&short_princ_s);
|
||||
if (!ok) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = smb_krb5_parse_name(context, princ_s, &princ);
|
||||
if (ret) {
|
||||
DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
|
||||
"failed (%s)\n", princ_s, error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (short_princ_s != NULL) {
|
||||
ret = smb_krb5_parse_name(context, short_princ_s, &short_princ);
|
||||
if (ret) {
|
||||
DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
|
||||
"failed (%s)\n", short_princ_s, error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Seek and delete old keytab entries */
|
||||
ret = smb_krb5_kt_seek_and_delete_old_entries(context,
|
||||
keytab,
|
||||
false, /* keep_old_kvno */
|
||||
-1,
|
||||
false, /* enctype_only */
|
||||
ENCTYPE_NULL,
|
||||
princ_s,
|
||||
princ,
|
||||
false); /* flush */
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (short_princ_s == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Seek and delete old keytab entries */
|
||||
ret = smb_krb5_kt_seek_and_delete_old_entries(context,
|
||||
keytab,
|
||||
false, /* keep_old_kvno */
|
||||
-1,
|
||||
false, /* enctype_only */
|
||||
ENCTYPE_NULL,
|
||||
short_princ_s,
|
||||
short_princ,
|
||||
false); /* flush */
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (princ) {
|
||||
krb5_free_principal(context, princ);
|
||||
}
|
||||
if (short_princ) {
|
||||
krb5_free_principal(context, short_princ);
|
||||
}
|
||||
if (keytab) {
|
||||
krb5_kt_close(context, keytab);
|
||||
}
|
||||
if (context) {
|
||||
krb5_free_context(context);
|
||||
}
|
||||
TALLOC_FREE(frame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Flushes all entries from the system keytab.
|
||||
***********************************************************************/
|
||||
@ -1563,278 +1055,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Adds all the required service principals to the system keytab.
|
||||
***********************************************************************/
|
||||
|
||||
int ads_keytab_create_default(ADS_STRUCT *ads)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
krb5_context context = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_kt_cursor cursor = {0};
|
||||
krb5_keytab_entry kt_entry = {0};
|
||||
krb5_kvno kvno;
|
||||
size_t found = 0;
|
||||
char *sam_account_name, *upn;
|
||||
char **oldEntries = NULL, *princ_s[26];
|
||||
TALLOC_CTX *frame;
|
||||
char *machine_name;
|
||||
char **spn_array;
|
||||
size_t num_spns;
|
||||
size_t i;
|
||||
bool ok = false;
|
||||
ADS_STATUS status;
|
||||
|
||||
ZERO_STRUCT(kt_entry);
|
||||
ZERO_STRUCT(cursor);
|
||||
|
||||
frame = talloc_stackframe();
|
||||
if (frame == NULL) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = ads_get_service_principal_names(frame,
|
||||
ads,
|
||||
lp_netbios_name(),
|
||||
&spn_array,
|
||||
&num_spns);
|
||||
if (!ADS_ERR_OK(status)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_spns; i++) {
|
||||
char *srv_princ;
|
||||
char *p;
|
||||
|
||||
srv_princ = strlower_talloc(frame, spn_array[i]);
|
||||
if (srv_princ == NULL) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = strchr_m(srv_princ, '/');
|
||||
if (p == NULL) {
|
||||
continue;
|
||||
}
|
||||
p[0] = '\0';
|
||||
|
||||
/* Add the SPNs found on the DC */
|
||||
ret = ads_keytab_add_entry(ads, srv_princ, false);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, ("ads_keytab_add_entry failed while "
|
||||
"adding '%s' principal.\n",
|
||||
spn_array[i]));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* don't create the CIFS/... keytab entries since no one except smbd
|
||||
really needs them and we will fall back to verifying against
|
||||
secrets.tdb */
|
||||
|
||||
ret = ads_keytab_add_entry(ads, "cifs", false));
|
||||
if (ret != 0 ) {
|
||||
DEBUG(1, (__location__ ": ads_keytab_add_entry failed while "
|
||||
"adding 'cifs'.\n"));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(princ_s, '\0', sizeof(princ_s));
|
||||
|
||||
ret = smb_krb5_init_context_common(&context);
|
||||
if (ret) {
|
||||
DBG_ERR("kerberos init context failed (%s)\n",
|
||||
error_message(ret));
|
||||
goto done;
|
||||
}
|
||||
|
||||
machine_name = talloc_strdup(frame, lp_netbios_name());
|
||||
if (!machine_name) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* now add the userPrincipalName and sAMAccountName entries */
|
||||
ok = ads_has_samaccountname(ads, frame, machine_name);
|
||||
if (!ok) {
|
||||
DEBUG(0, (__location__ ": unable to determine machine "
|
||||
"account's name in AD!\n"));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* append '$' to netbios name so 'ads_keytab_add_entry' recognises
|
||||
* it as a machine account rather than a service or Windows SPN.
|
||||
*/
|
||||
sam_account_name = talloc_asprintf(frame, "%s$",machine_name);
|
||||
if (sam_account_name == NULL) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
/* upper case the sAMAccountName to make it easier for apps to
|
||||
know what case to use in the keytab file */
|
||||
if (!strupper_m(sam_account_name)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = ads_keytab_add_entry(ads, sam_account_name, false);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, (__location__ ": ads_keytab_add_entry() failed "
|
||||
"while adding sAMAccountName (%s)\n",
|
||||
sam_account_name));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* remember that not every machine account will have a upn */
|
||||
upn = ads_get_upn(ads, frame, machine_name);
|
||||
if (upn) {
|
||||
ret = ads_keytab_add_entry(ads, upn, false);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, (__location__ ": ads_keytab_add_entry() "
|
||||
"failed while adding UPN (%s)\n", upn));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now loop through the keytab and update any other existing entries */
|
||||
kvno = (krb5_kvno)ads_get_machine_kvno(ads, machine_name);
|
||||
if (kvno == (krb5_kvno)-1) {
|
||||
DEBUG(1, (__location__ ": ads_get_machine_kvno() failed to "
|
||||
"determine the system's kvno.\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
DEBUG(3, (__location__ ": Searching for keytab entries to preserve "
|
||||
"and update.\n"));
|
||||
|
||||
ret = ads_keytab_open(context, &keytab);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
|
||||
if (ret != KRB5_KT_END && ret != ENOENT ) {
|
||||
while ((ret = samba_krb5_kt_next_entry(
|
||||
context, keytab, &kt_entry, &cursor)) == 0)
|
||||
{
|
||||
smb_krb5_kt_free_entry(context, &kt_entry);
|
||||
ZERO_STRUCT(kt_entry);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
krb5_kt_end_seq_get(context, keytab, &cursor);
|
||||
ZERO_STRUCT(cursor);
|
||||
|
||||
/*
|
||||
* Hmmm. There is no "rewind" function for the keytab. This means we
|
||||
* have a race condition where someone else could add entries after
|
||||
* we've counted them. Re-open asap to minimise the race. JRA.
|
||||
*/
|
||||
DEBUG(3, (__location__ ": Found %zd entries in the keytab.\n", found));
|
||||
if (!found) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
oldEntries = talloc_zero_array(frame, char *, found + 1);
|
||||
if (!oldEntries) {
|
||||
DEBUG(1, (__location__ ": Failed to allocate space to store "
|
||||
"the old keytab entries (talloc failed?).\n"));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
|
||||
if (ret == KRB5_KT_END || ret == ENOENT) {
|
||||
krb5_kt_end_seq_get(context, keytab, &cursor);
|
||||
ZERO_STRUCT(cursor);
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (samba_krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) ==
|
||||
0)
|
||||
{
|
||||
if (kt_entry.vno != kvno) {
|
||||
char *ktprinc = NULL;
|
||||
char *p;
|
||||
|
||||
/* This returns a malloc'ed string in ktprinc. */
|
||||
ret = smb_krb5_unparse_name(oldEntries,
|
||||
context,
|
||||
kt_entry.principal,
|
||||
&ktprinc);
|
||||
if (ret) {
|
||||
DEBUG(1, (__location__
|
||||
": smb_krb5_unparse_name failed "
|
||||
"(%s)\n", error_message(ret)));
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* From looking at the krb5 source they don't seem to
|
||||
* take locale or mb strings into account.
|
||||
* Maybe this is because they assume utf8 ?
|
||||
* In this case we may need to convert from utf8 to
|
||||
* mb charset here ? JRA.
|
||||
*/
|
||||
p = strchr_m(ktprinc, '@');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
p = strchr_m(ktprinc, '/');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
}
|
||||
for (i = 0; i < found; i++) {
|
||||
if (!oldEntries[i]) {
|
||||
oldEntries[i] = ktprinc;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(oldEntries[i], ktprinc)) {
|
||||
TALLOC_FREE(ktprinc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == found) {
|
||||
TALLOC_FREE(ktprinc);
|
||||
}
|
||||
}
|
||||
smb_krb5_kt_free_entry(context, &kt_entry);
|
||||
ZERO_STRUCT(kt_entry);
|
||||
}
|
||||
krb5_kt_end_seq_get(context, keytab, &cursor);
|
||||
ZERO_STRUCT(cursor);
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; oldEntries[i]; i++) {
|
||||
ret |= ads_keytab_add_entry(ads, oldEntries[i], false);
|
||||
TALLOC_FREE(oldEntries[i]);
|
||||
}
|
||||
|
||||
done:
|
||||
TALLOC_FREE(oldEntries);
|
||||
TALLOC_FREE(frame);
|
||||
|
||||
if (context) {
|
||||
if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
|
||||
smb_krb5_kt_free_entry(context, &kt_entry);
|
||||
}
|
||||
if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
|
||||
krb5_kt_end_seq_get(context, keytab, &cursor);
|
||||
}
|
||||
if (keytab) {
|
||||
krb5_kt_close(context, keytab);
|
||||
}
|
||||
krb5_free_context(context);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAVE_ADS */
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -2284,86 +2284,6 @@ ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
|
||||
(const void *) vals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the an account's current KVNO via an LDAP lookup
|
||||
* @param ads An initialized ADS_STRUCT
|
||||
* @param account_name the NT samaccountname.
|
||||
* @return the kvno for the account, or -1 in case of a failure.
|
||||
**/
|
||||
|
||||
uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
|
||||
{
|
||||
LDAPMessage *res = NULL;
|
||||
uint32_t kvno = (uint32_t)-1; /* -1 indicates a failure */
|
||||
char *filter;
|
||||
const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
|
||||
char *dn_string = NULL;
|
||||
ADS_STATUS ret;
|
||||
|
||||
DEBUG(5,("ads_get_kvno: Searching for account %s\n", account_name));
|
||||
if (asprintf(&filter, "(samAccountName=%s)", account_name) == -1) {
|
||||
return kvno;
|
||||
}
|
||||
ret = ads_search(ads, &res, filter, attrs);
|
||||
SAFE_FREE(filter);
|
||||
if (!ADS_ERR_OK(ret) || (ads_count_replies(ads, res) != 1)) {
|
||||
DEBUG(1,("ads_get_kvno: Account for %s not found.\n", account_name));
|
||||
ads_msgfree(ads, res);
|
||||
return kvno;
|
||||
}
|
||||
|
||||
dn_string = ads_get_dn(ads, talloc_tos(), res);
|
||||
if (!dn_string) {
|
||||
DEBUG(0,("ads_get_kvno: out of memory.\n"));
|
||||
ads_msgfree(ads, res);
|
||||
return kvno;
|
||||
}
|
||||
DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
|
||||
TALLOC_FREE(dn_string);
|
||||
|
||||
/* ---------------------------------------------------------
|
||||
* 0 is returned as a default KVNO from this point on...
|
||||
* This is done because Windows 2000 does not support key
|
||||
* version numbers. Chances are that a failure in the next
|
||||
* step is simply due to Windows 2000 being used for a
|
||||
* domain controller. */
|
||||
kvno = 0;
|
||||
|
||||
if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) {
|
||||
DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n"));
|
||||
DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n"));
|
||||
ads_msgfree(ads, res);
|
||||
return kvno;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno));
|
||||
ads_msgfree(ads, res);
|
||||
return kvno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the computer account's current KVNO via an LDAP lookup
|
||||
* @param ads An initialized ADS_STRUCT
|
||||
* @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
|
||||
* @return the kvno for the computer account, or -1 in case of a failure.
|
||||
**/
|
||||
|
||||
uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name)
|
||||
{
|
||||
char *computer_account = NULL;
|
||||
uint32_t kvno = -1;
|
||||
|
||||
if (asprintf(&computer_account, "%s$", machine_name) < 0) {
|
||||
return kvno;
|
||||
}
|
||||
|
||||
kvno = ads_get_kvno(ads, computer_account);
|
||||
free(computer_account);
|
||||
|
||||
return kvno;
|
||||
}
|
||||
|
||||
/**
|
||||
* This clears out all registered spn's for a given hostname
|
||||
* @param ads An initialized ADS_STRUCT
|
||||
@ -4178,124 +4098,6 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
|
||||
/********************************************************************
|
||||
********************************************************************/
|
||||
|
||||
char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
|
||||
{
|
||||
LDAPMessage *res = NULL;
|
||||
ADS_STATUS status;
|
||||
int count = 0;
|
||||
char *name = NULL;
|
||||
|
||||
status = ads_find_machine_acct(ads, &res, machine_name);
|
||||
if (!ADS_ERR_OK(status)) {
|
||||
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
|
||||
lp_netbios_name()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( (count = ads_count_replies(ads, res)) != 1 ) {
|
||||
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( (name = ads_pull_string(ads, ctx, res, "dNSHostName")) == NULL ) {
|
||||
DEBUG(0,("ads_get_dnshostname: No dNSHostName attribute!\n"));
|
||||
}
|
||||
|
||||
out:
|
||||
ads_msgfree(ads, res);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
********************************************************************/
|
||||
|
||||
static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
|
||||
LDAPMessage *msg, size_t *num_values)
|
||||
{
|
||||
const char *field = "msDS-AdditionalDnsHostName";
|
||||
struct berval **values = NULL;
|
||||
char **ret = NULL;
|
||||
size_t i, converted_size;
|
||||
|
||||
/*
|
||||
* Windows DC implicitly adds a short name for each FQDN added to
|
||||
* msDS-AdditionalDnsHostName, but it comes with a strange binary
|
||||
* suffix "\0$" which we should ignore (see bug #14406).
|
||||
*/
|
||||
|
||||
values = ldap_get_values_len(ads->ldap.ld, msg, field);
|
||||
if (values == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*num_values = ldap_count_values_len(values);
|
||||
|
||||
ret = talloc_array(mem_ctx, char *, *num_values + 1);
|
||||
if (ret == NULL) {
|
||||
ldap_value_free_len(values);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < *num_values; i++) {
|
||||
ret[i] = NULL;
|
||||
if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
|
||||
values[i]->bv_val,
|
||||
strnlen(values[i]->bv_val,
|
||||
values[i]->bv_len),
|
||||
&ret[i], &converted_size)) {
|
||||
ldap_value_free_len(values);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ret[i] = NULL;
|
||||
|
||||
ldap_value_free_len(values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
|
||||
ADS_STRUCT *ads,
|
||||
const char *machine_name,
|
||||
char ***hostnames_array,
|
||||
size_t *num_hostnames)
|
||||
{
|
||||
ADS_STATUS status;
|
||||
LDAPMessage *res = NULL;
|
||||
int count;
|
||||
|
||||
status = ads_find_machine_acct(ads,
|
||||
&res,
|
||||
machine_name);
|
||||
if (!ADS_ERR_OK(status)) {
|
||||
DEBUG(1,("Host Account for %s not found... skipping operation.\n",
|
||||
machine_name));
|
||||
return status;
|
||||
}
|
||||
|
||||
count = ads_count_replies(ads, res);
|
||||
if (count != 1) {
|
||||
status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
|
||||
goto done;
|
||||
}
|
||||
|
||||
*hostnames_array = get_addl_hosts(ads, mem_ctx, res, num_hostnames);
|
||||
if (*hostnames_array == NULL) {
|
||||
DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n",
|
||||
machine_name));
|
||||
status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
ads_msgfree(ads, res);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
********************************************************************/
|
||||
|
||||
char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
|
||||
{
|
||||
LDAPMessage *res = NULL;
|
||||
@ -4325,42 +4127,6 @@ out:
|
||||
return name;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
********************************************************************/
|
||||
|
||||
bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
|
||||
{
|
||||
LDAPMessage *res = NULL;
|
||||
ADS_STATUS status;
|
||||
int count = 0;
|
||||
char *name = NULL;
|
||||
bool ok = false;
|
||||
|
||||
status = ads_find_machine_acct(ads, &res, machine_name);
|
||||
if (!ADS_ERR_OK(status)) {
|
||||
DEBUG(0,("ads_has_samaccountname: Failed to find account for %s\n",
|
||||
lp_netbios_name()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( (count = ads_count_replies(ads, res)) != 1 ) {
|
||||
DEBUG(1,("ads_has_samaccountname: %d entries returned!\n", count));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) {
|
||||
DEBUG(0,("ads_has_samaccountname: No sAMAccountName attribute!\n"));
|
||||
}
|
||||
|
||||
out:
|
||||
ads_msgfree(ads, res);
|
||||
if (name != NULL) {
|
||||
ok = (strlen(name) > 0);
|
||||
}
|
||||
TALLOC_FREE(name);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
SAVED CODE - we used to join via ldap - remember how we did this. JRA.
|
||||
|
Loading…
x
Reference in New Issue
Block a user