Home | History | Annotate | Line # | Download | only in hdb
      1  1.1     elric /*	$NetBSD: print.c,v 1.2 2017/01/28 21:31:48 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.1     elric  * Copyright (c) 1999-2005 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of KTH nor the names of its contributors may be
     20  1.1     elric  *    used to endorse or promote products derived from this software without
     21  1.1     elric  *    specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     24  1.1     elric  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     26  1.1     elric  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
     27  1.1     elric  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     28  1.1     elric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     29  1.1     elric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     30  1.1     elric  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     31  1.1     elric  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     32  1.1     elric  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     33  1.1     elric  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
     34  1.1     elric 
     35  1.1     elric #include "hdb_locl.h"
     36  1.1     elric #include <krb5/hex.h>
     37  1.1     elric #include <ctype.h>
     38  1.1     elric 
     39  1.1     elric /*
     40  1.1     elric    This is the present contents of a dump line. This might change at
     41  1.1     elric    any time. Fields are separated by white space.
     42  1.1     elric 
     43  1.1     elric   principal
     44  1.1     elric   keyblock
     45  1.1     elric   	kvno
     46  1.1     elric 	keys...
     47  1.1     elric 		mkvno
     48  1.1     elric 		enctype
     49  1.1     elric 		keyvalue
     50  1.1     elric 		salt (- means use normal salt)
     51  1.1     elric   creation date and principal
     52  1.1     elric   modification date and principal
     53  1.1     elric   principal valid from date (not used)
     54  1.1     elric   principal valid end date (not used)
     55  1.1     elric   principal key expires (not used)
     56  1.1     elric   max ticket life
     57  1.1     elric   max renewable life
     58  1.1     elric   flags
     59  1.1     elric   generation number
     60  1.1     elric   */
     61  1.1     elric 
     62  1.2  christos /*
     63  1.2  christos  * These utility functions return the number of bytes written or -1, and
     64  1.2  christos  * they set an error in the context.
     65  1.2  christos  */
     66  1.2  christos static ssize_t
     67  1.1     elric append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
     68  1.1     elric {
     69  1.2  christos     ssize_t sz;
     70  1.1     elric     char *s;
     71  1.2  christos     int rc;
     72  1.1     elric     va_list ap;
     73  1.1     elric     va_start(ap, fmt);
     74  1.2  christos     rc = vasprintf(&s, fmt, ap);
     75  1.1     elric     va_end(ap);
     76  1.2  christos     if(rc < 0) {
     77  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     78  1.2  christos 	return -1;
     79  1.1     elric     }
     80  1.2  christos     sz = krb5_storage_write(sp, s, strlen(s));
     81  1.1     elric     free(s);
     82  1.2  christos     return sz;
     83  1.1     elric }
     84  1.1     elric 
     85  1.1     elric static krb5_error_code
     86  1.2  christos append_hex(krb5_context context, krb5_storage *sp,
     87  1.2  christos            int always_encode, int lower, krb5_data *data)
     88  1.1     elric {
     89  1.2  christos     ssize_t sz;
     90  1.2  christos     int printable = 1;
     91  1.2  christos     size_t i;
     92  1.1     elric     char *p;
     93  1.1     elric 
     94  1.1     elric     p = data->data;
     95  1.2  christos     if (!always_encode) {
     96  1.2  christos         for (i = 0; i < data->length; i++) {
     97  1.2  christos             if (!isalnum((unsigned char)p[i]) && p[i] != '.'){
     98  1.2  christos                 printable = 0;
     99  1.2  christos                 break;
    100  1.2  christos             }
    101  1.2  christos         }
    102  1.2  christos     }
    103  1.2  christos     if (printable && !always_encode)
    104  1.1     elric 	return append_string(context, sp, "\"%.*s\"",
    105  1.1     elric 			     data->length, data->data);
    106  1.2  christos     sz = hex_encode(data->data, data->length, &p);
    107  1.2  christos     if (sz == -1) return sz;
    108  1.2  christos     if (lower)
    109  1.2  christos         strlwr(p);
    110  1.2  christos     sz = append_string(context, sp, "%s", p);
    111  1.1     elric     free(p);
    112  1.2  christos     return sz;
    113  1.1     elric }
    114  1.1     elric 
    115  1.1     elric static char *
    116  1.1     elric time2str(time_t t)
    117  1.1     elric {
    118  1.1     elric     static char buf[128];
    119  1.1     elric     strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t));
    120  1.1     elric     return buf;
    121  1.1     elric }
    122  1.1     elric 
    123  1.2  christos static ssize_t
    124  1.1     elric append_event(krb5_context context, krb5_storage *sp, Event *ev)
    125  1.1     elric {
    126  1.2  christos     krb5_error_code ret;
    127  1.2  christos     ssize_t sz;
    128  1.1     elric     char *pr = NULL;
    129  1.1     elric     if(ev == NULL)
    130  1.1     elric 	return append_string(context, sp, "- ");
    131  1.1     elric     if (ev->principal != NULL) {
    132  1.1     elric        ret = krb5_unparse_name(context, ev->principal, &pr);
    133  1.2  christos        if (ret) return -1; /* krb5_unparse_name() sets error info */
    134  1.1     elric     }
    135  1.2  christos     sz = append_string(context, sp, "%s:%s ", time2str(ev->time),
    136  1.2  christos                        pr ? pr : "UNKNOWN");
    137  1.1     elric     free(pr);
    138  1.2  christos     return sz;
    139  1.2  christos }
    140  1.2  christos 
    141  1.2  christos #define KRB5_KDB_SALTTYPE_NORMAL        0
    142  1.2  christos #define KRB5_KDB_SALTTYPE_V4            1
    143  1.2  christos #define KRB5_KDB_SALTTYPE_NOREALM       2
    144  1.2  christos #define KRB5_KDB_SALTTYPE_ONLYREALM     3
    145  1.2  christos #define KRB5_KDB_SALTTYPE_SPECIAL       4
    146  1.2  christos #define KRB5_KDB_SALTTYPE_AFS3          5
    147  1.2  christos 
    148  1.2  christos static ssize_t
    149  1.2  christos append_mit_key(krb5_context context, krb5_storage *sp,
    150  1.2  christos                krb5_const_principal princ,
    151  1.2  christos                unsigned int kvno, Key *key)
    152  1.2  christos {
    153  1.2  christos     krb5_error_code ret;
    154  1.2  christos     krb5_salt k5salt;
    155  1.2  christos     ssize_t sz;
    156  1.2  christos     size_t key_versions = key->salt ? 2 : 1;
    157  1.2  christos     size_t decrypted_key_length;
    158  1.2  christos     char buf[2];
    159  1.2  christos     krb5_data keylenbytes;
    160  1.2  christos     unsigned int salttype;
    161  1.2  christos 
    162  1.2  christos     sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno,
    163  1.2  christos                         key->key.keytype, key->key.keyvalue.length + 2);
    164  1.2  christos     if (sz == -1) return sz;
    165  1.2  christos     ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length);
    166  1.2  christos     if (ret) return -1; /* XXX we lose the error code */
    167  1.2  christos     buf[0] = decrypted_key_length & 0xff;
    168  1.2  christos     buf[1] = (decrypted_key_length & 0xff00) >> 8;
    169  1.2  christos     keylenbytes.data = buf;
    170  1.2  christos     keylenbytes.length = sizeof (buf);
    171  1.2  christos     sz = append_hex(context, sp, 1, 1, &keylenbytes);
    172  1.2  christos     if (sz == -1) return sz;
    173  1.2  christos     sz = append_hex(context, sp, 1, 1, &key->key.keyvalue);
    174  1.2  christos     if (!key->salt)
    175  1.2  christos         return sz;
    176  1.2  christos 
    177  1.2  christos     /* Map salt to MIT KDB style */
    178  1.2  christos     switch (key->salt->type) {
    179  1.2  christos     case KRB5_PADATA_PW_SALT:
    180  1.2  christos 
    181  1.2  christos         /*
    182  1.2  christos          * Compute normal salt and then see whether it matches the stored one
    183  1.2  christos          */
    184  1.2  christos         ret = krb5_get_pw_salt(context, princ, &k5salt);
    185  1.2  christos         if (ret) return -1;
    186  1.2  christos         if (k5salt.saltvalue.length == key->salt->salt.length &&
    187  1.2  christos             memcmp(k5salt.saltvalue.data, key->salt->salt.data,
    188  1.2  christos                    k5salt.saltvalue.length) == 0)
    189  1.2  christos             salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */
    190  1.2  christos         else if (key->salt->salt.length == strlen(princ->realm) &&
    191  1.2  christos                  memcmp(key->salt->salt.data, princ->realm,
    192  1.2  christos                         key->salt->salt.length) == 0)
    193  1.2  christos             salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */
    194  1.2  christos         else if (key->salt->salt.length ==
    195  1.2  christos 		 k5salt.saltvalue.length - strlen(princ->realm) &&
    196  1.2  christos                  memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm),
    197  1.2  christos                         key->salt->salt.data, key->salt->salt.length) == 0)
    198  1.2  christos             salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */
    199  1.2  christos         else
    200  1.2  christos             salttype = KRB5_KDB_SALTTYPE_NORMAL;  /* hope for best */
    201  1.2  christos 
    202  1.2  christos 	break;
    203  1.2  christos 
    204  1.2  christos     case KRB5_PADATA_AFS3_SALT:
    205  1.2  christos         salttype = KRB5_KDB_SALTTYPE_AFS3;
    206  1.2  christos 	break;
    207  1.2  christos 
    208  1.2  christos     default:
    209  1.2  christos 	return -1;
    210  1.2  christos     }
    211  1.2  christos 
    212  1.2  christos     sz = append_string(context, sp, "\t%u\t%u\t", salttype,
    213  1.2  christos                        key->salt->salt.length);
    214  1.2  christos     if (sz == -1) return sz;
    215  1.2  christos     return append_hex(context, sp, 1, 1, &key->salt->salt);
    216  1.1     elric }
    217  1.1     elric 
    218  1.1     elric static krb5_error_code
    219  1.1     elric entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
    220  1.1     elric {
    221  1.1     elric     char *p;
    222  1.2  christos     size_t i;
    223  1.1     elric     krb5_error_code ret;
    224  1.1     elric 
    225  1.1     elric     /* --- principal */
    226  1.1     elric     ret = krb5_unparse_name(context, ent->principal, &p);
    227  1.1     elric     if(ret)
    228  1.1     elric 	return ret;
    229  1.1     elric     append_string(context, sp, "%s ", p);
    230  1.1     elric     free(p);
    231  1.1     elric     /* --- kvno */
    232  1.1     elric     append_string(context, sp, "%d", ent->kvno);
    233  1.1     elric     /* --- keys */
    234  1.1     elric     for(i = 0; i < ent->keys.len; i++){
    235  1.1     elric 	/* --- mkvno, keytype */
    236  1.1     elric 	if(ent->keys.val[i].mkvno)
    237  1.1     elric 	    append_string(context, sp, ":%d:%d:",
    238  1.1     elric 			  *ent->keys.val[i].mkvno,
    239  1.1     elric 			  ent->keys.val[i].key.keytype);
    240  1.1     elric 	else
    241  1.1     elric 	    append_string(context, sp, "::%d:",
    242  1.1     elric 			  ent->keys.val[i].key.keytype);
    243  1.1     elric 	/* --- keydata */
    244  1.2  christos 	append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue);
    245  1.1     elric 	append_string(context, sp, ":");
    246  1.1     elric 	/* --- salt */
    247  1.1     elric 	if(ent->keys.val[i].salt){
    248  1.1     elric 	    append_string(context, sp, "%u/", ent->keys.val[i].salt->type);
    249  1.2  christos 	    append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt);
    250  1.1     elric 	}else
    251  1.1     elric 	    append_string(context, sp, "-");
    252  1.1     elric     }
    253  1.1     elric     append_string(context, sp, " ");
    254  1.1     elric     /* --- created by */
    255  1.1     elric     append_event(context, sp, &ent->created_by);
    256  1.1     elric     /* --- modified by */
    257  1.1     elric     append_event(context, sp, ent->modified_by);
    258  1.1     elric 
    259  1.1     elric     /* --- valid start */
    260  1.1     elric     if(ent->valid_start)
    261  1.1     elric 	append_string(context, sp, "%s ", time2str(*ent->valid_start));
    262  1.1     elric     else
    263  1.1     elric 	append_string(context, sp, "- ");
    264  1.1     elric 
    265  1.1     elric     /* --- valid end */
    266  1.1     elric     if(ent->valid_end)
    267  1.1     elric 	append_string(context, sp, "%s ", time2str(*ent->valid_end));
    268  1.1     elric     else
    269  1.1     elric 	append_string(context, sp, "- ");
    270  1.1     elric 
    271  1.1     elric     /* --- password ends */
    272  1.1     elric     if(ent->pw_end)
    273  1.1     elric 	append_string(context, sp, "%s ", time2str(*ent->pw_end));
    274  1.1     elric     else
    275  1.1     elric 	append_string(context, sp, "- ");
    276  1.1     elric 
    277  1.1     elric     /* --- max life */
    278  1.1     elric     if(ent->max_life)
    279  1.1     elric 	append_string(context, sp, "%d ", *ent->max_life);
    280  1.1     elric     else
    281  1.1     elric 	append_string(context, sp, "- ");
    282  1.1     elric 
    283  1.1     elric     /* --- max renewable life */
    284  1.1     elric     if(ent->max_renew)
    285  1.1     elric 	append_string(context, sp, "%d ", *ent->max_renew);
    286  1.1     elric     else
    287  1.1     elric 	append_string(context, sp, "- ");
    288  1.1     elric 
    289  1.1     elric     /* --- flags */
    290  1.1     elric     append_string(context, sp, "%d ", HDBFlags2int(ent->flags));
    291  1.1     elric 
    292  1.1     elric     /* --- generation number */
    293  1.1     elric     if(ent->generation) {
    294  1.1     elric 	append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time),
    295  1.1     elric 		      ent->generation->usec,
    296  1.1     elric 		      ent->generation->gen);
    297  1.1     elric     } else
    298  1.1     elric 	append_string(context, sp, "- ");
    299  1.1     elric 
    300  1.1     elric     /* --- extensions */
    301  1.1     elric     if(ent->extensions && ent->extensions->len > 0) {
    302  1.1     elric 	for(i = 0; i < ent->extensions->len; i++) {
    303  1.1     elric 	    void *d;
    304  1.2  christos 	    size_t size, sz = 0;
    305  1.1     elric 
    306  1.1     elric 	    ASN1_MALLOC_ENCODE(HDB_extension, d, size,
    307  1.1     elric 			       &ent->extensions->val[i], &sz, ret);
    308  1.1     elric 	    if (ret) {
    309  1.1     elric 		krb5_clear_error_message(context);
    310  1.1     elric 		return ret;
    311  1.1     elric 	    }
    312  1.1     elric 	    if(size != sz)
    313  1.1     elric 		krb5_abortx(context, "internal asn.1 encoder error");
    314  1.1     elric 
    315  1.1     elric 	    if (hex_encode(d, size, &p) < 0) {
    316  1.1     elric 		free(d);
    317  1.1     elric 		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    318  1.1     elric 		return ENOMEM;
    319  1.1     elric 	    }
    320  1.1     elric 
    321  1.1     elric 	    free(d);
    322  1.1     elric 	    append_string(context, sp, "%s%s", p,
    323  1.1     elric 			  ent->extensions->len - 1 != i ? ":" : "");
    324  1.1     elric 	    free(p);
    325  1.1     elric 	}
    326  1.1     elric     } else
    327  1.1     elric 	append_string(context, sp, "-");
    328  1.1     elric 
    329  1.2  christos     return 0;
    330  1.2  christos }
    331  1.2  christos 
    332  1.2  christos #define KRB5_KDB_DISALLOW_POSTDATED     0x00000001
    333  1.2  christos #define KRB5_KDB_DISALLOW_FORWARDABLE   0x00000002
    334  1.2  christos #define KRB5_KDB_DISALLOW_TGT_BASED     0x00000004
    335  1.2  christos #define KRB5_KDB_DISALLOW_RENEWABLE     0x00000008
    336  1.2  christos #define KRB5_KDB_DISALLOW_PROXIABLE     0x00000010
    337  1.2  christos #define KRB5_KDB_DISALLOW_DUP_SKEY      0x00000020
    338  1.2  christos #define KRB5_KDB_DISALLOW_ALL_TIX       0x00000040
    339  1.2  christos #define KRB5_KDB_REQUIRES_PRE_AUTH      0x00000080
    340  1.2  christos #define KRB5_KDB_REQUIRES_HW_AUTH       0x00000100
    341  1.2  christos #define KRB5_KDB_REQUIRES_PWCHANGE      0x00000200
    342  1.2  christos #define KRB5_KDB_DISALLOW_SVR           0x00001000
    343  1.2  christos #define KRB5_KDB_PWCHANGE_SERVICE       0x00002000
    344  1.2  christos #define KRB5_KDB_SUPPORT_DESMD5         0x00004000
    345  1.2  christos #define KRB5_KDB_NEW_PRINC              0x00008000
    346  1.2  christos 
    347  1.2  christos static int
    348  1.2  christos flags_to_attr(HDBFlags flags)
    349  1.2  christos {
    350  1.2  christos     int a = 0;
    351  1.2  christos 
    352  1.2  christos     if (!flags.postdate)
    353  1.2  christos         a |= KRB5_KDB_DISALLOW_POSTDATED;
    354  1.2  christos     if (!flags.forwardable)
    355  1.2  christos         a |= KRB5_KDB_DISALLOW_FORWARDABLE;
    356  1.2  christos     if (flags.initial)
    357  1.2  christos         a |= KRB5_KDB_DISALLOW_TGT_BASED;
    358  1.2  christos     if (!flags.renewable)
    359  1.2  christos         a |= KRB5_KDB_DISALLOW_RENEWABLE;
    360  1.2  christos     if (!flags.proxiable)
    361  1.2  christos         a |= KRB5_KDB_DISALLOW_PROXIABLE;
    362  1.2  christos     if (flags.invalid)
    363  1.2  christos         a |= KRB5_KDB_DISALLOW_ALL_TIX;
    364  1.2  christos     if (flags.require_preauth)
    365  1.2  christos         a |= KRB5_KDB_REQUIRES_PRE_AUTH;
    366  1.2  christos     if (flags.require_hwauth)
    367  1.2  christos         a |= KRB5_KDB_REQUIRES_HW_AUTH;
    368  1.2  christos     if (!flags.server)
    369  1.2  christos         a |= KRB5_KDB_DISALLOW_SVR;
    370  1.2  christos     if (flags.change_pw)
    371  1.2  christos         a |= KRB5_KDB_PWCHANGE_SERVICE;
    372  1.2  christos     return a;
    373  1.2  christos }
    374  1.2  christos 
    375  1.2  christos krb5_error_code
    376  1.2  christos entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
    377  1.2  christos {
    378  1.2  christos     krb5_error_code ret;
    379  1.2  christos     ssize_t sz;
    380  1.2  christos     size_t i, k;
    381  1.2  christos     size_t num_tl_data = 0;
    382  1.2  christos     size_t num_key_data = 0;
    383  1.2  christos     char *p;
    384  1.2  christos     HDB_Ext_KeySet *hist_keys = NULL;
    385  1.2  christos     HDB_extension *extp;
    386  1.2  christos     time_t last_pw_chg = 0;
    387  1.2  christos     time_t exp = 0;
    388  1.2  christos     time_t pwexp = 0;
    389  1.2  christos     unsigned int max_life = 0;
    390  1.2  christos     unsigned int max_renew = 0;
    391  1.2  christos 
    392  1.2  christos     if (ent->modified_by)
    393  1.2  christos         num_tl_data++;
    394  1.2  christos 
    395  1.2  christos     ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg);
    396  1.2  christos     if (ret) return ret;
    397  1.2  christos     if (last_pw_chg)
    398  1.2  christos         num_tl_data++;
    399  1.2  christos 
    400  1.2  christos     extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
    401  1.2  christos     if (extp)
    402  1.2  christos         hist_keys = &extp->data.u.hist_keys;
    403  1.2  christos 
    404  1.2  christos     for (i = 0; i < ent->keys.len;i++) {
    405  1.2  christos         if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
    406  1.2  christos             ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
    407  1.2  christos             continue;
    408  1.2  christos         num_key_data++;
    409  1.2  christos     }
    410  1.2  christos     if (hist_keys) {
    411  1.2  christos         for (i = 0; i < hist_keys->len; i++) {
    412  1.2  christos             /*
    413  1.2  christos              * MIT uses the highest kvno as the current kvno instead of
    414  1.2  christos              * tracking kvno separately, so we can't dump keysets with kvno
    415  1.2  christos              * higher than the entry's kvno.
    416  1.2  christos              */
    417  1.2  christos             if (hist_keys->val[i].kvno >= ent->kvno)
    418  1.2  christos                 continue;
    419  1.2  christos             for (k = 0; k < hist_keys->val[i].keys.len; k++) {
    420  1.2  christos                 if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
    421  1.2  christos                     ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
    422  1.2  christos                     continue;
    423  1.2  christos                 num_key_data++;
    424  1.2  christos             }
    425  1.2  christos         }
    426  1.2  christos     }
    427  1.1     elric 
    428  1.2  christos     ret = krb5_unparse_name(context, ent->principal, &p);
    429  1.2  christos     if (ret) return ret;
    430  1.2  christos     sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d",
    431  1.2  christos                        strlen(p), num_tl_data, num_key_data, p,
    432  1.2  christos                        flags_to_attr(ent->flags));
    433  1.2  christos     free(p);
    434  1.2  christos     if (sz == -1) return ENOMEM;
    435  1.2  christos 
    436  1.2  christos     if (ent->max_life)
    437  1.2  christos         max_life = *ent->max_life;
    438  1.2  christos     if (ent->max_renew)
    439  1.2  christos         max_renew = *ent->max_renew;
    440  1.2  christos     if (ent->valid_end)
    441  1.2  christos         exp = *ent->valid_end;
    442  1.2  christos     if (ent->pw_end)
    443  1.2  christos         pwexp = *ent->pw_end;
    444  1.2  christos 
    445  1.2  christos     sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0",
    446  1.2  christos                        max_life, max_renew, exp, pwexp);
    447  1.2  christos     if (sz == -1) return ENOMEM;
    448  1.2  christos 
    449  1.2  christos     /* Dump TL data we know: last pw chg and modified_by */
    450  1.2  christos #define mit_KRB5_TL_LAST_PWD_CHANGE     1
    451  1.2  christos #define mit_KRB5_TL_MOD_PRINC           2
    452  1.2  christos     if (last_pw_chg) {
    453  1.2  christos         krb5_data d;
    454  1.2  christos         time_t val;
    455  1.2  christos         unsigned char *ptr;
    456  1.2  christos 
    457  1.2  christos         ptr = (unsigned char *)&last_pw_chg;
    458  1.2  christos         val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
    459  1.2  christos         d.data = &val;
    460  1.2  christos         d.length = sizeof (last_pw_chg);
    461  1.2  christos         sz = append_string(context, sp, "\t%u\t%u\t",
    462  1.2  christos                            mit_KRB5_TL_LAST_PWD_CHANGE, d.length);
    463  1.2  christos         if (sz == -1) return ENOMEM;
    464  1.2  christos         sz = append_hex(context, sp, 1, 1, &d);
    465  1.2  christos         if (sz == -1) return ENOMEM;
    466  1.2  christos     }
    467  1.2  christos     if (ent->modified_by) {
    468  1.2  christos         krb5_data d;
    469  1.2  christos         unsigned int val;
    470  1.2  christos         size_t plen;
    471  1.2  christos         unsigned char *ptr;
    472  1.2  christos         char *modby_p;
    473  1.2  christos 
    474  1.2  christos         ptr = (unsigned char *)&ent->modified_by->time;
    475  1.2  christos         val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
    476  1.2  christos         d.data = &val;
    477  1.2  christos         d.length = sizeof (ent->modified_by->time);
    478  1.2  christos         ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p);
    479  1.2  christos         if (ret) return ret;
    480  1.2  christos         plen = strlen(modby_p);
    481  1.2  christos         sz = append_string(context, sp, "\t%u\t%u\t",
    482  1.2  christos                            mit_KRB5_TL_MOD_PRINC,
    483  1.2  christos                            d.length + plen + 1 /* NULL counted */);
    484  1.2  christos         if (sz == -1) return ENOMEM;
    485  1.2  christos         sz = append_hex(context, sp, 1, 1, &d);
    486  1.2  christos         if (sz == -1) {
    487  1.2  christos             free(modby_p);
    488  1.2  christos             return ENOMEM;
    489  1.2  christos         }
    490  1.2  christos         d.data = modby_p;
    491  1.2  christos         d.length = plen + 1;
    492  1.2  christos         sz = append_hex(context, sp, 1, 1, &d);
    493  1.2  christos         free(modby_p);
    494  1.2  christos         if (sz == -1) return ENOMEM;
    495  1.2  christos     }
    496  1.2  christos     /*
    497  1.2  christos      * Dump keys (remembering to not include any with kvno higher than
    498  1.2  christos      * the entry's because MIT doesn't track entry kvno separately from
    499  1.2  christos      * the entry's keys -- max kvno is it)
    500  1.2  christos      */
    501  1.2  christos     for (i = 0; i < ent->keys.len; i++) {
    502  1.2  christos         if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
    503  1.2  christos             ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
    504  1.2  christos             continue;
    505  1.2  christos         sz = append_mit_key(context, sp, ent->principal, ent->kvno,
    506  1.2  christos                             &ent->keys.val[i]);
    507  1.2  christos         if (sz == -1) return ENOMEM;
    508  1.2  christos     }
    509  1.2  christos     for (i = 0; hist_keys && i < ent->kvno; i++) {
    510  1.2  christos         size_t m;
    511  1.2  christos 
    512  1.2  christos         /* dump historical keys */
    513  1.2  christos         for (k = 0; k < hist_keys->len; k++) {
    514  1.2  christos             if (hist_keys->val[k].kvno != ent->kvno - i)
    515  1.2  christos                 continue;
    516  1.2  christos             for (m = 0; m < hist_keys->val[k].keys.len; m++) {
    517  1.2  christos                 if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
    518  1.2  christos                     ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
    519  1.2  christos                     continue;
    520  1.2  christos                 sz = append_mit_key(context, sp, ent->principal,
    521  1.2  christos                                     hist_keys->val[k].kvno,
    522  1.2  christos                                     &hist_keys->val[k].keys.val[m]);
    523  1.2  christos                 if (sz == -1) return ENOMEM;
    524  1.2  christos             }
    525  1.2  christos         }
    526  1.2  christos     }
    527  1.2  christos     sz = append_string(context, sp, "\t-1;"); /* "extra data" */
    528  1.2  christos     if (sz == -1) return ENOMEM;
    529  1.1     elric     return 0;
    530  1.1     elric }
    531  1.1     elric 
    532  1.1     elric krb5_error_code
    533  1.2  christos hdb_entry2string(krb5_context context, hdb_entry *ent, char **str)
    534  1.1     elric {
    535  1.1     elric     krb5_error_code ret;
    536  1.1     elric     krb5_data data;
    537  1.1     elric     krb5_storage *sp;
    538  1.1     elric 
    539  1.1     elric     sp = krb5_storage_emem();
    540  1.2  christos     if (sp == NULL) {
    541  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    542  1.1     elric 	return ENOMEM;
    543  1.1     elric     }
    544  1.1     elric 
    545  1.1     elric     ret = entry2string_int(context, sp, ent);
    546  1.2  christos     if (ret) {
    547  1.1     elric 	krb5_storage_free(sp);
    548  1.1     elric 	return ret;
    549  1.1     elric     }
    550  1.1     elric 
    551  1.1     elric     krb5_storage_write(sp, "\0", 1);
    552  1.1     elric     krb5_storage_to_data(sp, &data);
    553  1.1     elric     krb5_storage_free(sp);
    554  1.1     elric     *str = data.data;
    555  1.1     elric     return 0;
    556  1.1     elric }
    557  1.1     elric 
    558  1.1     elric /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */
    559  1.1     elric 
    560  1.1     elric krb5_error_code
    561  1.2  christos hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry,
    562  1.2  christos                 void *data)
    563  1.1     elric {
    564  1.2  christos     struct hdb_print_entry_arg *parg = data;
    565  1.1     elric     krb5_error_code ret;
    566  1.1     elric     krb5_storage *sp;
    567  1.1     elric 
    568  1.2  christos     fflush(parg->out);
    569  1.2  christos     sp = krb5_storage_from_fd(fileno(parg->out));
    570  1.2  christos     if (sp == NULL) {
    571  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    572  1.1     elric 	return ENOMEM;
    573  1.1     elric     }
    574  1.1     elric 
    575  1.2  christos     switch (parg->fmt) {
    576  1.2  christos     case HDB_DUMP_HEIMDAL:
    577  1.2  christos         ret = entry2string_int(context, sp, &entry->entry);
    578  1.2  christos         break;
    579  1.2  christos     case HDB_DUMP_MIT:
    580  1.2  christos         ret = entry2mit_string_int(context, sp, &entry->entry);
    581  1.2  christos         break;
    582  1.2  christos     default:
    583  1.2  christos         heim_abort("Only two dump formats supported: Heimdal and MIT");
    584  1.2  christos     }
    585  1.2  christos     if (ret) {
    586  1.1     elric 	krb5_storage_free(sp);
    587  1.1     elric 	return ret;
    588  1.1     elric     }
    589  1.1     elric 
    590  1.1     elric     krb5_storage_write(sp, "\n", 1);
    591  1.1     elric     krb5_storage_free(sp);
    592  1.1     elric     return 0;
    593  1.1     elric }
    594