static krb5_error_code LDAP_principal2message(krb5_context context, HDB * db, krb5_principal princ, LDAPMessage ** msg) { char *name, *name_short = NULL; krb5_error_code ret; krb5_realm *r, *r0; *msg = NULL; ret = krb5_unparse_name(context, princ, &name); if (ret) return ret; ret = krb5_get_default_realms(context, &r0); if(ret) { free(name); return ret; } for (r = r0; *r != NULL; r++) { if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) { ret = krb5_unparse_name_short(context, princ, &name_short); if (ret) { krb5_free_host_realm(context, r0); free(name); return ret; } break; } } krb5_free_host_realm(context, r0); ret = LDAP__lookup_princ(context, db, name, name_short, msg); free(name); free(name_short); return ret; }
static krb5_error_code LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, LDAPMessage * msg, LDAPMod *** pmods) { krb5_error_code ret; krb5_boolean is_new_entry; char *tmp = NULL; LDAPMod **mods = NULL; hdb_entry_ex orig; unsigned long oflags, nflags; int i; krb5_boolean is_samba_account = FALSE; krb5_boolean is_account = FALSE; krb5_boolean is_heimdal_entry = FALSE; krb5_boolean is_heimdal_principal = FALSE; struct berval **vals; *pmods = NULL; if (msg != NULL) { ret = LDAP_message2entry(context, db, msg, 0, &orig); if (ret) goto out; is_new_entry = FALSE; vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass"); if (vals) { int num_objectclasses = ldap_count_values_len(vals); for (i=0; i < num_objectclasses; i++) { if (bervalstrcmp(vals[i], "sambaSamAccount")) is_samba_account = TRUE; else if (bervalstrcmp(vals[i], structural_object)) is_account = TRUE; else if (bervalstrcmp(vals[i], "krb5Principal")) is_heimdal_principal = TRUE; else if (bervalstrcmp(vals[i], "krb5KDCEntry")) is_heimdal_entry = TRUE; } ldap_value_free_len(vals); } /* * If this is just a "account" entry and no other objectclass * is hanging on this entry, it's really a new entry. */ if (is_samba_account == FALSE && is_heimdal_principal == FALSE && is_heimdal_entry == FALSE) { if (is_account == TRUE) { is_new_entry = TRUE; } else { ret = HDB_ERR_NOENTRY; goto out; } } } else is_new_entry = TRUE; if (is_new_entry) { /* to make it perfectly obvious we're depending on * orig being intiialized to zero */ memset(&orig, 0, sizeof(orig)); ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top"); if (ret) goto out; /* account is the structural object class */ if (is_account == FALSE) { ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", structural_object); is_account = TRUE; if (ret) goto out; } ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal"); is_heimdal_principal = TRUE; if (ret) goto out; ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry"); is_heimdal_entry = TRUE; if (ret) goto out; } if (is_new_entry || krb5_principal_compare(context, ent->entry.principal, orig.entry.principal) == FALSE) { if (is_heimdal_principal || is_heimdal_entry) { ret = krb5_unparse_name(context, ent->entry.principal, &tmp); if (ret) goto out; ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5PrincipalName", tmp); if (ret) { free(tmp); goto out; } free(tmp); } if (is_account || is_samba_account) { ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp); if (ret) goto out; ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp); if (ret) { free(tmp); goto out; } free(tmp); } } if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5KeyVersionNumber", ent->entry.kvno); if (ret) goto out; } if (is_heimdal_entry && ent->entry.valid_start) { if (orig.entry.valid_end == NULL || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5ValidStart", ent->entry.valid_start); if (ret) goto out; } } if (ent->entry.valid_end) { if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) { if (is_heimdal_entry) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5ValidEnd", ent->entry.valid_end); if (ret) goto out; } if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaKickoffTime", *(ent->entry.valid_end)); if (ret) goto out; } } } if (ent->entry.pw_end) { if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) { if (is_heimdal_entry) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5PasswordEnd", ent->entry.pw_end); if (ret) goto out; } if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaPwdMustChange", *(ent->entry.pw_end)); if (ret) goto out; } } } #if 0 /* we we have last_pw_change */ if (is_samba_account && ent->entry.last_pw_change) { if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaPwdLastSet", *(ent->entry.last_pw_change)); if (ret) goto out; } } #endif if (is_heimdal_entry && ent->entry.max_life) { if (orig.entry.max_life == NULL || (*(ent->entry.max_life) != *(orig.entry.max_life))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5MaxLife", *(ent->entry.max_life)); if (ret) goto out; } } if (is_heimdal_entry && ent->entry.max_renew) { if (orig.entry.max_renew == NULL || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5MaxRenew", *(ent->entry.max_renew)); if (ret) goto out; } } oflags = HDBFlags2int(orig.entry.flags); nflags = HDBFlags2int(ent->entry.flags); if (is_heimdal_entry && oflags != nflags) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5KDCFlags", nflags); if (ret) goto out; } /* Remove keys if they exists, and then replace keys. */ if (!is_new_entry && orig.entry.keys.len > 0) { vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (vals) { ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL); if (ret) goto out; } } for (i = 0; i < ent->entry.keys.len; i++) { if (is_samba_account && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { char *ntHexPassword; char *nt; time_t now = time(NULL); /* the key might have been 'sealed', but samba passwords are clear in the directory */ ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]); if (ret) goto out; nt = ent->entry.keys.val[i].key.keyvalue.data; /* store in ntPassword, not krb5key */ ret = hex_encode(nt, 16, &ntHexPassword); if (ret < 0) { ret = ENOMEM; krb5_set_error_message(context, ret, "hdb-ldap: failed to " "hex encode key"); goto out; } ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword", ntHexPassword); free(ntHexPassword); if (ret) goto out; ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaPwdLastSet", now); if (ret) goto out; /* have to kill the LM passwod if it exists */ vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword"); if (vals) { ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "sambaLMPassword", NULL); if (ret) goto out; } } else if (is_heimdal_entry) { unsigned char *buf; size_t len, buf_size; ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret); if (ret) goto out; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* addmod_len _owns_ the key, doesn't need to copy it */ ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len); if (ret) goto out; } } if (ent->entry.etypes) { int add_krb5EncryptionType = 0; /* * Only add/modify krb5EncryptionType if it's a new heimdal * entry or krb5EncryptionType already exists on the entry. */ if (!is_new_entry) { vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); if (vals) { ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType", NULL); if (ret) goto out; add_krb5EncryptionType = 1; } } else if (is_heimdal_entry) add_krb5EncryptionType = 1; if (add_krb5EncryptionType) { for (i = 0; i < ent->entry.etypes->len; i++) { if (is_samba_account && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { ; } else if (is_heimdal_entry) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD, "krb5EncryptionType", ent->entry.etypes->val[i]); if (ret) goto out; } } } } /* for clarity */ ret = 0; out: if (ret == 0) *pmods = mods; else if (mods != NULL) { ldap_mods_free(mods, 1); *pmods = NULL; } if (msg) hdb_free_entry(context, &orig); return ret; }
int main(int argc, char **argv) { struct testcase *t; krb5_context context; krb5_error_code ret; int val = 0; ret = krb5_init_context (&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); /* to enable realm-less principal name above */ krb5_set_default_realm(context, ""); for (t = tests; t->input_string; ++t) { krb5_principal princ; int i, j; char name_buf[1024]; char *s; ret = krb5_parse_name(context, t->input_string, &princ); if (ret) krb5_err (context, 1, ret, "krb5_parse_name %s", t->input_string); if (strcmp (t->realm, princ->realm) != 0) { printf ("wrong realm (\"%s\" should be \"%s\")" " for \"%s\"\n", princ->realm, t->realm, t->input_string); val = 1; } if (t->ncomponents != princ->name.name_string.len) { printf ("wrong number of components (%u should be %u)" " for \"%s\"\n", princ->name.name_string.len, t->ncomponents, t->input_string); val = 1; } else { for (i = 0; i < t->ncomponents; ++i) { if (strcmp(t->comp_val[i], princ->name.name_string.val[i]) != 0) { printf ("bad component %d (\"%s\" should be \"%s\")" " for \"%s\"\n", i, princ->name.name_string.val[i], t->comp_val[i], t->input_string); val = 1; } } } for (j = 0; j < strlen(t->output_string); ++j) { ret = krb5_unparse_name_fixed(context, princ, name_buf, j); if (ret != ERANGE) { printf ("unparse_name %s with length %d should have failed\n", t->input_string, j); val = 1; break; } } ret = krb5_unparse_name_fixed(context, princ, name_buf, sizeof(name_buf)); if (ret) krb5_err (context, 1, ret, "krb5_unparse_name_fixed"); if (strcmp (t->output_string, name_buf) != 0) { printf ("failed comparing the re-parsed" " (\"%s\" should be \"%s\")\n", name_buf, t->output_string); val = 1; } ret = krb5_unparse_name(context, princ, &s); if (ret) krb5_err (context, 1, ret, "krb5_unparse_name"); if (strcmp (t->output_string, s) != 0) { printf ("failed comparing the re-parsed" " (\"%s\" should be \"%s\"\n", s, t->output_string); val = 1; } free(s); if (!t->realmp) { for (j = 0; j < strlen(t->input_string); ++j) { ret = krb5_unparse_name_fixed_short(context, princ, name_buf, j); if (ret != ERANGE) { printf ("unparse_name_short %s with length %d" " should have failed\n", t->input_string, j); val = 1; break; } } ret = krb5_unparse_name_fixed_short(context, princ, name_buf, sizeof(name_buf)); if (ret) krb5_err (context, 1, ret, "krb5_unparse_name_fixed"); if (strcmp (t->input_string, name_buf) != 0) { printf ("failed comparing the re-parsed" " (\"%s\" should be \"%s\")\n", name_buf, t->input_string); val = 1; } ret = krb5_unparse_name_short(context, princ, &s); if (ret) krb5_err (context, 1, ret, "krb5_unparse_name_short"); if (strcmp (t->input_string, s) != 0) { printf ("failed comparing the re-parsed" " (\"%s\" should be \"%s\"\n", s, t->input_string); val = 1; } free(s); } krb5_free_principal (context, princ); } krb5_free_context(context); return val; }
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; }