Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kdc/mit_dump.c
34869 views
1
/*
2
* Copyright (c) 2000 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 "hprop.h"
35
36
/*
37
can have any number of princ stanzas.
38
format is as follows (only \n indicates newlines)
39
princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38)
40
%d\t (strlen of principal e.g. shadow/[email protected])
41
%d\t (number of tl_data)
42
%d\t (number of key data, e.g. how many keys for this user)
43
%d\t (extra data length)
44
%s\t (principal name)
45
%d\t (attributes)
46
%d\t (max lifetime, seconds)
47
%d\t (max renewable life, seconds)
48
%d\t (expiration, seconds since epoch or 2145830400 for never)
49
%d\t (password expiration, seconds, 0 for never)
50
%d\t (last successful auth, seconds since epoch)
51
%d\t (last failed auth, per above)
52
%d\t (failed auth count)
53
foreach tl_data 0 to number of tl_data - 1 as above
54
%d\t%d\t (data type, data length)
55
foreach tl_data 0 to length-1
56
%02x (tl data contents[element n])
57
except if tl_data length is 0
58
%d (always -1)
59
\t
60
foreach key 0 to number of keys - 1 as above
61
%d\t%d\t (key data version, kvno)
62
foreach version 0 to key data version - 1 (a key or a salt)
63
%d\t%d\t(data type for this key, data length for this key)
64
foreach key data length 0 to length-1
65
%02x (key data contents[element n])
66
except if key_data length is 0
67
%d (always -1)
68
\t
69
foreach extra data length 0 to length - 1
70
%02x (extra data part)
71
unless no extra data
72
%d (always -1)
73
;\n
74
75
*/
76
77
static int
78
hex_to_octet_string(const char *ptr, krb5_data *data)
79
{
80
size_t i;
81
unsigned int v;
82
for(i = 0; i < data->length; i++) {
83
if(sscanf(ptr + 2 * i, "%02x", &v) != 1)
84
return -1;
85
((unsigned char*)data->data)[i] = v;
86
}
87
return 2 * i;
88
}
89
90
static char *
91
nexttoken(char **p)
92
{
93
char *q;
94
do {
95
q = strsep(p, " \t");
96
} while(q && *q == '\0');
97
return q;
98
}
99
100
static size_t
101
getdata(char **p, unsigned char *buf, size_t len)
102
{
103
size_t i;
104
int v;
105
char *q = nexttoken(p);
106
i = 0;
107
while(*q && i < len) {
108
if(sscanf(q, "%02x", &v) != 1)
109
break;
110
buf[i++] = v;
111
q += 2;
112
}
113
return i;
114
}
115
116
static int
117
getint(char **p)
118
{
119
int val;
120
char *q = nexttoken(p);
121
sscanf(q, "%d", &val);
122
return val;
123
}
124
125
#include <kadm5/admin.h>
126
127
static void
128
attr_to_flags(unsigned attr, HDBFlags *flags)
129
{
130
flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED);
131
flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE);
132
flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED);
133
flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE);
134
flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE);
135
/* DUP_SKEY */
136
flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX);
137
flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH);
138
flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH);
139
flags->server = !(attr & KRB5_KDB_DISALLOW_SVR);
140
flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
141
flags->client = 1; /* XXX */
142
}
143
144
#define KRB5_KDB_SALTTYPE_NORMAL 0
145
#define KRB5_KDB_SALTTYPE_V4 1
146
#define KRB5_KDB_SALTTYPE_NOREALM 2
147
#define KRB5_KDB_SALTTYPE_ONLYREALM 3
148
#define KRB5_KDB_SALTTYPE_SPECIAL 4
149
#define KRB5_KDB_SALTTYPE_AFS3 5
150
151
static krb5_error_code
152
fix_salt(krb5_context context, hdb_entry *ent, int key_num)
153
{
154
krb5_error_code ret;
155
Salt *salt = ent->keys.val[key_num].salt;
156
/* fix salt type */
157
switch((int)salt->type) {
158
case KRB5_KDB_SALTTYPE_NORMAL:
159
salt->type = KRB5_PADATA_PW_SALT;
160
break;
161
case KRB5_KDB_SALTTYPE_V4:
162
krb5_data_free(&salt->salt);
163
salt->type = KRB5_PADATA_PW_SALT;
164
break;
165
case KRB5_KDB_SALTTYPE_NOREALM:
166
{
167
size_t len;
168
size_t i;
169
char *p;
170
171
len = 0;
172
for (i = 0; i < ent->principal->name.name_string.len; ++i)
173
len += strlen(ent->principal->name.name_string.val[i]);
174
ret = krb5_data_alloc (&salt->salt, len);
175
if (ret)
176
return ret;
177
p = salt->salt.data;
178
for (i = 0; i < ent->principal->name.name_string.len; ++i) {
179
memcpy (p,
180
ent->principal->name.name_string.val[i],
181
strlen(ent->principal->name.name_string.val[i]));
182
p += strlen(ent->principal->name.name_string.val[i]);
183
}
184
185
salt->type = KRB5_PADATA_PW_SALT;
186
break;
187
}
188
case KRB5_KDB_SALTTYPE_ONLYREALM:
189
krb5_data_free(&salt->salt);
190
ret = krb5_data_copy(&salt->salt,
191
ent->principal->realm,
192
strlen(ent->principal->realm));
193
if(ret)
194
return ret;
195
salt->type = KRB5_PADATA_PW_SALT;
196
break;
197
case KRB5_KDB_SALTTYPE_SPECIAL:
198
salt->type = KRB5_PADATA_PW_SALT;
199
break;
200
case KRB5_KDB_SALTTYPE_AFS3:
201
krb5_data_free(&salt->salt);
202
ret = krb5_data_copy(&salt->salt,
203
ent->principal->realm,
204
strlen(ent->principal->realm));
205
if(ret)
206
return ret;
207
salt->type = KRB5_PADATA_AFS3_SALT;
208
break;
209
default:
210
abort();
211
}
212
return 0;
213
}
214
215
int
216
mit_prop_dump(void *arg, const char *file)
217
{
218
krb5_error_code ret;
219
char line [2048];
220
FILE *f;
221
int lineno = 0;
222
struct hdb_entry_ex ent;
223
224
struct prop_data *pd = arg;
225
226
f = fopen(file, "r");
227
if(f == NULL)
228
return errno;
229
230
while(fgets(line, sizeof(line), f)) {
231
char *p = line, *q;
232
233
int i;
234
235
int num_tl_data;
236
int num_key_data;
237
int high_kvno;
238
int attributes;
239
240
int tmp;
241
242
lineno++;
243
244
memset(&ent, 0, sizeof(ent));
245
246
q = nexttoken(&p);
247
if(strcmp(q, "kdb5_util") == 0) {
248
int major;
249
q = nexttoken(&p); /* load_dump */
250
if(strcmp(q, "load_dump"))
251
errx(1, "line %d: unknown version", lineno);
252
q = nexttoken(&p); /* load_dump */
253
if(strcmp(q, "version"))
254
errx(1, "line %d: unknown version", lineno);
255
q = nexttoken(&p); /* x.0 */
256
if(sscanf(q, "%d", &major) != 1)
257
errx(1, "line %d: unknown version", lineno);
258
if(major != 4 && major != 5 && major != 6)
259
errx(1, "unknown dump file format, got %d, expected 4-6",
260
major);
261
continue;
262
} else if(strcmp(q, "policy") == 0) {
263
continue;
264
} else if(strcmp(q, "princ") != 0) {
265
warnx("line %d: not a principal", lineno);
266
continue;
267
}
268
tmp = getint(&p);
269
if(tmp != 38) {
270
warnx("line %d: bad base length %d != 38", lineno, tmp);
271
continue;
272
}
273
nexttoken(&p); /* length of principal */
274
num_tl_data = getint(&p); /* number of tl-data */
275
num_key_data = getint(&p); /* number of key-data */
276
getint(&p); /* length of extra data */
277
q = nexttoken(&p); /* principal name */
278
krb5_parse_name(pd->context, q, &ent.entry.principal);
279
attributes = getint(&p); /* attributes */
280
attr_to_flags(attributes, &ent.entry.flags);
281
tmp = getint(&p); /* max life */
282
if(tmp != 0) {
283
ALLOC(ent.entry.max_life);
284
*ent.entry.max_life = tmp;
285
}
286
tmp = getint(&p); /* max renewable life */
287
if(tmp != 0) {
288
ALLOC(ent.entry.max_renew);
289
*ent.entry.max_renew = tmp;
290
}
291
tmp = getint(&p); /* expiration */
292
if(tmp != 0 && tmp != 2145830400) {
293
ALLOC(ent.entry.valid_end);
294
*ent.entry.valid_end = tmp;
295
}
296
tmp = getint(&p); /* pw expiration */
297
if(tmp != 0) {
298
ALLOC(ent.entry.pw_end);
299
*ent.entry.pw_end = tmp;
300
}
301
nexttoken(&p); /* last auth */
302
nexttoken(&p); /* last failed auth */
303
nexttoken(&p); /* fail auth count */
304
for(i = 0; i < num_tl_data; i++) {
305
unsigned long val;
306
int tl_type, tl_length;
307
unsigned char *buf;
308
krb5_principal princ;
309
310
tl_type = getint(&p); /* data type */
311
tl_length = getint(&p); /* data length */
312
313
#define mit_KRB5_TL_LAST_PWD_CHANGE 1
314
#define mit_KRB5_TL_MOD_PRINC 2
315
switch(tl_type) {
316
case mit_KRB5_TL_LAST_PWD_CHANGE:
317
buf = malloc(tl_length);
318
if (buf == NULL)
319
errx(ENOMEM, "malloc");
320
getdata(&p, buf, tl_length); /* data itself */
321
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
322
free(buf);
323
ALLOC(ent.entry.extensions);
324
ALLOC_SEQ(ent.entry.extensions, 1);
325
ent.entry.extensions->val[0].mandatory = 0;
326
ent.entry.extensions->val[0].data.element
327
= choice_HDB_extension_data_last_pw_change;
328
ent.entry.extensions->val[0].data.u.last_pw_change = val;
329
break;
330
case mit_KRB5_TL_MOD_PRINC:
331
buf = malloc(tl_length);
332
if (buf == NULL)
333
errx(ENOMEM, "malloc");
334
getdata(&p, buf, tl_length); /* data itself */
335
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
336
ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ);
337
if (ret)
338
krb5_err(pd->context, 1, ret,
339
"parse_name: %s", (char *)buf + 4);
340
free(buf);
341
ALLOC(ent.entry.modified_by);
342
ent.entry.modified_by->time = val;
343
ent.entry.modified_by->principal = princ;
344
break;
345
default:
346
nexttoken(&p);
347
break;
348
}
349
}
350
ALLOC_SEQ(&ent.entry.keys, num_key_data);
351
high_kvno = -1;
352
for(i = 0; i < num_key_data; i++) {
353
int key_versions;
354
int kvno;
355
key_versions = getint(&p); /* key data version */
356
kvno = getint(&p);
357
358
/*
359
* An MIT dump file may contain multiple sets of keys with
360
* different kvnos. Since the Heimdal database can only represent
361
* one kvno per principal, we only want the highest set. Assume
362
* that set will be given first, and discard all keys with lower
363
* kvnos.
364
*/
365
if (kvno > high_kvno && high_kvno != -1)
366
errx(1, "line %d: high kvno keys given after low kvno keys",
367
lineno);
368
else if (kvno < high_kvno) {
369
nexttoken(&p); /* key type */
370
nexttoken(&p); /* key length */
371
nexttoken(&p); /* key */
372
if (key_versions > 1) {
373
nexttoken(&p); /* salt type */
374
nexttoken(&p); /* salt length */
375
nexttoken(&p); /* salt */
376
}
377
ent.entry.keys.len--;
378
continue;
379
}
380
ent.entry.kvno = kvno;
381
high_kvno = kvno;
382
ALLOC(ent.entry.keys.val[i].mkvno);
383
*ent.entry.keys.val[i].mkvno = 1;
384
385
/* key version 0 -- actual key */
386
ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */
387
tmp = getint(&p); /* key length */
388
/* the first two bytes of the key is the key length --
389
skip it */
390
krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2);
391
q = nexttoken(&p); /* key itself */
392
hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue);
393
394
if(key_versions > 1) {
395
/* key version 1 -- optional salt */
396
ALLOC(ent.entry.keys.val[i].salt);
397
ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */
398
tmp = getint(&p); /* salt length */
399
if(tmp > 0) {
400
krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2);
401
q = nexttoken(&p); /* salt itself */
402
hex_to_octet_string(q + 4,
403
&ent.entry.keys.val[i].salt->salt);
404
} else {
405
ent.entry.keys.val[i].salt->salt.length = 0;
406
ent.entry.keys.val[i].salt->salt.data = NULL;
407
getint(&p); /* -1, if no data. */
408
}
409
fix_salt(pd->context, &ent.entry, i);
410
}
411
}
412
nexttoken(&p); /* extra data */
413
v5_prop(pd->context, NULL, &ent, arg);
414
}
415
fclose(f);
416
return 0;
417
}
418
419