root/source4/heimdal/lib/hdb/ext.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hdb_entry_check_mandatory
  2. hdb_find_extension
  3. hdb_replace_extension
  4. hdb_clear_extension
  5. hdb_entry_get_pkinit_acl
  6. hdb_entry_get_pkinit_hash
  7. hdb_entry_get_pw_change_time
  8. hdb_entry_set_pw_change_time
  9. hdb_entry_get_password
  10. hdb_entry_set_password
  11. hdb_entry_clear_password
  12. hdb_entry_get_ConstrainedDelegACL
  13. hdb_entry_get_aliases

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

/* [<][>][^][v][top][bottom][index][help] */