static krb5_error_code LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { krb5_error_code ret; int msgid; ret = LDAP__connect(context, db); if (ret) return ret; ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) return ret; msgid = ldap_search(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, "(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))", krb5kdcentry_attrs, 0); if (msgid < 0) return HDB_ERR_NOENTRY; HDBSETMSGID(db, msgid); return LDAP_seq(context, db, flags, entry); }
static krb5_error_code LDAP_close(krb5_context context, HDB * db) { if (HDB2LDAP(db)) { ldap_unbind_ext(HDB2LDAP(db), NULL, NULL); ((struct hdbldapdb *)db->hdb_db)->h_lp = NULL; } return 0; }
static krb5_error_code LDAP__connect(krb5_context context, HDB * db) { int rc, version = LDAP_VERSION3; /* * Empty credentials to do a SASL bind with LDAP. Note that empty * different from NULL credentials. If you provide NULL * credentials instead of empty credentials you will get a SASL * bind in progress message. */ struct berval bv = { 0, "" }; if (HDB2LDAP(db)) { /* connection has been opened. ping server. */ struct sockaddr_un addr; socklen_t len = sizeof(addr); int sd; if (ldap_get_option(HDB2LDAP(db), LDAP_OPT_DESC, &sd) == 0 && getpeername(sd, (struct sockaddr *) &addr, &len) < 0) { /* the other end has died. reopen. */ LDAP_close(context, db); } } if (HDB2LDAP(db) != NULL) /* server is UP */ return 0; rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, "ldapi:///"); if (rc != LDAP_SUCCESS) { krb5_set_error_string(context, "ldap_initialize: %s", ldap_err2string(rc)); return HDB_ERR_NOENTRY; } rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION, (const void *)&version); if (rc != LDAP_SUCCESS) { krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc)); LDAP_close(context, db); return HDB_ERR_BADVERSION; } rc = ldap_sasl_bind_s(HDB2LDAP(db), NULL, "EXTERNAL", &bv, NULL, NULL, NULL); if (rc != LDAP_SUCCESS) { krb5_set_error_string(context, "ldap_sasl_bind_s: %s", ldap_err2string(rc)); LDAP_close(context, db); return HDB_ERR_BADVERSION; } return 0; }
static krb5_error_code LDAP_remove(krb5_context context, HDB * db, hdb_entry * entry) { krb5_error_code ret; LDAPMessage *msg, *e; char *dn = NULL; int rc, limit = LDAP_NO_LIMIT; ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret) goto out; e = ldap_first_entry(HDB2LDAP(db), msg); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } dn = ldap_get_dn(HDB2LDAP(db), e); if (dn == NULL) { ret = HDB_ERR_NOENTRY; goto out; } rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit); if (rc != LDAP_SUCCESS) { krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc)); ret = HDB_ERR_BADVERSION; goto out; } rc = ldap_delete_s(HDB2LDAP(db), dn); if (check_ldap(context, db, rc)) { krb5_set_error_string(context, "ldap_delete_s: %s", ldap_err2string(rc)); ret = HDB_ERR_CANT_LOCK_DB; } else ret = 0; out: if (dn != NULL) free(dn); if (msg != NULL) ldap_msgfree(msg); return ret; }
static krb5_error_code LDAP_get_string_value(HDB * db, LDAPMessage * entry, const char *attribute, char **ptr) { struct berval **vals; vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute); if (vals == NULL || vals[0] == NULL) { *ptr = NULL; return HDB_ERR_NOENTRY; } *ptr = malloc(vals[0]->bv_len + 1); if (*ptr == NULL) { ldap_value_free_len(vals); return ENOMEM; } memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len); (*ptr)[vals[0]->bv_len] = 0; ldap_value_free_len(vals); return 0; }
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_dn2principal(krb5_context context, HDB * db, const char *dn, krb5_principal * principal) { krb5_error_code ret; int rc; const char *filter = "(objectClass=krb5Principal)"; LDAPMessage *res = NULL, *e; char *p; ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, filter, krb5principal_attrs, 0, NULL, NULL, NULL, 0, &res); if (check_ldap(context, db, rc)) { ret = HDB_ERR_NOENTRY; krb5_set_error_message(context, ret, "ldap_search_ext_s: " "filter: %s error: %s", filter, ldap_err2string(rc)); goto out; } e = ldap_first_entry(HDB2LDAP(db), res); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p); if (ret) { ret = HDB_ERR_NOENTRY; goto out; } ret = krb5_parse_name(context, p, principal); free(p); out: if (res) ldap_msgfree(res); return ret; }
static krb5_error_code LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, krb5_principal * principal) { krb5_error_code ret; int rc; char **values; LDAPMessage *res = NULL, *e; ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, "(objectClass=krb5Principal)", krb5principal_attrs, 0, &res); if (check_ldap(context, db, rc)) { krb5_set_error_string(context, "ldap_search_s: %s", ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; goto out; } e = ldap_first_entry(HDB2LDAP(db), res); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } values = ldap_get_values(HDB2LDAP(db), e, "krb5PrincipalName"); if (values == NULL) { ret = HDB_ERR_NOENTRY; goto out; } ret = krb5_parse_name(context, values[0], principal); ldap_value_free(values); out: if (res) ldap_msgfree(res); return ret; }
static krb5_error_code LDAP_get_integer_value(HDB * db, LDAPMessage * entry, const char *attribute, int *ptr) { char **vals; vals = ldap_get_values(HDB2LDAP(db), entry, (char *) attribute); if (vals == NULL) return HDB_ERR_NOENTRY; *ptr = atoi(vals[0]); ldap_value_free(vals); return 0; }
static krb5_error_code LDAP_get_string_value(HDB * db, LDAPMessage * entry, const char *attribute, char **ptr) { char **vals; int ret; vals = ldap_get_values(HDB2LDAP(db), entry, (char *) attribute); if (vals == NULL) { *ptr = NULL; return HDB_ERR_NOENTRY; } *ptr = strdup(vals[0]); if (*ptr == NULL) ret = ENOMEM; else ret = 0; ldap_value_free(vals); 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; }
/* * Construct an hdb_entry from a directory entry. */ static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, hdb_entry * ent) { char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; int ret; unsigned long tmp; struct berval **keys; char **values; int tmp_time; memset(ent, 0, sizeof(*ent)); ent->flags = int2HDBFlags(0); ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name); if (ret == 0) { ret = krb5_parse_name(context, unparsed_name, &ent->principal); if (ret) goto out; } else { ret = LDAP_get_string_value(db, msg, "uid", &unparsed_name); if (ret == 0) { ret = krb5_parse_name(context, unparsed_name, &ent->principal); if (ret) goto out; } else { krb5_set_error_string(context, "hdb-ldap: ldap entry missing" "principal name"); return HDB_ERR_NOENTRY; } } ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber", &ent->kvno); if (ret) ent->kvno = 0; keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (keys != NULL) { int i; size_t l; ent->keys.len = ldap_count_values_len(keys); ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key)); if (ent->keys.val == NULL) { krb5_set_error_string(context, "calloc: out of memory"); ret = ENOMEM; goto out; } for (i = 0; i < ent->keys.len; i++) { decode_Key((unsigned char *) keys[i]->bv_val, (size_t) keys[i]->bv_len, &ent->keys.val[i], &l); } ber_bvecfree(keys); } else { #if 1 /* * This violates the ASN1 but it allows a principal to * be related to a general directory entry without creating * the keys. Hopefully it's OK. */ ent->keys.len = 0; ent->keys.val = NULL; #else ret = HDB_ERR_NOENTRY; goto out; #endif } values = ldap_get_values(HDB2LDAP(db), msg, "krb5EncryptionType"); if (values != NULL) { int i; ent->etypes = malloc(sizeof(*(ent->etypes))); if (ent->etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->len = ldap_count_values(values); ent->etypes->val = calloc(ent->etypes->len, sizeof(int)); if (ent->etypes->val == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } for (i = 0; i < ent->etypes->len; i++) { ent->etypes->val[i] = atoi(values[i]); } ldap_value_free(values); } /* manually construct the NT (type 23) key */ ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN); if (ret == 0) { int *etypes; Key *keys; keys = realloc(ent->keys.val, (ent->keys.len + 1) * sizeof(ent->keys.val[0])); if (keys == NULL) { free(ntPasswordIN); krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->keys.val = keys; memset(&ent->keys.val[ent->keys.len], 0, sizeof(Key)); ent->keys.val[ent->keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; ret = krb5_data_alloc (&ent->keys.val[ent->keys.len].key.keyvalue, 16); if (ret) { krb5_set_error_string(context, "malloc: out of memory"); free(ntPasswordIN); ret = ENOMEM; goto out; } ret = hex_decode(ntPasswordIN, ent->keys.val[ent->keys.len].key.keyvalue.data, 16); ent->keys.len++; if (ent->etypes == NULL) { ent->etypes = malloc(sizeof(*(ent->etypes))); if (ent->etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->val = NULL; ent->etypes->len = 0; } etypes = realloc(ent->etypes->val, (ent->etypes->len + 1) * sizeof(ent->etypes->val[0])); if (etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->val = etypes; ent->etypes->val[ent->etypes->len] = ETYPE_ARCFOUR_HMAC_MD5; ent->etypes->len++; } ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp", &ent->created_by.time); if (ret) ent->created_by.time = time(NULL); ent->created_by.principal = NULL; ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); if (ret == 0) { if (LDAP_dn2principal(context, db, dn, &ent->created_by.principal) != 0) { ent->created_by.principal = NULL; } free(dn); } ent->modified_by = (Event *) malloc(sizeof(Event)); if (ent->modified_by == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", &ent->modified_by->time); if (ret == 0) { ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); if (LDAP_dn2principal(context, db, dn, &ent->modified_by->principal)) ent->modified_by->principal = NULL; free(dn); } else { free(ent->modified_by); ent->modified_by = NULL; } ent->valid_start = malloc(sizeof(*ent->valid_start)); if (ent->valid_start == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", ent->valid_start); if (ret) { /* OPTIONAL */ free(ent->valid_start); ent->valid_start = NULL; } ent->valid_end = malloc(sizeof(*ent->valid_end)); if (ent->valid_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", ent->valid_end); if (ret) { /* OPTIONAL */ free(ent->valid_end); ent->valid_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time); if (ret == 0) { if (ent->valid_end == NULL) { ent->valid_end = malloc(sizeof(*ent->valid_end)); if (ent->valid_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } } *ent->valid_end = tmp_time; } ent->pw_end = malloc(sizeof(*ent->pw_end)); if (ent->pw_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", ent->pw_end); if (ret) { /* OPTIONAL */ free(ent->pw_end); ent->pw_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); if (ret == 0) { if (ent->pw_end == NULL) { ent->pw_end = malloc(sizeof(*ent->pw_end)); if (ent->pw_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } } *ent->pw_end = tmp_time; } #if 0 /* we we have last_pw_change */ ent->last_pw_change = malloc(sizeof(*ent->last_pw_change)); if (ent->last_pw_change == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); if (ret) { /* OPTIONAL */ free(ent->last_pw_change); ent->last_pw_change = NULL; } else *ent->last_pw_change = tmp_time; #endif ent->max_life = malloc(sizeof(*ent->max_life)); if (ent->max_life == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", ent->max_life); if (ret) { free(ent->max_life); ent->max_life = NULL; } ent->max_renew = malloc(sizeof(*ent->max_renew)); if (ent->max_renew == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", ent->max_renew); if (ret) { free(ent->max_renew); ent->max_renew = NULL; } values = ldap_get_values(HDB2LDAP(db), msg, "krb5KDCFlags"); if (values != NULL) { errno = 0; tmp = strtoul(values[0], (char **) NULL, 10); if (tmp == ULONG_MAX && errno == ERANGE) { krb5_set_error_string(context, "strtoul: could not convert flag"); ret = ERANGE; goto out; } } else { tmp = 0; } ent->flags = int2HDBFlags(tmp); /* Try and find Samba flags to put into the mix */ ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags); if (ret == 0) { /* parse the [UXW...] string: 'N' No password 'D' Disabled 'H' Homedir required 'T' Temp account. 'U' User account (normal) 'M' MNS logon user account - what is this ? 'W' Workstation account 'S' Server account 'L' Locked account 'X' No Xpiry on password 'I' Interdomain trust account */ int i; int flags_len = strlen(samba_acct_flags); if (flags_len < 2) goto out2; if (samba_acct_flags[0] != '[' || samba_acct_flags[flags_len - 1] != ']') goto out2; /* Allow forwarding */ if (samba_forwardable) ent->flags.forwardable = TRUE; for (i=0; i < flags_len; i++) { switch (samba_acct_flags[i]) { case ' ': case '[': case ']': break; case 'N': /* how to handle no password in kerberos? */ break; case 'D': ent->flags.invalid = TRUE; break; case 'H': break; case 'T': /* temp duplicate */ ent->flags.invalid = TRUE; break; case 'U': ent->flags.client = TRUE; break; case 'M': break; case 'W': case 'S': ent->flags.server = TRUE; ent->flags.client = TRUE; break; case 'L': ent->flags.invalid = TRUE; break; case 'X': if (ent->pw_end) { free(ent->pw_end); ent->pw_end = NULL; } break; case 'I': ent->flags.server = TRUE; ent->flags.client = TRUE; break; } } out2: free(samba_acct_flags); } ret = 0; out: if (unparsed_name) free(unparsed_name); if (ret) hdb_free_entry(context, ent); return ret; }
static krb5_error_code LDAP__lookup_princ(krb5_context context, HDB *db, const char *princname, const char *userid, LDAPMessage **msg) { krb5_error_code ret; int rc; char *filter = NULL; ret = LDAP__connect(context, db); if (ret) return ret; rc = asprintf(&filter, "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))", princname); if (rc < 0) { krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, filter, krb5kdcentry_attrs, 0, msg); if (check_ldap(context, db, rc)) { krb5_set_error_string(context, "ldap_search_s: %s", ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; goto out; } if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) { free(filter); filter = NULL; ldap_msgfree(*msg); *msg = NULL; rc = asprintf(&filter, "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))", structural_object, userid); if (rc < 0) { krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, filter, krb5kdcentry_attrs, 0, msg); if (check_ldap(context, db, rc)) { krb5_set_error_string(context, "ldap_search_s: %s", ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; goto out; } } ret = 0; out: if (filter) free(filter); return ret; }
static krb5_error_code LDAP_store(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { LDAPMod **mods = NULL; krb5_error_code ret; const char *errfn; int rc; LDAPMessage *msg = NULL, *e = NULL; char *dn = NULL, *name = NULL; ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret == 0) e = ldap_first_entry(HDB2LDAP(db), msg); ret = krb5_unparse_name(context, entry->principal, &name); if (ret) { free(name); return ret; } ret = hdb_seal_keys(context, db, entry); if (ret) goto out; /* turn new entry into LDAPMod array */ ret = LDAP_entry2mods(context, db, entry, e, &mods); if (ret) goto out; if (e == NULL) { ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db)); if (ret < 0) { krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; goto out; } } else if (flags & HDB_F_REPLACE) { /* Entry exists, and we're allowed to replace it. */ dn = ldap_get_dn(HDB2LDAP(db), e); } else { /* Entry exists, but we're not allowed to replace it. Bail. */ ret = HDB_ERR_EXISTS; goto out; } /* write entry into directory */ if (e == NULL) { /* didn't exist before */ rc = ldap_add_s(HDB2LDAP(db), dn, mods); errfn = "ldap_add_s"; } else { /* already existed, send deltas only */ rc = ldap_modify_s(HDB2LDAP(db), dn, mods); errfn = "ldap_modify_s"; } if (check_ldap(context, db, rc)) { char *ld_error = NULL; ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING, &ld_error); krb5_set_error_string(context, "%s: %s (dn=%s) %s: %s", errfn, name, dn, ldap_err2string(rc), ld_error); ret = HDB_ERR_CANT_LOCK_DB; } else ret = 0; out: /* free stuff */ if (dn) free(dn); if (msg) ldap_msgfree(msg); if (mods) ldap_mods_free(mods, 1); if (name) free(name); 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; }
static krb5_error_code LDAP__lookup_princ(krb5_context context, HDB *db, const char *princname, const char *userid, LDAPMessage **msg) { struct berval namebv, quotedp; krb5_error_code ret; int rc; char *filter = NULL; ret = LDAP__connect(context, db); if (ret) return ret; /* * Quote searches that contain filter language, this quote * searches for *@REALM, which takes very long time. */ ber_str2bv(princname, 0, 0, &namebv); if (ldap_bv2escaped_filter_value(&namebv, "edp) != 0) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } rc = asprintf(&filter, "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))", quotedp.bv_val); ber_memfree(quotedp.bv_val); if (rc < 0) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, filter, krb5kdcentry_attrs, 0, NULL, NULL, NULL, 0, msg); if (check_ldap(context, db, rc)) { ret = HDB_ERR_NOENTRY; krb5_set_error_message(context, ret, "ldap_search_ext_s: " "filter: %s - error: %s", filter, ldap_err2string(rc)); goto out; } if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) { free(filter); filter = NULL; ldap_msgfree(*msg); *msg = NULL; ber_str2bv(userid, 0, 0, &namebv); if (ldap_bv2escaped_filter_value(&namebv, "edp) != 0) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } rc = asprintf(&filter, "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))", structural_object, quotedp.bv_val); ber_memfree(quotedp.bv_val); if (rc < 0) { ret = ENOMEM; krb5_set_error_message(context, ret, "asprintf: out of memory"); goto out; } ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, filter, krb5kdcentry_attrs, 0, NULL, NULL, NULL, 0, msg); if (check_ldap(context, db, rc)) { ret = HDB_ERR_NOENTRY; krb5_set_error_message(context, ret, "ldap_search_ext_s: filter: %s error: %s", filter, ldap_err2string(rc)); goto out; } } ret = 0; out: if (filter) free(filter); return ret; }