keytab_str,
sizeof(keytab_str) - 2);
if (ret != 0) {
- DBG_WARNING("Failed to get default keytab name");
+ DBG_WARNING("Failed to get default keytab name\n");
goto out;
}
keytab_name = keytab_str;
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
***********************************************************************/
krb5_keytab keytab = NULL;
krb5_data password;
krb5_kvno kvno;
- krb5_enctype enctypes[6] = {
- ENCTYPE_DES_CBC_CRC,
- ENCTYPE_DES_CBC_MD5,
-#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
- ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-#endif
-#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
- ENCTYPE_AES256_CTS_HMAC_SHA1_96,
-#endif
- ENCTYPE_ARCFOUR_HMAC,
- 0
- };
- char *princ_s = NULL;
- char *short_princ_s = NULL;
char *salt_princ_s = NULL;
char *password_s = NULL;
char *my_fqdn;
TALLOC_CTX *tmpctx = NULL;
- int i;
+ char **hostnames_array = NULL;
+ size_t num_hostnames = 0;
- initialize_krb5_error_table();
- ret = krb5_init_context(&context);
+ ret = smb_krb5_init_context_common(&context);
if (ret) {
- DEBUG(1, (__location__ ": could not krb5_init_context: %s\n",
- error_message(ret)));
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(ret));
return -1;
}
/* retrieve the password */
if (!secrets_init()) {
- DEBUG(1, (__location__ ": secrets_init failed\n"));
+ DBG_WARNING("secrets_init failed\n");
ret = -1;
goto out;
}
password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
if (!password_s) {
- DEBUG(1, (__location__ ": failed to fetch machine password\n"));
+ DBG_WARNING("failed to fetch machine password\n");
ret = -1;
goto out;
}
/* we need the dNSHostName value here */
tmpctx = talloc_init(__location__);
if (!tmpctx) {
- DEBUG(0, (__location__ ": talloc_init() failed!\n"));
+ DBG_ERR("talloc_init() failed!\n");
ret = -1;
goto out;
}
my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
if (!my_fqdn) {
- DEBUG(0, (__location__ ": unable to determine machine "
- "account's dns name in AD!\n"));
+ 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 a the computer account */
+ /* make sure we have a single instance of the computer account */
if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
- DEBUG(0, (__location__ ": unable to determine machine "
- "account's short name in AD!\n"));
+ 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(tmpctx, "%s", srvPrinc);
+ 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(tmpctx, "%s@%s",
+ princ_s = talloc_asprintf(frame, "%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. */
+ /*
+ * 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;
+ }
+ }
- if (!service_or_spn_to_kerberos_princ(tmpctx,
+ ok = service_or_spn_to_kerberos_princ(frame,
srvPrinc,
my_fqdn,
&princ_s,
- &short_princ_s)) {
+ &short_princ_s);
+ if (!ok) {
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 */
+ 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 (update_ads && !strequal(srvPrinc, "cifs") &&
- !strequal(srvPrinc, "host")) {
- if (!ads_set_machine_account_spns(tmpctx,
- ads,
- srvPrinc,
- my_fqdn)) {
- ret = -1;
- 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;
}
}
- kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
- if (kvno == -1) {
- /* -1 indicates failure, everything else is OK */
- DEBUG(1, (__location__ ": ads_get_machine_kvno failed to "
- "determine the system's kvno.\n"));
- ret = -1;
+ /* 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;
}
- salt_princ_s = kerberos_secrets_fetch_salt_princ();
- if (salt_princ_s == NULL) {
- DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
- ret = -1;
+ if (short_princ_s == NULL) {
goto out;
}
- for (i = 0; enctypes[i]; i++) {
-
- /* add the fqdn principal to the keytab */
- ret = smb_krb5_kt_add_entry(context,
- keytab,
- kvno,
- princ_s,
- salt_princ_s,
- enctypes[i],
- &password,
- false,
- false);
- if (ret) {
- DEBUG(1, (__location__ ": 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_entry(context,
- keytab,
- kvno,
- short_princ_s,
- salt_princ_s,
- enctypes[i],
- &password,
- false,
- false);
- if (ret) {
- DEBUG(1, (__location__
- ": Failed to add short entry to keytab\n"));
- 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:
- SAFE_FREE(salt_princ_s);
- TALLOC_FREE(tmpctx);
-
+ 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);
}
- return (int)ret;
+ TALLOC_FREE(frame);
+ return ret;
}
/**********************************************************************
krb5_error_code ret = 0;
krb5_context context = NULL;
krb5_keytab keytab = NULL;
- krb5_kvno kvno;
ADS_STATUS aderr;
- initialize_krb5_error_table();
- ret = krb5_init_context(&context);
+ ret = smb_krb5_init_context_common(&context);
if (ret) {
- DEBUG(1, (__location__ ": could not krb5_init_context: %s\n",
- error_message(ret)));
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(ret));
return ret;
}
goto out;
}
- kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
- if (kvno == -1) {
- /* -1 indicates a failure */
- DEBUG(1, (__location__ ": Error determining the kvno.\n"));
- goto out;
- }
-
- /* Seek and delete old keytab entries */
+ /* Seek and delete all old keytab entries */
ret = smb_krb5_kt_seek_and_delete_old_entries(context,
keytab,
- kvno,
+ false, /* keep_old_kvno */
+ -1,
+ false, /* enctype_only */
ENCTYPE_NULL,
NULL,
NULL,
- true,
- false);
+ true); /* flush */
if (ret) {
goto out;
}
if (!ADS_ERR_OK(aderr)) {
DEBUG(1, (__location__ ": Error while clearing service "
"principal listings in LDAP.\n"));
+ ret = -1;
goto out;
}
memset(princ_s, '\0', sizeof(princ_s));
- initialize_krb5_error_table();
- ret = krb5_init_context(&context);
+ ret = smb_krb5_init_context_common(&context);
if (ret) {
- DEBUG(1, (__location__ ": could not krb5_init_context: %s\n",
- error_message(ret)));
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(ret));
goto done;
}
ZERO_STRUCT(kt_entry);
ZERO_STRUCT(cursor);
- initialize_krb5_error_table();
- ret = krb5_init_context(&context);
+ ret = smb_krb5_init_context_common(&context);
if (ret) {
- DEBUG(1, (__location__ ": could not krb5_init_context: %s\n",
- error_message(ret)));
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(ret));
return ret;
}
ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
if (ret &&
- (asprintf(&etype_s, "UNKNOWN: %d\n", enctype) == -1)) {
+ (asprintf(&etype_s, "UNKNOWN: %d", enctype) == -1)) {
TALLOC_FREE(princ_s);
goto out;
}