static krb5_error_code LDAP_fetch(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { LDAPMessage *msg, *e; krb5_error_code ret; ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret) return ret; e = ldap_first_entry(HDB2LDAP(db), msg); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } ret = LDAP_message2entry(context, db, e, entry); if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, entry); if (ret) hdb_free_entry(context,entry); } } out: ldap_msgfree(msg); 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; }
static krb5_error_code LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { int msgid, rc, parserc; krb5_error_code ret; LDAPMessage *e; msgid = HDB2MSGID(db); if (msgid < 0) return HDB_ERR_NOENTRY; do { rc = ldap_result(HDB2LDAP(db), msgid, LDAP_MSG_ONE, NULL, &e); switch (rc) { case LDAP_RES_SEARCH_REFERENCE: ldap_msgfree(e); ret = 0; break; case LDAP_RES_SEARCH_ENTRY: /* We have an entry. Parse it. */ ret = LDAP_message2entry(context, db, e, entry); ldap_msgfree(e); break; case LDAP_RES_SEARCH_RESULT: /* We're probably at the end of the results. If not, abandon. */ parserc = ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL, NULL, NULL, 1); if (parserc != LDAP_SUCCESS && parserc != LDAP_MORE_RESULTS_TO_RETURN) { krb5_set_error_string(context, "ldap_parse_result: %s", ldap_err2string(parserc)); ldap_abandon(HDB2LDAP(db), msgid); } ret = HDB_ERR_NOENTRY; HDBSETMSGID(db, -1); break; case LDAP_SERVER_DOWN: ldap_msgfree(e); LDAP_close(context, db); HDBSETMSGID(db, -1); ret = ENETDOWN; break; default: /* Some unspecified error (timeout?). Abandon. */ ldap_msgfree(e); ldap_abandon(HDB2LDAP(db), msgid); ret = HDB_ERR_NOENTRY; HDBSETMSGID(db, -1); break; } } while (rc == LDAP_RES_SEARCH_REFERENCE); if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, entry); if (ret) hdb_free_entry(context,entry); } } return ret; }