172445Sassar/* 2233294Sstas * Copyright (c) 2000 Kungliga Tekniska H��gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 5233294Sstas * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 9233294Sstas * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 12233294Sstas * 1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1472445Sassar * notice, this list of conditions and the following disclaimer in the 1572445Sassar * documentation and/or other materials provided with the distribution. 16233294Sstas * 1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 20233294Sstas * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "hprop.h" 3572445Sassar 3672445Sassar/* 3772445Sassarcan have any number of princ stanzas. 3872445Sassarformat is as follows (only \n indicates newlines) 3972445Sassarprinc\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) 4072445Sassar%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) 4172445Sassar%d\t (number of tl_data) 4272445Sassar%d\t (number of key data, e.g. how many keys for this user) 43233294Sstas%d\t (extra data length) 4472445Sassar%s\t (principal name) 4572445Sassar%d\t (attributes) 4672445Sassar%d\t (max lifetime, seconds) 4772445Sassar%d\t (max renewable life, seconds) 4872445Sassar%d\t (expiration, seconds since epoch or 2145830400 for never) 49233294Sstas%d\t (password expiration, seconds, 0 for never) 5072445Sassar%d\t (last successful auth, seconds since epoch) 5172445Sassar%d\t (last failed auth, per above) 5272445Sassar%d\t (failed auth count) 5372445Sassarforeach tl_data 0 to number of tl_data - 1 as above 5472445Sassar %d\t%d\t (data type, data length) 5572445Sassar foreach tl_data 0 to length-1 5672445Sassar %02x (tl data contents[element n]) 5772445Sassar except if tl_data length is 0 5872445Sassar %d (always -1) 5972445Sassar \t 6072445Sassarforeach key 0 to number of keys - 1 as above 6172445Sassar %d\t%d\t (key data version, kvno) 6272445Sassar foreach version 0 to key data version - 1 (a key or a salt) 6372445Sassar %d\t%d\t(data type for this key, data length for this key) 6472445Sassar foreach key data length 0 to length-1 6572445Sassar %02x (key data contents[element n]) 6672445Sassar except if key_data length is 0 6772445Sassar %d (always -1) 68233294Sstas \t 6972445Sassarforeach extra data length 0 to length - 1 7072445Sassar %02x (extra data part) 7172445Sassarunless no extra data 7272445Sassar %d (always -1) 7372445Sassar;\n 7472445Sassar 7572445Sassar*/ 7672445Sassar 7772445Sassarstatic int 7872445Sassarhex_to_octet_string(const char *ptr, krb5_data *data) 7972445Sassar{ 80233294Sstas size_t i; 8172445Sassar unsigned int v; 8272445Sassar for(i = 0; i < data->length; i++) { 8372445Sassar if(sscanf(ptr + 2 * i, "%02x", &v) != 1) 8472445Sassar return -1; 8572445Sassar ((unsigned char*)data->data)[i] = v; 8672445Sassar } 8772445Sassar return 2 * i; 8872445Sassar} 8972445Sassar 9072445Sassarstatic char * 9172445Sassarnexttoken(char **p) 9272445Sassar{ 9372445Sassar char *q; 9472445Sassar do { 9572445Sassar q = strsep(p, " \t"); 9672445Sassar } while(q && *q == '\0'); 9772445Sassar return q; 9872445Sassar} 9972445Sassar 10072445Sassarstatic size_t 10172445Sassargetdata(char **p, unsigned char *buf, size_t len) 10272445Sassar{ 10372445Sassar size_t i; 10472445Sassar int v; 10572445Sassar char *q = nexttoken(p); 10672445Sassar i = 0; 10772445Sassar while(*q && i < len) { 10872445Sassar if(sscanf(q, "%02x", &v) != 1) 10972445Sassar break; 11072445Sassar buf[i++] = v; 11172445Sassar q += 2; 11272445Sassar } 11372445Sassar return i; 11472445Sassar} 11572445Sassar 11672445Sassarstatic int 11772445Sassargetint(char **p) 11872445Sassar{ 11972445Sassar int val; 12072445Sassar char *q = nexttoken(p); 12172445Sassar sscanf(q, "%d", &val); 12272445Sassar return val; 12372445Sassar} 12472445Sassar 12572445Sassar#include <kadm5/admin.h> 12672445Sassar 12772445Sassarstatic void 12872445Sassarattr_to_flags(unsigned attr, HDBFlags *flags) 12972445Sassar{ 13072445Sassar flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); 13172445Sassar flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); 13272445Sassar flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); 13372445Sassar flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); 13472445Sassar flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); 13572445Sassar /* DUP_SKEY */ 13672445Sassar flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); 13772445Sassar flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); 138233294Sstas flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); 13972445Sassar flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); 14072445Sassar flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); 14172445Sassar flags->client = 1; /* XXX */ 14272445Sassar} 14372445Sassar 14472445Sassar#define KRB5_KDB_SALTTYPE_NORMAL 0 14572445Sassar#define KRB5_KDB_SALTTYPE_V4 1 14672445Sassar#define KRB5_KDB_SALTTYPE_NOREALM 2 14772445Sassar#define KRB5_KDB_SALTTYPE_ONLYREALM 3 14872445Sassar#define KRB5_KDB_SALTTYPE_SPECIAL 4 14972445Sassar#define KRB5_KDB_SALTTYPE_AFS3 5 15072445Sassar 15172445Sassarstatic krb5_error_code 15272445Sassarfix_salt(krb5_context context, hdb_entry *ent, int key_num) 15372445Sassar{ 15472445Sassar krb5_error_code ret; 15572445Sassar Salt *salt = ent->keys.val[key_num].salt; 15672445Sassar /* fix salt type */ 15772445Sassar switch((int)salt->type) { 15872445Sassar case KRB5_KDB_SALTTYPE_NORMAL: 15972445Sassar salt->type = KRB5_PADATA_PW_SALT; 16072445Sassar break; 16172445Sassar case KRB5_KDB_SALTTYPE_V4: 16272445Sassar krb5_data_free(&salt->salt); 16372445Sassar salt->type = KRB5_PADATA_PW_SALT; 16472445Sassar break; 16572445Sassar case KRB5_KDB_SALTTYPE_NOREALM: 16672445Sassar { 16772445Sassar size_t len; 168233294Sstas size_t i; 16972445Sassar char *p; 170233294Sstas 17172445Sassar len = 0; 17272445Sassar for (i = 0; i < ent->principal->name.name_string.len; ++i) 17372445Sassar len += strlen(ent->principal->name.name_string.val[i]); 17472445Sassar ret = krb5_data_alloc (&salt->salt, len); 17572445Sassar if (ret) 17672445Sassar return ret; 17772445Sassar p = salt->salt.data; 17872445Sassar for (i = 0; i < ent->principal->name.name_string.len; ++i) { 17972445Sassar memcpy (p, 18072445Sassar ent->principal->name.name_string.val[i], 18172445Sassar strlen(ent->principal->name.name_string.val[i])); 18272445Sassar p += strlen(ent->principal->name.name_string.val[i]); 18372445Sassar } 18472445Sassar 18572445Sassar salt->type = KRB5_PADATA_PW_SALT; 18672445Sassar break; 18772445Sassar } 18872445Sassar case KRB5_KDB_SALTTYPE_ONLYREALM: 18972445Sassar krb5_data_free(&salt->salt); 190233294Sstas ret = krb5_data_copy(&salt->salt, 191233294Sstas ent->principal->realm, 19272445Sassar strlen(ent->principal->realm)); 19372445Sassar if(ret) 19472445Sassar return ret; 19572445Sassar salt->type = KRB5_PADATA_PW_SALT; 19672445Sassar break; 19772445Sassar case KRB5_KDB_SALTTYPE_SPECIAL: 19872445Sassar salt->type = KRB5_PADATA_PW_SALT; 19972445Sassar break; 20072445Sassar case KRB5_KDB_SALTTYPE_AFS3: 20172445Sassar krb5_data_free(&salt->salt); 202233294Sstas ret = krb5_data_copy(&salt->salt, 203233294Sstas ent->principal->realm, 20472445Sassar strlen(ent->principal->realm)); 20572445Sassar if(ret) 20672445Sassar return ret; 20772445Sassar salt->type = KRB5_PADATA_AFS3_SALT; 20872445Sassar break; 20972445Sassar default: 21072445Sassar abort(); 21172445Sassar } 21272445Sassar return 0; 21372445Sassar} 21472445Sassar 21572445Sassarint 21672445Sassarmit_prop_dump(void *arg, const char *file) 21772445Sassar{ 21872445Sassar krb5_error_code ret; 219178825Sdfr char line [2048]; 22072445Sassar FILE *f; 22172445Sassar int lineno = 0; 222178825Sdfr struct hdb_entry_ex ent; 22372445Sassar 22472445Sassar struct prop_data *pd = arg; 22572445Sassar 22672445Sassar f = fopen(file, "r"); 22772445Sassar if(f == NULL) 22872445Sassar return errno; 229233294Sstas 230178825Sdfr while(fgets(line, sizeof(line), f)) { 231178825Sdfr char *p = line, *q; 23272445Sassar 23372445Sassar int i; 23472445Sassar 23572445Sassar int num_tl_data; 23672445Sassar int num_key_data; 237233294Sstas int high_kvno; 23872445Sassar int attributes; 23972445Sassar 24072445Sassar int tmp; 24172445Sassar 24272445Sassar lineno++; 24372445Sassar 24472445Sassar memset(&ent, 0, sizeof(ent)); 24572445Sassar 24672445Sassar q = nexttoken(&p); 24772445Sassar if(strcmp(q, "kdb5_util") == 0) { 24872445Sassar int major; 24972445Sassar q = nexttoken(&p); /* load_dump */ 25072445Sassar if(strcmp(q, "load_dump")) 25172445Sassar errx(1, "line %d: unknown version", lineno); 25272445Sassar q = nexttoken(&p); /* load_dump */ 25372445Sassar if(strcmp(q, "version")) 25472445Sassar errx(1, "line %d: unknown version", lineno); 25572445Sassar q = nexttoken(&p); /* x.0 */ 25672445Sassar if(sscanf(q, "%d", &major) != 1) 25772445Sassar errx(1, "line %d: unknown version", lineno); 258233294Sstas if(major != 4 && major != 5 && major != 6) 259233294Sstas errx(1, "unknown dump file format, got %d, expected 4-6", 260233294Sstas major); 26172445Sassar continue; 262233294Sstas } else if(strcmp(q, "policy") == 0) { 263233294Sstas continue; 26472445Sassar } else if(strcmp(q, "princ") != 0) { 26572445Sassar warnx("line %d: not a principal", lineno); 26672445Sassar continue; 26772445Sassar } 26872445Sassar tmp = getint(&p); 26972445Sassar if(tmp != 38) { 27072445Sassar warnx("line %d: bad base length %d != 38", lineno, tmp); 27172445Sassar continue; 27272445Sassar } 273233294Sstas nexttoken(&p); /* length of principal */ 27472445Sassar num_tl_data = getint(&p); /* number of tl-data */ 27572445Sassar num_key_data = getint(&p); /* number of key-data */ 276233294Sstas getint(&p); /* length of extra data */ 27772445Sassar q = nexttoken(&p); /* principal name */ 278178825Sdfr krb5_parse_name(pd->context, q, &ent.entry.principal); 27972445Sassar attributes = getint(&p); /* attributes */ 280178825Sdfr attr_to_flags(attributes, &ent.entry.flags); 28172445Sassar tmp = getint(&p); /* max life */ 28272445Sassar if(tmp != 0) { 283178825Sdfr ALLOC(ent.entry.max_life); 284178825Sdfr *ent.entry.max_life = tmp; 28572445Sassar } 28672445Sassar tmp = getint(&p); /* max renewable life */ 28772445Sassar if(tmp != 0) { 288178825Sdfr ALLOC(ent.entry.max_renew); 289178825Sdfr *ent.entry.max_renew = tmp; 29072445Sassar } 29172445Sassar tmp = getint(&p); /* expiration */ 29272445Sassar if(tmp != 0 && tmp != 2145830400) { 293178825Sdfr ALLOC(ent.entry.valid_end); 294178825Sdfr *ent.entry.valid_end = tmp; 29572445Sassar } 29672445Sassar tmp = getint(&p); /* pw expiration */ 29772445Sassar if(tmp != 0) { 298178825Sdfr ALLOC(ent.entry.pw_end); 299178825Sdfr *ent.entry.pw_end = tmp; 30072445Sassar } 301233294Sstas nexttoken(&p); /* last auth */ 302233294Sstas nexttoken(&p); /* last failed auth */ 303233294Sstas nexttoken(&p); /* fail auth count */ 30472445Sassar for(i = 0; i < num_tl_data; i++) { 30572445Sassar unsigned long val; 30672445Sassar int tl_type, tl_length; 30772445Sassar unsigned char *buf; 30872445Sassar krb5_principal princ; 30972445Sassar 31072445Sassar tl_type = getint(&p); /* data type */ 31172445Sassar tl_length = getint(&p); /* data length */ 31272445Sassar 313178825Sdfr#define mit_KRB5_TL_LAST_PWD_CHANGE 1 314178825Sdfr#define mit_KRB5_TL_MOD_PRINC 2 31572445Sassar switch(tl_type) { 316233294Sstas case mit_KRB5_TL_LAST_PWD_CHANGE: 317233294Sstas buf = malloc(tl_length); 318233294Sstas if (buf == NULL) 319233294Sstas errx(ENOMEM, "malloc"); 320233294Sstas getdata(&p, buf, tl_length); /* data itself */ 321233294Sstas val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 322233294Sstas free(buf); 323233294Sstas ALLOC(ent.entry.extensions); 324233294Sstas ALLOC_SEQ(ent.entry.extensions, 1); 325233294Sstas ent.entry.extensions->val[0].mandatory = 0; 326233294Sstas ent.entry.extensions->val[0].data.element 327233294Sstas = choice_HDB_extension_data_last_pw_change; 328233294Sstas ent.entry.extensions->val[0].data.u.last_pw_change = val; 329233294Sstas break; 330178825Sdfr case mit_KRB5_TL_MOD_PRINC: 33172445Sassar buf = malloc(tl_length); 332178825Sdfr if (buf == NULL) 333178825Sdfr errx(ENOMEM, "malloc"); 33472445Sassar getdata(&p, buf, tl_length); /* data itself */ 33572445Sassar val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 336178825Sdfr ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ); 337233294Sstas if (ret) 338233294Sstas krb5_err(pd->context, 1, ret, 339233294Sstas "parse_name: %s", (char *)buf + 4); 34072445Sassar free(buf); 341178825Sdfr ALLOC(ent.entry.modified_by); 342178825Sdfr ent.entry.modified_by->time = val; 343178825Sdfr ent.entry.modified_by->principal = princ; 34472445Sassar break; 34572445Sassar default: 34672445Sassar nexttoken(&p); 34772445Sassar break; 34872445Sassar } 34972445Sassar } 350178825Sdfr ALLOC_SEQ(&ent.entry.keys, num_key_data); 351233294Sstas high_kvno = -1; 35272445Sassar for(i = 0; i < num_key_data; i++) { 35372445Sassar int key_versions; 354233294Sstas int kvno; 35572445Sassar key_versions = getint(&p); /* key data version */ 356233294Sstas kvno = getint(&p); 357233294Sstas 358233294Sstas /* 359233294Sstas * An MIT dump file may contain multiple sets of keys with 360233294Sstas * different kvnos. Since the Heimdal database can only represent 361233294Sstas * one kvno per principal, we only want the highest set. Assume 362233294Sstas * that set will be given first, and discard all keys with lower 363233294Sstas * kvnos. 364233294Sstas */ 365233294Sstas if (kvno > high_kvno && high_kvno != -1) 366233294Sstas errx(1, "line %d: high kvno keys given after low kvno keys", 367233294Sstas lineno); 368233294Sstas else if (kvno < high_kvno) { 369233294Sstas nexttoken(&p); /* key type */ 370233294Sstas nexttoken(&p); /* key length */ 371233294Sstas nexttoken(&p); /* key */ 372233294Sstas if (key_versions > 1) { 373233294Sstas nexttoken(&p); /* salt type */ 374233294Sstas nexttoken(&p); /* salt length */ 375233294Sstas nexttoken(&p); /* salt */ 376233294Sstas } 377233294Sstas ent.entry.keys.len--; 378233294Sstas continue; 379233294Sstas } 380233294Sstas ent.entry.kvno = kvno; 381233294Sstas high_kvno = kvno; 382178825Sdfr ALLOC(ent.entry.keys.val[i].mkvno); 383233294Sstas *ent.entry.keys.val[i].mkvno = 1; 384233294Sstas 38572445Sassar /* key version 0 -- actual key */ 386178825Sdfr ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */ 38772445Sassar tmp = getint(&p); /* key length */ 38872445Sassar /* the first two bytes of the key is the key length -- 38972445Sassar skip it */ 390178825Sdfr krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2); 39172445Sassar q = nexttoken(&p); /* key itself */ 392178825Sdfr hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue); 39372445Sassar 39472445Sassar if(key_versions > 1) { 39572445Sassar /* key version 1 -- optional salt */ 396178825Sdfr ALLOC(ent.entry.keys.val[i].salt); 397178825Sdfr ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */ 39872445Sassar tmp = getint(&p); /* salt length */ 39972445Sassar if(tmp > 0) { 400178825Sdfr krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2); 40172445Sassar q = nexttoken(&p); /* salt itself */ 402178825Sdfr hex_to_octet_string(q + 4, 403178825Sdfr &ent.entry.keys.val[i].salt->salt); 40472445Sassar } else { 405178825Sdfr ent.entry.keys.val[i].salt->salt.length = 0; 406178825Sdfr ent.entry.keys.val[i].salt->salt.data = NULL; 407233294Sstas getint(&p); /* -1, if no data. */ 40872445Sassar } 409178825Sdfr fix_salt(pd->context, &ent.entry, i); 41072445Sassar } 41172445Sassar } 412233294Sstas nexttoken(&p); /* extra data */ 41372445Sassar v5_prop(pd->context, NULL, &ent, arg); 41472445Sassar } 415178825Sdfr fclose(f); 41672445Sassar return 0; 41772445Sassar} 418