build: use pkg-config for i18n
[exim.git] / src / src / auths / heimdal_gssapi.c
index 523f7c69a8a505fd2b469533f9cb2c28a3372066..e4e077c559c2e4e96ef296869796e7c5067d8733 100644 (file)
@@ -2,8 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* Copyright (c) Twitter Inc 2012
    Author: Phil Pennock <pdp@exim.org> */
 
 /* Copyright (c) Twitter Inc 2012
    Author: Phil Pennock <pdp@exim.org> */
@@ -59,11 +61,11 @@ static void dummy(int x) { dummy2(x-1); }
 /* Authenticator-specific options. */
 optionlist auth_heimdal_gssapi_options[] = {
   { "server_hostname",      opt_stringptr,
 /* Authenticator-specific options. */
 optionlist auth_heimdal_gssapi_options[] = {
   { "server_hostname",      opt_stringptr,
-      (void *)(offsetof(auth_heimdal_gssapi_options_block, server_hostname)) },
+      OPT_OFF(auth_heimdal_gssapi_options_block, server_hostname) },
   { "server_keytab",        opt_stringptr,
   { "server_keytab",        opt_stringptr,
-      (void *)(offsetof(auth_heimdal_gssapi_options_block, server_keytab)) },
+      OPT_OFF(auth_heimdal_gssapi_options_block, server_keytab) },
   { "server_service",       opt_stringptr,
   { "server_service",       opt_stringptr,
-      (void *)(offsetof(auth_heimdal_gssapi_options_block, server_service)) }
+      OPT_OFF(auth_heimdal_gssapi_options_block, server_service) }
 };
 
 int auth_heimdal_gssapi_options_count =
 };
 
 int auth_heimdal_gssapi_options_count =
@@ -80,11 +82,11 @@ auth_heimdal_gssapi_options_block auth_heimdal_gssapi_option_defaults = {
 #ifdef MACRO_PREDEF
 
 /* Dummy values */
 #ifdef MACRO_PREDEF
 
 /* Dummy values */
-void auth_heimdal_gssapi_init(auth_instance *ablock) {}
+void auth_heimdal_gssapi_init(driver_instance *ablock) {}
 int auth_heimdal_gssapi_server(auth_instance *ablock, uschar *data) {return 0;}
 int auth_heimdal_gssapi_client(auth_instance *ablock, void * sx,
   int timeout, uschar *buffer, int buffsize) {return 0;}
 int auth_heimdal_gssapi_server(auth_instance *ablock, uschar *data) {return 0;}
 int auth_heimdal_gssapi_client(auth_instance *ablock, void * sx,
   int timeout, uschar *buffer, int buffsize) {return 0;}
-void auth_heimdal_gssapi_version_report(FILE *f) {}
+gstring * auth_heimdal_gssapi_version_report(gstring * g) { return NULL; }
 
 #else   /*!MACRO_PREDEF*/
 
 
 #else   /*!MACRO_PREDEF*/
 
@@ -115,8 +117,11 @@ in the init, we mostly just use raw krb5 methods so that we can report
 the keytab contents, for -D+auth debugging. */
 
 void
 the keytab contents, for -D+auth debugging. */
 
 void
-auth_heimdal_gssapi_init(auth_instance *ablock)
+auth_heimdal_gssapi_init(driver_instance * a)
 {
 {
+auth_instance * ablock = (auth_instance *)a;
+auth_heimdal_gssapi_options_block * ob =
+  (auth_heimdal_gssapi_options_block *)(a->options_block);
 krb5_context context;
 krb5_keytab keytab;
 krb5_kt_cursor cursor;
 krb5_context context;
 krb5_keytab keytab;
 krb5_kt_cursor cursor;
@@ -124,8 +129,6 @@ krb5_keytab_entry entry;
 krb5_error_code krc;
 char *principal, *enctype_s;
 const char *k_keytab_typed_name = NULL;
 krb5_error_code krc;
 char *principal, *enctype_s;
 const char *k_keytab_typed_name = NULL;
-auth_heimdal_gssapi_options_block *ob =
-  (auth_heimdal_gssapi_options_block *)(ablock->options_block);
 
 ablock->server = FALSE;
 ablock->client = FALSE;
 
 ablock->server = FALSE;
 ablock->client = FALSE;
@@ -134,10 +137,9 @@ if (!ob->server_service || !*ob->server_service)
   {
   HDEBUG(D_auth) debug_printf("heimdal: missing server_service\n");
   return;
   {
   HDEBUG(D_auth) debug_printf("heimdal: missing server_service\n");
   return;
-}
+  }
 
 
-krc = krb5_init_context(&context);
-if (krc != 0)
+if ((krc = krb5_init_context(&context)))
   {
   int kerr = errno;
   HDEBUG(D_auth) debug_printf("heimdal: failed to initialise krb5 context: %s\n",
   {
   int kerr = errno;
   HDEBUG(D_auth) debug_printf("heimdal: failed to initialise krb5 context: %s\n",
@@ -149,8 +151,7 @@ if (ob->server_keytab)
   {
   k_keytab_typed_name = CCS string_sprintf("file:%s", expand_string(ob->server_keytab));
   HDEBUG(D_auth) debug_printf("heimdal: using keytab %s\n", k_keytab_typed_name);
   {
   k_keytab_typed_name = CCS string_sprintf("file:%s", expand_string(ob->server_keytab));
   HDEBUG(D_auth) debug_printf("heimdal: using keytab %s\n", k_keytab_typed_name);
-  krc = krb5_kt_resolve(context, k_keytab_typed_name, &keytab);
-  if (krc)
+  if ((krc = krb5_kt_resolve(context, k_keytab_typed_name, &keytab)))
     {
     HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_resolve", context, krc);
     return;
     {
     HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_resolve", context, krc);
     return;
@@ -159,8 +160,7 @@ if (ob->server_keytab)
 else
  {
   HDEBUG(D_auth) debug_printf("heimdal: using system default keytab\n");
 else
  {
   HDEBUG(D_auth) debug_printf("heimdal: using system default keytab\n");
-  krc = krb5_kt_default(context, &keytab);
-  if (krc)
+  if ((krc = krb5_kt_default(context, &keytab)))
     {
     HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_default", context, krc);
     return;
     {
     HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_default", context, krc);
     return;
@@ -170,12 +170,11 @@ else
 HDEBUG(D_auth)
   {
   /* http://www.h5l.org/manual/HEAD/krb5/krb5_keytab_intro.html */
 HDEBUG(D_auth)
   {
   /* http://www.h5l.org/manual/HEAD/krb5/krb5_keytab_intro.html */
-  krc = krb5_kt_start_seq_get(context, keytab, &cursor);
-  if (krc)
+  if ((krc = krb5_kt_start_seq_get(context, keytab, &cursor)))
     exim_heimdal_error_debug("krb5_kt_start_seq_get", context, krc);
   else
     {
     exim_heimdal_error_debug("krb5_kt_start_seq_get", context, krc);
   else
     {
-    while ((krc = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0)
+    while (!(krc = krb5_kt_next_entry(context, keytab, &entry, &cursor)))
       {
       principal = enctype_s = NULL;
       krb5_unparse_name(context, entry.principal, &principal);
       {
       principal = enctype_s = NULL;
       krb5_unparse_name(context, entry.principal, &principal);
@@ -188,14 +187,12 @@ HDEBUG(D_auth)
       free(enctype_s);
       krb5_kt_free_entry(context, &entry);
       }
       free(enctype_s);
       krb5_kt_free_entry(context, &entry);
       }
-    krc = krb5_kt_end_seq_get(context, keytab, &cursor);
-    if (krc)
+    if ((krc = krb5_kt_end_seq_get(context, keytab, &cursor)))
       exim_heimdal_error_debug("krb5_kt_end_seq_get", context, krc);
     }
   }
 
       exim_heimdal_error_debug("krb5_kt_end_seq_get", context, krc);
     }
   }
 
-krc = krb5_kt_close(context, keytab);
-if (krc)
+if ((krc = krb5_kt_close(context, keytab)))
   HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_close", context, krc);
 
 krb5_free_context(context);
   HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_close", context, krc);
 
 krb5_free_context(context);
@@ -230,6 +227,8 @@ gss_buffer_desc / *gss_buffer_t: hold/point-to size_t .length & void *value
 int
 auth_heimdal_gssapi_server(auth_instance *ablock, uschar *initial_data)
 {
 int
 auth_heimdal_gssapi_server(auth_instance *ablock, uschar *initial_data)
 {
+auth_heimdal_gssapi_options_block * ob =
+  (auth_heimdal_gssapi_options_block *)(ablock->drinst.options_block);
 gss_name_t gclient = GSS_C_NO_NAME;
 gss_name_t gserver = GSS_C_NO_NAME;
 gss_cred_id_t gcred = GSS_C_NO_CREDENTIAL;
 gss_name_t gclient = GSS_C_NO_NAME;
 gss_name_t gserver = GSS_C_NO_NAME;
 gss_cred_id_t gcred = GSS_C_NO_CREDENTIAL;
@@ -242,8 +241,6 @@ gss_OID mech_type;
 OM_uint32 maj_stat, min_stat;
 int step, error_out;
 uschar *tmp1, *tmp2, *from_client;
 OM_uint32 maj_stat, min_stat;
 int step, error_out;
 uschar *tmp1, *tmp2, *from_client;
-auth_heimdal_gssapi_options_block *ob =
-  (auth_heimdal_gssapi_options_block *)(ablock->options_block);
 BOOL handled_empty_ir;
 rmark store_reset_point;
 uschar *keytab;
 BOOL handled_empty_ir;
 rmark store_reset_point;
 uschar *keytab;
@@ -253,7 +250,7 @@ uschar requested_qop;
 store_reset_point = store_mark();
 
 HDEBUG(D_auth)
 store_reset_point = store_mark();
 
 HDEBUG(D_auth)
-  debug_printf("heimdal: initialising auth context for %s\n", ablock->name);
+  debug_printf("heimdal: initialising auth context for %s\n", ablock->drinst.name);
 
 /* Construct our gss_name_t gserver describing ourselves */
 tmp1 = expand_string(ob->server_service);
 
 /* Construct our gss_name_t gserver describing ourselves */
 tmp1 = expand_string(ob->server_service);
@@ -317,7 +314,7 @@ while (step < 4)
   switch (step)
     {
     case 0:
   switch (step)
     {
     case 0:
-      if (!from_client || *from_client == '\0')
+      if (!from_client || !*from_client)
         {
        if (handled_empty_ir)
          {
         {
        if (handled_empty_ir)
          {
@@ -325,15 +322,12 @@ while (step < 4)
          error_out = BAD64;
          goto ERROR_OUT;
          }
          error_out = BAD64;
          goto ERROR_OUT;
          }
-       else
-         {
-         HDEBUG(D_auth) debug_printf("gssapi: missing initial response, nudging.\n");
-         error_out = auth_get_data(&from_client, US"", 0);
-         if (error_out != OK)
-           goto ERROR_OUT;
-         handled_empty_ir = TRUE;
-         continue;
-         }
+
+       HDEBUG(D_auth) debug_printf("gssapi: missing initial response, nudging.\n");
+       if ((error_out = auth_get_data(&from_client, US"", 0)) != OK)
+         goto ERROR_OUT;
+       handled_empty_ir = TRUE;
+       continue;
        }
       /* We should now have the opening data from the client, base64-encoded. */
       step += 1;
        }
       /* We should now have the opening data from the client, base64-encoded. */
       step += 1;
@@ -341,7 +335,7 @@ while (step < 4)
       break;
 
     case 1:
       break;
 
     case 1:
-      gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value);
+      gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value, GET_TAINTED);
       if (gclient)
         {
        maj_stat = gss_release_name(&min_stat, &gclient);
       if (gclient)
         {
        maj_stat = gss_release_name(&min_stat, &gclient);
@@ -426,7 +420,7 @@ while (step < 4)
       break;
 
     case 3:
       break;
 
     case 3:
-      gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value);
+      gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value, GET_TAINTED);
       maj_stat = gss_unwrap(&min_stat,
          gcontext,
          &gbufdesc_in,       /* data from client */
       maj_stat = gss_unwrap(&min_stat,
          gcontext,
          &gbufdesc_in,       /* data from client */
@@ -451,7 +445,7 @@ while (step < 4)
        }
 
       requested_qop = (CS gbufdesc_out.value)[0];
        }
 
       requested_qop = (CS gbufdesc_out.value)[0];
-      if ((requested_qop & 0x01) == 0)
+      if (!(requested_qop & 0x01))
         {
        HDEBUG(D_auth)
          debug_printf("gssapi: client requested security layers (%x)\n",
         {
        HDEBUG(D_auth)
          debug_printf("gssapi: client requested security layers (%x)\n",
@@ -483,9 +477,7 @@ while (step < 4)
 
       /* $auth1 is GSSAPI display name */
       maj_stat = gss_display_name(&min_stat,
 
       /* $auth1 is GSSAPI display name */
       maj_stat = gss_display_name(&min_stat,
-         gclient,
-         &gbufdesc_out,
-         &mech_type);
+         gclient, &gbufdesc_out, &mech_type);
       if (GSS_ERROR(maj_stat))
         {
        auth_vars[1] = expand_nstring[2] = NULL;
       if (GSS_ERROR(maj_stat))
         {
        auth_vars[1] = expand_nstring[2] = NULL;
@@ -556,7 +548,7 @@ va_list ap;
 OM_uint32 maj_stat, min_stat;
 OM_uint32 msgcontext = 0;
 gss_buffer_desc status_string;
 OM_uint32 maj_stat, min_stat;
 OM_uint32 msgcontext = 0;
 gss_buffer_desc status_string;
-gstring * g;
+gstring * g = NULL;
 
 HDEBUG(D_auth)
   {
 
 HDEBUG(D_auth)
   {
@@ -574,9 +566,8 @@ do {
   if (!auth_defer_msg)
     auth_defer_msg = string_copy(US status_string.value);
 
   if (!auth_defer_msg)
     auth_defer_msg = string_copy(US status_string.value);
 
-  HDEBUG(D_auth) debug_printf("heimdal %s: %.*s\n",
-      string_from_gstring(g), (int)status_string.length,
-      CS status_string.value);
+  HDEBUG(D_auth) debug_printf("heimdal %Y: %.*s\n",
+      g, (int)status_string.length, CS status_string.value);
   gss_release_buffer(&min_stat, &status_string);
 
   } while (msgcontext != 0);
   gss_release_buffer(&min_stat, &status_string);
 
   } while (msgcontext != 0);
@@ -611,16 +602,39 @@ return FAIL;
 *                Diagnostic API                  *
 *************************************************/
 
 *                Diagnostic API                  *
 *************************************************/
 
-void
-auth_heimdal_gssapi_version_report(FILE *f)
+gstring *
+auth_heimdal_gssapi_version_report(gstring * g)
 {
 /* No build-time constants available unless we link against libraries at
 build-time and export the result as a string into a header ourselves. */
 {
 /* No build-time constants available unless we link against libraries at
 build-time and export the result as a string into a header ourselves. */
-fprintf(f, "Library version: Heimdal: Runtime: %s\n"
-          " Build Info: %s\n",
+
+return string_fmt_append(g, "Library version: Heimdal: Runtime: %s\n"
+                           " Build Info: %s\n",
        heimdal_version, heimdal_long_version);
 }
 
        heimdal_version, heimdal_long_version);
 }
 
+# ifdef DYNLOOKUP
+#  define heimdal_gssapi_auth_info _auth_info
+# endif
+
+auth_info heimdal_gssapi_auth_info = {
+.drinfo = {
+  .driver_name =       US"heimdal_gssapi",                   /* lookup name */
+  .options =           auth_heimdal_gssapi_options,
+  .options_count =     &auth_heimdal_gssapi_options_count,
+  .options_block =     &auth_heimdal_gssapi_option_defaults,
+  .options_len =       sizeof(auth_heimdal_gssapi_options_block),
+  .init =              auth_heimdal_gssapi_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =         AUTH_MAGIC,
+# endif
+  },
+.servercode =          auth_heimdal_gssapi_server,
+.clientcode =          NULL,
+.version_report =      auth_heimdal_gssapi_version_report,
+.macros_create =       NULL,
+};
+
 #endif   /*!MACRO_PREDEF*/
 #endif  /* AUTH_HEIMDAL_GSSAPI */
 
 #endif   /*!MACRO_PREDEF*/
 #endif  /* AUTH_HEIMDAL_GSSAPI */