LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - keytab.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 133 234 56.8 %
Date: 2021-09-23 10:06:22 Functions: 20 25 80.0 %

          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     5452526 : krb5_kt_register(krb5_context context,
     144             :                  const krb5_kt_ops *ops)
     145             : {
     146             :     struct krb5_keytab_data *tmp;
     147             : 
     148     5452526 :     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     5452526 :     tmp = realloc(context->kt_types,
     155     5452526 :                   (context->num_kt_types + 1) * sizeof(*context->kt_types));
     156     5452526 :     if(tmp == NULL) {
     157           0 :         krb5_set_error_message(context, ENOMEM,
     158           0 :                                N_("malloc: out of memory", ""));
     159           0 :         return ENOMEM;
     160             :     }
     161     5538250 :     memcpy(&tmp[context->num_kt_types], ops,
     162             :            sizeof(tmp[context->num_kt_types]));
     163     5452526 :     context->kt_types = tmp;
     164     5452526 :     context->num_kt_types++;
     165     5452526 :     return 0;
     166             : }
     167             : 
     168             : static const char *
     169      190654 : keytab_name(const char *name, const char **type, size_t *type_len)
     170             : {
     171             :     const char *residual;
     172             : 
     173      190654 :     residual = strchr(name, ':');
     174             : 
     175      381301 :     if (residual == NULL ||
     176      190647 :         name[0] == '/'
     177             : #ifdef _WIN32
     178             :         /* Avoid treating <drive>:<path> as a keytab type
     179             :          * specification */
     180             :         || name + 1 == residual
     181             : #endif
     182             :         ) {
     183             : 
     184           7 :         *type = "FILE";
     185           7 :         *type_len = strlen(*type);
     186           7 :         residual = name;
     187             :     } else {
     188      190647 :         *type = name;
     189      190647 :         *type_len = residual - name;
     190      190647 :         residual++;
     191             :     }
     192             : 
     193      190654 :     return residual;
     194             : }
     195             : 
     196             : /**
     197             :  * Resolve the keytab name (of the form `type:residual') in `name'
     198             :  * into a keytab in `id'.
     199             :  *
     200             :  * @param context a Keberos context.
     201             :  * @param name name to resolve
     202             :  * @param id resulting keytab, free with krb5_kt_close().
     203             :  *
     204             :  * @return Return an error code or 0, see krb5_get_error_message().
     205             :  *
     206             :  * @ingroup krb5_keytab
     207             :  */
     208             : 
     209             : 
     210             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     211      190654 : krb5_kt_resolve(krb5_context context,
     212             :                 const char *name,
     213             :                 krb5_keytab *id)
     214             : {
     215             :     krb5_keytab k;
     216             :     int i;
     217             :     const char *type, *residual;
     218             :     size_t type_len;
     219             :     krb5_error_code ret;
     220             : 
     221      190654 :     residual = keytab_name(name, &type, &type_len);
     222             : 
     223      202933 :     for(i = 0; i < context->num_kt_types; i++) {
     224      202933 :         if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
     225      185323 :             break;
     226             :     }
     227      190654 :     if(i == context->num_kt_types) {
     228           0 :         krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE,
     229           0 :                                N_("unknown keytab type %.*s", "type"),
     230             :                                (int)type_len, type);
     231           0 :         return KRB5_KT_UNKNOWN_TYPE;
     232             :     }
     233             : 
     234      190654 :     k = malloc (sizeof(*k));
     235      190654 :     if (k == NULL) {
     236           0 :         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
     237           0 :         return ENOMEM;
     238             :     }
     239      195985 :     memcpy(k, &context->kt_types[i], sizeof(*k));
     240      190654 :     k->data = NULL;
     241      190654 :     ret = (*k->resolve)(context, residual, k);
     242      190654 :     if(ret) {
     243           0 :         free(k);
     244           0 :         k = NULL;
     245             :     }
     246      190654 :     *id = k;
     247      190654 :     return ret;
     248             : }
     249             : 
     250             : /**
     251             :  * copy the name of the default keytab into `name'.
     252             :  *
     253             :  * @param context a Keberos context.
     254             :  * @param name buffer where the name will be written
     255             :  * @param namesize length of name
     256             :  *
     257             :  * @return Return an error code or 0, see krb5_get_error_message().
     258             :  *
     259             :  * @ingroup krb5_keytab
     260             :  */
     261             : 
     262             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     263           1 : krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
     264             : {
     265           1 :     if (strlcpy (name, context->default_keytab, namesize) >= namesize) {
     266           0 :         krb5_clear_error_message (context);
     267           0 :         return KRB5_CONFIG_NOTENUFSPACE;
     268             :     }
     269           0 :     return 0;
     270             : }
     271             : 
     272             : /**
     273             :  * Copy the name of the default modify keytab into `name'.
     274             :  *
     275             :  * @param context a Keberos context.
     276             :  * @param name buffer where the name will be written
     277             :  * @param namesize length of name
     278             :  *
     279             :  * @return Return an error code or 0, see krb5_get_error_message().
     280             :  *
     281             :  * @ingroup krb5_keytab
     282             :  */
     283             : 
     284             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     285           0 : krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
     286             : {
     287           0 :     const char *kt = NULL;
     288           0 :     if(context->default_keytab_modify == NULL) {
     289           0 :         if(strncasecmp(context->default_keytab, "ANY:", 4) != 0)
     290           0 :             kt = context->default_keytab;
     291             :         else {
     292           0 :             size_t len = strcspn(context->default_keytab + 4, ",");
     293           0 :             if(len >= namesize) {
     294           0 :                 krb5_clear_error_message(context);
     295           0 :                 return KRB5_CONFIG_NOTENUFSPACE;
     296             :             }
     297           0 :             strlcpy(name, context->default_keytab + 4, namesize);
     298           0 :             name[len] = '\0';
     299           0 :             return 0;
     300             :         }
     301             :     } else
     302           0 :         kt = context->default_keytab_modify;
     303           0 :     if (strlcpy (name, kt, namesize) >= namesize) {
     304           0 :         krb5_clear_error_message (context);
     305           0 :         return KRB5_CONFIG_NOTENUFSPACE;
     306             :     }
     307           0 :     return 0;
     308             : }
     309             : 
     310             : /**
     311             :  * Set `id' to the default keytab.
     312             :  *
     313             :  * @param context a Keberos context.
     314             :  * @param id the new default keytab.
     315             :  *
     316             :  * @return Return an error code or 0, see krb5_get_error_message().
     317             :  *
     318             :  * @ingroup krb5_keytab
     319             :  */
     320             : 
     321             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     322           0 : krb5_kt_default(krb5_context context, krb5_keytab *id)
     323             : {
     324           0 :     return krb5_kt_resolve (context, context->default_keytab, id);
     325             : }
     326             : 
     327             : /**
     328             :  * Read the key identified by `(principal, vno, enctype)' from the
     329             :  * keytab in `keyprocarg' (the default if == NULL) into `*key'.
     330             :  *
     331             :  * @param context a Keberos context.
     332             :  * @param keyprocarg
     333             :  * @param principal
     334             :  * @param vno
     335             :  * @param enctype
     336             :  * @param key
     337             :  *
     338             :  * @return Return an error code or 0, see krb5_get_error_message().
     339             :  *
     340             :  * @ingroup krb5_keytab
     341             :  */
     342             : 
     343             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     344           0 : krb5_kt_read_service_key(krb5_context context,
     345             :                          krb5_pointer keyprocarg,
     346             :                          krb5_principal principal,
     347             :                          krb5_kvno vno,
     348             :                          krb5_enctype enctype,
     349             :                          krb5_keyblock **key)
     350             : {
     351             :     krb5_keytab keytab;
     352             :     krb5_keytab_entry entry;
     353             :     krb5_error_code ret;
     354             : 
     355           0 :     if (keyprocarg)
     356           0 :         ret = krb5_kt_resolve (context, keyprocarg, &keytab);
     357             :     else
     358           0 :         ret = krb5_kt_default (context, &keytab);
     359             : 
     360           0 :     if (ret)
     361           0 :         return ret;
     362             : 
     363           0 :     ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
     364           0 :     krb5_kt_close (context, keytab);
     365           0 :     if (ret)
     366           0 :         return ret;
     367           0 :     ret = krb5_copy_keyblock (context, &entry.keyblock, key);
     368           0 :     krb5_kt_free_entry(context, &entry);
     369           0 :     return ret;
     370             : }
     371             : 
     372             : /**
     373             :  * Return the type of the `keytab' in the string `prefix of length
     374             :  * `prefixsize'.
     375             :  *
     376             :  * @param context a Keberos context.
     377             :  * @param keytab the keytab to get the prefix for
     378             :  * @param prefix prefix buffer
     379             :  * @param prefixsize length of prefix buffer
     380             :  *
     381             :  * @return Return an error code or 0, see krb5_get_error_message().
     382             :  *
     383             :  * @ingroup krb5_keytab
     384             :  */
     385             : 
     386             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     387      109164 : krb5_kt_get_type(krb5_context context,
     388             :                  krb5_keytab keytab,
     389             :                  char *prefix,
     390             :                  size_t prefixsize)
     391             : {
     392      109164 :     strlcpy(prefix, keytab->prefix, prefixsize);
     393      109164 :     return 0;
     394             : }
     395             : 
     396             : /**
     397             :  * Retrieve the name of the keytab `keytab' into `name', `namesize'
     398             :  *
     399             :  * @param context a Keberos context.
     400             :  * @param keytab the keytab to get the name for.
     401             :  * @param name name buffer.
     402             :  * @param namesize size of name buffer.
     403             :  *
     404             :  * @return Return an error code or 0, see krb5_get_error_message().
     405             :  *
     406             :  * @ingroup krb5_keytab
     407             :  */
     408             : 
     409             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     410      109164 : krb5_kt_get_name(krb5_context context,
     411             :                  krb5_keytab keytab,
     412             :                  char *name,
     413             :                  size_t namesize)
     414             : {
     415      109164 :     return (*keytab->get_name)(context, keytab, name, namesize);
     416             : }
     417             : 
     418             : /**
     419             :  * Retrieve the full name of the keytab `keytab' and store the name in
     420             :  * `str'.
     421             :  *
     422             :  * @param context a Keberos context.
     423             :  * @param keytab keytab to get name for.
     424             :  * @param str the name of the keytab name, usee krb5_xfree() to free
     425             :  *        the string.  On error, *str is set to NULL.
     426             :  *
     427             :  * @return Return an error code or 0, see krb5_get_error_message().
     428             :  *
     429             :  * @ingroup krb5_keytab
     430             :  */
     431             : 
     432             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     433      109164 : krb5_kt_get_full_name(krb5_context context,
     434             :                       krb5_keytab keytab,
     435             :                       char **str)
     436             : {
     437             :     char type[KRB5_KT_PREFIX_MAX_LEN];
     438             :     char name[MAXPATHLEN];
     439             :     krb5_error_code ret;
     440             : 
     441      109164 :     *str = NULL;
     442             : 
     443      109164 :     ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
     444      109164 :     if (ret)
     445           0 :         return ret;
     446             : 
     447      109164 :     ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
     448      109164 :     if (ret)
     449           0 :         return ret;
     450             : 
     451      109164 :     if (asprintf(str, "%s:%s", type, name) == -1) {
     452           0 :         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
     453           0 :         *str = NULL;
     454           0 :         return ENOMEM;
     455             :     }
     456             : 
     457      105864 :     return 0;
     458             : }
     459             : 
     460             : /**
     461             :  * Finish using the keytab in `id'.  All resources will be released,
     462             :  * even on errors.
     463             :  *
     464             :  * @param context a Keberos context.
     465             :  * @param id keytab to close.
     466             :  *
     467             :  * @return Return an error code or 0, see krb5_get_error_message().
     468             :  *
     469             :  * @ingroup krb5_keytab
     470             :  */
     471             : 
     472             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     473      190578 : krb5_kt_close(krb5_context context,
     474             :               krb5_keytab id)
     475             : {
     476             :     krb5_error_code ret;
     477             : 
     478      190578 :     ret = (*id->close)(context, id);
     479      190578 :     memset(id, 0, sizeof(*id));
     480      190578 :     free(id);
     481      190578 :     return ret;
     482             : }
     483             : 
     484             : /**
     485             :  * Destroy (remove) the keytab in `id'.  All resources will be released,
     486             :  * even on errors, does the equvalment of krb5_kt_close() on the resources.
     487             :  *
     488             :  * @param context a Keberos context.
     489             :  * @param id keytab to destroy.
     490             :  *
     491             :  * @return Return an error code or 0, see krb5_get_error_message().
     492             :  *
     493             :  * @ingroup krb5_keytab
     494             :  */
     495             : 
     496             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     497           0 : krb5_kt_destroy(krb5_context context,
     498             :                 krb5_keytab id)
     499             : {
     500             :     krb5_error_code ret;
     501             : 
     502           0 :     ret = (*id->destroy)(context, id);
     503           0 :     krb5_kt_close(context, id);
     504           0 :     return ret;
     505             : }
     506             : 
     507             : /*
     508             :  * Match any aliases in keytab `entry' with `principal'.
     509             :  */
     510             : 
     511             : static krb5_boolean
     512      125021 : compare_aliseses(krb5_context context,
     513             :                  krb5_keytab_entry *entry,
     514             :                  krb5_const_principal principal)
     515             : {
     516             :     unsigned int i;
     517      125021 :     if (entry->aliases == NULL)
     518      122872 :         return FALSE;
     519           0 :     for (i = 0; i < entry->aliases->len; i++)
     520           0 :         if (krb5_principal_compare(context, &entry->aliases->val[i], principal))
     521           0 :             return TRUE;
     522           0 :     return FALSE;
     523             : }
     524             : 
     525             : /**
     526             :  * Compare `entry' against `principal, vno, enctype'.
     527             :  * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
     528             :  * Return TRUE if they compare the same, FALSE otherwise.
     529             :  *
     530             :  * @param context a Keberos context.
     531             :  * @param entry an entry to match with.
     532             :  * @param principal principal to match, NULL matches all principals.
     533             :  * @param vno key version to match, 0 matches all key version numbers.
     534             :  * @param enctype encryption type to match, 0 matches all encryption types.
     535             :  *
     536             :  * @return Return TRUE or match, FALSE if not matched.
     537             :  *
     538             :  * @ingroup krb5_keytab
     539             :  */
     540             : 
     541             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     542      181532 : krb5_kt_compare(krb5_context context,
     543             :                 krb5_keytab_entry *entry,
     544             :                 krb5_const_principal principal,
     545             :                 krb5_kvno vno,
     546             :                 krb5_enctype enctype)
     547             : {
     548      363064 :     if(principal != NULL &&
     549      306553 :        !(krb5_principal_compare(context, entry->principal, principal) ||
     550      125021 :          compare_aliseses(context, entry, principal)))
     551      122872 :         return FALSE;
     552       56511 :     if(vno && vno != entry->vno)
     553         351 :         return FALSE;
     554       56075 :     if(enctype && enctype != entry->keyblock.keytype)
     555        7532 :         return FALSE;
     556       48516 :     return TRUE;
     557             : }
     558             : 
     559             : krb5_error_code
     560         742 : _krb5_kt_principal_not_found(krb5_context context,
     561             :                              krb5_error_code ret,
     562             :                              krb5_keytab id,
     563             :                              krb5_const_principal principal,
     564             :                              krb5_enctype enctype,
     565             :                              int kvno)
     566             : {
     567             :     char princ[256], kvno_str[25], *kt_name;
     568         742 :     char *enctype_str = NULL;
     569             : 
     570         742 :     krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
     571         742 :     krb5_kt_get_full_name (context, id, &kt_name);
     572         742 :     krb5_enctype_to_string(context, enctype, &enctype_str);
     573             : 
     574         742 :     if (kvno)
     575         742 :         snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
     576             :     else
     577           0 :         kvno_str[0] = '\0';
     578             : 
     579        2226 :     krb5_set_error_message (context, ret,
     580         742 :                             N_("Failed to find %s%s in keytab %s (%s)",
     581             :                                "principal, kvno, keytab file, enctype"),
     582             :                             princ,
     583             :                             kvno_str,
     584         742 :                             kt_name ? kt_name : "unknown keytab",
     585         742 :                             enctype_str ? enctype_str : "unknown enctype");
     586         742 :     free(kt_name);
     587         742 :     free(enctype_str);
     588         742 :     return ret;
     589             : }
     590             : 
     591             : 
     592             : /**
     593             :  * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
     594             :  * from the keytab `id'. Matching is done like krb5_kt_compare().
     595             :  *
     596             :  * @param context a Keberos context.
     597             :  * @param id a keytab.
     598             :  * @param principal principal to match, NULL matches all principals.
     599             :  * @param kvno key version to match, 0 matches all key version numbers.
     600             :  * @param enctype encryption type to match, 0 matches all encryption types.
     601             :  * @param entry the returned entry, free with krb5_kt_free_entry().
     602             :  *
     603             :  * @return Return an error code or 0, see krb5_get_error_message().
     604             :  *
     605             :  * @ingroup krb5_keytab
     606             :  */
     607             : 
     608             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     609       46238 : krb5_kt_get_entry(krb5_context context,
     610             :                   krb5_keytab id,
     611             :                   krb5_const_principal principal,
     612             :                   krb5_kvno kvno,
     613             :                   krb5_enctype enctype,
     614             :                   krb5_keytab_entry *entry)
     615             : {
     616             :     krb5_keytab_entry tmp;
     617             :     krb5_error_code ret;
     618             :     krb5_kt_cursor cursor;
     619             : 
     620       46238 :     if(id->get)
     621          34 :         return (*id->get)(context, id, principal, kvno, enctype, entry);
     622             : 
     623       46204 :     ret = krb5_kt_start_seq_get (context, id, &cursor);
     624       46204 :     if (ret) {
     625             :         /* This is needed for krb5_verify_init_creds, but keep error
     626             :          * string from previous error for the human. */
     627           0 :         context->error_code = KRB5_KT_NOTFOUND;
     628           0 :         return KRB5_KT_NOTFOUND;
     629             :     }
     630             : 
     631       46204 :     entry->vno = 0;
     632      206962 :     while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
     633      160002 :         if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
     634             :             /* the file keytab might only store the lower 8 bits of
     635             :                the kvno, so only compare those bits */
     636       45566 :             if (kvno == tmp.vno
     637         118 :                 || (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
     638       45448 :                 krb5_kt_copy_entry_contents (context, &tmp, entry);
     639       45448 :                 krb5_kt_free_entry (context, &tmp);
     640       45448 :                 krb5_kt_end_seq_get(context, id, &cursor);
     641       45448 :                 return 0;
     642         118 :             } else if (kvno == 0 && tmp.vno > entry->vno) {
     643          14 :                 if (entry->vno)
     644           0 :                     krb5_kt_free_entry (context, entry);
     645          14 :                 krb5_kt_copy_entry_contents (context, &tmp, entry);
     646             :             }
     647             :         }
     648      114554 :         krb5_kt_free_entry(context, &tmp);
     649             :     }
     650         756 :     krb5_kt_end_seq_get (context, id, &cursor);
     651         756 :     if (entry->vno == 0)
     652         742 :         return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
     653             :                                             id, principal, enctype, kvno);
     654          14 :     return 0;
     655             : }
     656             : 
     657             : /**
     658             :  * Copy the contents of `in' into `out'.
     659             :  *
     660             :  * @param context a Keberos context.
     661             :  * @param in the keytab entry to copy.
     662             :  * @param out the copy of the keytab entry, free with krb5_kt_free_entry().
     663             :  *
     664             :  * @return Return an error code or 0, see krb5_get_error_message().
     665             :  *
     666             :  * @ingroup krb5_keytab
     667             :  */
     668             : 
     669             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     670       59776 : krb5_kt_copy_entry_contents(krb5_context context,
     671             :                             const krb5_keytab_entry *in,
     672             :                             krb5_keytab_entry *out)
     673             : {
     674             :     krb5_error_code ret;
     675             : 
     676       59776 :     memset(out, 0, sizeof(*out));
     677       59776 :     out->vno = in->vno;
     678             : 
     679       59776 :     ret = krb5_copy_principal (context, in->principal, &out->principal);
     680       59776 :     if (ret)
     681           0 :         goto fail;
     682       59776 :     ret = krb5_copy_keyblock_contents (context,
     683             :                                        &in->keyblock,
     684             :                                        &out->keyblock);
     685       59776 :     if (ret)
     686           0 :         goto fail;
     687       59776 :     out->timestamp = in->timestamp;
     688       59776 :     return 0;
     689           0 : fail:
     690           0 :     krb5_kt_free_entry (context, out);
     691           0 :     return ret;
     692             : }
     693             : 
     694             : /**
     695             :  * Free the contents of `entry'.
     696             :  *
     697             :  * @param context a Keberos context.
     698             :  * @param entry the entry to free
     699             :  *
     700             :  * @return Return an error code or 0, see krb5_get_error_message().
     701             :  *
     702             :  * @ingroup krb5_keytab
     703             :  */
     704             : 
     705             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     706      236203 : krb5_kt_free_entry(krb5_context context,
     707             :                    krb5_keytab_entry *entry)
     708             : {
     709      236203 :     krb5_free_principal (context, entry->principal);
     710      236203 :     krb5_free_keyblock_contents (context, &entry->keyblock);
     711      236203 :     memset(entry, 0, sizeof(*entry));
     712      236203 :     return 0;
     713             : }
     714             : 
     715             : /**
     716             :  * Set `cursor' to point at the beginning of `id'.
     717             :  *
     718             :  * @param context a Keberos context.
     719             :  * @param id a keytab.
     720             :  * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get().
     721             :  *
     722             :  * @return Return an error code or 0, see krb5_get_error_message().
     723             :  *
     724             :  * @ingroup krb5_keytab
     725             :  */
     726             : 
     727             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     728       49808 : krb5_kt_start_seq_get(krb5_context context,
     729             :                       krb5_keytab id,
     730             :                       krb5_kt_cursor *cursor)
     731             : {
     732       49808 :     if(id->start_seq_get == NULL) {
     733           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     734           0 :                                N_("start_seq_get is not supported "
     735             :                                   "in the %s keytab type", ""),
     736             :                                id->prefix);
     737           0 :         return HEIM_ERR_OPNOTSUPP;
     738             :     }
     739       49808 :     return (*id->start_seq_get)(context, id, cursor);
     740             : }
     741             : 
     742             : /**
     743             :  * Get the next entry from keytab, advance the cursor.  On last entry
     744             :  * the function will return KRB5_KT_END.
     745             :  *
     746             :  * @param context a Keberos context.
     747             :  * @param id a keytab.
     748             :  * @param entry the returned entry, free with krb5_kt_free_entry().
     749             :  * @param cursor the cursor of the iteration.
     750             :  *
     751             :  * @return Return an error code or 0, see krb5_get_error_message().
     752             :  *
     753             :  * @ingroup krb5_keytab
     754             :  */
     755             : 
     756             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     757      176775 : krb5_kt_next_entry(krb5_context context,
     758             :                    krb5_keytab id,
     759             :                    krb5_keytab_entry *entry,
     760             :                    krb5_kt_cursor *cursor)
     761             : {
     762      176775 :     if(id->next_entry == NULL) {
     763           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     764           0 :                                N_("next_entry is not supported in the %s "
     765             :                                   " keytab", ""),
     766             :                                id->prefix);
     767           0 :         return HEIM_ERR_OPNOTSUPP;
     768             :     }
     769      176775 :     return (*id->next_entry)(context, id, entry, cursor);
     770             : }
     771             : 
     772             : /**
     773             :  * Release all resources associated with `cursor'.
     774             :  *
     775             :  * @param context a Keberos context.
     776             :  * @param id a keytab.
     777             :  * @param cursor the cursor to free.
     778             :  *
     779             :  * @return Return an error code or 0, see krb5_get_error_message().
     780             :  *
     781             :  * @ingroup krb5_keytab
     782             :  */
     783             : 
     784             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     785       48682 : krb5_kt_end_seq_get(krb5_context context,
     786             :                     krb5_keytab id,
     787             :                     krb5_kt_cursor *cursor)
     788             : {
     789       48682 :     if(id->end_seq_get == NULL) {
     790           0 :         krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
     791             :                                "end_seq_get is not supported in the %s "
     792             :                                " keytab", id->prefix);
     793           0 :         return HEIM_ERR_OPNOTSUPP;
     794             :     }
     795       48682 :     return (*id->end_seq_get)(context, id, cursor);
     796             : }
     797             : 
     798             : /**
     799             :  * Add the entry in `entry' to the keytab `id'.
     800             :  *
     801             :  * @param context a Keberos context.
     802             :  * @param id a keytab.
     803             :  * @param entry the entry to add
     804             :  *
     805             :  * @return Return an error code or 0, see krb5_get_error_message().
     806             :  *
     807             :  * @ingroup krb5_keytab
     808             :  */
     809             : 
     810             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     811       11598 : krb5_kt_add_entry(krb5_context context,
     812             :                   krb5_keytab id,
     813             :                   krb5_keytab_entry *entry)
     814             : {
     815       11598 :     if(id->add == NULL) {
     816           0 :         krb5_set_error_message(context, KRB5_KT_NOWRITE,
     817           0 :                                N_("Add is not supported in the %s keytab", ""),
     818             :                                id->prefix);
     819           0 :         return KRB5_KT_NOWRITE;
     820             :     }
     821       11598 :     entry->timestamp = time(NULL);
     822       11598 :     return (*id->add)(context, id,entry);
     823             : }
     824             : 
     825             : /**
     826             :  * Remove an entry from the keytab, matching is done using
     827             :  * krb5_kt_compare().
     828             : 
     829             :  * @param context a Keberos context.
     830             :  * @param id a keytab.
     831             :  * @param entry the entry to remove
     832             :  *
     833             :  * @return Return an error code or 0, see krb5_get_error_message().
     834             :  *
     835             :  * @ingroup krb5_keytab
     836             :  */
     837             : 
     838             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     839         501 : krb5_kt_remove_entry(krb5_context context,
     840             :                      krb5_keytab id,
     841             :                      krb5_keytab_entry *entry)
     842             : {
     843         501 :     if(id->remove == NULL) {
     844           0 :         krb5_set_error_message(context, KRB5_KT_NOWRITE,
     845           0 :                                N_("Remove is not supported in the %s keytab", ""),
     846             :                                id->prefix);
     847           0 :         return KRB5_KT_NOWRITE;
     848             :     }
     849         501 :     return (*id->remove)(context, id, entry);
     850             : }
     851             : 
     852             : /**
     853             :  * Return true if the keytab exists and have entries
     854             :  *
     855             :  * @param context a Keberos context.
     856             :  * @param id a keytab.
     857             :  *
     858             :  * @return Return an error code or 0, see krb5_get_error_message().
     859             :  *
     860             :  * @ingroup krb5_keytab
     861             :  */
     862             : 
     863             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     864           0 : krb5_kt_have_content(krb5_context context,
     865             :                      krb5_keytab id)
     866             : {
     867             :     krb5_keytab_entry entry;
     868             :     krb5_kt_cursor cursor;
     869             :     krb5_error_code ret;
     870             :     char *name;
     871             : 
     872           0 :     ret = krb5_kt_start_seq_get(context, id, &cursor);
     873           0 :     if (ret)
     874           0 :         goto notfound;
     875             : 
     876           0 :     ret = krb5_kt_next_entry(context, id, &entry, &cursor);
     877           0 :     krb5_kt_end_seq_get(context, id, &cursor);
     878           0 :     if (ret)
     879           0 :         goto notfound;
     880             : 
     881           0 :     krb5_kt_free_entry(context, &entry);
     882             : 
     883           0 :     return 0;
     884             : 
     885           0 :  notfound:
     886           0 :     ret = krb5_kt_get_full_name(context, id, &name);
     887           0 :     if (ret == 0) {
     888           0 :         krb5_set_error_message(context, KRB5_KT_NOTFOUND,
     889           0 :                                N_("No entry in keytab: %s", ""), name);
     890           0 :         free(name);
     891             :     }
     892           0 :     return KRB5_KT_NOTFOUND;
     893             : }

Generated by: LCOV version 1.13