1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* lib/kdb/kdb_xdr.c */ 3 /* 4 * Copyright (C) 2018 by the Massachusetts Institute of Technology. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "k5-int.h" 34 #include "k5-input.h" 35 #include <kdb.h> 36 #include "klmdb-int.h" 37 38 static void 39 put_tl_data(struct k5buf *buf, const krb5_tl_data *tl) 40 { 41 for (; tl != NULL; tl = tl->tl_data_next) { 42 k5_buf_add_uint16_le(buf, tl->tl_data_type); 43 k5_buf_add_uint16_le(buf, tl->tl_data_length); 44 k5_buf_add_len(buf, tl->tl_data_contents, tl->tl_data_length); 45 } 46 } 47 48 krb5_error_code 49 klmdb_encode_princ(krb5_context context, const krb5_db_entry *entry, 50 uint8_t **enc_out, size_t *len_out) 51 { 52 struct k5buf buf; 53 const krb5_key_data *kd; 54 int i, j; 55 56 *enc_out = NULL; 57 *len_out = 0; 58 59 k5_buf_init_dynamic(&buf); 60 61 k5_buf_add_uint32_le(&buf, entry->attributes); 62 k5_buf_add_uint32_le(&buf, entry->max_life); 63 k5_buf_add_uint32_le(&buf, entry->max_renewable_life); 64 k5_buf_add_uint32_le(&buf, entry->expiration); 65 k5_buf_add_uint32_le(&buf, entry->pw_expiration); 66 k5_buf_add_uint16_le(&buf, entry->n_tl_data); 67 k5_buf_add_uint16_le(&buf, entry->n_key_data); 68 put_tl_data(&buf, entry->tl_data); 69 for (i = 0; i < entry->n_key_data; i++) { 70 kd = &entry->key_data[i]; 71 k5_buf_add_uint16_le(&buf, kd->key_data_ver); 72 k5_buf_add_uint16_le(&buf, kd->key_data_kvno); 73 for (j = 0; j < kd->key_data_ver; j++) { 74 k5_buf_add_uint16_le(&buf, kd->key_data_type[j]); 75 k5_buf_add_uint16_le(&buf, kd->key_data_length[j]); 76 if (kd->key_data_length[j] > 0) { 77 k5_buf_add_len(&buf, kd->key_data_contents[j], 78 kd->key_data_length[j]); 79 } 80 } 81 } 82 83 if (k5_buf_status(&buf) != 0) 84 return ENOMEM; 85 86 *enc_out = buf.data; 87 *len_out = buf.len; 88 return 0; 89 } 90 91 void 92 klmdb_encode_princ_lockout(krb5_context context, const krb5_db_entry *entry, 93 uint8_t buf[LOCKOUT_RECORD_LEN]) 94 { 95 store_32_le(entry->last_success, buf); 96 store_32_le(entry->last_failed, buf + 4); 97 store_32_le(entry->fail_auth_count, buf + 8); 98 } 99 100 krb5_error_code 101 klmdb_encode_policy(krb5_context context, const osa_policy_ent_rec *pol, 102 uint8_t **enc_out, size_t *len_out) 103 { 104 struct k5buf buf; 105 106 *enc_out = NULL; 107 *len_out = 0; 108 109 k5_buf_init_dynamic(&buf); 110 k5_buf_add_uint32_le(&buf, pol->pw_min_life); 111 k5_buf_add_uint32_le(&buf, pol->pw_max_life); 112 k5_buf_add_uint32_le(&buf, pol->pw_min_length); 113 k5_buf_add_uint32_le(&buf, pol->pw_min_classes); 114 k5_buf_add_uint32_le(&buf, pol->pw_history_num); 115 k5_buf_add_uint32_le(&buf, pol->pw_max_fail); 116 k5_buf_add_uint32_le(&buf, pol->pw_failcnt_interval); 117 k5_buf_add_uint32_le(&buf, pol->pw_lockout_duration); 118 k5_buf_add_uint32_le(&buf, pol->attributes); 119 k5_buf_add_uint32_le(&buf, pol->max_life); 120 k5_buf_add_uint32_le(&buf, pol->max_renewable_life); 121 122 if (pol->allowed_keysalts == NULL) { 123 k5_buf_add_uint32_le(&buf, 0); 124 } else { 125 k5_buf_add_uint32_le(&buf, strlen(pol->allowed_keysalts)); 126 k5_buf_add(&buf, pol->allowed_keysalts); 127 } 128 129 k5_buf_add_uint16_le(&buf, pol->n_tl_data); 130 put_tl_data(&buf, pol->tl_data); 131 132 if (k5_buf_status(&buf) != 0) 133 return ENOMEM; 134 135 *enc_out = buf.data; 136 *len_out = buf.len; 137 return 0; 138 } 139 140 static krb5_error_code 141 get_tl_data(struct k5input *in, size_t count, krb5_tl_data **tl) 142 { 143 krb5_error_code ret; 144 const uint8_t *contents; 145 size_t i, len; 146 147 for (i = 0; i < count; i++) { 148 *tl = k5alloc(sizeof(**tl), &ret); 149 if (*tl == NULL) 150 return ret; 151 (*tl)->tl_data_type = k5_input_get_uint16_le(in); 152 len = (*tl)->tl_data_length = k5_input_get_uint16_le(in); 153 contents = k5_input_get_bytes(in, len); 154 if (contents == NULL) 155 return KRB5_KDB_TRUNCATED_RECORD; 156 (*tl)->tl_data_contents = k5memdup(contents, len, &ret); 157 if ((*tl)->tl_data_contents == NULL) 158 return ret; 159 tl = &(*tl)->tl_data_next; 160 } 161 162 return 0; 163 } 164 165 krb5_error_code 166 klmdb_decode_princ(krb5_context context, const void *key, size_t key_len, 167 const void *enc, size_t enc_len, krb5_db_entry **entry_out) 168 { 169 krb5_error_code ret; 170 struct k5input in; 171 krb5_db_entry *entry = NULL; 172 char *princname = NULL; 173 const uint8_t *contents; 174 int i, j; 175 size_t len; 176 krb5_key_data *kd; 177 178 *entry_out = NULL; 179 180 entry = k5alloc(sizeof(*entry), &ret); 181 if (entry == NULL) 182 goto cleanup; 183 184 princname = k5memdup0(key, key_len, &ret); 185 if (princname == NULL) 186 goto cleanup; 187 ret = krb5_parse_name(context, princname, &entry->princ); 188 if (ret) 189 goto cleanup; 190 191 k5_input_init(&in, enc, enc_len); 192 entry->attributes = k5_input_get_uint32_le(&in); 193 entry->max_life = k5_input_get_uint32_le(&in); 194 entry->max_renewable_life = k5_input_get_uint32_le(&in); 195 entry->expiration = k5_input_get_uint32_le(&in); 196 entry->pw_expiration = k5_input_get_uint32_le(&in); 197 entry->n_tl_data = k5_input_get_uint16_le(&in); 198 entry->n_key_data = k5_input_get_uint16_le(&in); 199 if (entry->n_tl_data < 0 || entry->n_key_data < 0) { 200 ret = KRB5_KDB_TRUNCATED_RECORD; 201 goto cleanup; 202 } 203 204 ret = get_tl_data(&in, entry->n_tl_data, &entry->tl_data); 205 if (ret) 206 goto cleanup; 207 208 if (entry->n_key_data > 0) { 209 entry->key_data = k5calloc(entry->n_key_data, sizeof(*entry->key_data), 210 &ret); 211 if (entry->key_data == NULL) 212 goto cleanup; 213 } 214 for (i = 0; i < entry->n_key_data; i++) { 215 kd = &entry->key_data[i]; 216 kd->key_data_ver = k5_input_get_uint16_le(&in); 217 kd->key_data_kvno = k5_input_get_uint16_le(&in); 218 if (kd->key_data_ver < 0 && 219 kd->key_data_ver > KRB5_KDB_V1_KEY_DATA_ARRAY) { 220 ret = KRB5_KDB_BAD_VERSION; 221 goto cleanup; 222 } 223 for (j = 0; j < kd->key_data_ver; j++) { 224 kd->key_data_type[j] = k5_input_get_uint16_le(&in); 225 len = kd->key_data_length[j] = k5_input_get_uint16_le(&in); 226 contents = k5_input_get_bytes(&in, len); 227 if (contents == NULL) { 228 ret = KRB5_KDB_TRUNCATED_RECORD; 229 goto cleanup; 230 } 231 if (len > 0) { 232 kd->key_data_contents[j] = k5memdup(contents, len, &ret); 233 if (kd->key_data_contents[j] == NULL) 234 goto cleanup; 235 } 236 } 237 } 238 239 ret = in.status; 240 if (ret) 241 goto cleanup; 242 243 entry->len = KRB5_KDB_V1_BASE_LENGTH; 244 *entry_out = entry; 245 entry = NULL; 246 247 cleanup: 248 free(princname); 249 krb5_db_free_principal(context, entry); 250 return ret; 251 } 252 253 void 254 klmdb_decode_princ_lockout(krb5_context context, krb5_db_entry *entry, 255 const uint8_t buf[LOCKOUT_RECORD_LEN]) 256 { 257 entry->last_success = load_32_le(buf); 258 entry->last_failed = load_32_le(buf + 4); 259 entry->fail_auth_count = load_32_le(buf + 8); 260 } 261 262 krb5_error_code 263 klmdb_decode_policy(krb5_context context, const void *key, size_t key_len, 264 const void *enc, size_t enc_len, osa_policy_ent_t *pol_out) 265 { 266 krb5_error_code ret; 267 osa_policy_ent_t pol = NULL; 268 struct k5input in; 269 const char *str; 270 size_t len; 271 272 *pol_out = NULL; 273 pol = k5alloc(sizeof(*pol), &ret); 274 if (pol == NULL) 275 goto error; 276 277 pol->name = k5memdup0(key, key_len, &ret); 278 if (pol->name == NULL) 279 goto error; 280 281 k5_input_init(&in, enc, enc_len); 282 pol->pw_min_life = k5_input_get_uint32_le(&in); 283 pol->pw_max_life = k5_input_get_uint32_le(&in); 284 pol->pw_min_length = k5_input_get_uint32_le(&in); 285 pol->pw_min_classes = k5_input_get_uint32_le(&in); 286 pol->pw_history_num = k5_input_get_uint32_le(&in); 287 pol->pw_max_fail = k5_input_get_uint32_le(&in); 288 pol->pw_failcnt_interval = k5_input_get_uint32_le(&in); 289 pol->pw_lockout_duration = k5_input_get_uint32_le(&in); 290 pol->attributes = k5_input_get_uint32_le(&in); 291 pol->max_life = k5_input_get_uint32_le(&in); 292 pol->max_renewable_life = k5_input_get_uint32_le(&in); 293 294 len = k5_input_get_uint32_le(&in); 295 if (len > 0) { 296 str = (char *)k5_input_get_bytes(&in, len); 297 if (str == NULL) { 298 ret = KRB5_KDB_TRUNCATED_RECORD; 299 goto error; 300 } 301 pol->allowed_keysalts = k5memdup0(str, len, &ret); 302 if (pol->allowed_keysalts == NULL) 303 goto error; 304 } 305 306 pol->n_tl_data = k5_input_get_uint16_le(&in); 307 ret = get_tl_data(&in, pol->n_tl_data, &pol->tl_data); 308 if (ret) 309 goto error; 310 311 ret = in.status; 312 if (ret) 313 goto error; 314 315 *pol_out = pol; 316 return 0; 317 318 error: 319 krb5_db_free_policy(context, pol); 320 return ret; 321 } 322