]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
krb5_wrap: Move smb_krb5_kt_add_entry() to krb5_wrap
authorAndreas Schneider <asn@samba.org>
Mon, 29 Feb 2016 16:31:56 +0000 (17:31 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 10 Mar 2016 05:52:25 +0000 (06:52 +0100)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/krb5_wrap/krb5_samba.c
lib/krb5_wrap/krb5_samba.h
source3/libads/kerberos_keytab.c

index 83bc8c923f10e506826d44a67fe064c52b8733bf..7cf62436b87026bce57a629b9da93a30b70231a7 100644 (file)
@@ -1448,6 +1448,311 @@ krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
        return ret;
 }
 
+/**
+ * @brief Seek and delete old entries in a keytab based on the passed
+ *        principal.
+ *
+ * @param[in]  context       The KRB5 context to use.
+ *
+ * @param[in]  keytab        The keytab to operate on.
+ *
+ * @param[in]  kvno          The kvnco to use.
+ *
+ * @param[in]  princ_s       The principal as a string to search for.
+ *
+ * @param[in]  princ         The principal as a krb5_principal to search for.
+ *
+ * @param[in]  flush         Weather to flush the complete keytab.
+ *
+ * @param[in]  keep_old_entries Keep the entry with the previous kvno.
+ *
+ * @retval 0 on Sucess
+ *
+ * @return An appropriate KRB5 error code.
+ */
+krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
+                                                       krb5_keytab keytab,
+                                                       krb5_kvno kvno,
+                                                       const char *princ_s,
+                                                       krb5_principal princ,
+                                                       bool flush,
+                                                       bool keep_old_entries)
+{
+       krb5_error_code ret;
+       krb5_kt_cursor cursor;
+       krb5_kt_cursor zero_csr;
+       krb5_keytab_entry kt_entry;
+       krb5_keytab_entry zero_kt_entry;
+       char *ktprinc = NULL;
+       krb5_kvno old_kvno = kvno - 1;
+       TALLOC_CTX *tmp_ctx;
+
+       ZERO_STRUCT(cursor);
+       ZERO_STRUCT(zero_csr);
+       ZERO_STRUCT(kt_entry);
+       ZERO_STRUCT(zero_kt_entry);
+
+       ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+       if (ret == KRB5_KT_END || ret == ENOENT ) {
+               /* no entries */
+               return 0;
+       }
+
+       tmp_ctx = talloc_new(NULL);
+       if (tmp_ctx == NULL) {
+               return ENOMEM;
+       }
+
+       DEBUG(3, (__location__ ": Will try to delete old keytab entries\n"));
+       while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+               bool name_ok = false;
+
+               if (!flush && (princ_s != NULL)) {
+                       ret = smb_krb5_unparse_name(tmp_ctx, context,
+                                                   kt_entry.principal,
+                                                   &ktprinc);
+                       if (ret) {
+                               DEBUG(1, (__location__
+                                         ": smb_krb5_unparse_name failed "
+                                         "(%s)\n", error_message(ret)));
+                               goto out;
+                       }
+
+#ifdef HAVE_KRB5_KT_COMPARE
+                       name_ok = krb5_kt_compare(context, &kt_entry,
+                                                 princ, 0, 0);
+#else
+                       name_ok = (strcmp(ktprinc, princ_s) == 0);
+#endif
+
+                       if (!name_ok) {
+                               DEBUG(10, (__location__ ": ignoring keytab "
+                                          "entry principal %s, kvno = %d\n",
+                                          ktprinc, kt_entry.vno));
+
+                               /* Not a match,
+                                * just free this entry and continue. */
+                               ret = smb_krb5_kt_free_entry(context,
+                                                            &kt_entry);
+                               ZERO_STRUCT(kt_entry);
+                               if (ret) {
+                                       DEBUG(1, (__location__
+                                                 ": smb_krb5_kt_free_entry "
+                                                 "failed (%s)\n",
+                                                 error_message(ret)));
+                                       goto out;
+                               }
+
+                               TALLOC_FREE(ktprinc);
+                               continue;
+                       }
+
+                       TALLOC_FREE(ktprinc);
+               }
+
+               /*------------------------------------------------------------
+                * Save the entries with kvno - 1. This is what microsoft does
+                * to allow people with existing sessions that have kvno - 1
+                * to still work. Otherwise, when the password for the machine
+                * changes, all kerberizied sessions will 'break' until either
+                * the client reboots or the client's session key expires and
+                * they get a new session ticket with the new kvno.
+                * Some keytab files only store the kvno in 8bits, limit
+                * the compare accordingly.
+                */
+
+               if (!flush && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
+                       DEBUG(5, (__location__ ": Saving previous (kvno %d) "
+                                 "entry for principal: %s.\n",
+                                 old_kvno, princ_s));
+                       continue;
+               }
+
+               if (keep_old_entries) {
+                       DEBUG(5, (__location__ ": Saving old (kvno %d) "
+                                 "entry for principal: %s.\n",
+                                 kvno, princ_s));
+                       continue;
+               }
+
+               DEBUG(5, (__location__ ": Found old entry for principal: %s "
+                         "(kvno %d) - trying to remove it.\n",
+                         princ_s, kt_entry.vno));
+
+               ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+               ZERO_STRUCT(cursor);
+               if (ret) {
+                       DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
+                                 "failed (%s)\n", error_message(ret)));
+                       goto out;
+               }
+               ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+               if (ret) {
+                       DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+                                 "failed (%s)\n", error_message(ret)));
+                       goto out;
+               }
+
+               DEBUG(5, (__location__ ": removed old entry for principal: "
+                         "%s (kvno %d).\n", princ_s, kt_entry.vno));
+
+               ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+               if (ret) {
+                       DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
+                                 "(%s)\n", error_message(ret)));
+                       goto out;
+               }
+               ret = smb_krb5_kt_free_entry(context, &kt_entry);
+               ZERO_STRUCT(kt_entry);
+               if (ret) {
+                       DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+                                 "failed (%s)\n", error_message(ret)));
+                       goto out;
+               }
+       }
+
+out:
+       talloc_free(tmp_ctx);
+       if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+               smb_krb5_kt_free_entry(context, &kt_entry);
+       }
+       if (keytab) {
+               if (memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) {
+                       krb5_kt_end_seq_get(context, keytab, &cursor);
+               }
+       }
+
+       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.
+ *
+ * @param[in]  no_salt        If the password should not be salted. Normally
+ *                            this is only set to false for encryption types
+ *                            which do not support salting like RC4.
+ *
+ * @param[in]  keep_old_entries Wether to keep or delte old keytab entries.
+ *
+ * @retval 0 on Success
+ *
+ * @return A corresponding KRB5 error code.
+ *
+ * @see smb_krb5_open_keytab()
+ */
+krb5_error_code smb_krb5_kt_add_entry(krb5_context context,
+                                     krb5_keytab keytab,
+                                     krb5_kvno kvno,
+                                     const char *princ_s,
+                                     const char *salt_principal,
+                                     krb5_enctype enctype,
+                                     krb5_data *password,
+                                     bool no_salt,
+                                     bool keep_old_entries)
+{
+       krb5_error_code ret;
+       krb5_keytab_entry kt_entry;
+       krb5_principal princ = NULL;
+       krb5_keyblock *keyp;
+
+       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,
+                                                     kvno,
+                                                     princ_s,
+                                                     princ,
+                                                     false,
+                                                     keep_old_entries);
+       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);
+
+       if (no_salt) {
+               KRB5_KEY_DATA(keyp) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
+               if (KRB5_KEY_DATA(keyp) == NULL) {
+                       ret = ENOMEM;
+                       goto out;
+               }
+               memcpy(KRB5_KEY_DATA(keyp), password->data, password->length);
+               KRB5_KEY_LENGTH(keyp) = password->length;
+               KRB5_KEY_TYPE(keyp) = enctype;
+       } else {
+               krb5_principal salt_princ = NULL;
+
+               /* 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 = 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)
index 5dcce04a3042cbe37852b2162e5130c1101f2095..a6079d3b4fc1cb391e6be4df26bd8561d9bc7995 100644 (file)
@@ -186,6 +186,23 @@ krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
                                     krb5_context context,
                                     krb5_keytab keytab,
                                     const char **keytab_name);
+krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
+                                                       krb5_keytab keytab,
+                                                       krb5_kvno kvno,
+                                                       const char *princ_s,
+                                                       krb5_principal princ,
+                                                       bool flush,
+                                                       bool keep_old_entries);
+krb5_error_code smb_krb5_kt_add_entry(krb5_context context,
+                                     krb5_keytab keytab,
+                                     krb5_kvno kvno,
+                                     const char *princ_s,
+                                     const char *salt_principal,
+                                     krb5_enctype enctype,
+                                     krb5_data *password,
+                                     bool no_salt,
+                                     bool keep_old_entries);
+
 krb5_error_code smb_krb5_get_credentials(krb5_context context,
                                         krb5_ccache ccache,
                                         krb5_principal me,
index 70bc68b95fd7bddd5db5bd0d0b46f86777c527bf..340e55252e822fad36ce67a1aa7112bdbf3fff4f 100644 (file)
 
 #ifdef HAVE_KRB5
 
-/**********************************************************************
-**********************************************************************/
-
-static krb5_error_code seek_and_delete_old_entries(krb5_context context,
-                                                  krb5_keytab keytab,
-                                                  krb5_kvno kvno,
-                                                  const char *princ_s,
-                                                  krb5_principal princ,
-                                                  bool flush,
-                                                  bool keep_old_entries)
-{
-       krb5_error_code ret;
-       krb5_kt_cursor cursor;
-       krb5_kt_cursor zero_csr;
-       krb5_keytab_entry kt_entry;
-       krb5_keytab_entry zero_kt_entry;
-       char *ktprinc = NULL;
-       krb5_kvno old_kvno = kvno - 1;
-
-       ZERO_STRUCT(cursor);
-       ZERO_STRUCT(zero_csr);
-       ZERO_STRUCT(kt_entry);
-       ZERO_STRUCT(zero_kt_entry);
-
-       ret = krb5_kt_start_seq_get(context, keytab, &cursor);
-       if (ret == KRB5_KT_END || ret == ENOENT ) {
-               /* no entries */
-               return 0;
-       }
-
-       DEBUG(3, (__location__ ": Will try to delete old keytab entries\n"));
-       while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
-               bool name_ok = false;
-
-               if (!flush && (princ_s != NULL)) {
-                       ret = smb_krb5_unparse_name(talloc_tos(), context,
-                                                   kt_entry.principal,
-                                                   &ktprinc);
-                       if (ret) {
-                               DEBUG(1, (__location__
-                                         ": smb_krb5_unparse_name failed "
-                                         "(%s)\n", error_message(ret)));
-                               goto out;
-                       }
-
-#ifdef HAVE_KRB5_KT_COMPARE
-                       name_ok = krb5_kt_compare(context, &kt_entry,
-                                                 princ, 0, 0);
-#else
-                       name_ok = (strcmp(ktprinc, princ_s) == 0);
-#endif
-
-                       if (!name_ok) {
-                               DEBUG(10, (__location__ ": ignoring keytab "
-                                          "entry principal %s, kvno = %d\n",
-                                          ktprinc, kt_entry.vno));
-
-                               /* Not a match,
-                                * just free this entry and continue. */
-                               ret = smb_krb5_kt_free_entry(context,
-                                                            &kt_entry);
-                               ZERO_STRUCT(kt_entry);
-                               if (ret) {
-                                       DEBUG(1, (__location__
-                                                 ": smb_krb5_kt_free_entry "
-                                                 "failed (%s)\n",
-                                                 error_message(ret)));
-                                       goto out;
-                               }
-
-                               TALLOC_FREE(ktprinc);
-                               continue;
-                       }
-
-                       TALLOC_FREE(ktprinc);
-               }
-
-               /*------------------------------------------------------------
-                * Save the entries with kvno - 1. This is what microsoft does
-                * to allow people with existing sessions that have kvno - 1
-                * to still work. Otherwise, when the password for the machine
-                * changes, all kerberizied sessions will 'break' until either
-                * the client reboots or the client's session key expires and
-                * they get a new session ticket with the new kvno.
-                * Some keytab files only store the kvno in 8bits, limit
-                * the compare accordingly.
-                */
-
-               if (!flush && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
-                       DEBUG(5, (__location__ ": Saving previous (kvno %d) "
-                                 "entry for principal: %s.\n",
-                                 old_kvno, princ_s));
-                       continue;
-               }
-
-               if (keep_old_entries) {
-                       DEBUG(5, (__location__ ": Saving old (kvno %d) "
-                                 "entry for principal: %s.\n",
-                                 kvno, princ_s));
-                       continue;
-               }
-
-               DEBUG(5, (__location__ ": Found old entry for principal: %s "
-                         "(kvno %d) - trying to remove it.\n",
-                         princ_s, kt_entry.vno));
-
-               ret = krb5_kt_end_seq_get(context, keytab, &cursor);
-               ZERO_STRUCT(cursor);
-               if (ret) {
-                       DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
-                                 "failed (%s)\n", error_message(ret)));
-                       goto out;
-               }
-               ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
-               if (ret) {
-                       DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
-                                 "failed (%s)\n", error_message(ret)));
-                       goto out;
-               }
-
-               DEBUG(5, (__location__ ": removed old entry for principal: "
-                         "%s (kvno %d).\n", princ_s, kt_entry.vno));
-
-               ret = krb5_kt_start_seq_get(context, keytab, &cursor);
-               if (ret) {
-                       DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
-                                 "(%s)\n", error_message(ret)));
-                       goto out;
-               }
-               ret = smb_krb5_kt_free_entry(context, &kt_entry);
-               ZERO_STRUCT(kt_entry);
-               if (ret) {
-                       DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
-                                 "failed (%s)\n", error_message(ret)));
-                       goto out;
-               }
-       }
-
-out:
-       if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
-               smb_krb5_kt_free_entry(context, &kt_entry);
-       }
-       if (keytab) {
-               if (memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) {
-                       krb5_kt_end_seq_get(context, keytab, &cursor);
-               }
-       }
-
-       return ret;
-}
-
-static int smb_krb5_kt_add_entry(krb5_context context,
-                                krb5_keytab keytab,
-                                krb5_kvno kvno,
-                                const char *princ_s,
-                                const char *salt_principal,
-                                krb5_enctype enctype,
-                                krb5_data *password,
-                                bool no_salt,
-                                bool keep_old_entries)
-{
-       krb5_error_code ret;
-       krb5_keytab_entry kt_entry;
-       krb5_principal princ = NULL;
-       krb5_keyblock *keyp;
-
-       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 = seek_and_delete_old_entries(context, keytab, kvno,
-                                         princ_s, princ, false,
-                                         keep_old_entries);
-       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);
-
-       if (no_salt) {
-               KRB5_KEY_DATA(keyp) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
-               if (KRB5_KEY_DATA(keyp) == NULL) {
-                       ret = ENOMEM;
-                       goto out;
-               }
-               memcpy(KRB5_KEY_DATA(keyp), password->data, password->length);
-               KRB5_KEY_LENGTH(keyp) = password->length;
-               KRB5_KEY_TYPE(keyp) = enctype;
-       } else {
-               krb5_principal salt_princ = NULL;
-
-               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 = 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 (int)ret;
-}
-
 #ifdef HAVE_ADS
 
 /**********************************************************************
@@ -519,8 +277,13 @@ int ads_keytab_flush(ADS_STRUCT *ads)
        }
 
        /* Seek and delete old keytab entries */
-       ret = seek_and_delete_old_entries(context, keytab, kvno,
-                                         NULL, NULL, true, false);
+       ret = smb_krb5_kt_seek_and_delete_old_entries(context,
+                                                     keytab,
+                                                     kvno,
+                                                     NULL,
+                                                     NULL,
+                                                     true,
+                                                     false);
        if (ret) {
                goto out;
        }