diff options
Diffstat (limited to 'source3/passdb/pdb_ldap.c')
-rw-r--r-- | source3/passdb/pdb_ldap.c | 354 |
1 files changed, 341 insertions, 13 deletions
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 99f6670653..e44ccc3bf9 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -178,6 +178,146 @@ static const char* get_objclass_filter( int schema_ver ) return objclass_filter; } +/***************************************************************** + Scan a sequence number off OpenLDAP's syncrepl contextCSN +******************************************************************/ + +static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_num) +{ + struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; + NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; + LDAPMessage *msg = NULL; + LDAPMessage *entry = NULL; + TALLOC_CTX *mem_ctx; + char **values = NULL; + int rc, num_result, num_values, rid; + pstring suffix; + fstring tok; + const char *p; + const char **attrs; + + /* Unfortunatly there is no proper way to detect syncrepl-support in + * smbldap_connect_system(). The syncrepl OIDs are submitted for publication + * but do not show up in the root-DSE yet. Neither we can query the + * subschema-context for the syncProviderSubentry or syncConsumerSubentry + * objectclass. Currently we require lp_ldap_suffix() to show up as + * namingContext. - Guenther + */ + + if (!lp_parm_bool(-1, "ldapsam", "syncrepl_seqnum", False)) { + return ntstatus; + } + + if (!seq_num) { + DEBUG(3,("ldapsam_get_seq_num: no sequence_number\n")); + return ntstatus; + } + + if (!smbldap_has_naming_context(ldap_state->smbldap_state, lp_ldap_suffix())) { + DEBUG(3,("ldapsam_get_seq_num: DIT not configured to hold %s " + "as top-level namingContext\n", lp_ldap_suffix())); + return ntstatus; + } + + mem_ctx = talloc_init("ldapsam_get_seq_num"); + + if (mem_ctx == NULL) + return NT_STATUS_NO_MEMORY; + + attrs = TALLOC_ARRAY(mem_ctx, const char *, 2); + + /* if we got a syncrepl-rid (up to three digits long) we speak with a consumer */ + rid = lp_parm_int(-1, "ldapsam", "syncrepl_rid", -1); + if (rid > 0) { + + /* consumer syncreplCookie: */ + /* csn=20050126161620Z#0000001#00#00000 */ + attrs[0] = talloc_strdup(mem_ctx, "syncreplCookie"); + attrs[1] = NULL; + pstr_sprintf( suffix, "cn=syncrepl%d,%s", rid, lp_ldap_suffix()); + + } else { + + /* provider contextCSN */ + /* 20050126161620Z#000009#00#000000 */ + attrs[0] = talloc_strdup(mem_ctx, "contextCSN"); + attrs[1] = NULL; + pstr_sprintf( suffix, "cn=ldapsync,%s", lp_ldap_suffix()); + + } + + rc = smbldap_search(ldap_state->smbldap_state, suffix, + LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg); + + if (rc != LDAP_SUCCESS) { + + char *ld_error = NULL; + ldap_get_option(ldap_state->smbldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(0,("ldapsam_get_seq_num: Failed search for suffix: %s, error: %s (%s)\n", + suffix,ldap_err2string(rc), ld_error?ld_error:"unknown")); + SAFE_FREE(ld_error); + goto done; + } + + num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg); + if (num_result != 1) { + DEBUG(3,("ldapsam_get_seq_num: Expected one entry, got %d\n", num_result)); + goto done; + } + + entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg); + if (entry == NULL) { + DEBUG(3,("ldapsam_get_seq_num: Could not retrieve entry\n")); + goto done; + } + + values = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, attrs[0]); + if (values == NULL) { + DEBUG(3,("ldapsam_get_seq_num: no values\n")); + goto done; + } + + num_values = ldap_count_values(values); + if (num_values == 0) { + DEBUG(3,("ldapsam_get_seq_num: not a single value\n")); + goto done; + } + + p = values[0]; + if (!next_token(&p, tok, "#", sizeof(tok))) { + DEBUG(0,("ldapsam_get_seq_num: failed to parse sequence number\n")); + goto done; + } + + p = tok; + if (!strncmp(p, "csn=", strlen("csn="))) + p += strlen("csn="); + + DEBUG(10,("ldapsam_get_seq_num: got %s: %s\n", attrs[0], p)); + + *seq_num = generalized_to_unix_time(p); + + /* very basic sanity check */ + if (*seq_num <= 0) { + DEBUG(3,("ldapsam_get_seq_num: invalid sequence number: %d\n", + (int)*seq_num)); + goto done; + } + + ntstatus = NT_STATUS_OK; + + done: + if (values != NULL) + ldap_value_free(values); + if (msg != NULL) + ldap_msgfree(msg); + if (mem_ctx) + talloc_destroy(mem_ctx); + + return ntstatus; +} + /******************************************************************* Run the search by name. ******************************************************************/ @@ -694,9 +834,9 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, if (ldap_state->is_nds_ldap) { char *user_dn; - int pwd_len; + size_t pwd_len; char clear_text_pw[512]; - + /* Make call to Novell eDirectory ldap extension to get clear text password. NOTE: This will only work if we have an SSL connection to eDirectory. */ user_dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); @@ -717,7 +857,7 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, } else { DEBUG(0, ("init_sam_from_ldap: failed to get user_dn for '%s'\n", username)); } - } + } if (use_samba_attrs) { if (!smbldap_get_single_pstring (ldap_state->smbldap_state->ldap_struct, entry, @@ -741,9 +881,11 @@ static BOOL init_sam_from_ldap(struct ldapsam_privates *ldap_state, return False; ZERO_STRUCT(smbntpwd); } - } + } + + pwHistLen = 0; - account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen > 0){ uint8 *pwhist = NULL; int i; @@ -1087,7 +1229,7 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, if (need_update(sampass, PDB_PWHISTORY)) { uint32 pwHistLen = 0; - account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen == 0) { /* Remove any password history from the LDAP store. */ memset(temp, '0', 64); /* NOTE !!!! '0' *NOT '\0' */ @@ -1153,7 +1295,7 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, uint16 badcount = pdb_get_bad_password_count(sampass); time_t badtime = pdb_get_bad_password_time(sampass); uint32 pol; - account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &pol); + pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &pol); DEBUG(3, ("updating bad password fields, policy=%u, count=%u, time=%u\n", (unsigned int)pol, (unsigned int)badcount, (unsigned int)badtime)); @@ -2158,10 +2300,10 @@ static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map, { pstring filter; - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))", + pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))", LDAP_OBJ_GROUPMAP, get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), - gid); + (unsigned long)gid); return ldapsam_getgroup(methods, filter, map); } @@ -2312,7 +2454,7 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, { const char *attrs[] = { "memberUid", NULL }; - rc = smbldap_search(conn, lp_ldap_group_suffix(), + rc = smbldap_search(conn, lp_ldap_user_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg); } @@ -2536,10 +2678,10 @@ static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state, { pstring filter; - pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%d))", + pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%lu))", LDAP_OBJ_POSIXGROUP, LDAP_OBJ_IDMAP_ENTRY, get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), - gid); + (unsigned long)gid); return ldapsam_search_one_group(ldap_state, filter, result); } @@ -2589,7 +2731,7 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods, ldap_msgfree(result); pstrcpy( suffix, lp_ldap_idmap_suffix() ); - pstr_sprintf(filter, "(&(objectClass=%s)(%s=%d))", + pstr_sprintf(filter, "(&(objectClass=%s)(%s=%u))", LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_GIDNUMBER, map->gid); @@ -3131,6 +3273,187 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods, return NT_STATUS_OK; } +static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods, int policy_index, uint32 value) +{ + NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; + int rc; + LDAPMod **mods = NULL; + fstring value_string; + const char *policy_attr = NULL; + + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)methods->private_data; + + const char *attrs[2]; + + DEBUG(10,("ldapsam_set_account_policy\n")); + + if (!ldap_state->domain_dn) { + return NT_STATUS_INVALID_PARAMETER; + } + + policy_attr = get_account_policy_attr(policy_index); + if (policy_attr == NULL) { + DEBUG(0,("ldapsam_set_account_policy: invalid policy\n")); + return ntstatus; + } + + attrs[0] = policy_attr; + attrs[1] = NULL; + + slprintf(value_string, sizeof(value_string) - 1, "%i", value); + + smbldap_set_mod(&mods, LDAP_MOD_REPLACE, policy_attr, value_string); + + rc = smbldap_modify(ldap_state->smbldap_state, ldap_state->domain_dn, mods); + + ldap_mods_free(mods, True); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->smbldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING,&ld_error); + + DEBUG(0, ("ldapsam_set_account_policy: Could not set account policy " + "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), + ld_error?ld_error:"unknown")); + SAFE_FREE(ld_error); + return ntstatus; + } + + if (!cache_account_policy_set(policy_index, value)) { + DEBUG(0,("ldapsam_set_account_policy: failed to update local tdb cache\n")); + return ntstatus; + } + + return NT_STATUS_OK; +} + +static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods, int policy_index, uint32 *value) +{ + NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + int count; + int rc; + char **vals = NULL; + const char *policy_attr = NULL; + + struct ldapsam_privates *ldap_state = + (struct ldapsam_privates *)methods->private_data; + + const char *attrs[2]; + + DEBUG(10,("ldapsam_get_account_policy_from_ldap\n")); + + if (!ldap_state->domain_dn) { + return NT_STATUS_INVALID_PARAMETER; + } + + policy_attr = get_account_policy_attr(policy_index); + if (!policy_attr) { + DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid policy index: %d\n", policy_index)); + return ntstatus; + } + + attrs[0] = policy_attr; + attrs[1] = NULL; + + rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn, + LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &result); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->smbldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING,&ld_error); + + DEBUG(0, ("ldapsam_get_account_policy_from_ldap: Could not set account policy " + "for %s, error: %s (%s)\n", ldap_state->domain_dn, ldap_err2string(rc), + ld_error?ld_error:"unknown")); + SAFE_FREE(ld_error); + return ntstatus; + } + + count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + if (count < 1) { + goto out; + } + + entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); + if (entry == NULL) { + goto out; + } + + vals = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, policy_attr); + if (vals == NULL) { + goto out; + } + + *value = (uint32)atol(vals[0]); + + ntstatus = NT_STATUS_OK; + +out: + if (vals) + ldap_value_free(vals); + ldap_msgfree(result); + + return ntstatus; +} + +/* wrapper around ldapsam_get_account_policy_from_ldap(), handles tdb as cache + + - if there is a valid cache entry, return that + - if there is an LDAP entry, update cache and return + - otherwise set to default, update cache and return + + Guenther +*/ +static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value) +{ + NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; + + if (cache_account_policy_get(policy_index, value)) { + DEBUG(11,("ldapsam_get_account_policy: got valid value from cache\n")); + return NT_STATUS_OK; + } + + ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index, value); + if (NT_STATUS_IS_OK(ntstatus)) { + goto update_cache; + } + + DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from ldap, returning default.\n")); + +#if 0 + /* should we automagically migrate old tdb value here ? */ + if (account_policy_get(policy_index, value)) + goto update_ldap; + + DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying default\n", policy_index)); +#endif + + if (!account_policy_get_default(policy_index, value)) { + return ntstatus; + } + +/* update_ldap: */ + + ntstatus = ldapsam_set_account_policy(methods, policy_index, *value); + if (!NT_STATUS_IS_OK(ntstatus)) { + return ntstatus; + } + + update_cache: + + if (!cache_account_policy_set(policy_index, *value)) { + DEBUG(0,("ldapsam_get_account_policy: failed to update local tdb as a cache\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + return NT_STATUS_OK; +} + static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, @@ -3890,6 +4213,11 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS ** (*pdb_method)->enum_group_memberships = ldapsam_enum_group_memberships; (*pdb_method)->lookup_rids = ldapsam_lookup_rids; + (*pdb_method)->get_account_policy = ldapsam_get_account_policy; + (*pdb_method)->set_account_policy = ldapsam_set_account_policy; + + (*pdb_method)->get_seq_num = ldapsam_get_seq_num; + /* TODO: Setup private data and free */ ldap_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct ldapsam_privates); |