LCOV - code coverage report
Current view: top level - source4/heimdal/lib/hdb - ext.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 13 205 6.3 %
Date: 2021-09-23 10:06:22 Functions: 3 20 15.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2004 - 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 "hdb_locl.h"
      35             : #include <der.h>
      36             : 
      37             : krb5_error_code
      38           0 : hdb_entry_check_mandatory(krb5_context context, const hdb_entry *ent)
      39             : {
      40             :     size_t i;
      41             : 
      42           0 :     if (ent->extensions == NULL)
      43           0 :         return 0;
      44             : 
      45             :     /*
      46             :      * check for unknown extensions and if they where tagged mandatory
      47             :      */
      48             : 
      49           0 :     for (i = 0; i < ent->extensions->len; i++) {
      50           0 :         if (ent->extensions->val[i].data.element !=
      51             :             choice_HDB_extension_data_asn1_ellipsis)
      52           0 :             continue;
      53           0 :         if (ent->extensions->val[i].mandatory) {
      54           0 :             krb5_set_error_message(context, HDB_ERR_MANDATORY_OPTION,
      55             :                                    "Principal have unknown "
      56             :                                    "mandatory extension");
      57           0 :             return HDB_ERR_MANDATORY_OPTION;
      58             :         }
      59             :     }
      60           0 :     return 0;
      61             : }
      62             : 
      63             : HDB_extension *
      64          70 : hdb_find_extension(const hdb_entry *entry, int type)
      65             : {
      66             :     size_t i;
      67             : 
      68          70 :     if (entry->extensions == NULL)
      69          70 :         return NULL;
      70             : 
      71           0 :     for (i = 0; i < entry->extensions->len; i++)
      72           0 :         if (entry->extensions->val[i].data.element == (unsigned)type)
      73           0 :             return &entry->extensions->val[i];
      74           0 :     return NULL;
      75             : }
      76             : 
      77             : /*
      78             :  * Replace the extension `ext' in `entry'. Make a copy of the
      79             :  * extension, so the caller must still free `ext' on both success and
      80             :  * failure. Returns 0 or error code.
      81             :  */
      82             : 
      83             : krb5_error_code
      84           0 : hdb_replace_extension(krb5_context context,
      85             :                       hdb_entry *entry,
      86             :                       const HDB_extension *ext)
      87             : {
      88             :     HDB_extension *ext2;
      89             :     HDB_extension *es;
      90             :     int ret;
      91             : 
      92           0 :     ext2 = NULL;
      93             : 
      94           0 :     if (entry->extensions == NULL) {
      95           0 :         entry->extensions = calloc(1, sizeof(*entry->extensions));
      96           0 :         if (entry->extensions == NULL) {
      97           0 :             krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
      98           0 :             return ENOMEM;
      99             :         }
     100           0 :     } else if (ext->data.element != choice_HDB_extension_data_asn1_ellipsis) {
     101           0 :         ext2 = hdb_find_extension(entry, ext->data.element);
     102             :     } else {
     103             :         /*
     104             :          * This is an unknown extention, and we are asked to replace a
     105             :          * possible entry in `entry' that is of the same type. This
     106             :          * might seem impossible, but ASN.1 CHOICE comes to our
     107             :          * rescue. The first tag in each branch in the CHOICE is
     108             :          * unique, so just find the element in the list that have the
     109             :          * same tag was we are putting into the list.
     110             :          */
     111             :         Der_class replace_class, list_class;
     112             :         Der_type replace_type, list_type;
     113             :         unsigned int replace_tag, list_tag;
     114             :         size_t size;
     115             :         size_t i;
     116             : 
     117           0 :         ret = der_get_tag(ext->data.u.asn1_ellipsis.data,
     118             :                           ext->data.u.asn1_ellipsis.length,
     119             :                           &replace_class, &replace_type, &replace_tag,
     120             :                           &size);
     121           0 :         if (ret) {
     122           0 :             krb5_set_error_message(context, ret, "hdb: failed to decode "
     123             :                                    "replacement hdb extention");
     124           0 :             return ret;
     125             :         }
     126             : 
     127           0 :         for (i = 0; i < entry->extensions->len; i++) {
     128           0 :             HDB_extension *ext3 = &entry->extensions->val[i];
     129             : 
     130           0 :             if (ext3->data.element != choice_HDB_extension_data_asn1_ellipsis)
     131           0 :                 continue;
     132             : 
     133           0 :             ret = der_get_tag(ext3->data.u.asn1_ellipsis.data,
     134             :                               ext3->data.u.asn1_ellipsis.length,
     135             :                               &list_class, &list_type, &list_tag,
     136             :                               &size);
     137           0 :             if (ret) {
     138           0 :                 krb5_set_error_message(context, ret, "hdb: failed to decode "
     139             :                                        "present hdb extention");
     140           0 :                 return ret;
     141             :             }
     142             : 
     143           0 :             if (MAKE_TAG(replace_class,replace_type,replace_type) ==
     144           0 :                 MAKE_TAG(list_class,list_type,list_type)) {
     145           0 :                 ext2 = ext3;
     146           0 :                 break;
     147             :             }
     148             :         }
     149             :     }
     150             : 
     151           0 :     if (ext2) {
     152           0 :         free_HDB_extension(ext2);
     153           0 :         ret = copy_HDB_extension(ext, ext2);
     154           0 :         if (ret)
     155           0 :             krb5_set_error_message(context, ret, "hdb: failed to copy replacement "
     156             :                                    "hdb extention");
     157           0 :         return ret;
     158             :     }
     159             : 
     160           0 :     es = realloc(entry->extensions->val,
     161           0 :                  (entry->extensions->len+1)*sizeof(entry->extensions->val[0]));
     162           0 :     if (es == NULL) {
     163           0 :         krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     164           0 :         return ENOMEM;
     165             :     }
     166           0 :     entry->extensions->val = es;
     167             : 
     168           0 :     ret = copy_HDB_extension(ext,
     169           0 :                              &entry->extensions->val[entry->extensions->len]);
     170           0 :     if (ret == 0)
     171           0 :         entry->extensions->len++;
     172             :     else
     173           0 :         krb5_set_error_message(context, ret, "hdb: failed to copy new extension");
     174             : 
     175           0 :     return ret;
     176             : }
     177             : 
     178             : krb5_error_code
     179           0 : hdb_clear_extension(krb5_context context,
     180             :                     hdb_entry *entry,
     181             :                     int type)
     182             : {
     183             :     size_t i;
     184             : 
     185           0 :     if (entry->extensions == NULL)
     186           0 :         return 0;
     187             : 
     188           0 :     for (i = 0; i < entry->extensions->len; i++) {
     189           0 :         if (entry->extensions->val[i].data.element == (unsigned)type) {
     190           0 :             free_HDB_extension(&entry->extensions->val[i]);
     191           0 :             memmove(&entry->extensions->val[i],
     192           0 :                     &entry->extensions->val[i + 1],
     193           0 :                     sizeof(entry->extensions->val[i]) * (entry->extensions->len - i - 1));
     194           0 :             entry->extensions->len--;
     195             :         }
     196             :     }
     197           0 :     if (entry->extensions->len == 0) {
     198           0 :         free(entry->extensions->val);
     199           0 :         free(entry->extensions);
     200           0 :         entry->extensions = NULL;
     201             :     }
     202             : 
     203           0 :     return 0;
     204             : }
     205             : 
     206             : 
     207             : krb5_error_code
     208           2 : hdb_entry_get_pkinit_acl(const hdb_entry *entry, const HDB_Ext_PKINIT_acl **a)
     209             : {
     210             :     const HDB_extension *ext;
     211             : 
     212           2 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_acl);
     213           2 :     if (ext)
     214           0 :         *a = &ext->data.u.pkinit_acl;
     215             :     else
     216           2 :         *a = NULL;
     217             : 
     218           2 :     return 0;
     219             : }
     220             : 
     221             : krb5_error_code
     222           0 : hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a)
     223             : {
     224             :     const HDB_extension *ext;
     225             : 
     226           0 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert_hash);
     227           0 :     if (ext)
     228           0 :         *a = &ext->data.u.pkinit_cert_hash;
     229             :     else
     230           0 :         *a = NULL;
     231             : 
     232           0 :     return 0;
     233             : }
     234             : 
     235             : krb5_error_code
     236          68 : hdb_entry_get_pkinit_cert(const hdb_entry *entry, const HDB_Ext_PKINIT_cert **a)
     237             : {
     238             :     const HDB_extension *ext;
     239             : 
     240          68 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert);
     241          68 :     if (ext)
     242           0 :         *a = &ext->data.u.pkinit_cert;
     243             :     else
     244          68 :         *a = NULL;
     245             : 
     246          68 :     return 0;
     247             : }
     248             : 
     249             : krb5_error_code
     250           0 : hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t)
     251             : {
     252             :     const HDB_extension *ext;
     253             : 
     254           0 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_last_pw_change);
     255           0 :     if (ext)
     256           0 :         *t = ext->data.u.last_pw_change;
     257             :     else
     258           0 :         *t = 0;
     259             : 
     260           0 :     return 0;
     261             : }
     262             : 
     263             : krb5_error_code
     264           0 : hdb_entry_set_pw_change_time(krb5_context context,
     265             :                              hdb_entry *entry,
     266             :                              time_t t)
     267             : {
     268             :     HDB_extension ext;
     269             : 
     270           0 :     ext.mandatory = FALSE;
     271           0 :     ext.data.element = choice_HDB_extension_data_last_pw_change;
     272           0 :     if (t == 0)
     273           0 :         t = time(NULL);
     274           0 :     ext.data.u.last_pw_change = t;
     275             : 
     276           0 :     return hdb_replace_extension(context, entry, &ext);
     277             : }
     278             : 
     279             : int
     280           0 : hdb_entry_get_password(krb5_context context, HDB *db,
     281             :                        const hdb_entry *entry, char **p)
     282             : {
     283             :     HDB_extension *ext;
     284             :     char *str;
     285             :     int ret;
     286             : 
     287           0 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_password);
     288           0 :     if (ext) {
     289             :         heim_utf8_string xstr;
     290             :         heim_octet_string pw;
     291             : 
     292           0 :         if (db->hdb_master_key_set && ext->data.u.password.mkvno) {
     293             :             hdb_master_key key;
     294             : 
     295           0 :             key = _hdb_find_master_key(ext->data.u.password.mkvno,
     296             :                                        db->hdb_master_key);
     297             : 
     298           0 :             if (key == NULL) {
     299           0 :                 krb5_set_error_message(context, HDB_ERR_NO_MKEY,
     300             :                                        "master key %d missing",
     301           0 :                                        *ext->data.u.password.mkvno);
     302           0 :                 return HDB_ERR_NO_MKEY;
     303             :             }
     304             : 
     305           0 :             ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
     306             :                                     ext->data.u.password.password.data,
     307             :                                     ext->data.u.password.password.length,
     308             :                                     &pw);
     309             :         } else {
     310           0 :             ret = der_copy_octet_string(&ext->data.u.password.password, &pw);
     311             :         }
     312           0 :         if (ret) {
     313           0 :             krb5_clear_error_message(context);
     314           0 :             return ret;
     315             :         }
     316             : 
     317           0 :         xstr = pw.data;
     318           0 :         if (xstr[pw.length - 1] != '\0') {
     319           0 :             krb5_set_error_message(context, EINVAL, "malformed password");
     320           0 :             return EINVAL;
     321             :         }
     322             : 
     323           0 :         *p = strdup(xstr);
     324             : 
     325           0 :         der_free_octet_string(&pw);
     326           0 :         if (*p == NULL) {
     327           0 :             krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     328           0 :             return ENOMEM;
     329             :         }
     330           0 :         return 0;
     331             :     }
     332             : 
     333           0 :     ret = krb5_unparse_name(context, entry->principal, &str);
     334           0 :     if (ret == 0) {
     335           0 :         krb5_set_error_message(context, ENOENT,
     336             :                                "no password attribute for %s", str);
     337           0 :         free(str);
     338             :     } else
     339           0 :         krb5_clear_error_message(context);
     340             : 
     341           0 :     return ENOENT;
     342             : }
     343             : 
     344             : int
     345           0 : hdb_entry_set_password(krb5_context context, HDB *db,
     346             :                        hdb_entry *entry, const char *p)
     347             : {
     348             :     HDB_extension ext;
     349             :     hdb_master_key key;
     350             :     int ret;
     351             : 
     352           0 :     ext.mandatory = FALSE;
     353           0 :     ext.data.element = choice_HDB_extension_data_password;
     354             : 
     355           0 :     if (db->hdb_master_key_set) {
     356             : 
     357           0 :         key = _hdb_find_master_key(NULL, db->hdb_master_key);
     358           0 :         if (key == NULL) {
     359           0 :             krb5_set_error_message(context, HDB_ERR_NO_MKEY,
     360             :                                    "hdb_entry_set_password: "
     361             :                                    "failed to find masterkey");
     362           0 :             return HDB_ERR_NO_MKEY;
     363             :         }
     364             : 
     365           0 :         ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
     366           0 :                                 p, strlen(p) + 1,
     367             :                                 &ext.data.u.password.password);
     368           0 :         if (ret)
     369           0 :             return ret;
     370             : 
     371           0 :         ext.data.u.password.mkvno =
     372           0 :             malloc(sizeof(*ext.data.u.password.mkvno));
     373           0 :         if (ext.data.u.password.mkvno == NULL) {
     374           0 :             free_HDB_extension(&ext);
     375           0 :             krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     376           0 :             return ENOMEM;
     377             :         }
     378           0 :         *ext.data.u.password.mkvno = _hdb_mkey_version(key);
     379             : 
     380             :     } else {
     381           0 :         ext.data.u.password.mkvno = NULL;
     382             : 
     383           0 :         ret = krb5_data_copy(&ext.data.u.password.password,
     384           0 :                              p, strlen(p) + 1);
     385           0 :         if (ret) {
     386           0 :             krb5_set_error_message(context, ret, "malloc: out of memory");
     387           0 :             free_HDB_extension(&ext);
     388           0 :             return ret;
     389             :         }
     390             :     }
     391             : 
     392           0 :     ret = hdb_replace_extension(context, entry, &ext);
     393             : 
     394           0 :     free_HDB_extension(&ext);
     395             : 
     396           0 :     return ret;
     397             : }
     398             : 
     399             : int
     400           0 : hdb_entry_clear_password(krb5_context context, hdb_entry *entry)
     401             : {
     402           0 :     return hdb_clear_extension(context, entry,
     403             :                                choice_HDB_extension_data_password);
     404             : }
     405             : 
     406             : krb5_error_code
     407           0 : hdb_entry_get_ConstrainedDelegACL(const hdb_entry *entry,
     408             :                                   const HDB_Ext_Constrained_delegation_acl **a)
     409             : {
     410             :     const HDB_extension *ext;
     411             : 
     412           0 :     ext = hdb_find_extension(entry,
     413             :                              choice_HDB_extension_data_allowed_to_delegate_to);
     414           0 :     if (ext)
     415           0 :         *a = &ext->data.u.allowed_to_delegate_to;
     416             :     else
     417           0 :         *a = NULL;
     418             : 
     419           0 :     return 0;
     420             : }
     421             : 
     422             : krb5_error_code
     423           0 : hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a)
     424             : {
     425             :     const HDB_extension *ext;
     426             : 
     427           0 :     ext = hdb_find_extension(entry, choice_HDB_extension_data_aliases);
     428           0 :     if (ext)
     429           0 :         *a = &ext->data.u.aliases;
     430             :     else
     431           0 :         *a = NULL;
     432             : 
     433           0 :     return 0;
     434             : }
     435             : 
     436             : unsigned int
     437           0 : hdb_entry_get_kvno_diff_clnt(const hdb_entry *entry)
     438             : {
     439             :     const HDB_extension *ext;
     440             : 
     441           0 :     ext = hdb_find_extension(entry,
     442             :                              choice_HDB_extension_data_hist_kvno_diff_clnt);
     443           0 :     if (ext)
     444           0 :         return ext->data.u.hist_kvno_diff_clnt;
     445           0 :     return 1;
     446             : }
     447             : 
     448             : krb5_error_code
     449           0 : hdb_entry_set_kvno_diff_clnt(krb5_context context, hdb_entry *entry,
     450             :                              unsigned int diff)
     451             : {
     452             :     HDB_extension ext;
     453             : 
     454           0 :     if (diff > 16384)
     455           0 :         return EINVAL;
     456           0 :     ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt;
     457           0 :     ext.data.u.hist_kvno_diff_clnt = diff;
     458           0 :     return hdb_replace_extension(context, entry, &ext);
     459             : }
     460             : 
     461             : krb5_error_code
     462           0 : hdb_entry_clear_kvno_diff_clnt(krb5_context context, hdb_entry *entry)
     463             : {
     464           0 :     return hdb_clear_extension(context, entry,
     465             :                                choice_HDB_extension_data_hist_kvno_diff_clnt);
     466             : }
     467             : 
     468             : unsigned int
     469           0 : hdb_entry_get_kvno_diff_svc(const hdb_entry *entry)
     470             : {
     471             :     const HDB_extension *ext;
     472             : 
     473           0 :     ext = hdb_find_extension(entry,
     474             :                              choice_HDB_extension_data_hist_kvno_diff_svc);
     475           0 :     if (ext)
     476           0 :         return ext->data.u.hist_kvno_diff_svc;
     477           0 :     return 1024; /* max_life effectively provides a better default */
     478             : }
     479             : 
     480             : krb5_error_code
     481           0 : hdb_entry_set_kvno_diff_svc(krb5_context context, hdb_entry *entry,
     482             :                             unsigned int diff)
     483             : {
     484             :     HDB_extension ext;
     485             : 
     486           0 :     if (diff > 16384)
     487           0 :         return EINVAL;
     488           0 :     ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc;
     489           0 :     ext.data.u.hist_kvno_diff_svc = diff;
     490           0 :     return hdb_replace_extension(context, entry, &ext);
     491             : }
     492             : 
     493             : krb5_error_code
     494           0 : hdb_entry_clear_kvno_diff_svc(krb5_context context, hdb_entry *entry)
     495             : {
     496           0 :     return hdb_clear_extension(context, entry,
     497             :                                choice_HDB_extension_data_hist_kvno_diff_svc);
     498             : }

Generated by: LCOV version 1.13