xref: /freebsd/crypto/krb5/src/plugins/kdb/lmdb/marshal.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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