]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add KDC pre-send and post-receive KDC hooks
authorAndreas Schneider <asn@samba.org>
Thu, 3 Mar 2016 17:53:31 +0000 (18:53 +0100)
committerGreg Hudson <ghudson@mit.edu>
Wed, 23 Mar 2016 16:02:14 +0000 (12:02 -0400)
Add two new APIs, krb5_set_kdc_send_hook() and
krb5_set_kdc_recv_hook(), which can be used to inspect and override
messages sent to KDCs.

[ghudson@mit.edu: style and documentation changes]

ticket: 8386 (new)

doc/appdev/refs/api/index.rst
doc/appdev/refs/types/index.rst
src/include/k5-int.h
src/include/krb5/krb5.hin
src/lib/krb5/libkrb5.exports
src/lib/krb5/os/sendto_kdc.c
src/lib/krb5_32.def

index 8df351d7f311f74b00eaf63ead2a4e8d8b63692c..e97cbca633d1097f730aedccfe69790172705c5a 100644 (file)
@@ -268,6 +268,8 @@ Rarely used public interfaces
    krb5_server_decrypt_ticket_keytab.rst
    krb5_set_default_tgs_enctypes.rst
    krb5_set_error_message.rst
+   krb5_set_kdc_recv_hook.rst
+   krb5_set_kdc_send_hook.rst
    krb5_set_real_time.rst
    krb5_string_to_cksumtype.rst
    krb5_string_to_deltat.rst
index 51c4093574bfce967010bbb3ac042074fed4151f..dc414cfdebe16dae375e268cb40f0c39b9ccd1ac 100644 (file)
@@ -57,6 +57,8 @@ Public
    krb5_pa_svr_referral_data.rst
    krb5_pa_data.rst
    krb5_pointer.rst
+   krb5_post_recv_fn.rst
+   krb5_pre_send_fn.rst
    krb5_preauthtype.rst
    krb5_principal.rst
    krb5_principal_data.rst
index 6b36e9d255525422d63ffc713ef4b650ea428394..d0216d61bb3b2fd754ac9d04aeaf5cc4e2952066 100644 (file)
@@ -1242,6 +1242,12 @@ struct _krb5_context {
     krb5_trace_callback trace_callback;
     void *trace_callback_data;
 
+    krb5_pre_send_fn kdc_send_hook;
+    void *kdc_send_hook_data;
+
+    krb5_post_recv_fn kdc_recv_hook;
+    void *kdc_recv_hook_data;
+
     struct plugin_interface plugins[PLUGIN_NUM_INTERFACES];
     char *plugin_base_dir;
 };
index 0a0d272ca1bd5619c8a626ffcc46e3e9e32079f2..9e91a60d2c0d460a704c0181f96a11774851adb0 100644 (file)
@@ -8292,6 +8292,110 @@ krb5_set_trace_callback(krb5_context context, krb5_trace_callback fn,
 krb5_error_code KRB5_CALLCONV
 krb5_set_trace_filename(krb5_context context, const char *filename);
 
+
+/**
+ * Hook function for inspecting or modifying messages sent to KDCs.
+ *
+ * If the hook function returns an error code, the KDC communication will be
+ * aborted and the error code will be returned to the library operation which
+ * initiated the communication.
+ *
+ * If the hook function sets @a reply_out, @a message will not be sent to the
+ * KDC, and the given reply will used instead.
+ *
+ * If the hook function sets @a new_message_out, the given message will be sent
+ * to the KDC in place of @a message.
+ *
+ * If the hook function returns successfully without setting either output,
+ * @a message will be sent to the KDC normally.
+ *
+ * The hook function should use krb5_copy_data() to construct the value for
+ * @a new_message_out or @a reply_out, to ensure that it can be freed correctly
+ * by the library.
+ *
+ * @param [in]  context         Library context
+ * @param [in]  data            Callback data
+ * @param [in]  realm           The realm the message will be sent to
+ * @param [in]  message         The original message to be sent to the KDC
+ * @param [out] new_message_out Optional replacement message to be sent
+ * @param [out] reply_out       Optional synthetic reply
+ *
+ * @retval 0 Success
+ * @return A Kerberos error code
+ */
+typedef krb5_error_code
+(KRB5_CALLCONV *krb5_pre_send_fn)(krb5_context context, void *data,
+                                  const krb5_data *realm,
+                                  const krb5_data *message,
+                                  krb5_data **new_message_out,
+                                  krb5_data **new_reply_out);
+
+/**
+ * Hook function for inspecting or overriding KDC replies.
+ *
+ * If @a code is zero, @a reply contains the reply received from the KDC.  The
+ * hook function may return an error code to simulate an error, may synthesize
+ * a different reply by setting @a new_reply_out, or may simply return
+ * successfully to do nothing.
+ *
+ * If @a code is non-zero, KDC communication failed and @a reply should be
+ * ignored.  The hook function may return @a code or a different error code, or
+ * may synthesize a reply by setting @a new_reply_out and return successfully.
+ *
+ * The hook function should use krb5_copy_data() to construct the value for
+ * @a new_reply_out, to ensure that it can be freed correctly by the library.
+ *
+ * @param [in]  context         Library context
+ * @param [in]  data            Callback data
+ * @param [in]  code            Status of KDC communication
+ * @param [in]  realm           The realm the reply was received from
+ * @param [in]  message         The message sent to the realm's KDC
+ * @param [in]  reply           The reply received from the KDC
+ * @param [out] new_reply_out   Optional replacement reply
+ *
+ * @retval 0 Success
+ * @return A Kerberos error code
+ */
+typedef krb5_error_code
+(KRB5_CALLCONV *krb5_post_recv_fn)(krb5_context context, void *data,
+                                   krb5_error_code code,
+                                   const krb5_data *realm,
+                                   const krb5_data *message,
+                                   const krb5_data *reply,
+                                   krb5_data **new_reply_out);
+
+/**
+ * Set a KDC pre-send hook function.
+ *
+ * @a send_hook will be called before messages are sent to KDCs by library
+ * functions such as krb5_get_credentials().  The hook function may inspect,
+ * override, or synthesize its own reply to the message.
+ *
+ * @param [in] context          Library context
+ * @param [in] send_hook        Hook function (or NULL to disable the hook)
+ * @param [in] data             Callback data to be passed to @a send_hook
+ */
+void KRB5_CALLCONV
+krb5_set_kdc_send_hook(krb5_context context, krb5_pre_send_fn send_hook,
+                       void *data);
+
+/**
+ * Set a KDC post-receive hook function.
+ *
+ * @a recv_hook will be called after a reply is received from a KDC during a
+ * call to a library function such as krb5_get_credentials().  The hook
+ * function may inspect or override the reply.  This hook will not be executed
+ * if the pre-send hook returns a synthetic reply.
+ *
+ * @param [in] context          The library context.
+ * @param [in] recv_hook        Hook function (or NULL to disable the hook)
+ * @param [in] data             Callback data to be passed to @a recv_hook
+ */
+void KRB5_CALLCONV
+krb5_set_kdc_recv_hook(krb5_context context, krb5_post_recv_fn recv_hook,
+                       void *data);
+
+
 #if TARGET_OS_MAC
 #    pragma pack(pop)
 #endif
index c623409f686c6639aed2767b1d9648db5ccc720e..ea6982d0269ce6b1f9027ac4627e82e703c49446 100644 (file)
@@ -581,6 +581,8 @@ krb5_set_password
 krb5_set_password_using_ccache
 krb5_set_principal_realm
 krb5_set_real_time
+krb5_set_kdc_send_hook
+krb5_set_kdc_recv_hook
 krb5_set_time_offsets
 krb5_set_trace_callback
 krb5_set_trace_filename
index 3b3b438ce6d89199dc0facf99b703449dc54ab2b..a2bc5915cff316bb37e13c84145b6f7263a91f24 100644 (file)
@@ -399,6 +399,22 @@ check_for_svc_unavailable (krb5_context context,
     return 1;
 }
 
+void
+krb5_set_kdc_send_hook(krb5_context context, krb5_pre_send_fn send_hook,
+                       void *data)
+{
+    context->kdc_send_hook = send_hook;
+    context->kdc_send_hook_data = data;
+}
+
+void
+krb5_set_kdc_recv_hook(krb5_context context, krb5_post_recv_fn recv_hook,
+                       void *data)
+{
+    context->kdc_recv_hook = recv_hook;
+    context->kdc_recv_hook_data = data;
+}
+
 /*
  * send the formatted request 'message' to a KDC for realm 'realm' and
  * return the response (if any) in 'reply'.
@@ -412,13 +428,16 @@ check_for_svc_unavailable (krb5_context context,
 
 krb5_error_code
 krb5_sendto_kdc(krb5_context context, const krb5_data *message,
-                const krb5_data *realm, krb5_data *reply, int *use_master,
+                const krb5_data *realm, krb5_data *reply_out, int *use_master,
                 int no_udp)
 {
     krb5_error_code retval, err;
     struct serverlist servers;
     int server_used;
     k5_transport_strategy strategy;
+    krb5_data reply = empty_data(), *hook_message = NULL, *hook_reply = NULL;
+
+    *reply_out = empty_data();
 
     /*
      * find KDC location(s) for realm
@@ -463,9 +482,26 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
     if (retval)
         return retval;
 
+    if (context->kdc_send_hook != NULL) {
+        retval = context->kdc_send_hook(context, context->kdc_send_hook_data,
+                                        realm, message, &hook_message,
+                                        &hook_reply);
+        if (retval)
+            goto cleanup;
+
+        if (hook_reply != NULL) {
+            *reply_out = *hook_reply;
+            free(hook_reply);
+            goto cleanup;
+        }
+
+        if (hook_message != NULL)
+            message = hook_message;
+    }
+
     err = 0;
     retval = k5_sendto(context, message, realm, &servers, strategy, NULL,
-                       reply, NULL, NULL, &server_used,
+                       &reply, NULL, NULL, &server_used,
                        check_for_svc_unavailable, &err);
     if (retval == KRB5_KDC_UNREACH) {
         if (err == KDC_ERR_SVC_UNAVAILABLE) {
@@ -476,9 +512,23 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
                       realm->length, realm->data);
         }
     }
+
+    if (context->kdc_recv_hook != NULL) {
+        retval = context->kdc_recv_hook(context, context->kdc_recv_hook_data,
+                                        retval, realm, message, &reply,
+                                        &hook_reply);
+    }
     if (retval)
         goto cleanup;
 
+    if (hook_reply != NULL) {
+        *reply_out = *hook_reply;
+        free(hook_reply);
+    } else {
+        *reply_out = reply;
+        reply = empty_data();
+    }
+
     /* Set use_master to 1 if we ended up talking to a master when we didn't
      * explicitly request to. */
     if (*use_master == 0) {
@@ -488,6 +538,8 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
     }
 
 cleanup:
+    krb5_free_data(context, hook_message);
+    krb5_free_data_contents(context, &reply);
     k5_free_serverlist(&servers);
     return retval;
 }
index 3734e9bba0186d30e1a77e018827f7b6a8e6cb8a..8d58ea1d968fa5f7be30706ac303859e502fa2d0 100644 (file)
@@ -463,3 +463,7 @@ EXPORTS
        krb5_vwrap_error_message                        @430
        krb5_c_prfplus                                  @431
        krb5_c_derive_prfplus                           @432
+
+; new in 1.15
+       krb5_set_kdc_send_hook                          @433
+       krb5_set_kdc_recv_hook                          @434