int mit_prop_dump(void *arg, const char *file) { krb5_error_code ret; char line [2048]; FILE *f; int lineno = 0; struct hdb_entry_ex ent; struct prop_data *pd = arg; f = fopen(file, "r"); if(f == NULL) return errno; while(fgets(line, sizeof(line), f)) { char *p = line, *q; int i; int num_tl_data; int num_key_data; int high_kvno; int attributes; int tmp; lineno++; memset(&ent, 0, sizeof(ent)); q = nexttoken(&p); if(strcmp(q, "kdb5_util") == 0) { int major; q = nexttoken(&p); /* load_dump */ if(strcmp(q, "load_dump")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* load_dump */ if(strcmp(q, "version")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* x.0 */ if(sscanf(q, "%d", &major) != 1) errx(1, "line %d: unknown version", lineno); if(major != 4 && major != 5 && major != 6) errx(1, "unknown dump file format, got %d, expected 4-6", major); continue; } else if(strcmp(q, "policy") == 0) { continue; } else if(strcmp(q, "princ") != 0) { warnx("line %d: not a principal", lineno); continue; } tmp = getint(&p); if(tmp != 38) { warnx("line %d: bad base length %d != 38", lineno, tmp); continue; } nexttoken(&p); /* length of principal */ num_tl_data = getint(&p); /* number of tl-data */ num_key_data = getint(&p); /* number of key-data */ getint(&p); /* length of extra data */ q = nexttoken(&p); /* principal name */ krb5_parse_name(pd->context, q, &ent.entry.principal); attributes = getint(&p); /* attributes */ attr_to_flags(attributes, &ent.entry.flags); tmp = getint(&p); /* max life */ if(tmp != 0) { ALLOC(ent.entry.max_life); *ent.entry.max_life = tmp; } tmp = getint(&p); /* max renewable life */ if(tmp != 0) { ALLOC(ent.entry.max_renew); *ent.entry.max_renew = tmp; } tmp = getint(&p); /* expiration */ if(tmp != 0 && tmp != 2145830400) { ALLOC(ent.entry.valid_end); *ent.entry.valid_end = tmp; } tmp = getint(&p); /* pw expiration */ if(tmp != 0) { ALLOC(ent.entry.pw_end); *ent.entry.pw_end = tmp; } nexttoken(&p); /* last auth */ nexttoken(&p); /* last failed auth */ nexttoken(&p); /* fail auth count */ for(i = 0; i < num_tl_data; i++) { unsigned long val; int tl_type, tl_length; unsigned char *buf; krb5_principal princ; tl_type = getint(&p); /* data type */ tl_length = getint(&p); /* data length */ #define mit_KRB5_TL_LAST_PWD_CHANGE 1 #define mit_KRB5_TL_MOD_PRINC 2 switch(tl_type) { case mit_KRB5_TL_LAST_PWD_CHANGE: buf = malloc(tl_length); if (buf == NULL) errx(ENOMEM, "malloc"); getdata(&p, buf, tl_length); /* data itself */ val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); free(buf); ALLOC(ent.entry.extensions); ALLOC_SEQ(ent.entry.extensions, 1); ent.entry.extensions->val[0].mandatory = 0; ent.entry.extensions->val[0].data.element = choice_HDB_extension_data_last_pw_change; ent.entry.extensions->val[0].data.u.last_pw_change = val; break; case mit_KRB5_TL_MOD_PRINC: buf = malloc(tl_length); if (buf == NULL) errx(ENOMEM, "malloc"); getdata(&p, buf, tl_length); /* data itself */ val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ); if (ret) krb5_err(pd->context, 1, ret, "parse_name: %s", (char *)buf + 4); free(buf); ALLOC(ent.entry.modified_by); ent.entry.modified_by->time = val; ent.entry.modified_by->principal = princ; break; default: nexttoken(&p); break; } } ALLOC_SEQ(&ent.entry.keys, num_key_data); high_kvno = -1; for(i = 0; i < num_key_data; i++) { int key_versions; int kvno; key_versions = getint(&p); /* key data version */ kvno = getint(&p); /* * An MIT dump file may contain multiple sets of keys with * different kvnos. Since the Heimdal database can only represent * one kvno per principal, we only want the highest set. Assume * that set will be given first, and discard all keys with lower * kvnos. */ if (kvno > high_kvno && high_kvno != -1) errx(1, "line %d: high kvno keys given after low kvno keys", lineno); else if (kvno < high_kvno) { nexttoken(&p); /* key type */ nexttoken(&p); /* key length */ nexttoken(&p); /* key */ if (key_versions > 1) { nexttoken(&p); /* salt type */ nexttoken(&p); /* salt length */ nexttoken(&p); /* salt */ } ent.entry.keys.len--; continue; } ent.entry.kvno = kvno; high_kvno = kvno; ALLOC(ent.entry.keys.val[i].mkvno); *ent.entry.keys.val[i].mkvno = 1; /* key version 0 -- actual key */ ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */ tmp = getint(&p); /* key length */ /* the first two bytes of the key is the key length -- skip it */ krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2); q = nexttoken(&p); /* key itself */ hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue); if(key_versions > 1) { /* key version 1 -- optional salt */ ALLOC(ent.entry.keys.val[i].salt); ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */ tmp = getint(&p); /* salt length */ if(tmp > 0) { krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2); q = nexttoken(&p); /* salt itself */ hex_to_octet_string(q + 4, &ent.entry.keys.val[i].salt->salt); } else { ent.entry.keys.val[i].salt->salt.length = 0; ent.entry.keys.val[i].salt->salt.data = NULL; getint(&p); /* -1, if no data. */ } fix_salt(pd->context, &ent.entry, i); } } nexttoken(&p); /* extra data */ v5_prop(pd->context, NULL, &ent, arg); } fclose(f); return 0; }
static int ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent) { int32_t flags = ntohl(ent->flags); krb5_error_code ret; hdb_entry_ex hdb; if(!kaspecials_flag && (flags & KAFNORMAL) == 0) /* remove special entries */ return 0; memset(&hdb, 0, sizeof(hdb)); ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, v4_realm, &hdb.entry.principal); if(ret) { krb5_warn(pd->context, ret, "krb5_425_conv_principal (%s.%s@%s)", ent->name, ent->instance, v4_realm); return 0; } hdb.entry.kvno = ntohl(ent->kvno); hdb.entry.keys.len = 3; hdb.entry.keys.val = malloc(hdb.entry.keys.len * sizeof(*hdb.entry.keys.val)); if (hdb.entry.keys.val == NULL) krb5_errx(pd->context, ENOMEM, "malloc"); hdb.entry.keys.val[0].mkvno = NULL; hdb.entry.keys.val[0].salt = calloc(1, sizeof(*hdb.entry.keys.val[0].salt)); if (hdb.entry.keys.val[0].salt == NULL) krb5_errx(pd->context, ENOMEM, "calloc"); if (ka_use_null_salt) { hdb.entry.keys.val[0].salt->type = hdb_pw_salt; hdb.entry.keys.val[0].salt->salt.data = NULL; hdb.entry.keys.val[0].salt->salt.length = 0; } else { hdb.entry.keys.val[0].salt->type = hdb_afs3_salt; hdb.entry.keys.val[0].salt->salt.data = strdup(afs_cell); if (hdb.entry.keys.val[0].salt->salt.data == NULL) krb5_errx(pd->context, ENOMEM, "strdup"); hdb.entry.keys.val[0].salt->salt.length = strlen(afs_cell); } hdb.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; krb5_data_copy(&hdb.entry.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key)); copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[1]); hdb.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[2]); hdb.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; ALLOC(hdb.entry.max_life); *hdb.entry.max_life = ntohl(ent->max_life); if(ntohl(ent->valid_end) != NEVERDATE && ntohl(ent->valid_end) != 0xffffffff) { ALLOC(hdb.entry.valid_end); *hdb.entry.valid_end = ntohl(ent->valid_end); } if (ntohl(ent->pw_change) != NEVERDATE && ent->pw_expire != 255 && ent->pw_expire != 0) { ALLOC(hdb.entry.pw_end); *hdb.entry.pw_end = ntohl(ent->pw_change) + 24 * 60 * 60 * ent->pw_expire; } ret = krb5_make_principal(pd->context, &hdb.entry.created_by.principal, v4_realm, "kadmin", "hprop", NULL); hdb.entry.created_by.time = time(NULL); if(ent->mod_ptr){ struct ka_entry mod; ALLOC(hdb.entry.modified_by); read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod)); krb5_425_conv_principal(pd->context, mod.name, mod.instance, v4_realm, &hdb.entry.modified_by->principal); hdb.entry.modified_by->time = ntohl(ent->mod_time); memset(&mod, 0, sizeof(mod)); } hdb.entry.flags.forwardable = 1; hdb.entry.flags.renewable = 1; hdb.entry.flags.proxiable = 1; hdb.entry.flags.postdate = 1; /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */ if (strcmp(ent->name, "krbtgt") == 0 && (flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL)) flags &= ~(KAFNOTGS|KAFNOSEAL); hdb.entry.flags.client = (flags & KAFNOTGS) == 0; hdb.entry.flags.server = (flags & KAFNOSEAL) == 0; ret = v5_prop(pd->context, NULL, &hdb, pd); hdb_free_entry(pd->context, &hdb); return ret; }
int mit_prop_dump(void *arg, const char *file) { krb5_error_code ret; char line [2048]; FILE *f; int lineno = 0; struct hdb_entry_ex ent; struct prop_data *pd = arg; f = fopen(file, "r"); if(f == NULL) return errno; while(fgets(line, sizeof(line), f)) { char *p = line, *q; int i; int num_tl_data; int num_key_data; int extra_data_length; int attributes; int tmp; lineno++; memset(&ent, 0, sizeof(ent)); q = nexttoken(&p); if(strcmp(q, "kdb5_util") == 0) { int major; q = nexttoken(&p); /* load_dump */ if(strcmp(q, "load_dump")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* load_dump */ if(strcmp(q, "version")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* x.0 */ if(sscanf(q, "%d", &major) != 1) errx(1, "line %d: unknown version", lineno); if(major != 4) errx(1, "unknown dump file format, got %d, expected 4", major); continue; } else if(strcmp(q, "princ") != 0) { warnx("line %d: not a principal", lineno); continue; } tmp = getint(&p); if(tmp != 38) { warnx("line %d: bad base length %d != 38", lineno, tmp); continue; } q = nexttoken(&p); /* length of principal */ num_tl_data = getint(&p); /* number of tl-data */ num_key_data = getint(&p); /* number of key-data */ extra_data_length = getint(&p); /* length of extra data */ q = nexttoken(&p); /* principal name */ krb5_parse_name(pd->context, q, &ent.entry.principal); attributes = getint(&p); /* attributes */ attr_to_flags(attributes, &ent.entry.flags); tmp = getint(&p); /* max life */ if(tmp != 0) { ALLOC(ent.entry.max_life); *ent.entry.max_life = tmp; } tmp = getint(&p); /* max renewable life */ if(tmp != 0) { ALLOC(ent.entry.max_renew); *ent.entry.max_renew = tmp; } tmp = getint(&p); /* expiration */ if(tmp != 0 && tmp != 2145830400) { ALLOC(ent.entry.valid_end); *ent.entry.valid_end = tmp; } tmp = getint(&p); /* pw expiration */ if(tmp != 0) { ALLOC(ent.entry.pw_end); *ent.entry.pw_end = tmp; } q = nexttoken(&p); /* last auth */ q = nexttoken(&p); /* last failed auth */ q = nexttoken(&p); /* fail auth count */ for(i = 0; i < num_tl_data; i++) { unsigned long val; int tl_type, tl_length; unsigned char *buf; krb5_principal princ; tl_type = getint(&p); /* data type */ tl_length = getint(&p); /* data length */ #define mit_KRB5_TL_LAST_PWD_CHANGE 1 #define mit_KRB5_TL_MOD_PRINC 2 switch(tl_type) { case mit_KRB5_TL_MOD_PRINC: buf = malloc(tl_length); if (buf == NULL) errx(ENOMEM, "malloc"); getdata(&p, buf, tl_length); /* data itself */ val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ); free(buf); ALLOC(ent.entry.modified_by); ent.entry.modified_by->time = val; ent.entry.modified_by->principal = princ; break; default: nexttoken(&p); break; } } ALLOC_SEQ(&ent.entry.keys, num_key_data); for(i = 0; i < num_key_data; i++) { int key_versions; key_versions = getint(&p); /* key data version */ ent.entry.kvno = getint(&p); /* XXX kvno */ ALLOC(ent.entry.keys.val[i].mkvno); *ent.entry.keys.val[i].mkvno = 0; /* key version 0 -- actual key */ ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */ tmp = getint(&p); /* key length */ /* the first two bytes of the key is the key length -- skip it */ krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2); q = nexttoken(&p); /* key itself */ hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue); if(key_versions > 1) { /* key version 1 -- optional salt */ ALLOC(ent.entry.keys.val[i].salt); ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */ tmp = getint(&p); /* salt length */ if(tmp > 0) { krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2); q = nexttoken(&p); /* salt itself */ hex_to_octet_string(q + 4, &ent.entry.keys.val[i].salt->salt); } else { ent.entry.keys.val[i].salt->salt.length = 0; ent.entry.keys.val[i].salt->salt.data = NULL; tmp = getint(&p); /* -1, if no data. */ } fix_salt(pd->context, &ent.entry, i); } } q = nexttoken(&p); /* extra data */ v5_prop(pd->context, NULL, &ent, arg); } fclose(f); return 0; }
int v4_prop(void *arg, struct v4_principal *p) { struct prop_data *pd = arg; hdb_entry_ex ent; krb5_error_code ret; memset(&ent, 0, sizeof(ent)); ret = krb5_425_conv_principal(pd->context, p->name, p->instance, v4_realm, &ent.entry.principal); if(ret) { krb5_warn(pd->context, ret, "krb5_425_conv_principal %s.%s@%s", p->name, p->instance, v4_realm); return 0; } if(verbose_flag) { char *s; krb5_unparse_name_short(pd->context, ent.entry.principal, &s); krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s); free(s); } ent.entry.kvno = p->kvno; ent.entry.keys.len = 3; ent.entry.keys.val = malloc(ent.entry.keys.len * sizeof(*ent.entry.keys.val)); if (ent.entry.keys.val == NULL) krb5_errx(pd->context, ENOMEM, "malloc"); if(p->mkvno != -1) { ent.entry.keys.val[0].mkvno = malloc (sizeof(*ent.entry.keys.val[0].mkvno)); if (ent.entry.keys.val[0].mkvno == NULL) krb5_errx(pd->context, ENOMEM, "malloc"); *(ent.entry.keys.val[0].mkvno) = p->mkvno; } else ent.entry.keys.val[0].mkvno = NULL; ent.entry.keys.val[0].salt = calloc(1, sizeof(*ent.entry.keys.val[0].salt)); if (ent.entry.keys.val[0].salt == NULL) krb5_errx(pd->context, ENOMEM, "calloc"); ent.entry.keys.val[0].salt->type = KRB5_PADATA_PW_SALT; ent.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; krb5_data_alloc(&ent.entry.keys.val[0].key.keyvalue, DES_KEY_SZ); memcpy(ent.entry.keys.val[0].key.keyvalue.data, p->key, 8); copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[1]); ent.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[2]); ent.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; { int life = _krb5_krb_life_to_time(0, p->max_life); if(life == NEVERDATE){ ent.entry.max_life = NULL; } else { /* clean up lifetime a bit */ if(life > 86400) life = (life + 86399) / 86400 * 86400; else if(life > 3600) life = (life + 3599) / 3600 * 3600; ALLOC(ent.entry.max_life); *ent.entry.max_life = life; } } ALLOC(ent.entry.valid_end); *ent.entry.valid_end = p->exp_date; ret = krb5_make_principal(pd->context, &ent.entry.created_by.principal, v4_realm, "kadmin", "hprop", NULL); if(ret){ krb5_warn(pd->context, ret, "krb5_make_principal"); ret = 0; goto out; } ent.entry.created_by.time = time(NULL); ALLOC(ent.entry.modified_by); ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, v4_realm, &ent.entry.modified_by->principal); if(ret){ krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, v4_realm); ent.entry.modified_by->principal = NULL; ret = 0; goto out; } ent.entry.modified_by->time = p->mod_date; ent.entry.flags.forwardable = 1; ent.entry.flags.renewable = 1; ent.entry.flags.proxiable = 1; ent.entry.flags.postdate = 1; ent.entry.flags.client = 1; ent.entry.flags.server = 1; /* special case password changing service */ if(strcmp(p->name, "changepw") == 0 && strcmp(p->instance, "kerberos") == 0) { ent.entry.flags.forwardable = 0; ent.entry.flags.renewable = 0; ent.entry.flags.proxiable = 0; ent.entry.flags.postdate = 0; ent.entry.flags.initial = 1; ent.entry.flags.change_pw = 1; } ret = v5_prop(pd->context, NULL, &ent, pd); if (strcmp (p->name, "krbtgt") == 0 && strcmp (v4_realm, p->instance) != 0) { krb5_free_principal (pd->context, ent.entry.principal); ret = krb5_425_conv_principal (pd->context, p->name, v4_realm, p->instance, &ent.entry.principal); if (ret == 0) ret = v5_prop (pd->context, NULL, &ent, pd); } out: hdb_free_entry(pd->context, &ent); return ret; }