src/gnutls.c: Remove bogus references to :verify-error.
[bpt/emacs.git] / src / gnutls.c
index fd97091..55c7ff0 100644 (file)
@@ -34,6 +34,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 static int
 emacs_gnutls_handle_error (gnutls_session_t, int err);
 
+static Lisp_Object Qgnutls_dll;
 static Lisp_Object Qgnutls_log_level;
 static Lisp_Object Qgnutls_code;
 static Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
@@ -50,12 +51,190 @@ static Lisp_Object Qgnutls_bootprop_callbacks;
 static Lisp_Object Qgnutls_bootprop_loglevel;
 static Lisp_Object Qgnutls_bootprop_hostname;
 static Lisp_Object Qgnutls_bootprop_verify_flags;
-static Lisp_Object Qgnutls_bootprop_verify_error;
 static Lisp_Object Qgnutls_bootprop_verify_hostname_error;
 
 /* Callback keys for `gnutls-boot'.  Unused currently.  */
 static Lisp_Object Qgnutls_bootprop_callbacks_verify;
 
+static void gnutls_log_function (int, const char *);
+static void gnutls_log_function2 (int, const char*, const char*);
+
+\f
+#ifdef WINDOWSNT
+
+/* Macro for defining functions that will be loaded from the GnuTLS DLL.  */
+#define DEF_GNUTLS_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
+
+/* Macro for loading GnuTLS functions from the library.  */
+#define LOAD_GNUTLS_FN(lib,func) {                                     \
+    fn_##func = (void *) GetProcAddress (lib, #func);                  \
+    if (!fn_##func) return 0;                                          \
+  }
+
+DEF_GNUTLS_FN (gnutls_alert_description_t, gnutls_alert_get,
+               (gnutls_session_t));
+DEF_GNUTLS_FN (const char *, gnutls_alert_get_name,
+               (gnutls_alert_description_t));
+DEF_GNUTLS_FN (int, gnutls_alert_send_appropriate, (gnutls_session_t, int));
+DEF_GNUTLS_FN (int, gnutls_anon_allocate_client_credentials,
+               (gnutls_anon_client_credentials_t *));
+DEF_GNUTLS_FN (void, gnutls_anon_free_client_credentials,
+               (gnutls_anon_client_credentials_t));
+DEF_GNUTLS_FN (int, gnutls_bye, (gnutls_session_t, gnutls_close_request_t));
+DEF_GNUTLS_FN (int, gnutls_certificate_allocate_credentials,
+               (gnutls_certificate_credentials_t *));
+DEF_GNUTLS_FN (void, gnutls_certificate_free_credentials,
+               (gnutls_certificate_credentials_t));
+DEF_GNUTLS_FN (const gnutls_datum_t *, gnutls_certificate_get_peers,
+               (gnutls_session_t, unsigned int *));
+DEF_GNUTLS_FN (void, gnutls_certificate_set_verify_flags,
+               (gnutls_certificate_credentials_t, unsigned int));
+DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_crl_file,
+               (gnutls_certificate_credentials_t, const char *,
+                gnutls_x509_crt_fmt_t));
+DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_key_file,
+               (gnutls_certificate_credentials_t, const char *, const char *,
+                gnutls_x509_crt_fmt_t));
+DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_trust_file,
+               (gnutls_certificate_credentials_t, const char *,
+                gnutls_x509_crt_fmt_t));
+DEF_GNUTLS_FN (gnutls_certificate_type_t, gnutls_certificate_type_get,
+               (gnutls_session_t));
+DEF_GNUTLS_FN (int, gnutls_certificate_verify_peers2,
+               (gnutls_session_t, unsigned int *));
+DEF_GNUTLS_FN (int, gnutls_credentials_set,
+               (gnutls_session_t, gnutls_credentials_type_t, void *));
+DEF_GNUTLS_FN (void, gnutls_deinit, (gnutls_session_t));
+DEF_GNUTLS_FN (int, gnutls_error_is_fatal, (int));
+DEF_GNUTLS_FN (int, gnutls_global_init, (void));
+DEF_GNUTLS_FN (void, gnutls_global_set_log_function, (gnutls_log_func));
+DEF_GNUTLS_FN (void, gnutls_global_set_log_level, (int));
+DEF_GNUTLS_FN (void, gnutls_global_set_mem_functions,
+              (gnutls_alloc_function, gnutls_alloc_function,
+               gnutls_is_secure_function, gnutls_realloc_function,
+               gnutls_free_function));
+DEF_GNUTLS_FN (int, gnutls_handshake, (gnutls_session_t));
+DEF_GNUTLS_FN (int, gnutls_init, (gnutls_session_t *, gnutls_connection_end_t));
+DEF_GNUTLS_FN (int, gnutls_priority_set_direct,
+               (gnutls_session_t, const char *, const char **));
+DEF_GNUTLS_FN (size_t, gnutls_record_check_pending, (gnutls_session_t));
+DEF_GNUTLS_FN (ssize_t, gnutls_record_recv, (gnutls_session_t, void *, size_t));
+DEF_GNUTLS_FN (ssize_t, gnutls_record_send,
+               (gnutls_session_t, const void *, size_t));
+DEF_GNUTLS_FN (const char *, gnutls_strerror, (int));
+DEF_GNUTLS_FN (void, gnutls_transport_set_errno, (gnutls_session_t, int));
+DEF_GNUTLS_FN (void, gnutls_transport_set_lowat, (gnutls_session_t, int));
+DEF_GNUTLS_FN (void, gnutls_transport_set_ptr2,
+               (gnutls_session_t, gnutls_transport_ptr_t,
+                gnutls_transport_ptr_t));
+DEF_GNUTLS_FN (void, gnutls_transport_set_pull_function,
+               (gnutls_session_t, gnutls_pull_func));
+DEF_GNUTLS_FN (void, gnutls_transport_set_push_function,
+               (gnutls_session_t, gnutls_push_func));
+DEF_GNUTLS_FN (int, gnutls_x509_crt_check_hostname,
+               (gnutls_x509_crt_t, const char *));
+DEF_GNUTLS_FN (void, gnutls_x509_crt_deinit, (gnutls_x509_crt_t));
+DEF_GNUTLS_FN (int, gnutls_x509_crt_import,
+               (gnutls_x509_crt_t, const gnutls_datum_t *,
+                gnutls_x509_crt_fmt_t));
+DEF_GNUTLS_FN (int, gnutls_x509_crt_init, (gnutls_x509_crt_t *));
+
+static int
+init_gnutls_functions (Lisp_Object libraries)
+{
+  HMODULE library;
+
+  if (!(library = w32_delayed_load (libraries, Qgnutls_dll)))
+    {
+      GNUTLS_LOG (1, 1, "GnuTLS library not found");
+      return 0;
+    }
+
+  LOAD_GNUTLS_FN (library, gnutls_alert_get);
+  LOAD_GNUTLS_FN (library, gnutls_alert_get_name);
+  LOAD_GNUTLS_FN (library, gnutls_alert_send_appropriate);
+  LOAD_GNUTLS_FN (library, gnutls_anon_allocate_client_credentials);
+  LOAD_GNUTLS_FN (library, gnutls_anon_free_client_credentials);
+  LOAD_GNUTLS_FN (library, gnutls_bye);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_allocate_credentials);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_free_credentials);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_get_peers);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_set_verify_flags);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_crl_file);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_key_file);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_trust_file);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_type_get);
+  LOAD_GNUTLS_FN (library, gnutls_certificate_verify_peers2);
+  LOAD_GNUTLS_FN (library, gnutls_credentials_set);
+  LOAD_GNUTLS_FN (library, gnutls_deinit);
+  LOAD_GNUTLS_FN (library, gnutls_error_is_fatal);
+  LOAD_GNUTLS_FN (library, gnutls_global_init);
+  LOAD_GNUTLS_FN (library, gnutls_global_set_log_function);
+  LOAD_GNUTLS_FN (library, gnutls_global_set_log_level);
+  LOAD_GNUTLS_FN (library, gnutls_global_set_mem_functions);
+  LOAD_GNUTLS_FN (library, gnutls_handshake);
+  LOAD_GNUTLS_FN (library, gnutls_init);
+  LOAD_GNUTLS_FN (library, gnutls_priority_set_direct);
+  LOAD_GNUTLS_FN (library, gnutls_record_check_pending);
+  LOAD_GNUTLS_FN (library, gnutls_record_recv);
+  LOAD_GNUTLS_FN (library, gnutls_record_send);
+  LOAD_GNUTLS_FN (library, gnutls_strerror);
+  LOAD_GNUTLS_FN (library, gnutls_transport_set_errno);
+  LOAD_GNUTLS_FN (library, gnutls_transport_set_lowat);
+  LOAD_GNUTLS_FN (library, gnutls_transport_set_ptr2);
+  LOAD_GNUTLS_FN (library, gnutls_transport_set_pull_function);
+  LOAD_GNUTLS_FN (library, gnutls_transport_set_push_function);
+  LOAD_GNUTLS_FN (library, gnutls_x509_crt_check_hostname);
+  LOAD_GNUTLS_FN (library, gnutls_x509_crt_deinit);
+  LOAD_GNUTLS_FN (library, gnutls_x509_crt_import);
+  LOAD_GNUTLS_FN (library, gnutls_x509_crt_init);
+
+  GNUTLS_LOG2 (1, 1, "GnuTLS library loaded:",
+               SDATA (Fget (Qgnutls_dll, QCloaded_from)));
+  return 1;
+}
+
+#else /* !WINDOWSNT */
+
+#define fn_gnutls_alert_get                    gnutls_alert_get
+#define fn_gnutls_alert_get_name               gnutls_alert_get_name
+#define fn_gnutls_alert_send_appropriate       gnutls_alert_send_appropriate
+#define fn_gnutls_anon_allocate_client_credentials gnutls_anon_allocate_client_credentials
+#define fn_gnutls_anon_free_client_credentials gnutls_anon_free_client_credentials
+#define fn_gnutls_bye                          gnutls_bye
+#define fn_gnutls_certificate_allocate_credentials gnutls_certificate_allocate_credentials
+#define fn_gnutls_certificate_free_credentials gnutls_certificate_free_credentials
+#define fn_gnutls_certificate_get_peers                gnutls_certificate_get_peers
+#define fn_gnutls_certificate_set_verify_flags gnutls_certificate_set_verify_flags
+#define fn_gnutls_certificate_set_x509_crl_file        gnutls_certificate_set_x509_crl_file
+#define fn_gnutls_certificate_set_x509_key_file gnutls_certificate_set_x509_key_file
+#define fn_gnutls_certificate_set_x509_trust_file gnutls_certificate_set_x509_trust_file
+#define fn_gnutls_certificate_type_get         gnutls_certificate_type_get
+#define fn_gnutls_certificate_verify_peers2    gnutls_certificate_verify_peers2
+#define fn_gnutls_credentials_set              gnutls_credentials_set
+#define fn_gnutls_deinit                       gnutls_deinit
+#define fn_gnutls_error_is_fatal               gnutls_error_is_fatal
+#define fn_gnutls_global_init                  gnutls_global_init
+#define fn_gnutls_global_set_log_function      gnutls_global_set_log_function
+#define fn_gnutls_global_set_log_level         gnutls_global_set_log_level
+#define fn_gnutls_global_set_mem_functions     gnutls_global_set_mem_functions
+#define fn_gnutls_handshake                    gnutls_handshake
+#define fn_gnutls_init                         gnutls_init
+#define fn_gnutls_priority_set_direct          gnutls_priority_set_direct
+#define fn_gnutls_record_check_pending         gnutls_record_check_pending
+#define fn_gnutls_record_recv                  gnutls_record_recv
+#define fn_gnutls_record_send                  gnutls_record_send
+#define fn_gnutls_strerror                     gnutls_strerror
+#define fn_gnutls_transport_set_errno          gnutls_transport_set_errno
+#define fn_gnutls_transport_set_ptr2           gnutls_transport_set_ptr2
+#define fn_gnutls_x509_crt_check_hostname      gnutls_x509_crt_check_hostname
+#define fn_gnutls_x509_crt_deinit              gnutls_x509_crt_deinit
+#define fn_gnutls_x509_crt_import              gnutls_x509_crt_import
+#define fn_gnutls_x509_crt_init                        gnutls_x509_crt_init
+
+#endif /* !WINDOWSNT */
+
+\f
 static void
 gnutls_log_function (int level, const char* string)
 {
@@ -83,11 +262,11 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
       /* On W32 we cannot transfer socket handles between different runtime
          libraries, so we tell GnuTLS to use our special push/pull
          functions.  */
-      gnutls_transport_set_ptr2 (state,
-                                 (gnutls_transport_ptr_t) proc,
-                                 (gnutls_transport_ptr_t) proc);
-      gnutls_transport_set_push_function (state, &emacs_gnutls_push);
-      gnutls_transport_set_pull_function (state, &emacs_gnutls_pull);
+      fn_gnutls_transport_set_ptr2 (state,
+                                    (gnutls_transport_ptr_t) proc,
+                                    (gnutls_transport_ptr_t) proc);
+      fn_gnutls_transport_set_push_function (state, &emacs_gnutls_push);
+      fn_gnutls_transport_set_pull_function (state, &emacs_gnutls_pull);
 
       /* For non blocking sockets or other custom made pull/push
          functions the gnutls_transport_set_lowat must be called, with
@@ -96,14 +275,14 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
          (Note: this is probably not strictly necessary as the lowat
           value is only used when no custom pull/push functions are
           set.)  */
-      gnutls_transport_set_lowat (state, 0);
+      fn_gnutls_transport_set_lowat (state, 0);
 #else
       /* This is how GnuTLS takes sockets: as file descriptors passed
          in.  For an Emacs process socket, infd and outfd are the
          same but we use this two-argument version for clarity.  */
-      gnutls_transport_set_ptr2 (state,
-                                (gnutls_transport_ptr_t) (long) proc->infd,
-                                (gnutls_transport_ptr_t) (long) proc->outfd);
+      fn_gnutls_transport_set_ptr2 (state,
+                                    (gnutls_transport_ptr_t) (long) proc->infd,
+                                    (gnutls_transport_ptr_t) (long) proc->outfd);
 #endif
 
       proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
@@ -111,10 +290,10 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
 
   do
     {
-      ret = gnutls_handshake (state);
+      ret = fn_gnutls_handshake (state);
       emacs_gnutls_handle_error (state, ret);
     }
-  while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
+  while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0);
 
   proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
 
@@ -125,14 +304,25 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
     }
   else
     {
-        gnutls_alert_send_appropriate (state, ret);
+      fn_gnutls_alert_send_appropriate (state, ret);
     }
   return ret;
 }
 
+int
+emacs_gnutls_record_check_pending (gnutls_session_t state)
+{
+  return fn_gnutls_record_check_pending (state);
+}
+
+void
+emacs_gnutls_transport_set_errno (gnutls_session_t state, int err)
+{
+  fn_gnutls_transport_set_errno (state, err);
+}
+
 EMACS_INT
-emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
-                    EMACS_INT nbyte)
+emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, EMACS_INT nbyte)
 {
   ssize_t rtnval = 0;
   EMACS_INT bytes_written;
@@ -152,7 +342,7 @@ emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
 
   while (nbyte > 0)
     {
-      rtnval = gnutls_write (state, buf, nbyte);
+      rtnval = fn_gnutls_record_send (state, buf, nbyte);
 
       if (rtnval < 0)
         {
@@ -172,8 +362,7 @@ emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
 }
 
 EMACS_INT
-emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
-                   EMACS_INT nbyte)
+emacs_gnutls_read (struct Lisp_Process *proc, char *buf, EMACS_INT nbyte)
 {
   ssize_t rtnval;
   gnutls_session_t state = proc->gnutls_state;
@@ -183,7 +372,7 @@ emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
       emacs_gnutls_handshake (proc);
       return -1;
     }
-  rtnval = gnutls_read (state, buf, nbyte);
+  rtnval = fn_gnutls_record_recv (state, buf, nbyte);
   if (rtnval >= 0)
     return rtnval;
   else if (emacs_gnutls_handle_error (state, rtnval) == 0)
@@ -215,11 +404,11 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err)
 
   /* TODO: use gnutls-error-fatalp and gnutls-error-string.  */
 
-  str = gnutls_strerror (err);
+  str = fn_gnutls_strerror (err);
   if (!str)
     str = "unknown";
 
-  if (gnutls_error_is_fatal (err))
+  if (fn_gnutls_error_is_fatal (err))
     {
       ret = err;
       GNUTLS_LOG2 (0, max_log_level, "fatal error:", str);
@@ -234,9 +423,9 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err)
   if (err == GNUTLS_E_WARNING_ALERT_RECEIVED
       || err == GNUTLS_E_FATAL_ALERT_RECEIVED)
     {
-      int alert = gnutls_alert_get (session);
+      int alert = fn_gnutls_alert_get (session);
       int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1;
-      str = gnutls_alert_get_name (alert);
+      str = fn_gnutls_alert_get_name (alert);
       if (!str)
        str = "unknown";
 
@@ -314,7 +503,7 @@ usage: (gnutls-error-fatalp ERROR)  */)
   if (!NUMBERP (err))
     error ("Not an error symbol or code");
 
-  if (0 == gnutls_error_is_fatal (XINT (err)))
+  if (0 == fn_gnutls_error_is_fatal (XINT (err)))
     return Qnil;
 
   return Qt;
@@ -346,7 +535,7 @@ usage: (gnutls-error-string ERROR)  */)
   if (!NUMBERP (err))
     return build_string ("Not an error symbol or code");
 
-  return build_string (gnutls_strerror (XINT (err)));
+  return build_string (fn_gnutls_strerror (XINT (err)));
 }
 
 DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
@@ -361,13 +550,34 @@ See also `gnutls-init'.  */)
 
   if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
     {
-      gnutls_deinit (state);
+      fn_gnutls_deinit (state);
       GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
     }
 
   return Qt;
 }
 
+DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0,
+       doc: /* Return t if GnuTLS is available in this instance of Emacs.  */)
+     (void)
+{
+#ifdef WINDOWSNT
+  Lisp_Object found = Fassq (Qgnutls_dll, Vlibrary_cache);
+  if (CONSP (found))
+    return XCDR (found);
+  else
+    {
+      Lisp_Object status;
+      status = init_gnutls_functions (Vdynamic_library_alist) ? Qt : Qnil;
+      Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache);
+      return status;
+    }
+#else
+  return Qt;
+#endif
+}
+
+
 /* Initializes global GnuTLS state to defaults.
 Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
 Returns zero on success.  */
@@ -377,8 +587,11 @@ emacs_gnutls_global_init (void)
   int ret = GNUTLS_E_SUCCESS;
 
   if (!gnutls_global_initialized)
-    ret = gnutls_global_init ();
-
+    {
+      fn_gnutls_global_set_mem_functions (xmalloc, xmalloc, NULL,
+                                         xrealloc, xfree);
+      ret = fn_gnutls_global_init ();
+    }
   gnutls_global_initialized = 1;
 
   return gnutls_make_error (ret);
@@ -425,9 +638,6 @@ certificates for `gnutls-x509pki'.
 :verify-flags is a bitset as per GnuTLS'
 gnutls_certificate_set_verify_flags.
 
-:verify-error, if non-nil, makes failure of the certificate validation
-an error.  Otherwise it will be just a series of warnings.
-
 :verify-hostname-error, if non-nil, makes a hostname mismatch an
 error.  Otherwise it will be just a warning.
 
@@ -488,6 +698,12 @@ one trustfile (usually a CA bundle).  */)
   CHECK_SYMBOL (type);
   CHECK_LIST (proplist);
 
+  if (NILP (Fgnutls_available_p ()))
+    {
+      error ("GnuTLS not available");
+      return gnutls_make_error (GNUTLS_EMACS_ERROR_NOT_LOADED);
+    }
+
   hostname              = Fplist_get (proplist, Qgnutls_bootprop_hostname);
   priority_string       = Fplist_get (proplist, Qgnutls_bootprop_priority);
   trustfiles            = Fplist_get (proplist, Qgnutls_bootprop_trustfiles);
@@ -509,8 +725,8 @@ one trustfile (usually a CA bundle).  */)
 
   if (NUMBERP (loglevel))
     {
-      gnutls_global_set_log_function (gnutls_log_function);
-      gnutls_global_set_log_level (XINT (loglevel));
+      fn_gnutls_global_set_log_function (gnutls_log_function);
+      fn_gnutls_global_set_log_level (XINT (loglevel));
       max_log_level = XINT (loglevel);
       XPROCESS (proc)->gnutls_log_level = max_log_level;
     }
@@ -529,13 +745,13 @@ one trustfile (usually a CA bundle).  */)
        {
           GNUTLS_LOG (2, max_log_level, "deallocating x509 credentials");
           x509_cred = XPROCESS (proc)->gnutls_x509_cred;
-          gnutls_certificate_free_credentials (x509_cred);
+          fn_gnutls_certificate_free_credentials (x509_cred);
        }
       else if (EQ (type, Qgnutls_anon))
        {
           GNUTLS_LOG (2, max_log_level, "deallocating anon credentials");
           anon_cred = XPROCESS (proc)->gnutls_anon_cred;
-          gnutls_anon_free_client_credentials (anon_cred);
+          fn_gnutls_anon_free_client_credentials (anon_cred);
        }
       else
        {
@@ -558,8 +774,7 @@ one trustfile (usually a CA bundle).  */)
     {
       GNUTLS_LOG (2, max_log_level, "allocating x509 credentials");
       x509_cred = XPROCESS (proc)->gnutls_x509_cred;
-      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
-        memory_full ();
+      fn_gnutls_certificate_allocate_credentials (&x509_cred);
 
       if (NUMBERP (verify_flags))
         {
@@ -576,14 +791,13 @@ one trustfile (usually a CA bundle).  */)
           /* The default is already GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT.  */
           GNUTLS_LOG (2, max_log_level, "ignoring invalid verify-flags");
         }
-      gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags);
+      fn_gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags);
     }
   else if (EQ (type, Qgnutls_anon))
     {
       GNUTLS_LOG (2, max_log_level, "allocating anon credentials");
       anon_cred = XPROCESS (proc)->gnutls_anon_cred;
-      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
-        memory_full ();
+      fn_gnutls_anon_allocate_client_credentials (&anon_cred);
     }
   else
     {
@@ -605,7 +819,7 @@ one trustfile (usually a CA bundle).  */)
             {
               GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
                            SSDATA (trustfile));
-              ret = gnutls_certificate_set_x509_trust_file
+              ret = fn_gnutls_certificate_set_x509_trust_file
                 (x509_cred,
                  SSDATA (trustfile),
                  file_format);
@@ -627,7 +841,7 @@ one trustfile (usually a CA bundle).  */)
             {
               GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
                            SSDATA (crlfile));
-              ret = gnutls_certificate_set_x509_crl_file
+              ret = fn_gnutls_certificate_set_x509_crl_file
                 (x509_cred,
                  SSDATA (crlfile),
                  file_format);
@@ -652,7 +866,7 @@ one trustfile (usually a CA bundle).  */)
                            SSDATA (keyfile));
               GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
                            SSDATA (certfile));
-              ret = gnutls_certificate_set_x509_key_file
+              ret = fn_gnutls_certificate_set_x509_key_file
                 (x509_cred,
                  SSDATA (certfile),
                  SSDATA (keyfile),
@@ -685,7 +899,7 @@ one trustfile (usually a CA bundle).  */)
 
   GNUTLS_LOG (1, max_log_level, "gnutls_init");
 
-  ret = gnutls_init (&state, GNUTLS_CLIENT);
+  ret = fn_gnutls_init (&state, GNUTLS_CLIENT);
 
   if (ret < GNUTLS_E_SUCCESS)
     return gnutls_make_error (ret);
@@ -708,9 +922,9 @@ one trustfile (usually a CA bundle).  */)
 
   GNUTLS_LOG (1, max_log_level, "setting the priority string");
 
-  ret = gnutls_priority_set_direct (state,
-                                   priority_string_ptr,
-                                   NULL);
+  ret = fn_gnutls_priority_set_direct (state,
+                                       priority_string_ptr,
+                                       NULL);
 
   if (ret < GNUTLS_E_SUCCESS)
     return gnutls_make_error (ret);
@@ -719,11 +933,11 @@ one trustfile (usually a CA bundle).  */)
 
   if (EQ (type, Qgnutls_x509pki))
     {
-      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+      ret = fn_gnutls_credentials_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
     }
   else if (EQ (type, Qgnutls_anon))
     {
-      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+      ret = fn_gnutls_credentials_set (state, GNUTLS_CRD_ANON, anon_cred);
     }
   else
     {
@@ -751,7 +965,7 @@ one trustfile (usually a CA bundle).  */)
      check of the certificate's hostname with
      gnutls_x509_crt_check_hostname() against :hostname.  */
 
-  ret = gnutls_certificate_verify_peers2 (state, &peer_verification);
+  ret = fn_gnutls_certificate_verify_peers2 (state, &peer_verification);
 
   if (ret < GNUTLS_E_SUCCESS)
     return gnutls_make_error (ret);
@@ -802,15 +1016,15 @@ one trustfile (usually a CA bundle).  */)
   /* Up to here the process is the same for X.509 certificates and
      OpenPGP keys.  From now on X.509 certificates are assumed.  This
      can be easily extended to work with openpgp keys as well.  */
-  if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
+  if (fn_gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
     {
-      ret = gnutls_x509_crt_init (&gnutls_verify_cert);
+      ret = fn_gnutls_x509_crt_init (&gnutls_verify_cert);
 
       if (ret < GNUTLS_E_SUCCESS)
         return gnutls_make_error (ret);
 
       gnutls_verify_cert_list =
-        gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
+        fn_gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
 
       if (NULL == gnutls_verify_cert_list)
         {
@@ -818,17 +1032,17 @@ one trustfile (usually a CA bundle).  */)
         }
 
       /* We only check the first certificate in the given chain.  */
-      ret = gnutls_x509_crt_import (gnutls_verify_cert,
-                                    &gnutls_verify_cert_list[0],
-                                    GNUTLS_X509_FMT_DER);
+      ret = fn_gnutls_x509_crt_import (gnutls_verify_cert,
+                                       &gnutls_verify_cert_list[0],
+                                       GNUTLS_X509_FMT_DER);
 
       if (ret < GNUTLS_E_SUCCESS)
         {
-          gnutls_x509_crt_deinit (gnutls_verify_cert);
+          fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
           return gnutls_make_error (ret);
         }
 
-      if (!gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
+      if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
         {
           if (NILP (verify_hostname_error))
             {
@@ -837,13 +1051,13 @@ one trustfile (usually a CA bundle).  */)
             }
           else
             {
-              gnutls_x509_crt_deinit (gnutls_verify_cert);
+              fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
               error ("The x509 certificate does not match \"%s\"",
                      c_hostname);
             }
         }
 
-      gnutls_x509_crt_deinit (gnutls_verify_cert);
+      fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
     }
 
   return gnutls_make_error (ret);
@@ -872,8 +1086,8 @@ This function may also return `gnutls-e-again', or
 
   state = XPROCESS (proc)->gnutls_state;
 
-  ret = gnutls_bye (state,
-                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  ret = fn_gnutls_bye (state,
+                       NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
 
   return gnutls_make_error (ret);
 }
@@ -883,69 +1097,35 @@ syms_of_gnutls (void)
 {
   gnutls_global_initialized = 0;
 
-  Qgnutls_log_level = intern_c_string ("gnutls-log-level");
-  staticpro (&Qgnutls_log_level);
-
-  Qgnutls_code = intern_c_string ("gnutls-code");
-  staticpro (&Qgnutls_code);
-
-  Qgnutls_anon = intern_c_string ("gnutls-anon");
-  staticpro (&Qgnutls_anon);
-
-  Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
-  staticpro (&Qgnutls_x509pki);
-
-  Qgnutls_bootprop_hostname = intern_c_string (":hostname");
-  staticpro (&Qgnutls_bootprop_hostname);
-
-  Qgnutls_bootprop_priority = intern_c_string (":priority");
-  staticpro (&Qgnutls_bootprop_priority);
-
-  Qgnutls_bootprop_trustfiles = intern_c_string (":trustfiles");
-  staticpro (&Qgnutls_bootprop_trustfiles);
-
-  Qgnutls_bootprop_keylist = intern_c_string (":keylist");
-  staticpro (&Qgnutls_bootprop_keylist);
-
-  Qgnutls_bootprop_crlfiles = intern_c_string (":crlfiles");
-  staticpro (&Qgnutls_bootprop_crlfiles);
-
-  Qgnutls_bootprop_callbacks = intern_c_string (":callbacks");
-  staticpro (&Qgnutls_bootprop_callbacks);
-
-  Qgnutls_bootprop_callbacks_verify = intern_c_string ("verify");
-  staticpro (&Qgnutls_bootprop_callbacks_verify);
-
-  Qgnutls_bootprop_loglevel = intern_c_string (":loglevel");
-  staticpro (&Qgnutls_bootprop_loglevel);
-
-  Qgnutls_bootprop_verify_flags = intern_c_string (":verify-flags");
-  staticpro (&Qgnutls_bootprop_verify_flags);
-
-  Qgnutls_bootprop_verify_hostname_error = intern_c_string (":verify-error");
-  staticpro (&Qgnutls_bootprop_verify_error);
-
-  Qgnutls_bootprop_verify_hostname_error = intern_c_string (":verify-hostname-error");
-  staticpro (&Qgnutls_bootprop_verify_hostname_error);
-
-  Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
-  staticpro (&Qgnutls_e_interrupted);
+  DEFSYM (Qgnutls_dll, "gnutls");
+  DEFSYM (Qgnutls_log_level, "gnutls-log-level");
+  DEFSYM (Qgnutls_code, "gnutls-code");
+  DEFSYM (Qgnutls_anon, "gnutls-anon");
+  DEFSYM (Qgnutls_x509pki, "gnutls-x509pki");
+  DEFSYM (Qgnutls_bootprop_hostname, ":hostname");
+  DEFSYM (Qgnutls_bootprop_priority, ":priority");
+  DEFSYM (Qgnutls_bootprop_trustfiles, ":trustfiles");
+  DEFSYM (Qgnutls_bootprop_keylist, ":keylist");
+  DEFSYM (Qgnutls_bootprop_crlfiles, ":crlfiles");
+  DEFSYM (Qgnutls_bootprop_callbacks, ":callbacks");
+  DEFSYM (Qgnutls_bootprop_callbacks_verify, "verify");
+  DEFSYM (Qgnutls_bootprop_loglevel, ":loglevel");
+  DEFSYM (Qgnutls_bootprop_verify_flags, ":verify-flags");
+  DEFSYM (Qgnutls_bootprop_verify_hostname_error, ":verify-hostname-error");
+
+  DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
   Fput (Qgnutls_e_interrupted, Qgnutls_code,
         make_number (GNUTLS_E_INTERRUPTED));
 
-  Qgnutls_e_again = intern_c_string ("gnutls-e-again");
-  staticpro (&Qgnutls_e_again);
+  DEFSYM (Qgnutls_e_again, "gnutls-e-again");
   Fput (Qgnutls_e_again, Qgnutls_code,
         make_number (GNUTLS_E_AGAIN));
 
-  Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
-  staticpro (&Qgnutls_e_invalid_session);
+  DEFSYM (Qgnutls_e_invalid_session, "gnutls-e-invalid-session");
   Fput (Qgnutls_e_invalid_session, Qgnutls_code,
         make_number (GNUTLS_E_INVALID_SESSION));
 
-  Qgnutls_e_not_ready_for_handshake =
-    intern_c_string ("gnutls-e-not-ready-for-handshake");
-  staticpro (&Qgnutls_e_not_ready_for_handshake);
+  DEFSYM (Qgnutls_e_not_ready_for_handshake, "gnutls-e-not-ready-for-handshake");
   Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
         make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
 
@@ -956,6 +1136,7 @@ syms_of_gnutls (void)
   defsubr (&Sgnutls_boot);
   defsubr (&Sgnutls_deinit);
   defsubr (&Sgnutls_bye);
+  defsubr (&Sgnutls_available_p);
 }
 
 #endif /* HAVE_GNUTLS */