From 54abd2aa66069e6baf7769c496f46d9dba18db39 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 30 Sep 2005 17:13:37 +0000 Subject: r10656: BIG merge from trunk. Features not copied over * \PIPE\unixinfo * winbindd's {group,alias}membership new functions * winbindd's lookupsids() functionality * swat (trunk changes to be reverted as per discussion with Deryck) (This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3) --- source3/passdb/lookup_sid.c | 28 ++-- source3/passdb/passdb.c | 16 +- source3/passdb/pdb_get_set.c | 8 +- source3/passdb/pdb_interface.c | 134 ++++++++++++++-- source3/passdb/pdb_ldap.c | 354 +++++++++++++++++++++++++++++++++++++++-- source3/passdb/pdb_nds.c | 2 +- source3/passdb/pdb_smbpasswd.c | 22 +-- source3/passdb/secrets.c | 66 +++++++- source3/passdb/util_sam_sid.c | 191 ++++++---------------- 9 files changed, 614 insertions(+), 207 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 4cd9516dd1..6b58210919 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -97,19 +97,27 @@ BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAM } } - if (!winbind_lookup_sid(sid, dom_name, name, name_type)) { - fstring sid_str; - DOM_SID tmp_sid; - uint32 rid; + if (winbind_lookup_sid(sid, dom_name, name, name_type)) { + return True; + } - DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) )); + DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying " + "special SIDs.\n", sid_string_static(sid))); - sid_copy(&tmp_sid, sid); - sid_split_rid(&tmp_sid, &rid); - return map_domain_sid_to_name(&tmp_sid, dom_name) && - lookup_known_rid(&tmp_sid, rid, name, name_type); + { + const char *dom, *obj_name; + + if (lookup_special_sid(sid, &dom, &obj_name, name_type)) { + DEBUG(10, ("found %s\\%s\n", dom, obj_name)); + fstrcpy(dom_name, dom); + fstrcpy(name, obj_name); + return True; + } } - return True; + + DEBUG(10, ("lookup_sid failed\n")); + + return False; } /***************************************************************** diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index 283eb7f1c1..a7ff3a04f7 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -1875,7 +1875,7 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) } /* Change from V1 is addition of password history field. */ - account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen) { uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN); if (!pw_hist) { @@ -2083,7 +2083,7 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si nt_pw_len = 0; } - account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); nt_pw_hist = pdb_get_pw_history(sampass, &nt_pw_hist_len); if (pwHistLen && nt_pw_hist && nt_pw_hist_len) { nt_pw_hist_len *= PW_HISTORY_ENTRY_LEN; @@ -2292,8 +2292,8 @@ BOOL pdb_update_bad_password_count(SAM_ACCOUNT *sampass, BOOL *updated) return True; } - if (!account_policy_get(AP_RESET_COUNT_TIME, &resettime)) { - DEBUG(0, ("pdb_update_bad_password_count: account_policy_get failed.\n")); + if (!pdb_get_account_policy(AP_RESET_COUNT_TIME, &resettime)) { + DEBUG(0, ("pdb_update_bad_password_count: pdb_get_account_policy failed.\n")); return False; } @@ -2334,8 +2334,8 @@ BOOL pdb_update_autolock_flag(SAM_ACCOUNT *sampass, BOOL *updated) return True; } - if (!account_policy_get(AP_LOCK_ACCOUNT_DURATION, &duration)) { - DEBUG(0, ("pdb_update_autolock_flag: account_policy_get failed.\n")); + if (!pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &duration)) { + DEBUG(0, ("pdb_update_autolock_flag: pdb_get_account_policy failed.\n")); return False; } @@ -2383,9 +2383,9 @@ BOOL pdb_increment_bad_password_count(SAM_ACCOUNT *sampass) return False; /* Retrieve the account lockout policy */ - if (!account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, + if (!pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout)) { - DEBUG(0, ("pdb_increment_bad_password_count: account_policy_get failed.\n")); + DEBUG(0, ("pdb_increment_bad_password_count: pdb_get_account_policy failed.\n")); return False; } diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c index 12e8bcc9cf..783e9e23fa 100644 --- a/source3/passdb/pdb_get_set.c +++ b/source3/passdb/pdb_get_set.c @@ -1123,7 +1123,7 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) return False; - if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire) + if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire) || (expire==(uint32)-1) || (expire == 0)) { if (!pdb_set_pass_must_change_time (sampass, get_time_t_max(), PDB_CHANGED)) return False; @@ -1134,7 +1134,7 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) return False; } - if (!account_policy_get(AP_MIN_PASSWORD_AGE, &min_age) + if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &min_age) || (min_age==(uint32)-1)) { if (!pdb_set_pass_can_change_time (sampass, 0, PDB_CHANGED)) return False; @@ -1189,13 +1189,13 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) { uchar *pwhistory; uint32 pwHistLen; - account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen != 0){ uint32 current_history_len; /* We need to make sure we don't have a race condition here - the account policy history length can change between when the pw_history was first loaded into the SAM_ACCOUNT struct and now.... JRA. */ - pwhistory = CONST_DISCARD(uchar *, pdb_get_pw_history(sampass, ¤t_history_len)); + pwhistory = (uchar *)pdb_get_pw_history(sampass, ¤t_history_len); if (current_history_len != pwHistLen) { /* After closing and reopening SAM_ACCOUNT the history diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index d4407492c2..a9e41984c3 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -665,43 +665,46 @@ static NTSTATUS context_lookup_rids(struct pdb_context *context, rids, names, attrs); } -static BOOL context_search_users(struct pdb_context *context, - struct pdb_search *search, uint16 acct_flags) +static NTSTATUS context_get_account_policy(struct pdb_context *context, + int policy_index, uint32 *value) { + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ((!context) || (!context->pdb_methods)) { DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + return ret; } - return context->pdb_methods->search_users(context->pdb_methods, - search, acct_flags); + return context->pdb_methods->get_account_policy(context->pdb_methods, + policy_index, value); } -static BOOL context_search_groups(struct pdb_context *context, - struct pdb_search *search) +static NTSTATUS context_set_account_policy(struct pdb_context *context, + int policy_index, uint32 value) { + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ((!context) || (!context->pdb_methods)) { DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + return ret; } - return context->pdb_methods->search_groups(context->pdb_methods, - search); + return context->pdb_methods->set_account_policy(context->pdb_methods, + policy_index, value); } -static BOOL context_search_aliases(struct pdb_context *context, - struct pdb_search *search, - const DOM_SID *sid) +static NTSTATUS context_get_seq_num(struct pdb_context *context, time_t *seq_num) { + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + if ((!context) || (!context->pdb_methods)) { DEBUG(0, ("invalid pdb_context specified!\n")); - return False; + return ret; } - return context->pdb_methods->search_aliases(context->pdb_methods, - search, sid); + return context->pdb_methods->get_seq_num(context->pdb_methods, seq_num); } - + /****************************************************************** Free and cleanup a pdb context, any associated data and anything that the attached modules might have associated. @@ -721,6 +724,43 @@ static void free_pdb_context(struct pdb_context **context) *context = NULL; } +static BOOL context_search_users(struct pdb_context *context, + struct pdb_search *search, uint16 acct_flags) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_users(context->pdb_methods, + search, acct_flags); +} + +static BOOL context_search_groups(struct pdb_context *context, + struct pdb_search *search) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_groups(context->pdb_methods, + search); +} + +static BOOL context_search_aliases(struct pdb_context *context, + struct pdb_search *search, + const DOM_SID *sid) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_aliases(context->pdb_methods, + search, sid); +} + /****************************************************************** Make a pdb_methods from scratch *******************************************************************/ @@ -832,6 +872,11 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_enum_alias_memberships = context_enum_alias_memberships; (*context)->pdb_lookup_rids = context_lookup_rids; + (*context)->pdb_get_account_policy = context_get_account_policy; + (*context)->pdb_set_account_policy = context_set_account_policy; + + (*context)->pdb_get_seq_num = context_get_seq_num; + (*context)->pdb_search_users = context_search_users; (*context)->pdb_search_groups = context_search_groups; (*context)->pdb_search_aliases = context_search_aliases; @@ -1318,6 +1363,41 @@ NTSTATUS pdb_lookup_rids(TALLOC_CTX *mem_ctx, num_rids, rids, names, attrs); } +BOOL pdb_get_account_policy(int policy_index, uint32 *value) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_get_account_policy(pdb_context, policy_index, value)); +} + +BOOL pdb_set_account_policy(int policy_index, uint32 value) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_set_account_policy(pdb_context, policy_index, value)); +} + +BOOL pdb_get_seq_num(time_t *seq_num) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_get_seq_num(pdb_context, seq_num)); +} /*************************************************************** Initialize the static context (at smbd startup etc). @@ -1380,6 +1460,22 @@ static void pdb_default_endsampwent(struct pdb_methods *methods) return; /* NT_STATUS_NOT_IMPLEMENTED; */ } +static NTSTATUS pdb_default_get_account_policy(struct pdb_methods *methods, int policy_index, uint32 *value) +{ + return account_policy_get(policy_index, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; +} + +static NTSTATUS pdb_default_set_account_policy(struct pdb_methods *methods, int policy_index, uint32 value) +{ + return account_policy_set(policy_index, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; +} + +static NTSTATUS pdb_default_get_seq_num(struct pdb_methods *methods, time_t *seq_num) +{ + *seq_num = time(NULL); + return NT_STATUS_OK; +} + static void add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid, uid_t **uids, int *num) { @@ -1908,6 +2004,10 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*methods)->enum_aliasmem = pdb_default_enum_aliasmem; (*methods)->enum_alias_memberships = pdb_default_alias_memberships; (*methods)->lookup_rids = pdb_default_lookup_rids; + (*methods)->get_account_policy = pdb_default_get_account_policy; + (*methods)->set_account_policy = pdb_default_set_account_policy; + (*methods)->get_seq_num = pdb_default_get_seq_num; + (*methods)->search_users = pdb_default_search_users; (*methods)->search_groups = pdb_default_search_groups; (*methods)->search_aliases = pdb_default_search_aliases; 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); diff --git a/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c index 3e5f8d1b93..599a198c5a 100644 --- a/source3/passdb/pdb_nds.c +++ b/source3/passdb/pdb_nds.c @@ -550,7 +550,7 @@ static int nmasldap_get_password( LDAP *ld, char *objectDN, size_t *pwdSize, /* in bytes */ - char *pwd ) + unsigned char *pwd ) { int err = 0; diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index edb578b1e7..6eb4305409 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/passdb/pdb_smbpasswd.c @@ -313,10 +313,11 @@ static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_s unsigned char *smbpwd = smbpasswd_state->smbpwd; unsigned char *smbntpwd = smbpasswd_state->smbntpwd; char linebuf[256]; - unsigned char c; + int c; unsigned char *p; long uidval; size_t linebuf_len; + char *status; if(fp == NULL) { DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n")); @@ -329,11 +330,12 @@ static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_s /* * Scan the file, a line at a time and check if the name matches. */ - while (!feof(fp)) { + status = linebuf; + while (status && !feof(fp)) { linebuf[0] = '\0'; - fgets(linebuf, 256, fp); - if (ferror(fp)) { + status = fgets(linebuf, 256, fp); + if (status == NULL && ferror(fp)) { return NULL; } @@ -651,7 +653,7 @@ Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); #ifdef DEBUG_PASSWORD DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", - fd, new_entry_length, new_entry)); + fd, (int)new_entry_length, new_entry)); #endif if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) { @@ -689,9 +691,10 @@ static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, con /* Static buffers we will return. */ pstring user_name; + char *status; char linebuf[256]; char readbuf[1024]; - unsigned char c; + int c; fstring ascii_p16; fstring encode_bits; unsigned char *p = NULL; @@ -738,13 +741,14 @@ static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, con /* * Scan the file, a line at a time and check if the name matches. */ - while (!feof(fp)) { + status = linebuf; + while (status && !feof(fp)) { pwd_seekpos = sys_ftell(fp); linebuf[0] = '\0'; - fgets(linebuf, sizeof(linebuf), fp); - if (ferror(fp)) { + status = fgets(linebuf, sizeof(linebuf), fp); + if (status == NULL && ferror(fp)) { pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); fclose(fp); return False; diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 6144037200..29437c35a8 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -30,6 +30,9 @@ static TDB_CONTEXT *tdb; +/* Urrrg. global.... */ +BOOL global_machine_password_needs_changing; + /** * Use a TDB to store an incrementing random seed. * @@ -294,12 +297,23 @@ BOOL secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], return False; } - if (pass_last_set_time) *pass_last_set_time = pass->mod_time; + if (pass_last_set_time) { + *pass_last_set_time = pass->mod_time; + } memcpy(ret_pwd, pass->hash, 16); SAFE_FREE(pass); - if (channel) + if (channel) { *channel = get_default_sec_channel(); + } + + /* Test if machine password has expired and needs to be changed */ + if (lp_machine_password_timeout()) { + if (pass->mod_time > 0 && time(NULL) > (pass->mod_time + + lp_machine_password_timeout())) { + global_machine_password_needs_changing = True; + } + } return True; } @@ -454,11 +468,11 @@ BOOL secrets_store_machine_password(const char *pass, const char *domain, uint32 return ret; } - /************************************************************************ Routine to fetch the plaintext machine account password for a realm -the password is assumed to be a null terminated ascii string + the password is assumed to be a null terminated ascii string. ************************************************************************/ + char *secrets_fetch_machine_password(const char *domain, time_t *pass_last_set_time, uint32 *channel) @@ -503,7 +517,46 @@ char *secrets_fetch_machine_password(const char *domain, return ret; } +/******************************************************************* + Wrapper around retrieving the trust account password +*******************************************************************/ + +BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16], uint32 *channel) +{ + DOM_SID sid; + char *pwd; + time_t last_set_time; + + /* if we are a DC and this is not our domain, then lookup an account + for the domain trust */ + + if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() ) { + if (!secrets_fetch_trusted_domain_password(domain, &pwd, &sid, + &last_set_time)) { + DEBUG(0, ("get_trust_pw: could not fetch trust " + "account password for trusted domain %s\n", + domain)); + return False; + } + + *channel = SEC_CHAN_DOMAIN; + E_md4hash(pwd, ret_pwd); + SAFE_FREE(pwd); + + return True; + } + + /* Just get the account for the requested domain. In the future this + * might also cover to be member of more than one domain. */ + + if (secrets_fetch_trust_account_password(domain, ret_pwd, + &last_set_time, channel)) + return True; + DEBUG(5, ("get_trust_pw: could not fetch trust account " + "password for domain %s\n", domain)); + return False; +} /************************************************************************ Routine to delete the machine trust account password file for a domain. @@ -523,7 +576,6 @@ BOOL trusted_domain_password_delete(const char *domain) return secrets_delete(trustdom_keystr(domain)); } - BOOL secrets_store_ldap_pw(const char* dn, char* pw) { char *key = NULL; @@ -541,8 +593,9 @@ BOOL secrets_store_ldap_pw(const char* dn, char* pw) } /******************************************************************* - find the ldap password + Find the ldap password. ******************************************************************/ + BOOL fetch_ldap_pw(char **dn, char** pw) { char *key = NULL; @@ -605,7 +658,6 @@ BOOL fetch_ldap_pw(char **dn, char** pw) return True; } - /** * Get trusted domains info from secrets.tdb. * diff --git a/source3/passdb/util_sam_sid.c b/source3/passdb/util_sam_sid.c index a9e1921e0d..42e4b6df96 100644 --- a/source3/passdb/util_sam_sid.c +++ b/source3/passdb/util_sam_sid.c @@ -30,15 +30,12 @@ typedef struct _known_sid_users { const char *known_user_name; } known_sid_users; -static struct sid_name_map_info +struct sid_name_map_info { const DOM_SID *sid; const char *name; const known_sid_users *known_users; -} sid_name_map[MAX_SID_NAMES]; - -static BOOL sid_name_map_initialized = False; -/* static known_sid_users no_users[] = {{0, 0, NULL}}; */ +}; static const known_sid_users everyone_users[] = { { 0, SID_NAME_WKN_GRP, "Everyone" }, @@ -83,64 +80,12 @@ static const known_sid_users builtin_groups[] = { { BUILTIN_ALIAS_RID_PRE_2K_ACCESS, SID_NAME_ALIAS, "Pre-Windows 2000 Compatible Access" }, { 0, (enum SID_NAME_USE)0, NULL}}; -/************************************************************************** - Quick init function. -*************************************************************************/ - -static void init_sid_name_map (void) -{ - int i = 0; - - if (sid_name_map_initialized) return; - - if ((lp_security() == SEC_USER) && lp_domain_logons()) { - sid_name_map[i].sid = get_global_sam_sid(); - /* This is not lp_workgroup() for good reason: - it must stay around longer than the lp_*() - strings do */ - sid_name_map[i].name = SMB_STRDUP(lp_workgroup()); - sid_name_map[i].known_users = NULL; - i++; - sid_name_map[i].sid = get_global_sam_sid(); - sid_name_map[i].name = SMB_STRDUP(global_myname()); - sid_name_map[i].known_users = NULL; - i++; - } else { - sid_name_map[i].sid = get_global_sam_sid(); - sid_name_map[i].name = SMB_STRDUP(global_myname()); - sid_name_map[i].known_users = NULL; - i++; - } - - sid_name_map[i].sid = &global_sid_Builtin; - sid_name_map[i].name = "BUILTIN"; - sid_name_map[i].known_users = &builtin_groups[0]; - i++; - - sid_name_map[i].sid = &global_sid_World_Domain; - sid_name_map[i].name = ""; - sid_name_map[i].known_users = &everyone_users[0]; - i++; - - sid_name_map[i].sid = &global_sid_Creator_Owner_Domain; - sid_name_map[i].name = ""; - sid_name_map[i].known_users = &creator_owner_users[0]; - i++; - - sid_name_map[i].sid = &global_sid_NT_Authority; - sid_name_map[i].name = "NT Authority"; - sid_name_map[i].known_users = &nt_authority_users[0]; - i++; - - /* End of array. */ - sid_name_map[i].sid = NULL; - sid_name_map[i].name = NULL; - sid_name_map[i].known_users = NULL; - - sid_name_map_initialized = True; - - return; -} +static struct sid_name_map_info special_domains[] = { + { &global_sid_Builtin, "BUILTIN", builtin_groups }, + { &global_sid_World_Domain, "", everyone_users }, + { &global_sid_Creator_Owner_Domain, "", creator_owner_users }, + { &global_sid_NT_Authority, "NT Authority", nt_authority_users }, + { NULL, NULL, NULL }}; /************************************************************************** Turns a domain SID into a name, returned in the nt_domain argument. @@ -153,101 +98,74 @@ BOOL map_domain_sid_to_name(DOM_SID *sid, fstring nt_domain) sid_to_string(sid_str, sid); - if (!sid_name_map_initialized) - init_sid_name_map(); - DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str)); - if (nt_domain == NULL) - return False; + if (sid_check_is_domain(sid)) { + fstrcpy(nt_domain, get_global_sam_name()); + return True; + } - while (sid_name_map[i].sid != NULL) { - sid_to_string(sid_str, sid_name_map[i].sid); - DEBUG(5,("map_domain_sid_to_name: compare: %s\n", sid_str)); - if (sid_equal(sid_name_map[i].sid, sid)) { - fstrcpy(nt_domain, sid_name_map[i].name); - DEBUG(5,("map_domain_sid_to_name: found '%s'\n", nt_domain)); + while (special_domains[i].sid != NULL) { + DEBUG(5,("map_domain_sid_to_name: compare: %s\n", + sid_string_static(special_domains[i].sid))); + if (sid_equal(special_domains[i].sid, sid)) { + fstrcpy(nt_domain, special_domains[i].name); + DEBUG(5,("map_domain_sid_to_name: found '%s'\n", + nt_domain)); return True; } i++; } - DEBUG(5,("map_domain_sid_to_name: mapping for %s not found\n", sid_str)); - - return False; -} - -/************************************************************************** - Looks up a known username from one of the known domains. -***************************************************************************/ - -BOOL lookup_known_rid(DOM_SID *sid, uint32 rid, char *name, enum SID_NAME_USE *psid_name_use) -{ - int i = 0; - struct sid_name_map_info *psnm; - - if (!sid_name_map_initialized) - init_sid_name_map(); - - for(i = 0; sid_name_map[i].sid != NULL; i++) { - psnm = &sid_name_map[i]; - if(sid_equal(psnm->sid, sid)) { - int j; - for(j = 0; psnm->known_users && psnm->known_users[j].known_user_name != NULL; j++) { - if(rid == psnm->known_users[j].rid) { - DEBUG(5,("lookup_builtin_rid: rid = %u, domain = '%s', user = '%s'\n", - (unsigned int)rid, psnm->name, psnm->known_users[j].known_user_name )); - fstrcpy( name, psnm->known_users[j].known_user_name); - *psid_name_use = psnm->known_users[j].sid_name_use; - return True; - } - } - } - } + DEBUG(5,("map_domain_sid_to_name: mapping for %s not found\n", + sid_string_static(sid))); return False; } /************************************************************************** - Turns a domain name into a SID. - *** side-effect: if the domain name is NULL, it is set to our domain *** + Looks up a known username from one of the known domains. ***************************************************************************/ -BOOL map_domain_name_to_sid(DOM_SID *sid, char *nt_domain) +BOOL lookup_special_sid(const DOM_SID *sid, const char **domain, + const char **name, enum SID_NAME_USE *type) { - int i = 0; + int i; + DOM_SID dom_sid; + uint32 rid; + const known_sid_users *users = NULL; - if (nt_domain == NULL) { - DEBUG(5,("map_domain_name_to_sid: mapping NULL domain to our SID.\n")); - sid_copy(sid, get_global_sam_sid()); - return True; + sid_copy(&dom_sid, sid); + if (!sid_split_rid(&dom_sid, &rid)) { + DEBUG(2, ("Could not split rid from SID\n")); + return False; } - if (nt_domain[0] == 0) { - fstrcpy(nt_domain, global_myname()); - DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n", nt_domain)); - sid_copy(sid, get_global_sam_sid()); - return True; + for (i=0; special_domains[i].sid != NULL; i++) { + if (sid_equal(&dom_sid, special_domains[i].sid)) { + *domain = special_domains[i].name; + users = special_domains[i].known_users; + break; + } } - DEBUG(5,("map_domain_name_to_sid: %s\n", nt_domain)); - - if (!sid_name_map_initialized) - init_sid_name_map(); + if (users == NULL) { + DEBUG(10, ("SID %s is no special sid\n", + sid_string_static(sid))); + return False; + } - while (sid_name_map[i].name != NULL) { - DEBUG(5,("map_domain_name_to_sid: compare: %s\n", sid_name_map[i].name)); - if (strequal(sid_name_map[i].name, nt_domain)) { - fstring sid_str; - sid_copy(sid, sid_name_map[i].sid); - sid_to_string(sid_str, sid_name_map[i].sid); - DEBUG(5,("map_domain_name_to_sid: found %s\n", sid_str)); + for (i=0; users[i].known_user_name != NULL; i++) { + if (rid == users[i].rid) { + *name = users[i].known_user_name; + *type = users[i].sid_name_use; return True; } - i++; } - DEBUG(0,("map_domain_name_to_sid: mapping to %s not found.\n", nt_domain)); + DEBUG(10, ("RID of special SID %s not found\n", + sid_string_static(sid))); + return False; } @@ -283,20 +201,17 @@ BOOL map_name_to_wellknown_sid(DOM_SID *sid, enum SID_NAME_USE *use, const char { int i, j; - if (!sid_name_map_initialized) - init_sid_name_map(); - DEBUG(10,("map_name_to_wellknown_sid: looking up %s\n", name)); - for (i=0; sid_name_map[i].sid != NULL; i++) { - const known_sid_users *users = sid_name_map[i].known_users; + for (i=0; special_domains[i].sid != NULL; i++) { + const known_sid_users *users = special_domains[i].known_users; if (users == NULL) continue; for (j=0; users[j].known_user_name != NULL; j++) { if ( strequal(users[j].known_user_name, name) ) { - sid_copy(sid, sid_name_map[i].sid); + sid_copy(sid, special_domains[i].sid); sid_append_rid(sid, users[j].rid); *use = users[j].sid_name_use; return True; -- cgit