LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - keytab.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 182 305 59.7 %
Date: 2024-04-21 15:09:00 Functions: 20 27 74.1 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2005 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             : /**
      37             :  * @page krb5_keytab_intro The keytab handing functions
      38             :  * @section section_krb5_keytab Kerberos Keytabs
      39             :  *
      40             :  * See the library functions here: @ref krb5_keytab
      41             :  *
      42             :  * Keytabs are long term key storage for servers, their equvalment of
      43             :  * password files.
      44             :  *
      45             :  * Normally the only function that useful for server are to specify
      46             :  * what keytab to use to other core functions like krb5_rd_req()
      47             :  * krb5_kt_resolve(), and krb5_kt_close().
      48             :  *
      49             :  * @subsection krb5_keytab_names Keytab names
      50             :  *
      51             :  * A keytab name is on the form type:residual. The residual part is
      52             :  * specific to each keytab-type.
      53             :  *
      54             :  * When a keytab-name is resolved, the type is matched with an internal
      55             :  * list of keytab types. If there is no matching keytab type,
      56             :  * the default keytab is used. The current default type is FILE.
      57             :  *
      58             :  * The default value can be changed in the configuration file
      59             :  * /etc/krb5.conf by setting the variable
      60             :  * [defaults]default_keytab_name.
      61             :  *
      62             :  * The keytab types that are implemented in Heimdal are:
      63             :  * - file
      64             :  *   store the keytab in a file, the type's name is FILE .  The
      65             :  *   residual part is a filename. For compatibility with other
      66             :  *   Kerberos implemtation WRFILE and JAVA14 is also accepted.  WRFILE
      67             :  *   has the same format as FILE. JAVA14 have a format that is
      68             :  *   compatible with older versions of MIT kerberos and SUN's Java
      69             :  *   based installation.  They store a truncted kvno, so when the knvo
      70             :  *   excess 255, they are truncted in this format.
      71             :  *
      72             :  * - keytab
      73             :  *   store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ),
      74             :  *   the type's name is AFSKEYFILE. The residual part is a filename.
      75             :  *
      76             :  * - memory
      77             :  *   The keytab is stored in a memory segment. This allows sensitive
      78             :  *   and/or temporary data not to be stored on disk. The type's name
      79             :  *   is MEMORY. Each MEMORY keytab is referenced counted by and
      80             :  *   opened by the residual name, so two handles can point to the
      81             :  *   same memory area.  When the last user closes using krb5_kt_close()
      82             :  *   the keytab, the keys in they keytab is memset() to zero and freed
      83             :  *   and can no longer be looked up by name.
      84             :  *
      85             :  *
      86             :  * @subsection krb5_keytab_example Keytab example
      87             :  *
      88             :  *  This is a minimalistic version of ktutil.
      89             :  *
      90             :  * @code
      91             : int
      92             : main (int argc, char **argv)
      93             : {
      94             :     krb5_context context;
      95             :     krb5_keytab keytab;
      96             :     krb5_kt_cursor cursor;
      97             :     krb5_keytab_entry entry;
      98             :     krb5_error_code ret;
      99             :     char *principal;
     100             : 
     101             :     if (krb5_init_context (&context) != 0)
     102             :         errx(1, "krb5_context");
     103             : 
     104             :     ret = krb5_kt_default (context, &keytab);
     105             :     if (ret)
     106             :         krb5_err(context, 1, ret, "krb5_kt_default");
     107             : 
     108             :     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     109             :     if (ret)
     110             :         krb5_err(context, 1, ret, "krb5_kt_start_seq_get");
     111             :     while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
     112             :         krb5_unparse_name(context, entry.principal, &principal);
     113             :         printf("principal: %s\n", principal);
     114             :         free(principal);
     115             :         krb5_kt_free_entry(context, &entry);
     116             :     }
     117             :     ret = krb5_kt_end_seq_get(context, keytab, &cursor);
     118             :     if (ret)
     119             :         krb5_err(context, 1, ret, "krb5_kt_end_seq_get");
     120             :     ret = krb5_kt_close(context, keytab);
     121             :     if (ret)
     122             :         krb5_err(context, 1, ret, "krb5_kt_close");
     123             :     krb5_free_context(context);
     124             :     return 0;
     125             : }
     126             :  * @endcode
     127             :  *
     128             :  */
     129             : 
     130             : 
     131             : /**
     132             :  * Register a new keytab backend.
     133             :  *
     134             :  * @param context a Keberos context.
     135             :  * @param ops a backend to register.
     136             :  *
     137             :  * @return Return an error code or 0, see krb5_get_error_message().
     138             :  *
     139             :  * @ingroup krb5_keytab
     140             :  */
     141             : 
     142             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     143     4752117 : krb5_kt_register(krb5_context context,
     144             :                  const krb5_kt_ops *ops)
     145             : {
     146      117068 :     struct krb5_keytab_data *tmp;
     147             : 
     148     4752117 :     if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) {
     149           0 :         krb5_set_error_message(context, KRB5_KT_BADNAME,
     150           0 :                                N_("can't register cache type, prefix too long", ""));
     151           0 :         return KRB5_KT_BADNAME;
     152             :     }
     153             : 
     154     4752117 :     tmp = realloc(context->kt_types,
     155     4752117 :                   (context->num_kt_types + 1) * sizeof(*context->kt_types));
     156     4752117 :     if(tmp == NULL)
     157           0 :         return krb5_enomem(context);
     158     4752117 :     memcpy(&tmp[context->num_kt_types], ops,
     159             :            sizeof(tmp[context->num_kt_types]));
     160     4752117 :     context->kt_types = tmp;
     161     4752117 :     context->num_kt_types++;
     162     4752117 :     return 0;
     163             : }
     164             : 
     165             : static const char *
     166      227124 : keytab_name(const char *name, const char **type, size_t *type_len)
     167             : {
     168        7000 :     const char *residual;
     169             : 
     170      227124 :     residual = strchr(name, ':');
     171             : 
     172      227124 :     if (residual == NULL ||
     173      227117 :         ISPATHSEP(name[0])
     174             : #ifdef _WIN32
     175             :         /* Avoid treating <drive>:<path> as a keytab type
     176             :          * specification */
     177             :         || name + 1 == residual
     178             : #endif
     179             :         ) {
     180             : 
     181           7 :         *type = "FILE";
     182           7 :         *type_len = strlen(*type);
     183           7 :         residual = name;
     184             :     } else {
     185      227117 :         *type = name;
     186      227117 :         *type_len = residual - name;
     187      227117 :         residual++;
     188             :     }
     189             : 
     190      227124 :     return residual;
     191             : }
     192             : 
     193             : /**
     194             :  * Resolve the keytab name (of the form `type:residual') in `name'
     195             :  * into a keytab in `id'.
     196             :  *
     197             :  * @param context a Keberos context.
     198             :  * @param name name to resolve
     199             :  * @param id resulting keytab, free with krb5_kt_close().
     200             :  *
     201             :  * @return Return an error code or 0, see krb5_get_error_message().
     202             :  *
     203             :  * @ingroup krb5_keytab
     204             :  */
     205             : 
     206             : 
     207             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     208      227124 : krb5_kt_resolve(krb5_context context,
     209             :                 const char *name,
     210             :                 krb5_keytab *id)
     211             : {
     212        7000 :     krb5_keytab k;
     213        7000 :     int i;
     214        7000 :     const char *type, *residual;
     215        7000 :     size_t type_len;
     216        7000 :     krb5_error_code ret;
     217             : 
     218      227124 :     residual = keytab_name(name, &type, &type_len);
     219             : 
     220      251965 :     for(i = 0; i < context->num_kt_types; i++) {
     221      244965 :         if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
     222      220124 :             break;
     223             :     }
     224      227124 :     if(i == context->num_kt_types) {
     225           0 :         krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE,
     226           0 :                                N_("unknown keytab type %.*s", "type"),
     227             :                                (int)type_len, type);
     228           0 :         return KRB5_KT_UNKNOWN_TYPE;
     229             :     }
     230             : 
     231      227124 :     k = malloc (sizeof(*k));
     232      227124 :     if (k == NULL)
     233           0 :         return krb5_enomem(context);
     234      227124 :     memcpy(k, &context->kt_types[i], sizeof(*k));
     235      227124 :     k->data = NULL;
     236      227124 :     ret = (*k->resolve)(context, residual, k);
     237      227124 :     if(ret) {
     238           0 :         free(k);
     239           0 :         k = NULL;
     240             :     }
     241      227124 :     *id = k;
     242      227124 :     return ret;
     243             : }
     244             : 
     245             : /*
     246             :  * Default ktname from context with possible environment
     247             :  * override
     248             :  */
     249           1 : static const char *default_ktname(krb5_context context)
     250             : {
     251           1 :     const char *tmp = NULL;
     252             : 
     253           2 :     tmp = secure_getenv("KRB5_KTNAME");
     254           1 :     if(tmp != NULL)
     255           0 :         return tmp;
     256           1 :     return context->default_keytab;
     257             : }
     258             : 
     259             : /**
     260             :  * copy the name of the default keytab into `name'.
     261             :  *
     262             :  * @param context a Keberos context.
     263             :  * @param name buffer where the name will be written
     264             :  * @param namesize length of name
     265             :  *
     266             :  * @return Return an error code or 0, see krb5_get_error_message().
     267             :  *
     268             :  * @ingroup krb5_keytab
     269             :  */
     270             : 
     271             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     272           1 : krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
     273             : {
     274           2 :     if (strlcpy (name, default_ktname(context), namesize) >= namesize) {
     275           0 :         krb5_clear_error_message (context);
     276           0 :         return KRB5_CONFIG_NOTENUFSPACE;
     277             :     }
     278           0 :     return 0;
     279             : }
     280             : 
     281             : /**
     282             :  * Copy the name of the default modify keytab into `name'.
     283             :  *
     284             :  * @param context a Keberos context.
     285             :  * @param name buffer where the name will be written
     286             :  * @param namesize length of name
     287             :  *
     288             :  * @return Return an error code or 0, see krb5_get_error_message().
     289             :  *
     290             :  * @ingroup krb5_keytab
     291             :  */
     292             : 
     293             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     294           0 : krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
     295             : {
     296           0 :     const char *kt;
     297             : 
     298           0 :     if(context->default_keytab_modify == NULL) {
     299           0 :         kt = default_ktname(context);
     300             : 
     301           0 :         if (strncasecmp(kt, "ANY:", 4) == 0) {
     302           0 :             size_t len = strcspn(kt + 4, ",");
     303           0 :             if (len >= namesize) {
     304           0 :                 krb5_clear_error_message(context);
     305           0 :                 return KRB5_CONFIG_NOTENUFSPACE;
     306             :             }
     307           0 :             strlcpy(name, kt + 4, namesize);
     308           0 :             name[len] = '\0';
     309           0 :             return 0;
     310             :         }
     311             :     } else
     312           0 :         kt = context->default_keytab_modify;
     313           0 :     if (strlcpy (name, kt, namesize) >= namesize) {
     314           0 :         krb5_clear_error_message (context);
     315           0 :         return KRB5_CONFIG_NOTENUFSPACE;
     316             :     }
     317           0 :     return 0;
     318             : }
     319             : 
     320             : /**
     321             :  * Set `id' to the default keytab.
     322             :  *
     323             :  * @param context a Keberos context.
     324             :  * @param id the new default keytab.
     325             :  *
     326             :  * @return Return an error code or 0, see krb5_get_error_message().
     327             :  *
     328             :  * @ingroup krb5_keytab
     329             :  */
     330             : 
     331             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     332           0 : krb5_kt_default(krb5_context context, krb5_keytab *id)
     333             : {
     334           0 :     return krb5_kt_resolve (context, default_ktname(context), id);
     335             : }
     336             : 
     337             : /**
     338             :  * Read the key identified by `(principal, vno, enctype)' from the
     339             :  * keytab in `keyprocarg' (the default if == NULL) into `*key'.
     340             :  *
     341             :  * @param context a Keberos context.
     342             :  * @param keyprocarg
     343             :  * @param principal
     344             :  * @param vno
     345             :  * @param enctype
     346             :  * @param key
     347             :  *
     348             :  * @return Return an error code or 0, see krb5_get_error_message().
     349             :  *
     350             :  * @ingroup krb5_keytab
     351             :  */
     352             : 
     353             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     354           0 : krb5_kt_read_service_key(krb5_context context,
     355             :                          krb5_pointer keyprocarg,
     356             :                          krb5_principal principal,
     357             :                          krb5_kvno vno,
     358             :                          krb5_enctype enctype,
     359             :                          krb5_keyblock **key)
     360             : {
     361           0 :     krb5_keytab keytab = NULL; /* Quiet lint */
     362           0 :     krb5_keytab_entry entry;
     363           0 :     krb5_error_code ret;
     364             : 
     365           0 :     memset(&entry, 0, sizeof(entry));
     366           0 :     if (keyprocarg)
     367           0 :         ret = krb5_kt_resolve (context, keyprocarg, &keytab);
     368             :     else
     369           0 :         ret = krb5_kt_default (context, &keytab);
     370             : 
     371           0 :     if (ret)
     372           0 :         return ret;
     373             : 
     374           0 :     ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
     375           0 :     if (ret == 0) {
     376           0 :         ret = krb5_copy_keyblock (context, &entry.keyblock, key);
     377           0 :         krb5_kt_free_entry(context, &entry);
     378             :     }
     379           0 :     krb5_kt_close (context, keytab);
     380           0 :     return ret;
     381             : }
     382             : 
     383             : /**
     384             :  * Return the type of the `keytab' in the string `prefix of length
     385             :  * `prefixsize'.
     386             :  *
     387             :  * @param context a Keberos context.
     388             :  * @param keytab the keytab to get the prefix for
     389             :  * @param prefix prefix buffer
     390             :  * @param prefixsize length of prefix buffer
     391             :  *
     392             :  * @return Return an error code or 0, see krb5_get_error_message().
     393             :  *
     394             :  * @ingroup krb5_keytab
     395             :  */
     396             : 
     397             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     398      127639 : krb5_kt_get_type(krb5_context context,
     399             :                  krb5_keytab keytab,
     400             :                  char *prefix,
     401             :                  size_t prefixsize)
     402             : {
     403      127639 :     strlcpy(prefix, keytab->prefix, prefixsize);
     404      127639 :     return 0;
     405             : }
     406             : 
     407             : /**
     408             :  * Retrieve the name of the keytab `keytab' into `name', `namesize'
     409             :  *
     410             :  * @param context a Keberos context.
     411             :  * @param keytab the keytab to get the name for.
     412             :  * @param name name buffer.
     413             :  * @param namesize size of name buffer.
     414             :  *
     415             :  * @return Return an error code or 0, see krb5_get_error_message().
     416             :  *
     417             :  * @ingroup krb5_keytab
     418             :  */
     419             : 
     420             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     421      127639 : krb5_kt_get_name(krb5_context context,
     422             :                  krb5_keytab keytab,
     423             :                  char *name,
     424             :                  size_t namesize)
     425             : {
     426      127639 :     return (*keytab->get_name)(context, keytab, name, namesize);
     427             : }
     428             : 
     429             : /**
     430             :  * Retrieve the full name of the keytab `keytab' and store the name in
     431             :  * `str'.
     432             :  *
     433             :  * @param context a Keberos context.
     434             :  * @param keytab keytab to get name for.
     435             :  * @param str the name of the keytab name, usee krb5_xfree() to free
     436             :  *        the string.  On error, *str is set to NULL.
     437             :  *
     438             :  * @return Return an error code or 0, see krb5_get_error_message().
     439             :  *
     440             :  * @ingroup krb5_keytab
     441             :  */
     442             : 
     443             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     444      127639 : krb5_kt_get_full_name(krb5_context context,
     445             :                       krb5_keytab keytab,
     446             :                       char **str)
     447             : {
     448        4314 :     char type[KRB5_KT_PREFIX_MAX_LEN];
     449        4314 :     char name[MAXPATHLEN];
     450        4314 :     krb5_error_code ret;
     451             : 
     452      127639 :     *str = NULL;
     453             : 
     454      127639 :     ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
     455      127639 :     if (ret)
     456           0 :         return ret;
     457             : 
     458      127639 :     ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
     459      127639 :     if (ret)
     460           0 :         return ret;
     461             : 
     462      127639 :     if (asprintf(str, "%s:%s", type, name) == -1) {
     463           0 :         *str = NULL;
     464           0 :         return krb5_enomem(context);
     465             :     }
     466             : 
     467      123325 :     return 0;
     468             : }
     469             : 
     470             : /**
     471             :  * Finish using the keytab in `id'.  All resources will be released,
     472             :  * even on errors.
     473             :  *
     474             :  * @param context a Keberos context.
     475             :  * @param id keytab to close.
     476             :  *
     477             :  * @return Return an error code or 0, see krb5_get_error_message().
     478             :  *
     479             :  * @ingroup krb5_keytab
     480             :  */
     481             : 
     482             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     483      227060 : krb5_kt_close(krb5_context context,
     484             :               krb5_keytab id)
     485             : {
     486      227060 :     krb5_error_code ret = 0;
     487             : 
     488      227060 :     if (id) {
     489      227046 :         ret = (id->close)(context, id);
     490      227046 :         memset(id, 0, sizeof(*id));
     491      227046 :         free(id);
     492             :     }
     493      227060 :     return ret;
     494             : }
     495             : 
     496             : /**
     497             :  * Destroy (remove) the keytab in `id'.  All resources will be released,
     498             :  * even on errors, does the equvalment of krb5_kt_close() on the resources.
     499             :  *
     500             :  * @param context a Keberos context.
     501             :  * @param id keytab to destroy.
     502             :  *
     503             :  * @return Return an error code or 0, see krb5_get_error_message().
     504             :  *
     505             :  * @ingroup krb5_keytab
     506             :  */
     507             : 
     508             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     509           0 : krb5_kt_destroy(krb5_context context,
     510             :                 krb5_keytab id)
     511             : {
     512           0 :     krb5_error_code ret;
     513             : 
     514           0 :     ret = (*id->destroy)(context, id);
     515           0 :     krb5_kt_close(context, id);
     516           0 :     return ret;
     517             : }
     518             : 
     519             : /*
     520             :  * Match any aliases in keytab `entry' with `principal'.
     521             :  */
     522             : 
     523             : static krb5_boolean
     524      151329 : compare_aliases(krb5_context context,
     525             :                  krb5_keytab_entry *entry,
     526             :                  krb5_const_principal principal)
     527             : {
     528        3371 :     unsigned int i;
     529      151329 :     if (entry->aliases == NULL)
     530      147958 :         return FALSE;
     531           0 :     for (i = 0; i < entry->aliases->len; i++)
     532           0 :         if (krb5_principal_compare(context, &entry->aliases->val[i], principal))
     533           0 :             return TRUE;
     534           0 :     return FALSE;
     535             : }
     536             : 
     537             : /**
     538             :  * Compare `entry' against `principal, vno, enctype'.
     539             :  * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
     540             :  * Return TRUE if they compare the same, FALSE otherwise.
     541             :  *
     542             :  * @param context a Keberos context.
     543             :  * @param entry an entry to match with.
     544             :  * @param principal principal to match, NULL matches all principals.
     545             :  * @param vno key version to match, 0 matches all key version numbers.
     546             :  * @param enctype encryption type to match, 0 matches all encryption types.
     547             :  *
     548             :  * @return Return TRUE or match, FALSE if not matched.
     549             :  *
     550             :  * @ingroup krb5_keytab
     551             :  */
     552             : 
     553             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     554      218360 : krb5_kt_compare(krb5_context context,
     555             :                 krb5_keytab_entry *entry,
     556             :                 krb5_const_principal principal,
     557             :                 krb5_kvno vno,
     558             :                 krb5_enctype enctype)
     559             : {
     560             :     /* krb5_principal_compare() does not special-case the referral realm */
     561      218360 :     if (principal != NULL && strcmp(principal->realm, "") == 0 &&
     562           0 :         !(krb5_principal_compare_any_realm(context, entry->principal, principal) ||
     563           0 :           compare_aliases(context, entry, principal))) {
     564           0 :         return FALSE;
     565      436720 :     } else if (principal != NULL && strcmp(principal->realm, "") != 0 &&
     566      369689 :         !(krb5_principal_compare(context, entry->principal, principal) ||
     567      151329 :           compare_aliases(context, entry, principal))) {
     568      147958 :         return FALSE;
     569             :     }
     570       67031 :     if (vno && vno != entry->vno)
     571        1044 :         return FALSE;
     572       65830 :     if (enctype && enctype != entry->keyblock.keytype)
     573       10253 :         return FALSE;
     574       54496 :     return TRUE;
     575             : }
     576             : 
     577             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     578         903 : _krb5_kt_principal_not_found(krb5_context context,
     579             :                              krb5_error_code ret,
     580             :                              krb5_keytab id,
     581             :                              krb5_const_principal principal,
     582             :                              krb5_enctype enctype,
     583             :                              int kvno)
     584             : {
     585           0 :     char kvno_str[25];
     586         903 :     char *enctype_str = NULL;
     587         903 :     char *kt_name = NULL;
     588         903 :     char *princ = NULL;
     589             : 
     590         903 :     (void) krb5_unparse_name(context, principal, &princ);
     591         903 :     (void) krb5_kt_get_full_name(context, id, &kt_name);
     592         903 :     if (enctype)
     593         903 :         (void) krb5_enctype_to_string(context, enctype, &enctype_str);
     594             : 
     595         903 :     if (kvno)
     596         903 :         snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
     597             :     else
     598           0 :         kvno_str[0] = '\0';
     599             : 
     600        2709 :     krb5_set_error_message(context, ret,
     601         903 :                            N_("Failed to find %s%s in keytab %s (%s)",
     602             :                               "principal, kvno, keytab file, enctype"),
     603         903 :                            princ ? princ : "<unknown>",
     604             :                            kvno_str,
     605         903 :                            kt_name ? kt_name : "unknown keytab",
     606         903 :                            enctype_str ? enctype_str : "unknown enctype");
     607         903 :     free(princ);
     608         903 :     free(kt_name);
     609         903 :     free(enctype_str);
     610         903 :     return ret;
     611             : }
     612             : 
     613             : static krb5_error_code
     614       53483 : krb5_kt_get_entry_wrapped(krb5_context context,
     615             :                           krb5_keytab id,
     616             :                           krb5_const_principal principal,
     617             :                           krb5_kvno kvno,
     618             :                           krb5_enctype enctype,
     619             :                           krb5_keytab_entry *entry)
     620             : {
     621         881 :     krb5_keytab_entry tmp;
     622         881 :     krb5_error_code ret;
     623         881 :     krb5_kt_cursor cursor;
     624             : 
     625       53483 :     if(id->get)
     626          68 :         return (*id->get)(context, id, principal, kvno, enctype, entry);
     627             : 
     628       53415 :     memset(&tmp, 0, sizeof(tmp));
     629       53415 :     ret = krb5_kt_start_seq_get (context, id, &cursor);
     630       53415 :     if (ret) {
     631             :         /* This is needed for krb5_verify_init_creds, but keep error
     632             :          * string from previous error for the human. */
     633           0 :         context->error_code = KRB5_KT_NOTFOUND;
     634           0 :         return KRB5_KT_NOTFOUND;
     635             :     }
     636             : 
     637       53415 :     entry->vno = 0;
     638      185118 :     while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
     639      184201 :         if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
     640             :             /* the file keytab might only store the lower 8 bits of
     641             :                the kvno, so only compare those bits */
     642       52616 :             if (kvno == tmp.vno
     643         118 :                 || (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
     644       52498 :                 krb5_kt_copy_entry_contents (context, &tmp, entry);
     645       52498 :                 krb5_kt_free_entry (context, &tmp);
     646       52498 :                 krb5_kt_end_seq_get(context, id, &cursor);
     647       52498 :                 return 0;
     648         118 :             } else if (kvno == 0 && tmp.vno > entry->vno) {
     649          14 :                 if (entry->vno)
     650           0 :                     krb5_kt_free_entry (context, entry);
     651          14 :                 krb5_kt_copy_entry_contents (context, &tmp, entry);
     652             :             }
     653             :         }
     654      131703 :         krb5_kt_free_entry(context, &tmp);
     655             :     }
     656         917 :     krb5_kt_end_seq_get (context, id, &cursor);
     657         917 :     if (entry->vno == 0)
     658         903 :         return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
     659             :                                             id, principal, enctype, kvno);
     660          14 :     return 0;
     661             : }
     662             : 
     663             : /**
     664             :  * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
     665             :  * from the keytab `id'. Matching is done like krb5_kt_compare().
     666             :  *
     667             :  * @param context a Keberos context.
     668             :  * @param id a keytab.
     669             :  * @param principal principal to match, NULL matches all principals.
     670             :  * @param kvno key version to match, 0 matches all key version numbers.
     671             :  * @param enctype encryption type to match, 0 matches all encryption types.
     672             :  * @param entry the returned entry, free with krb5_kt_free_entry().
     673             :  *
     674             :  * @return Return an error code or 0, see krb5_get_error_message().
     675             :  *
     676             :  * @ingroup krb5_keytab
     677             :  */
     678             : 
     679             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     680       53483 : krb5_kt_get_entry(krb5_context context,
     681             :                   krb5_keytab id,
     682             :                   krb5_const_principal principal,
     683             :                   krb5_kvno kvno,
     684             :                   krb5_enctype enctype,
     685             :                   krb5_keytab_entry *entry)
     686             : {
     687         881 :     krb5_error_code ret;
     688         881 :     krb5_const_principal try_princ;
     689         881 :     krb5_name_canon_iterator name_canon_iter;
     690             : 
     691       53483 :     if (!principal)
     692             :         /* Use `NULL' instead of `principal' to quiet static analizers */
     693           0 :         return krb5_kt_get_entry_wrapped(context, id, NULL, kvno, enctype,
     694             :                                          entry);
     695             : 
     696       53483 :     ret = krb5_name_canon_iterator_start(context, principal, &name_canon_iter);
     697       53483 :     if (ret)
     698           0 :         return ret;
     699             : 
     700         881 :     do {
     701       54390 :         ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ,
     702             :                                       NULL);
     703       54390 :         if (ret)
     704           0 :             break;
     705       54390 :         if (try_princ == NULL) {
     706         907 :             ret = KRB5_KT_NOTFOUND;
     707         907 :             continue;
     708             :         }
     709       53483 :         ret = krb5_kt_get_entry_wrapped(context, id, try_princ, kvno,
     710             :                                         enctype, entry);
     711       54390 :     } while (ret == KRB5_KT_NOTFOUND && name_canon_iter);
     712             : 
     713       53483 :     if (ret && ret != KRB5_KT_NOTFOUND)
     714           0 :         krb5_set_error_message(context, ret,
     715           0 :                                N_("Name canon failed while searching keytab",
     716             :                                   ""));
     717       53483 :     krb5_free_name_canon_iterator(context, name_canon_iter);
     718       53483 :     return ret;
     719             : }
     720             : 
     721             : /**
     722             :  * Copy the contents of `in' into `out'.
     723             :  *
     724             :  * @param context a Keberos context.
     725             :  * @param in the keytab entry to copy.
     726             :  * @param out the copy of the keytab entry, free with krb5_kt_free_entry().
     727             :  *
     728             :  * @return Return an error code or 0, see krb5_get_error_message().
     729             :  *
     730             :  * @ingroup krb5_keytab
     731             :  */
     732             : 
     733             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     734       75617 : krb5_kt_copy_entry_contents(krb5_context context,
     735             :                             const krb5_keytab_entry *in,
     736             :                             krb5_keytab_entry *out)
     737             : {
     738         983 :     krb5_error_code ret;
     739             : 
     740       75617 :     memset(out, 0, sizeof(*out));
     741             : 
     742       75617 :     ret = krb5_copy_principal (context, in->principal, &out->principal);
     743       75617 :     if (ret)
     744           0 :         return ret;
     745       75617 :     ret = krb5_copy_keyblock_contents (context,
     746             :                                        &in->keyblock,
     747             :                                        &out->keyblock);
     748       75617 :     if (ret) {
     749           0 :         krb5_free_principal(context, out->principal);
     750           0 :         memset(out, 0, sizeof(*out));
     751           0 :         return ret;
     752             :     }
     753       75617 :     out->vno = in->vno;
     754       75617 :     out->timestamp = in->timestamp;
     755       75617 :     return 0;
     756             : }
     757             : 
     758             : /**
     759             :  * Free the contents of `entry'.
     760             :  *
     761             :  * @param context a Keberos context.
     762             :  * @param entry the entry to free
     763             :  *
     764             :  * @return Return an error code or 0, see krb5_get_error_message().
     765             :  *
     766             :  * @ingroup krb5_keytab
     767             :  */
     768             : 
     769             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     770      287522 : krb5_kt_free_entry(krb5_context context,
     771             :                    krb5_keytab_entry *entry)
     772             : {
     773      287522 :     krb5_free_principal (context, entry->principal);
     774      287522 :     krb5_free_keyblock_contents (context, &entry->keyblock);
     775      287522 :     memset(entry, 0, sizeof(*entry));
     776      287522 :     return 0;
     777             : }
     778             : 
     779             : /**
     780             :  * Set `cursor' to point at the beginning of `id'.
     781             :  *
     782             :  * @param context a Keberos context.
     783             :  * @param id a keytab.
     784             :  * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get().
     785             :  *
     786             :  * @return Return an error code or 0, see krb5_get_error_message().
     787             :  *
     788             :  * @ingroup krb5_keytab
     789             :  */
     790             : 
     791             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     792       60314 : krb5_kt_start_seq_get(krb5_context context,
     793             :                       krb5_keytab id,
     794             :                       krb5_kt_cursor *cursor)
     795             : {
     796       60314 :     if(id->start_seq_get == NULL) {
     797           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     798           0 :                                N_("start_seq_get is not supported "
     799             :                                   "in the %s keytab type", ""),
     800             :                                id->prefix);
     801           0 :         return HEIM_ERR_OPNOTSUPP;
     802             :     }
     803       60314 :     return (*id->start_seq_get)(context, id, cursor);
     804             : }
     805             : 
     806             : /**
     807             :  * Get the next entry from keytab, advance the cursor.  On last entry
     808             :  * the function will return KRB5_KT_END.
     809             :  *
     810             :  * @param context a Keberos context.
     811             :  * @param id a keytab.
     812             :  * @param entry the returned entry, free with krb5_kt_free_entry().
     813             :  * @param cursor the cursor of the iteration.
     814             :  *
     815             :  * @return Return an error code or 0, see krb5_get_error_message().
     816             :  *
     817             :  * @ingroup krb5_keytab
     818             :  */
     819             : 
     820             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     821      216569 : krb5_kt_next_entry(krb5_context context,
     822             :                    krb5_keytab id,
     823             :                    krb5_keytab_entry *entry,
     824             :                    krb5_kt_cursor *cursor)
     825             : {
     826      216569 :     if(id->next_entry == NULL) {
     827           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     828           0 :                                N_("next_entry is not supported in the %s "
     829             :                                   " keytab", ""),
     830             :                                id->prefix);
     831           0 :         return HEIM_ERR_OPNOTSUPP;
     832             :     }
     833      216569 :     memset(entry, 0x0, sizeof(*entry));
     834      216569 :     return (*id->next_entry)(context, id, entry, cursor);
     835             : }
     836             : 
     837             : /**
     838             :  * Release all resources associated with `cursor'.
     839             :  *
     840             :  * @param context a Keberos context.
     841             :  * @param id a keytab.
     842             :  * @param cursor the cursor to free.
     843             :  *
     844             :  * @return Return an error code or 0, see krb5_get_error_message().
     845             :  *
     846             :  * @ingroup krb5_keytab
     847             :  */
     848             : 
     849             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     850       60460 : krb5_kt_end_seq_get(krb5_context context,
     851             :                     krb5_keytab id,
     852             :                     krb5_kt_cursor *cursor)
     853             : {
     854       60460 :     if(id->end_seq_get == NULL) {
     855           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     856             :                                "end_seq_get is not supported in the %s "
     857             :                                " keytab", id->prefix);
     858           0 :         return HEIM_ERR_OPNOTSUPP;
     859             :     }
     860       60460 :     return (*id->end_seq_get)(context, id, cursor);
     861             : }
     862             : 
     863             : /**
     864             :  * Add the entry in `entry' to the keytab `id'.
     865             :  *
     866             :  * @param context a Keberos context.
     867             :  * @param id a keytab.
     868             :  * @param entry the entry to add
     869             :  *
     870             :  * @return Return an error code or 0, see krb5_get_error_message().
     871             :  *
     872             :  * @ingroup krb5_keytab
     873             :  */
     874             : 
     875             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     876       18233 : krb5_kt_add_entry(krb5_context context,
     877             :                   krb5_keytab id,
     878             :                   krb5_keytab_entry *entry)
     879             : {
     880       18233 :     if(id->add == NULL) {
     881           0 :         krb5_set_error_message(context, KRB5_KT_NOWRITE,
     882           0 :                                N_("Add is not supported in the %s keytab", ""),
     883             :                                id->prefix);
     884           0 :         return KRB5_KT_NOWRITE;
     885             :     }
     886       18233 :     if (entry->timestamp == 0)
     887       16893 :         entry->timestamp = time(NULL);
     888       18233 :     return (*id->add)(context, id,entry);
     889             : }
     890             : 
     891             : /**
     892             :  * Remove an entry from the keytab, matching is done using
     893             :  * krb5_kt_compare().
     894             : 
     895             :  * @param context a Keberos context.
     896             :  * @param id a keytab.
     897             :  * @param entry the entry to remove
     898             :  *
     899             :  * @return Return an error code or 0, see krb5_get_error_message().
     900             :  *
     901             :  * @ingroup krb5_keytab
     902             :  */
     903             : 
     904             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     905         525 : krb5_kt_remove_entry(krb5_context context,
     906             :                      krb5_keytab id,
     907             :                      krb5_keytab_entry *entry)
     908             : {
     909         525 :     if(id->remove == NULL) {
     910           0 :         krb5_set_error_message(context, KRB5_KT_NOWRITE,
     911           0 :                                N_("Remove is not supported in the %s keytab", ""),
     912             :                                id->prefix);
     913           0 :         return KRB5_KT_NOWRITE;
     914             :     }
     915         525 :     return (*id->remove)(context, id, entry);
     916             : }
     917             : 
     918             : /**
     919             :  * Return true if the keytab exists and have entries
     920             :  *
     921             :  * @param context a Keberos context.
     922             :  * @param id a keytab.
     923             :  *
     924             :  * @return Return an error code or 0, see krb5_get_error_message().
     925             :  *
     926             :  * @ingroup krb5_keytab
     927             :  */
     928             : 
     929             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     930           0 : krb5_kt_have_content(krb5_context context,
     931             :                      krb5_keytab id)
     932             : {
     933           0 :     krb5_keytab_entry entry;
     934           0 :     krb5_kt_cursor cursor;
     935           0 :     krb5_error_code ret;
     936           0 :     char *name;
     937             : 
     938           0 :     memset(&entry, 0, sizeof(entry));
     939           0 :     ret = krb5_kt_start_seq_get(context, id, &cursor);
     940           0 :     if (ret)
     941           0 :         goto notfound;
     942             : 
     943           0 :     ret = krb5_kt_next_entry(context, id, &entry, &cursor);
     944           0 :     krb5_kt_end_seq_get(context, id, &cursor);
     945           0 :     if (ret)
     946           0 :         goto notfound;
     947             : 
     948           0 :     krb5_kt_free_entry(context, &entry);
     949             : 
     950           0 :     return 0;
     951             : 
     952           0 :  notfound:
     953           0 :     ret = krb5_kt_get_full_name(context, id, &name);
     954           0 :     if (ret == 0) {
     955           0 :         krb5_set_error_message(context, KRB5_KT_NOTFOUND,
     956           0 :                                N_("No entry in keytab: %s", ""), name);
     957           0 :         free(name);
     958             :     }
     959           0 :     return KRB5_KT_NOTFOUND;
     960             : }
     961             : 
     962             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     963           0 : _krb5_kt_client_default_name(krb5_context context, char **name)
     964             : {
     965           0 :     const char *tmp;
     966             : 
     967           0 :     tmp = secure_getenv("KRB5_CLIENT_KTNAME");
     968           0 :     if (tmp == NULL)
     969           0 :         tmp =  krb5_config_get_string(context, NULL,
     970             :                                       "libdefaults",
     971             :                                       "default_client_keytab_name", NULL);
     972           0 :     if (tmp == NULL)
     973           0 :         tmp = CLIENT_KEYTAB_DEFAULT;
     974             : 
     975           0 :     return _krb5_expand_path_tokens(context, tmp, 1, name);
     976             : }

Generated by: LCOV version 1.14