diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+0.6.11
+======
+
+  * Added `ldapExternalSaslBind`.
+
diff --git a/LDAP.cabal b/LDAP.cabal
--- a/LDAP.cabal
+++ b/LDAP.cabal
@@ -1,27 +1,31 @@
+cabal-version: >=1.8
+
 Name: LDAP
-Version: 0.6.10
+Version: 0.6.11
 License: BSD3
 Maintainer: Edward Z. Yang <ezyang@mit.edu>
 Author: John Goerzen, Edward Z. Yang
 Stability: Beta
-Copyright: Copyright (c) 2005-2014 John Goerzen, Edward Z. Yang
+Copyright: Copyright (c) 2005-2017 John Goerzen, Edward Z. Yang
 homepage: https://github.com/ezyang/ldap-haskell
 Category: Network
 Synopsis: Haskell binding for C LDAP API
 Description: This package provides LDAP interface code for Haskell programs,
  binding to the C LDAP API.
 license-file: COPYRIGHT
-extra-source-files: COPYING
+extra-source-files:
+ COPYING
+ ChangeLog.md
+ sasl_external.h
 
 Build-Type: Simple
-Cabal-Version: >=1.2.3
 
 Flag buildtests
   description: Build the executable to run unit tests
   default: False
 
 Library
-  -- C-Sources: glue/glue.c
+  C-Sources: sasl_external.c
   Exposed-Modules: LDAP,
    LDAP.Types,
    LDAP.Init,
@@ -39,8 +43,8 @@
 
   Extra-Libraries: ldap, lber
 
+
   GHC-Options: -O2
-  -- CC-Options: -Iglue
   if os(openbsd)
     CC-Options: -DLDAP_X_PROXY_AUTHZ_FAILURE=LDAP_PROXY_AUTHZ_FAILURE
   else
@@ -48,12 +52,27 @@
   Extensions: ForeignFunctionInterface, TypeSynonymInstances,
               EmptyDataDecls, ScopedTypeVariables, CPP
 
+Test-Suite test-ldap
+  type: exitcode-stdio-1.0
+  main-is: runtests.hs
+  Extra-Libraries: ldap, lber
+  build-depends: base >= 4 && < 5,
+                 LDAP,
+                 HUnit
+  if os(openbsd)
+    CC-Options: -DLDAP_X_PROXY_AUTHZ_FAILURE=LDAP_PROXY_AUTHZ_FAILURE
+  else
+    CC-Options: -DLDAP_DEPRECATED=1
+  GHC-Options: -O2
+  Extensions: ForeignFunctionInterface, TypeSynonymInstances,
+              EmptyDataDecls, ScopedTypeVariables, CPP
+  hs-source-dirs: testsrc, .
+
 Executable runtests
   if flag(buildtests)
     Buildable: True
   else
     Buildable: False
-  Extra-Libraries: ldap, lber
   Main-Is: runtests.hs
   if os(openbsd)
     CC-Options: -DLDAP_X_PROXY_AUTHZ_FAILURE=LDAP_PROXY_AUTHZ_FAILURE
diff --git a/LDAP/Init.hsc b/LDAP/Init.hsc
--- a/LDAP/Init.hsc
+++ b/LDAP/Init.hsc
@@ -23,7 +23,8 @@
 module LDAP.Init(ldapOpen,
                  ldapInit,
                  ldapInitialize,
-                 ldapSimpleBind)
+                 ldapSimpleBind,
+                 ldapExternalSaslBind)
 where
 
 import Foreign.Ptr
@@ -106,18 +107,32 @@
            return ()
                          )))
 
+{- | Bind with the SASL EXTERNAL mechanism. -}
+ldapExternalSaslBind :: LDAP   -- ^ LDAP Object
+                     -> String -- ^ Authorization identity (UTF-8 encoded; pass "" to derive it from the authentication identity)
+                     -> IO ()
+ldapExternalSaslBind ld authz =
+    withLDAPPtr ld (\ptr ->
+     withCStringLen authz (\(authzPtr,authzLen) ->
+        do checkLE "ldapExternalSaslBind" ld (external_sasl_bind ptr authzPtr authzLen)
+           return ()
+      ))
+
 foreign import ccall unsafe "ldap.h ldap_init"
   cldap_init :: CString -> CInt -> IO LDAPPtr
 
 
-foreign import ccall unsafe "ldap.h ldap_open"
+foreign import ccall safe "ldap.h ldap_open"
   cldap_open :: CString -> CInt -> IO LDAPPtr
 
 foreign import ccall unsafe "ldap.h ldap_initialize"
   ldap_initialize :: Ptr LDAPPtr -> CString -> IO LDAPInt
 
-foreign import ccall unsafe "ldap.h ldap_simple_bind_s"
+foreign import ccall safe "ldap.h ldap_simple_bind_s"
   ldap_simple_bind_s :: LDAPPtr -> CString -> CString -> IO LDAPInt
+
+foreign import ccall safe "sasl_external.h external_sasl_bind"
+  external_sasl_bind :: LDAPPtr -> CString -> Int -> IO LDAPInt
 
 foreign import ccall unsafe "ldap.h ldap_set_option"
   ldap_set_option :: LDAPPtr -> LDAPInt -> Ptr () -> IO LDAPInt
diff --git a/LDAP/Modify.hsc b/LDAP/Modify.hsc
--- a/LDAP/Modify.hsc
+++ b/LDAP/Modify.hsc
@@ -122,11 +122,11 @@
 withCLDAPModArr0 :: [LDAPMod] -> (Ptr (Ptr CLDAPMod) -> IO a) -> IO a
 withCLDAPModArr0 = withAnyArr0 newCLDAPMod freeCLDAPMod
 
-foreign import ccall unsafe "ldap.h ldap_modify_s"
+foreign import ccall safe "ldap.h ldap_modify_s"
   ldap_modify_s :: LDAPPtr -> CString -> Ptr (Ptr CLDAPMod) -> IO LDAPInt
 
-foreign import ccall unsafe "ldap.h ldap_delete_s"
+foreign import ccall safe "ldap.h ldap_delete_s"
   ldap_delete_s :: LDAPPtr -> CString -> IO LDAPInt
 
-foreign import ccall unsafe "ldap.h ldap_add_s"
+foreign import ccall safe "ldap.h ldap_add_s"
   ldap_add_s :: LDAPPtr -> CString -> Ptr (Ptr CLDAPMod) -> IO LDAPInt
diff --git a/LDAP/Result.hsc b/LDAP/Result.hsc
--- a/LDAP/Result.hsc
+++ b/LDAP/Result.hsc
@@ -54,7 +54,7 @@
           then fail (caller ++ ": got null LDAPMessage pointer")
           else newForeignPtr ldap_msgfree_call ptr
 
-foreign import ccall unsafe "ldap.h ldap_result"
+foreign import ccall safe "ldap.h ldap_result"
   ldap_result :: LDAPPtr -> LDAPInt -> LDAPInt -> Ptr () -> Ptr (Ptr CLDAPMessage) -> IO LDAPInt
 
 foreign import ccall unsafe "ldap.h &ldap_msgfree"
diff --git a/LDAP/Search.hsc b/LDAP/Search.hsc
--- a/LDAP/Search.hsc
+++ b/LDAP/Search.hsc
@@ -153,7 +153,7 @@
 foreign import ccall unsafe "ldap.h ldap_value_free_len"
   ldap_value_free_len :: Ptr (Ptr Berval) -> IO ()
 
-foreign import ccall unsafe "ldap.h ldap_search"
+foreign import ccall safe "ldap.h ldap_search"
   ldap_search :: LDAPPtr -> CString -> LDAPInt -> CString -> Ptr CString ->
                  LDAPInt -> IO LDAPInt
 
diff --git a/sasl_external.c b/sasl_external.c
new file mode 100644
--- /dev/null
+++ b/sasl_external.c
@@ -0,0 +1,39 @@
+#include <ldap.h>
+#include <sasl/sasl.h>
+
+#include "sasl_external.h"
+
+struct external_defaults {
+  const char *authzPtr;
+  int authzLen;
+};
+
+static int external_interact (LDAP *ld, unsigned flags, void *defaults, void *sasl_interact)
+{
+  (void)ld;
+  (void)flags;
+  struct external_defaults *defs = defaults;
+  sasl_interact_t *interact;
+
+  for (interact = sasl_interact; interact->id != SASL_CB_LIST_END; interact++) {
+    switch (interact->id) {
+    case SASL_CB_USER:
+      if (defs->authzLen) {
+        interact->result = defs->authzPtr;
+        interact->len = defs->authzLen;
+      }
+      break;
+    /* RFC 4422 (SASL) doesn't allow any other callbacks for EXTERNAL */
+    }
+  }
+  return LDAP_SUCCESS;
+}
+
+int external_sasl_bind (LDAP *ld, const char *authz, int len)
+{
+  struct external_defaults defaults = { authzPtr: authz, authzLen: len };
+
+  return ldap_sasl_interactive_bind_s (ld, NULL, "EXTERNAL", NULL, NULL,
+                                       LDAP_SASL_QUIET,
+                                       external_interact, &defaults);
+}
diff --git a/sasl_external.h b/sasl_external.h
new file mode 100644
--- /dev/null
+++ b/sasl_external.h
@@ -0,0 +1,3 @@
+#include <ldap.h>
+
+int external_sasl_bind (LDAP *ld, const char *authz, int len);
