Added support for the KrbServiceName option, which can be used to set the name
[mod_auth_kerb.git] / src / mod_auth_kerb.c
index 410fda6..ab17c72 100644 (file)
@@ -96,6 +96,7 @@
 #  define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
 #  define krb5_get_err_text(context,code) error_message(code)
 #endif
+#include "spnegokrb5.h"
 #endif /* KRB5 */
 
 #ifdef KRB4
@@ -137,6 +138,7 @@ typedef struct {
        char *krb_auth_realms;
        int krb_save_credentials;
        int krb_verify_kdc;
+       char *krb_service_name;
 #ifdef KRB5
        char *krb_5_keytab;
        int krb_method_gssapi;
@@ -176,6 +178,9 @@ static const command_rec kerb_auth_cmds[] = {
    command("KrbVerifyKDC", ap_set_flag_slot, krb_verify_kdc,
      FLAG, "Verify tickets against keytab to prevent KDC spoofing attacks."),
 
+   command("KrbServiceName", ap_set_file_slot, krb_service_name,
+     TAKE1, "Service name to be used by Apache for authentication."),
+
 #ifdef KRB5
    command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
      TAKE1, "Location of Kerberos V5 keytab file."),
@@ -217,6 +222,7 @@ static void *kerb_dir_create_config(MK_POOL *p, char *d)
 
        rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
         ((kerb_auth_config *)rec)->krb_verify_kdc = 1;
+       ((kerb_auth_config *)rec)->krb_service_name = "khttp";
 #ifdef KRB5
        ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
        ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
@@ -395,7 +401,8 @@ authenticate_user_krb4pwd(request_rec *r,
 
       ret = verify_krb4_user(r, (char *)sent_name, 
                             (sent_instance) ? sent_instance : "",
-                            (char *)realm, (char *)sent_pw, "khttp",
+                            (char *)realm, (char *)sent_pw,
+                            conf->krb_service_name,
                             conf->krb_4_srvtab, conf->krb_verify_kdc);
       if (ret == 0)
         break;
@@ -668,7 +675,8 @@ int authenticate_user_krb5pwd(request_rec *r,
       if (code)
         continue;
 
-      code = verify_krb5_user(r, kcontext, client, ccache, sent_pw, "khttp",
+      code = verify_krb5_user(r, kcontext, client, ccache, sent_pw, 
+                             conf->krb_service_name, 
                              keytab, conf->krb_verify_kdc);
       if (code == 0)
         break;
@@ -828,7 +836,7 @@ get_gss_creds(request_rec *r,
    gss_name_t server_name = GSS_C_NO_NAME;
    char buf[1024];
 
-   snprintf(buf, sizeof(buf), "%s/%s", "khttp", ap_get_server_name(r));
+   snprintf(buf, sizeof(buf), "%s/%s", conf->krb_service_name, ap_get_server_name(r));
 
    input_token.value = buf;
    input_token.length = strlen(buf) + 1;
@@ -858,6 +866,33 @@ get_gss_creds(request_rec *r,
 }
 
 static int
+cmp_gss_type(gss_buffer_t token, gss_OID oid)
+{
+   unsigned char *p;
+   size_t len;
+
+   if (token->length == 0)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   p = token->value;
+   if (*p++ != 0x60)
+      return GSS_S_DEFECTIVE_TOKEN;
+   len = *p++;
+   if (len & 0x80) {
+      if ((len & 0x7f) > 4)
+        return GSS_S_DEFECTIVE_TOKEN;
+      p += len & 0x7f;
+   }
+   if (*p++ != 0x06)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   if (((OM_uint32) *p++) != oid->length)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   return memcmp(p, oid->elements, oid->length);
+}
+
+static int
 authenticate_user_gss(request_rec *r,
                      kerb_auth_config *conf,
                      const char *auth_line)
@@ -869,6 +904,11 @@ authenticate_user_gss(request_rec *r,
   int ret;
   gss_name_t client_name = GSS_C_NO_NAME;
   gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
+  OM_uint32 (*accept_sec_token)();
+  gss_OID_desc spnego_oid;
+
+  spnego_oid.length = 6;
+  spnego_oid.elements = (void *)"\x2b\x06\x01\x05\x05\x02";
 
   if (gss_connection == NULL) {
      gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
@@ -922,22 +962,20 @@ authenticate_user_gss(request_rec *r,
   }
   input_token.length = ap_base64decode(input_token.value, auth_param);
 
-#if 0 
-  major_status = gss_accept_sec_context(
-#else
-  major_status = gss_accept_sec_context_spnego(
-#endif
-                                       &minor_status,
-                                       &gss_connection->context,
-                                       gss_connection->server_creds,
-                                       &input_token,
-                                       GSS_C_NO_CHANNEL_BINDINGS,
-                                       &client_name,
-                                       NULL,
-                                       &output_token,
-                                       NULL,
-                                       NULL,
-                                       &delegated_cred);
+  accept_sec_token = (cmp_gss_type(&input_token, &spnego_oid) == 0) ?
+                       gss_accept_sec_context_spnego : gss_accept_sec_context;
+
+  major_status = accept_sec_token(&minor_status,
+                                 &gss_connection->context,
+                                 gss_connection->server_creds,
+                                 &input_token,
+                                 GSS_C_NO_CHANNEL_BINDINGS,
+                                 &client_name,
+                                 NULL,
+                                 &output_token,
+                                 NULL,
+                                 NULL,
+                                 &delegated_cred);
   if (output_token.length) {
      char *token = NULL;
      size_t len;