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