summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/libads/kerberos_keytab.c136
1 files changed, 94 insertions, 42 deletions
diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c
index ec44bfbe68..95ff0c1cf3 100644
--- a/source3/libads/kerberos_keytab.c
+++ b/source3/libads/kerberos_keytab.c
@@ -46,7 +46,7 @@ void name_to_fqdn(fstring fqdn, const char *name)
}
/**********************************************************************
- Adds a single service principal, i.e. 'host' to the system keytab
+ Adds a single service principal, i.e. 'host' to the system keytab
***********************************************************************/
int ads_keytab_add_entry(const char *srvPrinc, ADS_STRUCT *ads)
@@ -290,7 +290,7 @@ out:
}
/**********************************************************************
- Flushes all entries from the system keytab.
+ Flushes all entries from the system keytab.
***********************************************************************/
int ads_keytab_flush(ADS_STRUCT *ads)
@@ -339,35 +339,40 @@ int ads_keytab_flush(ADS_STRUCT *ads)
goto out;
}
-HERE
-
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
if (ret != KRB5_KT_END && ret != ENOENT) {
- while (!krb5_kt_next_entry(context, keytab, &entry, &cursor)) {
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ cursor = NULL;
if (ret) {
- DEBUG(1,("krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
+ DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
goto out;
}
- ret = krb5_kt_remove_entry(context, keytab, &entry);
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
if (ret) {
- DEBUG(1,("krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
goto out;
}
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
if (ret) {
- DEBUG(1,("krb5_kt_start_seq failed (%s)\n",error_message(ret)));
+ DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret)));
goto out;
}
- ret = krb5_kt_free_entry(context, &entry);
+ ret = krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
if (ret) {
- DEBUG(1,("krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
goto out;
}
}
}
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ cursor = NULL;
+
if (!ADS_ERR_OK(ads_clear_spns(ads, global_myname()))) {
- DEBUG(1,("Error while clearing service principal listings in LDAP.\n"));
+ DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n"));
goto out;
}
@@ -392,78 +397,105 @@ 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;
- krb5_context context;
- krb5_keytab keytab;
- krb5_kt_cursor cursor;
- krb5_keytab_entry entry;
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor = NULL;
+ krb5_keytab_entry kt_entry;
krb5_kvno kvno;
- char *ktprinc;
int i, found = 0;
- char **oldEntries;
+ char **oldEntries = NULL;
ret = ads_keytab_add_entry("host", ads);
if (ret) {
- DEBUG(1,("ads_keytab_add_entry failed while adding 'host'.\n"));
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n"));
return ret;
}
ret = ads_keytab_add_entry("cifs", ads);
if (ret) {
- DEBUG(1,("ads_keytab_add_entry failed while adding 'cifs'.\n"));
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n"));
return ret;
}
kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
if (kvno == -1) {
- DEBUG(1,("ads_get_kvno failed to determine the system's kvno.\n"));
+ DEBUG(1,("ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno.\n"));
return -1;
}
- DEBUG(1,("Searching for keytab entries to preserve and update.\n"));
+ DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to preserve and update.\n"));
/* Now loop through the keytab and update any other existing entries... */
+
+ ZERO_STRUCT(kt_entry);
+
initialize_krb5_error_table();
ret = krb5_init_context(&context);
if (ret) {
- DEBUG(1,("could not krb5_init_context: %s\n",error_message(ret)));
+ DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret)));
return ret;
}
ret = krb5_kt_default(context, &keytab);
if (ret) {
- DEBUG(1,("krb5_kt_default failed (%s)\n",error_message(ret)));
- return ret;
+ DEBUG(1,("ads_keytab_create_default: krb5_kt_default failed (%s)\n",error_message(ret)));
+ goto done;
}
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
if (ret != KRB5_KT_END && ret != ENOENT ) {
- while ((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
+ while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
+ krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
found++;
}
}
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ cursor = NULL;
- DEBUG(1, ("Found %d entries in the keytab.\n", found));
+ /*
+ * 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, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found));
if (!found) {
goto done;
}
oldEntries = (char **) malloc(found * sizeof(char *));
if (!oldEntries) {
- DEBUG(1,("Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
- return ENOMEM;
+ DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
+ ret = -1;
+ goto done;
}
- memset(oldEntries, 0, found * sizeof(char *));
+ memset(oldEntries, '\0', found * sizeof(char *));
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
if (ret != KRB5_KT_END && ret != ENOENT ) {
- while ((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
- if (entry.vno != kvno) {
- krb5_unparse_name(context, entry.principal, &ktprinc);
- for (i = 0; *(ktprinc + i); i++) {
- if (*(ktprinc + i) == '/') {
- *(ktprinc + i) = (char) NULL;
- break;
- }
+ while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
+ if (kt_entry.vno != kvno) {
+ char *ktprinc;
+ char *p;
+
+ /* This returns a malloc'ed string in ktprinc. */
+ ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc);
+ if (ret) {
+ DEBUG(1,("krb5_unparse_name failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ /*
+ * 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';
}
for (i = 0; i < found; i++) {
if (!oldEntries[i]) {
@@ -475,17 +507,37 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
}
}
}
+ krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
}
for (i = 0; oldEntries[i]; i++) {
ret |= ads_keytab_add_entry(oldEntries[i], ads);
- free(oldEntries[i]);
+ SAFE_FREE(oldEntries[i]);
}
+ krb5_kt_end_seq_get(context, keytab, &cursor);
}
- free(oldEntries);
+ cursor = NULL;
done:
- krb5_kt_close(context, keytab);
+ SAFE_FREE(oldEntries);
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ if (cursor && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
return ret;
}
#endif /* HAVE_KRB5 */