1 /* $NetBSD: mit_dump.c,v 1.1.1.1 2011/04/13 18:14:37 elric Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "hprop.h" 37 38 /* 39 can have any number of princ stanzas. 40 format is as follows (only \n indicates newlines) 41 princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) 42 %d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) 43 %d\t (number of tl_data) 44 %d\t (number of key data, e.g. how many keys for this user) 45 %d\t (extra data length) 46 %s\t (principal name) 47 %d\t (attributes) 48 %d\t (max lifetime, seconds) 49 %d\t (max renewable life, seconds) 50 %d\t (expiration, seconds since epoch or 2145830400 for never) 51 %d\t (password expiration, seconds, 0 for never) 52 %d\t (last successful auth, seconds since epoch) 53 %d\t (last failed auth, per above) 54 %d\t (failed auth count) 55 foreach tl_data 0 to number of tl_data - 1 as above 56 %d\t%d\t (data type, data length) 57 foreach tl_data 0 to length-1 58 %02x (tl data contents[element n]) 59 except if tl_data length is 0 60 %d (always -1) 61 \t 62 foreach key 0 to number of keys - 1 as above 63 %d\t%d\t (key data version, kvno) 64 foreach version 0 to key data version - 1 (a key or a salt) 65 %d\t%d\t(data type for this key, data length for this key) 66 foreach key data length 0 to length-1 67 %02x (key data contents[element n]) 68 except if key_data length is 0 69 %d (always -1) 70 \t 71 foreach extra data length 0 to length - 1 72 %02x (extra data part) 73 unless no extra data 74 %d (always -1) 75 ;\n 76 77 */ 78 79 static int 80 hex_to_octet_string(const char *ptr, krb5_data *data) 81 { 82 int i; 83 unsigned int v; 84 for(i = 0; i < data->length; i++) { 85 if(sscanf(ptr + 2 * i, "%02x", &v) != 1) 86 return -1; 87 ((unsigned char*)data->data)[i] = v; 88 } 89 return 2 * i; 90 } 91 92 static char * 93 nexttoken(char **p) 94 { 95 char *q; 96 do { 97 q = strsep(p, " \t"); 98 } while(q && *q == '\0'); 99 return q; 100 } 101 102 static size_t 103 getdata(char **p, unsigned char *buf, size_t len) 104 { 105 size_t i; 106 int v; 107 char *q = nexttoken(p); 108 i = 0; 109 while(*q && i < len) { 110 if(sscanf(q, "%02x", &v) != 1) 111 break; 112 buf[i++] = v; 113 q += 2; 114 } 115 return i; 116 } 117 118 static int 119 getint(char **p) 120 { 121 int val; 122 char *q = nexttoken(p); 123 sscanf(q, "%d", &val); 124 return val; 125 } 126 127 #include <kadm5/admin.h> 128 129 static void 130 attr_to_flags(unsigned attr, HDBFlags *flags) 131 { 132 flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); 133 flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); 134 flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); 135 flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); 136 flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); 137 /* DUP_SKEY */ 138 flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); 139 flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); 140 flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); 141 flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); 142 flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); 143 flags->client = 1; /* XXX */ 144 } 145 146 #define KRB5_KDB_SALTTYPE_NORMAL 0 147 #define KRB5_KDB_SALTTYPE_V4 1 148 #define KRB5_KDB_SALTTYPE_NOREALM 2 149 #define KRB5_KDB_SALTTYPE_ONLYREALM 3 150 #define KRB5_KDB_SALTTYPE_SPECIAL 4 151 #define KRB5_KDB_SALTTYPE_AFS3 5 152 153 static krb5_error_code 154 fix_salt(krb5_context context, hdb_entry *ent, int key_num) 155 { 156 krb5_error_code ret; 157 Salt *salt = ent->keys.val[key_num].salt; 158 /* fix salt type */ 159 switch((int)salt->type) { 160 case KRB5_KDB_SALTTYPE_NORMAL: 161 salt->type = KRB5_PADATA_PW_SALT; 162 break; 163 case KRB5_KDB_SALTTYPE_V4: 164 krb5_data_free(&salt->salt); 165 salt->type = KRB5_PADATA_PW_SALT; 166 break; 167 case KRB5_KDB_SALTTYPE_NOREALM: 168 { 169 size_t len; 170 int i; 171 char *p; 172 173 len = 0; 174 for (i = 0; i < ent->principal->name.name_string.len; ++i) 175 len += strlen(ent->principal->name.name_string.val[i]); 176 ret = krb5_data_alloc (&salt->salt, len); 177 if (ret) 178 return ret; 179 p = salt->salt.data; 180 for (i = 0; i < ent->principal->name.name_string.len; ++i) { 181 memcpy (p, 182 ent->principal->name.name_string.val[i], 183 strlen(ent->principal->name.name_string.val[i])); 184 p += strlen(ent->principal->name.name_string.val[i]); 185 } 186 187 salt->type = KRB5_PADATA_PW_SALT; 188 break; 189 } 190 case KRB5_KDB_SALTTYPE_ONLYREALM: 191 krb5_data_free(&salt->salt); 192 ret = krb5_data_copy(&salt->salt, 193 ent->principal->realm, 194 strlen(ent->principal->realm)); 195 if(ret) 196 return ret; 197 salt->type = KRB5_PADATA_PW_SALT; 198 break; 199 case KRB5_KDB_SALTTYPE_SPECIAL: 200 salt->type = KRB5_PADATA_PW_SALT; 201 break; 202 case KRB5_KDB_SALTTYPE_AFS3: 203 krb5_data_free(&salt->salt); 204 ret = krb5_data_copy(&salt->salt, 205 ent->principal->realm, 206 strlen(ent->principal->realm)); 207 if(ret) 208 return ret; 209 salt->type = KRB5_PADATA_AFS3_SALT; 210 break; 211 default: 212 abort(); 213 } 214 return 0; 215 } 216 217 int 218 mit_prop_dump(void *arg, const char *file) 219 { 220 krb5_error_code ret; 221 char line [2048]; 222 FILE *f; 223 int lineno = 0; 224 struct hdb_entry_ex ent; 225 226 struct prop_data *pd = arg; 227 228 f = fopen(file, "r"); 229 if(f == NULL) 230 return errno; 231 232 while(fgets(line, sizeof(line), f)) { 233 char *p = line, *q; 234 235 int i; 236 237 int num_tl_data; 238 int num_key_data; 239 int high_kvno; 240 int attributes; 241 242 int tmp; 243 244 lineno++; 245 246 memset(&ent, 0, sizeof(ent)); 247 248 q = nexttoken(&p); 249 if(strcmp(q, "kdb5_util") == 0) { 250 int major; 251 q = nexttoken(&p); /* load_dump */ 252 if(strcmp(q, "load_dump")) 253 errx(1, "line %d: unknown version", lineno); 254 q = nexttoken(&p); /* load_dump */ 255 if(strcmp(q, "version")) 256 errx(1, "line %d: unknown version", lineno); 257 q = nexttoken(&p); /* x.0 */ 258 if(sscanf(q, "%d", &major) != 1) 259 errx(1, "line %d: unknown version", lineno); 260 if(major != 4 && major != 5 && major != 6) 261 errx(1, "unknown dump file format, got %d, expected 4-6", 262 major); 263 continue; 264 } else if(strcmp(q, "policy") == 0) { 265 continue; 266 } else if(strcmp(q, "princ") != 0) { 267 warnx("line %d: not a principal", lineno); 268 continue; 269 } 270 tmp = getint(&p); 271 if(tmp != 38) { 272 warnx("line %d: bad base length %d != 38", lineno, tmp); 273 continue; 274 } 275 nexttoken(&p); /* length of principal */ 276 num_tl_data = getint(&p); /* number of tl-data */ 277 num_key_data = getint(&p); /* number of key-data */ 278 getint(&p); /* length of extra data */ 279 q = nexttoken(&p); /* principal name */ 280 krb5_parse_name(pd->context, q, &ent.entry.principal); 281 attributes = getint(&p); /* attributes */ 282 attr_to_flags(attributes, &ent.entry.flags); 283 tmp = getint(&p); /* max life */ 284 if(tmp != 0) { 285 ALLOC(ent.entry.max_life); 286 *ent.entry.max_life = tmp; 287 } 288 tmp = getint(&p); /* max renewable life */ 289 if(tmp != 0) { 290 ALLOC(ent.entry.max_renew); 291 *ent.entry.max_renew = tmp; 292 } 293 tmp = getint(&p); /* expiration */ 294 if(tmp != 0 && tmp != 2145830400) { 295 ALLOC(ent.entry.valid_end); 296 *ent.entry.valid_end = tmp; 297 } 298 tmp = getint(&p); /* pw expiration */ 299 if(tmp != 0) { 300 ALLOC(ent.entry.pw_end); 301 *ent.entry.pw_end = tmp; 302 } 303 nexttoken(&p); /* last auth */ 304 nexttoken(&p); /* last failed auth */ 305 nexttoken(&p); /* fail auth count */ 306 for(i = 0; i < num_tl_data; i++) { 307 unsigned long val; 308 int tl_type, tl_length; 309 unsigned char *buf; 310 krb5_principal princ; 311 312 tl_type = getint(&p); /* data type */ 313 tl_length = getint(&p); /* data length */ 314 315 #define mit_KRB5_TL_LAST_PWD_CHANGE 1 316 #define mit_KRB5_TL_MOD_PRINC 2 317 switch(tl_type) { 318 case mit_KRB5_TL_LAST_PWD_CHANGE: 319 buf = malloc(tl_length); 320 if (buf == NULL) 321 errx(ENOMEM, "malloc"); 322 getdata(&p, buf, tl_length); /* data itself */ 323 val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 324 free(buf); 325 ALLOC(ent.entry.extensions); 326 ALLOC_SEQ(ent.entry.extensions, 1); 327 ent.entry.extensions->val[0].mandatory = 0; 328 ent.entry.extensions->val[0].data.element 329 = choice_HDB_extension_data_last_pw_change; 330 ent.entry.extensions->val[0].data.u.last_pw_change = val; 331 break; 332 case mit_KRB5_TL_MOD_PRINC: 333 buf = malloc(tl_length); 334 if (buf == NULL) 335 errx(ENOMEM, "malloc"); 336 getdata(&p, buf, tl_length); /* data itself */ 337 val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 338 ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ); 339 if (ret) 340 krb5_err(pd->context, 1, ret, 341 "parse_name: %s", (char *)buf + 4); 342 free(buf); 343 ALLOC(ent.entry.modified_by); 344 ent.entry.modified_by->time = val; 345 ent.entry.modified_by->principal = princ; 346 break; 347 default: 348 nexttoken(&p); 349 break; 350 } 351 } 352 ALLOC_SEQ(&ent.entry.keys, num_key_data); 353 high_kvno = -1; 354 for(i = 0; i < num_key_data; i++) { 355 int key_versions; 356 int kvno; 357 key_versions = getint(&p); /* key data version */ 358 kvno = getint(&p); 359 360 /* 361 * An MIT dump file may contain multiple sets of keys with 362 * different kvnos. Since the Heimdal database can only represent 363 * one kvno per principal, we only want the highest set. Assume 364 * that set will be given first, and discard all keys with lower 365 * kvnos. 366 */ 367 if (kvno > high_kvno && high_kvno != -1) 368 errx(1, "line %d: high kvno keys given after low kvno keys", 369 lineno); 370 else if (kvno < high_kvno) { 371 nexttoken(&p); /* key type */ 372 nexttoken(&p); /* key length */ 373 nexttoken(&p); /* key */ 374 if (key_versions > 1) { 375 nexttoken(&p); /* salt type */ 376 nexttoken(&p); /* salt length */ 377 nexttoken(&p); /* salt */ 378 } 379 ent.entry.keys.len--; 380 continue; 381 } 382 ent.entry.kvno = kvno; 383 high_kvno = kvno; 384 ALLOC(ent.entry.keys.val[i].mkvno); 385 *ent.entry.keys.val[i].mkvno = 1; 386 387 /* key version 0 -- actual key */ 388 ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */ 389 tmp = getint(&p); /* key length */ 390 /* the first two bytes of the key is the key length -- 391 skip it */ 392 krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2); 393 q = nexttoken(&p); /* key itself */ 394 hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue); 395 396 if(key_versions > 1) { 397 /* key version 1 -- optional salt */ 398 ALLOC(ent.entry.keys.val[i].salt); 399 ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */ 400 tmp = getint(&p); /* salt length */ 401 if(tmp > 0) { 402 krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2); 403 q = nexttoken(&p); /* salt itself */ 404 hex_to_octet_string(q + 4, 405 &ent.entry.keys.val[i].salt->salt); 406 } else { 407 ent.entry.keys.val[i].salt->salt.length = 0; 408 ent.entry.keys.val[i].salt->salt.data = NULL; 409 getint(&p); /* -1, if no data. */ 410 } 411 fix_salt(pd->context, &ent.entry, i); 412 } 413 } 414 nexttoken(&p); /* extra data */ 415 v5_prop(pd->context, NULL, &ent, arg); 416 } 417 fclose(f); 418 return 0; 419 } 420