LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - get_for_creds.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 78 202 38.6 %
Date: 2021-09-23 10:06:22 Functions: 1 3 33.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
      37           0 : add_addrs(krb5_context context,
      38             :           krb5_addresses *addr,
      39             :           struct addrinfo *ai)
      40             : {
      41             :     krb5_error_code ret;
      42             :     unsigned n, i;
      43             :     void *tmp;
      44             :     struct addrinfo *a;
      45             : 
      46           0 :     n = 0;
      47           0 :     for (a = ai; a != NULL; a = a->ai_next)
      48           0 :         ++n;
      49             : 
      50           0 :     tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val));
      51           0 :     if (tmp == NULL && (addr->len + n) != 0) {
      52           0 :         ret = ENOMEM;
      53           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
      54           0 :         goto fail;
      55             :     }
      56           0 :     addr->val = tmp;
      57           0 :     for (i = addr->len; i < (addr->len + n); ++i) {
      58           0 :         addr->val[i].addr_type = 0;
      59           0 :         krb5_data_zero(&addr->val[i].address);
      60             :     }
      61           0 :     i = addr->len;
      62           0 :     for (a = ai; a != NULL; a = a->ai_next) {
      63             :         krb5_address ad;
      64             : 
      65           0 :         ret = krb5_sockaddr2address (context, a->ai_addr, &ad);
      66           0 :         if (ret == 0) {
      67           0 :             if (krb5_address_search(context, &ad, addr))
      68           0 :                 krb5_free_address(context, &ad);
      69             :             else
      70           0 :                 addr->val[i++] = ad;
      71             :         }
      72           0 :         else if (ret == KRB5_PROG_ATYPE_NOSUPP)
      73           0 :             krb5_clear_error_message (context);
      74             :         else
      75           0 :             goto fail;
      76           0 :         addr->len = i;
      77             :     }
      78           0 :     return 0;
      79           0 : fail:
      80           0 :     krb5_free_addresses (context, addr);
      81           0 :     return ret;
      82             : }
      83             : 
      84             : /**
      85             :  * Forward credentials for client to host hostname , making them
      86             :  * forwardable if forwardable, and returning the blob of data to sent
      87             :  * in out_data.  If hostname == NULL, pick it from server.
      88             :  *
      89             :  * @param context A kerberos 5 context.
      90             :  * @param auth_context the auth context with the key to encrypt the out_data.
      91             :  * @param hostname the host to forward the tickets too.
      92             :  * @param client the client to delegate from.
      93             :  * @param server the server to delegate the credential too.
      94             :  * @param ccache credential cache to use.
      95             :  * @param forwardable make the forwarded ticket forwabledable.
      96             :  * @param out_data the resulting credential.
      97             :  *
      98             :  * @return Return an error code or 0.
      99             :  *
     100             :  * @ingroup krb5_credential
     101             :  */
     102             : 
     103             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     104           0 : krb5_fwd_tgt_creds (krb5_context        context,
     105             :                     krb5_auth_context   auth_context,
     106             :                     const char          *hostname,
     107             :                     krb5_principal      client,
     108             :                     krb5_principal      server,
     109             :                     krb5_ccache         ccache,
     110             :                     int                 forwardable,
     111             :                     krb5_data           *out_data)
     112             : {
     113           0 :     krb5_flags flags = 0;
     114             :     krb5_creds creds;
     115             :     krb5_error_code ret;
     116             :     krb5_const_realm client_realm;
     117             : 
     118           0 :     flags |= KDC_OPT_FORWARDED;
     119             : 
     120           0 :     if (forwardable)
     121           0 :         flags |= KDC_OPT_FORWARDABLE;
     122             : 
     123           0 :     if (hostname == NULL &&
     124           0 :         krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) {
     125           0 :         const char *inst = krb5_principal_get_comp_string(context, server, 0);
     126           0 :         const char *host = krb5_principal_get_comp_string(context, server, 1);
     127             : 
     128           0 :         if (inst != NULL &&
     129           0 :             strcmp(inst, "host") == 0 &&
     130           0 :             host != NULL &&
     131           0 :             krb5_principal_get_comp_string(context, server, 2) == NULL)
     132           0 :             hostname = host;
     133             :     }
     134             : 
     135           0 :     client_realm = krb5_principal_get_realm(context, client);
     136             : 
     137           0 :     memset (&creds, 0, sizeof(creds));
     138           0 :     creds.client = client;
     139             : 
     140           0 :     ret = krb5_make_principal(context,
     141             :                               &creds.server,
     142             :                               client_realm,
     143             :                               KRB5_TGS_NAME,
     144             :                               client_realm,
     145             :                               NULL);
     146           0 :     if (ret)
     147           0 :         return ret;
     148             : 
     149           0 :     ret = krb5_get_forwarded_creds (context,
     150             :                                     auth_context,
     151             :                                     ccache,
     152             :                                     flags,
     153             :                                     hostname,
     154             :                                     &creds,
     155             :                                     out_data);
     156           0 :     return ret;
     157             : }
     158             : 
     159             : /**
     160             :  * Gets tickets forwarded to hostname. If the tickets that are
     161             :  * forwarded are address-less, the forwarded tickets will also be
     162             :  * address-less.
     163             :  *
     164             :  * If the ticket have any address, hostname will be used for figure
     165             :  * out the address to forward the ticket too. This since this might
     166             :  * use DNS, its insecure and also doesn't represent configured all
     167             :  * addresses of the host. For example, the host might have two
     168             :  * adresses, one IPv4 and one IPv6 address where the later is not
     169             :  * published in DNS. This IPv6 address might be used communications
     170             :  * and thus the resulting ticket useless.
     171             :  *
     172             :  * @param context A kerberos 5 context.
     173             :  * @param auth_context the auth context with the key to encrypt the out_data.
     174             :  * @param ccache credential cache to use
     175             :  * @param flags the flags to control the resulting ticket flags
     176             :  * @param hostname the host to forward the tickets too.
     177             :  * @param in_creds the in client and server ticket names.  The client
     178             :  * and server components forwarded to the remote host.
     179             :  * @param out_data the resulting credential.
     180             :  *
     181             :  * @return Return an error code or 0.
     182             :  *
     183             :  * @ingroup krb5_credential
     184             :  */
     185             : 
     186             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     187       19981 : krb5_get_forwarded_creds (krb5_context      context,
     188             :                           krb5_auth_context auth_context,
     189             :                           krb5_ccache       ccache,
     190             :                           krb5_flags        flags,
     191             :                           const char        *hostname,
     192             :                           krb5_creds        *in_creds,
     193             :                           krb5_data         *out_data)
     194             : {
     195             :     krb5_error_code ret;
     196             :     krb5_creds *out_creds;
     197             :     krb5_addresses addrs, *paddrs;
     198             :     KRB_CRED cred;
     199             :     KrbCredInfo *krb_cred_info;
     200             :     EncKrbCredPart enc_krb_cred_part;
     201             :     size_t len;
     202             :     unsigned char *buf;
     203             :     size_t buf_size;
     204             :     krb5_kdc_flags kdc_flags;
     205             :     krb5_crypto crypto;
     206             :     struct addrinfo *ai;
     207             :     krb5_creds *ticket;
     208             : 
     209       19981 :     paddrs = NULL;
     210       19981 :     addrs.len = 0;
     211       19981 :     addrs.val = NULL;
     212             : 
     213       19981 :     ret = krb5_get_credentials(context, 0, ccache, in_creds, &ticket);
     214       19981 :     if(ret == 0) {
     215       19978 :         if (ticket->addresses.len)
     216           0 :             paddrs = &addrs;
     217       19978 :         krb5_free_creds (context, ticket);
     218             :     } else {
     219             :         krb5_boolean noaddr;
     220           3 :         krb5_appdefault_boolean(context, NULL,
     221             :                                 krb5_principal_get_realm(context,
     222           3 :                                                          in_creds->client),
     223             :                                 "no-addresses", KRB5_ADDRESSLESS_DEFAULT,
     224             :                                 &noaddr);
     225           3 :         if (!noaddr)
     226           0 :             paddrs = &addrs;
     227             :     }
     228             : 
     229             :     /*
     230             :      * If tickets have addresses, get the address of the remote host.
     231             :      */
     232             : 
     233       19981 :     if (paddrs != NULL) {
     234             : 
     235           0 :         ret = getaddrinfo (hostname, NULL, NULL, &ai);
     236           0 :         if (ret) {
     237           0 :             krb5_error_code ret2 = krb5_eai_to_heim_errno(ret, errno);
     238           0 :             krb5_set_error_message(context, ret2,
     239           0 :                                    N_("resolving host %s failed: %s",
     240             :                                       "hostname, error"),
     241             :                                   hostname, gai_strerror(ret));
     242           0 :             return ret2;
     243             :         }
     244             : 
     245           0 :         ret = add_addrs (context, &addrs, ai);
     246           0 :         freeaddrinfo (ai);
     247           0 :         if (ret)
     248           0 :             return ret;
     249             :     }
     250             : 
     251       19981 :     kdc_flags.b = int2KDCOptions(flags);
     252             : 
     253       19981 :     ret = krb5_get_kdc_cred (context,
     254             :                              ccache,
     255             :                              kdc_flags,
     256             :                              paddrs,
     257             :                              NULL,
     258             :                              in_creds,
     259             :                              &out_creds);
     260       19981 :     krb5_free_addresses (context, &addrs);
     261       19981 :     if (ret)
     262         189 :         return ret;
     263             : 
     264       19792 :     memset (&cred, 0, sizeof(cred));
     265       19792 :     cred.pvno = 5;
     266       19792 :     cred.msg_type = krb_cred;
     267       19792 :     ALLOC_SEQ(&cred.tickets, 1);
     268       19792 :     if (cred.tickets.val == NULL) {
     269           0 :         ret = ENOMEM;
     270           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     271           0 :         goto out2;
     272             :     }
     273       38834 :     ret = decode_Ticket(out_creds->ticket.data,
     274       19792 :                         out_creds->ticket.length,
     275             :                         cred.tickets.val, &len);
     276       19792 :     if (ret)
     277           0 :         goto out3;
     278             : 
     279       19792 :     memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part));
     280       19792 :     ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1);
     281       19792 :     if (enc_krb_cred_part.ticket_info.val == NULL) {
     282           0 :         ret = ENOMEM;
     283           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     284           0 :         goto out4;
     285             :     }
     286             : 
     287       19792 :     if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
     288             :         krb5_timestamp sec;
     289             :         int32_t usec;
     290             : 
     291       19792 :         krb5_us_timeofday (context, &sec, &usec);
     292             : 
     293       19792 :         ALLOC(enc_krb_cred_part.timestamp, 1);
     294       19792 :         if (enc_krb_cred_part.timestamp == NULL) {
     295           0 :             ret = ENOMEM;
     296           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     297           0 :             goto out4;
     298             :         }
     299       19792 :         *enc_krb_cred_part.timestamp = sec;
     300       19792 :         ALLOC(enc_krb_cred_part.usec, 1);
     301       19792 :         if (enc_krb_cred_part.usec == NULL) {
     302           0 :             ret = ENOMEM;
     303           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     304           0 :             goto out4;
     305             :         }
     306       19792 :         *enc_krb_cred_part.usec      = usec;
     307             :     } else {
     308           0 :         enc_krb_cred_part.timestamp = NULL;
     309           0 :         enc_krb_cred_part.usec = NULL;
     310             :     }
     311             : 
     312       19792 :     if (auth_context->local_address && auth_context->local_port && paddrs) {
     313             : 
     314           0 :         ret = krb5_make_addrport (context,
     315             :                                   &enc_krb_cred_part.s_address,
     316           0 :                                   auth_context->local_address,
     317           0 :                                   auth_context->local_port);
     318           0 :         if (ret)
     319           0 :             goto out4;
     320             :     }
     321             : 
     322       19792 :     if (auth_context->remote_address) {
     323           0 :         if (auth_context->remote_port) {
     324             :             krb5_boolean noaddr;
     325             :             krb5_const_realm srealm;
     326             : 
     327           0 :             srealm = krb5_principal_get_realm(context, out_creds->server);
     328             :             /* Is this correct, and should we use the paddrs == NULL
     329             :                trick here as well? Having an address-less ticket may
     330             :                indicate that we don't know our own global address, but
     331             :                it does not necessary mean that we don't know the
     332             :                server's. */
     333           0 :             krb5_appdefault_boolean(context, NULL, srealm, "no-addresses",
     334             :                                     FALSE, &noaddr);
     335           0 :             if (!noaddr) {
     336           0 :                 ret = krb5_make_addrport (context,
     337             :                                           &enc_krb_cred_part.r_address,
     338           0 :                                           auth_context->remote_address,
     339           0 :                                           auth_context->remote_port);
     340           0 :                 if (ret)
     341           0 :                     goto out4;
     342             :             }
     343             :         } else {
     344           0 :             ALLOC(enc_krb_cred_part.r_address, 1);
     345           0 :             if (enc_krb_cred_part.r_address == NULL) {
     346           0 :                 ret = ENOMEM;
     347           0 :                 krb5_set_error_message(context, ret,
     348           0 :                                        N_("malloc: out of memory", ""));
     349           0 :                 goto out4;
     350             :             }
     351             : 
     352           0 :             ret = krb5_copy_address (context, auth_context->remote_address,
     353           0 :                                      enc_krb_cred_part.r_address);
     354           0 :             if (ret)
     355           0 :                 goto out4;
     356             :         }
     357             :     }
     358             : 
     359             :     /* fill ticket_info.val[0] */
     360             : 
     361       19792 :     enc_krb_cred_part.ticket_info.len = 1;
     362             : 
     363       19792 :     krb_cred_info = enc_krb_cred_part.ticket_info.val;
     364             : 
     365       19792 :     copy_EncryptionKey (&out_creds->session, &krb_cred_info->key);
     366       19792 :     ALLOC(krb_cred_info->prealm, 1);
     367       19792 :     copy_Realm (&out_creds->client->realm, krb_cred_info->prealm);
     368       19792 :     ALLOC(krb_cred_info->pname, 1);
     369       19792 :     copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname);
     370       19792 :     ALLOC(krb_cred_info->flags, 1);
     371       19792 :     *krb_cred_info->flags          = out_creds->flags.b;
     372       19792 :     ALLOC(krb_cred_info->authtime, 1);
     373       19792 :     *krb_cred_info->authtime       = out_creds->times.authtime;
     374       19792 :     ALLOC(krb_cred_info->starttime, 1);
     375       19792 :     *krb_cred_info->starttime      = out_creds->times.starttime;
     376       19792 :     ALLOC(krb_cred_info->endtime, 1);
     377       19792 :     *krb_cred_info->endtime        = out_creds->times.endtime;
     378       19792 :     ALLOC(krb_cred_info->renew_till, 1);
     379       19792 :     *krb_cred_info->renew_till = out_creds->times.renew_till;
     380       19792 :     ALLOC(krb_cred_info->srealm, 1);
     381       19792 :     copy_Realm (&out_creds->server->realm, krb_cred_info->srealm);
     382       19792 :     ALLOC(krb_cred_info->sname, 1);
     383       19792 :     copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname);
     384       19792 :     ALLOC(krb_cred_info->caddr, 1);
     385       19792 :     copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr);
     386             : 
     387       19792 :     krb5_free_creds (context, out_creds);
     388             : 
     389             :     /* encode EncKrbCredPart */
     390             : 
     391       19792 :     ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size,
     392             :                        &enc_krb_cred_part, &len, ret);
     393       19792 :     free_EncKrbCredPart (&enc_krb_cred_part);
     394       19792 :     if (ret) {
     395           0 :         free_KRB_CRED(&cred);
     396           0 :         return ret;
     397             :     }
     398       19792 :     if(buf_size != len)
     399           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     400             : 
     401             :     /**
     402             :      * Some older of the MIT gssapi library used clear-text tickets
     403             :      * (warped inside AP-REQ encryption), use the krb5_auth_context
     404             :      * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those
     405             :      * tickets. The session key is used otherwise to encrypt the
     406             :      * forwarded ticket.
     407             :      */
     408             : 
     409       19792 :     if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) {
     410       19792 :         cred.enc_part.etype = KRB5_ENCTYPE_NULL;
     411       19792 :         cred.enc_part.kvno = NULL;
     412       19792 :         cred.enc_part.cipher.data = buf;
     413       19792 :         cred.enc_part.cipher.length = buf_size;
     414             :     } else {
     415             :         /*
     416             :          * Here older versions then 0.7.2 of Heimdal used the local or
     417             :          * remote subkey. That is wrong, the session key should be
     418             :          * used. Heimdal 0.7.2 and newer have code to try both in the
     419             :          * receiving end.
     420             :          */
     421             : 
     422           0 :         ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
     423           0 :         if (ret) {
     424           0 :             free(buf);
     425           0 :             free_KRB_CRED(&cred);
     426           0 :             return ret;
     427             :         }
     428           0 :         ret = krb5_encrypt_EncryptedData (context,
     429             :                                           crypto,
     430             :                                           KRB5_KU_KRB_CRED,
     431             :                                           buf,
     432             :                                           len,
     433             :                                           0,
     434             :                                           &cred.enc_part);
     435           0 :         free(buf);
     436           0 :         krb5_crypto_destroy(context, crypto);
     437           0 :         if (ret) {
     438           0 :             free_KRB_CRED(&cred);
     439           0 :             return ret;
     440             :         }
     441             :     }
     442             : 
     443       19792 :     ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret);
     444       19792 :     free_KRB_CRED (&cred);
     445       19792 :     if (ret)
     446           0 :         return ret;
     447       19792 :     if(buf_size != len)
     448           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     449       19792 :     out_data->length = len;
     450       19792 :     out_data->data   = buf;
     451       19792 :     return 0;
     452           0 :  out4:
     453           0 :     free_EncKrbCredPart(&enc_krb_cred_part);
     454           0 :  out3:
     455           0 :     free_KRB_CRED(&cred);
     456           0 :  out2:
     457           0 :     krb5_free_creds (context, out_creds);
     458           0 :     return ret;
     459             : }

Generated by: LCOV version 1.13