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
put_tl_data(struct k5buf * buf,const krb5_tl_data * tl)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
klmdb_encode_princ(krb5_context context,const krb5_db_entry * entry,uint8_t ** enc_out,size_t * len_out)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
klmdb_encode_princ_lockout(krb5_context context,const krb5_db_entry * entry,uint8_t buf[LOCKOUT_RECORD_LEN])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
klmdb_encode_policy(krb5_context context,const osa_policy_ent_rec * pol,uint8_t ** enc_out,size_t * len_out)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
get_tl_data(struct k5input * in,size_t count,krb5_tl_data ** tl)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
klmdb_decode_princ(krb5_context context,const void * key,size_t key_len,const void * enc,size_t enc_len,krb5_db_entry ** entry_out)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
klmdb_decode_princ_lockout(krb5_context context,krb5_db_entry * entry,const uint8_t buf[LOCKOUT_RECORD_LEN])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
klmdb_decode_policy(krb5_context context,const void * key,size_t key_len,const void * enc,size_t enc_len,osa_policy_ent_t * pol_out)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