INN commit: trunk (TODO authprogs/auth_krb5.c)

INN Commit rra at isc.org
Thu Aug 20 23:31:59 UTC 2009


    Date: Thursday, August 20, 2009 @ 16:31:59
  Author: eagle
Revision: 8587

Rewrite auth_krb5 to use modern Kerberos APIs

Use krb5_get_init_creds_password and the current APIs and remove a bunch
of cruft that's unnecessary and uninteresting.  The library defaults will
take care of things like building the correct service principal.

Add a call to krb5_verify_init_creds, although this will only work if
nnrpd is pointed to a keytab that it can read or if it's run as root.
Looking in a different keytab for a local key with which to validate the
credentials is left as future work and requires additional configuration
to point to the correct keytab.

Modified:
  trunk/TODO
  trunk/authprogs/auth_krb5.c

-----------------------+
 TODO                  |    4 -
 authprogs/auth_krb5.c |  185 ++++++++++++++----------------------------------
 2 files changed, 56 insertions(+), 133 deletions(-)

Modified: TODO
===================================================================
--- TODO	2009-08-20 22:30:18 UTC (rev 8586)
+++ TODO	2009-08-20 23:31:59 UTC (rev 8587)
@@ -365,10 +365,6 @@
   Setting cnfscheckfudgesize clears up issues that otherwises causes INN
   to crash.
 
-* The way Kerberos authentication is done uses an obsolete interface and
-  doesn't verify the user's authentication by getting a service ticket.
-  It needs to be overhauled to use the right API.
-
 * There should be a way, with the Perl authentication hooks, to either
   immediately return a list of newsgroups one has access to based on the
   hostname or to indicate that authentication is required and make the

Modified: authprogs/auth_krb5.c
===================================================================
--- authprogs/auth_krb5.c	2009-08-20 22:30:18 UTC (rev 8586)
+++ authprogs/auth_krb5.c	2009-08-20 23:31:59 UTC (rev 8587)
@@ -27,149 +27,76 @@
 # include <com_err.h>
 #endif
 
-/* krb5_get_in_tkt_with_password is deprecated. */
-#define KRB5_DEPRECATED 1
 #include <krb5.h>
 
 #include "inn/messages.h"
 #include "inn/libinn.h"
 
 /*
- * Default life of the ticket we are getting. Since we are just checking
- * to see if the user can get one, it doesn't need a long lifetime.
- */
-#define KRB5_DEFAULT_LIFE    60 * 5 /* 5 minutes */
-
-
-/*
 **  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.
 */
 static int
-krb5_check_password (char *principal_name, char *password)
+krb5_check_password(const char *principal, const char *password)
 {
-   krb5_context      kcontext;
-   krb5_creds        creds;
-   krb5_principal    user_principal;
-   krb5_data         *user_realm;
-   krb5_principal    service_principal;
-   krb5_timestamp    now;
-   krb5_address      **addrs = (krb5_address **) NULL;   /* Use default */
-   long              lifetime = KRB5_DEFAULT_LIFE;
-   int               options = 0;
+    krb5_error_code code;
+    krb5_context ctx;
+    krb5_creds creds;
+    krb5_principal princ = NULL;
+    krb5_get_init_creds_opt opts;
+    bool creds_valid = false;
+    int result = 0;
 
-   krb5_preauthtype  *preauth = NULL;
+    code = krb5_init_context(&ctx);
+    if (code != 0) {
+        com_err(message_program_name, code, "initializing krb5 context");
+        return 0;
+    }
+    code = krb5_parse_name(ctx, principal, &princ);
+    if (code != 0) {
+        com_err(message_program_name, code, "parsing principal name %.100s",
+                principal);
+        goto cleanup;
+    }
+    memset(&opts, 0, sizeof(opts));
+    krb5_get_init_creds_opt_init(&opts);
+    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
+    krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+    code = krb5_get_init_creds_password(ctx, &creds, princ, (char *) password,
+                                        NULL, NULL, 0, NULL, &opts);
+    if (code == 0) {
+        krb5_verify_init_creds_opt vopts;
 
-   krb5_error_code   code;
-
-   /* Our return code - 1 is success */
-   int                result = 0;
+        creds_valid = true;
+        memset(&opts, 0, sizeof(vopts));
+        krb5_verify_init_creds_opt_init(&vopts);
+        code = krb5_verify_init_creds(ctx, &creds, princ, NULL, NULL, &vopts);
+    }
+    if (code == 0)
+        result = 1;
+    else {
+        switch (code) {
+        case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+            com_err(message_program_name, 0, "bad password for %.100s",
+                    principal);
+            break;
+        case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+            com_err(message_program_name, 0, "unknown user %.100s",
+                    principal);
+            break;
+        default:
+            com_err(message_program_name, code,
+                    "checking Kerberos password for %.100s", principal);
+        }
+    }
    
-   /* Initialize our Kerberos state */
-   code = krb5_init_context (&kcontext);
-   if (code) {
-       com_err (message_program_name, code, "initializing krb5 context");
-       return 0;
-   }
-   
-#ifdef HAVE_KRB5_INIT_ETS
-   /* Initialize krb5 error tables */    
-   krb5_init_ets (kcontext);
-#endif
-
-   /* Get current time */
-   code = krb5_timeofday (kcontext, &now);
-   if (code) {
-       com_err (message_program_name, code, "getting time of day");
-       return 0;
-   }
-
-   /* Set up credentials to be filled in */
-   memset (&creds, 0, sizeof(creds));
-
-   /* From here on, goto cleanup to exit */
-
-   /* Parse the username into a krb5 principal */
-   if (!principal_name) {
-       com_err (message_program_name, 0, "passed NULL principal name");
-       goto cleanup;
-   }
-
-   code = krb5_parse_name (kcontext, principal_name, &user_principal);
-   if (code) {
-       com_err (message_program_name, code,
-                "parsing user principal name %.100s", principal_name);
-       goto cleanup;
-   }
-
-   creds.client = user_principal;
-
-   /* Get the user's realm for building service principal */
-   user_realm = krb5_princ_realm (kcontext, user_principal);
-   
-   /*
-    * Build the service name into a principal. Right now this is
-    * a TGT for the user's realm.
-    */
-   code = krb5_build_principal_ext (kcontext,
-               &service_principal,
-               user_realm->length,
-               user_realm->data,
-               KRB5_TGS_NAME_SIZE,
-               KRB5_TGS_NAME,
-               user_realm->length,
-               user_realm->data,
-               0 /* terminator */);
-   if (code) {
-       com_err(message_program_name, code, "building service principal name");
-       goto cleanup;
-   }
-
-   creds.server = service_principal;
-
-   creds.times.starttime = 0;   /* Now */
-   creds.times.endtime = now + lifetime;
-   creds.times.renew_till = 0;   /* Unrenewable */
-
-   /* DO IT */
-   code = krb5_get_in_tkt_with_password (kcontext,
-               options,
-               addrs,
-               NULL,
-               preauth,
-               password,
-               0,
-               &creds,
-               0);
-   
-   /* We are done with password at this point... */
-
-   if (code) {   
-      /* FAILURE - Parse a few common errors here */
-      switch (code) {
-      case KRB5KRB_AP_ERR_BAD_INTEGRITY:
-         com_err (message_program_name, 0, "bad password for %.100s",
-                  principal_name);
-         break;
-      case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
-         com_err (message_program_name, 0, "unknown user \"%.100s\"",
-                  principal_name);
-         break;
-      default:
-         com_err (message_program_name, code,
-                  "checking Kerberos password for %.100s", principal_name);
-      }
-      result = 0;
-   } else {
-      /* SUCCESS */
-      result = 1;
-   }
-   
-   /* Cleanup */
- cleanup:
-   krb5_free_cred_contents (kcontext, &creds);
-
-   return result;
+cleanup:
+    if (creds_valid)
+        krb5_free_cred_contents(ctx, &creds);
+    if (princ != NULL)
+        krb5_free_principal(ctx, princ);
+    krb5_free_context(ctx);
+    return result;
 }
 
 int




More information about the inn-committers mailing list