Add dns_canonicalize_hostname=fallback support
This commit is contained in:
		
							parent
							
								
									9d9730eb07
								
							
						
					
					
						commit
						0555bc87c8
					
				
							
								
								
									
										409
									
								
								Add-dns_canonicalize_hostname-fallback-support.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								Add-dns_canonicalize_hostname-fallback-support.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,409 @@ | ||||
| From 18d45e4b48c363f631b1acd7dac5902351bf1a0e Mon Sep 17 00:00:00 2001 | ||||
| From: Simo Sorce <simo@redhat.com> | ||||
| Date: Tue, 4 Dec 2018 15:22:55 -0500 | ||||
| Subject: [PATCH] Add dns_canonicalize_hostname=fallback support | ||||
| 
 | ||||
| Turn dns_canonicalize_hostname into a tristate variable, allowing the | ||||
| value "fallback" as well as the true/false booleans.  If it is set to | ||||
| fallback, delay DNS canonicalization and attempt it only in | ||||
| krb5_get_credentials() if the KDC responds that the requested server | ||||
| principal name is unknown. | ||||
| 
 | ||||
| [ghudson@mit.edu: added TGS tests; refactored code; edited commit | ||||
| message and documentation] | ||||
| 
 | ||||
| ticket: 8765 (new) | ||||
| (cherry picked from commit 6c20cb1c89acaa03db897182a3b28d5f8f284907) | ||||
| ---
 | ||||
|  doc/admin/conf_files/krb5_conf.rst |  4 ++ | ||||
|  src/include/k5-int.h               |  8 ++- | ||||
|  src/include/k5-trace.h             |  3 ++ | ||||
|  src/lib/krb5/krb/get_creds.c       | 79 ++++++++++++++++++++++++++---- | ||||
|  src/lib/krb5/krb/init_ctx.c        | 27 +++++++++- | ||||
|  src/lib/krb5/krb/t_copy_context.c  |  2 +- | ||||
|  src/lib/krb5/os/os-proto.h         |  4 ++ | ||||
|  src/lib/krb5/os/sn2princ.c         | 19 +++++-- | ||||
|  src/tests/gcred.c                  |  5 +- | ||||
|  src/tests/t_sn2princ.py            | 34 ++++++++++++- | ||||
|  10 files changed, 167 insertions(+), 18 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
 | ||||
| index 7b4389f6b..e9f7e8c59 100644
 | ||||
| --- a/doc/admin/conf_files/krb5_conf.rst
 | ||||
| +++ b/doc/admin/conf_files/krb5_conf.rst
 | ||||
| @@ -201,6 +201,10 @@ The libdefaults section may contain any of the following relations:
 | ||||
|      means that short hostnames will not be canonicalized to | ||||
|      fully-qualified hostnames.  The default value is true. | ||||
|   | ||||
| +    If this option is set to ``fallback`` (new in release 1.18), DNS
 | ||||
| +    canonicalization will only be performed the server hostname is not
 | ||||
| +    found with the original name when requesting credentials.
 | ||||
| +
 | ||||
|  **dns_lookup_kdc** | ||||
|      Indicate whether DNS SRV records should be used to locate the KDCs | ||||
|      and other servers for a realm, if they are not listed in the | ||||
| diff --git a/src/include/k5-int.h b/src/include/k5-int.h
 | ||||
| index 255cee822..1e6a739e9 100644
 | ||||
| --- a/src/include/k5-int.h
 | ||||
| +++ b/src/include/k5-int.h
 | ||||
| @@ -1159,6 +1159,12 @@ k5_plugin_register_dyn(krb5_context context, int interface_id,
 | ||||
|  void | ||||
|  k5_plugin_free_context(krb5_context context); | ||||
|   | ||||
| +enum dns_canonhost {
 | ||||
| +    CANONHOST_FALSE = 0,
 | ||||
| +    CANONHOST_TRUE = 1,
 | ||||
| +    CANONHOST_FALLBACK = 2
 | ||||
| +};
 | ||||
| +
 | ||||
|  struct _kdb5_dal_handle;        /* private, in kdb5.h */ | ||||
|  typedef struct _kdb5_dal_handle kdb5_dal_handle; | ||||
|  struct _kdb_log_context; | ||||
| @@ -1222,7 +1228,7 @@ struct _krb5_context {
 | ||||
|   | ||||
|      krb5_boolean allow_weak_crypto; | ||||
|      krb5_boolean ignore_acceptor_hostname; | ||||
| -    krb5_boolean dns_canonicalize_hostname;
 | ||||
| +    enum dns_canonhost dns_canonicalize_hostname;
 | ||||
|   | ||||
|      krb5_trace_callback trace_callback; | ||||
|      void *trace_callback_data; | ||||
| diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
 | ||||
| index 2aa379b76..f3ed6a45d 100644
 | ||||
| --- a/src/include/k5-trace.h
 | ||||
| +++ b/src/include/k5-trace.h
 | ||||
| @@ -191,6 +191,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
 | ||||
|  #define TRACE_FAST_REQUIRED(c)                                  \ | ||||
|      TRACE(c, "Using FAST due to KRB5_FAST_REQUIRED flag") | ||||
|   | ||||
| +#define TRACE_GET_CREDS_FALLBACK(c, hostname)                           \
 | ||||
| +    TRACE(c, "Falling back to canonicalized server hostname {str}", hostname)
 | ||||
| +
 | ||||
|  #define TRACE_GIC_PWD_CHANGED(c)                                \ | ||||
|      TRACE(c, "Getting initial TGT with changed password") | ||||
|  #define TRACE_GIC_PWD_CHANGEPW(c, tries)                                \ | ||||
| diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
 | ||||
| index 69900adfa..0a04d68b9 100644
 | ||||
| --- a/src/lib/krb5/krb/get_creds.c
 | ||||
| +++ b/src/lib/krb5/krb/get_creds.c
 | ||||
| @@ -39,6 +39,7 @@
 | ||||
|   | ||||
|  #include "k5-int.h" | ||||
|  #include "int-proto.h" | ||||
| +#include "os-proto.h"
 | ||||
|  #include "fast.h" | ||||
|   | ||||
|  /* | ||||
| @@ -1249,6 +1250,26 @@ krb5_tkt_creds_step(krb5_context context, krb5_tkt_creds_context ctx,
 | ||||
|          return EINVAL; | ||||
|  } | ||||
|   | ||||
| +static krb5_error_code
 | ||||
| +try_get_creds(krb5_context context, krb5_flags options, krb5_ccache ccache,
 | ||||
| +              krb5_creds *in_creds, krb5_creds *creds_out)
 | ||||
| +{
 | ||||
| +    krb5_error_code code;
 | ||||
| +    krb5_tkt_creds_context ctx = NULL;
 | ||||
| +
 | ||||
| +    code = krb5_tkt_creds_init(context, ccache, in_creds, options, &ctx);
 | ||||
| +    if (code)
 | ||||
| +        goto cleanup;
 | ||||
| +    code = krb5_tkt_creds_get(context, ctx);
 | ||||
| +    if (code)
 | ||||
| +        goto cleanup;
 | ||||
| +    code = krb5_tkt_creds_get_creds(context, ctx, creds_out);
 | ||||
| +
 | ||||
| +cleanup:
 | ||||
| +    krb5_tkt_creds_free(context, ctx);
 | ||||
| +    return code;
 | ||||
| +}
 | ||||
| +
 | ||||
|  krb5_error_code KRB5_CALLCONV | ||||
|  krb5_get_credentials(krb5_context context, krb5_flags options, | ||||
|                       krb5_ccache ccache, krb5_creds *in_creds, | ||||
| @@ -1256,7 +1277,10 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
 | ||||
|  { | ||||
|      krb5_error_code code; | ||||
|      krb5_creds *ncreds = NULL; | ||||
| -    krb5_tkt_creds_context ctx = NULL;
 | ||||
| +    krb5_creds canon_creds, store_creds;
 | ||||
| +    krb5_principal_data canon_server;
 | ||||
| +    krb5_data canon_components[2];
 | ||||
| +    char *hostname = NULL, *canon_hostname = NULL;
 | ||||
|   | ||||
|      *out_creds = NULL; | ||||
|   | ||||
| @@ -1265,22 +1289,59 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
 | ||||
|      if (ncreds == NULL) | ||||
|          goto cleanup; | ||||
|   | ||||
| -    /* Make and execute a krb5_tkt_creds context to get the credential. */
 | ||||
| -    code = krb5_tkt_creds_init(context, ccache, in_creds, options, &ctx);
 | ||||
| -    if (code != 0)
 | ||||
| +    code = try_get_creds(context, options, ccache, in_creds, ncreds);
 | ||||
| +    if (!code) {
 | ||||
| +        *out_creds = ncreds;
 | ||||
| +        return 0;
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    /* Possibly try again with the canonicalized hostname, if the server is
 | ||||
| +     * host-based and we are configured for fallback canonicalization. */
 | ||||
| +    if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
 | ||||
|          goto cleanup; | ||||
| -    code = krb5_tkt_creds_get(context, ctx);
 | ||||
| -    if (code != 0)
 | ||||
| +    if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK)
 | ||||
|          goto cleanup; | ||||
| -    code = krb5_tkt_creds_get_creds(context, ctx, ncreds);
 | ||||
| -    if (code != 0)
 | ||||
| +    if (in_creds->server->type != KRB5_NT_SRV_HST ||
 | ||||
| +        in_creds->server->length != 2)
 | ||||
|          goto cleanup; | ||||
|   | ||||
| +    hostname = k5memdup0(in_creds->server->data[1].data,
 | ||||
| +                         in_creds->server->data[1].length, &code);
 | ||||
| +    if (hostname == NULL)
 | ||||
| +        goto cleanup;
 | ||||
| +    code = k5_expand_hostname(context, hostname, TRUE, &canon_hostname);
 | ||||
| +    if (code)
 | ||||
| +        goto cleanup;
 | ||||
| +
 | ||||
| +    TRACE_GET_CREDS_FALLBACK(context, canon_hostname);
 | ||||
| +
 | ||||
| +    /* Make shallow copies of in_creds and its server to alter the hostname. */
 | ||||
| +    canon_components[0] = in_creds->server->data[0];
 | ||||
| +    canon_components[1] = string2data(canon_hostname);
 | ||||
| +    canon_server = *in_creds->server;
 | ||||
| +    canon_server.data = canon_components;
 | ||||
| +    canon_creds = *in_creds;
 | ||||
| +    canon_creds.server = &canon_server;
 | ||||
| +
 | ||||
| +    code = try_get_creds(context, options | KRB5_GC_NO_STORE, ccache,
 | ||||
| +                         &canon_creds, ncreds);
 | ||||
| +    if (code)
 | ||||
| +        goto cleanup;
 | ||||
| +
 | ||||
| +    if (!(options & KRB5_GC_NO_STORE)) {
 | ||||
| +        /* Store the creds under the originally requested server name.  The
 | ||||
| +         * ccache layer will also store them under the ticket server name. */
 | ||||
| +        store_creds = *ncreds;
 | ||||
| +        store_creds.server = in_creds->server;
 | ||||
| +        (void)krb5_cc_store_cred(context, ccache, &store_creds);
 | ||||
| +    }
 | ||||
| +
 | ||||
|      *out_creds = ncreds; | ||||
|      ncreds = NULL; | ||||
|   | ||||
|  cleanup: | ||||
| +    free(hostname);
 | ||||
| +    free(canon_hostname);
 | ||||
|      krb5_free_creds(context, ncreds); | ||||
| -    krb5_tkt_creds_free(context, ctx);
 | ||||
|      return code; | ||||
|  } | ||||
| diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
 | ||||
| index 947e50400..d263d5cc5 100644
 | ||||
| --- a/src/lib/krb5/krb/init_ctx.c
 | ||||
| +++ b/src/lib/krb5/krb/init_ctx.c
 | ||||
| @@ -101,6 +101,30 @@ get_boolean(krb5_context ctx, const char *name, int def_val, int *boolean_out)
 | ||||
|      return retval; | ||||
|  } | ||||
|   | ||||
| +static krb5_error_code
 | ||||
| +get_tristate(krb5_context ctx, const char *name, const char *third_option,
 | ||||
| +             int third_option_val, int def_val, int *val_out)
 | ||||
| +{
 | ||||
| +    krb5_error_code retval;
 | ||||
| +    char *str;
 | ||||
| +    int match;
 | ||||
| +
 | ||||
| +    retval = profile_get_boolean(ctx->profile, KRB5_CONF_LIBDEFAULTS, name,
 | ||||
| +                                 NULL, def_val, val_out);
 | ||||
| +    if (retval != PROF_BAD_BOOLEAN)
 | ||||
| +        return retval;
 | ||||
| +    retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS, name,
 | ||||
| +                                NULL, NULL, &str);
 | ||||
| +    if (retval)
 | ||||
| +        return retval;
 | ||||
| +    match = (strcasecmp(third_option, str) == 0);
 | ||||
| +    free(str);
 | ||||
| +    if (!match)
 | ||||
| +        return EINVAL;
 | ||||
| +    *val_out = third_option_val;
 | ||||
| +    return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  krb5_error_code KRB5_CALLCONV | ||||
|  krb5_init_context(krb5_context *context) | ||||
|  { | ||||
| @@ -213,7 +237,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
 | ||||
|          goto cleanup; | ||||
|      ctx->ignore_acceptor_hostname = tmp; | ||||
|   | ||||
| -    retval = get_boolean(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, 1, &tmp);
 | ||||
| +    retval = get_tristate(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, "fallback",
 | ||||
| +                          CANONHOST_FALLBACK, 1, &tmp);
 | ||||
|      if (retval) | ||||
|          goto cleanup; | ||||
|      ctx->dns_canonicalize_hostname = tmp; | ||||
| diff --git a/src/lib/krb5/krb/t_copy_context.c b/src/lib/krb5/krb/t_copy_context.c
 | ||||
| index fa810be8a..a6e48cd25 100644
 | ||||
| --- a/src/lib/krb5/krb/t_copy_context.c
 | ||||
| +++ b/src/lib/krb5/krb/t_copy_context.c
 | ||||
| @@ -145,7 +145,7 @@ main(int argc, char **argv)
 | ||||
|      ctx->udp_pref_limit = 2345; | ||||
|      ctx->use_conf_ktypes = TRUE; | ||||
|      ctx->ignore_acceptor_hostname = TRUE; | ||||
| -    ctx->dns_canonicalize_hostname = FALSE;
 | ||||
| +    ctx->dns_canonicalize_hostname = CANONHOST_FALSE;
 | ||||
|      free(ctx->plugin_base_dir); | ||||
|      check((ctx->plugin_base_dir = strdup("/a/b/c/d")) != NULL); | ||||
|   | ||||
| diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
 | ||||
| index 634e82d70..066d30221 100644
 | ||||
| --- a/src/lib/krb5/os/os-proto.h
 | ||||
| +++ b/src/lib/krb5/os/os-proto.h
 | ||||
| @@ -83,6 +83,10 @@ struct sendto_callback_info {
 | ||||
|      void *data; | ||||
|  }; | ||||
|   | ||||
| +krb5_error_code k5_expand_hostname(krb5_context context, const char *host,
 | ||||
| +                                   krb5_boolean is_fallback,
 | ||||
| +                                   char **canonhost_out);
 | ||||
| +
 | ||||
|  krb5_error_code k5_locate_server(krb5_context, const krb5_data *realm, | ||||
|                                   struct serverlist *serverlist, | ||||
|                                   enum locate_service_type svc, | ||||
| diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c
 | ||||
| index 5932fd9b3..98d2600aa 100644
 | ||||
| --- a/src/lib/krb5/os/sn2princ.c
 | ||||
| +++ b/src/lib/krb5/os/sn2princ.c
 | ||||
| @@ -53,19 +53,23 @@ use_reverse_dns(krb5_context context)
 | ||||
|      return value; | ||||
|  } | ||||
|   | ||||
| -krb5_error_code KRB5_CALLCONV
 | ||||
| -krb5_expand_hostname(krb5_context context, const char *host,
 | ||||
| -                     char **canonhost_out)
 | ||||
| +krb5_error_code
 | ||||
| +k5_expand_hostname(krb5_context context, const char *host,
 | ||||
| +                   krb5_boolean is_fallback, char **canonhost_out)
 | ||||
|  { | ||||
|      struct addrinfo *ai = NULL, hint; | ||||
|      char namebuf[NI_MAXHOST], *copy, *p; | ||||
|      int err; | ||||
|      const char *canonhost; | ||||
| +    krb5_boolean use_dns;
 | ||||
|   | ||||
|      *canonhost_out = NULL; | ||||
|   | ||||
|      canonhost = host; | ||||
| -    if (context->dns_canonicalize_hostname) {
 | ||||
| +    use_dns = (context->dns_canonicalize_hostname == CANONHOST_TRUE ||
 | ||||
| +               (is_fallback &&
 | ||||
| +                context->dns_canonicalize_hostname == CANONHOST_FALLBACK));
 | ||||
| +    if (use_dns) {
 | ||||
|          /* Try a forward lookup of the hostname. */ | ||||
|          memset(&hint, 0, sizeof(hint)); | ||||
|          hint.ai_flags = AI_CANONNAME; | ||||
| @@ -112,6 +116,13 @@ cleanup:
 | ||||
|      return (*canonhost_out == NULL) ? ENOMEM : 0; | ||||
|  } | ||||
|   | ||||
| +krb5_error_code KRB5_CALLCONV
 | ||||
| +krb5_expand_hostname(krb5_context context, const char *host,
 | ||||
| +                     char **canonhost_out)
 | ||||
| +{
 | ||||
| +    return k5_expand_hostname(context, host, FALSE, canonhost_out);
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* If hostname appears to have a :port or :instance trailer (used in MSSQLSvc | ||||
|   * principals), return a pointer to the separator.  Otherwise return NULL. */ | ||||
|  static const char * | ||||
| diff --git a/src/tests/gcred.c b/src/tests/gcred.c
 | ||||
| index b14e4fc9a..cac524c51 100644
 | ||||
| --- a/src/tests/gcred.c
 | ||||
| +++ b/src/tests/gcred.c
 | ||||
| @@ -66,6 +66,7 @@ main(int argc, char **argv)
 | ||||
|      krb5_principal client, server; | ||||
|      krb5_ccache ccache; | ||||
|      krb5_creds in_creds, *creds; | ||||
| +    krb5_ticket *ticket;
 | ||||
|      krb5_flags options = 0; | ||||
|      char *name; | ||||
|      int c; | ||||
| @@ -102,9 +103,11 @@ main(int argc, char **argv)
 | ||||
|      in_creds.client = client; | ||||
|      in_creds.server = server; | ||||
|      check(krb5_get_credentials(ctx, options, ccache, &in_creds, &creds)); | ||||
| -    check(krb5_unparse_name(ctx, creds->server, &name));
 | ||||
| +    check(krb5_decode_ticket(&creds->ticket, &ticket));
 | ||||
| +    check(krb5_unparse_name(ctx, ticket->server, &name));
 | ||||
|      printf("%s\n", name); | ||||
|   | ||||
| +    krb5_free_ticket(ctx, ticket);
 | ||||
|      krb5_free_unparsed_name(ctx, name); | ||||
|      krb5_free_creds(ctx, creds); | ||||
|      krb5_free_principal(ctx, client); | ||||
| diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py
 | ||||
| index 1ffda51f4..fe435a2d5 100755
 | ||||
| --- a/src/tests/t_sn2princ.py
 | ||||
| +++ b/src/tests/t_sn2princ.py
 | ||||
| @@ -7,10 +7,15 @@ conf = {'domain_realm': {'kerberos.org': 'R1',
 | ||||
|                           'mit.edu': 'R3'}} | ||||
|  no_rdns_conf = {'libdefaults': {'rdns': 'false'}} | ||||
|  no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}} | ||||
| +fallback_canon_conf = {'libdefaults':
 | ||||
| +                       {'rdns': 'false',
 | ||||
| +                        'dns_canonicalize_hostname': 'fallback'}}
 | ||||
|   | ||||
| -realm = K5Realm(create_kdb=False, krb5_conf=conf)
 | ||||
| +realm = K5Realm(realm='R1', create_host=False, krb5_conf=conf)
 | ||||
|  no_rdns = realm.special_env('no_rdns', False, krb5_conf=no_rdns_conf) | ||||
|  no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf) | ||||
| +fallback_canon = realm.special_env('fallback_canon', False,
 | ||||
| +                                   krb5_conf=fallback_canon_conf)
 | ||||
|   | ||||
|  def testbase(host, nametype, princhost, princrealm, env=None): | ||||
|      # Run the sn2princ harness with a specified host and name type and | ||||
| @@ -37,6 +42,10 @@ def testu(host, princhost, princrealm):
 | ||||
|      # Test with the unknown name type. | ||||
|      testbase(host, 'unknown', princhost, princrealm) | ||||
|   | ||||
| +def testfc(host, princhost, princrealm):
 | ||||
| +    # Test with the host-based name type with canonicalization fallback.
 | ||||
| +    testbase(host, 'srv-hst', princhost, princrealm, env=fallback_canon)
 | ||||
| +
 | ||||
|  # With the unknown principal type, we do not canonicalize or downcase, | ||||
|  # but we do remove a trailing period and look up the realm. | ||||
|  mark('unknown type') | ||||
| @@ -71,6 +80,29 @@ if offline:
 | ||||
|  oname = 'ptr-mismatch.kerberos.org' | ||||
|  fname = 'www.kerberos.org' | ||||
|   | ||||
| +# Test fallback canonicalization krb5_sname_to_principal() results
 | ||||
| +# (same as dns_canonicalize_hostname=false).
 | ||||
| +mark('dns_canonicalize_host=fallback')
 | ||||
| +testfc(oname, oname, 'R1')
 | ||||
| +
 | ||||
| +# Test fallback canonicalization in krb5_get_credentials().
 | ||||
| +oprinc = 'host/' + oname
 | ||||
| +fprinc = 'host/' + fname
 | ||||
| +shutil.copy(realm.ccache, realm.ccache + '.save')
 | ||||
| +realm.addprinc(fprinc)
 | ||||
| +# oprinc doesn't exist, so we get the canonicalized fprinc as a fallback.
 | ||||
| +msgs = ('Falling back to canonicalized server hostname ' + fname,)
 | ||||
| +realm.run(['./gcred', 'srv-hst', oprinc], env=fallback_canon,
 | ||||
| +          expected_msg=fprinc, expected_trace=msgs)
 | ||||
| +realm.addprinc(oprinc)
 | ||||
| +# oprinc now exists, but we still get the fprinc ticket from the cache.
 | ||||
| +realm.run(['./gcred', 'srv-hst', oprinc], env=fallback_canon,
 | ||||
| +          expected_msg=fprinc)
 | ||||
| +# Without the cached result, we sould get oprinc in preference to fprinc.
 | ||||
| +os.rename(realm.ccache + '.save', realm.ccache)
 | ||||
| +realm.run(['./gcred', 'srv-hst', oprinc], env=fallback_canon,
 | ||||
| +          expected_msg=oprinc)
 | ||||
| +
 | ||||
|  # Verify forward resolution before testing for it. | ||||
|  try: | ||||
|      ai = socket.getaddrinfo(oname, None, 0, 0, 0, socket.AI_CANONNAME) | ||||
							
								
								
									
										484
									
								
								Clear-forwardable-flag-instead-of-denying-request.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								Clear-forwardable-flag-instead-of-denying-request.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,484 @@ | ||||
| From 297ad5039231e655eaae7c142991326fd863e70a Mon Sep 17 00:00:00 2001 | ||||
| From: Greg Hudson <ghudson@mit.edu> | ||||
| Date: Thu, 15 Nov 2018 13:40:43 -0500 | ||||
| Subject: [PATCH] Clear forwardable flag instead of denying request | ||||
| 
 | ||||
| If the client requests a forwardable or proxiable ticket and the | ||||
| option cannot be honored by policy, issue a non-forwardable or | ||||
| non-proxiable ticket rather than denying the request. | ||||
| 
 | ||||
| Add a test script for testing KDC request options and populate it with | ||||
| tests for the forwardable and proxiable flags. | ||||
| 
 | ||||
| ticket: 7871 | ||||
| (cherry picked from commit 08e948cce2c79a3604066fcf7a64fc527456f83d) | ||||
| ---
 | ||||
|  src/kdc/do_as_req.c       |  19 ++------ | ||||
|  src/kdc/do_tgs_req.c      |  56 ++++----------------- | ||||
|  src/kdc/kdc_util.c        |  82 ++++++++++++++++++------------- | ||||
|  src/kdc/kdc_util.h        |   9 ++-- | ||||
|  src/kdc/tgs_policy.c      |   8 +-- | ||||
|  src/tests/Makefile.in     |   1 + | ||||
|  src/tests/gcred.c         |  28 ++++++++--- | ||||
|  src/tests/t_kdcoptions.py | 100 ++++++++++++++++++++++++++++++++++++++ | ||||
|  8 files changed, 189 insertions(+), 114 deletions(-) | ||||
|  create mode 100644 src/tests/t_kdcoptions.py | ||||
| 
 | ||||
| diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
 | ||||
| index 588c1375a..8a96c12a9 100644
 | ||||
| --- a/src/kdc/do_as_req.c
 | ||||
| +++ b/src/kdc/do_as_req.c
 | ||||
| @@ -192,13 +192,6 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
 | ||||
|   | ||||
|      au_state->stage = ENCR_REP; | ||||
|   | ||||
| -    if ((errcode = validate_forwardable(state->request, *state->client,
 | ||||
| -                                        *state->server, state->kdc_time,
 | ||||
| -                                        &state->status))) {
 | ||||
| -        errcode += ERROR_TABLE_BASE_krb5;
 | ||||
| -        goto egress;
 | ||||
| -    }
 | ||||
| -
 | ||||
|      errcode = check_indicators(kdc_context, state->server, | ||||
|                                 state->auth_indicators); | ||||
|      if (errcode) { | ||||
| @@ -708,12 +701,11 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 | ||||
|      } | ||||
|   | ||||
|      /* Copy options that request the corresponding ticket flags. */ | ||||
| -    state->enc_tkt_reply.flags = OPTS2FLAGS(state->request->kdc_options);
 | ||||
| +    state->enc_tkt_reply.flags = get_ticket_flags(state->request->kdc_options,
 | ||||
| +                                                  state->client, state->server,
 | ||||
| +                                                  NULL);
 | ||||
|      state->enc_tkt_reply.times.authtime = state->authtime; | ||||
|   | ||||
| -    setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
 | ||||
| -    setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
 | ||||
| -
 | ||||
|      /* | ||||
|       * It should be noted that local policy may affect the | ||||
|       * processing of any of these flags.  For example, some | ||||
| @@ -732,10 +724,9 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 | ||||
|      state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; | ||||
|      state->enc_tkt_reply.transited.tr_contents = empty_string; | ||||
|   | ||||
| -    if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
 | ||||
| -        setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
 | ||||
| +    if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED))
 | ||||
|          state->enc_tkt_reply.times.starttime = state->request->from; | ||||
| -    } else
 | ||||
| +    else
 | ||||
|          state->enc_tkt_reply.times.starttime = state->kdc_time; | ||||
|   | ||||
|      kdc_get_ticket_endtime(kdc_active_realm, | ||||
| diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
 | ||||
| index 587342a6c..1da099318 100644
 | ||||
| --- a/src/kdc/do_tgs_req.c
 | ||||
| +++ b/src/kdc/do_tgs_req.c
 | ||||
| @@ -378,15 +378,16 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
 | ||||
|      else | ||||
|          ticket_reply.server = request->server; /* XXX careful for realm... */ | ||||
|   | ||||
| -    enc_tkt_reply.flags = OPTS2FLAGS(request->kdc_options);
 | ||||
| -    enc_tkt_reply.flags |= COPY_TKT_FLAGS(header_enc_tkt->flags);
 | ||||
| +    enc_tkt_reply.flags = get_ticket_flags(request->kdc_options, client,
 | ||||
| +                                           server, header_enc_tkt);
 | ||||
|      enc_tkt_reply.times.starttime = 0; | ||||
|   | ||||
| -    if (isflagset(server->attributes, KRB5_KDB_OK_AS_DELEGATE))
 | ||||
| -        setflag(enc_tkt_reply.flags, TKT_FLG_OK_AS_DELEGATE);
 | ||||
| -
 | ||||
| -    /* Indicate support for encrypted padata (RFC 6806). */
 | ||||
| -    setflag(enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
 | ||||
| +    /* OK_TO_AUTH_AS_DELEGATE must be set on the service requesting S4U2Self
 | ||||
| +     * for forwardable tickets to be issued. */
 | ||||
| +    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
 | ||||
| +        !is_referral &&
 | ||||
| +        !isflagset(server->attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
 | ||||
| +        clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 | ||||
|   | ||||
|      /* don't use new addresses unless forwarded, see below */ | ||||
|   | ||||
| @@ -401,37 +402,6 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
 | ||||
|       * realms may refuse to issue renewable tickets | ||||
|       */ | ||||
|   | ||||
| -    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) {
 | ||||
| -
 | ||||
| -        if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
 | ||||
| -            /*
 | ||||
| -             * If S4U2Self principal is not forwardable, then mark ticket as
 | ||||
| -             * unforwardable. This behaviour matches Windows, but it is
 | ||||
| -             * different to the MIT AS-REQ path, which returns an error
 | ||||
| -             * (KDC_ERR_POLICY) if forwardable tickets cannot be issued.
 | ||||
| -             *
 | ||||
| -             * Consider this block the S4U2Self equivalent to
 | ||||
| -             * validate_forwardable().
 | ||||
| -             */
 | ||||
| -            if (client != NULL &&
 | ||||
| -                isflagset(client->attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
 | ||||
| -                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 | ||||
| -            /*
 | ||||
| -             * Forwardable flag is propagated along referral path.
 | ||||
| -             */
 | ||||
| -            else if (!isflagset(header_enc_tkt->flags, TKT_FLG_FORWARDABLE))
 | ||||
| -                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 | ||||
| -            /*
 | ||||
| -             * OK_TO_AUTH_AS_DELEGATE must be set on the service requesting
 | ||||
| -             * S4U2Self in order for forwardable tickets to be returned.
 | ||||
| -             */
 | ||||
| -            else if (!is_referral &&
 | ||||
| -                     !isflagset(server->attributes,
 | ||||
| -                                KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
 | ||||
| -                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 | ||||
| -        }
 | ||||
| -    }
 | ||||
| -
 | ||||
|      if (isflagset(request->kdc_options, KDC_OPT_FORWARDED) || | ||||
|          isflagset(request->kdc_options, KDC_OPT_PROXY)) { | ||||
|   | ||||
| @@ -440,16 +410,10 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
 | ||||
|          enc_tkt_reply.caddrs = request->addresses; | ||||
|          reply_encpart.caddrs = request->addresses; | ||||
|      } | ||||
| -    /* We don't currently handle issuing anonymous tickets based on
 | ||||
| -     * non-anonymous ones, so just ignore the option. */
 | ||||
| -    if (isflagset(request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS) &&
 | ||||
| -        !isflagset(header_enc_tkt->flags, TKT_FLG_ANONYMOUS))
 | ||||
| -        clear(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
 | ||||
|   | ||||
| -    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
 | ||||
| -        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
 | ||||
| +    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED))
 | ||||
|          enc_tkt_reply.times.starttime = request->from; | ||||
| -    } else
 | ||||
| +    else
 | ||||
|          enc_tkt_reply.times.starttime = kdc_time; | ||||
|   | ||||
|      if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) { | ||||
| diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
 | ||||
| index 96c88edc1..f2741090e 100644
 | ||||
| --- a/src/kdc/kdc_util.c
 | ||||
| +++ b/src/kdc/kdc_util.c
 | ||||
| @@ -697,29 +697,6 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
 | ||||
|          return(KDC_ERR_CANNOT_POSTDATE); | ||||
|      } | ||||
|   | ||||
| -    /*
 | ||||
| -     * A Windows KDC will return KDC_ERR_PREAUTH_REQUIRED instead of
 | ||||
| -     * KDC_ERR_POLICY in the following case:
 | ||||
| -     *
 | ||||
| -     *   - KDC_OPT_FORWARDABLE is set in KDCOptions but local
 | ||||
| -     *     policy has KRB5_KDB_DISALLOW_FORWARDABLE set for the
 | ||||
| -     *     client, and;
 | ||||
| -     *   - KRB5_KDB_REQUIRES_PRE_AUTH is set for the client but
 | ||||
| -     *     preauthentication data is absent in the request.
 | ||||
| -     *
 | ||||
| -     * Hence, this check most be done after the check for preauth
 | ||||
| -     * data, and is now performed by validate_forwardable() (the
 | ||||
| -     * contents of which were previously below).
 | ||||
| -     */
 | ||||
| -
 | ||||
| -    /* Client and server must allow proxiable tickets */
 | ||||
| -    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE) &&
 | ||||
| -        (isflagset(client.attributes, KRB5_KDB_DISALLOW_PROXIABLE) ||
 | ||||
| -         isflagset(server.attributes, KRB5_KDB_DISALLOW_PROXIABLE))) {
 | ||||
| -        *status = "PROXIABLE NOT ALLOWED";
 | ||||
| -        return(KDC_ERR_POLICY);
 | ||||
| -    }
 | ||||
| -
 | ||||
|      /* Check to see if client is locked out */ | ||||
|      if (isflagset(client.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { | ||||
|          *status = "CLIENT LOCKED OUT"; | ||||
| @@ -752,19 +729,54 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
 | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
| -int
 | ||||
| -validate_forwardable(krb5_kdc_req *request, krb5_db_entry client,
 | ||||
| -                     krb5_db_entry server, krb5_timestamp kdc_time,
 | ||||
| -                     const char **status)
 | ||||
| +/*
 | ||||
| + * Compute ticket flags based on the request, the client and server DB entry
 | ||||
| + * (which may prohibit forwardable or proxiable tickets), and the header
 | ||||
| + * ticket.  client may be NULL for a TGS request (although it may be set, such
 | ||||
| + * as for an S4U2Self request).  header_enc may be NULL for an AS request.
 | ||||
| + */
 | ||||
| +krb5_flags
 | ||||
| +get_ticket_flags(krb5_flags reqflags, krb5_db_entry *client,
 | ||||
| +                 krb5_db_entry *server, krb5_enc_tkt_part *header_enc)
 | ||||
|  { | ||||
| -    *status = NULL;
 | ||||
| -    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) &&
 | ||||
| -        (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE) ||
 | ||||
| -         isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))) {
 | ||||
| -        *status = "FORWARDABLE NOT ALLOWED";
 | ||||
| -        return(KDC_ERR_POLICY);
 | ||||
| -    } else
 | ||||
| -        return 0;
 | ||||
| +    krb5_flags flags;
 | ||||
| +
 | ||||
| +    /* Indicate support for encrypted padata (RFC 6806), and set flags based on
 | ||||
| +     * request options and the header ticket. */
 | ||||
| +    flags = OPTS2FLAGS(reqflags) | TKT_FLG_ENC_PA_REP;
 | ||||
| +    if (reqflags & KDC_OPT_POSTDATED)
 | ||||
| +        flags |= TKT_FLG_INVALID;
 | ||||
| +    if (header_enc != NULL)
 | ||||
| +        flags |= COPY_TKT_FLAGS(header_enc->flags);
 | ||||
| +    if (header_enc == NULL)
 | ||||
| +        flags |= TKT_FLG_INITIAL;
 | ||||
| +
 | ||||
| +    /* For TGS requests, indicate if the service is marked ok-as-delegate. */
 | ||||
| +    if (header_enc != NULL && (server->attributes & KRB5_KDB_OK_AS_DELEGATE))
 | ||||
| +        flags |= TKT_FLG_OK_AS_DELEGATE;
 | ||||
| +
 | ||||
| +    /* Unset PROXIABLE if it is disallowed. */
 | ||||
| +    if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_PROXIABLE))
 | ||||
| +        flags &= ~TKT_FLG_PROXIABLE;
 | ||||
| +    if (server->attributes & KRB5_KDB_DISALLOW_PROXIABLE)
 | ||||
| +        flags &= ~TKT_FLG_PROXIABLE;
 | ||||
| +    if (header_enc != NULL && !(header_enc->flags & TKT_FLG_PROXIABLE))
 | ||||
| +        flags &= ~TKT_FLG_PROXIABLE;
 | ||||
| +
 | ||||
| +    /* Unset FORWARDABLE if it is disallowed. */
 | ||||
| +    if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_FORWARDABLE))
 | ||||
| +        flags &= ~TKT_FLG_FORWARDABLE;
 | ||||
| +    if (server->attributes & KRB5_KDB_DISALLOW_FORWARDABLE)
 | ||||
| +        flags &= ~TKT_FLG_FORWARDABLE;
 | ||||
| +    if (header_enc != NULL && !(header_enc->flags & TKT_FLG_FORWARDABLE))
 | ||||
| +        flags &= ~TKT_FLG_FORWARDABLE;
 | ||||
| +
 | ||||
| +    /* We don't currently handle issuing anonymous tickets based on
 | ||||
| +     * non-anonymous ones. */
 | ||||
| +    if (header_enc != NULL && !(header_enc->flags & TKT_FLG_ANONYMOUS))
 | ||||
| +        flags &= ~TKT_FLG_ANONYMOUS;
 | ||||
| +
 | ||||
| +    return flags;
 | ||||
|  } | ||||
|   | ||||
|  /* Return KRB5KDC_ERR_POLICY if indicators does not contain the required auth | ||||
| diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
 | ||||
| index 25077cbf5..1314bdd58 100644
 | ||||
| --- a/src/kdc/kdc_util.h
 | ||||
| +++ b/src/kdc/kdc_util.h
 | ||||
| @@ -85,16 +85,15 @@ validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry,
 | ||||
|                       krb5_db_entry, krb5_timestamp, | ||||
|                       const char **, krb5_pa_data ***); | ||||
|   | ||||
| -int
 | ||||
| -validate_forwardable(krb5_kdc_req *, krb5_db_entry,
 | ||||
| -                     krb5_db_entry, krb5_timestamp,
 | ||||
| -                     const char **);
 | ||||
| -
 | ||||
|  int | ||||
|  validate_tgs_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry, | ||||
|                        krb5_ticket *, krb5_timestamp, | ||||
|                        const char **, krb5_pa_data ***); | ||||
|   | ||||
| +krb5_flags
 | ||||
| +get_ticket_flags(krb5_flags reqflags, krb5_db_entry *client,
 | ||||
| +                 krb5_db_entry *server, krb5_enc_tkt_part *header_enc);
 | ||||
| +
 | ||||
|  krb5_error_code | ||||
|  check_indicators(krb5_context context, krb5_db_entry *server, | ||||
|                   krb5_data *const *indicators); | ||||
| diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
 | ||||
| index 907fcd330..554345ba5 100644
 | ||||
| --- a/src/kdc/tgs_policy.c
 | ||||
| +++ b/src/kdc/tgs_policy.c
 | ||||
| @@ -63,9 +63,9 @@ static check_tgs_svc_pol_fn * const svc_pol_fns[] = {
 | ||||
|  }; | ||||
|   | ||||
|  static const struct tgsflagrule tgsflagrules[] = { | ||||
| -    { (KDC_OPT_FORWARDED | KDC_OPT_FORWARDABLE), TKT_FLG_FORWARDABLE,
 | ||||
| +    { KDC_OPT_FORWARDED, TKT_FLG_FORWARDABLE,
 | ||||
|        "TGT NOT FORWARDABLE", KDC_ERR_BADOPTION }, | ||||
| -    { (KDC_OPT_PROXY | KDC_OPT_PROXIABLE), TKT_FLG_PROXIABLE,
 | ||||
| +    { KDC_OPT_PROXY, TKT_FLG_PROXIABLE,
 | ||||
|        "TGT NOT PROXIABLE", KDC_ERR_BADOPTION }, | ||||
|      { (KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED), TKT_FLG_MAY_POSTDATE, | ||||
|        "TGT NOT POSTDATABLE", KDC_ERR_BADOPTION }, | ||||
| @@ -98,12 +98,8 @@ check_tgs_opts(krb5_kdc_req *req, krb5_ticket *tkt, const char **status)
 | ||||
|  } | ||||
|   | ||||
|  static const struct tgsflagrule svcdenyrules[] = { | ||||
| -    { KDC_OPT_FORWARDABLE, KRB5_KDB_DISALLOW_FORWARDABLE,
 | ||||
| -      "NON-FORWARDABLE TICKET", KDC_ERR_POLICY },
 | ||||
|      { KDC_OPT_RENEWABLE, KRB5_KDB_DISALLOW_RENEWABLE, | ||||
|        "NON-RENEWABLE TICKET", KDC_ERR_POLICY }, | ||||
| -    { KDC_OPT_PROXIABLE, KRB5_KDB_DISALLOW_PROXIABLE,
 | ||||
| -      "NON-PROXIABLE TICKET", KDC_ERR_POLICY },
 | ||||
|      { KDC_OPT_ALLOW_POSTDATE, KRB5_KDB_DISALLOW_POSTDATED, | ||||
|        "NON-POSTDATABLE TICKET", KDC_ERR_CANNOT_POSTDATE }, | ||||
|      { KDC_OPT_ENC_TKT_IN_SKEY, KRB5_KDB_DISALLOW_DUP_SKEY, | ||||
| diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
 | ||||
| index c96c5d6b7..d2a37c616 100644
 | ||||
| --- a/src/tests/Makefile.in
 | ||||
| +++ b/src/tests/Makefile.in
 | ||||
| @@ -171,6 +171,7 @@ check-pytests: unlockiter
 | ||||
|  	$(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS) | ||||
|  	$(RUNPYTEST) $(srcdir)/t_kdcpolicy.py $(PYTESTFLAGS) | ||||
|  	$(RUNPYTEST) $(srcdir)/t_u2u.py $(PYTESTFLAGS) | ||||
| +	$(RUNPYTEST) $(srcdir)/t_kdcoptions.py $(PYTESTFLAGS)
 | ||||
|   | ||||
|  clean: | ||||
|  	$(RM) adata etinfo forward gcred hist hooks hrealm icinterleave icred | ||||
| diff --git a/src/tests/gcred.c b/src/tests/gcred.c
 | ||||
| index cb0ae6af5..b14e4fc9a 100644
 | ||||
| --- a/src/tests/gcred.c
 | ||||
| +++ b/src/tests/gcred.c
 | ||||
| @@ -66,20 +66,32 @@ main(int argc, char **argv)
 | ||||
|      krb5_principal client, server; | ||||
|      krb5_ccache ccache; | ||||
|      krb5_creds in_creds, *creds; | ||||
| +    krb5_flags options = 0;
 | ||||
|      char *name; | ||||
| +    int c;
 | ||||
|   | ||||
|      check(krb5_init_context(&ctx)); | ||||
|   | ||||
| -    /* Parse arguments. */
 | ||||
| -    assert(argc == 3);
 | ||||
| -    check(krb5_parse_name(ctx, argv[2], &server));
 | ||||
| -    if (strcmp(argv[1], "unknown") == 0)
 | ||||
| +    while ((c = getopt(argc, argv, "f")) != -1) {
 | ||||
| +        switch (c) {
 | ||||
| +        case 'f':
 | ||||
| +            options |= KRB5_GC_FORWARDABLE;
 | ||||
| +            break;
 | ||||
| +        default:
 | ||||
| +            abort();
 | ||||
| +        }
 | ||||
| +    }
 | ||||
| +    argc -= optind;
 | ||||
| +    argv += optind;
 | ||||
| +    assert(argc == 2);
 | ||||
| +    check(krb5_parse_name(ctx, argv[1], &server));
 | ||||
| +    if (strcmp(argv[0], "unknown") == 0)
 | ||||
|          server->type = KRB5_NT_UNKNOWN; | ||||
| -    else if (strcmp(argv[1], "principal") == 0)
 | ||||
| +    else if (strcmp(argv[0], "principal") == 0)
 | ||||
|          server->type = KRB5_NT_PRINCIPAL; | ||||
| -    else if (strcmp(argv[1], "srv-inst") == 0)
 | ||||
| +    else if (strcmp(argv[0], "srv-inst") == 0)
 | ||||
|          server->type = KRB5_NT_SRV_INST; | ||||
| -    else if (strcmp(argv[1], "srv-hst") == 0)
 | ||||
| +    else if (strcmp(argv[0], "srv-hst") == 0)
 | ||||
|          server->type = KRB5_NT_SRV_HST; | ||||
|      else | ||||
|          abort(); | ||||
| @@ -89,7 +101,7 @@ main(int argc, char **argv)
 | ||||
|      memset(&in_creds, 0, sizeof(in_creds)); | ||||
|      in_creds.client = client; | ||||
|      in_creds.server = server; | ||||
| -    check(krb5_get_credentials(ctx, 0, ccache, &in_creds, &creds));
 | ||||
| +    check(krb5_get_credentials(ctx, options, ccache, &in_creds, &creds));
 | ||||
|      check(krb5_unparse_name(ctx, creds->server, &name)); | ||||
|      printf("%s\n", name); | ||||
|   | ||||
| diff --git a/src/tests/t_kdcoptions.py b/src/tests/t_kdcoptions.py
 | ||||
| new file mode 100644 | ||||
| index 000000000..7ec57508c
 | ||||
| --- /dev/null
 | ||||
| +++ b/src/tests/t_kdcoptions.py
 | ||||
| @@ -0,0 +1,100 @@
 | ||||
| +from k5test import *
 | ||||
| +import re
 | ||||
| +
 | ||||
| +# KDC option test coverage notes:
 | ||||
| +#
 | ||||
| +# FORWARDABLE              here
 | ||||
| +# FORWARDED                no test
 | ||||
| +# PROXIABLE                here
 | ||||
| +# PROXY                    no test
 | ||||
| +# ALLOW_POSTDATE           no test
 | ||||
| +# POSTDATED                no test
 | ||||
| +# RENEWABLE                t_renew.py
 | ||||
| +# CNAME_IN_ADDL_TKT        gssapi/t_s4u.py
 | ||||
| +# CANONICALIZE             t_kdb.py and various other tests
 | ||||
| +# REQUEST_ANONYMOUS        t_pkinit.py
 | ||||
| +# DISABLE_TRANSITED_CHECK  no test
 | ||||
| +# RENEWABLE_OK             t_renew.py
 | ||||
| +# ENC_TKT_IN_SKEY          t_u2u.py
 | ||||
| +# RENEW                    t_renew.py
 | ||||
| +# VALIDATE                 no test
 | ||||
| +
 | ||||
| +# Run klist -f and return the flags on the ticket for svcprinc.
 | ||||
| +def get_flags(realm, svcprinc):
 | ||||
| +    grab_flags = False
 | ||||
| +    for line in realm.run([klist, '-f']).splitlines():
 | ||||
| +        if grab_flags:
 | ||||
| +            return re.findall(r'Flags: ([a-zA-Z]*)', line)[0]
 | ||||
| +        grab_flags = line.endswith(svcprinc)
 | ||||
| +
 | ||||
| +
 | ||||
| +# Get the flags on the ticket for svcprinc, and check for an expected
 | ||||
| +# element and an expected-absent element, either of which can be None.
 | ||||
| +def check_flags(realm, svcprinc, expected_flag, expected_noflag):
 | ||||
| +    flags = get_flags(realm, svcprinc)
 | ||||
| +    if expected_flag is not None and not expected_flag in flags:
 | ||||
| +        fail('expected flag ' + expected_flag)
 | ||||
| +    if expected_noflag is not None and expected_noflag in flags:
 | ||||
| +        fail('did not expect flag ' + expected_noflag)
 | ||||
| +
 | ||||
| +
 | ||||
| +# Run kinit with the given flags, and check the flags on the resulting
 | ||||
| +# TGT.
 | ||||
| +def kinit_check_flags(realm, flags, expected_flag, expected_noflag):
 | ||||
| +    realm.kinit(realm.user_princ, password('user'), flags)
 | ||||
| +    check_flags(realm, realm.krbtgt_princ, expected_flag, expected_noflag)
 | ||||
| +
 | ||||
| +
 | ||||
| +# Run kinit with kflags.  Then get credentials for the host principal
 | ||||
| +# with gflags, and check the flags on the resulting ticket.
 | ||||
| +def gcred_check_flags(realm, kflags, gflags, expected_flag, expected_noflag):
 | ||||
| +    realm.kinit(realm.user_princ, password('user'), kflags)
 | ||||
| +    realm.run(['./gcred'] + gflags + ['unknown', realm.host_princ])
 | ||||
| +    check_flags(realm, realm.host_princ, expected_flag, expected_noflag)
 | ||||
| +
 | ||||
| +
 | ||||
| +realm = K5Realm()
 | ||||
| +
 | ||||
| +mark('proxiable (AS)')
 | ||||
| +kinit_check_flags(realm, [], None, 'P')
 | ||||
| +kinit_check_flags(realm, ['-p'], 'P', None)
 | ||||
| +realm.run([kadminl, 'modprinc', '-allow_proxiable', realm.user_princ])
 | ||||
| +kinit_check_flags(realm, ['-p'], None, 'P')
 | ||||
| +realm.run([kadminl, 'modprinc', '+allow_proxiable', realm.user_princ])
 | ||||
| +realm.run([kadminl, 'modprinc', '-allow_proxiable', realm.krbtgt_princ])
 | ||||
| +kinit_check_flags(realm, ['-p'], None, 'P')
 | ||||
| +realm.run([kadminl, 'modprinc', '+allow_proxiable', realm.krbtgt_princ])
 | ||||
| +
 | ||||
| +mark('proxiable (TGS)')
 | ||||
| +gcred_check_flags(realm, [], [], None, 'P')
 | ||||
| +gcred_check_flags(realm, ['-p'], [], 'P', None)
 | ||||
| +
 | ||||
| +# Not tested: PROXIABLE option set with a non-proxiable TGT (because
 | ||||
| +# there is no krb5_get_credentials() flag to request this; would
 | ||||
| +# expect a non-proxiable ticket).
 | ||||
| +
 | ||||
| +# Not tested: proxiable TGT but PROXIABLE flag not set (because we
 | ||||
| +# internally set the PROXIABLE option when using a proxiable TGT;
 | ||||
| +# would expect a non-proxiable ticket).
 | ||||
| +
 | ||||
| +mark('forwardable (AS)')
 | ||||
| +kinit_check_flags(realm, [], None, 'F')
 | ||||
| +kinit_check_flags(realm, ['-f'], 'F', None)
 | ||||
| +realm.run([kadminl, 'modprinc', '-allow_forwardable', realm.user_princ])
 | ||||
| +kinit_check_flags(realm, ['-f'], None, 'F')
 | ||||
| +realm.run([kadminl, 'modprinc', '+allow_forwardable', realm.user_princ])
 | ||||
| +realm.run([kadminl, 'modprinc', '-allow_forwardable', realm.krbtgt_princ])
 | ||||
| +kinit_check_flags(realm, ['-f'], None, 'F')
 | ||||
| +realm.run([kadminl, 'modprinc', '+allow_forwardable', realm.krbtgt_princ])
 | ||||
| +
 | ||||
| +mark('forwardable (TGS)')
 | ||||
| +realm.kinit(realm.user_princ, password('user'))
 | ||||
| +gcred_check_flags(realm, [], [], None, 'F')
 | ||||
| +gcred_check_flags(realm, [], ['-f'], None, 'F')
 | ||||
| +gcred_check_flags(realm, ['-f'], [], 'F', None)
 | ||||
| +
 | ||||
| +# Not tested: forwardable TGT but FORWARDABLE flag not set (because we
 | ||||
| +# internally set the FORWARDABLE option when using a forwardable TGT;
 | ||||
| +# would expect a non-proxiable ticket).
 | ||||
| +
 | ||||
| +success('KDC option tests')
 | ||||
| @ -18,7 +18,7 @@ Summary: The Kerberos network authentication system | ||||
| Name: krb5 | ||||
| Version: 1.17 | ||||
| # for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces) | ||||
| Release: 13%{?dist} | ||||
| Release: 14%{?dist} | ||||
| 
 | ||||
| # lookaside-cached sources; two downloads and a build artifact | ||||
| Source0: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz | ||||
| @ -85,6 +85,8 @@ Patch112: Remove-confvalidator-utility.patch | ||||
| Patch113: Remove-ovsec_adm_export-dump-format-support.patch | ||||
| Patch114: Fix-potential-close-1-in-cc_file.c.patch | ||||
| Patch115: Check-more-errors-in-OpenSSL-crypto-backend.patch | ||||
| Patch116: Clear-forwardable-flag-instead-of-denying-request.patch | ||||
| Patch117: Add-dns_canonicalize_hostname-fallback-support.patch | ||||
| 
 | ||||
| License: MIT | ||||
| URL: http://web.mit.edu/kerberos/www/ | ||||
| @ -721,6 +723,9 @@ exit 0 | ||||
| %{_libdir}/libkadm5srv_mit.so.* | ||||
| 
 | ||||
| %changelog | ||||
| * Wed Apr 24 2019 Robbie Harwood <rharwood@redhat.com> - 1.17-14 | ||||
| - Add dns_canonicalize_hostname=fallback support | ||||
| 
 | ||||
| * Wed Apr 24 2019 Robbie Harwood <rharwood@redhat.com> - 1.17-13 | ||||
| - Check more errors in OpenSSL crypto backend | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user