"Fossies" - the Fresh Open Source Software Archive

Member "krb5-1.18/src/tests/adata.c" (12 Feb 2020, 12046 Bytes) of package /linux/misc/krb5-1.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "adata.c": 1.17.1_vs_1.18.

    1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
    2 /* tests/adata.c - Test harness for KDC authorization data */
    3 /*
    4  * Copyright (C) 2014 by the Massachusetts Institute of Technology.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  * * Redistributions of source code must retain the above copyright
   12  *   notice, this list of conditions and the following disclaimer.
   13  *
   14  * * Redistributions in binary form must reproduce the above copyright
   15  *   notice, this list of conditions and the following disclaimer in
   16  *   the documentation and/or other materials provided with the
   17  *   distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   30  * OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Usage: ./adata [-c ccname] [-p clientprinc] serviceprinc
   35  *            [ad-type ad-contents ...]
   36  *
   37  * This program acquires credentials for the specified service principal, using
   38  * the specified or default ccache, possibly including requested authdata.  The
   39  * resulting ticket is decrypted using the default keytab, and the authdata in
   40  * the ticket are displayed to stdout.
   41  *
   42  * In the requested authdata types, the type may be prefixed with '?' for an
   43  * AD-IF-RELEVANT container, '!' for an AD-MANDATORY-FOR-KDC container, or '^'
   44  * for an AD-KDC-ISSUED container checksummed with a random AES256 key.
   45  * Multiple prefixes may be specified for nested container.
   46  *
   47  * In the output, authdata containers will be flattened and displayed with the
   48  * above prefixes or '+' for an AD-CAMMAC container.  AD-KDC-ISSUED and
   49  * AD-CAMMAC containers will be verified with the appropriate key.  Nested
   50  * containers only display the prefix for the innermost container.
   51  */
   52 
   53 #include <k5-int.h>
   54 #include <ctype.h>
   55 
   56 static krb5_context ctx;
   57 
   58 static void display_authdata_list(krb5_authdata **list, krb5_keyblock *skey,
   59                                   krb5_keyblock *tktkey, char prefix_byte,
   60                                   krb5_boolean pac_expected);
   61 
   62 static void
   63 check(krb5_error_code code)
   64 {
   65     const char *errmsg;
   66 
   67     if (code) {
   68         errmsg = krb5_get_error_message(ctx, code);
   69         fprintf(stderr, "%s\n", errmsg);
   70         krb5_free_error_message(ctx, errmsg);
   71         exit(1);
   72     }
   73 }
   74 
   75 static krb5_authdatatype
   76 get_type_for_prefix(int prefix_byte)
   77 {
   78     if (prefix_byte == '?')
   79         return KRB5_AUTHDATA_IF_RELEVANT;
   80     if (prefix_byte == '!')
   81         return KRB5_AUTHDATA_MANDATORY_FOR_KDC;
   82     if (prefix_byte == '^')
   83         return KRB5_AUTHDATA_KDC_ISSUED;
   84     if (prefix_byte == '+')
   85         return KRB5_AUTHDATA_CAMMAC;
   86     abort();
   87 }
   88 
   89 static int
   90 get_prefix_byte(krb5_authdata *ad)
   91 {
   92     if (ad->ad_type == KRB5_AUTHDATA_IF_RELEVANT)
   93         return '?';
   94     if (ad->ad_type == KRB5_AUTHDATA_MANDATORY_FOR_KDC)
   95         return '!';
   96     if (ad->ad_type == KRB5_AUTHDATA_KDC_ISSUED)
   97         return '^';
   98     if (ad->ad_type == KRB5_AUTHDATA_CAMMAC)
   99         return '+';
  100     abort();
  101 }
  102 
  103 /* Construct a container of type ad_type for the single authdata element
  104  * content.  For KDC-ISSUED containers, use a random checksum key. */
  105 static krb5_authdata *
  106 make_container(krb5_authdatatype ad_type, krb5_authdata *content)
  107 {
  108     krb5_authdata *list[2], **enclist, *ad;
  109     krb5_keyblock kb;
  110 
  111     list[0] = content;
  112     list[1] = NULL;
  113 
  114     if (ad_type == KRB5_AUTHDATA_KDC_ISSUED) {
  115         check(krb5_c_make_random_key(ctx, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
  116                                      &kb));
  117         check(krb5_make_authdata_kdc_issued(ctx, &kb, NULL, list, &enclist));
  118         krb5_free_keyblock_contents(ctx, &kb);
  119     } else {
  120         check(krb5_encode_authdata_container(ctx, ad_type, list, &enclist));
  121     }
  122 
  123     /* Grab the first element from the encoded list and free the array. */
  124     ad = enclist[0];
  125     free(enclist);
  126     return ad;
  127 }
  128 
  129 /* Parse typestr and contents into an authdata element. */
  130 static krb5_authdata *
  131 make_authdata(const char *typestr, const char *contents)
  132 {
  133     krb5_authdata *inner_ad, *ad;
  134 
  135     if (*typestr == '?' || *typestr == '!' || *typestr == '^') {
  136         inner_ad = make_authdata(typestr + 1, contents);
  137         ad = make_container(get_type_for_prefix(*typestr), inner_ad);
  138         free(inner_ad->contents);
  139         free(inner_ad);
  140         return ad;
  141     }
  142 
  143     ad = malloc(sizeof(*ad));
  144     assert(ad != NULL);
  145     ad->magic = KV5M_AUTHDATA;
  146     ad->ad_type = atoi(typestr);
  147     ad->length = strlen(contents);
  148     ad->contents = (unsigned char *)strdup(contents);
  149     assert(ad->contents != NULL);
  150     return ad;
  151 }
  152 
  153 static krb5_authdata **
  154 get_container_contents(krb5_authdata *ad, krb5_keyblock *skey,
  155                        krb5_keyblock *tktkey)
  156 {
  157     krb5_authdata **inner_ad;
  158 
  159     if (ad->ad_type == KRB5_AUTHDATA_KDC_ISSUED)
  160         check(krb5_verify_authdata_kdc_issued(ctx, skey, ad, NULL, &inner_ad));
  161     else if (ad->ad_type == KRB5_AUTHDATA_CAMMAC)
  162         check(k5_unwrap_cammac_svc(ctx, ad, tktkey, &inner_ad));
  163     else
  164         check(krb5_decode_authdata_container(ctx, ad->ad_type, ad, &inner_ad));
  165     return inner_ad;
  166 }
  167 
  168 /* Decode and display authentication indicator authdata. */
  169 static void
  170 display_auth_indicator(krb5_authdata *ad)
  171 {
  172     krb5_data **strs = NULL, **p;
  173 
  174     check(k5_authind_decode(ad, &strs));
  175     assert(strs != NULL);
  176 
  177     printf("[");
  178     for (p = strs; *p != NULL; p++) {
  179         printf("%.*s", (int)(*p)->length, (*p)->data);
  180         if (*(p + 1) != NULL)
  181             printf(", ");
  182     }
  183     printf("]");
  184     k5_free_data_ptr_list(strs);
  185 }
  186 
  187 /* Display ad as either a hex dump or ASCII text. */
  188 static void
  189 display_binary_or_ascii(krb5_authdata *ad)
  190 {
  191     krb5_boolean binary = FALSE;
  192     unsigned char *p;
  193 
  194     for (p = ad->contents; p < ad->contents + ad->length; p++) {
  195         if (!isascii(*p) || !isprint(*p))
  196             binary = TRUE;
  197     }
  198     if (binary) {
  199         for (p = ad->contents; p < ad->contents + ad->length; p++)
  200             printf("%02X", *p);
  201     } else {
  202         printf("%.*s", (int)ad->length, ad->contents);
  203     }
  204 }
  205 
  206 /* Display the contents of an authdata element, prefixed by prefix_byte.  skey
  207  * must be the ticket session key. */
  208 static void
  209 display_authdata(krb5_authdata *ad, krb5_keyblock *skey, krb5_keyblock *tktkey,
  210                  int prefix_byte, krb5_boolean pac_expected)
  211 {
  212     krb5_authdata **inner_ad;
  213 
  214     if (ad->ad_type == KRB5_AUTHDATA_IF_RELEVANT ||
  215         ad->ad_type == KRB5_AUTHDATA_MANDATORY_FOR_KDC ||
  216         ad->ad_type == KRB5_AUTHDATA_KDC_ISSUED ||
  217         ad->ad_type == KRB5_AUTHDATA_CAMMAC) {
  218         if (ad->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
  219             pac_expected = FALSE;
  220         /* Decode and display the contents. */
  221         inner_ad = get_container_contents(ad, skey, tktkey);
  222         display_authdata_list(inner_ad, skey, tktkey, get_prefix_byte(ad),
  223                               pac_expected);
  224         krb5_free_authdata(ctx, inner_ad);
  225         return;
  226     }
  227 
  228     assert(!pac_expected || ad->ad_type == KRB5_AUTHDATA_WIN2K_PAC);
  229 
  230     printf("%c", prefix_byte);
  231     printf("%d: ", (int)ad->ad_type);
  232 
  233     if (ad->ad_type == KRB5_AUTHDATA_AUTH_INDICATOR)
  234         display_auth_indicator(ad);
  235     else
  236         display_binary_or_ascii(ad);
  237     printf("\n");
  238 }
  239 
  240 static void
  241 display_authdata_list(krb5_authdata **list, krb5_keyblock *skey,
  242                       krb5_keyblock *tktkey, char prefix_byte,
  243                       krb5_boolean pac_expected)
  244 {
  245     if (list == NULL)
  246         return;
  247     /* Only expect a PAC in the first element, if at all. */
  248     for (; *list != NULL; list++) {
  249         display_authdata(*list, skey, tktkey, prefix_byte, pac_expected);
  250         pac_expected = FALSE;
  251     }
  252 }
  253 
  254 /* If a PAC is present in enc_part2, verify its service signature with key and
  255  * set *has_pac to true. */
  256 static void
  257 check_pac(krb5_context context, krb5_enc_tkt_part *enc_part2,
  258           const krb5_keyblock *key, krb5_boolean *has_pac)
  259 {
  260     krb5_authdata **authdata;
  261     krb5_pac pac;
  262 
  263     *has_pac = FALSE;
  264 
  265     check(krb5_find_authdata(context, enc_part2->authorization_data, NULL,
  266                              KRB5_AUTHDATA_WIN2K_PAC, &authdata));
  267     if (authdata == NULL)
  268         return;
  269 
  270     assert(authdata[1] == NULL);
  271     check(krb5_pac_parse(context, authdata[0]->contents, authdata[0]->length,
  272                          &pac));
  273     krb5_free_authdata(context, authdata);
  274 
  275     check(krb5_pac_verify(context, pac, enc_part2->times.authtime,
  276                           enc_part2->client, key, NULL));
  277     krb5_pac_free(context, pac);
  278     *has_pac = TRUE;
  279 }
  280 
  281 int
  282 main(int argc, char **argv)
  283 {
  284     const char *ccname = NULL, *clientname = NULL;
  285     krb5_principal client, server;
  286     krb5_ccache ccache;
  287     krb5_keytab keytab;
  288     krb5_creds in_creds, *creds;
  289     krb5_ticket *ticket;
  290     krb5_authdata **req_authdata = NULL, *ad;
  291     krb5_keytab_entry ktent;
  292     krb5_boolean with_pac;
  293     size_t count;
  294     int c;
  295 
  296     check(krb5_init_context(&ctx));
  297 
  298     while ((c = getopt(argc, argv, "+c:p:")) != -1) {
  299         switch (c) {
  300         case 'c':
  301             ccname = optarg;
  302             break;
  303         case 'p':
  304             clientname = optarg;
  305             break;
  306         default:
  307             abort();
  308         }
  309     }
  310     argv += optind;
  311     /* Parse arguments. */
  312     assert(*argv != NULL);
  313     check(krb5_parse_name(ctx, *argv++, &server));
  314 
  315     count = 0;
  316     for (; argv[0] != NULL && argv[1] != NULL; argv += 2) {
  317         ad = make_authdata(argv[0], argv[1]);
  318         req_authdata = realloc(req_authdata,
  319                                (count + 2) * sizeof(*req_authdata));
  320         assert(req_authdata != NULL);
  321         req_authdata[count++] = ad;
  322         req_authdata[count] = NULL;
  323     }
  324     assert(*argv == NULL);
  325 
  326     if (ccname != NULL)
  327         check(krb5_cc_resolve(ctx, ccname, &ccache));
  328     else
  329         check(krb5_cc_default(ctx, &ccache));
  330 
  331     if (clientname != NULL)
  332         check(krb5_parse_name(ctx, clientname, &client));
  333     else
  334         check(krb5_cc_get_principal(ctx, ccache, &client));
  335 
  336     memset(&in_creds, 0, sizeof(in_creds));
  337     in_creds.client = client;
  338     in_creds.server = server;
  339     in_creds.authdata = req_authdata;
  340 
  341     check(krb5_get_credentials(ctx, KRB5_GC_NO_STORE, ccache, &in_creds,
  342                                &creds));
  343 
  344     assert(in_creds.authdata == NULL || creds->authdata != NULL);
  345 
  346     check(krb5_decode_ticket(&creds->ticket, &ticket));
  347     check(krb5_kt_default(ctx, &keytab));
  348     check(krb5_kt_get_entry(ctx, keytab, ticket->server, ticket->enc_part.kvno,
  349                             ticket->enc_part.enctype, &ktent));
  350     check(krb5_decrypt_tkt_part(ctx, &ktent.key, ticket));
  351 
  352     check_pac(ctx, ticket->enc_part2, &ktent.key, &with_pac);
  353     display_authdata_list(ticket->enc_part2->authorization_data,
  354                           ticket->enc_part2->session, &ktent.key, ' ',
  355                           with_pac);
  356 
  357     while (count > 0) {
  358         free(req_authdata[--count]->contents);
  359         free(req_authdata[count]);
  360     }
  361     free(req_authdata);
  362     krb5_free_keytab_entry_contents(ctx, &ktent);
  363     krb5_free_creds(ctx, creds);
  364     krb5_free_ticket(ctx, ticket);
  365     krb5_free_principal(ctx, client);
  366     krb5_free_principal(ctx, server);
  367     krb5_cc_close(ctx, ccache);
  368     krb5_kt_close(ctx, keytab);
  369     krb5_free_context(ctx);
  370     return 0;
  371 }