LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - get_for_creds.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 72 131 55.0 %
Date: 2024-04-21 15:09:00 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : 
      36             : static krb5_error_code set_tgs_creds(krb5_context, krb5_ccache,
      37             :                                      krb5_const_principal,
      38             :                                      krb5_const_principal, krb5_creds *);
      39             : static krb5_error_code get_cred(krb5_context, krb5_ccache, krb5_creds *,
      40             :                                 krb5_flags, const char *, krb5_creds **);
      41             : static krb5_error_code get_addresses(krb5_context, krb5_ccache, krb5_creds *,
      42             :                                      const char *, krb5_addresses *);
      43             : 
      44             : static krb5_error_code
      45           0 : add_addrs(krb5_context context,
      46             :           krb5_addresses *addr,
      47             :           struct addrinfo *ai)
      48             : {
      49           0 :     krb5_error_code ret;
      50           0 :     unsigned n, i;
      51           0 :     void *tmp;
      52           0 :     struct addrinfo *a;
      53             : 
      54           0 :     n = 0;
      55           0 :     for (a = ai; a != NULL; a = a->ai_next)
      56           0 :         ++n;
      57             : 
      58           0 :     tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val));
      59           0 :     if (tmp == NULL && (addr->len + n) != 0) {
      60           0 :         ret = krb5_enomem(context);
      61           0 :         goto fail;
      62             :     }
      63           0 :     addr->val = tmp;
      64           0 :     for (i = addr->len; i < (addr->len + n); ++i) {
      65           0 :         addr->val[i].addr_type = 0;
      66           0 :         krb5_data_zero(&addr->val[i].address);
      67             :     }
      68           0 :     i = addr->len;
      69           0 :     for (a = ai; a != NULL; a = a->ai_next) {
      70           0 :         krb5_address ad;
      71             : 
      72           0 :         ret = krb5_sockaddr2address (context, a->ai_addr, &ad);
      73           0 :         if (ret == 0) {
      74           0 :             if (krb5_address_search(context, &ad, addr))
      75           0 :                 krb5_free_address(context, &ad);
      76             :             else
      77           0 :                 addr->val[i++] = ad;
      78             :         }
      79           0 :         else if (ret == KRB5_PROG_ATYPE_NOSUPP)
      80           0 :             krb5_clear_error_message (context);
      81             :         else
      82           0 :             goto fail;
      83           0 :         addr->len = i;
      84             :     }
      85           0 :     return 0;
      86           0 : fail:
      87           0 :     krb5_free_addresses (context, addr);
      88           0 :     return ret;
      89             : }
      90             : 
      91             : /**
      92             :  * Forward credentials for client to host hostname, making them
      93             :  * forwardable if forwardable, and returning the blob of data to sent
      94             :  * in out_data.  If hostname == NULL, pick it from server.
      95             :  *
      96             :  * If the server's realm is configured for delegation of destination
      97             :  * TGTs, forward a TGT for the server realm, rather than the client
      98             :  * realm. This works better with destinations on the far side of a
      99             :  * firewall. We also forward the destination TGT when the client
     100             :  * TGT is not available (we may have just the destination TGT).
     101             :  *
     102             :  * @param context A kerberos 5 context.
     103             :  * @param auth_context the auth context with the key to encrypt the out_data.
     104             :  * @param hostname the host to forward the tickets too.
     105             :  * @param client the client to delegate from.
     106             :  * @param server the server to delegate the credential too.
     107             :  * @param ccache credential cache to use.
     108             :  * @param forwardable make the forwarded ticket forwabledable.
     109             :  * @param out_data the resulting credential.
     110             :  *
     111             :  * @return Return an error code or 0.
     112             :  *
     113             :  * @ingroup krb5_credential
     114             :  */
     115             : 
     116             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     117       23039 : krb5_fwd_tgt_creds(krb5_context context,
     118             :                    krb5_auth_context    auth_context,
     119             :                    const char           *hostname,
     120             :                    krb5_const_principal client,
     121             :                    krb5_const_principal server,
     122             :                    krb5_ccache          ccache,
     123             :                    int                  forwardable,
     124             :                    krb5_data            *out_data)
     125             : {
     126       23039 :     krb5_flags flags = 0;
     127        1035 :     krb5_creds creds;
     128        1035 :     krb5_error_code ret;
     129             : 
     130       23039 :     flags |= KDC_OPT_FORWARDED;
     131             : 
     132       23039 :     if (forwardable)
     133       23039 :         flags |= KDC_OPT_FORWARDABLE;
     134             : 
     135       23039 :     if (hostname == NULL &&
     136           0 :         krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) {
     137           0 :         const char *inst = krb5_principal_get_comp_string(context, server, 0);
     138           0 :         const char *host = krb5_principal_get_comp_string(context, server, 1);
     139             : 
     140           0 :         if (inst != NULL &&
     141           0 :             strcmp(inst, "host") == 0 &&
     142           0 :             host != NULL &&
     143           0 :             krb5_principal_get_comp_string(context, server, 2) == NULL)
     144           0 :             hostname = host;
     145             :     }
     146             : 
     147             :     /*
     148             :      * Fill-in the request creds, the server principal will be the TGS
     149             :      * of either the client's or the server's realm.
     150             :      */
     151       23039 :     ret = set_tgs_creds(context, ccache, client, server, &creds);
     152       23039 :     if (ret)
     153           0 :         return ret;
     154             : 
     155       23039 :     ret = krb5_get_forwarded_creds (context,
     156             :                                     auth_context,
     157             :                                     ccache,
     158             :                                     flags,
     159             :                                     hostname,
     160             :                                     &creds,
     161             :                                     out_data);
     162             : 
     163       23039 :     krb5_free_cred_contents(context, &creds);
     164       23039 :     return ret;
     165             : }
     166             : 
     167             : /**
     168             :  * Gets tickets forwarded to hostname. If the tickets that are
     169             :  * forwarded are address-less, the forwarded tickets will also be
     170             :  * address-less.
     171             :  *
     172             :  * If the ticket have any address, hostname will be used for figure
     173             :  * out the address to forward the ticket too. This since this might
     174             :  * use DNS, its insecure and also doesn't represent configured all
     175             :  * addresses of the host. For example, the host might have two
     176             :  * adresses, one IPv4 and one IPv6 address where the later is not
     177             :  * published in DNS. This IPv6 address might be used communications
     178             :  * and thus the resulting ticket useless.
     179             :  *
     180             :  * @param context A kerberos 5 context.
     181             :  * @param auth_context the auth context with the key to encrypt the out_data.
     182             :  * @param ccache credential cache to use
     183             :  * @param flags the flags to control the resulting ticket flags
     184             :  * @param hostname the host to forward the tickets too.
     185             :  * @param in_creds the in client and server ticket names.  The client
     186             :  * and server components forwarded to the remote host.
     187             :  * @param out_data the resulting credential.
     188             :  *
     189             :  * @return Return an error code or 0.
     190             :  *
     191             :  * @ingroup krb5_credential
     192             :  */
     193             : 
     194             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     195       23039 : krb5_get_forwarded_creds (krb5_context      context,
     196             :                           krb5_auth_context auth_context,
     197             :                           krb5_ccache       ccache,
     198             :                           krb5_flags        flags,
     199             :                           const char        *hostname,
     200             :                           krb5_creds        *in_creds,
     201             :                           krb5_data         *out_data)
     202             : {
     203        1035 :     krb5_error_code ret;
     204        1035 :     krb5_creds *creds;
     205             : 
     206             :     /* Obtain the requested TGT */
     207       23039 :     ret = get_cred(context, ccache, in_creds, flags, hostname, &creds);
     208       23039 :     if (ret)
     209          11 :         return ret;
     210             : 
     211             :     /* Forward obtained creds */
     212       23028 :     ret = _krb5_mk_1cred(context, auth_context, creds, out_data, NULL);
     213       23028 :     krb5_free_creds(context, creds);
     214       23028 :     return ret;
     215             : }
     216             : 
     217             : /*
     218             :  * Get a TGT for forwarding to hostname. If the client TGT is
     219             :  * addressless, the forwarded ticket will also be addressless.
     220             :  *
     221             :  * If the TGT has any addresses, hostname will be used to determine
     222             :  * the address to forward the ticket to. Thus, since this might use DNS,
     223             :  * it's insecure and also may not capture all the addresses of the host.
     224             :  * In general addressless tickets are more robust, be it at a small
     225             :  * security penalty.
     226             :  *
     227             :  * @param context A kerberos 5 context.
     228             :  * @param ccache The credential cache to use
     229             :  * @param creds Creds with client and server principals
     230             :  * @param flags The flags to control the resulting ticket flags
     231             :  * @param hostname The hostname of server
     232             :  * @param out_creds The resulting credential
     233             :  *
     234             :  * @return Return an error code or 0.
     235             :  */
     236             : 
     237             : static krb5_error_code
     238       23039 : get_cred(krb5_context      context,
     239             :          krb5_ccache       ccache,
     240             :          krb5_creds        *creds,
     241             :          krb5_flags        flags,
     242             :          const char        *hostname,
     243             :          krb5_creds        **out_creds)
     244             : {
     245        1035 :     krb5_error_code ret;
     246        1035 :     krb5_kdc_flags kdc_flags;
     247        1035 :     krb5_addresses addrs;
     248             : 
     249       23039 :     addrs.len = 0;
     250       23039 :     addrs.val = NULL;
     251       23039 :     ret = get_addresses(context, ccache, creds, hostname, &addrs);
     252       23039 :     if (ret)
     253           0 :         return ret;
     254             : 
     255       23039 :     kdc_flags.b = int2KDCOptions(flags);
     256       23039 :     ret = krb5_get_kdc_cred(context, ccache, kdc_flags, &addrs, NULL,
     257             :                             creds, out_creds);
     258             : 
     259       23039 :     krb5_free_addresses(context, &addrs);
     260       23039 :     return ret;
     261             : }
     262             : 
     263             : static krb5_error_code
     264       23039 : set_tgs_creds(krb5_context              context,
     265             :               krb5_ccache               ccache,
     266             :               krb5_const_principal      client,
     267             :               krb5_const_principal      server,
     268             :               krb5_creds                *creds)
     269             : {
     270        1035 :     krb5_error_code ret;
     271        1035 :     krb5_const_realm client_realm;
     272        1035 :     krb5_const_realm server_realm;
     273        1035 :     krb5_boolean fwd_dest_tgt;
     274        1035 :     krb5_creds *client_tgt;
     275             : 
     276       23039 :     client_realm = krb5_principal_get_realm(context, client);
     277       23039 :     server_realm = krb5_principal_get_realm(context, server);
     278             : 
     279       23039 :     memset (creds, 0, sizeof(*creds));
     280       23039 :     ret = krb5_copy_principal(context, client, &creds->client);
     281       23039 :     if (ret)
     282           0 :         return ret;
     283       23039 :     ret = krb5_make_principal(context, &creds->server, client_realm,
     284             :                               KRB5_TGS_NAME, client_realm, NULL);
     285       23039 :     if (ret) {
     286           0 :         krb5_free_principal(context, creds->client);
     287           0 :         return ret;
     288             :     }
     289             : 
     290             :     /*
     291             :      * Optionally delegate a TGT for the server's realm, rather than
     292             :      * the client's. Do this also when we don't have a client realm TGT.
     293             :      *
     294             :      * XXX: Note, when we have a start-realm, and delegate-destination-tgt
     295             :      * is not set, we must use the start-realm.
     296             :      */
     297       23039 :     krb5_appdefault_boolean(context, NULL, server_realm,
     298             :                             "delegate-destination-tgt", FALSE, &fwd_dest_tgt);
     299             : 
     300       23039 :     if (!fwd_dest_tgt) {
     301       23039 :         ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, creds,
     302             :                                    &client_tgt);
     303       23039 :         if (ret == 0) {
     304       23030 :             krb5_free_creds(context, client_tgt);
     305       23030 :             return ret;
     306             :         }
     307             :     }
     308             : 
     309             :     /*
     310             :      * Client TGT inapplicable or unavailable
     311             :      */
     312           9 :     krb5_free_principal(context, creds->server);
     313           9 :     creds->server = 0;
     314           9 :     return krb5_make_principal(context, &creds->server, server_realm,
     315             :                                KRB5_TGS_NAME, server_realm, NULL);
     316             : }
     317             : 
     318             : /*
     319             :  * Obtain address list for hostname if server realm policy is not addressless.
     320             :  */
     321             : static krb5_error_code
     322       23039 : get_addresses(krb5_context      context,
     323             :               krb5_ccache       ccache,
     324             :               krb5_creds        *creds,
     325             :               const char        *hostname,
     326             :               krb5_addresses    *addrs)
     327             : {
     328        1035 :     krb5_error_code ret;
     329        1035 :     krb5_creds *ticket;
     330        1035 :     krb5_const_realm realm;
     331        1035 :     krb5_boolean noaddr;
     332        1035 :     struct addrinfo *ai, hints;
     333        1035 :     int eai;
     334             : 
     335       23039 :     if (hostname == 0)
     336           0 :         return 0;
     337             : 
     338       23039 :     ret = krb5_get_credentials(context, 0, ccache, creds, &ticket);
     339       23039 :     if (ret == 0) {
     340       23030 :         noaddr = (ticket->addresses.len == 0) ? TRUE : FALSE;
     341       23030 :         krb5_free_creds(context, ticket);
     342             :     } else {
     343           9 :         realm = krb5_principal_get_realm(context, creds->server);
     344           9 :         krb5_appdefault_boolean(context, NULL, realm, "no-addresses",
     345             :                                 KRB5_ADDRESSLESS_DEFAULT, &noaddr);
     346             :     }
     347             : 
     348       23039 :     if (noaddr)
     349       22004 :         return 0;
     350             : 
     351             :     /* Need addresses, get the address of the remote host. */
     352           0 :     memset(&hints, 0, sizeof(hints));
     353           0 :     if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     354             :             NULL)) {
     355           0 :         hints.ai_flags &= ~AI_CANONNAME;
     356           0 :         hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
     357             :     }
     358           0 :     eai = getaddrinfo(hostname, NULL, &hints, &ai);
     359           0 :     if (eai) {
     360           0 :         ret = krb5_eai_to_heim_errno(eai, errno);
     361           0 :         krb5_set_error_message(context, ret,
     362           0 :                                N_("resolving host %s failed: %s",
     363             :                                   "hostname, error"),
     364             :                                hostname, gai_strerror(eai));
     365           0 :         return ret;
     366             :     }
     367             : 
     368           0 :     ret = add_addrs(context, addrs, ai);
     369           0 :     freeaddrinfo(ai);
     370             : 
     371           0 :     return ret;
     372             : }

Generated by: LCOV version 1.14