krb5_error_code krb5_ktsrvint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry) { FILE *fp; char name[SNAME_SZ], instance[INST_SZ], realm[REALM_SZ]; unsigned char key[8]; int vno; krb5_error_code kerror; /* Read in an entry from the srvtab file. */ fp = KTFILEP(id); kerror = read_field(fp, name, sizeof(name)); if (kerror != 0) return kerror; kerror = read_field(fp, instance, sizeof(instance)); if (kerror != 0) return kerror; kerror = read_field(fp, realm, sizeof(realm)); if (kerror != 0) return kerror; vno = getc(fp); if (vno == EOF) return KRB5_KT_END; if (fread(key, 1, sizeof(key), fp) != sizeof(key)) return KRB5_KT_END; /* Fill in ret_entry with the data we read. Everything maps well * except for the timestamp, which we don't have a value for. For * now we just set it to 0. */ memset(ret_entry, 0, sizeof(*ret_entry)); ret_entry->magic = KV5M_KEYTAB_ENTRY; kerror = krb5_425_conv_principal(context, name, instance, realm, &ret_entry->principal); if (kerror != 0) return kerror; ret_entry->vno = vno; ret_entry->timestamp = 0; ret_entry->key.enctype = ENCTYPE_DES_CBC_CRC; ret_entry->key.magic = KV5M_KEYBLOCK; ret_entry->key.length = sizeof(key); ret_entry->key.contents = malloc(sizeof(key)); if (!ret_entry->key.contents) { krb5_free_principal(context, ret_entry->principal); return ENOMEM; } memcpy(ret_entry->key.contents, key, sizeof(key)); return 0; }
void test_425_conv_principal(krb5_context ctx, char *name, char *inst, char *realm) { krb5_error_code retval; krb5_principal princ; char *out_name; retval = krb5_425_conv_principal(ctx, name, inst, realm, &princ); if (retval) { com_err("krb5_425_conv_principal", retval, 0); return; } retval = krb5_unparse_name(ctx, princ, &out_name); if (retval) { com_err("krb5_unparse_name", retval, 0); return; } printf("425_converted principal(%s, %s, %s): '%s'\n", name, inst, realm, out_name); free(out_name); krb5_free_principal(ctx, princ); }
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 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; }
/* * Previously this code returned either a v4 key or a v5 key and you * could tell from the enctype of the v5 key whether the v4 key was * useful. Now we return both keys so the code can try both des3 and * des decryption. We fail if the ticket doesn't have a v4 key. * Also, note as a side effect, the v5 key is basically useless in * the client case. It is still returned so the caller can free it. */ static int kerb_get_principal(char *name, char *inst, /* could have wild cards */ Principal *principal, int *more, /* more tuples than room for */ krb5_keyblock *k5key, krb5_kvno kvno, int issrv, /* true if retrieving a service key */ krb5_deltat *k5life) { /* Note that this structure should not be passed to the krb5_free* functions, because the pointers within it point to data with other references. */ krb5_principal search; krb5_db_entry entries; /* filled in by krb5_db_get_principal() */ int nprinc; /* how many found */ krb5_boolean more5; /* are there more? */ C_Block k; short toggle = 0; unsigned long *date; char* text; struct tm *tp; krb5_key_data *pkey; krb5_error_code retval; *more = 0; /* begin setting up the principal structure * with the first info we have: */ memcpy( principal->name, name, 1 + strlen( name)); memcpy( principal->instance, inst, 1 + strlen( inst)); /* the principal-name format changed between v4 & v5: * v4: name.instance@realm * v5: realm/name/instance * in v5, null instance means the null-component doesn't exist. */ if ((retval = krb5_425_conv_principal(kdc_context, name, inst, local_realm, &search))) return(0); if ((retval = krb5_db_get_principal(kdc_context, search, &entries, &nprinc, &more5))) { krb5_free_principal(kdc_context, search); return(0); } principal->key_low = principal->key_high = 0; krb5_free_principal(kdc_context, search); if (nprinc < 1) { *more = (int)more5 || (nprinc > 1); return(nprinc); } if (!issrv) { if (krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_V4, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, -1, kvno, &pkey)) { lt = klog(L_KRB_PERR, "KDC V4: principal %s.%s isn't V4 compatible", name, inst); krb5_db_free_principal(kdc_context, &entries, nprinc); return(0); } } else { if ( krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_V4, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, -1, kvno, &pkey)) { lt = klog(L_KRB_PERR, "KDC V4: failed to find key for %s.%s #%d", name, inst, kvno); krb5_db_free_principal(kdc_context, &entries, nprinc); return(0); } } if (!compat_decrypt_key(pkey, k, k5key, issrv)) { memcpy( &principal->key_low, k, LONGLEN); memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN); } memset(k, 0, sizeof k); if (issrv) { krb5_free_keyblock_contents (kdc_context, k5key); if (krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES3_CBC_RAW, -1, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES3_CBC_SHA1, -1, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_V4, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, -1, kvno, &pkey)) { lt = klog(L_KRB_PERR, "KDC V4: failed to find key for %s.%s #%d (after having found it once)", name, inst, kvno); krb5_db_free_principal(kdc_context, &entries, nprinc); return(0); } compat_decrypt_key(pkey, k, k5key, issrv); memset (k, 0, sizeof k); } /* * Convert v5's entries struct to v4's Principal struct: * v5's time-unit for lifetimes is 1 sec, while v4 uses 5 minutes, * and gets weirder above (128 * 300) seconds. */ principal->max_life = krb_time_to_life(0, entries.max_life); if (k5life != NULL) *k5life = entries.max_life; /* * This is weird, but the intent is that the expiration is the minimum * of the principal expiration and key expiration */ principal->exp_date = (unsigned long) entries.expiration && entries.pw_expiration ? min(entries.expiration, entries.pw_expiration) : (entries.pw_expiration ? entries.pw_expiration : entries.expiration); /* principal->mod_date = (unsigned long) entries.mod_date; */ /* Set the master key version to 1. It's not really useful because all keys * will be encrypted in the same master key version, and digging out the * actual key version will be harder than it's worth --proven */ /* principal->kdc_key_ver = entries.mkvno; */ principal->kdc_key_ver = 1; principal->key_version = pkey->key_data_kvno; /* We overload the attributes with the relevant v5 ones */ principal->attributes = 0; if (isflagset(entries.attributes, KRB5_KDB_REQUIRES_HW_AUTH) || isflagset(entries.attributes, KRB5_KDB_REQUIRES_PRE_AUTH)) { principal->attributes |= V4_KDB_REQUIRES_PREAUTH; } if (isflagset(entries.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) { principal->attributes |= V4_KDB_DISALLOW_ALL_TIX; } if (issrv && isflagset(entries.attributes, KRB5_KDB_DISALLOW_SVR)) { principal->attributes |= V4_KDB_DISALLOW_SVR; } if (isflagset(entries.attributes, KRB5_KDB_REQUIRES_PWCHANGE)) { principal->attributes |= V4_KDB_REQUIRES_PWCHANGE; } /* set up v4 format of each date's text: */ for ( date = &principal->exp_date, text = principal->exp_date_txt; toggle ^= 1; date = &principal->mod_date, text = principal->mod_date_txt) { tp = localtime( (time_t *) date); sprintf( text, "%4d-%02d-%02d", tp->tm_year > 1900 ? tp->tm_year : tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday); /* January is 0, not 1 */ } /* * free the storage held by the v5 entry struct, * which was allocated by krb5_db_get_principal(). * this routine clears the keyblock's contents for us. */ krb5_db_free_principal(kdc_context, &entries, nprinc); *more = (int) more5 || (nprinc > 1); return( nprinc); }