INN commit: trunk (authprogs/auth_krb5.c configure.ac)

INN Commit rra at isc.org
Sun Mar 4 03:40:18 UTC 2018


    Date: Saturday, March 3, 2018 @ 19:40:17
  Author: eagle
Revision: 10252

Stop using com_err directly

com_err is an obsolete way of reporting Kerberos errors.  Add some
additional Kerberos portability code from rra-c-util to allow using
krb5_get_error_message, which is the modern approach, and remove the
additional probing for com_err.h.

Modified:
  trunk/authprogs/auth_krb5.c
  trunk/configure.ac

-----------------------+
 authprogs/auth_krb5.c |  137 ++++++++++++++++++++++++++++++++++++++++--------
 configure.ac          |   46 ----------------
 2 files changed, 117 insertions(+), 66 deletions(-)

Modified: authprogs/auth_krb5.c
===================================================================
--- authprogs/auth_krb5.c	2018-02-26 21:06:13 UTC (rev 10251)
+++ authprogs/auth_krb5.c	2018-03-04 03:40:17 UTC (rev 10252)
@@ -1,12 +1,12 @@
 /*  $Id$
 **
-**  Check an username and password against Kerberos v5.
+**  Check an username and password against Kerberos.
 **
 **  Based on nnrpkrb5auth by Christopher P. Lindsey <lindsey at mallorn.com>
 **  See <http://www.mallorn.com/tools/nnrpkrb5auth>
 **
 **  This program takes a username and password pair from nnrpd and checks
-**  checks their validity against a Kerberos v5 KDC by attempting to obtain a
+**  checks their validity against a Kerberos KDC by attempting to obtain a
 **  TGT.  With the -i <instance> command line option, appends /<instance> to
 **  the username prior to authentication.
 **
@@ -21,28 +21,123 @@
 #include "config.h"
 #include "clibrary.h"
 #include "libauth.h"
-#ifdef HAVE_ET_COM_ERR_H
-# include <et/com_err.h>
-#elif defined(HAVE_KERBEROSV5_COM_ERR_H)
-# include <kerberosv5/com_err.h>
-#else
-# include <com_err.h>
-#endif
 
-#ifdef HAVE_KRB5_H
+#if defined(HAVE_KRB5_H)
 # include <krb5.h>
-#elif HAVE_KERBEROSV5_KRB5_H
+#elif defined(HAVE_KERBEROSV5_KRB5_H)
 # include <kerberosv5/krb5.h>
 #else
 # include <krb5/krb5.h>
 #endif
 
+/* Figure out what header files to include for error reporting. */
+#if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) && !defined(HAVE_KRB5_GET_ERR_TEXT)
+# if !defined(HAVE_KRB5_GET_ERROR_STRING)
+#  if defined(HAVE_IBM_SVC_KRB5_SVC_H)
+#   include <ibm_svc/krb5_svc.h>
+#  elif defined(HAVE_ET_COM_ERR_H)
+#   include <et/com_err.h>
+#  elif defined(HAVE_KERBEROSV5_COM_ERR_H)
+#   include <kerberosv5/com_err.h>
+#  else
+#   include <com_err.h>
+#  endif
+# endif
+#endif
+
 #include "inn/messages.h"
 #include "inn/libinn.h"
+#include "inn/xmalloc.h"
 
 /*
+ * This string is returned for unknown error messages.  We use a static
+ * variable so that we can be sure not to free it.
+ */
+#if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) \
+    || !defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
+static const char error_unknown[] = "unknown error";
+#endif
+
+
+#ifndef HAVE_KRB5_GET_ERROR_MESSAGE
+/*
+ * Given a Kerberos error code, return the corresponding error.  Prefer the
+ * Kerberos interface if available since it will provide context-specific
+ * error information, whereas the error_message() call will only provide a
+ * fixed message.
+ */
+const char *
+krb5_get_error_message(krb5_context ctx UNUSED, krb5_error_code code UNUSED)
+{
+    const char *msg;
+
+# if defined(HAVE_KRB5_GET_ERROR_STRING)
+    msg = krb5_get_error_string(ctx);
+# elif defined(HAVE_KRB5_GET_ERR_TEXT)
+    msg = krb5_get_err_text(ctx, code);
+# elif defined(HAVE_KRB5_SVC_GET_MSG)
+    krb5_svc_get_msg(code, (char **) &msg);
+# else
+    msg = error_message(code);
+# endif
+    if (msg == NULL)
+        return error_unknown;
+    else
+        return msg;
+}
+#endif /* !HAVE_KRB5_GET_ERROR_MESSAGE */
+
+
+#ifndef HAVE_KRB5_FREE_ERROR_MESSAGE
+/*
+ * Free an error string if necessary.  If we returned a static string, make
+ * sure we don't free it.
+ *
+ * This code assumes that the set of implementations that have
+ * krb5_free_error_message is a subset of those with krb5_get_error_message.
+ * If this assumption ever breaks, we may call the wrong free function.
+ */
+void
+krb5_free_error_message(krb5_context ctx UNUSED, const char *msg)
+{
+    if (msg == error_unknown)
+        return;
+# if defined(HAVE_KRB5_GET_ERROR_STRING)
+    krb5_free_error_string(ctx, (char *) msg);
+# elif defined(HAVE_KRB5_SVC_GET_MSG)
+    krb5_free_string(ctx, (char *) msg);
+# endif
+}
+#endif /* !HAVE_KRB5_FREE_ERROR_MESSAGE */
+
+
+/*
+**  Report a Kerberos error to standard error.
+*/
+static void __attribute__((__format__(printf, 3, 0)))
+warn_krb5(krb5_context ctx, krb5_error_code code, const char *format, ...)
+{
+    const char *k5_msg;
+    char *message;
+    va_list args;
+
+    k5_msg = krb5_get_error_message(ctx, code);
+    va_start(args, format);
+    xvasprintf(&message, format, args);
+    va_end(args);
+    if (k5_msg == NULL)
+        warn("%s", message);
+    else
+        warn("%s: %s", message, k5_msg);
+    free(message);
+    if (k5_msg != NULL)
+        krb5_free_error_message(ctx, k5_msg);
+}
+
+
+/*
 **  Check the username and password by attempting to get a TGT.  Returns 1 on
-**  success and 0 on failure.  Errors are reported via com_err.
+**  success and 0 on failure.
 */
 static int
 krb5_check_password(const char *principal, const char *password)
@@ -57,13 +152,12 @@
 
     code = krb5_init_context(&ctx);
     if (code != 0) {
-        com_err(message_program_name, code, "initializing krb5 context");
+        warn_krb5(NULL, code, "cannot initialize Kerberos");
         return 0;
     }
     code = krb5_parse_name(ctx, principal, &princ);
     if (code != 0) {
-        com_err(message_program_name, code, "parsing principal name %.100s",
-                principal);
+        warn_krb5(ctx, code, "cannot parse principal %.100s", principal);
         goto cleanup;
     }
     memset(&opts, 0, sizeof(opts));
@@ -85,16 +179,15 @@
     else {
         switch (code) {
         case KRB5KRB_AP_ERR_BAD_INTEGRITY:
-            com_err(message_program_name, 0, "bad password for %.100s",
-                    principal);
+            warn("bad password for %.100s", principal);
             break;
         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
-            com_err(message_program_name, 0, "unknown user %.100s",
-                    principal);
+            warn("unknown user %.100s", principal);
             break;
         default:
-            com_err(message_program_name, code,
-                    "checking Kerberos password for %.100s", principal);
+            warn_krb5(ctx, code, "Kerberos authentication for %.100s failed",
+                      principal);
+            break;
         }
     }
    
@@ -132,7 +225,7 @@
     /* May need to prepend instance name if -i option was given. */
     if (argc > 1) {
         if (argc == 3 && strcmp(argv[1], "-i") == 0) {
-            new_user = concat(authinfo->username, "/", argv[2], (char *) 0);
+            xasprintf(&new_user, "%s/%s", authinfo->username, argv[2]);
             free(authinfo->username);
             authinfo->username = new_user;
         } else {

Modified: configure.ac
===================================================================
--- configure.ac	2018-02-26 21:06:13 UTC (rev 10251)
+++ configure.ac	2018-03-04 03:40:17 UTC (rev 10252)
@@ -394,50 +394,8 @@
 INN_LIB_ZLIB_OPTIONAL
 
 dnl If Kerberos is found, define KRB5_AUTH to auth_krb5 so as to build
-dnl that program.  In case neither et/com_err.h nor kerberosv5/com_err.h
-dnl nor com_err.h can be found and --with-krb5 is not given, do not define
-dnl KRB5_AUTH and clear the other variables set for Kerberos support.
-AS_IF([test x"$inn_use_KRB5" = xtrue],
-    [inn_KRB5_incroot=
-     inn_KRB5_header_found=
-     AS_IF([test x"$inn_krb5_includedir" != x],
-        [inn_KRB5_incroot="$inn_krb5_includedir"],
-        [AS_IF([test x"$inn_krb5_root" != x],
-            [inn_KRB5_incroot="${inn_krb5_root}/include"])])
-     AS_IF([test x"$inn_KRB5_incroot" = x],
-        [AC_CHECK_HEADERS([et/com_err.h], 
-            [inn_KRB5_header_found=yes],
-            [inn_KRB5_header_found=no])],
-        [AS_IF([test -f "${inn_KRB5_incroot}/et/com_err.h"],
-            [inn_KRB5_header_found=yes
-             AC_DEFINE([HAVE_ET_COM_ERR_H], [1],
-                [Define if you have the <et/com_err.h> header file.])],
-            [inn_KRB5_header_found=no])])
-     AS_IF([test x"$inn_KRB5_incroot" = x],
-        [AC_CHECK_HEADERS([kerberosv5/com_err.h], 
-            [inn_KRB5_header_found=yes],
-            [inn_KRB5_header_found=no])],
-        [AS_IF([test -f "${inn_KRB5_incroot}/kerberosv5/com_err.h"],
-            [inn_KRB5_header_found=yes
-             AC_DEFINE([HAVE_KERBEROSV5_COM_ERR_H], [1],
-                [Define if you have the <kerberosv5/com_err.h> header file.])],
-            [inn_KRB5_header_found=no])])
-     AS_IF([test x"$inn_KRB5_incroot" = x],
-        [AC_CHECK_HEADERS([com_err.h], 
-            [inn_KRB5_header_found=yes],
-            [inn_KRB5_header_found=no])],
-        [AS_IF([test -f "${inn_KRB5_incroot}/com_err.h"],
-            [inn_KRB5_header_found=yes
-             AC_DEFINE([HAVE_COM_ERR_H], [1],
-                [Define if you have the <com_err.h> header file.])],
-            [inn_KRB5_header_found=no])])
-     AS_IF([test x"${inn_KRB5_header_found}" = xyes],
-        [KRB5_AUTH=auth_krb5],
-        [AS_IF([test x"$with_krb5" = x],
-            [KRB5_CPPFLAGS=
-             KRB5_LDFLAGS=
-             KRB5_LIBS=],
-            [AC_MSG_ERROR([cannot find usable com_err header])])])])
+dnl that program.
+AS_IF([test x"$inn_use_KRB5" = xtrue], [KRB5_AUTH=auth_krb5])
 AC_SUBST([KRB5_AUTH])
 
 dnl If Berkeley DB is found, check the presence of its header and whether the



More information about the inn-committers mailing list