summaryrefslogtreecommitdiffstats
path: root/source3/passdb
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/passdb
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/passdb')
-rw-r--r--source3/passdb/ABI/pdb-0.1.0.sigs311
-rw-r--r--source3/passdb/ABI/pdb-0.1.1.sigs312
-rw-r--r--source3/passdb/ABI/pdb-0.1.2.sigs313
-rw-r--r--source3/passdb/ABI/pdb-0.sigs311
-rw-r--r--source3/passdb/ABI/samba-passdb-0.2.0.sigs312
-rw-r--r--source3/passdb/ABI/samba-passdb-0.24.1.sigs313
-rw-r--r--source3/passdb/ABI/samba-passdb-0.24.2.sigs313
-rw-r--r--source3/passdb/ABI/samba-passdb-0.25.0.sigs312
-rw-r--r--source3/passdb/ABI/samba-passdb-0.26.0.sigs310
-rw-r--r--source3/passdb/ABI/samba-passdb-0.27.0.sigs308
-rw-r--r--source3/passdb/ABI/samba-passdb-0.27.1.sigs309
-rw-r--r--source3/passdb/ABI/samba-passdb-0.27.2.sigs306
-rw-r--r--source3/passdb/ABI/samba-passdb-0.28.0.sigs306
-rw-r--r--source3/passdb/account_pol.c494
-rw-r--r--source3/passdb/login_cache.c202
-rw-r--r--source3/passdb/lookup_sid.c1731
-rw-r--r--source3/passdb/lookup_sid.h96
-rw-r--r--source3/passdb/machine_account_secrets.c2080
-rw-r--r--source3/passdb/machine_sid.c251
-rw-r--r--source3/passdb/machine_sid.h33
-rw-r--r--source3/passdb/passdb.c2755
-rw-r--r--source3/passdb/pdb_compat.c105
-rw-r--r--source3/passdb/pdb_get_set.c1163
-rw-r--r--source3/passdb/pdb_interface.c2713
-rw-r--r--source3/passdb/pdb_ldap.c6822
-rw-r--r--source3/passdb/pdb_ldap.h71
-rw-r--r--source3/passdb/pdb_ldap_schema.c191
-rw-r--r--source3/passdb/pdb_ldap_schema.h124
-rw-r--r--source3/passdb/pdb_ldap_util.c338
-rw-r--r--source3/passdb/pdb_ldap_util.h32
-rw-r--r--source3/passdb/pdb_nds.c908
-rw-r--r--source3/passdb/pdb_nds.h39
-rw-r--r--source3/passdb/pdb_samba_dsdb.c3895
-rw-r--r--source3/passdb/pdb_secrets.c172
-rw-r--r--source3/passdb/pdb_secrets.h30
-rw-r--r--source3/passdb/pdb_smbpasswd.c1750
-rw-r--r--source3/passdb/pdb_smbpasswd.h30
-rw-r--r--source3/passdb/pdb_tdb.c1369
-rw-r--r--source3/passdb/pdb_tdb.h32
-rw-r--r--source3/passdb/pdb_util.c245
-rw-r--r--source3/passdb/py_passdb.c4074
-rw-r--r--source3/passdb/secrets.c546
-rw-r--r--source3/passdb/secrets_lsa.c245
-rw-r--r--source3/passdb/wscript_build42
44 files changed, 36614 insertions, 0 deletions
diff --git a/source3/passdb/ABI/pdb-0.1.0.sigs b/source3/passdb/ABI/pdb-0.1.0.sigs
new file mode 100644
index 0000000..f4de9c4
--- /dev/null
+++ b/source3/passdb/ABI/pdb-0.1.0.sigs
@@ -0,0 +1,311 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_gid_to_sid: bool (gid_t, struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_uid_to_sid: bool (uid_t, struct dom_sid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/pdb-0.1.1.sigs b/source3/passdb/ABI/pdb-0.1.1.sigs
new file mode 100644
index 0000000..99f9605
--- /dev/null
+++ b/source3/passdb/ABI/pdb-0.1.1.sigs
@@ -0,0 +1,312 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_gid_to_sid: bool (gid_t, struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_uid_to_sid: bool (uid_t, struct dom_sid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/pdb-0.1.2.sigs b/source3/passdb/ABI/pdb-0.1.2.sigs
new file mode 100644
index 0000000..8b97bac
--- /dev/null
+++ b/source3/passdb/ABI/pdb-0.1.2.sigs
@@ -0,0 +1,313 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_gid_to_sid: bool (gid_t, struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_uid_to_sid: bool (uid_t, struct dom_sid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/pdb-0.sigs b/source3/passdb/ABI/pdb-0.sigs
new file mode 100644
index 0000000..e6e3f73
--- /dev/null
+++ b/source3/passdb/ABI/pdb-0.sigs
@@ -0,0 +1,311 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_gid_to_sid: bool (gid_t, struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_uid_to_sid: bool (uid_t, struct dom_sid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.2.0.sigs b/source3/passdb/ABI/samba-passdb-0.2.0.sigs
new file mode 100644
index 0000000..e2246f6
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.2.0.sigs
@@ -0,0 +1,312 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.24.1.sigs b/source3/passdb/ABI/samba-passdb-0.24.1.sigs
new file mode 100644
index 0000000..e5885d0
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.24.1.sigs
@@ -0,0 +1,313 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_init: struct pdb_search *(TALLOC_CTX *, enum pdb_search_type)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.24.2.sigs b/source3/passdb/ABI/samba-passdb-0.24.2.sigs
new file mode 100644
index 0000000..6ab600e
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.24.2.sigs
@@ -0,0 +1,313 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+my_sam_name: const char *(void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.25.0.sigs b/source3/passdb/ABI/samba-passdb-0.25.0.sigs
new file mode 100644
index 0000000..546374c
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.25.0.sigs
@@ -0,0 +1,312 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.26.0.sigs b/source3/passdb/ABI/samba-passdb-0.26.0.sigs
new file mode 100644
index 0000000..f3762e5
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.26.0.sigs
@@ -0,0 +1,310 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.27.0.sigs b/source3/passdb/ABI/samba-passdb-0.27.0.sigs
new file mode 100644
index 0000000..1245ce5
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.27.0.sigs
@@ -0,0 +1,308 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.27.1.sigs b/source3/passdb/ABI/samba-passdb-0.27.1.sigs
new file mode 100644
index 0000000..6437ed2
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.27.1.sigs
@@ -0,0 +1,309 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_guests: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/passdb/ABI/samba-passdb-0.27.2.sigs b/source3/passdb/ABI/samba-passdb-0.27.2.sigs
new file mode 100644
index 0000000..06fc3b7
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.27.2.sigs
@@ -0,0 +1,306 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_guests: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_xid_to_sid: bool (struct dom_sid *, const struct unixid *)
+xid_to_sid: void (struct dom_sid *, const struct unixid *)
diff --git a/source3/passdb/ABI/samba-passdb-0.28.0.sigs b/source3/passdb/ABI/samba-passdb-0.28.0.sigs
new file mode 100644
index 0000000..06fc3b7
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.28.0.sigs
@@ -0,0 +1,306 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_guests: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_xid_to_sid: bool (struct dom_sid *, const struct unixid *)
+xid_to_sid: void (struct dom_sid *, const struct unixid *)
diff --git a/source3/passdb/account_pol.c b/source3/passdb/account_pol.c
new file mode 100644
index 0000000..34c0d72
--- /dev/null
+++ b/source3/passdb/account_pol.c
@@ -0,0 +1,494 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * account policy storage
+ * Copyright (C) Jean François Micouleau 1998-2001
+ * Copyright (C) Andrew Bartlett 2002
+ * Copyright (C) Guenther Deschner 2004-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "passdb.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "../libcli/security/security.h"
+#include "lib/privileges.h"
+#include "lib/gencache.h"
+#include "lib/util/smb_strtox.h"
+
+static struct db_context *db;
+
+/* cache all entries for 60 seconds for to save ldap-queries (cache is updated
+ * after this period if admins do not use pdbedit or usermanager but manipulate
+ * ldap directly) - gd */
+
+#define DATABASE_VERSION 3
+#define AP_TTL 60
+
+
+struct ap_table {
+ enum pdb_policy_type type;
+ const char *string;
+ uint32_t default_val;
+ const char *description;
+ const char *ldap_attr;
+};
+
+static const struct ap_table account_policy_names[] = {
+ {PDB_POLICY_MIN_PASSWORD_LEN, "min password length", MINPASSWDLENGTH,
+ "Minimal password length (default: 5)",
+ "sambaMinPwdLength" },
+
+ {PDB_POLICY_PASSWORD_HISTORY, "password history", 0,
+ "Length of Password History Entries (default: 0 => off)",
+ "sambaPwdHistoryLength" },
+
+ {PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, "user must logon to change password", 0,
+ "Force Users to logon for password change (default: 0 => off, 2 => on)",
+ "sambaLogonToChgPwd" },
+
+ {PDB_POLICY_MAX_PASSWORD_AGE, "maximum password age", (uint32_t) -1,
+ "Maximum password age, in seconds (default: -1 => never expire passwords)",
+ "sambaMaxPwdAge" },
+
+ {PDB_POLICY_MIN_PASSWORD_AGE,"minimum password age", 0,
+ "Minimal password age, in seconds (default: 0 => allow immediate password change)",
+ "sambaMinPwdAge" },
+
+ {PDB_POLICY_LOCK_ACCOUNT_DURATION, "lockout duration", 30,
+ "Lockout duration in minutes (default: 30, -1 => forever)",
+ "sambaLockoutDuration" },
+
+ {PDB_POLICY_RESET_COUNT_TIME, "reset count minutes", 30,
+ "Reset time after lockout in minutes (default: 30)",
+ "sambaLockoutObservationWindow" },
+
+ {PDB_POLICY_BAD_ATTEMPT_LOCKOUT, "bad lockout attempt", 0,
+ "Lockout users after bad logon attempts (default: 0 => off)",
+ "sambaLockoutThreshold" },
+
+ {PDB_POLICY_TIME_TO_LOGOUT, "disconnect time", (uint32_t) -1,
+ "Disconnect Users outside logon hours (default: -1 => off, 0 => on)",
+ "sambaForceLogoff" },
+
+ {PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, "refuse machine password change", 0,
+ "Allow Machine Password changes (default: 0 => off)",
+ "sambaRefuseMachinePwdChange" },
+
+ {0, NULL, 0, "", NULL}
+};
+
+void account_policy_names_list(TALLOC_CTX *mem_ctx, const char ***names, int *num_names)
+{
+ const char **nl;
+ int i, count = ARRAY_SIZE(account_policy_names);
+
+ nl = talloc_array(mem_ctx, const char *, count);
+ if (!nl) {
+ *num_names = 0;
+ return;
+ }
+ for (i=0; i<count; i++) {
+ nl[i] = account_policy_names[i].string;
+ }
+ /* Do not return the last null entry */
+ *num_names = count-1;
+ *names = nl;
+ return;
+}
+
+/****************************************************************************
+Get the account policy name as a string from its #define'ed number
+****************************************************************************/
+
+const char *decode_account_policy_name(enum pdb_policy_type type)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (type == account_policy_names[i].type) {
+ return account_policy_names[i].string;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy LDAP attribute as a string from its #define'ed number
+****************************************************************************/
+
+const char *get_account_policy_attr(enum pdb_policy_type type)
+{
+ int i;
+ for (i=0; account_policy_names[i].type; i++) {
+ if (type == account_policy_names[i].type) {
+ return account_policy_names[i].ldap_attr;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy description as a string from its #define'ed number
+****************************************************************************/
+
+const char *account_policy_get_desc(enum pdb_policy_type type)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (type == account_policy_names[i].type) {
+ return account_policy_names[i].description;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+Get the account policy name as a string from its #define'ed number
+****************************************************************************/
+
+enum pdb_policy_type account_policy_name_to_typenum(const char *name)
+{
+ int i;
+ for (i=0; account_policy_names[i].string; i++) {
+ if (strcmp(name, account_policy_names[i].string) == 0) {
+ return account_policy_names[i].type;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************
+Get default value for account policy
+*****************************************************************************/
+
+bool account_policy_get_default(enum pdb_policy_type type, uint32_t *val)
+{
+ int i;
+ for (i=0; account_policy_names[i].type; i++) {
+ if (account_policy_names[i].type == type) {
+ *val = account_policy_names[i].default_val;
+ return True;
+ }
+ }
+ DEBUG(0,("no default for account_policy index %d found. This should never happen\n",
+ type));
+ return False;
+}
+
+/*****************************************************************************
+ Set default for a type if it is empty
+*****************************************************************************/
+
+static bool account_policy_set_default_on_empty(enum pdb_policy_type type)
+{
+
+ uint32_t value;
+
+ if (!account_policy_get(type, &value) &&
+ !account_policy_get_default(type, &value)) {
+ return False;
+ }
+
+ return account_policy_set(type, value);
+}
+
+/*****************************************************************************
+ Open the account policy tdb.
+***`*************************************************************************/
+
+bool init_account_policy(void)
+{
+
+ const char *vstring = "INFO/version";
+ uint32_t version = 0;
+ int i;
+ NTSTATUS status;
+ char *db_path;
+
+ if (db != NULL) {
+ return True;
+ }
+
+ db_path = state_path(talloc_tos(), "account_policy.tdb");
+ if (db_path == NULL) {
+ return false;
+ }
+
+ db = db_open(NULL, db_path, 0, TDB_DEFAULT,
+ O_RDWR, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+
+ if (db == NULL) { /* the account policies files does not exist or open
+ * failed, try to create a new one */
+ db = db_open(NULL, db_path, 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+ if (db == NULL) {
+ DEBUG(0,("Failed to open account policy database\n"));
+ TALLOC_FREE(db_path);
+ return False;
+ }
+ }
+ TALLOC_FREE(db_path);
+
+ status = dbwrap_fetch_uint32_bystring(db, vstring, &version);
+ if (!NT_STATUS_IS_OK(status)) {
+ version = 0;
+ }
+
+ if (version == DATABASE_VERSION) {
+ return true;
+ }
+
+ /* handle a Samba upgrade */
+
+ if (dbwrap_transaction_start(db) != 0) {
+ DEBUG(0, ("transaction_start failed\n"));
+ TALLOC_FREE(db);
+ return false;
+ }
+
+ status = dbwrap_fetch_uint32_bystring(db, vstring, &version);
+ if (!NT_STATUS_IS_OK(status)) {
+ version = 0;
+ }
+
+ if (version == DATABASE_VERSION) {
+ /*
+ * Race condition
+ */
+ if (dbwrap_transaction_cancel(db)) {
+ smb_panic("transaction_cancel failed");
+ }
+ return true;
+ }
+
+ if (version != DATABASE_VERSION) {
+ status = dbwrap_store_uint32_bystring(db, vstring,
+ DATABASE_VERSION);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("dbwrap_store_uint32_t failed: %s\n",
+ nt_errstr(status)));
+ goto cancel;
+ }
+
+ for (i=0; account_policy_names[i].type; i++) {
+
+ if (!account_policy_set_default_on_empty(account_policy_names[i].type)) {
+ DEBUG(0,("failed to set default value in account policy tdb\n"));
+ goto cancel;
+ }
+ }
+ }
+
+ /* These exist by default on NT4 in [HKLM\SECURITY\Policy\Accounts] */
+
+ privilege_create_account( &global_sid_World );
+ privilege_create_account( &global_sid_Builtin_Account_Operators );
+ privilege_create_account( &global_sid_Builtin_Server_Operators );
+ privilege_create_account( &global_sid_Builtin_Print_Operators );
+ privilege_create_account( &global_sid_Builtin_Backup_Operators );
+
+ /* BUILTIN\Administrators get everything -- *always* */
+
+ if ( lp_enable_privileges() ) {
+ if ( !grant_all_privileges( &global_sid_Builtin_Administrators ) ) {
+ DEBUG(1,("init_account_policy: Failed to grant privileges "
+ "to BUILTIN\\Administrators!\n"));
+ }
+ }
+
+ if (dbwrap_transaction_commit(db) != 0) {
+ DEBUG(0, ("transaction_commit failed\n"));
+ TALLOC_FREE(db);
+ return false;
+ }
+
+ return True;
+
+ cancel:
+ if (dbwrap_transaction_cancel(db)) {
+ smb_panic("transaction_cancel failed");
+ }
+ TALLOC_FREE(db);
+
+ return false;
+}
+
+/*****************************************************************************
+Get an account policy (from tdb)
+*****************************************************************************/
+
+bool account_policy_get(enum pdb_policy_type type, uint32_t *value)
+{
+ const char *name;
+ uint32_t regval;
+ NTSTATUS status;
+
+ if (!init_account_policy()) {
+ return False;
+ }
+
+ if (value) {
+ *value = 0;
+ }
+
+ name = decode_account_policy_name(type);
+ if (name == NULL) {
+ DEBUG(1, ("account_policy_get: Field %d is not a valid account policy type! Cannot get, returning 0.\n", type));
+ return False;
+ }
+
+ status = dbwrap_fetch_uint32_bystring(db, name, &regval);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("account_policy_get: tdb_fetch_uint32_t failed for type %d (%s), returning 0\n", type, name));
+ return False;
+ }
+
+ if (value) {
+ *value = regval;
+ }
+
+ DEBUG(10,("account_policy_get: name: %s, val: %d\n", name, regval));
+ return True;
+}
+
+
+/****************************************************************************
+Set an account policy (in tdb)
+****************************************************************************/
+
+bool account_policy_set(enum pdb_policy_type type, uint32_t value)
+{
+ const char *name;
+ NTSTATUS status;
+
+ if (!init_account_policy()) {
+ return False;
+ }
+
+ name = decode_account_policy_name(type);
+ if (name == NULL) {
+ DEBUG(1, ("Field %d is not a valid account policy type! Cannot set.\n", type));
+ return False;
+ }
+
+ status = dbwrap_trans_store_uint32_bystring(db, name, value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("store_uint32_t failed for type %d (%s) on value "
+ "%u: %s\n", type, name, value, nt_errstr(status)));
+ return False;
+ }
+
+ DEBUG(10,("account_policy_set: name: %s, value: %d\n", name, value));
+
+ return True;
+}
+
+/****************************************************************************
+Set an account policy in the cache
+****************************************************************************/
+
+bool cache_account_policy_set(enum pdb_policy_type type, uint32_t value)
+{
+ const char *policy_name = NULL;
+ char *cache_key = NULL;
+ char *cache_value = NULL;
+ bool ret = False;
+
+ policy_name = decode_account_policy_name(type);
+ if (policy_name == NULL) {
+ DEBUG(0,("cache_account_policy_set: no policy found\n"));
+ return False;
+ }
+
+ if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ if (asprintf(&cache_value, "%lu\n", (unsigned long)value) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ DEBUG(10,("cache_account_policy_set: updating account pol cache\n"));
+
+ ret = gencache_set(cache_key, cache_value, time(NULL)+AP_TTL);
+
+ done:
+ SAFE_FREE(cache_key);
+ SAFE_FREE(cache_value);
+ return ret;
+}
+
+/*****************************************************************************
+Get an account policy from the cache
+*****************************************************************************/
+
+bool cache_account_policy_get(enum pdb_policy_type type, uint32_t *value)
+{
+ const char *policy_name = NULL;
+ char *cache_key = NULL;
+ char *cache_value = NULL;
+ bool ret = False;
+
+ policy_name = decode_account_policy_name(type);
+ if (policy_name == NULL) {
+ DEBUG(0,("cache_account_policy_set: no policy found\n"));
+ return False;
+ }
+
+ if (asprintf(&cache_key, "ACCT_POL/%s", policy_name) < 0) {
+ DEBUG(0, ("asprintf failed\n"));
+ goto done;
+ }
+
+ if (gencache_get(cache_key, talloc_tos(), &cache_value, NULL)) {
+ int error = 0;
+ uint32_t tmp;
+
+ tmp = smb_strtoul(cache_value,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+ *value = tmp;
+ ret = True;
+ }
+
+ done:
+ SAFE_FREE(cache_key);
+ TALLOC_FREE(cache_value);
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+struct db_context *get_account_pol_db( void )
+{
+
+ if ( db == NULL ) {
+ if ( !init_account_policy() ) {
+ return NULL;
+ }
+ }
+
+ return db;
+}
diff --git a/source3/passdb/login_cache.c b/source3/passdb/login_cache.c
new file mode 100644
index 0000000..6b636b3
--- /dev/null
+++ b/source3/passdb/login_cache.c
@@ -0,0 +1,202 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu local cache for
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "passdb.h"
+#include "util_tdb.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#define LOGIN_CACHE_FILE "login_cache.tdb"
+
+#define SAM_CACHE_FORMAT "dwwd"
+
+static TDB_CONTEXT *cache;
+
+bool login_cache_init(void)
+{
+ char* cache_fname = NULL;
+
+ /* skip file open if it's already opened */
+ if (cache) return True;
+
+ cache_fname = cache_path(talloc_tos(), LOGIN_CACHE_FILE);
+ if (cache_fname == NULL) {
+ DEBUG(0, ("Filename allocation failed.\n"));
+ return False;
+ }
+
+ DEBUG(5, ("Opening cache file at %s\n", cache_fname));
+
+ cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0644);
+
+ if (!cache)
+ DEBUG(5, ("Attempt to open %s failed.\n", cache_fname));
+
+ TALLOC_FREE(cache_fname);
+
+ return (cache ? True : False);
+}
+
+bool login_cache_shutdown(void)
+{
+ /* tdb_close routine returns non-zero on error */
+ if (!cache) return False;
+ DEBUG(5, ("Closing cache file\n"));
+ return tdb_close(cache) == 0;
+}
+
+/* if we can't read the cache, oh well, no need to return anything */
+bool login_cache_read(struct samu *sampass, struct login_cache *entry)
+{
+ char *keystr;
+ TDB_DATA databuf;
+ uint32_t entry_timestamp = 0, bad_password_time = 0;
+ uint16_t acct_ctrl;
+
+ if (!login_cache_init()) {
+ return false;
+ }
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return false;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return false;
+ }
+
+ DEBUG(7, ("Looking up login cache for user %s\n",
+ keystr));
+ databuf = tdb_fetch_bystring(cache, keystr);
+ SAFE_FREE(keystr);
+
+ ZERO_STRUCTP(entry);
+
+ if (tdb_unpack (databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
+ &entry_timestamp,
+ &acct_ctrl,
+ &entry->bad_password_count,
+ &bad_password_time) == -1) {
+ DEBUG(7, ("No cache entry found\n"));
+ SAFE_FREE(databuf.dptr);
+ return false;
+ }
+
+ /*
+ * Deal with 32-bit acct_ctrl. In the tdb we only store 16-bit
+ * ("w" in SAM_CACHE_FORMAT). Fixes bug 7253.
+ */
+ entry->acct_ctrl = acct_ctrl;
+
+ /* Deal with possible 64-bit time_t. */
+ entry->entry_timestamp = (time_t)entry_timestamp;
+ entry->bad_password_time = (time_t)bad_password_time;
+
+ SAFE_FREE(databuf.dptr);
+
+ DEBUG(5, ("Found login cache entry: timestamp %12u, flags 0x%x, count %d, time %12u\n",
+ (unsigned int)entry->entry_timestamp, entry->acct_ctrl,
+ entry->bad_password_count, (unsigned int)entry->bad_password_time));
+ return true;
+}
+
+bool login_cache_write(const struct samu *sampass,
+ const struct login_cache *entry)
+{
+ char *keystr;
+ TDB_DATA databuf;
+ bool ret;
+ uint32_t entry_timestamp;
+ uint32_t bad_password_time = entry->bad_password_time;
+
+ if (!login_cache_init())
+ return False;
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return False;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ entry_timestamp = (uint32_t)time(NULL);
+
+ databuf.dsize =
+ tdb_pack(NULL, 0, SAM_CACHE_FORMAT,
+ entry_timestamp,
+ entry->acct_ctrl,
+ entry->bad_password_count,
+ bad_password_time);
+ databuf.dptr = SMB_MALLOC_ARRAY(uint8_t, databuf.dsize);
+ if (!databuf.dptr) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ if (tdb_pack(databuf.dptr, databuf.dsize, SAM_CACHE_FORMAT,
+ entry_timestamp,
+ entry->acct_ctrl,
+ entry->bad_password_count,
+ bad_password_time)
+ != databuf.dsize) {
+ SAFE_FREE(keystr);
+ SAFE_FREE(databuf.dptr);
+ return False;
+ }
+
+ ret = tdb_store_bystring(cache, keystr, databuf, 0);
+ SAFE_FREE(keystr);
+ SAFE_FREE(databuf.dptr);
+ return ret == 0;
+}
+
+bool login_cache_delentry(const struct samu *sampass)
+{
+ int ret;
+ char *keystr;
+
+ if (!login_cache_init())
+ return False;
+
+ if (pdb_get_nt_username(sampass) == NULL) {
+ return False;
+ }
+
+ keystr = SMB_STRDUP(pdb_get_nt_username(sampass));
+ if (!keystr || !keystr[0]) {
+ SAFE_FREE(keystr);
+ return False;
+ }
+
+ DEBUG(9, ("About to delete entry for %s\n", keystr));
+ ret = tdb_delete_bystring(cache, keystr);
+ DEBUG(9, ("tdb_delete returned %d\n", ret));
+
+ SAFE_FREE(keystr);
+ return ret == 0;
+}
diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
new file mode 100644
index 0000000..426ea3f
--- /dev/null
+++ b/source3/passdb/lookup_sid.c
@@ -0,0 +1,1731 @@
+/*
+ Unix SMB/CIFS implementation.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Gerald (Jerry) Carter 2003
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "passdb.h"
+#include "lib/util_unixsids.h"
+#include "../librpc/gen_ndr/ndr_security.h"
+#include "secrets.h"
+#include "../lib/util/memcache.h"
+#include "idmap_cache.h"
+#include "../libcli/security/security.h"
+#include "lib/winbind_util.h"
+#include "../librpc/gen_ndr/idmap.h"
+#include "lib/util/bitmap.h"
+
+static bool lookup_unix_user_name(const char *name, struct dom_sid *sid)
+{
+ struct passwd *pwd;
+ bool ret;
+
+ pwd = Get_Pwnam_alloc(talloc_tos(), name);
+ if (pwd == NULL) {
+ return False;
+ }
+
+ /*
+ * For 64-bit uid's we have enough space in the whole SID,
+ * should they become necessary
+ */
+ ret = sid_compose(sid, &global_sid_Unix_Users, pwd->pw_uid);
+ TALLOC_FREE(pwd);
+ return ret;
+}
+
+static bool lookup_unix_group_name(const char *name, struct dom_sid *sid)
+{
+ struct group *grp;
+
+ grp = getgrnam(name);
+ if (grp == NULL) {
+ return False;
+ }
+
+ /*
+ * For 64-bit gid's we have enough space in the whole SID,
+ * should they become necessary
+ */
+ return sid_compose(sid, &global_sid_Unix_Groups, grp->gr_gid);
+}
+
+/*****************************************************************
+ Dissect a user-provided name into domain, name, sid and type.
+
+ If an explicit domain name was given in the form domain\user, it
+ has to try that. If no explicit domain name was given, we have
+ to do guesswork.
+*****************************************************************/
+
+bool lookup_name(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ struct dom_sid *ret_sid, enum lsa_SidType *ret_type)
+{
+ char *p;
+ const char *tmp;
+ const char *domain = NULL;
+ const char *name = NULL;
+ uint32_t rid;
+ struct dom_sid sid;
+ enum lsa_SidType type;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ if (tmp_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return false;
+ }
+
+ p = strchr_m(full_name, '\\');
+
+ if (p != NULL) {
+ domain = talloc_strndup(tmp_ctx, full_name,
+ PTR_DIFF(p, full_name));
+ name = talloc_strdup(tmp_ctx, p+1);
+ } else {
+ char *q = strchr_m(full_name, '@');
+
+ /* Set the domain for UPNs */
+ if (q != NULL) {
+ name = talloc_strndup(tmp_ctx,
+ full_name,
+ PTR_DIFF(q, full_name));
+ domain = talloc_strdup(tmp_ctx, q + 1);
+ } else {
+ domain = talloc_strdup(tmp_ctx, "");
+ name = talloc_strdup(tmp_ctx, full_name);
+ }
+ }
+
+ if ((domain == NULL) || (name == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ DEBUG(10,("lookup_name: %s => domain=[%s], name=[%s]\n",
+ full_name, domain, name));
+ DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
+
+ if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) {
+ bool check_global_sam = false;
+
+ check_global_sam = strequal(domain, get_global_sam_name());
+
+ /* If we are running on a DC that has PASSDB module with domain
+ * information, check if DNS forest name is matching the domain
+ * name. This is the case of IPA domain controller when
+ * trusted AD DC looks up users found in a Global Catalog of
+ * the forest root domain. */
+ if (!check_global_sam && (IS_DC)) {
+ struct pdb_domain_info *dom_info = NULL;
+ dom_info = pdb_get_domain_info(tmp_ctx);
+
+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) {
+ check_global_sam = strequal(domain, dom_info->dns_forest);
+ }
+
+ TALLOC_FREE(dom_info);
+ }
+
+ if (check_global_sam) {
+ /* It's our own domain, lookup the name in passdb */
+ if (lookup_global_sam_name(name, flags, &rid, &type)) {
+ sid_compose(&sid, get_global_sam_sid(), rid);
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ }
+
+ if ((flags & LOOKUP_NAME_BUILTIN) &&
+ strequal(domain, builtin_domain_name()))
+ {
+ if (strlen(name) == 0) {
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ sid_copy(&sid, &global_sid_Builtin);
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* Explicit request for a name in BUILTIN */
+ if (lookup_builtin_name(name, &rid)) {
+ sid_compose(&sid, &global_sid_Builtin, rid);
+ type = SID_NAME_ALIAS;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* Try the explicit winbind lookup first, don't let it guess the
+ * domain yet at this point yet. This comes later. */
+
+ if ((domain[0] != '\0') &&
+ (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
+ (winbind_lookup_name(domain, name, &sid, &type))) {
+ goto ok;
+ }
+
+ if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0)
+ && strequal(domain, unix_users_domain_name())) {
+ if (lookup_unix_user_name(name, &sid)) {
+ type = SID_NAME_USER;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if (((flags & LOOKUP_NAME_NO_NSS) == 0)
+ && strequal(domain, unix_groups_domain_name())) {
+ if (lookup_unix_group_name(name, &sid)) {
+ type = SID_NAME_DOM_GRP;
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * Finally check for a well known domain name ("NT Authority"),
+ * this is being taken care of in lookup_wellknown_name().
+ */
+ if ((domain[0] != '\0') &&
+ (flags & LOOKUP_NAME_WKN) &&
+ lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
+ {
+ type = SID_NAME_WKN_GRP;
+ goto ok;
+ }
+
+ /*
+ * If we're told not to look up 'isolated' names then we're
+ * done.
+ */
+ if (!(flags & LOOKUP_NAME_ISOLATED)) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * No domain names beyond this point
+ */
+ if (domain[0] != '\0') {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* Now the guesswork begins, we haven't been given an explicit
+ * domain. Try the sequence as documented on
+ * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
+ * November 27, 2005 */
+
+ /* 1. well-known names */
+
+ /*
+ * Check for well known names without a domain name.
+ * e.g. \Creator Owner.
+ */
+
+ if ((flags & LOOKUP_NAME_WKN) &&
+ lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
+ {
+ type = SID_NAME_WKN_GRP;
+ goto ok;
+ }
+
+ /* 2. Builtin domain as such */
+
+ if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
+ strequal(name, builtin_domain_name()))
+ {
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ sid_copy(&sid, &global_sid_Builtin);
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 3. Account domain */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) &&
+ strequal(name, get_global_sam_name()))
+ {
+ if (!secrets_fetch_domain_sid(name, &sid)) {
+ DEBUG(3, ("Could not fetch my SID\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 4. Primary domain */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
+ strequal(name, lp_workgroup()))
+ {
+ if (!secrets_fetch_domain_sid(name, &sid)) {
+ DEBUG(3, ("Could not fetch the domain SID\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 5. Trusted domains as such, to me it looks as if members don't do
+ this, tested an XP workstation in a NT domain -- vl */
+
+ if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
+ (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
+ {
+ /* Swap domain and name */
+ tmp = name; name = domain; domain = tmp;
+ type = SID_NAME_DOMAIN;
+ goto ok;
+ }
+
+ /* 6. Builtin aliases */
+
+ if ((flags & LOOKUP_NAME_BUILTIN) &&
+ lookup_builtin_name(name, &rid))
+ {
+ domain = talloc_strdup(tmp_ctx, builtin_domain_name());
+ sid_compose(&sid, &global_sid_Builtin, rid);
+ type = SID_NAME_ALIAS;
+ goto ok;
+ }
+
+ /* 7. Local systems' SAM (DCs don't have a local SAM) */
+ /* 8. Primary SAM (On members, this is the domain) */
+
+ /* Both cases are done by looking at our passdb */
+
+ if ((flags & LOOKUP_NAME_DOMAIN) &&
+ lookup_global_sam_name(name, flags, &rid, &type))
+ {
+ domain = talloc_strdup(tmp_ctx, get_global_sam_name());
+ sid_compose(&sid, get_global_sam_sid(), rid);
+ goto ok;
+ }
+
+ /* Now our local possibilities are exhausted. */
+
+ if (!(flags & LOOKUP_NAME_REMOTE)) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /* If we are not a DC, we have to ask in our primary domain. Let
+ * winbind do that. */
+
+ if (!IS_DC &&
+ (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
+ domain = talloc_strdup(tmp_ctx, lp_workgroup());
+ goto ok;
+ }
+
+ /* 9. Trusted domains */
+
+ /* If we're a DC we have to ask all trusted DC's. Winbind does not do
+ * that (yet), but give it a chance. */
+
+ if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
+ struct dom_sid dom_sid;
+ enum lsa_SidType domain_type;
+
+ if (type == SID_NAME_DOMAIN) {
+ /* Swap name and type */
+ tmp = name; name = domain; domain = tmp;
+ goto ok;
+ }
+
+ /* Here we have to cope with a little deficiency in the
+ * winbind API: We have to ask it again for the name of the
+ * domain it figured out itself. Maybe fix that later... */
+
+ sid_copy(&dom_sid, &sid);
+ sid_split_rid(&dom_sid, NULL);
+
+ if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
+ &domain_type) ||
+ (domain_type != SID_NAME_DOMAIN)) {
+ DEBUG(2, ("winbind could not find the domain's name "
+ "it just looked up for us\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ goto ok;
+ }
+
+ /* 10. Don't translate */
+
+ /* 11. Ok, windows would end here. Samba has two more options:
+ Unmapped users and unmapped groups */
+
+ if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0)
+ && lookup_unix_user_name(name, &sid)) {
+ domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
+ type = SID_NAME_USER;
+ goto ok;
+ }
+
+ if (((flags & LOOKUP_NAME_NO_NSS) == 0)
+ && lookup_unix_group_name(name, &sid)) {
+ domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
+ type = SID_NAME_DOM_GRP;
+ goto ok;
+ }
+
+ /*
+ * Ok, all possibilities tried. Fail.
+ */
+
+ TALLOC_FREE(tmp_ctx);
+ return false;
+
+ ok:
+ if ((domain == NULL) || (name == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * Hand over the results to the talloc context we've been given.
+ */
+
+ if ((ret_name != NULL) &&
+ !(*ret_name = talloc_strdup(mem_ctx, name))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ if (ret_domain != NULL) {
+ char *tmp_dom;
+ if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ if (!strupper_m(tmp_dom)) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ *ret_domain = tmp_dom;
+ }
+
+ if (ret_sid != NULL) {
+ sid_copy(ret_sid, &sid);
+ }
+
+ if (ret_type != NULL) {
+ *ret_type = type;
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+/************************************************************************
+ Names from smb.conf can be unqualified. eg. valid users = foo
+ These names should never map to a remote name. Try global_sam_name()\foo,
+ and then "Unix Users"\foo (or "Unix Groups"\foo).
+************************************************************************/
+
+bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ struct dom_sid *ret_sid, enum lsa_SidType *ret_type)
+{
+ char *qualified_name = NULL;
+ const char *p = strchr_m(full_name, *lp_winbind_separator());
+ bool is_qualified = p != NULL || strchr_m(full_name, '@') != NULL;
+
+ /* For DOMAIN\user or user@REALM directly call lookup_name(). */
+ if (is_qualified) {
+
+ /* The name is already qualified with a domain. */
+
+ if (p != NULL && *lp_winbind_separator() != '\\') {
+ /* lookup_name() needs '\\' as a separator */
+
+ qualified_name = talloc_strdup(mem_ctx, full_name);
+ if (qualified_name == NULL) {
+ return false;
+ }
+ qualified_name[p - full_name] = '\\';
+ full_name = qualified_name;
+ }
+
+ return lookup_name(mem_ctx, full_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type);
+ }
+
+ /* Try with winbind default domain name. */
+ if (lp_winbind_use_default_domain()) {
+ bool ok;
+
+ qualified_name = talloc_asprintf(mem_ctx,
+ "%s\\%s",
+ lp_workgroup(),
+ full_name);
+ if (qualified_name == NULL) {
+ return false;
+ }
+
+ ok = lookup_name(mem_ctx,
+ qualified_name,
+ flags,
+ ret_domain,
+ ret_name,
+ ret_sid,
+ ret_type);
+ if (ok) {
+ return true;
+ }
+ }
+
+ /* Try with our own SAM name. */
+ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
+ get_global_sam_name(),
+ full_name );
+ if (!qualified_name) {
+ return false;
+ }
+
+ if (lookup_name(mem_ctx, qualified_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type)) {
+ return true;
+ }
+
+ /* Finally try with "Unix Users" or "Unix Group" */
+ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
+ flags & LOOKUP_NAME_GROUP ?
+ unix_groups_domain_name() :
+ unix_users_domain_name(),
+ full_name );
+ if (!qualified_name) {
+ return false;
+ }
+
+ return lookup_name(mem_ctx, qualified_name, flags,
+ ret_domain, ret_name,
+ ret_sid, ret_type);
+}
+
+static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ int num_rids, uint32_t *rids,
+ const char **domain_name,
+ const char **names, enum lsa_SidType *types)
+{
+ int i;
+ const char **my_names;
+ enum lsa_SidType *my_types;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
+ return false;
+ }
+
+ if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
+ domain_name, &my_names, &my_types)) {
+ *domain_name = "";
+ for (i=0; i<num_rids; i++) {
+ names[i] = "";
+ types[i] = SID_NAME_UNKNOWN;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return true;
+ }
+
+ if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ /*
+ * winbind_lookup_rids allocates its own array. We've been given the
+ * array, so copy it over
+ */
+
+ for (i=0; i<num_rids; i++) {
+ if (my_names[i] == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ if (!(names[i] = talloc_strdup(names, my_names[i]))) {
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ types[i] = my_types[i];
+ }
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+static bool lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid,
+ int num_rids, uint32_t *rids,
+ const char **domain_name,
+ const char ***names, enum lsa_SidType **types)
+{
+ int i;
+ struct dom_sid_buf buf;
+
+ DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
+ dom_sid_str_buf(domain_sid, &buf)));
+
+ if (num_rids) {
+ *names = talloc_zero_array(mem_ctx, const char *, num_rids);
+ *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
+
+ if ((*names == NULL) || (*types == NULL)) {
+ return false;
+ }
+
+ for (i = 0; i < num_rids; i++)
+ (*types)[i] = SID_NAME_UNKNOWN;
+ } else {
+ *names = NULL;
+ *types = NULL;
+ }
+
+ if (sid_check_is_our_sam(domain_sid)) {
+ NTSTATUS result;
+
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, get_global_sam_name());
+ }
+
+ if (*domain_name == NULL) {
+ return false;
+ }
+
+ become_root();
+ result = pdb_lookup_rids(domain_sid, num_rids, rids,
+ *names, *types);
+ unbecome_root();
+
+ return (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
+ NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
+ }
+
+ if (sid_check_is_builtin(domain_sid)) {
+
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, builtin_domain_name());
+ }
+
+ if (*domain_name == NULL) {
+ return false;
+ }
+
+ for (i=0; i<num_rids; i++) {
+ if (lookup_builtin_rid(*names, rids[i],
+ &(*names)[i])) {
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_ALIAS;
+ } else {
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ return true;
+ }
+
+ if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
+ for (i=0; i<num_rids; i++) {
+ struct dom_sid sid;
+ sid_compose(&sid, domain_sid, rids[i]);
+ if (lookup_wellknown_sid(mem_ctx, &sid,
+ domain_name, &(*names)[i])) {
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_WKN_GRP;
+ } else {
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ return true;
+ }
+
+ if (sid_check_is_unix_users(domain_sid)) {
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, unix_users_domain_name());
+ if (*domain_name == NULL) {
+ return false;
+ }
+ }
+ for (i=0; i<num_rids; i++) {
+ (*names)[i] = talloc_strdup(
+ (*names), uidtoname(rids[i]));
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_USER;
+ }
+ return true;
+ }
+
+ if (sid_check_is_unix_groups(domain_sid)) {
+ if (*domain_name == NULL) {
+ *domain_name = talloc_strdup(
+ mem_ctx, unix_groups_domain_name());
+ if (*domain_name == NULL) {
+ return false;
+ }
+ }
+ for (i=0; i<num_rids; i++) {
+ (*names)[i] = talloc_strdup(
+ (*names), gidtoname(rids[i]));
+ if ((*names)[i] == NULL) {
+ return false;
+ }
+ (*types)[i] = SID_NAME_DOM_GRP;
+ }
+ return true;
+ }
+
+ return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
+ domain_name, *names, *types);
+}
+
+/*
+ * Is the SID a domain as such? If yes, lookup its name.
+ */
+
+static bool lookup_as_domain(const struct dom_sid *sid, TALLOC_CTX *mem_ctx,
+ const char **name)
+{
+ const char *tmp;
+ enum lsa_SidType type;
+
+ if (sid_check_is_our_sam(sid)) {
+ *name = talloc_strdup(mem_ctx, get_global_sam_name());
+ return true;
+ }
+
+ if (sid_check_is_builtin(sid)) {
+ *name = talloc_strdup(mem_ctx, builtin_domain_name());
+ return true;
+ }
+
+ if (sid_check_is_wellknown_domain(sid, &tmp)) {
+ *name = talloc_strdup(mem_ctx, tmp);
+ return true;
+ }
+
+ if (sid_check_is_unix_users(sid)) {
+ *name = talloc_strdup(mem_ctx, unix_users_domain_name());
+ return true;
+ }
+
+ if (sid_check_is_unix_groups(sid)) {
+ *name = talloc_strdup(mem_ctx, unix_groups_domain_name());
+ return true;
+ }
+
+ if (sid->num_auths != 4) {
+ /* This can't be a domain */
+ return false;
+ }
+
+ if (IS_DC) {
+ uint32_t i, num_domains;
+ struct trustdom_info **domains;
+
+ /* This is relatively expensive, but it happens only on DCs
+ * and for SIDs that have 4 sub-authorities and thus look like
+ * domains */
+
+ if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
+ &num_domains,
+ &domains))) {
+ return false;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ if (dom_sid_equal(sid, &domains[i]->sid)) {
+ *name = talloc_strdup(mem_ctx,
+ domains[i]->name);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
+ (type == SID_NAME_DOMAIN)) {
+ *name = tmp;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This tries to implement the rather weird rules for the lsa_lookup level
+ * parameter.
+ *
+ * This is as close as we can get to what W2k3 does. With this we survive the
+ * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
+ * different, but I assume that's just being too liberal. For example, W2k3
+ * replies to everything else but the levels 1-6 with INVALID_PARAMETER
+ * whereas NT4 does the same as level 1 (I think). I did not fully test that
+ * with NT4, this is what w2k3 does.
+ *
+ * Level 1: Ask everywhere
+ * Level 2: Ask domain and trusted domains, no builtin and wkn
+ * Level 3: Only ask domain
+ * Level 4: W2k3ad: Only ask AD trusts
+ * Level 5: Only ask transitive forest trusts
+ * Level 6: Like 4
+ */
+
+static bool check_dom_sid_to_level(const struct dom_sid *sid, int level)
+{
+ struct dom_sid_buf buf;
+ int ret = false;
+
+ switch(level) {
+ case 1:
+ ret = true;
+ break;
+ case 2:
+ ret = (!sid_check_is_builtin(sid) &&
+ !sid_check_is_wellknown_domain(sid, NULL));
+ break;
+ case 3:
+ case 4:
+ case 6:
+ ret = sid_check_is_our_sam(sid);
+ break;
+ case 5:
+ ret = false;
+ break;
+ }
+
+ DEBUG(10, ("%s SID %s in level %d\n",
+ ret ? "Accepting" : "Rejecting",
+ dom_sid_str_buf(sid, &buf),
+ level));
+ return ret;
+}
+
+/*
+ * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
+ * references to domains, it is explicitly made for this.
+ *
+ * This attempts to be as efficient as possible: It collects all SIDs
+ * belonging to a domain and hands them in bulk to the appropriate lookup
+ * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
+ * *hugely* from this.
+ */
+
+NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
+ const struct dom_sid **sids, int level,
+ struct lsa_dom_info **ret_domains,
+ struct lsa_name_info **ret_names)
+{
+ TALLOC_CTX *tmp_ctx;
+ NTSTATUS result;
+ struct lsa_name_info *name_infos;
+ struct lsa_dom_info *dom_infos = NULL;
+
+ int i, j;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (num_sids) {
+ name_infos = talloc_array(mem_ctx, struct lsa_name_info, num_sids);
+ if (name_infos == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ name_infos = NULL;
+ }
+
+ dom_infos = talloc_zero_array(mem_ctx, struct lsa_dom_info,
+ LSA_REF_DOMAIN_LIST_MULTIPLIER);
+ if (dom_infos == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ /* First build up the data structures:
+ *
+ * dom_infos is a list of domains referenced in the list of
+ * SIDs. Later we will walk the list of domains and look up the RIDs
+ * in bulk.
+ *
+ * name_infos is a shadow-copy of the SIDs array to collect the real
+ * data.
+ *
+ * dom_info->idxs is an index into the name_infos array. The
+ * difficulty we have here is that we need to keep the SIDs the client
+ * asked for in the same order for the reply
+ */
+
+ for (i=0; i<num_sids; i++) {
+ struct dom_sid sid;
+ uint32_t rid = 0;
+ const char *domain_name = NULL;
+
+ sid_copy(&sid, sids[i]);
+ name_infos[i].type = SID_NAME_USE_NONE;
+
+ if (lookup_as_domain(&sid, name_infos, &domain_name)) {
+ /* We can't push that through the normal lookup
+ * process, as this would reference illegal
+ * domains.
+ *
+ * For example S-1-5-32 would end up referencing
+ * domain S-1-5- with RID 32 which is clearly wrong.
+ */
+ if (domain_name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ name_infos[i].rid = 0;
+ name_infos[i].type = SID_NAME_DOMAIN;
+ name_infos[i].name = NULL;
+
+ if (sid_check_is_builtin(&sid)) {
+ /* Yes, W2k3 returns "BUILTIN" both as domain
+ * and name here */
+ name_infos[i].name = talloc_strdup(
+ name_infos, builtin_domain_name());
+ if (name_infos[i].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+ } else {
+ /* This is a normal SID with rid component */
+ if (!sid_split_rid(&sid, &rid)) {
+ result = NT_STATUS_INVALID_SID;
+ goto fail;
+ }
+ }
+
+ if (!check_dom_sid_to_level(&sid, level)) {
+ name_infos[i].rid = 0;
+ name_infos[i].type = SID_NAME_UNKNOWN;
+ name_infos[i].name = NULL;
+ continue;
+ }
+
+ for (j=0; j<LSA_REF_DOMAIN_LIST_MULTIPLIER; j++) {
+ if (!dom_infos[j].valid) {
+ break;
+ }
+ if (dom_sid_equal(&sid, &dom_infos[j].sid)) {
+ break;
+ }
+ }
+
+ if (j == LSA_REF_DOMAIN_LIST_MULTIPLIER) {
+ /* TODO: What's the right error message here? */
+ result = NT_STATUS_NONE_MAPPED;
+ goto fail;
+ }
+
+ if (!dom_infos[j].valid) {
+ /* We found a domain not yet referenced, create a new
+ * ref. */
+ dom_infos[j].valid = true;
+ sid_copy(&dom_infos[j].sid, &sid);
+
+ if (domain_name != NULL) {
+ /* This name was being found above in the case
+ * when we found a domain SID */
+ dom_infos[j].name =
+ talloc_strdup(dom_infos, domain_name);
+ if (dom_infos[j].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ /* lookup_rids will take care of this */
+ dom_infos[j].name = NULL;
+ }
+ }
+
+ name_infos[i].dom_idx = j;
+
+ if (name_infos[i].type == SID_NAME_USE_NONE) {
+ name_infos[i].rid = rid;
+
+ ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
+ &dom_infos[j].num_idxs);
+
+ if (dom_infos[j].idxs == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+ }
+
+ /* Iterate over the domains found */
+
+ for (i=0; i<LSA_REF_DOMAIN_LIST_MULTIPLIER; i++) {
+ uint32_t *rids;
+ const char *domain_name = NULL;
+ const char **names;
+ enum lsa_SidType *types;
+ struct lsa_dom_info *dom = &dom_infos[i];
+
+ if (!dom->valid) {
+ /* No domains left, we're done */
+ break;
+ }
+
+ if (dom->num_idxs == 0) {
+ /*
+ * This happens only if the only sid related to
+ * this domain is the domain sid itself, which
+ * is mapped to SID_NAME_DOMAIN above.
+ */
+ continue;
+ }
+
+ if (!(rids = talloc_array(tmp_ctx, uint32_t, dom->num_idxs))) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (j=0; j<dom->num_idxs; j++) {
+ rids[j] = name_infos[dom->idxs[j]].rid;
+ }
+
+ if (!lookup_rids(tmp_ctx, &dom->sid,
+ dom->num_idxs, rids, &domain_name,
+ &names, &types)) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (j=0; j<dom->num_idxs; j++) {
+ int idx = dom->idxs[j];
+ name_infos[idx].type = types[j];
+ if (types[j] != SID_NAME_UNKNOWN) {
+ name_infos[idx].name =
+ talloc_strdup(name_infos, names[j]);
+ if (name_infos[idx].name == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ } else {
+ name_infos[idx].name = NULL;
+ }
+ }
+ }
+
+ *ret_domains = dom_infos;
+ *ret_names = name_infos;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(dom_infos);
+ TALLOC_FREE(name_infos);
+ TALLOC_FREE(tmp_ctx);
+ return result;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to name function.
+*****************************************************************/
+
+bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const char **ret_domain, const char **ret_name,
+ enum lsa_SidType *ret_type)
+{
+ struct lsa_dom_info *domain;
+ struct lsa_name_info *name;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx;
+ bool ret = false;
+
+ DEBUG(10, ("lookup_sid called for SID '%s'\n",
+ dom_sid_str_buf(sid, &buf)));
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
+ &domain, &name))) {
+ goto done;
+ }
+
+ if (name->type == SID_NAME_UNKNOWN) {
+ goto done;
+ }
+
+ if ((ret_domain != NULL) &&
+ !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
+ goto done;
+ }
+
+ if ((ret_name != NULL) &&
+ !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
+ goto done;
+ }
+
+ if (ret_type != NULL) {
+ *ret_type = name->type;
+ }
+
+ ret = true;
+
+ done:
+ if (ret) {
+ DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
+ dom_sid_str_buf(sid, &buf),
+ domain->name, name->name, name->type));
+ } else {
+ DEBUG(10, ("failed to lookup sid %s\n",
+ dom_sid_str_buf(sid, &buf)));
+ }
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+/*****************************************************************
+ *THE LEGACY* convert SID to id function.
+*****************************************************************/
+
+static bool legacy_sid_to_unixid(const struct dom_sid *psid, struct unixid *id)
+{
+ bool ret;
+
+ become_root();
+ ret = pdb_sid_to_id(psid, id);
+ unbecome_root();
+
+ if (!ret) {
+ struct dom_sid_buf buf;
+ DEBUG(10,("LEGACY: mapping failed for sid %s\n",
+ dom_sid_str_buf(psid, &buf)));
+ return false;
+ }
+
+ return true;
+}
+
+static bool legacy_sid_to_gid(const struct dom_sid *psid, gid_t *pgid)
+{
+ struct unixid id;
+ if (!legacy_sid_to_unixid(psid, &id)) {
+ return false;
+ }
+ if (id.type == ID_TYPE_GID || id.type == ID_TYPE_BOTH) {
+ *pgid = id.id;
+ return true;
+ }
+ return false;
+}
+
+static bool legacy_sid_to_uid(const struct dom_sid *psid, uid_t *puid)
+{
+ struct unixid id;
+ if (!legacy_sid_to_unixid(psid, &id)) {
+ return false;
+ }
+ if (id.type == ID_TYPE_UID || id.type == ID_TYPE_BOTH) {
+ *puid = id.id;
+ return true;
+ }
+ return false;
+}
+
+void xid_to_sid(struct dom_sid *psid, const struct unixid *xid)
+{
+ bool expired = true;
+ bool ret;
+ struct dom_sid_buf buf;
+
+ SMB_ASSERT(xid->type == ID_TYPE_UID || xid->type == ID_TYPE_GID);
+
+ *psid = (struct dom_sid) {0};
+
+ ret = idmap_cache_find_xid2sid(xid, psid, &expired);
+ if (ret && !expired) {
+ DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n",
+ xid->type == ID_TYPE_UID ? 'U' : 'G',
+ xid->id,
+ dom_sid_str_buf(psid, &buf));
+ goto done;
+ }
+
+ ret = winbind_xid_to_sid(psid, xid);
+ if (ret) {
+ /*
+ * winbind can return an explicit negative mapping
+ * here. It's up to winbind to prime the cache either
+ * positively or negatively, don't mess with the cache
+ * here.
+ */
+ DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n",
+ xid->type == ID_TYPE_UID ? 'U' : 'G',
+ xid->id,
+ dom_sid_str_buf(psid, &buf));
+ goto done;
+ }
+
+ {
+ /*
+ * Make a copy, pdb_id_to_sid might want to turn
+ * xid->type into ID_TYPE_BOTH, which we ignore here.
+ */
+ struct unixid rw_xid = *xid;
+
+ become_root();
+ ret = pdb_id_to_sid(&rw_xid, psid);
+ unbecome_root();
+ }
+
+ if (ret) {
+ DBG_DEBUG("%cID %"PRIu32" -> %s from passdb\n",
+ xid->type == ID_TYPE_UID ? 'U' : 'G',
+ xid->id,
+ dom_sid_str_buf(psid, &buf));
+ goto done;
+ }
+
+done:
+ if (is_null_sid(psid)) {
+ /*
+ * Nobody found anything: Return S-1-22-xx-yy. Don't
+ * store that in caches, this is up to the layers
+ * beneath us.
+ */
+ if (xid->type == ID_TYPE_UID) {
+ uid_to_unix_users_sid(xid->id, psid);
+ } else {
+ gid_to_unix_groups_sid(xid->id, psid);
+ }
+
+ DBG_DEBUG("%cID %"PRIu32" -> %s fallback\n",
+ xid->type == ID_TYPE_UID ? 'U' : 'G',
+ xid->id,
+ dom_sid_str_buf(psid, &buf));
+ }
+}
+
+void uid_to_sid(struct dom_sid *psid, uid_t uid)
+{
+ struct unixid xid = { .type = ID_TYPE_UID, .id = uid};
+ xid_to_sid(psid, &xid);
+}
+
+void gid_to_sid(struct dom_sid *psid, gid_t gid)
+{
+ struct unixid xid = { .type = ID_TYPE_GID, .id = gid};
+ xid_to_sid(psid, &xid);
+}
+
+bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
+ struct unixid *ids)
+{
+ struct wbcDomainSid *wbc_sids = NULL;
+ struct wbcUnixId *wbc_ids = NULL;
+ struct bitmap *found = NULL;
+ uint32_t i, num_not_cached;
+ uint32_t wbc_ids_size = 0;
+ wbcErr err;
+ bool ret = false;
+
+ wbc_sids = talloc_array(talloc_tos(), struct wbcDomainSid, num_sids);
+ if (wbc_sids == NULL) {
+ return false;
+ }
+ found = bitmap_talloc(wbc_sids, num_sids);
+ if (found == NULL) {
+ goto fail;
+ }
+
+ /*
+ * We go through the requested SID array three times.
+ * First time to look for global_sid_Unix_Users
+ * and global_sid_Unix_Groups SIDS, and to look
+ * for mappings cached in the idmap_cache.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
+ num_not_cached = 0;
+
+ for (i=0; i<num_sids; i++) {
+ bool expired;
+ uint32_t rid;
+
+ if (sid_peek_check_rid(&global_sid_Unix_Users,
+ &sids[i], &rid)) {
+ ids[i].type = ID_TYPE_UID;
+ ids[i].id = rid;
+ bitmap_set(found, i);
+ continue;
+ }
+ if (sid_peek_check_rid(&global_sid_Unix_Groups,
+ &sids[i], &rid)) {
+ ids[i].type = ID_TYPE_GID;
+ ids[i].id = rid;
+ bitmap_set(found, i);
+ continue;
+ }
+ if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired)
+ && !expired)
+ {
+ bitmap_set(found, i);
+ continue;
+ }
+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
+ memcpy(&wbc_sids[num_not_cached], &sids[i],
+ ndr_size_dom_sid(&sids[i], 0));
+ num_not_cached += 1;
+ }
+ if (num_not_cached == 0) {
+ goto done;
+ }
+
+ /*
+ * For the ones that we couldn't map in the loop above, query winbindd
+ * via wbcSidsToUnixIds().
+ */
+
+ wbc_ids_size = num_not_cached;
+ wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size);
+ if (wbc_ids == NULL) {
+ goto fail;
+ }
+ for (i=0; i<wbc_ids_size; i++) {
+ wbc_ids[i].type = WBC_ID_TYPE_NOT_SPECIFIED;
+ wbc_ids[i].id.gid = (uint32_t)-1;
+ }
+ err = wbcSidsToUnixIds(wbc_sids, wbc_ids_size, wbc_ids);
+ if (!WBC_ERROR_IS_OK(err)) {
+ DEBUG(10, ("wbcSidsToUnixIds returned %s\n",
+ wbcErrorString(err)));
+ }
+
+ /*
+ * Second time through the SID array, replace
+ * the ids[] entries that wbcSidsToUnixIds() was able to
+ * map.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
+ num_not_cached = 0;
+
+ for (i=0; i<num_sids; i++) {
+ if (bitmap_query(found, i)) {
+ continue;
+ }
+
+ SMB_ASSERT(num_not_cached < wbc_ids_size);
+
+ switch (wbc_ids[num_not_cached].type) {
+ case WBC_ID_TYPE_UID:
+ ids[i].type = ID_TYPE_UID;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_GID:
+ ids[i].type = ID_TYPE_GID;
+ ids[i].id = wbc_ids[num_not_cached].id.gid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_BOTH:
+ ids[i].type = ID_TYPE_BOTH;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_NOT_SPECIFIED:
+ /*
+ * wbcSidsToUnixIds() wasn't able to map this
+ * so we still need to check legacy_sid_to_XXX()
+ * below. Don't mark the bitmap entry
+ * as being found so the final loop knows
+ * to try and map this entry.
+ */
+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
+ ids[i].id = (uint32_t)-1;
+ break;
+ default:
+ /*
+ * A successful return from wbcSidsToUnixIds()
+ * cannot return anything other than the values
+ * checked for above. Ensure this is so.
+ */
+ smb_panic(__location__);
+ break;
+ }
+ num_not_cached += 1;
+ }
+
+ /*
+ * Third and final time through the SID array,
+ * try legacy_sid_to_gid()/legacy_sid_to_uid()
+ * for entries we haven't already been able to
+ * map.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
+ for (i=0; i<num_sids; i++) {
+ if (bitmap_query(found, i)) {
+ continue;
+ }
+ if (legacy_sid_to_gid(&sids[i], &ids[i].id)) {
+ ids[i].type = ID_TYPE_GID;
+ bitmap_set(found, i);
+ continue;
+ }
+ if (legacy_sid_to_uid(&sids[i], &ids[i].id)) {
+ ids[i].type = ID_TYPE_UID;
+ bitmap_set(found, i);
+ continue;
+ }
+ }
+done:
+ /*
+ * Pass through the return array for consistency.
+ * Any ids[].id mapped to (uint32_t)-1 must be returned
+ * as ID_TYPE_NOT_SPECIFIED.
+ */
+ for (i=0; i<num_sids; i++) {
+ switch(ids[i].type) {
+ case ID_TYPE_GID:
+ case ID_TYPE_UID:
+ case ID_TYPE_BOTH:
+ if (ids[i].id == (uint32_t)-1) {
+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
+ }
+ break;
+ case ID_TYPE_NOT_SPECIFIED:
+ break;
+ case ID_TYPE_WB_REQUIRE_TYPE:
+ /*
+ * these are internal between winbindd
+ * parent and child.
+ */
+ smb_panic(__location__);
+ break;
+ }
+ }
+
+ ret = true;
+fail:
+ TALLOC_FREE(wbc_ids);
+ TALLOC_FREE(wbc_sids);
+ return ret;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to uid function.
+*****************************************************************/
+
+bool sid_to_uid(const struct dom_sid *psid, uid_t *puid)
+{
+ bool expired = true;
+ bool ret;
+ uint32_t rid;
+ struct dom_sid_buf buf;
+
+ /* Optimize for the Unix Users Domain
+ * as the conversion is straightforward */
+ if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
+ uid_t uid = rid;
+ *puid = uid;
+
+ /* return here, don't cache */
+ DEBUG(10,("sid %s -> uid %u\n",
+ dom_sid_str_buf(psid, &buf),
+ (unsigned int)*puid ));
+ return true;
+ }
+
+ if (sid_check_is_in_unix_groups(psid)) {
+ DBG_DEBUG("SID %s is a group, failing\n",
+ dom_sid_str_buf(psid, &buf));
+ return false;
+ }
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_sid2uid(psid, puid, &expired);
+
+ if (ret && !expired && (*puid == (uid_t)-1)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ return legacy_sid_to_uid(psid, puid);
+ }
+
+ if (!ret || expired) {
+ /* Not in cache. Ask winbindd. */
+ if (!winbind_sid_to_uid(puid, psid)) {
+ DEBUG(5, ("winbind failed to find a uid for sid %s\n",
+ dom_sid_str_buf(psid, &buf)));
+ /* winbind failed. do legacy */
+ return legacy_sid_to_uid(psid, puid);
+ }
+ }
+
+ /* TODO: Here would be the place to allocate both a gid and a uid for
+ * the SID in question */
+
+ DEBUG(10,("sid %s -> uid %u\n",
+ dom_sid_str_buf(psid, &buf),
+ (unsigned int)*puid ));
+
+ return true;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to gid function.
+ Group mapping is used for gids that maps to Wellknown SIDs
+*****************************************************************/
+
+bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid)
+{
+ bool expired = true;
+ bool ret;
+ uint32_t rid;
+ struct dom_sid_buf buf;
+
+ /* Optimize for the Unix Groups Domain
+ * as the conversion is straightforward */
+ if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
+ gid_t gid = rid;
+ *pgid = gid;
+
+ /* return here, don't cache */
+ DEBUG(10,("sid %s -> gid %u\n",
+ dom_sid_str_buf(psid, &buf),
+ (unsigned int)*pgid ));
+ return true;
+ }
+
+ if (sid_check_is_in_unix_users(psid)) {
+ DBG_DEBUG("SID %s is a user, failing\n",
+ dom_sid_str_buf(psid, &buf));
+ return false;
+ }
+
+ /* Check the winbindd cache directly. */
+ ret = idmap_cache_find_sid2gid(psid, pgid, &expired);
+
+ if (ret && !expired && (*pgid == (gid_t)-1)) {
+ /*
+ * Negative cache entry, we already asked.
+ * do legacy.
+ */
+ return legacy_sid_to_gid(psid, pgid);
+ }
+
+ if (!ret || expired) {
+ /* Not in cache or negative. Ask winbindd. */
+ /* Ask winbindd if it can map this sid to a gid.
+ * (Idmap will check it is a valid SID and of the right type) */
+
+ if ( !winbind_sid_to_gid(pgid, psid) ) {
+
+ DEBUG(10,("winbind failed to find a gid for sid %s\n",
+ dom_sid_str_buf(psid, &buf)));
+ /* winbind failed. do legacy */
+ return legacy_sid_to_gid(psid, pgid);
+ }
+ }
+
+ DEBUG(10,("sid %s -> gid %u\n",
+ dom_sid_str_buf(psid, &buf),
+ (unsigned int)*pgid ));
+
+ return true;
+}
+
+/**
+ * @brief This function gets the primary group SID mapping the primary
+ * GID of the user as obtained by an actual getpwnam() call.
+ * This is necessary to avoid issues with arbitrary group SIDs
+ * stored in passdb. We try as hard as we can to get the SID
+ * corresponding to the GID, including trying group mapping.
+ * If nothing else works, we will force "Domain Users" as the
+ * primary group.
+ * This is needed because we must always be able to lookup the
+ * primary group SID, so we cannot settle for an arbitrary SID.
+ *
+ * This call can be expensive. Use with moderation.
+ * If you have a "samu" struct around use pdb_get_group_sid()
+ * instead as it does properly cache results.
+ *
+ * @param mem_ctx[in] The memory context iused to allocate the result.
+ * @param username[in] The user's name
+ * @param _pwd[in|out] If available, pass in user's passwd struct.
+ * It will contain a tallocated passwd if NULL was
+ * passed in.
+ * @param _group_sid[out] The user's Primary Group SID
+ *
+ * @return NTSTATUS error code.
+ */
+NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx,
+ const char *username,
+ struct passwd **_pwd,
+ struct dom_sid **_group_sid)
+{
+ TALLOC_CTX *tmp_ctx;
+ bool need_lookup_sid = false;
+ struct dom_sid *group_sid;
+ struct passwd *pwd = *_pwd;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pwd) {
+ pwd = Get_Pwnam_alloc(mem_ctx, username);
+ if (!pwd) {
+ DEBUG(0, ("Failed to find a Unix account for %s\n",
+ username));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ group_sid = talloc_zero(mem_ctx, struct dom_sid);
+ if (!group_sid) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gid_to_sid(group_sid, pwd->pw_gid);
+ if (!is_null_sid(group_sid)) {
+ struct dom_sid domain_sid;
+ uint32_t rid;
+
+ /* We need a sid within our domain */
+ sid_copy(&domain_sid, group_sid);
+ sid_split_rid(&domain_sid, &rid);
+ if (dom_sid_equal(&domain_sid, get_global_sam_sid())) {
+ /*
+ * As shortcut for the expensive lookup_sid call
+ * compare the domain sid part
+ */
+ switch (rid) {
+ case DOMAIN_RID_ADMINS:
+ case DOMAIN_RID_USERS:
+ goto done;
+ default:
+ need_lookup_sid = true;
+ break;
+ }
+ } else {
+ /* Try group mapping */
+ struct unixid id;
+
+ id.id = pwd->pw_gid;
+ id.type = ID_TYPE_GID;
+
+ ZERO_STRUCTP(group_sid);
+ if (pdb_id_to_sid(&id, group_sid)) {
+ need_lookup_sid = true;
+ }
+ }
+ }
+
+ /* We must verify that this is a valid SID that resolves to a
+ * group of the correct type */
+ if (need_lookup_sid) {
+ enum lsa_SidType type = SID_NAME_UNKNOWN;
+ bool lookup_ret;
+ struct dom_sid_buf buf;
+
+ DEBUG(10, ("do lookup_sid(%s) for group of user %s\n",
+ dom_sid_str_buf(group_sid, &buf),
+ username));
+
+ /* Now check that it's actually a domain group and
+ * not something else */
+ lookup_ret = lookup_sid(tmp_ctx, group_sid,
+ NULL, NULL, &type);
+
+ if (lookup_ret && (type == SID_NAME_DOM_GRP)) {
+ goto done;
+ }
+
+ DEBUG(3, ("Primary group %s for user %s is"
+ " a %s and not a domain group\n",
+ dom_sid_str_buf(group_sid, &buf),
+ username,
+ sid_type_lookup(type)));
+ }
+
+ /* Everything else, failed.
+ * Just set it to the 'Domain Users' RID of 513 which will
+ always resolve to a name */
+ DEBUG(3, ("Forcing Primary Group to 'Domain Users' for %s\n",
+ username));
+
+ sid_compose(group_sid, get_global_sam_sid(), DOMAIN_RID_USERS);
+
+done:
+ *_pwd = talloc_move(mem_ctx, &pwd);
+ *_group_sid = talloc_move(mem_ctx, &group_sid);
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/passdb/lookup_sid.h b/source3/passdb/lookup_sid.h
new file mode 100644
index 0000000..8a21cca
--- /dev/null
+++ b/source3/passdb/lookup_sid.h
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/CIFS implementation.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Gerald (Jerry) Carter 2003
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef _PASSDB_LOOKUP_SID_H_
+#define _PASSDB_LOOKUP_SID_H_
+
+#include "../librpc/gen_ndr/lsa.h"
+
+struct passwd;
+struct unixid;
+
+#define LOOKUP_NAME_NONE 0x00000000
+#define LOOKUP_NAME_ISOLATED 0x00000001 /* Look up unqualified names */
+#define LOOKUP_NAME_REMOTE 0x00000002 /* Ask others */
+#define LOOKUP_NAME_GROUP 0x00000004 /* This is a NASTY hack for
+ valid users = @foo where foo also
+ exists in as user. */
+#define LOOKUP_NAME_NO_NSS 0x00000008 /* no NSS calls to avoid
+ winbind recursions */
+#define LOOKUP_NAME_BUILTIN 0x00000010 /* builtin names */
+#define LOOKUP_NAME_WKN 0x00000020 /* well known names */
+#define LOOKUP_NAME_DOMAIN 0x00000040 /* only lookup own domain */
+#define LOOKUP_NAME_LOCAL (LOOKUP_NAME_ISOLATED\
+ |LOOKUP_NAME_BUILTIN\
+ |LOOKUP_NAME_WKN\
+ |LOOKUP_NAME_DOMAIN)
+#define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED\
+ |LOOKUP_NAME_REMOTE\
+ |LOOKUP_NAME_BUILTIN\
+ |LOOKUP_NAME_WKN\
+ |LOOKUP_NAME_DOMAIN)
+
+struct lsa_dom_info {
+ bool valid;
+ struct dom_sid sid;
+ const char *name;
+ int num_idxs;
+ int *idxs;
+};
+
+struct lsa_name_info {
+ uint32_t rid;
+ enum lsa_SidType type;
+ const char *name;
+ int dom_idx;
+};
+
+/* The following definitions come from passdb/lookup_sid.c */
+
+bool lookup_name(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ struct dom_sid *ret_sid, enum lsa_SidType *ret_type);
+bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
+ const char *full_name, int flags,
+ const char **ret_domain, const char **ret_name,
+ struct dom_sid *ret_sid, enum lsa_SidType *ret_type);
+NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
+ const struct dom_sid **sids, int level,
+ struct lsa_dom_info **ret_domains,
+ struct lsa_name_info **ret_names);
+bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const char **ret_domain, const char **ret_name,
+ enum lsa_SidType *ret_type);
+void uid_to_sid(struct dom_sid *psid, uid_t uid);
+void gid_to_sid(struct dom_sid *psid, gid_t gid);
+void xid_to_sid(struct dom_sid *psid, const struct unixid *xid);
+bool sid_to_uid(const struct dom_sid *psid, uid_t *puid);
+bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid);
+bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
+ struct unixid *ids);
+NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx,
+ const char *username,
+ struct passwd **_pwd,
+ struct dom_sid **_group_sid);
+
+#endif /* _PASSDB_LOOKUP_SID_H_ */
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
new file mode 100644
index 0000000..c97b35e
--- /dev/null
+++ b/source3/passdb/machine_account_secrets.c
@@ -0,0 +1,2080 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+#include "passdb.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "secrets.h"
+#include "dbwrap/dbwrap.h"
+#include "../librpc/ndr/libndr.h"
+#include "util_tdb.h"
+#include "libcli/security/security.h"
+
+#include "librpc/gen_ndr/libnet_join.h"
+#include "librpc/gen_ndr/ndr_secrets.h"
+#include "lib/crypto/crypto.h"
+#include "lib/krb5_wrap/krb5_samba.h"
+#include "lib/util/time_basic.h"
+#include "../libds/common/flags.h"
+#include "lib/util/string_wrappers.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+static char *domain_info_keystr(const char *domain);
+
+static char *des_salt_key(const char *realm);
+
+/**
+ * Form a key for fetching the domain sid
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *domain_sid_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_DOMAIN_SID, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+static const char *domain_guid_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_DOMAIN_GUID, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+static const char *protect_ids_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_PROTECT_IDS, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/* N O T E: never use this outside of passdb modules that store the SID on their own */
+bool secrets_mark_domain_protected(const char *domain)
+{
+ bool ret;
+
+ ret = secrets_store(protect_ids_keystr(domain), "TRUE", 5);
+ if (!ret) {
+ DEBUG(0, ("Failed to protect the Domain IDs\n"));
+ }
+ return ret;
+}
+
+bool secrets_clear_domain_protection(const char *domain)
+{
+ bool ret;
+ void *protection = secrets_fetch(protect_ids_keystr(domain), NULL);
+
+ if (protection) {
+ SAFE_FREE(protection);
+ ret = secrets_delete_entry(protect_ids_keystr(domain));
+ if (!ret) {
+ DEBUG(0, ("Failed to remove Domain IDs protection\n"));
+ }
+ return ret;
+ }
+ return true;
+}
+
+bool secrets_store_domain_sid(const char *domain, const struct dom_sid *sid)
+{
+ char *protect_ids;
+ bool ret;
+ struct dom_sid clean_sid = { 0 };
+
+ protect_ids = secrets_fetch(protect_ids_keystr(domain), NULL);
+ if (protect_ids) {
+ if (strncmp(protect_ids, "TRUE", 4)) {
+ DEBUG(0, ("Refusing to store a Domain SID, "
+ "it has been marked as protected!\n"));
+ SAFE_FREE(protect_ids);
+ return false;
+ }
+ }
+ SAFE_FREE(protect_ids);
+
+ /*
+ * use a copy to prevent uninitialized memory from being carried over
+ * to the tdb
+ */
+ sid_copy(&clean_sid, sid);
+
+ ret = secrets_store(domain_sid_keystr(domain),
+ &clean_sid,
+ sizeof(struct dom_sid));
+
+ /* Force a re-query */
+ if (ret) {
+ /*
+ * Do not call get_global_domain_sid() here, or we will call it
+ * recursively.
+ */
+ reset_global_sam_sid();
+ }
+ return ret;
+}
+
+bool secrets_fetch_domain_sid(const char *domain, struct dom_sid *sid)
+{
+ struct dom_sid *dyn_sid;
+ size_t size = 0;
+
+ dyn_sid = (struct dom_sid *)secrets_fetch(domain_sid_keystr(domain), &size);
+
+ if (dyn_sid == NULL)
+ return False;
+
+ if (size != sizeof(struct dom_sid)) {
+ SAFE_FREE(dyn_sid);
+ return False;
+ }
+
+ *sid = *dyn_sid;
+ SAFE_FREE(dyn_sid);
+ return True;
+}
+
+bool secrets_store_domain_guid(const char *domain, const struct GUID *guid)
+{
+ char *protect_ids;
+ const char *key;
+
+ protect_ids = secrets_fetch(protect_ids_keystr(domain), NULL);
+ if (protect_ids) {
+ if (strncmp(protect_ids, "TRUE", 4)) {
+ DEBUG(0, ("Refusing to store a Domain SID, "
+ "it has been marked as protected!\n"));
+ SAFE_FREE(protect_ids);
+ return false;
+ }
+ }
+ SAFE_FREE(protect_ids);
+
+ key = domain_guid_keystr(domain);
+ return secrets_store(key, guid, sizeof(struct GUID));
+}
+
+bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
+{
+ struct GUID *dyn_guid;
+ const char *key;
+ size_t size = 0;
+ struct GUID new_guid;
+
+ key = domain_guid_keystr(domain);
+ dyn_guid = (struct GUID *)secrets_fetch(key, &size);
+
+ if (!dyn_guid) {
+ if (lp_server_role() == ROLE_DOMAIN_PDC ||
+ lp_server_role() == ROLE_IPA_DC) {
+ new_guid = GUID_random();
+ if (!secrets_store_domain_guid(domain, &new_guid))
+ return False;
+ dyn_guid = (struct GUID *)secrets_fetch(key, &size);
+ }
+ if (dyn_guid == NULL) {
+ return False;
+ }
+ }
+
+ if (size != sizeof(struct GUID)) {
+ DEBUG(1,("UUID size %d is wrong!\n", (int)size));
+ SAFE_FREE(dyn_guid);
+ return False;
+ }
+
+ *guid = *dyn_guid;
+ SAFE_FREE(dyn_guid);
+ return True;
+}
+
+/**
+ * Form a key for fetching the machine trust account sec channel type
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_sec_channel_type_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_SEC_CHANNEL_TYPE,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching the machine trust account last change time
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_last_change_time_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_LAST_CHANGE_TIME,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+
+/**
+ * Form a key for fetching the machine previous trust account password
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_prev_password_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_PASSWORD_PREV, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching the machine trust account password
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_password_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_PASSWORD, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
+ * Form a key for fetching the machine trust account password
+ *
+ * @param domain domain name
+ *
+ * @return stored password's key
+ **/
+static const char *trust_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_ACCT_PASS, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get the default secure channel type for trust accounts
+************************************************************************/
+
+enum netr_SchannelType get_default_sec_channel(void)
+{
+ if (IS_DC) {
+ return SEC_CHAN_BDC;
+ } else {
+ return SEC_CHAN_WKSTA;
+ }
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+ This only tries to get the legacy hashed version of the password.
+ The user of this function must have locked the trust password file using
+ the above secrets_lock_trust_account_password().
+************************************************************************/
+
+bool secrets_fetch_trust_account_password_legacy(const char *domain,
+ uint8_t ret_pwd[16],
+ time_t *pass_last_set_time,
+ enum netr_SchannelType *channel)
+{
+ struct machine_acct_pass *pass;
+ size_t size = 0;
+
+ if (!(pass = (struct machine_acct_pass *)secrets_fetch(
+ trust_keystr(domain), &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ if (size != sizeof(*pass)) {
+ DEBUG(0, ("secrets were of incorrect size!\n"));
+ BURN_FREE(pass, size);
+ return False;
+ }
+
+ if (pass_last_set_time) {
+ *pass_last_set_time = pass->mod_time;
+ }
+ memcpy(ret_pwd, pass->hash, 16);
+
+ if (channel) {
+ *channel = get_default_sec_channel();
+ }
+
+ BURN_FREE(pass, size);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete all information related to the domain joined machine.
+************************************************************************/
+
+bool secrets_delete_machine_password_ex(const char *domain, const char *realm)
+{
+ const char *tmpkey = NULL;
+ bool ok;
+
+ tmpkey = domain_info_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ if (realm != NULL) {
+ tmpkey = des_salt_key(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ tmpkey = domain_guid_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ tmpkey = machine_prev_password_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ tmpkey = machine_password_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ tmpkey = machine_sec_channel_type_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ tmpkey = machine_last_change_time_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ tmpkey = domain_sid_keystr(domain);
+ ok = secrets_delete(tmpkey);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+/************************************************************************
+ Routine to delete the domain sid
+************************************************************************/
+
+bool secrets_delete_domain_sid(const char *domain)
+{
+ return secrets_delete_entry(domain_sid_keystr(domain));
+}
+
+/************************************************************************
+ Set the machine trust account password, the old pw and last change
+ time, domain SID and salting principals based on values passed in
+ (added to support the secrets_tdb_sync module on secrets.ldb)
+************************************************************************/
+
+bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const char *domain,
+ const char *realm,
+ const char *salting_principal, uint32_t supported_enc_types,
+ const struct dom_sid *domain_sid, uint32_t last_change_time,
+ uint32_t secure_channel_type,
+ bool delete_join)
+{
+ bool ret;
+ uint8_t last_change_time_store[4];
+ TALLOC_CTX *frame = talloc_stackframe();
+ uint8_t sec_channel_bytes[4];
+
+ if (delete_join) {
+ secrets_delete_machine_password_ex(domain, realm);
+ TALLOC_FREE(frame);
+ return true;
+ }
+
+ ret = secrets_store(machine_password_keystr(domain), pass, strlen(pass)+1);
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ if (oldpass) {
+ ret = secrets_store(machine_prev_password_keystr(domain), oldpass, strlen(oldpass)+1);
+ } else {
+ ret = secrets_delete(machine_prev_password_keystr(domain));
+ }
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ if (secure_channel_type == 0) {
+ /* We delete this and instead have the read code fall back to
+ * a default based on server role, as our caller can't specify
+ * this with any more certainty */
+ ret = secrets_delete(machine_sec_channel_type_keystr(domain));
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+ } else {
+ SIVAL(&sec_channel_bytes, 0, secure_channel_type);
+ ret = secrets_store(machine_sec_channel_type_keystr(domain),
+ &sec_channel_bytes, sizeof(sec_channel_bytes));
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+ }
+
+ SIVAL(&last_change_time_store, 0, last_change_time);
+ ret = secrets_store(machine_last_change_time_keystr(domain),
+ &last_change_time_store, sizeof(last_change_time));
+
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ ret = secrets_store_domain_sid(domain, domain_sid);
+
+ if (!ret) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ if (realm != NULL) {
+ char *key = des_salt_key(realm);
+
+ if (salting_principal != NULL) {
+ ret = secrets_store(key,
+ salting_principal,
+ strlen(salting_principal)+1);
+ } else {
+ ret = secrets_delete(key);
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/************************************************************************
+ Return the standard DES salt key
+************************************************************************/
+
+char* kerberos_standard_des_salt( void )
+{
+ fstring salt;
+
+ fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
+ (void)strlower_m( salt );
+ fstrcat( salt, lp_realm() );
+
+ return SMB_STRDUP( salt );
+}
+
+/************************************************************************
+************************************************************************/
+
+static char *des_salt_key(const char *realm)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/DES/%s",
+ SECRETS_SALTING_PRINCIPAL,
+ realm);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/************************************************************************
+************************************************************************/
+
+bool kerberos_secrets_store_des_salt( const char* salt )
+{
+ char* key;
+ bool ret;
+
+ key = des_salt_key(lp_realm());
+ if (key == NULL) {
+ DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
+ return False;
+ }
+
+ if ( !salt ) {
+ DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
+ secrets_delete_entry( key );
+ return True;
+ }
+
+ DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
+
+ ret = secrets_store( key, salt, strlen(salt)+1 );
+
+ TALLOC_FREE(key);
+
+ return ret;
+}
+
+/************************************************************************
+************************************************************************/
+
+static
+char* kerberos_secrets_fetch_des_salt( void )
+{
+ char *salt, *key;
+
+ key = des_salt_key(lp_realm());
+ if (key == NULL) {
+ DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
+ return NULL;
+ }
+
+ salt = (char*)secrets_fetch( key, NULL );
+
+ TALLOC_FREE(key);
+
+ return salt;
+}
+
+/************************************************************************
+ Routine to get the salting principal for this service.
+ Caller must free if return is not null.
+ ************************************************************************/
+
+char *kerberos_secrets_fetch_salt_princ(void)
+{
+ char *salt_princ_s;
+ /* lookup new key first */
+
+ salt_princ_s = kerberos_secrets_fetch_des_salt();
+ if (salt_princ_s == NULL) {
+ /* fall back to host/machine.realm@REALM */
+ salt_princ_s = kerberos_standard_des_salt();
+ }
+
+ return salt_princ_s;
+}
+
+/************************************************************************
+ Routine to fetch the previous plaintext machine account password for a realm
+ the password is assumed to be a null terminated ascii string.
+************************************************************************/
+
+char *secrets_fetch_prev_machine_password(const char *domain)
+{
+ return (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
+}
+
+/************************************************************************
+ Routine to fetch the last change time of the machine account password
+ for a realm
+************************************************************************/
+
+time_t secrets_fetch_pass_last_set_time(const char *domain)
+{
+ uint32_t *last_set_time;
+ time_t pass_last_set_time;
+
+ last_set_time = secrets_fetch(machine_last_change_time_keystr(domain),
+ NULL);
+ if (last_set_time) {
+ pass_last_set_time = IVAL(last_set_time,0);
+ SAFE_FREE(last_set_time);
+ } else {
+ pass_last_set_time = 0;
+ }
+
+ return pass_last_set_time;
+}
+
+/************************************************************************
+ Routine to fetch the plaintext machine account password for a realm
+ 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,
+ enum netr_SchannelType *channel)
+{
+ char *ret;
+ ret = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
+
+ if (pass_last_set_time) {
+ *pass_last_set_time = secrets_fetch_pass_last_set_time(domain);
+ }
+
+ if (channel) {
+ size_t size;
+ uint32_t *channel_type;
+ channel_type = (unsigned int *)secrets_fetch(machine_sec_channel_type_keystr(domain), &size);
+ if (channel_type) {
+ *channel = IVAL(channel_type,0);
+ SAFE_FREE(channel_type);
+ } else {
+ *channel = get_default_sec_channel();
+ }
+ }
+
+ return ret;
+}
+
+static int password_nt_hash_destructor(struct secrets_domain_info1_password *pw)
+{
+ ZERO_STRUCT(pw->nt_hash);
+
+ return 0;
+}
+
+static int setup_password_zeroing(struct secrets_domain_info1_password *pw)
+{
+ if (pw != NULL) {
+ size_t i;
+
+ talloc_keep_secret(pw->cleartext_blob.data);
+ talloc_set_destructor(pw, password_nt_hash_destructor);
+ for (i = 0; i < pw->num_keys; i++) {
+ talloc_keep_secret(pw->keys[i].value.data);
+ }
+ }
+
+ return 0;
+}
+
+static char *domain_info_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_DOMAIN_INFO,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get account password to trusted domain
+************************************************************************/
+
+static NTSTATUS secrets_fetch_domain_info1_by_key(const char *key,
+ TALLOC_CTX *mem_ctx,
+ struct secrets_domain_info1 **_info1)
+{
+ struct secrets_domain_infoB sdib = { .version = 0, };
+ enum ndr_err_code ndr_err;
+ /* unpacking structures */
+ DATA_BLOB blob;
+
+ /* fetching trusted domain password structure */
+ blob.data = (uint8_t *)secrets_fetch(key, &blob.length);
+ if (blob.data == NULL) {
+ DBG_NOTICE("secrets_fetch failed!\n");
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* unpack trusted domain password */
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &sdib,
+ (ndr_pull_flags_fn_t)ndr_pull_secrets_domain_infoB);
+ BURN_FREE(blob.data, blob.length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_pull_struct_blob failed - %s!\n",
+ ndr_errstr(ndr_err));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (sdib.info.info1->next_change != NULL) {
+ setup_password_zeroing(sdib.info.info1->next_change->password);
+ }
+ setup_password_zeroing(sdib.info.info1->password);
+ setup_password_zeroing(sdib.info.info1->old_password);
+ setup_password_zeroing(sdib.info.info1->older_password);
+
+ if (sdib.version != SECRETS_DOMAIN_INFO_VERSION_1) {
+ DBG_ERR("sdib.version = %u\n", (unsigned)sdib.version);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ *_info1 = sdib.info.info1;
+ return NT_STATUS_OK;;
+}
+
+static NTSTATUS secrets_fetch_domain_info(const char *domain,
+ TALLOC_CTX *mem_ctx,
+ struct secrets_domain_info1 **pinfo)
+{
+ char *key = domain_info_keystr(domain);
+ return secrets_fetch_domain_info1_by_key(key, mem_ctx, pinfo);
+}
+
+void secrets_debug_domain_info(int lvl, const struct secrets_domain_info1 *info1,
+ const char *name)
+{
+ struct secrets_domain_infoB sdib = {
+ .version = SECRETS_DOMAIN_INFO_VERSION_1,
+ };
+
+ sdib.info.info1 = discard_const_p(struct secrets_domain_info1, info1);
+
+ NDR_PRINT_DEBUG_LEVEL(lvl, secrets_domain_infoB, &sdib);
+}
+
+char *secrets_domain_info_string(TALLOC_CTX *mem_ctx, const struct secrets_domain_info1 *info1,
+ const char *name, bool include_secrets)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct secrets_domain_infoB sdib = {
+ .version = SECRETS_DOMAIN_INFO_VERSION_1,
+ };
+ struct ndr_print *ndr = NULL;
+ char *ret = NULL;
+
+ sdib.info.info1 = discard_const_p(struct secrets_domain_info1, info1);
+
+ ndr = talloc_zero(frame, struct ndr_print);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (ndr->private_data == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->print_secrets = include_secrets;
+
+ ndr_print_secrets_domain_infoB(ndr, name, &sdib);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static NTSTATUS secrets_store_domain_info1_by_key(const char *key,
+ const struct secrets_domain_info1 *info1)
+{
+ struct secrets_domain_infoB sdib = {
+ .version = SECRETS_DOMAIN_INFO_VERSION_1,
+ };
+ /* packing structures */
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ bool ok;
+
+ sdib.info.info1 = discard_const_p(struct secrets_domain_info1, info1);
+
+ ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &sdib,
+ (ndr_push_flags_fn_t)ndr_push_secrets_domain_infoB);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ok = secrets_store(key, blob.data, blob.length);
+ data_blob_clear_free(&blob);
+ if (!ok) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS secrets_store_domain_info(const struct secrets_domain_info1 *info,
+ bool upgrade)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *domain = info->domain_info.name.string;
+ const char *realm = info->domain_info.dns_domain.string;
+ char *key = domain_info_keystr(domain);
+ struct db_context *db = NULL;
+ struct timeval last_change_tv;
+ const DATA_BLOB *cleartext_blob = NULL;
+ DATA_BLOB pw_blob = data_blob_null;
+ DATA_BLOB old_pw_blob = data_blob_null;
+ const char *pw = NULL;
+ const char *old_pw = NULL;
+ bool ok;
+ NTSTATUS status;
+ int ret;
+ int role = lp_server_role();
+
+ switch (info->secure_channel_type) {
+ case SEC_CHAN_WKSTA:
+ case SEC_CHAN_BDC:
+ if (!upgrade && role >= ROLE_ACTIVE_DIRECTORY_DC) {
+ DBG_ERR("AD_DC not supported for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ break;
+ default:
+ DBG_ERR("SEC_CHAN_* not supported for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ ok = secrets_clear_domain_protection(domain);
+ if (!ok) {
+ DBG_ERR("secrets_clear_domain_protection(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ ok = secrets_delete_machine_password_ex(domain, realm);
+ if (!ok) {
+ DBG_ERR("secrets_delete_machine_password_ex(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ status = secrets_store_domain_info1_by_key(key, info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info1_by_key() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * We use info->password_last_change instead
+ * of info->password.change_time because
+ * we may want to defer the next change approach
+ * if the server rejected the change the last time,
+ * e.g. due to RefusePasswordChange=1.
+ */
+ nttime_to_timeval(&last_change_tv, info->password_last_change);
+
+ cleartext_blob = &info->password->cleartext_blob;
+ ok = convert_string_talloc(frame, CH_UTF16MUNGED, CH_UNIX,
+ cleartext_blob->data,
+ cleartext_blob->length,
+ (void **)&pw_blob.data,
+ &pw_blob.length);
+ if (!ok) {
+ status = NT_STATUS_UNMAPPABLE_CHARACTER;
+ if (errno == ENOMEM) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
+ "failed for pw of %s - %s\n",
+ domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+ pw = (const char *)pw_blob.data;
+ if (info->old_password != NULL) {
+ cleartext_blob = &info->old_password->cleartext_blob;
+ ok = convert_string_talloc(frame, CH_UTF16MUNGED, CH_UNIX,
+ cleartext_blob->data,
+ cleartext_blob->length,
+ (void **)&old_pw_blob.data,
+ &old_pw_blob.length);
+ if (!ok) {
+ status = NT_STATUS_UNMAPPABLE_CHARACTER;
+ if (errno == ENOMEM) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
+ "failed for old_pw of %s - %s\n",
+ domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ data_blob_clear_free(&pw_blob);
+ TALLOC_FREE(frame);
+ return status;
+ }
+ old_pw = (const char *)old_pw_blob.data;
+ }
+
+ ok = secrets_store_machine_pw_sync(pw, old_pw,
+ domain, realm,
+ info->salt_principal,
+ info->supported_enc_types,
+ info->domain_info.sid,
+ last_change_tv.tv_sec,
+ info->secure_channel_type,
+ false); /* delete_join */
+ data_blob_clear_free(&pw_blob);
+ data_blob_clear_free(&old_pw_blob);
+ if (!ok) {
+ DBG_ERR("secrets_store_machine_pw_sync(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ if (!GUID_all_zero(&info->domain_info.domain_guid)) {
+ ok = secrets_store_domain_guid(domain,
+ &info->domain_info.domain_guid);
+ if (!ok) {
+ DBG_ERR("secrets_store_domain_guid(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ }
+
+ ok = secrets_mark_domain_protected(domain);
+ if (!ok) {
+ DBG_ERR("secrets_mark_domain_protected(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_password *p,
+ const char *salt_principal)
+{
+#ifdef HAVE_ADS
+ krb5_error_code krb5_ret;
+ krb5_context krb5_ctx = NULL;
+ DATA_BLOB cleartext_utf8_b = data_blob_null;
+ krb5_data cleartext_utf8;
+ krb5_data salt;
+ krb5_keyblock key;
+ DATA_BLOB aes_256_b = data_blob_null;
+ DATA_BLOB aes_128_b = data_blob_null;
+ bool ok;
+#endif /* HAVE_ADS */
+ DATA_BLOB arc4_b = data_blob_null;
+ const uint16_t max_keys = 4;
+ struct secrets_domain_info1_kerberos_key *keys = NULL;
+ uint16_t idx = 0;
+ char *salt_data = NULL;
+
+ /*
+ * We calculate:
+ * ENCTYPE_AES256_CTS_HMAC_SHA1_96
+ * ENCTYPE_AES128_CTS_HMAC_SHA1_96
+ * ENCTYPE_ARCFOUR_HMAC
+ * ENCTYPE_DES_CBC_MD5
+ *
+ * We don't include ENCTYPE_DES_CBC_CRC
+ * as W2008R2 also doesn't store it anymore.
+ *
+ * Note we store all enctypes we support,
+ * including the weak encryption types,
+ * but that's no problem as we also
+ * store the cleartext password anyway.
+ *
+ * Which values are then used to construct
+ * a keytab is configured at runtime and the
+ * configuration of msDS-SupportedEncryptionTypes.
+ *
+ * If we don't have kerberos support or no
+ * salt, we only generate an entry for arcfour-hmac-md5.
+ */
+ keys = talloc_zero_array(p,
+ struct secrets_domain_info1_kerberos_key,
+ max_keys);
+ if (keys == NULL) {
+ return ENOMEM;
+ }
+
+ arc4_b = data_blob_talloc(keys,
+ p->nt_hash.hash,
+ sizeof(p->nt_hash.hash));
+ if (arc4_b.data == NULL) {
+ DBG_ERR("data_blob_talloc failed for arcfour-hmac-md5.\n");
+ TALLOC_FREE(keys);
+ return ENOMEM;
+ }
+ talloc_keep_secret(arc4_b.data);
+
+#ifdef HAVE_ADS
+ if (salt_principal == NULL) {
+ goto no_kerberos;
+ }
+
+ krb5_ret = smb_krb5_init_context_common(&krb5_ctx);
+ if (krb5_ret != 0) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(krb5_ret));
+ TALLOC_FREE(keys);
+ return krb5_ret;
+ }
+
+ krb5_ret = smb_krb5_salt_principal2data(krb5_ctx, salt_principal,
+ p, &salt_data);
+ if (krb5_ret != 0) {
+ DBG_ERR("smb_krb5_salt_principal2data(%s) failed: %s\n",
+ salt_principal,
+ smb_get_krb5_error_message(krb5_ctx, krb5_ret, keys));
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ return krb5_ret;
+ }
+
+ salt = (krb5_data) {
+ .data = discard_const(salt_data),
+ .length = strlen(salt_data),
+ };
+
+ ok = convert_string_talloc(keys, CH_UTF16MUNGED, CH_UTF8,
+ p->cleartext_blob.data,
+ p->cleartext_blob.length,
+ (void **)&cleartext_utf8_b.data,
+ &cleartext_utf8_b.length);
+ if (!ok) {
+ if (errno != 0) {
+ krb5_ret = errno;
+ } else {
+ krb5_ret = EINVAL;
+ }
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ return krb5_ret;
+ }
+ talloc_keep_secret(cleartext_utf8_b.data);
+ cleartext_utf8.data = (void *)cleartext_utf8_b.data;
+ cleartext_utf8.length = cleartext_utf8_b.length;
+
+ krb5_ret = smb_krb5_create_key_from_string(krb5_ctx,
+ NULL,
+ &salt,
+ &cleartext_utf8,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ &key);
+ if (krb5_ret != 0) {
+ DBG_ERR("generation of a aes256-cts-hmac-sha1-96 key failed: %s\n",
+ smb_get_krb5_error_message(krb5_ctx, krb5_ret, keys));
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ TALLOC_FREE(salt_data);
+ return krb5_ret;
+ }
+ aes_256_b = data_blob_talloc(keys,
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
+ krb5_free_keyblock_contents(krb5_ctx, &key);
+ if (aes_256_b.data == NULL) {
+ DBG_ERR("data_blob_talloc failed for aes-256.\n");
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ TALLOC_FREE(salt_data);
+ return ENOMEM;
+ }
+ talloc_keep_secret(aes_256_b.data);
+
+ krb5_ret = smb_krb5_create_key_from_string(krb5_ctx,
+ NULL,
+ &salt,
+ &cleartext_utf8,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ &key);
+ if (krb5_ret != 0) {
+ DBG_ERR("generation of a aes128-cts-hmac-sha1-96 key failed: %s\n",
+ smb_get_krb5_error_message(krb5_ctx, krb5_ret, keys));
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ TALLOC_FREE(salt_data);
+ return krb5_ret;
+ }
+ aes_128_b = data_blob_talloc(keys,
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
+ krb5_free_keyblock_contents(krb5_ctx, &key);
+ if (aes_128_b.data == NULL) {
+ DBG_ERR("data_blob_talloc failed for aes-128.\n");
+ krb5_free_context(krb5_ctx);
+ TALLOC_FREE(keys);
+ TALLOC_FREE(salt_data);
+ return ENOMEM;
+ }
+ talloc_keep_secret(aes_128_b.data);
+
+ krb5_free_context(krb5_ctx);
+no_kerberos:
+
+ if (aes_256_b.length != 0) {
+ keys[idx].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ keys[idx].iteration_count = 4096;
+ keys[idx].value = aes_256_b;
+ idx += 1;
+ }
+
+ if (aes_128_b.length != 0) {
+ keys[idx].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ keys[idx].iteration_count = 4096;
+ keys[idx].value = aes_128_b;
+ idx += 1;
+ }
+
+#endif /* HAVE_ADS */
+
+ keys[idx].keytype = ENCTYPE_ARCFOUR_HMAC;
+ keys[idx].iteration_count = 4096;
+ keys[idx].value = arc4_b;
+ idx += 1;
+
+ p->salt_data = salt_data;
+ p->default_iteration_count = 4096;
+ p->num_keys = idx;
+ p->keys = keys;
+ return 0;
+}
+
+static NTSTATUS secrets_domain_info_password_create(TALLOC_CTX *mem_ctx,
+ const char *cleartext_unix,
+ const char *salt_principal,
+ NTTIME change_time,
+ const char *change_server,
+ struct secrets_domain_info1_password **_p)
+{
+ struct secrets_domain_info1_password *p = NULL;
+ bool ok;
+ size_t len;
+ int ret;
+
+ if (change_server == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ p = talloc_zero(mem_ctx, struct secrets_domain_info1_password);
+ if (p == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p->change_time = change_time;
+ p->change_server = talloc_strdup(p, change_server);
+ if (p->change_server == NULL) {
+ TALLOC_FREE(p);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = strlen(cleartext_unix);
+ ok = convert_string_talloc(p, CH_UNIX, CH_UTF16,
+ cleartext_unix, len,
+ (void **)&p->cleartext_blob.data,
+ &p->cleartext_blob.length);
+ if (!ok) {
+ NTSTATUS status = NT_STATUS_UNMAPPABLE_CHARACTER;
+ if (errno == ENOMEM) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(p);
+ return status;
+ }
+ talloc_keep_secret(p->cleartext_blob.data);
+ mdfour(p->nt_hash.hash,
+ p->cleartext_blob.data,
+ p->cleartext_blob.length);
+
+ talloc_set_destructor(p, password_nt_hash_destructor);
+ ret = secrets_domain_info_kerberos_keys(p, salt_principal);
+ if (ret != 0) {
+ NTSTATUS status = krb5_to_nt_status(ret);
+ TALLOC_FREE(p);
+ return status;
+ }
+
+ *_p = p;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
+ TALLOC_CTX *mem_ctx,
+ struct secrets_domain_info1 **pinfo)
+{
+ TALLOC_CTX *frame = NULL;
+ struct secrets_domain_info1 *old = NULL;
+ struct secrets_domain_info1 *info = NULL;
+ const char *dns_domain = NULL;
+ const char *server = NULL;
+ struct db_context *db = NULL;
+ time_t last_set_time;
+ NTTIME last_set_nt;
+ enum netr_SchannelType channel;
+ char *pw = NULL;
+ char *old_pw = NULL;
+ struct dom_sid domain_sid;
+ struct GUID domain_guid;
+ bool ok;
+ NTSTATUS status;
+ int ret;
+
+ ok = strequal(domain, lp_workgroup());
+ if (ok) {
+ dns_domain = lp_dnsdomain();
+
+ if (dns_domain != NULL && dns_domain[0] == '\0') {
+ dns_domain = NULL;
+ }
+ }
+
+ last_set_time = secrets_fetch_pass_last_set_time(domain);
+ if (last_set_time == 0) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ unix_to_nt_time(&last_set_nt, last_set_time);
+
+ frame = talloc_stackframe();
+
+ status = secrets_fetch_domain_info(domain, frame, &old);
+ if (NT_STATUS_IS_OK(status)) {
+ if (old->password_last_change >= last_set_nt) {
+ *pinfo = talloc_move(mem_ctx, &old);
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+ TALLOC_FREE(old);
+ }
+
+ info = talloc_zero(frame, struct secrets_domain_info1);
+ if (info == NULL) {
+ DBG_ERR("talloc_zero failed\n");
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ pw = secrets_fetch_machine_password(domain,
+ &last_set_time,
+ &channel);
+ if (pw == NULL) {
+ DBG_ERR("secrets_fetch_machine_password(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ unix_to_nt_time(&last_set_nt, last_set_time);
+
+ old_pw = secrets_fetch_prev_machine_password(domain);
+
+ ok = secrets_fetch_domain_sid(domain, &domain_sid);
+ if (!ok) {
+ DBG_ERR("secrets_fetch_domain_sid(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(old_pw);
+ BURN_FREE_STR(pw);
+ TALLOC_FREE(frame);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ ok = secrets_fetch_domain_guid(domain, &domain_guid);
+ if (!ok) {
+ domain_guid = GUID_zero();
+ }
+
+ info->computer_name = lp_netbios_name();
+ info->account_name = talloc_asprintf(frame, "%s$", info->computer_name);
+ if (info->account_name == NULL) {
+ DBG_ERR("talloc_asprintf(%s$) failed\n", info->computer_name);
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(old_pw);
+ BURN_FREE_STR(pw);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ info->secure_channel_type = channel;
+
+ info->domain_info.name.string = domain;
+ info->domain_info.dns_domain.string = dns_domain;
+ info->domain_info.dns_forest.string = dns_domain;
+ info->domain_info.domain_guid = domain_guid;
+ info->domain_info.sid = &domain_sid;
+
+ info->trust_flags = NETR_TRUST_FLAG_PRIMARY;
+ info->trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+
+ if (dns_domain != NULL) {
+ /*
+ * We just assume all AD domains are
+ * NETR_TRUST_FLAG_NATIVE these days.
+ *
+ * This isn't used anyway for now.
+ */
+ info->trust_flags |= NETR_TRUST_FLAG_NATIVE;
+
+ info->trust_type = LSA_TRUST_TYPE_UPLEVEL;
+
+ server = info->domain_info.dns_domain.string;
+ } else {
+ info->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+
+ server = talloc_asprintf(info,
+ "%s#%02X",
+ domain,
+ NBT_NAME_PDC);
+ if (server == NULL) {
+ DBG_ERR("talloc_asprintf(%s#%02X) failed\n",
+ domain, NBT_NAME_PDC);
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(pw);
+ BURN_FREE_STR(old_pw);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ info->trust_attributes = LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL;
+
+ info->join_time = 0;
+
+ /*
+ * We don't have enough information about the configured
+ * enctypes.
+ */
+ info->supported_enc_types = 0;
+ info->salt_principal = NULL;
+ if (info->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+ char *p = NULL;
+
+ p = kerberos_secrets_fetch_salt_princ();
+ if (p == NULL) {
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(old_pw);
+ BURN_FREE_STR(pw);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ info->salt_principal = talloc_strdup(info, p);
+ SAFE_FREE(p);
+ if (info->salt_principal == NULL) {
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(pw);
+ BURN_FREE_STR(old_pw);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ info->password_last_change = last_set_nt;
+ info->password_changes = 1;
+ info->next_change = NULL;
+
+ status = secrets_domain_info_password_create(info,
+ pw,
+ info->salt_principal,
+ last_set_nt, server,
+ &info->password);
+ BURN_FREE_STR(pw);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_domain_info_password_create(pw) failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ BURN_FREE_STR(old_pw);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * After a join we don't have old passwords.
+ */
+ if (old_pw != NULL) {
+ status = secrets_domain_info_password_create(info,
+ old_pw,
+ info->salt_principal,
+ 0, server,
+ &info->old_password);
+ BURN_FREE_STR(old_pw);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_domain_info_password_create(old) failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+ info->password_changes += 1;
+ } else {
+ info->old_password = NULL;
+ }
+ info->older_password = NULL;
+
+ secrets_debug_domain_info(DBGLVL_INFO, info, "upgrade");
+
+ status = secrets_store_domain_info(info, true /* upgrade */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * We now reparse it.
+ */
+ status = secrets_fetch_domain_info(domain, frame, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_fetch_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ *pinfo = talloc_move(mem_ctx, &info);
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS secrets_store_JoinCtx(const struct libnet_JoinCtx *r)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct secrets_domain_info1 *old = NULL;
+ struct secrets_domain_info1 *info = NULL;
+ struct db_context *db = NULL;
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+ const char *domain = r->out.netbios_domain_name;
+ NTSTATUS status;
+ int ret;
+
+ info = talloc_zero(frame, struct secrets_domain_info1);
+ if (info == NULL) {
+ DBG_ERR("talloc_zero failed\n");
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ info->computer_name = r->in.machine_name;
+ info->account_name = r->out.account_name;
+ info->secure_channel_type = r->in.secure_channel_type;
+
+ info->domain_info.name.string =
+ r->out.netbios_domain_name;
+ info->domain_info.dns_domain.string =
+ r->out.dns_domain_name;
+ info->domain_info.dns_forest.string =
+ r->out.forest_name;
+ info->domain_info.domain_guid = r->out.domain_guid;
+ info->domain_info.sid = r->out.domain_sid;
+
+ info->trust_flags = NETR_TRUST_FLAG_PRIMARY;
+ info->trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+ if (r->out.domain_is_ad) {
+ /*
+ * We just assume all AD domains are
+ * NETR_TRUST_FLAG_NATIVE these days.
+ *
+ * This isn't used anyway for now.
+ */
+ info->trust_flags |= NETR_TRUST_FLAG_NATIVE;
+
+ info->trust_type = LSA_TRUST_TYPE_UPLEVEL;
+ } else {
+ info->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+ }
+ info->trust_attributes = LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL;
+
+ info->join_time = now;
+
+ info->supported_enc_types = r->out.set_encryption_types;
+ info->salt_principal = r->out.krb5_salt;
+
+ if (info->salt_principal == NULL && r->out.domain_is_ad) {
+ char *p = NULL;
+
+ ret = smb_krb5_salt_principal_str(info->domain_info.dns_domain.string,
+ info->account_name,
+ NULL /* userPrincipalName */,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ info, &p);
+ if (ret != 0) {
+ status = krb5_to_nt_status(ret);
+ DBG_ERR("smb_krb5_salt_principal() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ TALLOC_FREE(frame);
+ return status;
+ }
+ info->salt_principal = p;
+ }
+
+ info->password_last_change = now;
+ info->password_changes = 1;
+ info->next_change = NULL;
+
+ status = secrets_domain_info_password_create(info,
+ r->in.machine_password,
+ info->salt_principal,
+ now, r->in.dc_name,
+ &info->password);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_domain_info_password_create(pw) failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ status = secrets_fetch_or_upgrade_domain_info(domain, frame, &old);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
+ DBG_DEBUG("no old join for domain(%s) available\n",
+ domain);
+ old = NULL;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_fetch_or_upgrade_domain_info(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * We reuse values from an old join, so that
+ * we still accept already granted kerberos tickets.
+ */
+ if (old != NULL) {
+ info->old_password = old->password;
+ info->older_password = old->old_password;
+ }
+
+ secrets_debug_domain_info(DBGLVL_INFO, info, "join");
+
+ status = secrets_store_domain_info(info, false /* upgrade */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS secrets_prepare_password_change(const char *domain, const char *dcname,
+ const char *cleartext_unix,
+ TALLOC_CTX *mem_ctx,
+ struct secrets_domain_info1 **pinfo,
+ struct secrets_domain_info1_change **pprev)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db = NULL;
+ struct secrets_domain_info1 *info = NULL;
+ struct secrets_domain_info1_change *prev = NULL;
+ struct secrets_domain_info1_change *next = NULL;
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+ NTSTATUS status;
+ int ret;
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ status = secrets_fetch_or_upgrade_domain_info(domain, frame, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_fetch_or_upgrade_domain_info(%s) failed\n",
+ domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ prev = info->next_change;
+ info->next_change = NULL;
+
+ next = talloc_zero(frame, struct secrets_domain_info1_change);
+ if (next == NULL) {
+ DBG_ERR("talloc_zero failed\n");
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (prev != NULL) {
+ *next = *prev;
+ } else {
+ status = secrets_domain_info_password_create(next,
+ cleartext_unix,
+ info->salt_principal,
+ now, dcname,
+ &next->password);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_domain_info_password_create(next) failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+ }
+
+ next->local_status = NT_STATUS_OK;
+ next->remote_status = NT_STATUS_NOT_COMMITTED;
+ next->change_time = now;
+ next->change_server = dcname;
+
+ info->next_change = next;
+
+ secrets_debug_domain_info(DBGLVL_INFO, info, "prepare_change");
+
+ status = secrets_store_domain_info(info, false /* upgrade */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * We now reparse it.
+ */
+ status = secrets_fetch_domain_info(domain, frame, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_fetch_domain_info(%s) failed\n", domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ *pinfo = talloc_move(mem_ctx, &info);
+ if (prev != NULL) {
+ *pprev = talloc_move(mem_ctx, &prev);
+ } else {
+ *pprev = NULL;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS secrets_check_password_change(const struct secrets_domain_info1 *cookie,
+ TALLOC_CTX *mem_ctx,
+ struct secrets_domain_info1 **pstored)
+{
+ const char *domain = cookie->domain_info.name.string;
+ struct secrets_domain_info1 *stored = NULL;
+ struct secrets_domain_info1_change *sn = NULL;
+ struct secrets_domain_info1_change *cn = NULL;
+ NTSTATUS status;
+ bool cmp;
+
+ if (cookie->next_change == NULL) {
+ DBG_ERR("cookie->next_change == NULL for %s.\n", domain);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (cookie->next_change->password == NULL) {
+ DBG_ERR("cookie->next_change->password == NULL for %s.\n", domain);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (cookie->password == NULL) {
+ DBG_ERR("cookie->password == NULL for %s.\n", domain);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * Here we check that the given structure still contains the
+ * same secrets_domain_info1_change as currently stored.
+ *
+ * There's always a gap between secrets_prepare_password_change()
+ * and the callers of secrets_check_password_change().
+ */
+
+ status = secrets_fetch_domain_info(domain, mem_ctx, &stored);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_fetch_domain_info(%s) failed\n", domain);
+ return status;
+ }
+
+ if (stored->next_change == NULL) {
+ /*
+ * We hit a race..., the administrator
+ * rejoined or something similar happened.
+ */
+ DBG_ERR("stored->next_change == NULL for %s.\n", domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ if (stored->password_last_change != cookie->password_last_change) {
+ struct timeval store_tv;
+ struct timeval_buf store_buf;
+ struct timeval cookie_tv;
+ struct timeval_buf cookie_buf;
+
+ nttime_to_timeval(&store_tv, stored->password_last_change);
+ nttime_to_timeval(&cookie_tv, cookie->password_last_change);
+
+ DBG_ERR("password_last_change differs %s != %s for %s.\n",
+ timeval_str_buf(&store_tv, false, false, &store_buf),
+ timeval_str_buf(&cookie_tv, false, false, &cookie_buf),
+ domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ sn = stored->next_change;
+ cn = cookie->next_change;
+
+ if (sn->change_time != cn->change_time) {
+ struct timeval store_tv;
+ struct timeval_buf store_buf;
+ struct timeval cookie_tv;
+ struct timeval_buf cookie_buf;
+
+ nttime_to_timeval(&store_tv, sn->change_time);
+ nttime_to_timeval(&cookie_tv, cn->change_time);
+
+ DBG_ERR("next change_time differs %s != %s for %s.\n",
+ timeval_str_buf(&store_tv, false, false, &store_buf),
+ timeval_str_buf(&cookie_tv, false, false, &cookie_buf),
+ domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ if (sn->password->change_time != cn->password->change_time) {
+ struct timeval store_tv;
+ struct timeval_buf store_buf;
+ struct timeval cookie_tv;
+ struct timeval_buf cookie_buf;
+
+ nttime_to_timeval(&store_tv, sn->password->change_time);
+ nttime_to_timeval(&cookie_tv, cn->password->change_time);
+
+ DBG_ERR("next password.change_time differs %s != %s for %s.\n",
+ timeval_str_buf(&store_tv, false, false, &store_buf),
+ timeval_str_buf(&cookie_tv, false, false, &cookie_buf),
+ domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ cmp = mem_equal_const_time(sn->password->nt_hash.hash,
+ cn->password->nt_hash.hash,
+ 16);
+ if (!cmp) {
+ DBG_ERR("next password.nt_hash differs for %s.\n",
+ domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ cmp = mem_equal_const_time(stored->password->nt_hash.hash,
+ cookie->password->nt_hash.hash,
+ 16);
+ if (!cmp) {
+ DBG_ERR("password.nt_hash differs for %s.\n",
+ domain);
+ TALLOC_FREE(stored);
+ return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ *pstored = stored;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS secrets_abort_password_change(const char *change_server,
+ NTSTATUS local_status,
+ NTSTATUS remote_status,
+ const struct secrets_domain_info1 *cookie,
+ bool defer)
+{
+ const char *domain = cookie->domain_info.name.string;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db = NULL;
+ struct secrets_domain_info1 *info = NULL;
+ const char *reason = defer ? "defer_change" : "failed_change";
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+ NTSTATUS status;
+ int ret;
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /*
+ * secrets_check_password_change()
+ * checks that cookie->next_change
+ * is valid and the same as store
+ * in the database.
+ */
+ status = secrets_check_password_change(cookie, frame, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_check_password_change(%s) failed\n", domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * Remember the last server and error.
+ */
+ info->next_change->change_server = change_server;
+ info->next_change->change_time = now;
+ info->next_change->local_status = local_status;
+ info->next_change->remote_status = remote_status;
+
+ /*
+ * Make sure the next automatic change is deferred.
+ */
+ if (defer) {
+ info->password_last_change = now;
+ }
+
+ secrets_debug_domain_info(DBGLVL_WARNING, info, reason);
+
+ status = secrets_store_domain_info(info, false /* upgrade */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS secrets_failed_password_change(const char *change_server,
+ NTSTATUS local_status,
+ NTSTATUS remote_status,
+ const struct secrets_domain_info1 *cookie)
+{
+ static const bool defer = false;
+ return secrets_abort_password_change(change_server,
+ local_status,
+ remote_status,
+ cookie, defer);
+}
+
+NTSTATUS secrets_defer_password_change(const char *change_server,
+ NTSTATUS local_status,
+ NTSTATUS remote_status,
+ const struct secrets_domain_info1 *cookie)
+{
+ static const bool defer = true;
+ return secrets_abort_password_change(change_server,
+ local_status,
+ remote_status,
+ cookie, defer);
+}
+
+NTSTATUS secrets_finish_password_change(const char *change_server,
+ NTTIME change_time,
+ const struct secrets_domain_info1 *cookie)
+{
+ const char *domain = cookie->domain_info.name.string;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db = NULL;
+ struct secrets_domain_info1 *info = NULL;
+ struct secrets_domain_info1_change *nc = NULL;
+ NTSTATUS status;
+ int ret;
+
+ db = secrets_db_ctx();
+
+ ret = dbwrap_transaction_start(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_start() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ /*
+ * secrets_check_password_change() checks that cookie->next_change is
+ * valid and the same as store in the database.
+ */
+ status = secrets_check_password_change(cookie, frame, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_check_password_change(%s) failed\n", domain);
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ nc = info->next_change;
+
+ nc->password->change_server = change_server;
+ nc->password->change_time = change_time;
+
+ info->password_last_change = change_time;
+ info->password_changes += 1;
+ info->next_change = NULL;
+
+ info->older_password = info->old_password;
+ info->old_password = info->password;
+ info->password = nc->password;
+
+ secrets_debug_domain_info(DBGLVL_WARNING, info, "finish_change");
+
+ status = secrets_store_domain_info(info, false /* upgrade */);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("secrets_store_domain_info() failed "
+ "for %s - %s\n", domain, nt_errstr(status));
+ dbwrap_transaction_cancel(db);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ ret = dbwrap_transaction_commit(db);
+ if (ret != 0) {
+ DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
+ domain);
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/machine_sid.c b/source3/passdb/machine_sid.c
new file mode 100644
index 0000000..fa420d8
--- /dev/null
+++ b/source3/passdb/machine_sid.c
@@ -0,0 +1,251 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2002
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Gerald (Jerry) Carter 2000
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "passdb/machine_sid.h"
+#include "secrets.h"
+#include "dbwrap/dbwrap.h"
+#include "../libcli/security/security.h"
+
+/* NOTE! the global_sam_sid is the SID of our local SAM. This is only
+ equal to the domain SID when we are a DC, otherwise its our
+ workstation SID */
+static struct dom_sid *global_sam_sid=NULL;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/****************************************************************************
+ Read a SID from a file. This is for compatibility with the old MACHINE.SID
+ style of SID storage
+****************************************************************************/
+
+static bool read_sid_from_file(const char *fname, struct dom_sid *sid)
+{
+ char **lines;
+ int numlines;
+ bool ret;
+
+ lines = file_lines_load(fname, &numlines,0, NULL);
+
+ if (!lines || numlines < 1) {
+ TALLOC_FREE(lines);
+ return False;
+ }
+
+ ret = string_to_sid(sid, lines[0]);
+ TALLOC_FREE(lines);
+ return ret;
+}
+
+/*
+ generate a random sid - used to build our own sid if we don't have one
+*/
+static void generate_random_sid(struct dom_sid *sid)
+{
+ int i;
+ uchar raw_sid_data[12];
+
+ *sid = (struct dom_sid) {
+ .sid_rev_num = 1,
+ .id_auth[5] = 5,
+ };
+
+ sid->sub_auths[sid->num_auths++] = 21;
+
+ generate_random_buffer(raw_sid_data, 12);
+ for (i = 0; i < 3; i++)
+ sid->sub_auths[sid->num_auths++] = IVAL(raw_sid_data, i*4);
+}
+
+/****************************************************************************
+ Generate the global machine sid.
+****************************************************************************/
+
+static struct dom_sid *pdb_generate_sam_sid(void)
+{
+ struct dom_sid domain_sid;
+ char *fname = NULL;
+ struct dom_sid *sam_sid;
+
+ if(!(sam_sid=SMB_MALLOC_P(struct dom_sid)))
+ return NULL;
+
+ if ( IS_DC ) {
+ if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ sid_copy(sam_sid, &domain_sid);
+ return sam_sid;
+ }
+ }
+
+ if (secrets_fetch_domain_sid(lp_netbios_name(), sam_sid)) {
+
+ /* We got our sid. If not a pdc/bdc, we're done. */
+ if ( !IS_DC )
+ return sam_sid;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+
+ /* No domain sid and we're a pdc/bdc. Store it */
+
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ return sam_sid;
+ }
+
+ if (!dom_sid_equal(&domain_sid, sam_sid)) {
+
+ /* Domain name sid doesn't match global sam sid. Re-store domain sid as 'local' sid. */
+
+ DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n"));
+ if (!secrets_store_domain_sid(lp_netbios_name(), &domain_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID for local sid as PDC/BDC.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ return sam_sid;
+ }
+
+ return sam_sid;
+ }
+
+ /* check for an old MACHINE.SID file for backwards compatibility */
+ if (asprintf(&fname, "%s/MACHINE.SID", lp_private_dir()) == -1) {
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+
+ if (read_sid_from_file(fname, sam_sid)) {
+ /* remember it for future reference and unlink the old MACHINE.SID */
+ if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n"));
+ SAFE_FREE(fname);
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ unlink(fname);
+ if ( !IS_DC ) {
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n"));
+ SAFE_FREE(fname);
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ }
+
+ /* Stored the old sid from MACHINE.SID successfully.*/
+ SAFE_FREE(fname);
+ return sam_sid;
+ }
+
+ SAFE_FREE(fname);
+
+ /* we don't have the SID in secrets.tdb, we will need to
+ generate one and save it */
+ generate_random_sid(sam_sid);
+
+ if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ if ( IS_DC ) {
+ if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+ DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n"));
+ SAFE_FREE(sam_sid);
+ return NULL;
+ }
+ }
+
+ return sam_sid;
+}
+
+/* return our global_sam_sid */
+struct dom_sid *get_global_sam_sid(void)
+{
+ struct db_context *db;
+
+ if (global_sam_sid != NULL)
+ return global_sam_sid;
+
+ /*
+ * memory for global_sam_sid is allocated in
+ * pdb_generate_sam_sid() as needed
+ *
+ * Note: this is guarded by a transaction
+ * to prevent races on startup which
+ * can happen with some dbwrap backends
+ */
+
+ db = secrets_db_ctx();
+ if (!db) {
+ smb_panic("could not open secrets db");
+ }
+
+ if (dbwrap_transaction_start(db) != 0) {
+ smb_panic("could not start transaction on secrets db");
+ }
+
+ if (!(global_sam_sid = pdb_generate_sam_sid())) {
+ dbwrap_transaction_cancel(db);
+ smb_panic("could not generate a machine SID");
+ }
+
+ if (dbwrap_transaction_commit(db) != 0) {
+ smb_panic("could not start commit secrets db");
+ }
+
+ return global_sam_sid;
+}
+
+/**
+ * Force get_global_sam_sid to requery the backends
+ */
+void reset_global_sam_sid(void)
+{
+ SAFE_FREE(global_sam_sid);
+}
+
+/*****************************************************************
+ Check if the SID is our sam SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_our_sam(const struct dom_sid *sid)
+{
+ return dom_sid_equal(sid, get_global_sam_sid());
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_in_our_sam(const struct dom_sid *sid)
+{
+ struct dom_sid dom_sid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, NULL);
+ return sid_check_is_our_sam(&dom_sid);
+}
diff --git a/source3/passdb/machine_sid.h b/source3/passdb/machine_sid.h
new file mode 100644
index 0000000..33dce25
--- /dev/null
+++ b/source3/passdb/machine_sid.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Password and authentication handling
+ * Copyright (C) Jeremy Allison 1996-2002
+ * Copyright (C) Andrew Tridgell 2002
+ * Copyright (C) Gerald (Jerry) Carter 2000
+ * Copyright (C) Stefan (metze) Metzmacher 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The following definitions come from passdb/machine_sid.c */
+
+#ifndef _PASSDB_MACHINE_SID_H_
+#define _PASSDB_MACHINE_SID_H_
+
+struct dom_sid *get_global_sam_sid(void);
+void reset_global_sam_sid(void) ;
+bool sid_check_is_our_sam(const struct dom_sid *sid);
+bool sid_check_is_in_our_sam(const struct dom_sid *sid);
+
+#endif /* _PASSDB_MACHINE_SID_H_ */
diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c
new file mode 100644
index 0000000..4bc48f6
--- /dev/null
+++ b/source3/passdb/passdb.c
@@ -0,0 +1,2755 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2006
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "passdb.h"
+#include "system/passwd.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "secrets.h"
+#include "../libcli/security/security.h"
+#include "../lib/util/util_pw.h"
+#include "util_tdb.h"
+#include "auth/credentials/credentials.h"
+#include "lib/param/param.h"
+#include "lib/util/string_wrappers.h"
+#include "source3/lib/substitute.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/**********************************************************************
+***********************************************************************/
+
+static int samu_destroy(struct samu *user)
+{
+ data_blob_clear_free( &user->lm_pw );
+ data_blob_clear_free( &user->nt_pw );
+
+ if ( user->plaintext_pw )
+ BURN_STR(user->plaintext_pw);
+
+ return 0;
+}
+
+/**********************************************************************
+ generate a new struct samuser
+***********************************************************************/
+
+struct samu *samu_new( TALLOC_CTX *ctx )
+{
+ struct samu *user;
+
+ if ( !(user = talloc_zero( ctx, struct samu )) ) {
+ DEBUG(0,("samuser_new: Talloc failed!\n"));
+ return NULL;
+ }
+
+ talloc_set_destructor( user, samu_destroy );
+
+ /* no initial methods */
+
+ user->methods = NULL;
+
+ /* Don't change these timestamp settings without a good reason.
+ They are important for NT member server compatibility. */
+
+ user->logon_time = (time_t)0;
+ user->pass_last_set_time = (time_t)0;
+ user->pass_can_change_time = (time_t)0;
+ user->logoff_time = get_time_t_max();
+ user->kickoff_time = get_time_t_max();
+ user->fields_present = 0x00ffffff;
+ user->logon_divs = 168; /* hours per week */
+ user->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->hours, 0xff, user->hours_len); /* available at all hours */
+ user->bad_password_count = 0;
+ user->logon_count = 0;
+ user->unknown_6 = 0x000004ec; /* don't know */
+
+ /* Some parts of samba strlen their pdb_get...() returns,
+ so this keeps the interface unchanged for now. */
+
+ user->username = "";
+ user->domain = "";
+ user->nt_username = "";
+ user->full_name = "";
+ user->home_dir = "";
+ user->logon_script = "";
+ user->profile_path = "";
+ user->acct_desc = "";
+ user->workstations = "";
+ user->comment = "";
+ user->munged_dial = "";
+
+ user->plaintext_pw = NULL;
+
+ /* Unless we know otherwise have a Account Control Bit
+ value of 'normal user'. This helps User Manager, which
+ asks for a filtered list of users. */
+
+ user->acct_ctrl = ACB_NORMAL;
+
+ return user;
+}
+
+static int count_commas(const char *str)
+{
+ int num_commas = 0;
+ const char *comma = str;
+
+ while ((comma = strchr(comma, ',')) != NULL) {
+ comma += 1;
+ num_commas += 1;
+ }
+ return num_commas;
+}
+
+/*********************************************************************
+ Initialize a struct samu from a struct passwd including the user
+ and group SIDs. The *user structure is filled out with the Unix
+ attributes and a user SID.
+*********************************************************************/
+
+static NTSTATUS samu_set_unix_internal(struct pdb_methods *methods,
+ struct samu *user, const struct passwd *pwd, bool create)
+{
+ const char *guest_account = lp_guest_account();
+ const char *domain = lp_netbios_name();
+ char *fullname;
+ uint32_t urid;
+ bool ok;
+
+ if ( !pwd ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* Basic properties based upon the Unix account information */
+
+ ok = pdb_set_username(user, pwd->pw_name, PDB_SET);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fullname = NULL;
+
+ if (count_commas(pwd->pw_gecos) == 3) {
+ /*
+ * Heuristic: This seems to be a gecos field that has been
+ * edited by chfn(1). Only use the part before the first
+ * comma. Fixes bug 5198.
+ */
+ fullname = talloc_strndup(
+ talloc_tos(), pwd->pw_gecos,
+ strchr(pwd->pw_gecos, ',') - pwd->pw_gecos);
+ if (fullname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (fullname != NULL) {
+ ok = pdb_set_fullname(user, fullname, PDB_SET);
+ } else {
+ ok = pdb_set_fullname(user, pwd->pw_gecos, PDB_SET);
+ }
+ TALLOC_FREE(fullname);
+
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = pdb_set_domain(user, get_global_sam_name(), PDB_DEFAULT);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+#if 0
+ /* This can lead to a primary group of S-1-22-2-XX which
+ will be rejected by other parts of the Samba code.
+ Rely on pdb_get_group_sid() to "Do The Right Thing" (TM)
+ --jerry */
+
+ gid_to_sid(&group_sid, pwd->pw_gid);
+ pdb_set_group_sid(user, &group_sid, PDB_SET);
+#endif
+
+ /* save the password structure for later use */
+
+ user->unix_pw = tcopy_passwd( user, pwd );
+ if (user->unix_pw == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Special case for the guest account which must have a RID of 501 */
+
+ if ( strequal( pwd->pw_name, guest_account ) ) {
+ if ( !pdb_set_user_sid_from_rid(user, DOMAIN_RID_GUEST, PDB_DEFAULT)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ return NT_STATUS_OK;
+ }
+
+ /* Non-guest accounts...Check for a workstation or user account */
+
+ if (pwd->pw_name[strlen(pwd->pw_name)-1] == '$') {
+ /* workstation */
+
+ if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_DEFAULT)) {
+ DEBUG(1, ("Failed to set 'workstation account' flags for user %s.\n",
+ pwd->pw_name));
+ return NT_STATUS_INVALID_COMPUTER_NAME;
+ }
+ }
+ else {
+ /* user */
+
+ if (!pdb_set_acct_ctrl(user, ACB_NORMAL, PDB_DEFAULT)) {
+ DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n",
+ pwd->pw_name));
+ return NT_STATUS_INVALID_ACCOUNT_NAME;
+ }
+
+ /* set some basic attributes */
+
+ ok = pdb_set_profile_path(
+ user,
+ talloc_sub_specified(
+ user,
+ lp_logon_path(),
+ pwd->pw_name,
+ NULL,
+ domain,
+ pwd->pw_uid,
+ pwd->pw_gid),
+ PDB_DEFAULT);
+ ok &= pdb_set_homedir(
+ user,
+ talloc_sub_specified(
+ user,
+ lp_logon_home(),
+ pwd->pw_name,
+ NULL,
+ domain,
+ pwd->pw_uid,
+ pwd->pw_gid),
+ PDB_DEFAULT);
+ ok &= pdb_set_dir_drive(
+ user,
+ talloc_sub_specified(
+ user,
+ lp_logon_drive(),
+ pwd->pw_name,
+ NULL,
+ domain,
+ pwd->pw_uid,
+ pwd->pw_gid),
+ PDB_DEFAULT);
+ ok &= pdb_set_logon_script(
+ user,
+ talloc_sub_specified(
+ user,
+ lp_logon_script(),
+ pwd->pw_name,
+ NULL,
+ domain,
+ pwd->pw_uid,
+ pwd->pw_gid),
+ PDB_DEFAULT);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* Now deal with the user SID. If we have a backend that can generate
+ RIDs, then do so. But sometimes the caller just wanted a structure
+ initialized and will fill in these fields later (such as from a
+ netr_SamInfo3 structure) */
+
+ if ( create && (methods->capabilities(methods) & PDB_CAP_STORE_RIDS)) {
+ uint32_t user_rid;
+ struct dom_sid user_sid;
+
+ if ( !methods->new_rid(methods, &user_rid) ) {
+ DEBUG(3, ("Could not allocate a new RID\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), user_rid);
+
+ if ( !pdb_set_user_sid(user, &user_sid, PDB_SET) ) {
+ DEBUG(3, ("pdb_set_user_sid failed\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+ }
+
+ /* generate a SID for the user with the RID algorithm */
+
+ urid = algorithmic_pdb_uid_to_user_rid( user->unix_pw->pw_uid );
+
+ if ( !pdb_set_user_sid_from_rid( user, urid, PDB_SET) ) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Set the Unix user attributes
+********************************************************************/
+
+NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd)
+{
+ return samu_set_unix_internal( NULL, user, pwd, False );
+}
+
+NTSTATUS samu_alloc_rid_unix(struct pdb_methods *methods,
+ struct samu *user, const struct passwd *pwd)
+{
+ return samu_set_unix_internal( methods, user, pwd, True );
+}
+
+/**********************************************************
+ Encode the account control bits into a string.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *pdb_encode_acct_ctrl(uint32_t acct_ctrl, size_t length)
+{
+ fstring acct_str;
+ char *result;
+
+ size_t i = 0;
+
+ SMB_ASSERT(length <= sizeof(acct_str));
+
+ acct_str[i++] = '[';
+
+ if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
+ if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
+ if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
+ if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
+ if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
+ if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
+ if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
+ if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
+ if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
+ if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
+ if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
+
+ for ( ; i < length - 2 ; i++ )
+ acct_str[i] = ' ';
+
+ i = length - 2;
+ acct_str[i++] = ']';
+ acct_str[i++] = '\0';
+
+ result = talloc_strdup(talloc_tos(), acct_str);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/**********************************************************
+ Decode the account control bits from a string.
+ **********************************************************/
+
+uint32_t pdb_decode_acct_ctrl(const char *p)
+{
+ uint32_t acct_ctrl = 0;
+ bool finished = false;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[')
+ return 0;
+
+ for (p++; *p && !finished; p++) {
+ switch (*p) {
+ case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
+ case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
+ case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
+ case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
+ case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
+ case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
+ case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
+ case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
+ case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
+ case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
+ case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
+ case ' ': { break; }
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default: { finished = true; }
+ }
+ }
+
+ return acct_ctrl;
+}
+
+/*************************************************************
+ Routine to set 32 hex password characters from a 16 byte array.
+**************************************************************/
+
+void pdb_sethexpwd(char p[33], const unsigned char *pwd, uint32_t acct_ctrl)
+{
+ if (pwd != NULL) {
+ hex_encode_buf(p, pwd, 16);
+ } else {
+ if (acct_ctrl & ACB_PWNOTREQ)
+ strlcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
+ else
+ strlcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
+ }
+}
+
+/*************************************************************
+ Routine to get the 32 hex characters and turn them
+ into a 16 byte array.
+**************************************************************/
+
+bool pdb_gethexpwd(const char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p)
+ return false;
+
+ for (i = 0; i < 32; i += 2) {
+ hinybble = toupper_m(p[i]);
+ lonybble = toupper_m(p[i + 1]);
+
+ p1 = strchr(hexchars, hinybble);
+ p2 = strchr(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ return false;
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return true;
+}
+
+/*************************************************************
+ Routine to set 42 hex hours characters from a 21 byte array.
+**************************************************************/
+
+void pdb_sethexhours(char *p, const unsigned char *hours)
+{
+ if (hours != NULL) {
+ hex_encode_buf(p, hours, 21);
+ } else {
+ strlcpy(p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 44);
+ }
+}
+
+/*************************************************************
+ Routine to get the 42 hex characters and turn them
+ into a 21 byte array.
+**************************************************************/
+
+bool pdb_gethexhours(const char *p, unsigned char *hours)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p) {
+ return (False);
+ }
+
+ for (i = 0; i < 42; i += 2) {
+ hinybble = toupper_m(p[i]);
+ lonybble = toupper_m(p[i + 1]);
+
+ p1 = strchr(hexchars, hinybble);
+ p2 = strchr(hexchars, lonybble);
+
+ if (!p1 || !p2) {
+ return (False);
+ }
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ hours[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/********************************************************************
+********************************************************************/
+
+int algorithmic_rid_base(void)
+{
+ int rid_offset;
+
+ rid_offset = lp_algorithmic_rid_base();
+
+ if (rid_offset < BASE_RID) {
+ /* Try to prevent admin foot-shooting, we can't put algorithmic
+ rids below 1000, that's the 'well known RIDs' on NT */
+ DEBUG(0, ("'algorithmic rid base' must be equal to or above %ld\n", BASE_RID));
+ rid_offset = BASE_RID;
+ }
+ if (rid_offset & 1) {
+ DEBUG(0, ("algorithmic rid base must be even\n"));
+ rid_offset += 1;
+ }
+ return rid_offset;
+}
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+uid_t algorithmic_pdb_user_rid_to_uid(uint32_t user_rid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER);
+}
+
+uid_t max_algorithmic_uid(void)
+{
+ return algorithmic_pdb_user_rid_to_uid(0xfffffffe);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+uint32_t algorithmic_pdb_uid_to_user_rid(uid_t uid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (((((uint32_t)uid)*RID_MULTIPLIER) + rid_offset) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ Converts NT group RID to a UNIX gid.
+ ********************************************************************/
+
+gid_t pdb_group_rid_to_gid(uint32_t group_rid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER);
+}
+
+gid_t max_algorithmic_gid(void)
+{
+ return pdb_group_rid_to_gid(0xffffffff);
+}
+
+/*******************************************************************
+ converts NT Group RID to a UNIX uid.
+
+ warning: you must not call that function only
+ you must do a call to the group mapping first.
+ there is not anymore a direct link between the gid and the rid.
+ ********************************************************************/
+
+uint32_t algorithmic_pdb_gid_to_group_rid(gid_t gid)
+{
+ int rid_offset = algorithmic_rid_base();
+ return (((((uint32_t)gid)*RID_MULTIPLIER) + rid_offset) | GROUP_RID_TYPE);
+}
+
+/*******************************************************************
+ Decides if a RID is a well known RID.
+ ********************************************************************/
+
+static bool rid_is_well_known(uint32_t rid)
+{
+ /* Not using rid_offset here, because this is the actual
+ NT fixed value (1000) */
+
+ return (rid < BASE_RID);
+}
+
+/*******************************************************************
+ Decides if a RID is a user or group RID.
+ ********************************************************************/
+
+bool algorithmic_pdb_rid_is_user(uint32_t rid)
+{
+ if ( rid_is_well_known(rid) ) {
+ /*
+ * The only well known user RIDs are DOMAIN_RID_ADMINISTRATOR
+ * and DOMAIN_RID_GUEST.
+ */
+ if(rid == DOMAIN_RID_ADMINISTRATOR || rid == DOMAIN_RID_GUEST)
+ return True;
+ } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ Convert a name into a SID. Used in the lookup name rpc.
+ ********************************************************************/
+
+bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
+ enum lsa_SidType *type)
+{
+ GROUP_MAP *map;
+ bool ret;
+
+ /* Windows treats "MACHINE\None" as a special name for
+ rid 513 on non-DCs. You cannot create a user or group
+ name "None" on Windows. You will get an error that
+ the group already exists. */
+
+ if ( strequal( name, "None" ) ) {
+ *rid = DOMAIN_RID_USERS;
+ *type = SID_NAME_DOM_GRP;
+
+ return True;
+ }
+
+ /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work
+ * correctly in the case where foo also exists as a user. If the flag
+ * is set, don't look for users at all. */
+
+ if ((flags & LOOKUP_NAME_GROUP) == 0) {
+ struct samu *sam_account = NULL;
+ struct dom_sid user_sid;
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sam_account, name);
+ unbecome_root();
+
+ if (ret) {
+ sid_copy(&user_sid, pdb_get_user_sid(sam_account));
+ }
+
+ TALLOC_FREE(sam_account);
+
+ if (ret) {
+ if (!sid_check_is_in_our_sam(&user_sid)) {
+ struct dom_sid_buf buf;
+ DBG_ERR("User %s with invalid SID %s"
+ " in passdb\n",
+ name,
+ dom_sid_str_buf(&user_sid, &buf));
+ return False;
+ }
+
+ sid_peek_rid(&user_sid, rid);
+ *type = SID_NAME_USER;
+ return True;
+ }
+ }
+
+ /*
+ * Maybe it is a group ?
+ */
+
+ map = talloc_zero(NULL, GROUP_MAP);
+ if (!map) {
+ return false;
+ }
+
+ become_root();
+ ret = pdb_getgrnam(map, name);
+ unbecome_root();
+
+ if (!ret) {
+ TALLOC_FREE(map);
+ return False;
+ }
+
+ /* BUILTIN groups are looked up elsewhere */
+ if (!sid_check_is_in_our_sam(&map->sid)) {
+ struct dom_sid_buf buf;
+ DEBUG(10, ("Found group %s (%s) not in our domain -- "
+ "ignoring.\n",
+ name,
+ dom_sid_str_buf(&map->sid, &buf)));
+ TALLOC_FREE(map);
+ return False;
+ }
+
+ /* yes it's a mapped group */
+ sid_peek_rid(&map->sid, rid);
+ *type = map->sid_name_use;
+ TALLOC_FREE(map);
+ return True;
+}
+
+/*************************************************************
+ Change a password entry in the local passdb backend.
+
+ Assumptions:
+ - always called as root
+ - ignores the account type except when adding a new account
+ - will create/delete the unix account if the relative
+ add/delete user script is configured
+
+ *************************************************************/
+
+NTSTATUS local_password_change(const char *user_name,
+ int local_flags,
+ const char *new_passwd,
+ char **pp_err_str,
+ char **pp_msg_str)
+{
+ TALLOC_CTX *tosctx;
+ struct samu *sam_pass;
+ uint32_t acb;
+ uint32_t rid;
+ NTSTATUS result;
+ bool user_exists;
+ int ret = -1;
+
+ *pp_err_str = NULL;
+ *pp_msg_str = NULL;
+
+ tosctx = talloc_tos();
+
+ sam_pass = samu_new(tosctx);
+ if (!sam_pass) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* Get the smb passwd entry for this user */
+ user_exists = pdb_getsampwnam(sam_pass, user_name);
+
+ /* Check delete first, we don't need to do anything else if we
+ * are going to delete the account */
+ if (user_exists && (local_flags & LOCAL_DELETE_USER)) {
+
+ result = pdb_delete_user(tosctx, sam_pass);
+ if (!NT_STATUS_IS_OK(result)) {
+ ret = asprintf(pp_err_str,
+ "Failed to delete entry for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ } else {
+ ret = asprintf(pp_msg_str,
+ "Deleted user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_msg_str = NULL;
+ }
+ }
+ goto done;
+ }
+
+ if (user_exists && (local_flags & LOCAL_ADD_USER)) {
+ /* the entry already existed */
+ local_flags &= ~LOCAL_ADD_USER;
+ }
+
+ if (!user_exists && !(local_flags & LOCAL_ADD_USER)) {
+ ret = asprintf(pp_err_str,
+ "Failed to find entry for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ /* First thing add the new user if we are required to do so */
+ if (local_flags & LOCAL_ADD_USER) {
+
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ acb = ACB_WSTRUST;
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ acb = ACB_DOMTRUST;
+ } else {
+ acb = ACB_NORMAL;
+ }
+
+ result = pdb_create_user(tosctx, user_name, acb, &rid);
+ if (!NT_STATUS_IS_OK(result)) {
+ ret = asprintf(pp_err_str,
+ "Failed to add entry for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ sam_pass = samu_new(tosctx);
+ if (!sam_pass) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* Now get back the smb passwd entry for this new user */
+ user_exists = pdb_getsampwnam(sam_pass, user_name);
+ if (!user_exists) {
+ ret = asprintf(pp_err_str,
+ "Failed to add entry for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ acb = pdb_get_acct_ctrl(sam_pass);
+
+ /*
+ * We are root - just write the new password
+ * and the valid last change time.
+ */
+ if ((local_flags & LOCAL_SET_NO_PASSWORD) && !(acb & ACB_PWNOTREQ)) {
+ acb |= ACB_PWNOTREQ;
+ if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+ ret = asprintf(pp_err_str,
+ "Failed to set 'no password required' "
+ "flag for user %s.\n", user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ if (local_flags & LOCAL_SET_PASSWORD) {
+ /*
+ * If we're dealing with setting a completely empty user account
+ * ie. One with a password of 'XXXX', but not set disabled (like
+ * an account created from scratch) then if the old password was
+ * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
+ * We remove that as we're giving this user their first password
+ * and the decision hasn't really been made to disable them (ie.
+ * don't create them disabled). JRA.
+ */
+ if ((pdb_get_lanman_passwd(sam_pass) == NULL) &&
+ (acb & ACB_DISABLED)) {
+ acb &= (~ACB_DISABLED);
+ if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+ ret = asprintf(pp_err_str,
+ "Failed to unset 'disabled' "
+ "flag for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ acb &= (~ACB_PWNOTREQ);
+ if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+ ret = asprintf(pp_err_str,
+ "Failed to unset 'no password required'"
+ " flag for user %s.\n", user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!pdb_set_plaintext_passwd(sam_pass, new_passwd)) {
+ ret = asprintf(pp_err_str,
+ "Failed to set password for "
+ "user %s.\n", user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ if ((local_flags & LOCAL_DISABLE_USER) && !(acb & ACB_DISABLED)) {
+ acb |= ACB_DISABLED;
+ if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+ ret = asprintf(pp_err_str,
+ "Failed to set 'disabled' flag for "
+ "user %s.\n", user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ if ((local_flags & LOCAL_ENABLE_USER) && (acb & ACB_DISABLED)) {
+ acb &= (~ACB_DISABLED);
+ if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+ ret = asprintf(pp_err_str,
+ "Failed to unset 'disabled' flag for "
+ "user %s.\n", user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+
+ /* now commit changes if any */
+ result = pdb_update_sam_account(sam_pass);
+ if (!NT_STATUS_IS_OK(result)) {
+ ret = asprintf(pp_err_str,
+ "Failed to modify entry for user %s.\n",
+ user_name);
+ if (ret < 0) {
+ *pp_err_str = NULL;
+ }
+ goto done;
+ }
+
+ if (local_flags & LOCAL_ADD_USER) {
+ ret = asprintf(pp_msg_str, "Added user %s.\n", user_name);
+ } else if (local_flags & LOCAL_DISABLE_USER) {
+ ret = asprintf(pp_msg_str, "Disabled user %s.\n", user_name);
+ } else if (local_flags & LOCAL_ENABLE_USER) {
+ ret = asprintf(pp_msg_str, "Enabled user %s.\n", user_name);
+ } else if (local_flags & LOCAL_SET_NO_PASSWORD) {
+ ret = asprintf(pp_msg_str,
+ "User %s password set to none.\n", user_name);
+ }
+
+ if (ret < 0) {
+ *pp_msg_str = NULL;
+ }
+
+ result = NT_STATUS_OK;
+
+done:
+ TALLOC_FREE(sam_pass);
+ return result;
+}
+
+/**********************************************************************
+ Marshall/unmarshall struct samu structs.
+ *********************************************************************/
+
+#define SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
+#define SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
+#define SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd"
+/* nothing changed between V3 and V4 */
+
+/*********************************************************************
+*********************************************************************/
+
+static bool init_samu_from_buffer_v0(struct samu *sampass, uint8_t *buf, uint32_t buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32_t username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32_t user_rid, group_rid, remove_me, hours_len, unknown_6;
+ uint16_t acct_ctrl, logon_divs;
+ uint16_t bad_password_count, logon_count;
+ uint8_t *hours = NULL;
+ uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
+ uint32_t len = 0;
+ uint32_t lm_pw_len, nt_pw_len, hourslen;
+ bool ret = True;
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_samu_from_buffer_v0: NULL parameters found!\n"));
+ return False;
+ }
+
+/* SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V0,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ &acct_ctrl, /* w */
+ &remove_me, /* remove on the next TDB_FORMAT upgrade */ /* d */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32_t) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else {
+ pdb_set_dir_drive(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_drive()),
+ PDB_DEFAULT);
+ }
+
+ if (logon_script)
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, hours_len, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool init_samu_from_buffer_v1(struct samu *sampass, uint8_t *buf, uint32_t buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32_t logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32_t username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32_t user_rid, group_rid, remove_me, hours_len, unknown_6;
+ uint16_t acct_ctrl, logon_divs;
+ uint16_t bad_password_count, logon_count;
+ uint8_t *hours = NULL;
+ uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
+ uint32_t len = 0;
+ uint32_t lm_pw_len, nt_pw_len, hourslen;
+ bool ret = True;
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_samu_from_buffer_v1: NULL parameters found!\n"));
+ return False;
+ }
+
+/* SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V1,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ /* Change from V0 is addition of bad_password_time field. */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ &acct_ctrl, /* w */
+ &remove_me, /* d */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32_t) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+
+ /* Change from V0 is addition of bad_password_time field. */
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else {
+ pdb_set_dir_drive(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_drive()),
+ PDB_DEFAULT);
+ }
+
+ if (logon_script)
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, hours_len, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+static bool init_samu_from_buffer_v2(struct samu *sampass, uint8_t *buf, uint32_t buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32_t logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *unknown_str = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32_t username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32_t user_rid, group_rid, hours_len, unknown_6;
+ uint16_t acct_ctrl, logon_divs;
+ uint16_t bad_password_count, logon_count;
+ uint8_t *hours = NULL;
+ uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
+ uint32_t len = 0;
+ uint32_t lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
+ uint32_t pwHistLen = 0;
+ bool ret = True;
+ fstring tmp_string;
+ bool expand_explicit = lp_passdb_expand_explicit();
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_samu_from_buffer_v2: NULL parameters found!\n"));
+ return False;
+ }
+
+/* SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V2,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &unknown_str_len, &unknown_str, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ /* Change from V1 is addition of password history field. */
+ &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
+ &acct_ctrl, /* w */
+ /* Also "remove_me" field was removed. */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32_t) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ fstrcpy( tmp_string, homedir );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_homedir(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else
+ pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
+
+ if (logon_script) {
+ fstrcpy( tmp_string, logon_script );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_logon_script(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ fstrcpy( tmp_string, profile_path );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_profile_path(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ /* Change from V1 is addition of password history field. */
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen) {
+ uint8_t *pw_hist = SMB_MALLOC_ARRAY(uint8_t, pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (!pw_hist) {
+ ret = False;
+ goto done;
+ }
+ memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (nt_pw_hist_ptr && nt_pw_hist_len) {
+ int i;
+ SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
+ nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
+ for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
+ memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
+ &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
+ PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
+ SAFE_FREE(pw_hist);
+ ret = False;
+ goto done;
+ }
+ SAFE_FREE(pw_hist);
+ } else {
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ }
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, hours_len, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(unknown_str);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(nt_pw_hist_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static bool init_samu_from_buffer_v3(struct samu *sampass, uint8_t *buf, uint32_t buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32_t logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username = NULL;
+ char *domain = NULL;
+ char *nt_username = NULL;
+ char *dir_drive = NULL;
+ char *comment = NULL;
+ char *munged_dial = NULL;
+ char *fullname = NULL;
+ char *homedir = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *acct_desc = NULL;
+ char *workstations = NULL;
+ uint32_t username_len, domain_len, nt_username_len,
+ dir_drive_len, comment_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32_t user_rid, group_rid, hours_len, unknown_6, acct_ctrl;
+ uint16_t logon_divs;
+ uint16_t bad_password_count, logon_count;
+ uint8_t *hours = NULL;
+ uint8_t *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
+ uint32_t len = 0;
+ uint32_t lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
+ uint32_t pwHistLen = 0;
+ bool ret = True;
+ fstring tmp_string;
+ bool expand_explicit = lp_passdb_expand_explicit();
+
+ if(sampass == NULL || buf == NULL) {
+ DEBUG(0, ("init_samu_from_buffer_v3: NULL parameters found!\n"));
+ return False;
+ }
+
+/* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V3,
+ &logon_time, /* d */
+ &logoff_time, /* d */
+ &kickoff_time, /* d */
+ &bad_password_time, /* d */
+ &pass_last_set_time, /* d */
+ &pass_can_change_time, /* d */
+ &pass_must_change_time, /* d */
+ &username_len, &username, /* B */
+ &domain_len, &domain, /* B */
+ &nt_username_len, &nt_username, /* B */
+ &fullname_len, &fullname, /* B */
+ &homedir_len, &homedir, /* B */
+ &dir_drive_len, &dir_drive, /* B */
+ &logon_script_len, &logon_script, /* B */
+ &profile_path_len, &profile_path, /* B */
+ &acct_desc_len, &acct_desc, /* B */
+ &workstations_len, &workstations, /* B */
+ &comment_len, &comment, /* B */
+ &munged_dial_len, &munged_dial, /* B */
+ &user_rid, /* d */
+ &group_rid, /* d */
+ &lm_pw_len, &lm_pw_ptr, /* B */
+ &nt_pw_len, &nt_pw_ptr, /* B */
+ /* Change from V1 is addition of password history field. */
+ &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
+ /* Change from V2 is the uint32_t acb_mask */
+ &acct_ctrl, /* d */
+ /* Also "remove_me" field was removed. */
+ &logon_divs, /* w */
+ &hours_len, /* d */
+ &hourslen, &hours, /* B */
+ &bad_password_count, /* w */
+ &logon_count, /* w */
+ &unknown_6); /* d */
+
+ if (len == (uint32_t) -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, convert_uint32_t_to_time_t(logon_time), PDB_SET);
+ pdb_set_logoff_time(sampass, convert_uint32_t_to_time_t(logoff_time), PDB_SET);
+ pdb_set_kickoff_time(sampass, convert_uint32_t_to_time_t(kickoff_time), PDB_SET);
+ pdb_set_bad_password_time(sampass, convert_uint32_t_to_time_t(bad_password_time), PDB_SET);
+ pdb_set_pass_can_change_time(sampass, convert_uint32_t_to_time_t(pass_can_change_time), PDB_SET);
+ pdb_set_pass_last_set_time(sampass, convert_uint32_t_to_time_t(pass_last_set_time), PDB_SET);
+
+ pdb_set_username(sampass, username, PDB_SET);
+ pdb_set_domain(sampass, domain, PDB_SET);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+
+ if (homedir) {
+ fstrcpy( tmp_string, homedir );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_homedir(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ if (dir_drive)
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ else
+ pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
+
+ if (logon_script) {
+ fstrcpy( tmp_string, logon_script );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_logon_script(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(sampass, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT);
+ }
+
+ if (profile_path) {
+ fstrcpy( tmp_string, profile_path );
+ if (expand_explicit) {
+ standard_sub_basic( username, domain, tmp_string,
+ sizeof(tmp_string) );
+ }
+ pdb_set_profile_path(sampass, tmp_string, PDB_SET);
+ }
+ else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(sampass, username, domain, lp_logon_path()),
+ PDB_DEFAULT);
+ }
+
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ pdb_set_comment(sampass, comment, PDB_SET);
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+
+ if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
+ if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
+ if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen) {
+ uint8_t *pw_hist = (uint8_t *)SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (!pw_hist) {
+ ret = False;
+ goto done;
+ }
+ memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (nt_pw_hist_ptr && nt_pw_hist_len) {
+ int i;
+ SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
+ nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
+ for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
+ memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
+ &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
+ PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
+ SAFE_FREE(pw_hist);
+ ret = False;
+ goto done;
+ }
+ SAFE_FREE(pw_hist);
+ } else {
+ pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
+ }
+
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
+ /* Change from V2 is the uint32_t acct_ctrl */
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+ pdb_set_hours(sampass, hours, hours_len, PDB_SET);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+ SAFE_FREE(comment);
+ SAFE_FREE(lm_pw_ptr);
+ SAFE_FREE(nt_pw_ptr);
+ SAFE_FREE(nt_pw_hist_ptr);
+ SAFE_FREE(hours);
+
+ return ret;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static uint32_t init_buffer_from_samu_v3 (uint8_t **buf, struct samu *sampass, bool size_only)
+{
+ size_t len, buflen;
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32_t logon_time,
+ logoff_time,
+ kickoff_time,
+ bad_password_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+
+ uint32_t user_rid, group_rid;
+
+ const char *username;
+ const char *domain;
+ const char *nt_username;
+ const char *dir_drive;
+ const char *comment;
+ const char *munged_dial;
+ const char *fullname;
+ const char *homedir;
+ const char *logon_script;
+ const char *profile_path;
+ const char *acct_desc;
+ const char *workstations;
+ uint32_t username_len, domain_len, nt_username_len,
+ dir_drive_len, comment_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ const uint8_t *lm_pw;
+ const uint8_t *nt_pw;
+ const uint8_t *nt_pw_hist;
+ uint32_t lm_pw_len = 16;
+ uint32_t nt_pw_len = 16;
+ uint32_t nt_pw_hist_len;
+ uint32_t pwHistLen = 0;
+
+ *buf = NULL;
+ buflen = 0;
+
+ logon_time = convert_time_t_to_uint32_t(pdb_get_logon_time(sampass));
+ logoff_time = convert_time_t_to_uint32_t(pdb_get_logoff_time(sampass));
+ kickoff_time = convert_time_t_to_uint32_t(pdb_get_kickoff_time(sampass));
+ bad_password_time = convert_time_t_to_uint32_t(pdb_get_bad_password_time(sampass));
+ pass_can_change_time = convert_time_t_to_uint32_t(pdb_get_pass_can_change_time_noncalc(sampass));
+ pass_must_change_time = convert_time_t_to_uint32_t(pdb_get_pass_must_change_time(sampass));
+ pass_last_set_time = convert_time_t_to_uint32_t(pdb_get_pass_last_set_time(sampass));
+
+ user_rid = pdb_get_user_rid(sampass);
+ group_rid = pdb_get_group_rid(sampass);
+
+ username = pdb_get_username(sampass);
+ if (username) {
+ username_len = strlen(username) +1;
+ } else {
+ username_len = 0;
+ }
+
+ domain = pdb_get_domain(sampass);
+ if (domain) {
+ domain_len = strlen(domain) +1;
+ } else {
+ domain_len = 0;
+ }
+
+ nt_username = pdb_get_nt_username(sampass);
+ if (nt_username) {
+ nt_username_len = strlen(nt_username) +1;
+ } else {
+ nt_username_len = 0;
+ }
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname) {
+ fullname_len = strlen(fullname) +1;
+ } else {
+ fullname_len = 0;
+ }
+
+ /*
+ * Only updates fields which have been set (not defaults from smb.conf)
+ */
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_DRIVE)) {
+ dir_drive = pdb_get_dir_drive(sampass);
+ } else {
+ dir_drive = NULL;
+ }
+ if (dir_drive) {
+ dir_drive_len = strlen(dir_drive) +1;
+ } else {
+ dir_drive_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_SMBHOME)) {
+ homedir = pdb_get_homedir(sampass);
+ } else {
+ homedir = NULL;
+ }
+ if (homedir) {
+ homedir_len = strlen(homedir) +1;
+ } else {
+ homedir_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_LOGONSCRIPT)) {
+ logon_script = pdb_get_logon_script(sampass);
+ } else {
+ logon_script = NULL;
+ }
+ if (logon_script) {
+ logon_script_len = strlen(logon_script) +1;
+ } else {
+ logon_script_len = 0;
+ }
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_PROFILE)) {
+ profile_path = pdb_get_profile_path(sampass);
+ } else {
+ profile_path = NULL;
+ }
+ if (profile_path) {
+ profile_path_len = strlen(profile_path) +1;
+ } else {
+ profile_path_len = 0;
+ }
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ if (!lm_pw) {
+ lm_pw_len = 0;
+ }
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ if (!nt_pw) {
+ nt_pw_len = 0;
+ }
+
+ pdb_get_account_policy(PDB_POLICY_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;
+ } else {
+ nt_pw_hist_len = 0;
+ }
+
+ acct_desc = pdb_get_acct_desc(sampass);
+ if (acct_desc) {
+ acct_desc_len = strlen(acct_desc) +1;
+ } else {
+ acct_desc_len = 0;
+ }
+
+ workstations = pdb_get_workstations(sampass);
+ if (workstations) {
+ workstations_len = strlen(workstations) +1;
+ } else {
+ workstations_len = 0;
+ }
+
+ comment = pdb_get_comment(sampass);
+ if (comment) {
+ comment_len = strlen(comment) +1;
+ } else {
+ comment_len = 0;
+ }
+
+ munged_dial = pdb_get_munged_dial(sampass);
+ if (munged_dial) {
+ munged_dial_len = strlen(munged_dial) +1;
+ } else {
+ munged_dial_len = 0;
+ }
+
+/* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
+
+ /* one time to get the size needed */
+ len = tdb_pack(NULL, 0, SAMU_BUFFER_FORMAT_V3,
+ logon_time, /* d */
+ logoff_time, /* d */
+ kickoff_time, /* d */
+ bad_password_time, /* d */
+ pass_last_set_time, /* d */
+ pass_can_change_time, /* d */
+ pass_must_change_time, /* d */
+ username_len, username, /* B */
+ domain_len, domain, /* B */
+ nt_username_len, nt_username, /* B */
+ fullname_len, fullname, /* B */
+ homedir_len, homedir, /* B */
+ dir_drive_len, dir_drive, /* B */
+ logon_script_len, logon_script, /* B */
+ profile_path_len, profile_path, /* B */
+ acct_desc_len, acct_desc, /* B */
+ workstations_len, workstations, /* B */
+ comment_len, comment, /* B */
+ munged_dial_len, munged_dial, /* B */
+ user_rid, /* d */
+ group_rid, /* d */
+ lm_pw_len, lm_pw, /* B */
+ nt_pw_len, nt_pw, /* B */
+ nt_pw_hist_len, nt_pw_hist, /* B */
+ pdb_get_acct_ctrl(sampass), /* d */
+ pdb_get_logon_divs(sampass), /* w */
+ pdb_get_hours_len(sampass), /* d */
+ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
+ pdb_get_bad_password_count(sampass), /* w */
+ pdb_get_logon_count(sampass), /* w */
+ pdb_get_unknown_6(sampass)); /* d */
+
+ if (size_only) {
+ return buflen;
+ }
+
+ /* malloc the space needed */
+ if ( (*buf=(uint8_t*)SMB_MALLOC(len)) == NULL) {
+ DEBUG(0,("init_buffer_from_samu_v3: Unable to malloc() memory for buffer!\n"));
+ return (-1);
+ }
+
+ /* now for the real call to tdb_pack() */
+ buflen = tdb_pack(*buf, len, SAMU_BUFFER_FORMAT_V3,
+ logon_time, /* d */
+ logoff_time, /* d */
+ kickoff_time, /* d */
+ bad_password_time, /* d */
+ pass_last_set_time, /* d */
+ pass_can_change_time, /* d */
+ pass_must_change_time, /* d */
+ username_len, username, /* B */
+ domain_len, domain, /* B */
+ nt_username_len, nt_username, /* B */
+ fullname_len, fullname, /* B */
+ homedir_len, homedir, /* B */
+ dir_drive_len, dir_drive, /* B */
+ logon_script_len, logon_script, /* B */
+ profile_path_len, profile_path, /* B */
+ acct_desc_len, acct_desc, /* B */
+ workstations_len, workstations, /* B */
+ comment_len, comment, /* B */
+ munged_dial_len, munged_dial, /* B */
+ user_rid, /* d */
+ group_rid, /* d */
+ lm_pw_len, lm_pw, /* B */
+ nt_pw_len, nt_pw, /* B */
+ nt_pw_hist_len, nt_pw_hist, /* B */
+ pdb_get_acct_ctrl(sampass), /* d */
+ pdb_get_logon_divs(sampass), /* w */
+ pdb_get_hours_len(sampass), /* d */
+ MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
+ pdb_get_bad_password_count(sampass), /* w */
+ pdb_get_logon_count(sampass), /* w */
+ pdb_get_unknown_6(sampass)); /* d */
+
+ /* check to make sure we got it correct */
+ if (buflen != len) {
+ DEBUG(0, ("init_buffer_from_samu_v3: something odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n",
+ (unsigned long)buflen, (unsigned long)len));
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+static bool init_samu_from_buffer_v4(struct samu *sampass, uint8_t *buf, uint32_t buflen)
+{
+ /* nothing changed between V3 and V4 */
+ return init_samu_from_buffer_v3(sampass, buf, buflen);
+}
+
+static uint32_t init_buffer_from_samu_v4(uint8_t **buf, struct samu *sampass, bool size_only)
+{
+ /* nothing changed between V3 and V4 */
+ return init_buffer_from_samu_v3(buf, sampass, size_only);
+}
+
+/**********************************************************************
+ Initialize a struct samu struct from a BYTE buffer of size len
+ *********************************************************************/
+
+bool init_samu_from_buffer(struct samu *sampass, uint32_t level,
+ uint8_t *buf, uint32_t buflen)
+{
+ switch (level) {
+ case SAMU_BUFFER_V0:
+ return init_samu_from_buffer_v0(sampass, buf, buflen);
+ case SAMU_BUFFER_V1:
+ return init_samu_from_buffer_v1(sampass, buf, buflen);
+ case SAMU_BUFFER_V2:
+ return init_samu_from_buffer_v2(sampass, buf, buflen);
+ case SAMU_BUFFER_V3:
+ return init_samu_from_buffer_v3(sampass, buf, buflen);
+ case SAMU_BUFFER_V4:
+ return init_samu_from_buffer_v4(sampass, buf, buflen);
+ }
+
+ return false;
+}
+
+/**********************************************************************
+ Initialize a BYTE buffer from a struct samu struct
+ *********************************************************************/
+
+uint32_t init_buffer_from_samu (uint8_t **buf, struct samu *sampass, bool size_only)
+{
+ return init_buffer_from_samu_v4(buf, sampass, size_only);
+}
+
+/*********************************************************************
+*********************************************************************/
+
+bool pdb_copy_sam_account(struct samu *dst, struct samu *src )
+{
+ uint8_t *buf = NULL;
+ int len;
+
+ len = init_buffer_from_samu(&buf, src, False);
+ if (len == -1 || !buf) {
+ SAFE_FREE(buf);
+ return False;
+ }
+
+ if (!init_samu_from_buffer( dst, SAMU_BUFFER_LATEST, buf, len )) {
+ free(buf);
+ return False;
+ }
+
+ dst->methods = src->methods;
+
+ if ( src->unix_pw ) {
+ dst->unix_pw = tcopy_passwd( dst, src->unix_pw );
+ if (!dst->unix_pw) {
+ free(buf);
+ return False;
+ }
+ }
+
+ if (src->group_sid) {
+ pdb_set_group_sid(dst, src->group_sid, PDB_SET);
+ }
+
+ free(buf);
+ return True;
+}
+
+/*********************************************************************
+ Update the bad password count checking the PDB_POLICY_RESET_COUNT_TIME
+*********************************************************************/
+
+bool pdb_update_bad_password_count(struct samu *sampass, bool *updated)
+{
+ time_t LastBadPassword;
+ uint16_t BadPasswordCount;
+ uint32_t resettime;
+ bool res;
+
+ BadPasswordCount = pdb_get_bad_password_count(sampass);
+ if (!BadPasswordCount) {
+ DEBUG(9, ("No bad password attempts.\n"));
+ return True;
+ }
+
+ become_root();
+ res = pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &resettime);
+ unbecome_root();
+
+ if (!res) {
+ DEBUG(0, ("pdb_update_bad_password_count: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* First, check if there is a reset time to compare */
+ if ((resettime == (uint32_t) -1) || (resettime == 0)) {
+ DEBUG(9, ("No reset time, can't reset bad pw count\n"));
+ return True;
+ }
+
+ LastBadPassword = pdb_get_bad_password_time(sampass);
+ DEBUG(7, ("LastBadPassword=%d, resettime=%d, current time=%d.\n",
+ (uint32_t) LastBadPassword, resettime, (uint32_t)time(NULL)));
+ if (time(NULL) > (LastBadPassword + convert_uint32_t_to_time_t(resettime)*60)){
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ if (updated) {
+ *updated = True;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Update the ACB_AUTOLOCK flag checking the PDB_POLICY_LOCK_ACCOUNT_DURATION
+*********************************************************************/
+
+bool pdb_update_autolock_flag(struct samu *sampass, bool *updated)
+{
+ uint32_t duration;
+ time_t LastBadPassword;
+ bool res;
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK)) {
+ DEBUG(9, ("pdb_update_autolock_flag: Account %s not autolocked, no check needed\n",
+ pdb_get_username(sampass)));
+ return True;
+ }
+
+ become_root();
+ res = pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &duration);
+ unbecome_root();
+
+ if (!res) {
+ DEBUG(0, ("pdb_update_autolock_flag: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* First, check if there is a duration to compare */
+ if ((duration == (uint32_t) -1) || (duration == 0)) {
+ DEBUG(9, ("pdb_update_autolock_flag: No reset duration, can't reset autolock\n"));
+ return True;
+ }
+
+ LastBadPassword = pdb_get_bad_password_time(sampass);
+ DEBUG(7, ("pdb_update_autolock_flag: Account %s, LastBadPassword=%d, duration=%d, current time =%d.\n",
+ pdb_get_username(sampass), (uint32_t)LastBadPassword, duration*60, (uint32_t)time(NULL)));
+
+ if (LastBadPassword == (time_t)0) {
+ DEBUG(1,("pdb_update_autolock_flag: Account %s "
+ "administratively locked out with no bad password "
+ "time. Leaving locked out.\n",
+ pdb_get_username(sampass) ));
+ return True;
+ }
+
+ if ((time(NULL) > (LastBadPassword + convert_uint32_t_to_time_t(duration) * 60))) {
+ pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) & ~ACB_AUTOLOCK,
+ PDB_CHANGED);
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ if (updated) {
+ *updated = True;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Increment the bad_password_count
+*********************************************************************/
+
+bool pdb_increment_bad_password_count(struct samu *sampass)
+{
+ uint32_t account_policy_lockout;
+ bool autolock_updated = False, badpw_updated = False;
+ bool ret;
+
+ /* Retrieve the account lockout policy */
+ become_root();
+ ret = pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout);
+ unbecome_root();
+ if ( !ret ) {
+ DEBUG(0, ("pdb_increment_bad_password_count: pdb_get_account_policy failed.\n"));
+ return False;
+ }
+
+ /* If there is no policy, we don't need to continue checking */
+ if (!account_policy_lockout) {
+ DEBUG(9, ("No lockout policy, don't track bad passwords\n"));
+ return True;
+ }
+
+ /* Check if the autolock needs to be cleared */
+ if (!pdb_update_autolock_flag(sampass, &autolock_updated))
+ return False;
+
+ /* Check if the badpw count needs to be reset */
+ if (!pdb_update_bad_password_count(sampass, &badpw_updated))
+ return False;
+
+ /*
+ Ok, now we can assume that any resetting that needs to be
+ done has been done, and just get on with incrementing
+ and autolocking if necessary
+ */
+
+ pdb_set_bad_password_count(sampass,
+ pdb_get_bad_password_count(sampass)+1,
+ PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, time(NULL), PDB_CHANGED);
+
+
+ if (pdb_get_bad_password_count(sampass) < account_policy_lockout)
+ return True;
+
+ if (!pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) | ACB_AUTOLOCK,
+ PDB_CHANGED)) {
+ DEBUG(1, ("pdb_increment_bad_password_count:failed to set 'autolock' flag. \n"));
+ return False;
+ }
+
+ return True;
+}
+
+bool is_dc_trusted_domain_situation(const char *domain_name)
+{
+ return IS_DC && !strequal(domain_name, lp_workgroup());
+}
+
+/*******************************************************************
+ Wrapper around retrieving the clear text trust account password.
+ appropriate account name is stored in account_name.
+ Caller must free password, but not account_name.
+*******************************************************************/
+
+static bool get_trust_pw_clear2(const char *domain,
+ const char **account_name,
+ enum netr_SchannelType *channel,
+ char **cur_pw,
+ time_t *_last_set_time,
+ char **prev_pw)
+{
+ char *pwd;
+ time_t last_set_time;
+
+ if (cur_pw != NULL) {
+ *cur_pw = NULL;
+ }
+ if (_last_set_time != NULL) {
+ *_last_set_time = 0;
+ }
+ if (prev_pw != NULL) {
+ *prev_pw = NULL;
+ }
+
+ /* if we are a DC and this is not our domain, then lookup an account
+ * for the domain trust */
+
+ if (is_dc_trusted_domain_situation(domain)) {
+ if (!lp_allow_trusted_domains()) {
+ return false;
+ }
+
+ if (!pdb_get_trusteddom_pw(domain, cur_pw, NULL,
+ &last_set_time))
+ {
+ DEBUG(0, ("get_trust_pw: could not fetch trust "
+ "account password for trusted domain %s\n",
+ domain));
+ return false;
+ }
+
+ if (channel != NULL) {
+ *channel = SEC_CHAN_DOMAIN;
+ }
+
+ if (account_name != NULL) {
+ *account_name = lp_workgroup();
+ }
+
+ if (_last_set_time != NULL) {
+ *_last_set_time = last_set_time;
+ }
+
+ return true;
+ }
+
+ /*
+ * Since we can only be member of one single domain, we are now
+ * in a member situation:
+ *
+ * - Either we are a DC (selfjoined) and the domain is our
+ * own domain.
+ * - Or we are on a member and the domain is our own or some
+ * other (potentially trusted) domain.
+ *
+ * In both cases, we can only get the machine account password
+ * for our own domain to connect to our own dc. (For a member,
+ * request to trusted domains are performed through our dc.)
+ *
+ * So we simply use our own domain name to retrieve the
+ * machine account password and ignore the request domain here.
+ */
+
+ pwd = secrets_fetch_machine_password(lp_workgroup(), &last_set_time, channel);
+
+ if (pwd != NULL) {
+ struct timeval expire;
+
+ *cur_pw = pwd;
+
+ if (account_name != NULL) {
+ *account_name = lp_netbios_name();
+ }
+
+ if (_last_set_time != NULL) {
+ *_last_set_time = last_set_time;
+ }
+
+ if (prev_pw == NULL) {
+ return true;
+ }
+
+ ZERO_STRUCT(expire);
+ expire.tv_sec = lp_machine_password_timeout();
+ expire.tv_sec /= 2;
+ expire.tv_sec += last_set_time;
+ if (timeval_expired(&expire)) {
+ return true;
+ }
+
+ pwd = secrets_fetch_prev_machine_password(lp_workgroup());
+ if (pwd != NULL) {
+ *prev_pw = pwd;
+ }
+
+ return true;
+ }
+
+ DEBUG(5, ("get_trust_pw_clear2: could not fetch clear text trust "
+ "account password for domain %s\n", domain));
+ return false;
+}
+
+bool get_trust_pw_clear(const char *domain, char **ret_pwd,
+ const char **account_name,
+ enum netr_SchannelType *channel)
+{
+ return get_trust_pw_clear2(domain,
+ account_name,
+ channel,
+ ret_pwd,
+ NULL,
+ NULL);
+}
+
+/*******************************************************************
+ Wrapper around retrieving the trust account password.
+ appropriate account name is stored in account_name.
+*******************************************************************/
+
+static bool get_trust_pw_hash2(const char *domain,
+ const char **account_name,
+ enum netr_SchannelType *channel,
+ struct samr_Password *current_nt_hash,
+ time_t *last_set_time,
+ struct samr_Password **_previous_nt_hash)
+{
+ char *cur_pw = NULL;
+ char *prev_pw = NULL;
+ char **_prev_pw = NULL;
+ bool ok;
+
+ if (_previous_nt_hash != NULL) {
+ *_previous_nt_hash = NULL;
+ _prev_pw = &prev_pw;
+ }
+
+ ok = get_trust_pw_clear2(domain, account_name, channel,
+ &cur_pw, last_set_time, _prev_pw);
+ if (ok) {
+ struct samr_Password *previous_nt_hash = NULL;
+
+ E_md4hash(cur_pw, current_nt_hash->hash);
+ BURN_FREE_STR(cur_pw);
+
+ if (prev_pw == NULL) {
+ return true;
+ }
+
+ previous_nt_hash = SMB_MALLOC_P(struct samr_Password);
+ if (previous_nt_hash == NULL) {
+ return false;
+ }
+
+ E_md4hash(prev_pw, previous_nt_hash->hash);
+ BURN_FREE_STR(prev_pw);
+
+ *_previous_nt_hash = previous_nt_hash;
+ return true;
+ } else if (is_dc_trusted_domain_situation(domain)) {
+ return false;
+ }
+
+ /* as a fallback, try to get the hashed pwd directly from the tdb... */
+
+ if (secrets_fetch_trust_account_password_legacy(domain,
+ current_nt_hash->hash,
+ last_set_time,
+ channel))
+ {
+ if (account_name != NULL) {
+ *account_name = lp_netbios_name();
+ }
+
+ return true;
+ }
+
+ DEBUG(5, ("get_trust_pw_hash: could not fetch trust account "
+ "password for domain %s\n", domain));
+ return False;
+}
+
+bool get_trust_pw_hash(const char *domain, uint8_t ret_pwd[16],
+ const char **account_name,
+ enum netr_SchannelType *channel)
+{
+ struct samr_Password current_nt_hash;
+ bool ok;
+
+ ok = get_trust_pw_hash2(domain, account_name, channel,
+ &current_nt_hash, NULL, NULL);
+ if (!ok) {
+ return false;
+ }
+
+ memcpy(ret_pwd, current_nt_hash.hash, sizeof(current_nt_hash.hash));
+ return true;
+}
+
+NTSTATUS pdb_get_trust_credentials(const char *netbios_domain,
+ const char *dns_domain, /* optional */
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials **_creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct loadparm_context *lp_ctx;
+ enum netr_SchannelType channel;
+ time_t last_set_time;
+ const char *_account_name;
+ const char *account_name;
+ char *cur_pw = NULL;
+ char *prev_pw = NULL;
+ struct samr_Password cur_nt_hash;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+
+ /*
+ * If this is our primary trust relationship, use the common
+ * code to read the secrets.ldb or secrets.tdb file.
+ */
+ if (strequal(netbios_domain, lp_workgroup())) {
+ struct db_context *db_ctx = secrets_db_ctx();
+ if (db_ctx == NULL) {
+ DEBUG(1, ("failed to open secrets.tdb to obtain our trust credentials for %s\n",
+ netbios_domain));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ DEBUG(1, ("loadparm_init_s3 failed\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ ok = cli_credentials_set_conf(creds, lp_ctx);
+ if (!ok) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ status = cli_credentials_set_machine_account_db_ctx(creds,
+ lp_ctx,
+ db_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ goto done;
+ } else if (!IS_DC) {
+ DEBUG(1, ("Refusing to get trust account info for %s, "
+ "which is not our primary domain %s, "
+ "as we are not a DC\n",
+ netbios_domain, lp_workgroup()));
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ goto fail;
+ }
+
+ status = pdb_get_trusteddom_creds(netbios_domain, mem_ctx, &creds);
+ if (NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ goto fail;
+ }
+
+ ok = get_trust_pw_clear2(netbios_domain,
+ &_account_name,
+ &channel,
+ &cur_pw,
+ &last_set_time,
+ &prev_pw);
+ if (!ok) {
+ ok = get_trust_pw_hash2(netbios_domain,
+ &_account_name,
+ &channel,
+ &cur_nt_hash,
+ &last_set_time,
+ NULL);
+ if (!ok) {
+ DEBUG(1, ("get_trust_pw_*2 failed for domain[%s]\n",
+ netbios_domain));
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ goto fail;
+ }
+ }
+
+ account_name = talloc_asprintf(frame, "%s$", _account_name);
+ if (account_name == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ DEBUG(1, ("loadparm_init_s3 failed\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ ok = cli_credentials_set_conf(creds, lp_ctx);
+ if (!ok) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ cli_credentials_set_secure_channel_type(creds, channel);
+ cli_credentials_set_password_last_changed_time(creds, last_set_time);
+
+ ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (dns_domain != NULL) {
+ ok = cli_credentials_set_realm(creds, dns_domain, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ /*
+ * It's not possible to use NTLMSSP with a domain trust account.
+ */
+ cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+ } else {
+ /*
+ * We can't use kerberos against an NT4 domain.
+ *
+ * We should have a mode that also disallows NTLMSSP here,
+ * as only NETLOGON SCHANNEL is possible.
+ */
+ cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+ }
+
+ ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (cur_pw == NULL) {
+ ok = cli_credentials_set_nt_hash(creds, &cur_nt_hash, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ /*
+ * We currently can't do kerberos just with an NTHASH.
+ */
+ cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+ goto done;
+ }
+
+ ok = cli_credentials_set_password(creds, cur_pw, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (prev_pw != NULL) {
+ ok = cli_credentials_set_old_password(creds, prev_pw, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
+
+ done:
+ *_creds = creds;
+ creds = NULL;
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(creds);
+ SAFE_FREE(cur_pw);
+ SAFE_FREE(prev_pw);
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/source3/passdb/pdb_compat.c b/source3/passdb/pdb_compat.c
new file mode 100644
index 0000000..2a32ec8
--- /dev/null
+++ b/source3/passdb/pdb_compat.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu access routines
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "passdb.h"
+#include "../libcli/security/security.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+uint32_t pdb_get_user_rid (const struct samu *sampass)
+{
+ uint32_t u_rid;
+
+ if (sampass)
+ if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_user_sid(sampass),&u_rid))
+ return u_rid;
+
+ return (0);
+}
+
+uint32_t pdb_get_group_rid (struct samu *sampass)
+{
+ uint32_t g_rid;
+
+ if (sampass)
+ if (sid_peek_check_rid(get_global_sam_sid(), pdb_get_group_sid(sampass),&g_rid))
+ return g_rid;
+ return (0);
+}
+
+bool pdb_set_user_sid_from_rid (struct samu *sampass, uint32_t rid, enum pdb_value_state flag)
+{
+ struct dom_sid u_sid;
+ struct dom_sid_buf buf;
+ const struct dom_sid *global_sam_sid;
+
+ if (!sampass)
+ return False;
+
+ if (!(global_sam_sid = get_global_sam_sid())) {
+ DEBUG(1, ("pdb_set_user_sid_from_rid: Could not read global sam sid!\n"));
+ return False;
+ }
+
+ if (!sid_compose(&u_sid, global_sam_sid, rid)) {
+ return False;
+ }
+
+ if (!pdb_set_user_sid(sampass, &u_sid, flag))
+ return False;
+
+ DEBUG(10, ("pdb_set_user_sid_from_rid:\n\tsetting user sid %s from rid %d\n",
+ dom_sid_str_buf(&u_sid, &buf), rid));
+
+ return True;
+}
+
+bool pdb_set_group_sid_from_rid (struct samu *sampass, uint32_t grid, enum pdb_value_state flag)
+{
+ struct dom_sid g_sid;
+ struct dom_sid_buf buf;
+ const struct dom_sid *global_sam_sid;
+
+ if (!sampass)
+ return False;
+
+ if (!(global_sam_sid = get_global_sam_sid())) {
+ DEBUG(1, ("pdb_set_user_sid_from_rid: Could not read global sam sid!\n"));
+ return False;
+ }
+
+ if (!sid_compose(&g_sid, global_sam_sid, grid)) {
+ return False;
+ }
+
+ if (!pdb_set_group_sid(sampass, &g_sid, flag))
+ return False;
+
+ DEBUG(10, ("pdb_set_group_sid_from_rid:\n\tsetting group sid %s from rid %d\n",
+ dom_sid_str_buf(&g_sid, &buf), grid));
+
+ return True;
+}
+
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
new file mode 100644
index 0000000..6789cc0
--- /dev/null
+++ b/source3/passdb/pdb_get_set.c
@@ -0,0 +1,1163 @@
+/*
+ Unix SMB/CIFS implementation.
+ struct samu access routines
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2006
+ Copyright (C) Andrew Bartlett 2001-2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "passdb.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../libcli/security/security.h"
+#include "../lib/util/bitmap.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/**
+ * @todo Redefine this to NULL, but this changes the API because
+ * much of samba assumes that the pdb_get...() functions
+ * return strings. (ie not null-pointers).
+ * See also pdb_fill_default_sam().
+ */
+
+#define PDB_NOT_QUITE_NULL ""
+
+/*********************************************************************
+ Test if a change time is a max value. Copes with old and new values
+ of max.
+ ********************************************************************/
+
+bool pdb_is_password_change_time_max(time_t test_time)
+{
+ if (test_time == get_time_t_max()) {
+ return true;
+ }
+#if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
+ if (test_time == 0x7FFFFFFFFFFFFFFFLL) {
+ return true;
+ }
+#endif
+ if (test_time == 0x7FFFFFFF) {
+ return true;
+ }
+ return false;
+}
+
+/*********************************************************************
+ Return an unchanging version of max password change time - 0x7FFFFFFF.
+ ********************************************************************/
+
+static time_t pdb_password_change_time_max(void)
+{
+ return 0x7FFFFFFF;
+}
+
+/*********************************************************************
+ Collection of get...() functions for struct samu.
+ ********************************************************************/
+
+uint32_t pdb_get_acct_ctrl(const struct samu *sampass)
+{
+ return sampass->acct_ctrl;
+}
+
+time_t pdb_get_logon_time(const struct samu *sampass)
+{
+ return sampass->logon_time;
+}
+
+time_t pdb_get_logoff_time(const struct samu *sampass)
+{
+ return sampass->logoff_time;
+}
+
+time_t pdb_get_kickoff_time(const struct samu *sampass)
+{
+ return sampass->kickoff_time;
+}
+
+time_t pdb_get_bad_password_time(const struct samu *sampass)
+{
+ return sampass->bad_password_time;
+}
+
+time_t pdb_get_pass_last_set_time(const struct samu *sampass)
+{
+ return sampass->pass_last_set_time;
+}
+
+time_t pdb_get_pass_can_change_time(const struct samu *sampass)
+{
+ uint32_t allow;
+
+ /* if the last set time is zero, it means the user cannot
+ change their password, and this time must be zero. jmcd
+ */
+ if (sampass->pass_last_set_time == 0)
+ return (time_t) 0;
+
+ /* if the time is max, and the field has been changed,
+ we're trying to update this real value from the sampass
+ to indicate that the user cannot change their password. jmcd
+ */
+ if (pdb_is_password_change_time_max(sampass->pass_can_change_time) &&
+ IS_SAM_CHANGED(sampass, PDB_CANCHANGETIME))
+ return sampass->pass_can_change_time;
+
+ if (!pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &allow))
+ allow = 0;
+
+ /* in normal cases, just calculate it from policy */
+ return sampass->pass_last_set_time + allow;
+}
+
+/* we need this for loading from the backend, so that we don't overwrite
+ non-changed max times, otherwise the pass_can_change checking won't work */
+time_t pdb_get_pass_can_change_time_noncalc(const struct samu *sampass)
+{
+ return sampass->pass_can_change_time;
+}
+
+time_t pdb_get_pass_must_change_time(const struct samu *sampass)
+{
+ uint32_t expire;
+
+ if (sampass->pass_last_set_time == 0)
+ return (time_t) 0;
+
+ if (sampass->acct_ctrl & ACB_PWNOEXP)
+ return pdb_password_change_time_max();
+
+ if (!pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &expire)
+ || expire == (uint32_t)-1 || expire == 0)
+ return get_time_t_max();
+
+ return sampass->pass_last_set_time + expire;
+}
+
+bool pdb_get_pass_can_change(const struct samu *sampass)
+{
+ if (pdb_is_password_change_time_max(sampass->pass_can_change_time))
+ return False;
+ return True;
+}
+
+uint16_t pdb_get_logon_divs(const struct samu *sampass)
+{
+ return sampass->logon_divs;
+}
+
+uint32_t pdb_get_hours_len(const struct samu *sampass)
+{
+ return sampass->hours_len;
+}
+
+const uint8_t *pdb_get_hours(const struct samu *sampass)
+{
+ return (sampass->hours);
+}
+
+const uint8_t *pdb_get_nt_passwd(const struct samu *sampass)
+{
+ SMB_ASSERT((!sampass->nt_pw.data)
+ || sampass->nt_pw.length == NT_HASH_LEN);
+ return (uint8_t *)sampass->nt_pw.data;
+}
+
+const uint8_t *pdb_get_lanman_passwd(const struct samu *sampass)
+{
+ SMB_ASSERT((!sampass->lm_pw.data)
+ || sampass->lm_pw.length == LM_HASH_LEN);
+ return (uint8_t *)sampass->lm_pw.data;
+}
+
+const uint8_t *pdb_get_pw_history(const struct samu *sampass, uint32_t *current_hist_len)
+{
+ SMB_ASSERT((!sampass->nt_pw_his.data)
+ || ((sampass->nt_pw_his.length % PW_HISTORY_ENTRY_LEN) == 0));
+ *current_hist_len = sampass->nt_pw_his.length / PW_HISTORY_ENTRY_LEN;
+ return (uint8_t *)sampass->nt_pw_his.data;
+}
+
+/* Return the plaintext password if known. Most of the time
+ it isn't, so don't assume anything magic about this function.
+
+ Used to pass the plaintext to passdb backends that might
+ want to store more than just the NTLM hashes.
+*/
+const char *pdb_get_plaintext_passwd(const struct samu *sampass)
+{
+ return sampass->plaintext_pw;
+}
+
+const struct dom_sid *pdb_get_user_sid(const struct samu *sampass)
+{
+ return &sampass->user_sid;
+}
+
+const struct dom_sid *pdb_get_group_sid(struct samu *sampass)
+{
+ NTSTATUS status;
+
+ /* Return the cached group SID if we have that */
+ if (sampass->group_sid) {
+ return sampass->group_sid;
+ }
+
+ /* No algorithmic mapping, meaning that we have to figure out the
+ primary group SID according to group mapping and the user SID must
+ be a newly allocated one. We rely on the user's Unix primary gid.
+ We have no choice but to fail if we can't find it. */
+ status = get_primary_group_sid(sampass,
+ pdb_get_username(sampass),
+ &sampass->unix_pw,
+ &sampass->group_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return sampass->group_sid;
+}
+
+/**
+ * Get flags showing what is initialised in the struct samu
+ * @param sampass the struct samu in question
+ * @return the flags indicating the members initialised in the struct.
+ **/
+
+enum pdb_value_state pdb_get_init_flags(const struct samu *sampass, enum pdb_elements element)
+{
+ enum pdb_value_state ret = PDB_DEFAULT;
+
+ if (!sampass->change_flags || !sampass->set_flags)
+ return ret;
+
+ if (bitmap_query(sampass->set_flags, element)) {
+ DEBUG(11, ("element %d: SET\n", element));
+ ret = PDB_SET;
+ }
+
+ if (bitmap_query(sampass->change_flags, element)) {
+ DEBUG(11, ("element %d: CHANGED\n", element));
+ ret = PDB_CHANGED;
+ }
+
+ if (ret == PDB_DEFAULT) {
+ DEBUG(11, ("element %d: DEFAULT\n", element));
+ }
+
+ return ret;
+}
+
+const char *pdb_get_username(const struct samu *sampass)
+{
+ return sampass->username;
+}
+
+const char *pdb_get_domain(const struct samu *sampass)
+{
+ return sampass->domain;
+}
+
+const char *pdb_get_nt_username(const struct samu *sampass)
+{
+ return sampass->nt_username;
+}
+
+const char *pdb_get_fullname(const struct samu *sampass)
+{
+ return sampass->full_name;
+}
+
+const char *pdb_get_homedir(const struct samu *sampass)
+{
+ return sampass->home_dir;
+}
+
+const char *pdb_get_dir_drive(const struct samu *sampass)
+{
+ return sampass->dir_drive;
+}
+
+const char *pdb_get_logon_script(const struct samu *sampass)
+{
+ return sampass->logon_script;
+}
+
+const char *pdb_get_profile_path(const struct samu *sampass)
+{
+ return sampass->profile_path;
+}
+
+const char *pdb_get_acct_desc(const struct samu *sampass)
+{
+ return sampass->acct_desc;
+}
+
+const char *pdb_get_workstations(const struct samu *sampass)
+{
+ return sampass->workstations;
+}
+
+const char *pdb_get_comment(const struct samu *sampass)
+{
+ return sampass->comment;
+}
+
+const char *pdb_get_munged_dial(const struct samu *sampass)
+{
+ return sampass->munged_dial;
+}
+
+uint16_t pdb_get_bad_password_count(const struct samu *sampass)
+{
+ return sampass->bad_password_count;
+}
+
+uint16_t pdb_get_logon_count(const struct samu *sampass)
+{
+ return sampass->logon_count;
+}
+
+uint16_t pdb_get_country_code(const struct samu *sampass)
+{
+ return sampass->country_code;
+}
+
+uint16_t pdb_get_code_page(const struct samu *sampass)
+{
+ return sampass->code_page;
+}
+
+uint32_t pdb_get_unknown_6(const struct samu *sampass)
+{
+ return sampass->unknown_6;
+}
+
+void *pdb_get_backend_private_data(const struct samu *sampass, const struct pdb_methods *my_methods)
+{
+ if (my_methods == sampass->backend_private_methods) {
+ return sampass->backend_private_data;
+ } else {
+ return NULL;
+ }
+}
+
+/*********************************************************************
+ Collection of set...() functions for struct samu.
+ ********************************************************************/
+
+bool pdb_set_acct_ctrl(struct samu *sampass, uint32_t acct_ctrl, enum pdb_value_state flag)
+{
+ sampass->acct_ctrl = acct_ctrl;
+ return pdb_set_init_flags(sampass, PDB_ACCTCTRL, flag);
+}
+
+bool pdb_set_logon_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->logon_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_LOGONTIME, flag);
+}
+
+bool pdb_set_logoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->logoff_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_LOGOFFTIME, flag);
+}
+
+bool pdb_set_kickoff_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->kickoff_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_KICKOFFTIME, flag);
+}
+
+bool pdb_set_bad_password_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->bad_password_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_TIME, flag);
+}
+
+bool pdb_set_pass_can_change_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->pass_can_change_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_CANCHANGETIME, flag);
+}
+
+bool pdb_set_pass_last_set_time(struct samu *sampass, time_t mytime, enum pdb_value_state flag)
+{
+ sampass->pass_last_set_time = mytime;
+ return pdb_set_init_flags(sampass, PDB_PASSLASTSET, flag);
+}
+
+bool pdb_set_hours_len(struct samu *sampass, uint32_t len, enum pdb_value_state flag)
+{
+ sampass->hours_len = len;
+ return pdb_set_init_flags(sampass, PDB_HOURSLEN, flag);
+}
+
+bool pdb_set_logon_divs(struct samu *sampass, uint16_t hours, enum pdb_value_state flag)
+{
+ sampass->logon_divs = hours;
+ return pdb_set_init_flags(sampass, PDB_LOGONDIVS, flag);
+}
+
+/**
+ * Set flags showing what is initialised in the struct samu
+ * @param sampass the struct samu in question
+ * @param flag The *new* flag to be set. Old flags preserved
+ * this flag is only added.
+ **/
+
+bool pdb_set_init_flags(struct samu *sampass, enum pdb_elements element, enum pdb_value_state value_flag)
+{
+ if (!sampass->set_flags) {
+ if ((sampass->set_flags =
+ bitmap_talloc(sampass,
+ PDB_COUNT))==NULL) {
+ DEBUG(0,("bitmap_talloc failed\n"));
+ return False;
+ }
+ }
+ if (!sampass->change_flags) {
+ if ((sampass->change_flags =
+ bitmap_talloc(sampass,
+ PDB_COUNT))==NULL) {
+ DEBUG(0,("bitmap_talloc failed\n"));
+ return False;
+ }
+ }
+
+ switch(value_flag) {
+ case PDB_CHANGED:
+ if (!bitmap_set(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_set(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now CHANGED\n", element));
+ break;
+ case PDB_SET:
+ if (!bitmap_clear(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_set(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now SET\n", element));
+ break;
+ case PDB_DEFAULT:
+ default:
+ if (!bitmap_clear(sampass->change_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in change_flags.\n",element));
+ return False;
+ }
+ if (!bitmap_clear(sampass->set_flags, element)) {
+ DEBUG(0,("Can't set flag: %d in set_flags.\n",element));
+ return False;
+ }
+ DEBUG(11, ("element %d -> now DEFAULT\n", element));
+ break;
+ }
+
+ return True;
+}
+
+bool pdb_set_user_sid(struct samu *sampass, const struct dom_sid *u_sid, enum pdb_value_state flag)
+{
+ struct dom_sid_buf buf;
+
+ if (!u_sid)
+ return False;
+
+ sid_copy(&sampass->user_sid, u_sid);
+
+ DEBUG(10, ("pdb_set_user_sid: setting user sid %s\n",
+ dom_sid_str_buf(&sampass->user_sid, &buf)));
+
+ return pdb_set_init_flags(sampass, PDB_USERSID, flag);
+}
+
+bool pdb_set_user_sid_from_string(struct samu *sampass, const char *u_sid, enum pdb_value_state flag)
+{
+ struct dom_sid new_sid;
+
+ if (!u_sid)
+ return False;
+
+ DEBUG(10, ("pdb_set_user_sid_from_string: setting user sid %s\n",
+ u_sid));
+
+ if (!string_to_sid(&new_sid, u_sid)) {
+ DEBUG(1, ("pdb_set_user_sid_from_string: %s isn't a valid SID!\n", u_sid));
+ return False;
+ }
+
+ if (!pdb_set_user_sid(sampass, &new_sid, flag)) {
+ DEBUG(1, ("pdb_set_user_sid_from_string: could not set sid %s on struct samu!\n", u_sid));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ We never fill this in from a passdb backend but rather set is
+ based on the user's primary group membership. However, the
+ struct samu* is overloaded and reused in domain memship code
+ as well and built from the netr_SamInfo3 or PAC so we
+ have to allow the explicitly setting of a group SID here.
+********************************************************************/
+
+bool pdb_set_group_sid(struct samu *sampass, const struct dom_sid *g_sid, enum pdb_value_state flag)
+{
+ gid_t gid;
+ struct dom_sid dug_sid;
+ struct dom_sid_buf buf;
+
+ if (!g_sid)
+ return False;
+
+ if ( !(sampass->group_sid = talloc( sampass, struct dom_sid )) ) {
+ return False;
+ }
+
+ /* if we cannot resolve the SID to gid, then just ignore it and
+ store DOMAIN_USERS as the primary groupSID */
+
+ sid_compose(&dug_sid, get_global_sam_sid(), DOMAIN_RID_USERS);
+
+ if (dom_sid_equal(&dug_sid, g_sid)) {
+ sid_copy(sampass->group_sid, &dug_sid);
+ } else if (sid_to_gid( g_sid, &gid ) ) {
+ sid_copy(sampass->group_sid, g_sid);
+ } else {
+ sid_copy(sampass->group_sid, &dug_sid);
+ }
+
+ DEBUG(10, ("pdb_set_group_sid: setting group sid %s\n",
+ dom_sid_str_buf(sampass->group_sid, &buf)));
+
+ return pdb_set_init_flags(sampass, PDB_GROUPSID, flag);
+}
+
+/*********************************************************************
+ Set the user's UNIX name.
+ ********************************************************************/
+
+bool pdb_set_username(struct samu *sampass, const char *username, enum pdb_value_state flag)
+{
+ if (username) {
+ DEBUG(10, ("pdb_set_username: setting username %s, was %s\n", username,
+ (sampass->username)?(sampass->username):"NULL"));
+
+ sampass->username = talloc_strdup(sampass, username);
+
+ if (!sampass->username) {
+ DEBUG(0, ("pdb_set_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->username = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_USERNAME, flag);
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+bool pdb_set_domain(struct samu *sampass, const char *domain, enum pdb_value_state flag)
+{
+ if (domain) {
+ DEBUG(10, ("pdb_set_domain: setting domain %s, was %s\n", domain,
+ (sampass->domain)?(sampass->domain):"NULL"));
+
+ sampass->domain = talloc_strdup(sampass, domain);
+
+ if (!sampass->domain) {
+ DEBUG(0, ("pdb_set_domain: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->domain = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_DOMAIN, flag);
+}
+
+/*********************************************************************
+ Set the user's NT name.
+ ********************************************************************/
+
+bool pdb_set_nt_username(struct samu *sampass, const char *nt_username, enum pdb_value_state flag)
+{
+ if (nt_username) {
+ DEBUG(10, ("pdb_set_nt_username: setting nt username %s, was %s\n", nt_username,
+ (sampass->nt_username)?(sampass->nt_username):"NULL"));
+
+ sampass->nt_username = talloc_strdup(sampass, nt_username);
+
+ if (!sampass->nt_username) {
+ DEBUG(0, ("pdb_set_nt_username: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->nt_username = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_NTUSERNAME, flag);
+}
+
+/*********************************************************************
+ Set the user's full name.
+ ********************************************************************/
+
+bool pdb_set_fullname(struct samu *sampass, const char *full_name, enum pdb_value_state flag)
+{
+ if (full_name) {
+ DEBUG(10, ("pdb_set_full_name: setting full name %s, was %s\n", full_name,
+ (sampass->full_name)?(sampass->full_name):"NULL"));
+
+ sampass->full_name = talloc_strdup(sampass, full_name);
+
+ if (!sampass->full_name) {
+ DEBUG(0, ("pdb_set_fullname: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->full_name = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_FULLNAME, flag);
+}
+
+/*********************************************************************
+ Set the user's logon script.
+ ********************************************************************/
+
+bool pdb_set_logon_script(struct samu *sampass, const char *logon_script, enum pdb_value_state flag)
+{
+ if (logon_script) {
+ DEBUG(10, ("pdb_set_logon_script: setting logon script %s, was %s\n", logon_script,
+ (sampass->logon_script)?(sampass->logon_script):"NULL"));
+
+ sampass->logon_script = talloc_strdup(sampass, logon_script);
+
+ if (!sampass->logon_script) {
+ DEBUG(0, ("pdb_set_logon_script: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->logon_script = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_LOGONSCRIPT, flag);
+}
+
+/*********************************************************************
+ Set the user's profile path.
+ ********************************************************************/
+
+bool pdb_set_profile_path(struct samu *sampass, const char *profile_path, enum pdb_value_state flag)
+{
+ if (profile_path) {
+ DEBUG(10, ("pdb_set_profile_path: setting profile path %s, was %s\n", profile_path,
+ (sampass->profile_path)?(sampass->profile_path):"NULL"));
+
+ sampass->profile_path = talloc_strdup(sampass, profile_path);
+
+ if (!sampass->profile_path) {
+ DEBUG(0, ("pdb_set_profile_path: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->profile_path = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PROFILE, flag);
+}
+
+/*********************************************************************
+ Set the user's directory drive.
+ ********************************************************************/
+
+bool pdb_set_dir_drive(struct samu *sampass, const char *dir_drive, enum pdb_value_state flag)
+{
+ if (dir_drive) {
+ DEBUG(10, ("pdb_set_dir_drive: setting dir drive %s, was %s\n", dir_drive,
+ (sampass->dir_drive)?(sampass->dir_drive):"NULL"));
+
+ sampass->dir_drive = talloc_strdup(sampass, dir_drive);
+
+ if (!sampass->dir_drive) {
+ DEBUG(0, ("pdb_set_dir_drive: talloc_strdup() failed!\n"));
+ return False;
+ }
+
+ } else {
+ sampass->dir_drive = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_DRIVE, flag);
+}
+
+/*********************************************************************
+ Set the user's home directory.
+ ********************************************************************/
+
+bool pdb_set_homedir(struct samu *sampass, const char *home_dir, enum pdb_value_state flag)
+{
+ if (home_dir) {
+ DEBUG(10, ("pdb_set_homedir: setting home dir %s, was %s\n", home_dir,
+ (sampass->home_dir)?(sampass->home_dir):"NULL"));
+
+ sampass->home_dir = talloc_strdup(sampass, home_dir);
+
+ if (!sampass->home_dir) {
+ DEBUG(0, ("pdb_set_home_dir: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->home_dir = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_SMBHOME, flag);
+}
+
+/*********************************************************************
+ Set the user's account description.
+ ********************************************************************/
+
+bool pdb_set_acct_desc(struct samu *sampass, const char *acct_desc, enum pdb_value_state flag)
+{
+ if (acct_desc) {
+ sampass->acct_desc = talloc_strdup(sampass, acct_desc);
+
+ if (!sampass->acct_desc) {
+ DEBUG(0, ("pdb_set_acct_desc: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->acct_desc = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_ACCTDESC, flag);
+}
+
+/*********************************************************************
+ Set the user's workstation allowed list.
+ ********************************************************************/
+
+bool pdb_set_workstations(struct samu *sampass, const char *workstations, enum pdb_value_state flag)
+{
+ if (workstations) {
+ DEBUG(10, ("pdb_set_workstations: setting workstations %s, was %s\n", workstations,
+ (sampass->workstations)?(sampass->workstations):"NULL"));
+
+ sampass->workstations = talloc_strdup(sampass, workstations);
+
+ if (!sampass->workstations) {
+ DEBUG(0, ("pdb_set_workstations: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->workstations = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_WORKSTATIONS, flag);
+}
+
+/*********************************************************************
+ ********************************************************************/
+
+bool pdb_set_comment(struct samu *sampass, const char *comment, enum pdb_value_state flag)
+{
+ if (comment) {
+ sampass->comment = talloc_strdup(sampass, comment);
+
+ if (!sampass->comment) {
+ DEBUG(0, ("pdb_set_comment: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->comment = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_COMMENT, flag);
+}
+
+/*********************************************************************
+ Set the user's dial string.
+ ********************************************************************/
+
+bool pdb_set_munged_dial(struct samu *sampass, const char *munged_dial, enum pdb_value_state flag)
+{
+ if (munged_dial) {
+ sampass->munged_dial = talloc_strdup(sampass, munged_dial);
+
+ if (!sampass->munged_dial) {
+ DEBUG(0, ("pdb_set_munged_dial: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->munged_dial = PDB_NOT_QUITE_NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_MUNGEDDIAL, flag);
+}
+
+/*********************************************************************
+ Set the user's NT hash.
+ ********************************************************************/
+
+bool pdb_set_nt_passwd(struct samu *sampass, const uint8_t pwd[NT_HASH_LEN], enum pdb_value_state flag)
+{
+ data_blob_clear_free(&sampass->nt_pw);
+
+ if (pwd) {
+ sampass->nt_pw =
+ data_blob_talloc(sampass, pwd, NT_HASH_LEN);
+ } else {
+ sampass->nt_pw = data_blob_null;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_NTPASSWD, flag);
+}
+
+/*********************************************************************
+ Set the user's LM hash.
+ ********************************************************************/
+
+bool pdb_set_lanman_passwd(struct samu *sampass, const uint8_t pwd[LM_HASH_LEN], enum pdb_value_state flag)
+{
+ data_blob_clear_free(&sampass->lm_pw);
+
+ /* on keep the password if we are allowing LANMAN authentication */
+
+ if (pwd && lp_lanman_auth() ) {
+ sampass->lm_pw = data_blob_talloc(sampass, pwd, LM_HASH_LEN);
+ } else {
+ sampass->lm_pw = data_blob_null;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_LMPASSWD, flag);
+}
+
+/*********************************************************************
+ Set the user's password history hash. historyLen is the number of
+ PW_HISTORY_SALT_LEN+SALTED_MD5_HASH_LEN length
+ entries to store in the history - this must match the size of the uint8_t array
+ in pwd.
+********************************************************************/
+
+bool pdb_set_pw_history(struct samu *sampass, const uint8_t *pwd, uint32_t historyLen, enum pdb_value_state flag)
+{
+ DATA_BLOB new_nt_pw_his = {};
+
+ if (historyLen && pwd){
+ new_nt_pw_his = data_blob_talloc(sampass,
+ pwd, historyLen*PW_HISTORY_ENTRY_LEN);
+ if (new_nt_pw_his.length == 0) {
+ DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n"));
+ return False;
+ }
+ }
+
+ data_blob_clear_free(&sampass->nt_pw_his);
+ sampass->nt_pw_his = new_nt_pw_his;
+
+ return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag);
+}
+
+/*********************************************************************
+ Set the user's plaintext password only (base procedure, see helper
+ below)
+ ********************************************************************/
+
+bool pdb_set_plaintext_pw_only(struct samu *sampass, const char *password, enum pdb_value_state flag)
+{
+ BURN_STR(sampass->plaintext_pw);
+
+ if (password != NULL) {
+ sampass->plaintext_pw = talloc_strdup(sampass, password);
+
+ if (!sampass->plaintext_pw) {
+ DEBUG(0, ("pdb_set_unknown_str: talloc_strdup() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->plaintext_pw = NULL;
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PLAINTEXT_PW, flag);
+}
+
+bool pdb_set_bad_password_count(struct samu *sampass, uint16_t bad_password_count, enum pdb_value_state flag)
+{
+ sampass->bad_password_count = bad_password_count;
+ return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_COUNT, flag);
+}
+
+bool pdb_set_logon_count(struct samu *sampass, uint16_t logon_count, enum pdb_value_state flag)
+{
+ sampass->logon_count = logon_count;
+ return pdb_set_init_flags(sampass, PDB_LOGON_COUNT, flag);
+}
+
+bool pdb_set_country_code(struct samu *sampass, uint16_t country_code,
+ enum pdb_value_state flag)
+{
+ sampass->country_code = country_code;
+ return pdb_set_init_flags(sampass, PDB_COUNTRY_CODE, flag);
+}
+
+bool pdb_set_code_page(struct samu *sampass, uint16_t code_page,
+ enum pdb_value_state flag)
+{
+ sampass->code_page = code_page;
+ return pdb_set_init_flags(sampass, PDB_CODE_PAGE, flag);
+}
+
+bool pdb_set_unknown_6(struct samu *sampass, uint32_t unkn, enum pdb_value_state flag)
+{
+ sampass->unknown_6 = unkn;
+ return pdb_set_init_flags(sampass, PDB_UNKNOWN6, flag);
+}
+
+bool pdb_set_hours(struct samu *sampass, const uint8_t *hours, int hours_len,
+ enum pdb_value_state flag)
+{
+ if (hours_len > sizeof(sampass->hours)) {
+ return false;
+ }
+
+ if (!hours) {
+ memset ((char *)sampass->hours, 0, hours_len);
+ } else {
+ memcpy (sampass->hours, hours, hours_len);
+ }
+
+ return pdb_set_init_flags(sampass, PDB_HOURS, flag);
+}
+
+bool pdb_set_backend_private_data(struct samu *sampass, void *private_data,
+ void (*free_fn)(void **),
+ const struct pdb_methods *my_methods,
+ enum pdb_value_state flag)
+{
+ if (sampass->backend_private_data &&
+ sampass->backend_private_data_free_fn) {
+ sampass->backend_private_data_free_fn(
+ &sampass->backend_private_data);
+ }
+
+ sampass->backend_private_data = private_data;
+ sampass->backend_private_data_free_fn = free_fn;
+ sampass->backend_private_methods = my_methods;
+
+ return pdb_set_init_flags(sampass, PDB_BACKEND_PRIVATE_DATA, flag);
+}
+
+
+/* Helpful interfaces to the above */
+
+bool pdb_set_pass_can_change(struct samu *sampass, bool canchange)
+{
+ return pdb_set_pass_can_change_time(sampass,
+ canchange ? 0 : pdb_password_change_time_max(),
+ PDB_CHANGED);
+}
+
+
+/*********************************************************************
+ Set the user's PLAINTEXT password. Used as an interface to the above.
+ Also sets the last change time to NOW.
+ ********************************************************************/
+
+bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
+{
+ uchar new_lanman_p16[LM_HASH_LEN];
+ uchar new_nt_p16[NT_HASH_LEN];
+ bool ok;
+
+ if (!plaintext)
+ return False;
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ E_md4hash(plaintext, new_nt_p16);
+
+ if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) {
+ ZERO_STRUCT(new_nt_p16);
+ return False;
+ }
+
+ if (!E_deshash(plaintext, new_lanman_p16)) {
+ /* E_deshash returns false for 'long' passwords (> 14
+ DOS chars). This allows us to match Win2k, which
+ does not store a LM hash for these passwords (which
+ would reduce the effective password length to 14 */
+
+ if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) {
+ ZERO_STRUCT(new_nt_p16);
+ ZERO_STRUCT(new_lanman_p16);
+ return False;
+ }
+ } else {
+ if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED)) {
+ ZERO_STRUCT(new_nt_p16);
+ ZERO_STRUCT(new_lanman_p16);
+ return False;
+ }
+ }
+ ZERO_STRUCT(new_lanman_p16);
+
+ if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED)) {
+ ZERO_STRUCT(new_nt_p16);
+ return False;
+ }
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) {
+ ZERO_STRUCT(new_nt_p16);
+ return False;
+ }
+
+ ok = pdb_update_history(sampass, new_nt_p16);
+ ZERO_STRUCT(new_nt_p16);
+ return ok;
+}
+
+/*********************************************************************
+ Update password history after change
+ ********************************************************************/
+
+bool pdb_update_history(struct samu *sampass, const uint8_t new_nt[NT_HASH_LEN])
+{
+ uchar *pwhistory;
+ uint32_t pwHistLen;
+ uint32_t current_history_len;
+ const uint8_t *current_history;
+
+ if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) {
+ /*
+ * No password history for non-user accounts
+ */
+ return true;
+ }
+
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+
+ if (pwHistLen == 0) {
+ /* Set the history length to zero. */
+ pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
+ return true;
+ }
+
+ /*
+ * 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 struct samu struct
+ * and now.... JRA.
+ */
+ current_history = pdb_get_pw_history(sampass, &current_history_len);
+ if ((current_history_len != 0) && (current_history == NULL)) {
+ DEBUG(1, ("pdb_update_history: pwhistory == NULL!\n"));
+ return false;
+ }
+
+ /*
+ * Ensure we have space for the needed history. This
+ * also takes care of an account which did not have
+ * any history at all so far, i.e. pwhistory==NULL
+ */
+ pwhistory = talloc_zero_array(
+ sampass, uchar,
+ pwHistLen*PW_HISTORY_ENTRY_LEN);
+ if (!pwhistory) {
+ return false;
+ }
+
+ memcpy(pwhistory, current_history,
+ current_history_len*PW_HISTORY_ENTRY_LEN);
+
+ /*
+ * Make room for the new password in the history list.
+ */
+ if (pwHistLen > 1) {
+ memmove(&pwhistory[PW_HISTORY_ENTRY_LEN], pwhistory,
+ (pwHistLen-1)*PW_HISTORY_ENTRY_LEN );
+ }
+
+ /*
+ * Fill the salt area with 0-s: this indicates that
+ * a plain nt hash is stored in the has area.
+ * The old format was to store a 16 byte salt and
+ * then an md5hash of the nt_hash concatenated with
+ * the salt.
+ */
+ memset(pwhistory, 0, PW_HISTORY_SALT_LEN);
+
+ /*
+ * Store the plain nt hash in the second 16 bytes.
+ * The old format was to store the md5 hash of
+ * the salt+newpw.
+ */
+ memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt, SALTED_MD5_HASH_LEN);
+
+ pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
+
+ return True;
+
+}
+
+/* check for any PDB_SET/CHANGED field and fill the appropriate mask bit */
+uint32_t pdb_build_fields_present(struct samu *sampass)
+{
+ /* value set to all for testing */
+ return 0x00ffffff;
+}
+
+/**********************************************************************
+ Helper function to determine for update_sam_account whether
+ we need LDAP modification.
+*********************************************************************/
+
+bool pdb_element_is_changed(const struct samu *sampass,
+ enum pdb_elements element)
+{
+ return IS_SAM_CHANGED(sampass, element);
+}
+
+/**********************************************************************
+ Helper function to determine for update_sam_account whether
+ we need LDAP modification.
+ *********************************************************************/
+
+bool pdb_element_is_set_or_changed(const struct samu *sampass,
+ enum pdb_elements element)
+{
+ return (IS_SAM_SET(sampass, element) ||
+ IS_SAM_CHANGED(sampass, element));
+}
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
new file mode 100644
index 0000000..d3648f1
--- /dev/null
+++ b/source3/passdb/pdb_interface.c
@@ -0,0 +1,2713 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/passwd.h"
+#include "passdb.h"
+#include "secrets.h"
+#include "messages.h"
+#include "serverid.h"
+#include "../librpc/gen_ndr/samr.h"
+#include "../librpc/gen_ndr/drsblobs.h"
+#include "../librpc/gen_ndr/ndr_drsblobs.h"
+#include "../librpc/gen_ndr/idmap.h"
+#include "../lib/util/memcache.h"
+#include "nsswitch/winbind_client.h"
+#include "../libcli/security/security.h"
+#include "../lib/util/util_pw.h"
+#include "passdb/pdb_secrets.h"
+#include "lib/util_sid_passdb.h"
+#include "idmap_cache.h"
+#include "lib/util/string_wrappers.h"
+#include "lib/global_contexts.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+static_decl_pdb;
+
+static struct pdb_init_function_entry *backends = NULL;
+
+static void lazy_initialize_passdb(void)
+{
+ static bool initialized = False;
+ if(initialized) {
+ return;
+ }
+ static_init_pdb(NULL);
+ initialized = True;
+}
+
+static bool lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32_t rid,
+ const char **name,
+ enum lsa_SidType *psid_name_use,
+ uid_t *uid, gid_t *gid);
+
+NTSTATUS smb_register_passdb(int version, const char *name, pdb_init_function init)
+{
+ struct pdb_init_function_entry *entry = NULL;
+
+ if(version != PASSDB_INTERFACE_VERSION) {
+ DEBUG(0,("Can't register passdb backend!\n"
+ "You tried to register a passdb module with PASSDB_INTERFACE_VERSION %d, "
+ "while this version of samba uses version %d\n",
+ version,PASSDB_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !init) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5,("Attempting to register passdb backend %s\n", name));
+
+ /* Check for duplicates */
+ if (pdb_find_backend_entry(name)) {
+ DEBUG(0,("There already is a passdb backend registered with the name %s!\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = SMB_XMALLOC_P(struct pdb_init_function_entry);
+ entry->name = smb_xstrdup(name);
+ entry->init = init;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5,("Successfully added passdb backend '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+struct pdb_init_function_entry *pdb_find_backend_entry(const char *name)
+{
+ struct pdb_init_function_entry *entry = backends;
+
+ while(entry) {
+ if (strcmp(entry->name, name)==0) return entry;
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+const struct pdb_init_function_entry *pdb_get_backends(void)
+{
+ return backends;
+}
+
+
+/*
+ * The event context for the passdb backend. I know this is a bad hack and yet
+ * another static variable, but our pdb API is a global thing per
+ * definition. The first use for this is the LDAP idle function, more might be
+ * added later.
+ *
+ * I don't feel too bad about this static variable, it replaces the
+ * smb_idle_event_list that used to exist in lib/module.c. -- VL
+ */
+
+static struct tevent_context *pdb_tevent_ctx;
+
+struct tevent_context *pdb_get_tevent_context(void)
+{
+ return pdb_tevent_ctx;
+}
+
+/******************************************************************
+ Make a pdb_methods from scratch
+ *******************************************************************/
+
+NTSTATUS make_pdb_method_name(struct pdb_methods **methods, const char *selected)
+{
+ char *module_name = smb_xstrdup(selected);
+ char *module_location = NULL, *p;
+ struct pdb_init_function_entry *entry;
+ NTSTATUS nt_status;
+
+ lazy_initialize_passdb();
+
+ p = strchr(module_name, ':');
+
+ if (p) {
+ *p = 0;
+ module_location = p+1;
+ trim_char(module_location, ' ', ' ');
+ }
+
+ trim_char(module_name, ' ', ' ');
+
+
+ DEBUG(5,("Attempting to find a passdb backend to match %s (%s)\n", selected, module_name));
+
+ entry = pdb_find_backend_entry(module_name);
+
+ /* Try to find a module that contains this module */
+ if (!entry) {
+ DEBUG(2,("No builtin backend found, trying to load plugin\n"));
+ if(NT_STATUS_IS_OK(smb_probe_module("pdb", module_name)) && !(entry = pdb_find_backend_entry(module_name))) {
+ DEBUG(0,("Plugin is available, but doesn't register passdb backend %s\n", module_name));
+ SAFE_FREE(module_name);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* No such backend found */
+ if(!entry) {
+ DEBUG(0,("No builtin nor plugin backend for %s found\n", module_name));
+ SAFE_FREE(module_name);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(5,("Found pdb backend %s\n", module_name));
+
+ nt_status = entry->init(methods, module_location);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n",
+ selected, nt_errstr(nt_status)));
+ SAFE_FREE(module_name);
+ return nt_status;
+ }
+
+ SAFE_FREE(module_name);
+
+ DEBUG(5,("pdb backend %s has a valid init\n", selected));
+
+ return nt_status;
+}
+
+/******************************************************************
+ Return an already initialized pdb_methods structure
+*******************************************************************/
+
+static struct pdb_methods *pdb_get_methods_reload( bool reload )
+{
+ static struct pdb_methods *pdb = NULL;
+ const char *backend = lp_passdb_backend();
+ NTSTATUS status = NT_STATUS_OK;
+
+ if ( pdb && reload ) {
+ if (pdb->free_private_data != NULL) {
+ pdb->free_private_data( &(pdb->private_data) );
+ }
+ status = make_pdb_method_name(&pdb, backend);
+ }
+
+ if ( !pdb ) {
+ status = make_pdb_method_name(&pdb, backend);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return pdb;
+}
+
+static struct pdb_methods *pdb_get_methods(void)
+{
+ struct pdb_methods *pdb;
+
+ pdb = pdb_get_methods_reload(false);
+ if (!pdb) {
+ char *msg = NULL;
+ if (asprintf(&msg, "pdb_get_methods: "
+ "failed to get pdb methods for backend %s\n",
+ lp_passdb_backend()) > 0) {
+ smb_panic(msg);
+ } else {
+ smb_panic("pdb_get_methods");
+ }
+ }
+
+ return pdb;
+}
+
+struct pdb_domain_info *pdb_get_domain_info(TALLOC_CTX *mem_ctx)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_domain_info(pdb, mem_ctx);
+}
+
+/**
+ * @brief Check if the user account has been locked out and try to unlock it.
+ *
+ * If the user has been automatically locked out and a lockout duration is set,
+ * then check if we can unlock the account and reset the bad password values.
+ *
+ * @param[in] sampass The sam user to check.
+ *
+ * @return True if the function was successful, false on an error.
+ */
+static bool pdb_try_account_unlock(struct samu *sampass)
+{
+ uint32_t acb_info = pdb_get_acct_ctrl(sampass);
+
+ if ((acb_info & ACB_NORMAL) && (acb_info & ACB_AUTOLOCK)) {
+ uint32_t lockout_duration;
+ time_t bad_password_time;
+ time_t now = time(NULL);
+ bool ok;
+
+ ok = pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION,
+ &lockout_duration);
+ if (!ok) {
+ DEBUG(0, ("pdb_try_account_unlock: "
+ "pdb_get_account_policy failed.\n"));
+ return false;
+ }
+
+ if (lockout_duration == (uint32_t) -1 ||
+ lockout_duration == 0) {
+ DEBUG(9, ("pdb_try_account_unlock: No reset duration, "
+ "can't reset autolock\n"));
+ return false;
+ }
+ lockout_duration *= 60;
+
+ bad_password_time = pdb_get_bad_password_time(sampass);
+ if (bad_password_time == (time_t) 0) {
+ DEBUG(2, ("pdb_try_account_unlock: Account %s "
+ "administratively locked out "
+ "with no bad password "
+ "time. Leaving locked out.\n",
+ pdb_get_username(sampass)));
+ return true;
+ }
+
+ if ((bad_password_time +
+ convert_uint32_t_to_time_t(lockout_duration)) < now) {
+ NTSTATUS status;
+
+ pdb_set_acct_ctrl(sampass, acb_info & ~ACB_AUTOLOCK,
+ PDB_CHANGED);
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+
+ become_root();
+ status = pdb_update_sam_account(sampass);
+ unbecome_root();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("_samr_OpenUser: Couldn't "
+ "update account %s - %s\n",
+ pdb_get_username(sampass),
+ nt_errstr(status)));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief Get a sam user structure by the given username.
+ *
+ * This functions also checks if the account has been automatically locked out
+ * and unlocks it if a lockout duration time has been defined and the time has
+ * elapsed.
+ *
+ * @param[in] sam_acct The sam user structure to fill.
+ *
+ * @param[in] username The username to look for.
+ *
+ * @return True on success, false on error.
+ */
+bool pdb_getsampwnam(struct samu *sam_acct, const char *username)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct samu *for_cache;
+ const struct dom_sid *user_sid;
+ NTSTATUS status;
+ bool ok;
+
+ status = pdb->getsampwnam(pdb, sam_acct, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ok = pdb_try_account_unlock(sam_acct);
+ if (!ok) {
+ DEBUG(1, ("pdb_getsampwnam: Failed to unlock account %s\n",
+ username));
+ }
+
+ for_cache = samu_new(NULL);
+ if (for_cache == NULL) {
+ return False;
+ }
+
+ if (!pdb_copy_sam_account(for_cache, sam_acct)) {
+ TALLOC_FREE(for_cache);
+ return False;
+ }
+
+ user_sid = pdb_get_user_sid(for_cache);
+
+ ok = memcache_add_talloc(NULL,
+ PDB_GETPWSID_CACHE,
+ data_blob_const(user_sid, sizeof(*user_sid)),
+ &for_cache);
+ if (!ok) {
+ TALLOC_FREE(for_cache);
+ }
+
+ return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static bool guest_user_info( struct samu *user )
+{
+ struct passwd *pwd;
+ NTSTATUS result;
+ const char *guestname = lp_guest_account();
+
+ pwd = Get_Pwnam_alloc(talloc_tos(), guestname);
+ if (pwd == NULL) {
+ DEBUG(0,("guest_user_info: Unable to locate guest account [%s]!\n",
+ guestname));
+ return False;
+ }
+
+ result = samu_set_unix(user, pwd );
+
+ TALLOC_FREE( pwd );
+
+ return NT_STATUS_IS_OK( result );
+}
+
+/**
+ * @brief Get a sam user structure by the given username.
+ *
+ * This functions also checks if the account has been automatically locked out
+ * and unlocks it if a lockout duration time has been defined and the time has
+ * elapsed.
+ *
+ *
+ * @param[in] sam_acct The sam user structure to fill.
+ *
+ * @param[in] sid The user SDI to look up.
+ *
+ * @return True on success, false on error.
+ */
+bool pdb_getsampwsid(struct samu *sam_acct, const struct dom_sid *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uint32_t rid;
+ void *cache_data;
+ bool ok = false;
+
+ /* hard code the Guest RID of 501 */
+
+ if ( !sid_peek_check_rid( get_global_sam_sid(), sid, &rid ) )
+ return False;
+
+ if ( rid == DOMAIN_RID_GUEST ) {
+ DEBUG(6,("pdb_getsampwsid: Building guest account\n"));
+ return guest_user_info( sam_acct );
+ }
+
+ /* check the cache first */
+
+ cache_data = memcache_lookup_talloc(
+ NULL, PDB_GETPWSID_CACHE, data_blob_const(sid, sizeof(*sid)));
+
+ if (cache_data != NULL) {
+ struct samu *cache_copy = talloc_get_type_abort(
+ cache_data, struct samu);
+
+ ok = pdb_copy_sam_account(sam_acct, cache_copy);
+ } else {
+ ok = NT_STATUS_IS_OK(pdb->getsampwsid(pdb, sam_acct, sid));
+ }
+
+ if (!ok) {
+ return false;
+ }
+
+ ok = pdb_try_account_unlock(sam_acct);
+ if (!ok) {
+ DEBUG(1, ("pdb_getsampwsid: Failed to unlock account %s\n",
+ sam_acct->username));
+ }
+
+ return true;
+}
+
+static NTSTATUS pdb_default_create_user(struct pdb_methods *methods,
+ TALLOC_CTX *tmp_ctx, const char *name,
+ uint32_t acb_info, uint32_t *rid)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ struct samu *sam_pass;
+ NTSTATUS status;
+ struct passwd *pwd;
+
+ if ((sam_pass = samu_new(tmp_ctx)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(pwd = Get_Pwnam_alloc(tmp_ctx, name)) ) {
+ char *add_script = NULL;
+ int add_ret;
+ fstring name2;
+
+ if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') {
+ add_script = lp_add_user_script(tmp_ctx, lp_sub);
+ } else {
+ add_script = lp_add_machine_script(tmp_ctx, lp_sub);
+ }
+
+ if (!add_script || add_script[0] == '\0') {
+ DEBUG(3, ("Could not find user %s and no add script "
+ "defined\n", name));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* lowercase the username before creating the Unix account for
+ compatibility with previous Samba releases */
+ fstrcpy( name2, name );
+ if (!strlower_m( name2 )) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ add_script = talloc_all_string_sub(tmp_ctx,
+ add_script,
+ "%u",
+ name2);
+ if (!add_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ add_ret = smbrun(add_script, NULL, NULL);
+ DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the command `%s' gave %d\n",
+ add_script, add_ret));
+ if (add_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ flush_pwnam_cache();
+
+ pwd = Get_Pwnam_alloc(tmp_ctx, name);
+
+ if(pwd == NULL) {
+ DEBUG(3, ("Could not find user %s, add script did not work\n", name));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ /* we have a valid SID coming out of this call */
+
+ status = samu_alloc_rid_unix(methods, sam_pass, pwd);
+
+ TALLOC_FREE( pwd );
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("pdb_default_create_user: failed to create a new user structure: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ if (!sid_peek_check_rid(get_global_sam_sid(),
+ pdb_get_user_sid(sam_pass), rid)) {
+ DEBUG(0, ("Could not get RID of fresh user\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* Use the username case specified in the original request */
+
+ pdb_set_username( sam_pass, name, PDB_SET );
+
+ /* Disable the account on creation, it does not have a reasonable password yet. */
+
+ acb_info |= ACB_DISABLED;
+
+ pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED);
+
+ status = methods->add_sam_account(methods, sam_pass);
+
+ TALLOC_FREE(sam_pass);
+
+ return status;
+}
+
+NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32_t flags,
+ uint32_t *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_user(pdb, mem_ctx, name, flags, rid);
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(const char *unix_user)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ char *del_script = NULL;
+ int ret;
+
+ /* safety check */
+
+ if ( strequal( unix_user, "root" ) ) {
+ DEBUG(0,("smb_delete_user: Refusing to delete local system root account!\n"));
+ return -1;
+ }
+
+ del_script = lp_delete_user_script(talloc_tos(), lp_sub);
+ if (!del_script || !*del_script) {
+ return -1;
+ }
+ del_script = talloc_all_string_sub(talloc_tos(),
+ del_script,
+ "%u",
+ unix_user);
+ if (!del_script) {
+ return -1;
+ }
+ ret = smbrun(del_script, NULL, NULL);
+ flush_pwnam_cache();
+ if (ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+ DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+
+ return ret;
+}
+
+static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sam_acct)
+{
+ NTSTATUS status;
+ fstring username;
+
+ status = methods->delete_sam_account(methods, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Now delete the unix side ....
+ * note: we don't check if the delete really happened as the script is
+ * not necessary present and maybe the sysadmin doesn't want to delete
+ * the unix side
+ */
+
+ /* always lower case the username before handing it off to
+ external scripts */
+
+ fstrcpy( username, pdb_get_username(sam_acct) );
+ if (!strlower_m( username )) {
+ return status;
+ }
+
+ smb_delete_user( username );
+
+ return status;
+}
+
+NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uid_t uid = -1;
+ NTSTATUS status;
+ const struct dom_sid *user_sid;
+ char *msg_data;
+
+ user_sid = pdb_get_user_sid(sam_acct);
+
+ /* sanity check to make sure we don't delete root */
+
+ if ( !sid_to_uid(user_sid, &uid ) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if ( uid == 0 ) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memcache_delete(NULL,
+ PDB_GETPWSID_CACHE,
+ data_blob_const(user_sid, sizeof(*user_sid)));
+
+ status = pdb->delete_user(pdb, mem_ctx, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ msg_data = talloc_asprintf(mem_ctx, "USER %s",
+ pdb_get_username(sam_acct));
+ if (!msg_data) {
+ /* not fatal, and too late to rollback,
+ * just return */
+ return status;
+ }
+ messaging_send_all(global_messaging_context(),
+ ID_CACHE_DELETE,
+ msg_data,
+ strlen(msg_data) + 1);
+
+ TALLOC_FREE(msg_data);
+ return status;
+}
+
+NTSTATUS pdb_add_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_update_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+
+ memcache_flush(NULL, PDB_GETPWSID_CACHE);
+
+ return pdb->update_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_delete_sam_account(struct samu *sam_acct)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ const struct dom_sid *user_sid = pdb_get_user_sid(sam_acct);
+
+ memcache_delete(NULL,
+ PDB_GETPWSID_CACHE,
+ data_blob_const(user_sid, sizeof(*user_sid)));
+
+ return pdb->delete_sam_account(pdb, sam_acct);
+}
+
+NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ uid_t uid;
+ NTSTATUS status;
+
+ memcache_flush(NULL, PDB_GETPWSID_CACHE);
+
+ /* sanity check to make sure we don't rename root */
+
+ if ( !sid_to_uid( pdb_get_user_sid(oldname), &uid ) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if ( uid == 0 ) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = pdb->rename_sam_account(pdb, oldname, newname);
+
+ /* always flush the cache here just to be safe */
+ flush_pwnam_cache();
+
+ return status;
+}
+
+NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, bool success)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->update_login_attempts(pdb, sam_acct, success);
+}
+
+bool pdb_getgrsid(GROUP_MAP *map, struct dom_sid sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrsid(pdb, map, sid));
+}
+
+bool pdb_getgrgid(GROUP_MAP *map, gid_t gid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrgid(pdb, map, gid));
+}
+
+bool pdb_getgrnam(GROUP_MAP *map, const char *name)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->getgrnam(pdb, map, name));
+}
+
+static NTSTATUS pdb_default_create_dom_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ uint32_t *rid)
+{
+ struct dom_sid group_sid;
+ struct group *grp;
+ struct dom_sid_buf tmp;
+
+ grp = getgrnam(name);
+
+ if (grp == NULL) {
+ gid_t gid;
+
+ if (smb_create_group(name, &gid) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ grp = getgrgid(gid);
+ }
+
+ if (grp == NULL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (pdb_capabilities() & PDB_CAP_STORE_RIDS) {
+ if (!pdb_new_rid(rid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ *rid = algorithmic_pdb_gid_to_group_rid( grp->gr_gid );
+ }
+
+ sid_compose(&group_sid, get_global_sam_sid(), *rid);
+
+ return add_initial_entry(
+ grp->gr_gid,
+ dom_sid_str_buf(&group_sid, &tmp),
+ SID_NAME_DOM_GRP,
+ name,
+ NULL);
+}
+
+NTSTATUS pdb_create_dom_group(TALLOC_CTX *mem_ctx, const char *name,
+ uint32_t *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_dom_group(pdb, mem_ctx, name, rid);
+}
+
+static NTSTATUS pdb_default_delete_dom_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t rid)
+{
+ struct dom_sid group_sid;
+ GROUP_MAP *map;
+ NTSTATUS status;
+ struct group *grp;
+ const char *grp_name;
+
+ map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (!map) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* coverity */
+ map->gid = (gid_t) -1;
+
+ sid_compose(&group_sid, get_global_sam_sid(), rid);
+
+ if (!get_domain_group_from_sid(group_sid, map)) {
+ DEBUG(10, ("Could not find group for rid %d\n", rid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ /* We need the group name for the smb_delete_group later on */
+
+ if (map->gid == (gid_t)-1) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ grp = getgrgid(map->gid);
+ if (grp == NULL) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ TALLOC_FREE(map);
+
+ /* Copy the name, no idea what pdb_delete_group_mapping_entry does.. */
+
+ grp_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (grp_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = pdb_delete_group_mapping_entry(group_sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Don't check the result of smb_delete_group */
+
+ smb_delete_group(grp_name);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_delete_dom_group(TALLOC_CTX *mem_ctx, uint32_t rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_dom_group(pdb, mem_ctx, rid);
+}
+
+NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_group_mapping_entry(pdb, map);
+}
+
+NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->update_group_mapping_entry(pdb, map);
+}
+
+NTSTATUS pdb_delete_group_mapping_entry(struct dom_sid sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_group_mapping_entry(pdb, sid);
+}
+
+bool pdb_enum_group_mapping(const struct dom_sid *sid,
+ enum lsa_SidType sid_name_use,
+ GROUP_MAP ***pp_rmap,
+ size_t *p_num_entries,
+ bool unix_only)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb-> enum_group_mapping(pdb, sid, sid_name_use,
+ pp_rmap, p_num_entries, unix_only));
+}
+
+NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid,
+ uint32_t **pp_member_rids,
+ size_t *p_num_members)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS result;
+
+ result = pdb->enum_group_members(pdb, mem_ctx,
+ sid, pp_member_rids, p_num_members);
+
+ /* special check for rid 513 */
+
+ if ( !NT_STATUS_IS_OK( result ) ) {
+ uint32_t rid;
+
+ sid_peek_rid( sid, &rid );
+
+ if ( rid == DOMAIN_RID_USERS ) {
+ *p_num_members = 0;
+ *pp_member_rids = NULL;
+
+ return NT_STATUS_OK;
+ }
+ }
+
+ return result;
+}
+
+NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, struct samu *user,
+ struct dom_sid **pp_sids, gid_t **pp_gids,
+ uint32_t *p_num_groups)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_group_memberships(
+ pdb, mem_ctx, user,
+ pp_sids, pp_gids, p_num_groups);
+}
+
+static NTSTATUS pdb_default_set_unix_primary_group(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sampass)
+{
+ struct group *grp;
+ gid_t gid;
+
+ if (!sid_to_gid(pdb_get_group_sid(sampass), &gid) ||
+ (grp = getgrgid(gid)) == NULL) {
+ return NT_STATUS_INVALID_PRIMARY_GROUP;
+ }
+
+ if (smb_set_primary_group(grp->gr_name,
+ pdb_get_username(sampass)) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_set_unix_primary_group(TALLOC_CTX *mem_ctx, struct samu *user)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_unix_primary_group(pdb, mem_ctx, user);
+}
+
+/*
+ * Helper function to see whether a user is in a group. We can't use
+ * user_in_group_sid here because this creates dependencies only smbd can
+ * fulfil.
+ */
+
+static bool pdb_user_in_group(TALLOC_CTX *mem_ctx, struct samu *account,
+ const struct dom_sid *group_sid)
+{
+ struct dom_sid *sids;
+ gid_t *gids;
+ uint32_t i, num_groups;
+
+ if (!NT_STATUS_IS_OK(pdb_enum_group_memberships(mem_ctx, account,
+ &sids, &gids,
+ &num_groups))) {
+ return False;
+ }
+
+ for (i=0; i<num_groups; i++) {
+ if (dom_sid_equal(group_sid, &sids[i])) {
+ return True;
+ }
+ }
+ return False;
+}
+
+static NTSTATUS pdb_default_add_groupmem(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid)
+{
+ struct dom_sid group_sid, member_sid;
+ struct samu *account = NULL;
+ GROUP_MAP *map;
+ struct group *grp;
+ struct passwd *pwd;
+ const char *group_name;
+ uid_t uid;
+
+ map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (!map) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* coverity */
+ map->gid = (gid_t) -1;
+
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ if (!get_domain_group_from_sid(group_sid, map) ||
+ (map->gid == (gid_t)-1) ||
+ ((grp = getgrgid(map->gid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ TALLOC_FREE(map);
+
+ group_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (group_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_getsampwsid(account, &member_sid) ||
+ !sid_to_uid(&member_sid, &uid) ||
+ ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_MEMBER_IN_GROUP;
+ }
+
+ /*
+ * ok, the group exist, the user exist, the user is not in the group,
+ * we can (finally) add it to the group !
+ */
+
+ smb_add_user_group(group_name, pwd->pw_name);
+
+ if (!pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_add_groupmem(TALLOC_CTX *mem_ctx, uint32_t group_rid,
+ uint32_t member_rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_groupmem(pdb, mem_ctx, group_rid, member_rid);
+}
+
+static NTSTATUS pdb_default_del_groupmem(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid)
+{
+ struct dom_sid group_sid, member_sid;
+ struct samu *account = NULL;
+ GROUP_MAP *map;
+ struct group *grp;
+ struct passwd *pwd;
+ const char *group_name;
+ uid_t uid;
+
+ map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (!map) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ if (!get_domain_group_from_sid(group_sid, map) ||
+ (map->gid == (gid_t)-1) ||
+ ((grp = getgrgid(map->gid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ TALLOC_FREE(map);
+
+ group_name = talloc_strdup(mem_ctx, grp->gr_name);
+ if (group_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !(account = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_getsampwsid(account, &member_sid) ||
+ !sid_to_uid(&member_sid, &uid) ||
+ ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (!pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+
+ /*
+ * ok, the group exist, the user exist, the user is in the group,
+ * we can (finally) delete it from the group!
+ */
+
+ smb_delete_user_group(group_name, pwd->pw_name);
+
+ if (pdb_user_in_group(mem_ctx, account, &group_sid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_del_groupmem(TALLOC_CTX *mem_ctx, uint32_t group_rid,
+ uint32_t member_rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_groupmem(pdb, mem_ctx, group_rid, member_rid);
+}
+
+NTSTATUS pdb_create_alias(const char *name, uint32_t *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->create_alias(pdb, name, rid);
+}
+
+NTSTATUS pdb_delete_alias(const struct dom_sid *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_alias(pdb, sid);
+}
+
+NTSTATUS pdb_get_aliasinfo(const struct dom_sid *sid, struct acct_info *info)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_aliasinfo(pdb, sid, info);
+}
+
+NTSTATUS pdb_set_aliasinfo(const struct dom_sid *sid, struct acct_info *info)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_aliasinfo(pdb, sid, info);
+}
+
+NTSTATUS pdb_add_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->add_aliasmem(pdb, alias, member);
+}
+
+NTSTATUS pdb_del_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_aliasmem(pdb, alias, member);
+}
+
+NTSTATUS pdb_enum_aliasmem(const struct dom_sid *alias, TALLOC_CTX *mem_ctx,
+ struct dom_sid **pp_members, size_t *p_num_members)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_aliasmem(pdb, alias, mem_ctx, pp_members,
+ p_num_members);
+}
+
+NTSTATUS pdb_enum_alias_memberships(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ const struct dom_sid *members, size_t num_members,
+ uint32_t **pp_alias_rids,
+ size_t *p_num_alias_rids)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_alias_memberships(pdb, mem_ctx,
+ domain_sid,
+ members, num_members,
+ pp_alias_rids,
+ p_num_alias_rids);
+}
+
+NTSTATUS pdb_lookup_rids(const struct dom_sid *domain_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->lookup_rids(pdb, domain_sid, num_rids, rids, names, attrs);
+}
+
+bool pdb_get_account_policy(enum pdb_policy_type type, uint32_t *value)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS status;
+
+ become_root();
+ status = pdb->get_account_policy(pdb, type, value);
+ unbecome_root();
+
+ return NT_STATUS_IS_OK(status);
+}
+
+bool pdb_set_account_policy(enum pdb_policy_type type, uint32_t value)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ NTSTATUS status;
+
+ become_root();
+ status = pdb->set_account_policy(pdb, type, value);
+ unbecome_root();
+
+ return NT_STATUS_IS_OK(status);
+}
+
+bool pdb_get_seq_num(time_t *seq_num)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return NT_STATUS_IS_OK(pdb->get_seq_num(pdb, seq_num));
+}
+
+/*
+ * Instead of passing down a gid or uid, this function sends down a pointer
+ * to a unixid.
+ *
+ * This acts as an in-out variable so that the idmap functions can correctly
+ * receive ID_TYPE_BOTH, filling in cache details correctly rather than forcing
+ * the cache to store ID_TYPE_UID or ID_TYPE_GID.
+ */
+bool pdb_id_to_sid(struct unixid *id, struct dom_sid *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ bool ret;
+
+ ret = pdb->id_to_sid(pdb, id, sid);
+
+ if (ret) {
+ idmap_cache_set_sid2unixid(sid, id);
+ }
+
+ return ret;
+}
+
+bool pdb_sid_to_id(const struct dom_sid *sid, struct unixid *id)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ bool ret;
+
+ /* only ask the backend if it is responsible */
+ if (!sid_check_object_is_for_passdb(sid)) {
+ return false;
+ }
+
+ ret = pdb->sid_to_id(pdb, sid, id);
+
+ if (ret) {
+ idmap_cache_set_sid2unixid(sid, id);
+ }
+
+ return ret;
+}
+
+uint32_t pdb_capabilities(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->capabilities(pdb);
+}
+
+/********************************************************************
+ Allocate a new RID from the passdb backend. Verify that it is free
+ by calling lookup_global_sam_rid() to verify that the RID is not
+ in use. This handles servers that have existing users or groups
+ with add RIDs (assigned from previous algorithmic mappings)
+********************************************************************/
+
+bool pdb_new_rid(uint32_t *rid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ const char *name = NULL;
+ enum lsa_SidType type;
+ uint32_t allocated_rid = 0;
+ int i;
+ TALLOC_CTX *ctx;
+
+ if ((pdb_capabilities() & PDB_CAP_STORE_RIDS) == 0) {
+ DEBUG(0, ("Trying to allocate a RID when algorithmic RIDs "
+ "are active\n"));
+ return False;
+ }
+
+ if (algorithmic_rid_base() != BASE_RID) {
+ DEBUG(0, ("'algorithmic rid base' is set but a passdb backend "
+ "without algorithmic RIDs is chosen.\n"));
+ DEBUGADD(0, ("Please map all used groups using 'net groupmap "
+ "add', set the maximum used RID\n"));
+ DEBUGADD(0, ("and remove the parameter\n"));
+ return False;
+ }
+
+ if ( (ctx = talloc_init("pdb_new_rid")) == NULL ) {
+ DEBUG(0,("pdb_new_rid: Talloc initialization failure\n"));
+ return False;
+ }
+
+ /* Attempt to get an unused RID (max tires is 250...yes that it is
+ and arbitrary number I pulkled out of my head). -- jerry */
+
+ for ( i=0; allocated_rid==0 && i<250; i++ ) {
+ /* get a new RID */
+
+ if ( !pdb->new_rid(pdb, &allocated_rid) ) {
+ return False;
+ }
+
+ /* validate that the RID is not in use */
+
+ if (lookup_global_sam_rid(ctx, allocated_rid, &name, &type, NULL, NULL)) {
+ allocated_rid = 0;
+ }
+ }
+
+ TALLOC_FREE( ctx );
+
+ if ( allocated_rid == 0 ) {
+ DEBUG(0,("pdb_new_rid: Failed to find unused RID\n"));
+ return False;
+ }
+
+ *rid = allocated_rid;
+
+ return True;
+}
+
+/***************************************************************
+ Initialize the static context (at smbd startup etc).
+
+ If uninitialised, context will auto-init on first use.
+ ***************************************************************/
+
+bool initialize_password_db(bool reload, struct tevent_context *tevent_ctx)
+{
+ if (tevent_ctx) {
+ pdb_tevent_ctx = tevent_ctx;
+ }
+ return (pdb_get_methods_reload(reload) != NULL);
+}
+
+/***************************************************************************
+ Default implementations of some functions.
+ ****************************************************************************/
+
+static NTSTATUS pdb_default_getsampwnam (struct pdb_methods *methods, struct samu *user, const char *sname)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+static NTSTATUS pdb_default_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const struct dom_sid *sid)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+static NTSTATUS pdb_default_add_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_update_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, struct samu *pwd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_rename_sam_account (struct pdb_methods *methods, struct samu *pwd, const char *newname)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods, struct samu *newpwd, bool success)
+{
+ /* Only the pdb_nds backend implements this, by
+ * default just return ok. */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_default_get_account_policy(struct pdb_methods *methods, enum pdb_policy_type type, uint32_t *value)
+{
+ return account_policy_get(type, value) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_default_set_account_policy(struct pdb_methods *methods, enum pdb_policy_type type, uint32_t value)
+{
+ return account_policy_set(type, 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 bool pdb_default_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+ struct dom_sid *sid)
+{
+ struct samu *sampw = NULL;
+ struct passwd *unix_pw;
+ fstring pw_name = { 0 };
+ bool ret;
+
+ unix_pw = getpwuid( uid );
+
+ if ( !unix_pw ) {
+ DEBUG(4,("pdb_default_uid_to_sid: host has no idea of uid "
+ "%lu\n", (unsigned long)uid));
+ return False;
+ }
+
+ if (unix_pw->pw_name == NULL) {
+ DBG_DEBUG("No pw_name for uid %d\n", (int)uid);
+ return false;
+ }
+
+ /*
+ * Make a copy, "unix_pw" might go away soon.
+ */
+ fstrcpy(pw_name, unix_pw->pw_name);
+
+ if ( !(sampw = samu_new( NULL )) ) {
+ DEBUG(0,("pdb_default_uid_to_sid: samu_new() failed!\n"));
+ return False;
+ }
+
+ become_root();
+ ret = NT_STATUS_IS_OK(methods->getsampwnam(methods, sampw, pw_name));
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(5, ("pdb_default_uid_to_sid: Did not find user "
+ "%s (%u)\n", unix_pw->pw_name, (unsigned int)uid));
+ TALLOC_FREE(sampw);
+ return False;
+ }
+
+ sid_copy(sid, pdb_get_user_sid(sampw));
+
+ TALLOC_FREE(sampw);
+
+ return True;
+}
+
+static bool pdb_default_gid_to_sid(struct pdb_methods *methods, gid_t gid,
+ struct dom_sid *sid)
+{
+ GROUP_MAP *map;
+
+ map = talloc_zero(NULL, GROUP_MAP);
+ if (!map) {
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(methods->getgrgid(methods, map, gid))) {
+ TALLOC_FREE(map);
+ return false;
+ }
+
+ sid_copy(sid, &map->sid);
+ TALLOC_FREE(map);
+ return true;
+}
+
+static bool pdb_default_id_to_sid(struct pdb_methods *methods, struct unixid *id,
+ struct dom_sid *sid)
+{
+ switch (id->type) {
+ case ID_TYPE_UID:
+ return pdb_default_uid_to_sid(methods, id->id, sid);
+
+ case ID_TYPE_GID:
+ return pdb_default_gid_to_sid(methods, id->id, sid);
+
+ default:
+ return false;
+ }
+}
+/**
+ * The "Unix User" and "Unix Group" domains have a special
+ * id mapping that is a rid-algorithm with range starting at 0.
+ */
+bool pdb_sid_to_id_unix_users_and_groups(const struct dom_sid *sid,
+ struct unixid *id)
+{
+ uint32_t rid;
+
+ id->id = -1;
+
+ if (sid_peek_check_rid(&global_sid_Unix_Users, sid, &rid)) {
+ id->id = rid;
+ id->type = ID_TYPE_UID;
+ return true;
+ }
+
+ if (sid_peek_check_rid(&global_sid_Unix_Groups, sid, &rid)) {
+ id->id = rid;
+ id->type = ID_TYPE_GID;
+ return true;
+ }
+
+ return false;
+}
+
+static bool pdb_default_sid_to_id(struct pdb_methods *methods,
+ const struct dom_sid *sid,
+ struct unixid *id)
+{
+ TALLOC_CTX *mem_ctx;
+ bool ret = False;
+ uint32_t rid;
+ struct dom_sid_buf buf;
+
+ id->id = -1;
+
+ mem_ctx = talloc_new(NULL);
+
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
+ const char *name;
+ enum lsa_SidType type;
+ uid_t uid = (uid_t)-1;
+ gid_t gid = (gid_t)-1;
+ /* Here we might have users as well as groups and aliases */
+ ret = lookup_global_sam_rid(mem_ctx, rid, &name, &type, &uid, &gid);
+ if (ret) {
+ switch (type) {
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+ id->type = ID_TYPE_GID;
+ id->id = gid;
+ break;
+ case SID_NAME_USER:
+ id->type = ID_TYPE_UID;
+ id->id = uid;
+ break;
+ default:
+ DEBUG(5, ("SID %s belongs to our domain, and "
+ "an object exists in the database, "
+ "but it is neither a user nor a "
+ "group (got type %d).\n",
+ dom_sid_str_buf(sid, &buf),
+ type));
+ ret = false;
+ }
+ } else {
+ DEBUG(5, ("SID %s belongs to our domain, but there is "
+ "no corresponding object in the database.\n",
+ dom_sid_str_buf(sid, &buf)));
+ }
+ goto done;
+ }
+
+ /*
+ * "Unix User" and "Unix Group"
+ */
+ ret = pdb_sid_to_id_unix_users_and_groups(sid, id);
+ if (ret) {
+ goto done;
+ }
+
+ /* BUILTIN */
+
+ if (sid_check_is_in_builtin(sid) ||
+ sid_check_is_in_wellknown_domain(sid)) {
+ /* Here we only have aliases */
+ GROUP_MAP *map;
+
+ map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (!map) {
+ ret = false;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(methods->getgrsid(methods, map, *sid))) {
+ DEBUG(10, ("Could not find map for sid %s\n",
+ dom_sid_str_buf(sid, &buf)));
+ goto done;
+ }
+ if ((map->sid_name_use != SID_NAME_ALIAS) &&
+ (map->sid_name_use != SID_NAME_WKN_GRP)) {
+ DEBUG(10, ("Map for sid %s is a %s, expected an "
+ "alias\n",
+ dom_sid_str_buf(sid, &buf),
+ sid_type_lookup(map->sid_name_use)));
+ goto done;
+ }
+
+ id->id = map->gid;
+ id->type = ID_TYPE_GID;
+ ret = True;
+ goto done;
+ }
+
+ DEBUG(5, ("Sid %s is neither ours, a Unix SID, nor builtin\n",
+ dom_sid_str_buf(sid, &buf)));
+
+ done:
+
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, uint32_t *p_num)
+{
+ struct group *grp;
+ char **gr;
+ struct passwd *pwd;
+ bool winbind_env;
+ bool ret = False;
+
+ *pp_uids = NULL;
+ *p_num = 0;
+
+ /* We only look at our own sam, so don't care about imported stuff */
+ winbind_env = winbind_env_set();
+ (void)winbind_off();
+
+ if ((grp = getgrgid(gid)) == NULL) {
+ /* allow winbindd lookups, but only if they weren't already disabled */
+ goto done;
+ }
+
+ /* Primary group members */
+ setpwent();
+ while ((pwd = getpwent()) != NULL) {
+ if (pwd->pw_gid == gid) {
+ if (!add_uid_to_array_unique(mem_ctx, pwd->pw_uid,
+ pp_uids, p_num)) {
+ goto done;
+ }
+ }
+ }
+ endpwent();
+
+ /* Secondary group members */
+ for (gr = grp->gr_mem; (*gr != NULL) && ((*gr)[0] != '\0'); gr += 1) {
+ struct passwd *pw = getpwnam(*gr);
+
+ if (pw == NULL)
+ continue;
+ if (!add_uid_to_array_unique(mem_ctx, pw->pw_uid, pp_uids, p_num)) {
+ goto done;
+ }
+ }
+
+ ret = True;
+
+ done:
+
+ /* allow winbindd lookups, but only if they weren't already disabled */
+ if (!winbind_env) {
+ (void)winbind_on();
+ }
+
+ return ret;
+}
+
+static NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *group,
+ uint32_t **pp_member_rids,
+ size_t *p_num_members)
+{
+ gid_t gid;
+ uid_t *uids;
+ uint32_t i, num_uids;
+
+ *pp_member_rids = NULL;
+ *p_num_members = 0;
+
+ if (!sid_to_gid(group, &gid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if(!get_memberuids(mem_ctx, gid, &uids, &num_uids))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if (num_uids == 0)
+ return NT_STATUS_OK;
+
+ *pp_member_rids = talloc_zero_array(mem_ctx, uint32_t, num_uids);
+
+ for (i=0; i<num_uids; i++) {
+ struct dom_sid sid;
+
+ uid_to_sid(&sid, uids[i]);
+
+ if (!sid_check_is_in_our_sam(&sid)) {
+ DEBUG(5, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ continue;
+ }
+
+ sid_peek_rid(&sid, &(*pp_member_rids)[*p_num_members]);
+ *p_num_members += 1;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ struct dom_sid **pp_sids,
+ gid_t **pp_gids,
+ uint32_t *p_num_groups)
+{
+ size_t i;
+ gid_t gid;
+ struct passwd *pw;
+ const char *username = pdb_get_username(user);
+
+
+ /* Ignore the primary group SID. Honor the real Unix primary group.
+ The primary group SID is only of real use to Windows clients */
+
+ if ( !(pw = Get_Pwnam_alloc(mem_ctx, username)) ) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ gid = pw->pw_gid;
+
+ TALLOC_FREE( pw );
+
+ if (!getgroups_unix_user(mem_ctx, username, gid, pp_gids, p_num_groups)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (*p_num_groups == 0) {
+ smb_panic("primary group missing");
+ }
+
+ *pp_sids = talloc_array(mem_ctx, struct dom_sid, *p_num_groups);
+
+ if (*pp_sids == NULL) {
+ TALLOC_FREE(*pp_gids);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<*p_num_groups; i++) {
+ gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Look up a rid in the SAM we're responsible for (i.e. passdb)
+ ********************************************************************/
+
+static bool lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32_t rid,
+ const char **name,
+ enum lsa_SidType *psid_name_use,
+ uid_t *uid, gid_t *gid)
+{
+ struct samu *sam_account = NULL;
+ GROUP_MAP *map = NULL;
+ bool ret;
+ struct dom_sid sid;
+
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ DEBUG(5,("lookup_global_sam_rid: looking up RID %u.\n",
+ (unsigned int)rid));
+
+ sid_compose(&sid, get_global_sam_sid(), rid);
+
+ /* see if the passdb can help us with the name of the user */
+
+ if ( !(sam_account = samu_new( NULL )) ) {
+ return False;
+ }
+
+ map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (!map) {
+ return false;
+ }
+
+ /* BEING ROOT BLOCK */
+ become_root();
+ ret = pdb_getsampwsid(sam_account, &sid);
+ if (!ret) {
+ TALLOC_FREE(sam_account);
+ ret = pdb_getgrsid(map, sid);
+ }
+ unbecome_root();
+ /* END BECOME_ROOT BLOCK */
+
+ if (sam_account || !ret) {
+ TALLOC_FREE(map);
+ }
+
+ if (sam_account) {
+ struct passwd *pw;
+
+ *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account));
+ if (!*name) {
+ TALLOC_FREE(sam_account);
+ return False;
+ }
+
+ *psid_name_use = SID_NAME_USER;
+
+ TALLOC_FREE(sam_account);
+
+ if (uid == NULL) {
+ return True;
+ }
+
+ pw = Get_Pwnam_alloc(talloc_tos(), *name);
+ if (pw == NULL) {
+ return False;
+ }
+ *uid = pw->pw_uid;
+ TALLOC_FREE(pw);
+ return True;
+
+ } else if (map && (map->gid != (gid_t)-1)) {
+
+ /* do not resolve SIDs to a name unless there is a valid
+ gid associated with it */
+
+ *name = talloc_steal(mem_ctx, map->nt_name);
+ *psid_name_use = map->sid_name_use;
+
+ if (gid) {
+ *gid = map->gid;
+ }
+
+ TALLOC_FREE(map);
+ return True;
+ }
+
+ TALLOC_FREE(map);
+
+ /* Windows will always map RID 513 to something. On a non-domain
+ controller, this gets mapped to SERVER\None. */
+
+ if (uid || gid) {
+ DEBUG(5, ("Can't find a unix id for an unmapped group\n"));
+ return False;
+ }
+
+ if ( rid == DOMAIN_RID_USERS ) {
+ *name = talloc_strdup(mem_ctx, "None" );
+ *psid_name_use = SID_NAME_DOM_GRP;
+
+ return True;
+ }
+
+ return False;
+}
+
+static NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods,
+ const struct dom_sid *domain_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ int i;
+ NTSTATUS result;
+ bool have_mapped = False;
+ bool have_unmapped = False;
+
+ if (sid_check_is_builtin(domain_sid)) {
+
+ for (i=0; i<num_rids; i++) {
+ const char *name;
+
+ if (lookup_builtin_rid(names, rids[i], &name)) {
+ attrs[i] = SID_NAME_ALIAS;
+ names[i] = name;
+ DEBUG(5,("lookup_rids: %s:%d\n",
+ names[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+ goto done;
+ }
+
+ /* Should not happen, but better check once too many */
+ if (!sid_check_is_our_sam(domain_sid)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ for (i = 0; i < num_rids; i++) {
+ const char *name;
+
+ if (lookup_global_sam_rid(names, rids[i], &name, &attrs[i],
+ NULL, NULL)) {
+ if (name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ names[i] = name;
+ DEBUG(5,("lookup_rids: %s:%d\n", names[i], attrs[i]));
+ have_mapped = True;
+ } else {
+ have_unmapped = True;
+ attrs[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+
+ result = NT_STATUS_NONE_MAPPED;
+
+ if (have_mapped)
+ result = have_unmapped ? STATUS_SOME_UNMAPPED : NT_STATUS_OK;
+
+ return result;
+}
+
+static int pdb_search_destructor(struct pdb_search *search)
+{
+ if ((!search->search_ended) && (search->search_end != NULL)) {
+ search->search_end(search);
+ }
+ return 0;
+}
+
+struct pdb_search *pdb_search_init(TALLOC_CTX *mem_ctx,
+ enum pdb_search_type type)
+{
+ struct pdb_search *result;
+
+ result = talloc(mem_ctx, struct pdb_search);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->type = type;
+ result->cache = NULL;
+ result->num_entries = 0;
+ result->cache_size = 0;
+ result->search_ended = False;
+ result->search_end = NULL;
+
+ /* Segfault appropriately if not initialized */
+ result->next_entry = NULL;
+ result->search_end = NULL;
+
+ talloc_set_destructor(result, pdb_search_destructor);
+
+ return result;
+}
+
+static void fill_displayentry(TALLOC_CTX *mem_ctx, uint32_t rid,
+ uint16_t acct_flags,
+ const char *account_name,
+ const char *fullname,
+ const char *description,
+ struct samr_displayentry *entry)
+{
+ entry->rid = rid;
+ entry->acct_flags = acct_flags;
+
+ if (account_name != NULL)
+ entry->account_name = talloc_strdup(mem_ctx, account_name);
+ else
+ entry->account_name = "";
+
+ if (fullname != NULL)
+ entry->fullname = talloc_strdup(mem_ctx, fullname);
+ else
+ entry->fullname = "";
+
+ if (description != NULL)
+ entry->description = talloc_strdup(mem_ctx, description);
+ else
+ entry->description = "";
+}
+
+struct group_search {
+ GROUP_MAP **groups;
+ size_t num_groups, current_group;
+};
+
+static bool next_entry_groups(struct pdb_search *s,
+ struct samr_displayentry *entry)
+{
+ struct group_search *state = (struct group_search *)s->private_data;
+ uint32_t rid;
+ GROUP_MAP *map;
+
+ if (state->current_group == state->num_groups)
+ return False;
+
+ map = state->groups[state->current_group];
+
+ sid_peek_rid(&map->sid, &rid);
+
+ fill_displayentry(s, rid, 0, map->nt_name, NULL, map->comment, entry);
+
+ state->current_group += 1;
+ return True;
+}
+
+static void search_end_groups(struct pdb_search *search)
+{
+ struct group_search *state =
+ (struct group_search *)search->private_data;
+ TALLOC_FREE(state->groups);
+}
+
+static bool pdb_search_grouptype(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const struct dom_sid *sid, enum lsa_SidType type)
+{
+ struct group_search *state;
+
+ state = talloc_zero(search, struct group_search);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ if (!NT_STATUS_IS_OK(methods->enum_group_mapping(methods, sid, type,
+ &state->groups, &state->num_groups,
+ True))) {
+ DEBUG(0, ("Could not enum groups\n"));
+ return False;
+ }
+
+ state->current_group = 0;
+ search->private_data = state;
+ search->next_entry = next_entry_groups;
+ search->search_end = search_end_groups;
+ return True;
+}
+
+static bool pdb_default_search_groups(struct pdb_methods *methods,
+ struct pdb_search *search)
+{
+ return pdb_search_grouptype(methods, search, get_global_sam_sid(), SID_NAME_DOM_GRP);
+}
+
+static bool pdb_default_search_aliases(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const struct dom_sid *sid)
+{
+
+ return pdb_search_grouptype(methods, search, sid, SID_NAME_ALIAS);
+}
+
+static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search,
+ uint32_t idx)
+{
+ if (idx < search->num_entries)
+ return &search->cache[idx];
+
+ if (search->search_ended)
+ return NULL;
+
+ while (idx >= search->num_entries) {
+ struct samr_displayentry entry;
+
+ if (!search->next_entry(search, &entry)) {
+ search->search_end(search);
+ search->search_ended = True;
+ break;
+ }
+
+ ADD_TO_LARGE_ARRAY(search, struct samr_displayentry,
+ entry, &search->cache, &search->num_entries,
+ &search->cache_size);
+ }
+
+ return (search->num_entries > idx) ? &search->cache[idx] : NULL;
+}
+
+struct pdb_search *pdb_search_users(TALLOC_CTX *mem_ctx, uint32_t acct_flags)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ result = pdb_search_init(mem_ctx, PDB_USER_SEARCH);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (!pdb->search_users(pdb, result, acct_flags)) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ return result;
+}
+
+struct pdb_search *pdb_search_groups(TALLOC_CTX *mem_ctx)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ result = pdb_search_init(mem_ctx, PDB_GROUP_SEARCH);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (!pdb->search_groups(pdb, result)) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ return result;
+}
+
+struct pdb_search *pdb_search_aliases(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ struct pdb_search *result;
+
+ if (pdb == NULL) return NULL;
+
+ result = pdb_search_init(mem_ctx, PDB_ALIAS_SEARCH);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (!pdb->search_aliases(pdb, result, sid)) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+ return result;
+}
+
+uint32_t pdb_search_entries(struct pdb_search *search,
+ uint32_t start_idx, uint32_t max_entries,
+ struct samr_displayentry **result)
+{
+ struct samr_displayentry *end_entry;
+ uint32_t end_idx = start_idx+max_entries-1;
+
+ /* The first entry needs to be searched after the last. Otherwise the
+ * first entry might have moved due to a realloc during the search for
+ * the last entry. */
+
+ end_entry = pdb_search_getentry(search, end_idx);
+ *result = pdb_search_getentry(search, start_idx);
+
+ if (end_entry != NULL)
+ return max_entries;
+
+ if (start_idx >= search->num_entries)
+ return 0;
+
+ return search->num_entries - start_idx;
+}
+
+/*******************************************************************
+ trustdom methods
+ *******************************************************************/
+
+bool pdb_get_trusteddom_pw(const char *domain, char** pwd, struct dom_sid *sid,
+ time_t *pass_last_set_time)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_trusteddom_pw(pdb, domain, pwd, sid,
+ pass_last_set_time);
+}
+
+NTSTATUS pdb_get_trusteddom_creds(const char *domain, TALLOC_CTX *mem_ctx,
+ struct cli_credentials **creds)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_trusteddom_creds(pdb, domain, mem_ctx, creds);
+}
+
+bool pdb_set_trusteddom_pw(const char* domain, const char* pwd,
+ const struct dom_sid *sid)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_trusteddom_pw(pdb, domain, pwd, sid);
+}
+
+bool pdb_del_trusteddom_pw(const char *domain)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_trusteddom_pw(pdb, domain);
+}
+
+NTSTATUS pdb_enum_trusteddoms(TALLOC_CTX *mem_ctx, uint32_t *num_domains,
+ struct trustdom_info ***domains)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_trusteddoms(pdb, mem_ctx, num_domains, domains);
+}
+
+/*******************************************************************
+ the defaults for trustdom methods:
+ these simply call the original passdb/secrets.c actions,
+ to be replaced by pdb_ldap.
+ *******************************************************************/
+
+static bool pdb_default_get_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain,
+ char** pwd,
+ struct dom_sid *sid,
+ time_t *pass_last_set_time)
+{
+ return secrets_fetch_trusted_domain_password(domain, pwd,
+ sid, pass_last_set_time);
+
+}
+
+static NTSTATUS pdb_default_get_trusteddom_creds(struct pdb_methods *methods,
+ const char *domain,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials **creds)
+{
+ *creds = NULL;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static bool pdb_default_set_trusteddom_pw(struct pdb_methods *methods,
+ const char* domain,
+ const char* pwd,
+ const struct dom_sid *sid)
+{
+ return secrets_store_trusted_domain_password(domain, pwd, sid);
+}
+
+static bool pdb_default_del_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain)
+{
+ return trusted_domain_password_delete(domain);
+}
+
+static NTSTATUS pdb_default_enum_trusteddoms(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_domains,
+ struct trustdom_info ***domains)
+{
+ return secrets_trusted_domains(mem_ctx, num_domains, domains);
+}
+
+/*******************************************************************
+ trusted_domain methods
+ *******************************************************************/
+
+NTSTATUS pdb_get_trusted_domain(TALLOC_CTX *mem_ctx, const char *domain,
+ struct pdb_trusted_domain **td)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_trusted_domain(pdb, mem_ctx, domain, td);
+}
+
+NTSTATUS pdb_get_trusted_domain_by_sid(TALLOC_CTX *mem_ctx, struct dom_sid *sid,
+ struct pdb_trusted_domain **td)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_trusted_domain_by_sid(pdb, mem_ctx, sid, td);
+}
+
+NTSTATUS pdb_set_trusted_domain(const char* domain,
+ const struct pdb_trusted_domain *td)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_trusted_domain(pdb, domain, td);
+}
+
+NTSTATUS pdb_del_trusted_domain(const char *domain)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->del_trusted_domain(pdb, domain);
+}
+
+NTSTATUS pdb_enum_trusted_domains(TALLOC_CTX *mem_ctx, uint32_t *num_domains,
+ struct pdb_trusted_domain ***domains)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_trusted_domains(pdb, mem_ctx, num_domains, domains);
+}
+
+static NTSTATUS pdb_default_get_trusted_domain(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const char *domain,
+ struct pdb_trusted_domain **td)
+{
+ struct trustAuthInOutBlob taiob;
+ struct AuthenticationInformation aia;
+ struct pdb_trusted_domain *tdom;
+ enum ndr_err_code ndr_err;
+ time_t last_set_time;
+ char *pwd;
+ bool ok;
+
+ tdom = talloc(mem_ctx, struct pdb_trusted_domain);
+ if (!tdom) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tdom->domain_name = talloc_strdup(tdom, domain);
+ tdom->netbios_name = talloc_strdup(tdom, domain);
+ if (!tdom->domain_name || !tdom->netbios_name) {
+ talloc_free(tdom);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tdom->trust_auth_incoming = data_blob_null;
+
+ ok = pdb_get_trusteddom_pw(domain, &pwd, &tdom->security_identifier,
+ &last_set_time);
+ if (!ok) {
+ talloc_free(tdom);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ZERO_STRUCT(taiob);
+ ZERO_STRUCT(aia);
+ taiob.count = 1;
+ taiob.current.count = 1;
+ taiob.current.array = &aia;
+ unix_to_nt_time(&aia.LastUpdateTime, last_set_time);
+
+ aia.AuthType = TRUST_AUTH_TYPE_CLEAR;
+ aia.AuthInfo.clear.size = strlen(pwd);
+ aia.AuthInfo.clear.password = (uint8_t *)talloc_memdup(tdom, pwd,
+ aia.AuthInfo.clear.size);
+ SAFE_FREE(pwd);
+ if (aia.AuthInfo.clear.password == NULL) {
+ talloc_free(tdom);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ taiob.previous.count = 0;
+ taiob.previous.array = NULL;
+
+ ndr_err = ndr_push_struct_blob(&tdom->trust_auth_outgoing,
+ tdom, &taiob,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tdom);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tdom->trust_direction = LSA_TRUST_DIRECTION_OUTBOUND;
+ tdom->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+ tdom->trust_attributes = 0;
+ tdom->trust_forest_trust_info = data_blob_null;
+
+ *td = tdom;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_default_get_trusted_domain_by_sid(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid *sid,
+ struct pdb_trusted_domain **td)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#define IS_NULL_DATA_BLOB(d) ((d).data == NULL && (d).length == 0)
+
+static NTSTATUS pdb_default_set_trusted_domain(struct pdb_methods *methods,
+ const char* domain,
+ const struct pdb_trusted_domain *td)
+{
+ struct trustAuthInOutBlob taiob;
+ struct AuthenticationInformation *aia;
+ enum ndr_err_code ndr_err;
+ char *pwd;
+ bool ok;
+
+ if (td->trust_attributes != 0 ||
+ td->trust_type != LSA_TRUST_TYPE_DOWNLEVEL ||
+ td->trust_direction != LSA_TRUST_DIRECTION_OUTBOUND ||
+ !IS_NULL_DATA_BLOB(td->trust_auth_incoming) ||
+ !IS_NULL_DATA_BLOB(td->trust_forest_trust_info)) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ ZERO_STRUCT(taiob);
+ ndr_err = ndr_pull_struct_blob(&td->trust_auth_outgoing, talloc_tos(),
+ &taiob,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ aia = (struct AuthenticationInformation *) taiob.current.array;
+
+ if (taiob.count != 1 || taiob.current.count != 1 ||
+ taiob.previous.count != 0 ||
+ aia->AuthType != TRUST_AUTH_TYPE_CLEAR) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ pwd = talloc_strndup(talloc_tos(), (char *) aia->AuthInfo.clear.password,
+ aia->AuthInfo.clear.size);
+ if (!pwd) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = pdb_set_trusteddom_pw(domain, pwd, &td->security_identifier);
+ if (!ok) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_default_del_trusted_domain(struct pdb_methods *methods,
+ const char *domain)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_enum_trusted_domains(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_domains,
+ struct pdb_trusted_domain ***domains)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static struct pdb_domain_info *pdb_default_get_domain_info(
+ struct pdb_methods *m, TALLOC_CTX *mem_ctx)
+{
+ return NULL;
+}
+
+/*****************************************************************
+ UPN suffixes
+ *****************************************************************/
+static NTSTATUS pdb_default_enum_upn_suffixes(struct pdb_methods *pdb,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_suffixes,
+ char ***suffixes)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_default_set_upn_suffixes(struct pdb_methods *pdb,
+ uint32_t num_suffixes,
+ const char **suffixes)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS pdb_enum_upn_suffixes(TALLOC_CTX *mem_ctx,
+ uint32_t *num_suffixes,
+ char ***suffixes)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->enum_upn_suffixes(pdb, mem_ctx, num_suffixes, suffixes);
+}
+
+NTSTATUS pdb_set_upn_suffixes(uint32_t num_suffixes,
+ const char **suffixes)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_upn_suffixes(pdb, num_suffixes, suffixes);
+}
+
+/*******************************************************************
+ idmap control methods
+ *******************************************************************/
+static bool pdb_default_is_responsible_for_our_sam(
+ struct pdb_methods *methods)
+{
+ return true;
+}
+
+static bool pdb_default_is_responsible_for_builtin(
+ struct pdb_methods *methods)
+{
+ return true;
+}
+
+static bool pdb_default_is_responsible_for_wellknown(
+ struct pdb_methods *methods)
+{
+ return false;
+}
+
+static bool pdb_default_is_responsible_for_unix_users(
+ struct pdb_methods *methods)
+{
+ return true;
+}
+
+static bool pdb_default_is_responsible_for_unix_groups(
+ struct pdb_methods *methods)
+{
+ return true;
+}
+
+static bool pdb_default_is_responsible_for_everything_else(
+ struct pdb_methods *methods)
+{
+ return false;
+}
+
+bool pdb_is_responsible_for_our_sam(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_our_sam(pdb);
+}
+
+bool pdb_is_responsible_for_builtin(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_builtin(pdb);
+}
+
+bool pdb_is_responsible_for_wellknown(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_wellknown(pdb);
+}
+
+bool pdb_is_responsible_for_unix_users(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_unix_users(pdb);
+}
+
+bool pdb_is_responsible_for_unix_groups(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_unix_groups(pdb);
+}
+
+bool pdb_is_responsible_for_everything_else(void)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->is_responsible_for_everything_else(pdb);
+}
+
+/*******************************************************************
+ secret methods
+ *******************************************************************/
+
+NTSTATUS pdb_get_secret(TALLOC_CTX *mem_ctx,
+ const char *secret_name,
+ DATA_BLOB *secret_current,
+ NTTIME *secret_current_lastchange,
+ DATA_BLOB *secret_old,
+ NTTIME *secret_old_lastchange,
+ struct security_descriptor **sd)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->get_secret(pdb, mem_ctx, secret_name,
+ secret_current, secret_current_lastchange,
+ secret_old, secret_old_lastchange,
+ sd);
+}
+
+NTSTATUS pdb_set_secret(const char *secret_name,
+ DATA_BLOB *secret_current,
+ DATA_BLOB *secret_old,
+ struct security_descriptor *sd)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->set_secret(pdb, secret_name,
+ secret_current,
+ secret_old,
+ sd);
+}
+
+NTSTATUS pdb_delete_secret(const char *secret_name)
+{
+ struct pdb_methods *pdb = pdb_get_methods();
+ return pdb->delete_secret(pdb, secret_name);
+}
+
+static NTSTATUS pdb_default_get_secret(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const char *secret_name,
+ DATA_BLOB *secret_current,
+ NTTIME *secret_current_lastchange,
+ DATA_BLOB *secret_old,
+ NTTIME *secret_old_lastchange,
+ struct security_descriptor **sd)
+{
+ return lsa_secret_get(mem_ctx, secret_name,
+ secret_current,
+ secret_current_lastchange,
+ secret_old,
+ secret_old_lastchange,
+ sd);
+}
+
+static NTSTATUS pdb_default_set_secret(struct pdb_methods *methods,
+ const char *secret_name,
+ DATA_BLOB *secret_current,
+ DATA_BLOB *secret_old,
+ struct security_descriptor *sd)
+{
+ return lsa_secret_set(secret_name,
+ secret_current,
+ secret_old,
+ sd);
+}
+
+static NTSTATUS pdb_default_delete_secret(struct pdb_methods *methods,
+ const char *secret_name)
+{
+ return lsa_secret_delete(secret_name);
+}
+
+/*******************************************************************
+ Create a pdb_methods structure and initialize it with the default
+ operations. In this way a passdb module can simply implement
+ the functionality it cares about. However, normally this is done
+ in groups of related functions.
+*******************************************************************/
+
+NTSTATUS make_pdb_method( struct pdb_methods **methods )
+{
+ /* allocate memory for the structure as its own talloc CTX */
+
+ *methods = talloc_zero(NULL, struct pdb_methods);
+ if (*methods == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*methods)->get_domain_info = pdb_default_get_domain_info;
+ (*methods)->getsampwnam = pdb_default_getsampwnam;
+ (*methods)->getsampwsid = pdb_default_getsampwsid;
+ (*methods)->create_user = pdb_default_create_user;
+ (*methods)->delete_user = pdb_default_delete_user;
+ (*methods)->add_sam_account = pdb_default_add_sam_account;
+ (*methods)->update_sam_account = pdb_default_update_sam_account;
+ (*methods)->delete_sam_account = pdb_default_delete_sam_account;
+ (*methods)->rename_sam_account = pdb_default_rename_sam_account;
+ (*methods)->update_login_attempts = pdb_default_update_login_attempts;
+
+ (*methods)->getgrsid = pdb_default_getgrsid;
+ (*methods)->getgrgid = pdb_default_getgrgid;
+ (*methods)->getgrnam = pdb_default_getgrnam;
+ (*methods)->create_dom_group = pdb_default_create_dom_group;
+ (*methods)->delete_dom_group = pdb_default_delete_dom_group;
+ (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry;
+ (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry;
+ (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry;
+ (*methods)->enum_group_mapping = pdb_default_enum_group_mapping;
+ (*methods)->enum_group_members = pdb_default_enum_group_members;
+ (*methods)->enum_group_memberships = pdb_default_enum_group_memberships;
+ (*methods)->set_unix_primary_group = pdb_default_set_unix_primary_group;
+ (*methods)->add_groupmem = pdb_default_add_groupmem;
+ (*methods)->del_groupmem = pdb_default_del_groupmem;
+ (*methods)->create_alias = pdb_default_create_alias;
+ (*methods)->delete_alias = pdb_default_delete_alias;
+ (*methods)->get_aliasinfo = pdb_default_get_aliasinfo;
+ (*methods)->set_aliasinfo = pdb_default_set_aliasinfo;
+ (*methods)->add_aliasmem = pdb_default_add_aliasmem;
+ (*methods)->del_aliasmem = pdb_default_del_aliasmem;
+ (*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)->id_to_sid = pdb_default_id_to_sid;
+ (*methods)->sid_to_id = pdb_default_sid_to_id;
+
+ (*methods)->search_groups = pdb_default_search_groups;
+ (*methods)->search_aliases = pdb_default_search_aliases;
+
+ (*methods)->get_trusteddom_pw = pdb_default_get_trusteddom_pw;
+ (*methods)->get_trusteddom_creds = pdb_default_get_trusteddom_creds;
+ (*methods)->set_trusteddom_pw = pdb_default_set_trusteddom_pw;
+ (*methods)->del_trusteddom_pw = pdb_default_del_trusteddom_pw;
+ (*methods)->enum_trusteddoms = pdb_default_enum_trusteddoms;
+
+ (*methods)->get_trusted_domain = pdb_default_get_trusted_domain;
+ (*methods)->get_trusted_domain_by_sid = pdb_default_get_trusted_domain_by_sid;
+ (*methods)->set_trusted_domain = pdb_default_set_trusted_domain;
+ (*methods)->del_trusted_domain = pdb_default_del_trusted_domain;
+ (*methods)->enum_trusted_domains = pdb_default_enum_trusted_domains;
+
+ (*methods)->get_secret = pdb_default_get_secret;
+ (*methods)->set_secret = pdb_default_set_secret;
+ (*methods)->delete_secret = pdb_default_delete_secret;
+
+ (*methods)->enum_upn_suffixes = pdb_default_enum_upn_suffixes;
+ (*methods)->set_upn_suffixes = pdb_default_set_upn_suffixes;
+
+ (*methods)->is_responsible_for_our_sam =
+ pdb_default_is_responsible_for_our_sam;
+ (*methods)->is_responsible_for_builtin =
+ pdb_default_is_responsible_for_builtin;
+ (*methods)->is_responsible_for_wellknown =
+ pdb_default_is_responsible_for_wellknown;
+ (*methods)->is_responsible_for_unix_users =
+ pdb_default_is_responsible_for_unix_users;
+ (*methods)->is_responsible_for_unix_groups =
+ pdb_default_is_responsible_for_unix_groups;
+ (*methods)->is_responsible_for_everything_else =
+ pdb_default_is_responsible_for_everything_else;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
new file mode 100644
index 0000000..ed5c3e9
--- /dev/null
+++ b/source3/passdb/pdb_ldap.c
@@ -0,0 +1,6822 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+ Copyright (C) Simo Sorce 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* TODO:
+* persistent connections: if using NSS LDAP, many connections are made
+* however, using only one within Samba would be nice
+*
+* Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
+*
+* Other LDAP based login attributes: accountExpires, etc.
+* (should be the domain of Samba proper, but the sam_password/struct samu
+* structures don't have fields for some of these attributes)
+*
+* SSL is done, but can't get the certificate based authentication to work
+* against on my test platform (Linux 2.4, OpenLDAP 2.x)
+*/
+
+/* NOTE: this will NOT work against an Active Directory server
+* due to the fact that the two password fields cannot be retrieved
+* from a server; recommend using security = domain in this situation
+* and/or winbind
+*/
+
+#include "includes.h"
+#include "passdb.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "secrets.h"
+#include "idmap_cache.h"
+#include "../libcli/security/security.h"
+#include "../lib/util/util_pw.h"
+#include "lib/winbind_util.h"
+#include "librpc/gen_ndr/idmap.h"
+#include "lib/param/loadparm.h"
+#include "lib/util_sid_passdb.h"
+#include "lib/util/smb_strtox.h"
+#include "lib/util/string_wrappers.h"
+#include "source3/lib/substitute.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#include <lber.h>
+#include <ldap.h>
+
+
+#include "smbldap.h"
+#include "passdb/pdb_ldap.h"
+#include "passdb/pdb_nds.h"
+#include "passdb/pdb_ldap_util.h"
+#include "passdb/pdb_ldap_schema.h"
+
+/**********************************************************************
+ Simple helper function to make stuff better readable
+ **********************************************************************/
+
+LDAP *priv2ld(struct ldapsam_privates *priv)
+{
+ return smbldap_get_ldap(priv->smbldap_state);
+}
+
+/**********************************************************************
+ Get the attribute name given a user schema version.
+ **********************************************************************/
+
+static const char* get_userattr_key2string( int schema_ver, int key )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_key2string( attrib_map_v30, key );
+
+ default:
+ DEBUG(0,("get_userattr_key2string: unknown schema version specified\n"));
+ break;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+ Return the list of attribute names given a user schema version.
+**********************************************************************/
+
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_list( mem_ctx, attrib_map_v30 );
+ default:
+ DEBUG(0,("get_userattr_list: unknown schema version specified!\n"));
+ break;
+ }
+
+ return NULL;
+}
+
+/**************************************************************************
+ Return the list of attribute names to delete given a user schema version.
+**************************************************************************/
+
+static const char** get_userattr_delete_list( TALLOC_CTX *mem_ctx,
+ int schema_ver )
+{
+ switch ( schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ return get_attr_list( mem_ctx,
+ attrib_map_to_delete_v30 );
+ default:
+ DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n"));
+ break;
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************
+ Generate the LDAP search filter for the objectclass based on the
+ version of the schema we are using.
+******************************************************************/
+
+static const char* get_objclass_filter( int schema_ver )
+{
+ fstring objclass_filter;
+ char *result;
+
+ switch( schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT );
+ break;
+ default:
+ DEBUG(0,("get_objclass_filter: Invalid schema version specified!\n"));
+ objclass_filter[0] = '\0';
+ break;
+ }
+
+ result = talloc_strdup(talloc_tos(), objclass_filter);
+ SMB_ASSERT(result != NULL);
+ return result;
+}
+
+/*****************************************************************
+ 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;
+ char *suffix = NULL;
+ char *tok;
+ const char *p;
+ const char **attrs;
+
+ /* Unfortunately 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(
+ smbldap_get_ldap(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;
+
+ if ((attrs = talloc_array(mem_ctx, const char *, 2)) == NULL) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* 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;
+ suffix = talloc_asprintf(mem_ctx,
+ "cn=syncrepl%d,%s", rid, lp_ldap_suffix());
+ if (!suffix) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ } else {
+
+ /* provider contextCSN */
+ /* 20050126161620Z#000009#00#000000 */
+ attrs[0] = talloc_strdup(mem_ctx, "contextCSN");
+ attrs[1] = NULL;
+ suffix = talloc_asprintf(mem_ctx,
+ "cn=ldapsync,%s", lp_ldap_suffix());
+
+ if (!suffix) {
+ ntstatus = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state, suffix,
+ LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg);
+
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ num_result = ldap_count_entries(
+ smbldap_get_ldap(ldap_state->smbldap_state), 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(
+ smbldap_get_ldap(ldap_state->smbldap_state), msg);
+ if (entry == NULL) {
+ DEBUG(3,("ldapsam_get_seq_num: Could not retrieve entry\n"));
+ goto done;
+ }
+
+ values = ldap_get_values(
+ smbldap_get_ldap(ldap_state->smbldap_state), 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_talloc(mem_ctx, &p, &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.
+******************************************************************/
+
+int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
+ const char *user,
+ LDAPMessage ** result,
+ const char **attr)
+{
+ char *filter = NULL;
+ char *escape_user = escape_ldap_string(talloc_tos(), user);
+ int ret = -1;
+
+ if (!escape_user) {
+ return LDAP_NO_MEMORY;
+ }
+
+ /*
+ * in the filter expression, replace %u with the real name
+ * so in ldap filter, %u MUST exist :-)
+ */
+ filter = talloc_asprintf(talloc_tos(), "(&%s%s)", "(uid=%u)",
+ get_objclass_filter(ldap_state->schema_ver));
+ if (!filter) {
+ TALLOC_FREE(escape_user);
+ return LDAP_NO_MEMORY;
+ }
+ /*
+ * have to use this here because $ is filtered out
+ * in string_sub
+ */
+
+ filter = talloc_all_string_sub(talloc_tos(),
+ filter, "%u", escape_user);
+ TALLOC_FREE(escape_user);
+ if (!filter) {
+ return LDAP_NO_MEMORY;
+ }
+
+ ret = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr, result);
+ TALLOC_FREE(filter);
+ return ret;
+}
+
+/*******************************************************************
+ Run the search by SID.
+******************************************************************/
+
+static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
+ const struct dom_sid *sid, LDAPMessage ** result,
+ const char **attr)
+{
+ char *filter = NULL;
+ int rc;
+ struct dom_sid_buf sid_string;
+
+ filter = talloc_asprintf(talloc_tos(), "(&(%s=%s)%s)",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ dom_sid_str_buf(sid, &sid_string),
+ get_objclass_filter(ldap_state->schema_ver));
+ if (!filter) {
+ return LDAP_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr, result);
+
+ TALLOC_FREE(filter);
+ return rc;
+}
+
+/*******************************************************************
+ Delete complete object or objectclass and attrs from
+ object found in search_result depending on lp_ldap_delete_dn
+******************************************************************/
+
+static int ldapsam_delete_entry(struct ldapsam_privates *priv,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *entry,
+ const char *objectclass,
+ const char **attrs)
+{
+ LDAPMod **mods = NULL;
+ char *name;
+ const char *dn;
+ BerElement *ptr = NULL;
+
+ dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry);
+ if (dn == NULL) {
+ return LDAP_NO_MEMORY;
+ }
+
+ if (lp_ldap_delete_dn()) {
+ return smbldap_delete(priv->smbldap_state, dn);
+ }
+
+ /* Ok, delete only the SAM attributes */
+
+ for (name = ldap_first_attribute(priv2ld(priv), entry, &ptr);
+ name != NULL;
+ name = ldap_next_attribute(priv2ld(priv), entry, ptr)) {
+ const char **attrib;
+
+ /* We are only allowed to delete the attributes that
+ really exist. */
+
+ for (attrib = attrs; *attrib != NULL; attrib++) {
+ if (strequal(*attrib, name)) {
+ DEBUG(10, ("ldapsam_delete_entry: deleting "
+ "attribute %s\n", name));
+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, name,
+ NULL);
+ }
+ }
+ ldap_memfree(name);
+ }
+
+ if (ptr != NULL) {
+ ber_free(ptr, 0);
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
+ smbldap_talloc_autofree_ldapmod(mem_ctx, mods);
+
+ return smbldap_modify(priv->smbldap_state, dn, mods);
+}
+
+static time_t ldapsam_get_entry_timestamp( struct ldapsam_privates *ldap_state, LDAPMessage * entry)
+{
+ char *temp;
+ struct tm tm = {};
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_MOD_TIMESTAMP),
+ talloc_tos());
+ if (!temp) {
+ return (time_t) 0;
+ }
+
+ if ( !strptime(temp, "%Y%m%d%H%M%SZ", &tm)) {
+ DEBUG(2,("ldapsam_get_entry_timestamp: strptime failed on: %s\n",
+ (char*)temp));
+ TALLOC_FREE(temp);
+ return (time_t) 0;
+ }
+ TALLOC_FREE(temp);
+ tzset();
+ return timegm(&tm);
+}
+
+/**********************************************************************
+ Initialize struct samu from an LDAP query.
+ (Based on init_sam_from_buffer in pdb_tdb.c)
+*********************************************************************/
+
+static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
+ struct samu * sampass,
+ LDAPMessage * entry)
+{
+ time_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ ldap_entry_time,
+ bad_password_time;
+ char *username = NULL,
+ *domain = NULL,
+ *nt_username = NULL,
+ *fullname = NULL,
+ *homedir = NULL,
+ *dir_drive = NULL,
+ *logon_script = NULL,
+ *profile_path = NULL,
+ *acct_desc = NULL,
+ *workstations = NULL,
+ *munged_dial = NULL;
+ uint32_t user_rid;
+ uint8_t smblmpwd[LM_HASH_LEN],
+ smbntpwd[NT_HASH_LEN];
+ bool use_samba_attrs = True;
+ uint16_t logon_divs;
+ uint16_t bad_password_count = 0,
+ logon_count = 0;
+ uint32_t hours_len;
+ uint8_t hours[MAX_HOURS_LEN];
+ char *temp = NULL;
+ struct login_cache cache_entry;
+ uint32_t pwHistLen;
+ bool expand_explicit = lp_passdb_expand_explicit();
+ bool ret = false;
+ TALLOC_CTX *ctx = talloc_init("init_sam_from_ldap");
+
+ if (!ctx) {
+ return false;
+ }
+ if (sampass == NULL || ldap_state == NULL || entry == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
+ goto fn_exit;
+ }
+
+ if (priv2ld(ldap_state) == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->"
+ "ldap_struct is NULL!\n"));
+ goto fn_exit;
+ }
+
+ if (!(username = smbldap_talloc_first_attribute(priv2ld(ldap_state),
+ entry,
+ "uid",
+ ctx))) {
+ DEBUG(1, ("init_sam_from_ldap: No uid attribute found for "
+ "this user!\n"));
+ goto fn_exit;
+ }
+
+ DEBUG(2, ("init_sam_from_ldap: Entry found for user: %s\n", username));
+
+ nt_username = talloc_strdup(ctx, username);
+ if (!nt_username) {
+ goto fn_exit;
+ }
+
+ domain = talloc_strdup(ctx, ldap_state->domain_name);
+ if (!domain) {
+ goto fn_exit;
+ }
+
+ pdb_set_username(sampass, username, PDB_SET);
+
+ pdb_set_domain(sampass, domain, PDB_DEFAULT);
+ pdb_set_nt_username(sampass, nt_username, PDB_SET);
+
+ /* deal with different attributes between the schema first */
+
+ if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ) {
+ if ((temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ ctx))!=NULL) {
+ pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
+ }
+ } else {
+ if ((temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_RID),
+ ctx))!=NULL) {
+ user_rid = (uint32_t)atol(temp);
+ pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
+ }
+ }
+
+ if (IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
+ DEBUG(1, ("init_sam_from_ldap: no %s or %s attribute found for this user %s\n",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_RID),
+ username));
+ return False;
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_LAST_SET),
+ ctx);
+ if (temp) {
+ pass_last_set_time = (time_t) atol(temp);
+ pdb_set_pass_last_set_time(sampass,
+ pass_last_set_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_TIME),
+ ctx);
+ if (temp) {
+ logon_time = (time_t) atol(temp);
+ pdb_set_logon_time(sampass, logon_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGOFF_TIME),
+ ctx);
+ if (temp) {
+ logoff_time = (time_t) atol(temp);
+ pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_KICKOFF_TIME),
+ ctx);
+ if (temp) {
+ kickoff_time = (time_t) atol(temp);
+ pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_CAN_CHANGE),
+ ctx);
+ if (temp) {
+ pass_can_change_time = (time_t) atol(temp);
+ pdb_set_pass_can_change_time(sampass,
+ pass_can_change_time, PDB_SET);
+ }
+
+ /* recommend that 'gecos' and 'displayName' should refer to the same
+ * attribute OID. userFullName depreciated, only used by Samba
+ * primary rules of LDAP: don't make a new attribute when one is already defined
+ * that fits your needs; using cn then displayName rather than 'userFullName'
+ */
+
+ fullname = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_DISPLAY_NAME),
+ ctx);
+ if (fullname) {
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+ } else {
+ fullname = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_CN),
+ ctx);
+ if (fullname) {
+ pdb_set_fullname(sampass, fullname, PDB_SET);
+ }
+ }
+
+ dir_drive = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_HOME_DRIVE),
+ ctx);
+ if (dir_drive) {
+ pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
+ } else {
+ pdb_set_dir_drive( sampass, lp_logon_drive(), PDB_DEFAULT );
+ }
+
+ homedir = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_HOME_PATH),
+ ctx);
+ if (homedir) {
+ if (expand_explicit) {
+ homedir = talloc_sub_basic(ctx,
+ username,
+ domain,
+ homedir);
+ if (!homedir) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_homedir(sampass, homedir, PDB_SET);
+ } else {
+ pdb_set_homedir(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_home()),
+ PDB_DEFAULT);
+ }
+
+ logon_script = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_SCRIPT),
+ ctx);
+ if (logon_script) {
+ if (expand_explicit) {
+ logon_script = talloc_sub_basic(ctx,
+ username,
+ domain,
+ logon_script);
+ if (!logon_script) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_logon_script(sampass, logon_script, PDB_SET);
+ } else {
+ pdb_set_logon_script(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_script()),
+ PDB_DEFAULT );
+ }
+
+ profile_path = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PROFILE_PATH),
+ ctx);
+ if (profile_path) {
+ if (expand_explicit) {
+ profile_path = talloc_sub_basic(ctx,
+ username,
+ domain,
+ profile_path);
+ if (!profile_path) {
+ goto fn_exit;
+ }
+ }
+ pdb_set_profile_path(sampass, profile_path, PDB_SET);
+ } else {
+ pdb_set_profile_path(sampass,
+ talloc_sub_basic(ctx, username, domain,
+ lp_logon_path()),
+ PDB_DEFAULT );
+ }
+
+ acct_desc = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_DESC),
+ ctx);
+ if (acct_desc) {
+ pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
+ }
+
+ workstations = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_WKS),
+ ctx);
+ if (workstations) {
+ pdb_set_workstations(sampass, workstations, PDB_SET);
+ }
+
+ munged_dial = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_MUNGED_DIAL),
+ ctx);
+ if (munged_dial) {
+ pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
+ }
+
+ /* FIXME: hours stuff should be cleaner */
+
+ logon_divs = 168;
+ hours_len = 21;
+ memset(hours, 0xff, hours_len);
+
+ if (ldap_state->is_nds_ldap) {
+ char *user_dn;
+ 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_talloc_dn(
+ ctx, smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (user_dn != NULL) {
+ DEBUG(3, ("init_sam_from_ldap: smbldap_talloc_dn(ctx, %s) returned '%s'\n", username, user_dn));
+
+ pwd_len = sizeof(clear_text_pw);
+ if (pdb_nds_get_password(ldap_state->smbldap_state, user_dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
+ nt_lm_owf_gen(clear_text_pw, smbntpwd, smblmpwd);
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
+ TALLOC_FREE(user_dn);
+ return False;
+ }
+ ZERO_STRUCT(smblmpwd);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
+ TALLOC_FREE(user_dn);
+ return False;
+ }
+ ZERO_STRUCT(smbntpwd);
+ use_samba_attrs = False;
+ }
+
+ TALLOC_FREE(user_dn);
+
+ } else {
+ DEBUG(0, ("init_sam_from_ldap: failed to get user_dn for '%s'\n", username));
+ }
+ }
+
+ if (use_samba_attrs) {
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LMPW),
+ ctx);
+ if (temp) {
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', strlen(temp)+1);
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
+ goto fn_exit;
+ }
+ ZERO_STRUCT(smblmpwd);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_NTPW),
+ ctx);
+ if (temp) {
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', strlen(temp)+1);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
+ goto fn_exit;
+ }
+ ZERO_STRUCT(smbntpwd);
+ }
+ }
+
+ pwHistLen = 0;
+
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen > 0){
+ uint8_t *pwhist = NULL;
+ int i;
+ char *history_string = talloc_array(ctx, char,
+ MAX_PW_HISTORY_LEN*64);
+
+ if (!history_string) {
+ goto fn_exit;
+ }
+
+ pwHistLen = MIN(pwHistLen, MAX_PW_HISTORY_LEN);
+
+ pwhist = talloc_zero_array(ctx, uint8_t,
+ pwHistLen * PW_HISTORY_ENTRY_LEN);
+ if (pwhist == NULL) {
+ DEBUG(0, ("init_sam_from_ldap: talloc failed!\n"));
+ goto fn_exit;
+ }
+
+ if (smbldap_get_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PWD_HISTORY),
+ history_string,
+ MAX_PW_HISTORY_LEN*64)) {
+ bool hex_failed = false;
+ for (i = 0; i < pwHistLen; i++){
+ /* Get the 16 byte salt. */
+ if (!pdb_gethexpwd(&history_string[i*64],
+ &pwhist[i*PW_HISTORY_ENTRY_LEN])) {
+ hex_failed = true;
+ break;
+ }
+ /* Get the 16 byte MD5 hash of salt+passwd. */
+ if (!pdb_gethexpwd(&history_string[(i*64)+32],
+ &pwhist[(i*PW_HISTORY_ENTRY_LEN)+
+ PW_HISTORY_SALT_LEN])) {
+ hex_failed = True;
+ break;
+ }
+ }
+ if (hex_failed) {
+ DEBUG(2,("init_sam_from_ldap: Failed to get password history for user %s\n",
+ username));
+ memset(pwhist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET)){
+ goto fn_exit;
+ }
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_ACB_INFO),
+ ctx);
+ if (temp) {
+ uint32_t acct_ctrl = 0;
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0) {
+ acct_ctrl |= ACB_NORMAL;
+ }
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
+ }
+
+ pdb_set_hours_len(sampass, hours_len, PDB_SET);
+ pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_COUNT),
+ ctx);
+ if (temp) {
+ bad_password_count = (uint32_t) atol(temp);
+ pdb_set_bad_password_count(sampass,
+ bad_password_count, PDB_SET);
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_TIME),
+ ctx);
+ if (temp) {
+ bad_password_time = (time_t) atol(temp);
+ pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
+ }
+
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_COUNT),
+ ctx);
+ if (temp) {
+ logon_count = (uint32_t) atol(temp);
+ pdb_set_logon_count(sampass, logon_count, PDB_SET);
+ }
+
+ /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_HOURS),
+ ctx);
+ if (temp) {
+ pdb_gethexhours(temp, hours);
+ memset((char *)temp, '\0', strlen(temp) +1);
+ pdb_set_hours(sampass, hours, hours_len, PDB_SET);
+ ZERO_STRUCT(hours);
+ }
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
+ struct passwd unix_pw;
+ bool have_uid = false;
+ bool have_gid = false;
+ struct dom_sid mapped_gsid;
+ const struct dom_sid *primary_gsid;
+ struct unixid id;
+ int error = 0;
+
+ ZERO_STRUCT(unix_pw);
+
+ unix_pw.pw_name = username;
+ unix_pw.pw_passwd = discard_const_p(char, "x");
+
+ temp = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "uidNumber",
+ ctx);
+ if (temp) {
+ /* We've got a uid, feed the cache */
+ unix_pw.pw_uid = smb_strtoul(temp,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_ERR("Failed to convert UID\n");
+ goto fn_exit;
+ }
+ have_uid = true;
+ }
+ temp = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "gidNumber",
+ ctx);
+ if (temp) {
+ /* We've got a uid, feed the cache */
+ unix_pw.pw_gid = smb_strtoul(temp,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_ERR("Failed to convert GID\n");
+ goto fn_exit;
+ }
+ have_gid = true;
+ }
+ unix_pw.pw_gecos = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "gecos",
+ ctx);
+ if (unix_pw.pw_gecos == NULL) {
+ unix_pw.pw_gecos = fullname;
+ }
+ unix_pw.pw_dir = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "homeDirectory",
+ ctx);
+ if (unix_pw.pw_dir == NULL) {
+ unix_pw.pw_dir = discard_const_p(char, "");
+ }
+ unix_pw.pw_shell = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state),
+ entry,
+ "loginShell",
+ ctx);
+ if (unix_pw.pw_shell == NULL) {
+ unix_pw.pw_shell = discard_const_p(char, "");
+ }
+
+ if (have_uid && have_gid) {
+ sampass->unix_pw = tcopy_passwd(sampass, &unix_pw);
+ } else {
+ sampass->unix_pw = Get_Pwnam_alloc(sampass, unix_pw.pw_name);
+ }
+
+ if (sampass->unix_pw == NULL) {
+ DEBUG(0,("init_sam_from_ldap: Failed to find Unix account for %s\n",
+ pdb_get_username(sampass)));
+ goto fn_exit;
+ }
+
+ id.id = sampass->unix_pw->pw_uid;
+ id.type = ID_TYPE_UID;
+
+ idmap_cache_set_sid2unixid(pdb_get_user_sid(sampass), &id);
+
+ gid_to_sid(&mapped_gsid, sampass->unix_pw->pw_gid);
+ primary_gsid = pdb_get_group_sid(sampass);
+ if (primary_gsid && dom_sid_equal(primary_gsid, &mapped_gsid)) {
+ id.id = sampass->unix_pw->pw_gid;
+ id.type = ID_TYPE_GID;
+
+ idmap_cache_set_sid2unixid(primary_gsid, &id);
+ }
+ }
+
+ /* check the timestamp of the cache vs ldap entry */
+ if (!(ldap_entry_time = ldapsam_get_entry_timestamp(ldap_state,
+ entry))) {
+ ret = true;
+ goto fn_exit;
+ }
+
+ /* see if we have newer updates */
+ if (!login_cache_read(sampass, &cache_entry)) {
+ DEBUG (9, ("No cache entry, bad count = %u, bad time = %u\n",
+ (unsigned int)pdb_get_bad_password_count(sampass),
+ (unsigned int)pdb_get_bad_password_time(sampass)));
+ ret = true;
+ goto fn_exit;
+ }
+
+ DEBUG(7, ("ldap time is %u, cache time is %u, bad time = %u\n",
+ (unsigned int)ldap_entry_time,
+ (unsigned int)cache_entry.entry_timestamp,
+ (unsigned int)cache_entry.bad_password_time));
+
+ if (ldap_entry_time > cache_entry.entry_timestamp) {
+ /* cache is older than directory , so
+ we need to delete the entry but allow the
+ fields to be written out */
+ login_cache_delentry(sampass);
+ } else {
+ /* read cache in */
+ pdb_set_acct_ctrl(sampass,
+ pdb_get_acct_ctrl(sampass) |
+ (cache_entry.acct_ctrl & ACB_AUTOLOCK),
+ PDB_SET);
+ pdb_set_bad_password_count(sampass,
+ cache_entry.bad_password_count,
+ PDB_SET);
+ pdb_set_bad_password_time(sampass,
+ cache_entry.bad_password_time,
+ PDB_SET);
+ }
+
+ ret = true;
+
+ fn_exit:
+
+ TALLOC_FREE(ctx);
+ return ret;
+}
+
+/**********************************************************************
+ Initialize the ldap db from a struct samu. Called on update.
+ (Based on init_buffer_from_sam in pdb_tdb.c)
+*********************************************************************/
+
+static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
+ LDAPMessage *existing,
+ LDAPMod *** mods, struct samu * sampass,
+ bool (*need_update)(const struct samu *,
+ enum pdb_elements))
+{
+ char *temp = NULL;
+
+ if (mods == NULL || sampass == NULL) {
+ DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
+ return False;
+ }
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+ if (need_update(sampass, PDB_USERNAME)) {
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ "uid", pdb_get_username(sampass));
+ if (ldap_state->is_nds_ldap) {
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ "cn", pdb_get_username(sampass));
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ "sn", pdb_get_username(sampass));
+ }
+ }
+
+ DEBUG(2, ("init_ldap_from_sam: Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ /* only update the RID if we actually need to */
+ if (need_update(sampass, PDB_USERSID)) {
+ struct dom_sid_buf sid_str;
+ const struct dom_sid *user_sid = pdb_get_user_sid(sampass);
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
+ dom_sid_str_buf(user_sid, &sid_str));
+ break;
+
+ default:
+ DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
+ break;
+ }
+ }
+
+ /* we don't need to store the primary group RID - so leaving it
+ 'free' to hang off the unix primary group makes life easier */
+
+ if (need_update(sampass, PDB_GROUPSID)) {
+ struct dom_sid_buf sid_str;
+ const struct dom_sid *group_sid = pdb_get_group_sid(sampass);
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_PRIMARY_GROUP_SID),
+ dom_sid_str_buf(group_sid, &sid_str));
+ break;
+
+ default:
+ DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
+ break;
+ }
+
+ }
+
+ /* displayName, cn, and gecos should all be the same
+ * most easily accomplished by giving them the same OID
+ * gecos isn't set here b/c it should be handled by the
+ * add-user script
+ * We change displayName only and fall back to cn if
+ * it does not exist.
+ */
+
+ if (need_update(sampass, PDB_FULLNAME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME),
+ pdb_get_fullname(sampass));
+
+ if (need_update(sampass, PDB_ACCTDESC))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC),
+ pdb_get_acct_desc(sampass));
+
+ if (need_update(sampass, PDB_WORKSTATIONS))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS),
+ pdb_get_workstations(sampass));
+
+ if (need_update(sampass, PDB_MUNGEDDIAL))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MUNGED_DIAL),
+ pdb_get_munged_dial(sampass));
+
+ if (need_update(sampass, PDB_SMBHOME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH),
+ pdb_get_homedir(sampass));
+
+ if (need_update(sampass, PDB_DRIVE))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE),
+ pdb_get_dir_drive(sampass));
+
+ if (need_update(sampass, PDB_LOGONSCRIPT))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT),
+ pdb_get_logon_script(sampass));
+
+ if (need_update(sampass, PDB_PROFILE))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH),
+ pdb_get_profile_path(sampass));
+
+ if (asprintf(&temp, "%li", (long int)pdb_get_logon_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_LOGONTIME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", (long int)pdb_get_logoff_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_LOGOFFTIME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", (long int)pdb_get_kickoff_time(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_KICKOFFTIME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", (long int)pdb_get_pass_can_change_time_noncalc(sampass)) < 0) {
+ return false;
+ }
+ if (need_update(sampass, PDB_CANCHANGETIME))
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp);
+ SAFE_FREE(temp);
+
+ if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
+ || (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
+
+ if (need_update(sampass, PDB_LMPASSWD)) {
+ const uchar *lm_pw = pdb_get_lanman_passwd(sampass);
+ if (lm_pw) {
+ char pwstr[34];
+ pdb_sethexpwd(pwstr, lm_pw,
+ pdb_get_acct_ctrl(sampass));
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW),
+ pwstr);
+ } else {
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW),
+ NULL);
+ }
+ }
+ if (need_update(sampass, PDB_NTPASSWD)) {
+ const uchar *nt_pw = pdb_get_nt_passwd(sampass);
+ if (nt_pw) {
+ char pwstr[34];
+ pdb_sethexpwd(pwstr, nt_pw,
+ pdb_get_acct_ctrl(sampass));
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW),
+ pwstr);
+ } else {
+ smbldap_make_mod(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW),
+ NULL);
+ }
+ }
+
+ if (need_update(sampass, PDB_PWHISTORY)) {
+ char *pwstr = NULL;
+ uint32_t pwHistLen = 0;
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+
+ pwstr = SMB_MALLOC_ARRAY(char, 1024);
+ if (!pwstr) {
+ return false;
+ }
+ if (pwHistLen == 0) {
+ /* Remove any password history from the LDAP store. */
+ memset(pwstr, '0', 64); /* NOTE !!!! '0' *NOT '\0' */
+ pwstr[64] = '\0';
+ } else {
+ int i;
+ uint32_t currHistLen = 0;
+ const uint8_t *pwhist = pdb_get_pw_history(sampass, &currHistLen);
+ if (pwhist != NULL) {
+ /* We can only store (1024-1/64 password history entries. */
+ pwHistLen = MIN(pwHistLen, ((1024-1)/64));
+ for (i=0; i< pwHistLen && i < currHistLen; i++) {
+ /* Store the salt. */
+ pdb_sethexpwd(&pwstr[i*64], &pwhist[i*PW_HISTORY_ENTRY_LEN], 0);
+ /* Followed by the md5 hash of salt + md4 hash */
+ pdb_sethexpwd(&pwstr[(i*64)+32],
+ &pwhist[(i*PW_HISTORY_ENTRY_LEN)+PW_HISTORY_SALT_LEN], 0);
+ DEBUG(100, ("pwstr=%s\n", pwstr));
+ }
+ }
+ }
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY),
+ pwstr);
+ SAFE_FREE(pwstr);
+ }
+
+ if (need_update(sampass, PDB_PASSLASTSET)) {
+ if (asprintf(&temp, "%li",
+ (long int)pdb_get_pass_last_set_time(sampass)) < 0) {
+ return false;
+ }
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET),
+ temp);
+ SAFE_FREE(temp);
+ }
+ }
+
+ if (need_update(sampass, PDB_HOURS)) {
+ const uint8_t *hours = pdb_get_hours(sampass);
+ if (hours) {
+ char hourstr[44];
+ pdb_sethexhours(hourstr, hours);
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing,
+ mods,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_LOGON_HOURS),
+ hourstr);
+ }
+ }
+
+ if (need_update(sampass, PDB_ACCTCTRL))
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO),
+ pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ /* password lockout cache:
+ - If we are now autolocking or clearing, we write to ldap
+ - If we are clearing, we delete the cache entry
+ - If the count is > 0, we update the cache
+
+ This even means when autolocking, we cache, just in case the
+ update doesn't work, and we have to cache the autolock flag */
+
+ if (need_update(sampass, PDB_BAD_PASSWORD_COUNT)) /* &&
+ need_update(sampass, PDB_BAD_PASSWORD_TIME)) */ {
+ uint16_t badcount = pdb_get_bad_password_count(sampass);
+ time_t badtime = pdb_get_bad_password_time(sampass);
+ uint32_t pol;
+ pdb_get_account_policy(PDB_POLICY_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));
+
+ if ((badcount >= pol) || (badcount == 0)) {
+ DEBUG(7, ("making mods to update ldap, count=%u, time=%u\n",
+ (unsigned int)badcount, (unsigned int)badtime));
+ if (asprintf(&temp, "%li", (long)badcount) < 0) {
+ return false;
+ }
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_COUNT),
+ temp);
+ SAFE_FREE(temp);
+
+ if (asprintf(&temp, "%li", (long int)badtime) < 0) {
+ return false;
+ }
+ smbldap_make_mod(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ existing, mods,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_BAD_PASSWORD_TIME),
+ temp);
+ SAFE_FREE(temp);
+ }
+ if (badcount == 0) {
+ DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass)));
+ login_cache_delentry(sampass);
+ } else {
+ struct login_cache cache_entry;
+
+ cache_entry.entry_timestamp = time(NULL);
+ cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass);
+ cache_entry.bad_password_count = badcount;
+ cache_entry.bad_password_time = badtime;
+
+ DEBUG(7, ("Updating bad password count and time in login cache\n"));
+ login_cache_write(sampass, &cache_entry);
+ }
+ }
+
+ return True;
+}
+
+/**********************************************************************
+ End enumeration of the LDAP password list.
+*********************************************************************/
+
+static void ldapsam_endsampwent(struct pdb_methods *my_methods)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ if (ldap_state->result) {
+ ldap_msgfree(ldap_state->result);
+ ldap_state->result = NULL;
+ }
+}
+
+static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list,
+ const char *new_attr)
+{
+ int i;
+
+ if (new_attr == NULL) {
+ return;
+ }
+
+ for (i=0; (*attr_list)[i] != NULL; i++) {
+ ;
+ }
+
+ (*attr_list) = talloc_realloc(mem_ctx, (*attr_list),
+ const char *, i+2);
+ SMB_ASSERT((*attr_list) != NULL);
+ (*attr_list)[i] = talloc_strdup((*attr_list), new_attr);
+ (*attr_list)[i+1] = NULL;
+}
+
+static void ldapsam_add_unix_attributes(TALLOC_CTX *mem_ctx,
+ const char ***attr_list)
+{
+ append_attr(mem_ctx, attr_list, "uidNumber");
+ append_attr(mem_ctx, attr_list, "gidNumber");
+ append_attr(mem_ctx, attr_list, "homeDirectory");
+ append_attr(mem_ctx, attr_list, "loginShell");
+ append_attr(mem_ctx, attr_list, "gecos");
+}
+
+/**********************************************************************
+Get struct samu entry from LDAP by username.
+*********************************************************************/
+
+static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, struct samu *user, const char *sname)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ const char ** attr_list;
+ int rc;
+
+ attr_list = get_userattr_list( user, ldap_state->schema_ver );
+ append_attr(user, &attr_list,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_MOD_TIMESTAMP));
+ ldapsam_add_unix_attributes(user, &attr_list);
+ rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result,
+ attr_list);
+ TALLOC_FREE( attr_list );
+
+ if ( rc != LDAP_SUCCESS )
+ return NT_STATUS_NO_SUCH_USER;
+
+ count = ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_getsampwnam: Unable to locate user [%s] count=%d\n", sname, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ } else if (count > 1) {
+ DEBUG(1, ("ldapsam_getsampwnam: Duplicate entries for this user [%s] Failing. count=%d\n", sname, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+ if (entry) {
+ if (!init_sam_from_ldap(ldap_state, user, entry)) {
+ DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ pdb_set_backend_private_data(user, result, NULL,
+ my_methods, PDB_CHANGED);
+ smbldap_talloc_autofree_ldapmsg(user, result);
+ ret = NT_STATUS_OK;
+ } else {
+ ldap_msgfree(result);
+ }
+ return ret;
+}
+
+static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state,
+ const struct dom_sid *sid, LDAPMessage **result)
+{
+ int rc = -1;
+ const char ** attr_list;
+
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT: {
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return LDAP_NO_MEMORY;
+ }
+
+ attr_list = get_userattr_list(tmp_ctx,
+ ldap_state->schema_ver);
+ append_attr(tmp_ctx, &attr_list,
+ get_userattr_key2string(
+ ldap_state->schema_ver,
+ LDAP_ATTR_MOD_TIMESTAMP));
+ ldapsam_add_unix_attributes(tmp_ctx, &attr_list);
+ rc = ldapsam_search_suffix_by_sid(ldap_state, sid,
+ result, attr_list);
+ TALLOC_FREE(tmp_ctx);
+
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+ break;
+ }
+
+ default:
+ DEBUG(0,("Invalid schema version specified\n"));
+ break;
+ }
+ return rc;
+}
+
+/**********************************************************************
+ Get struct samu entry from LDAP by SID.
+*********************************************************************/
+
+static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const struct dom_sid *sid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ int rc;
+
+ rc = ldapsam_get_ldap_user_by_sid(ldap_state,
+ sid, &result);
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_NO_SUCH_USER;
+
+ count = ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (count < 1) {
+ struct dom_sid_buf buf;
+ DEBUG(4, ("ldapsam_getsampwsid: Unable to locate SID [%s] "
+ "count=%d\n",
+ dom_sid_str_buf(sid, &buf),
+ count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ } else if (count > 1) {
+ struct dom_sid_buf buf;
+ DEBUG(1, ("ldapsam_getsampwsid: More than one user with SID "
+ "[%s]. Failing. count=%d\n",
+ dom_sid_str_buf(sid, &buf),
+ count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (!init_sam_from_ldap(ldap_state, user, entry)) {
+ DEBUG(1,("ldapsam_getsampwsid: init_sam_from_ldap failed!\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ pdb_set_backend_private_data(user, result, NULL,
+ my_methods, PDB_CHANGED);
+ smbldap_talloc_autofree_ldapmsg(user, result);
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Do the actual modification - also change a plaintext password if
+ it it set.
+**********************************************************************/
+
+static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
+ struct samu *newpwd, char *dn,
+ LDAPMod **mods, int ldap_op,
+ bool (*need_update)(const struct samu *, enum pdb_elements))
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc;
+
+ if (!newpwd || !dn) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
+ (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
+ need_update(newpwd, PDB_PLAINTEXT_PW) &&
+ (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
+ BerElement *ber;
+ struct berval *bv;
+ char *retoid = NULL;
+ struct berval *retdata = NULL;
+ char *utf8_password;
+ char *utf8_dn;
+ size_t converted_size;
+ int ret;
+
+ if (!ldap_state->is_nds_ldap) {
+
+ if (!smbldap_has_extension(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ LDAP_EXOP_MODIFY_PASSWD)) {
+ DEBUG(2, ("ldap password change requested, but LDAP "
+ "server does not support it -- ignoring\n"));
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!push_utf8_talloc(talloc_tos(), &utf8_password,
+ pdb_get_plaintext_passwd(newpwd),
+ &converted_size))
+ {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
+ TALLOC_FREE(utf8_password);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
+ DEBUG(0,("ber_alloc_t returns NULL\n"));
+ TALLOC_FREE(utf8_password);
+ TALLOC_FREE(utf8_dn);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((ber_printf (ber, "{") < 0) ||
+ (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
+ utf8_dn) < 0)) {
+ DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
+ "value <0\n"));
+ ber_free(ber,1);
+ TALLOC_FREE(utf8_dn);
+ TALLOC_FREE(utf8_password);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((utf8_password != NULL) && (*utf8_password != '\0')) {
+ ret = ber_printf(ber, "ts}",
+ LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
+ utf8_password);
+ } else {
+ ret = ber_printf(ber, "}");
+ }
+
+ if (ret < 0) {
+ DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
+ "value <0\n"));
+ ber_free(ber,1);
+ TALLOC_FREE(utf8_dn);
+ TALLOC_FREE(utf8_password);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((rc = ber_flatten (ber, &bv))<0) {
+ DEBUG(0,("ldapsam_modify_entry: ber_flatten returns a value <0\n"));
+ ber_free(ber,1);
+ TALLOC_FREE(utf8_dn);
+ TALLOC_FREE(utf8_password);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ TALLOC_FREE(utf8_dn);
+ TALLOC_FREE(utf8_password);
+ ber_free(ber, 1);
+
+ if (!ldap_state->is_nds_ldap) {
+ rc = smbldap_extended_operation(ldap_state->smbldap_state,
+ LDAP_EXOP_MODIFY_PASSWD,
+ bv, NULL, NULL, &retoid,
+ &retdata);
+ } else {
+ rc = pdb_nds_set_password(ldap_state->smbldap_state, dn,
+ pdb_get_plaintext_passwd(newpwd));
+ }
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+
+ if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
+ DEBUG(3, ("Could not set userPassword "
+ "attribute due to an objectClass "
+ "violation -- ignoring\n"));
+ ber_bvfree(bv);
+ return NT_STATUS_OK;
+ }
+
+ ldap_get_option(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,("ldapsam_modify_entry: LDAP Password could not be changed for user %s: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string(rc), ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ ber_bvfree(bv);
+#if defined(LDAP_CONSTRAINT_VIOLATION)
+ if (rc == LDAP_CONSTRAINT_VIOLATION)
+ return NT_STATUS_PASSWORD_RESTRICTION;
+#endif
+ return NT_STATUS_UNSUCCESSFUL;
+ } else {
+ DEBUG(3,("ldapsam_modify_entry: LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("ldapsam_modify_entry: LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
+#endif
+ if (retdata)
+ ber_bvfree(retdata);
+ if (retoid)
+ ldap_memfree(retoid);
+ }
+ ber_bvfree(bv);
+ }
+
+ if (!mods) {
+ DEBUG(5,("ldapsam_modify_entry: mods is empty: nothing to modify\n"));
+ /* may be password change below however */
+ } else {
+ switch(ldap_op) {
+ case LDAP_MOD_ADD:
+ if (ldap_state->is_nds_ldap) {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectclass",
+ "inetOrgPerson");
+ } else {
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ "objectclass",
+ LDAP_OBJ_ACCOUNT);
+ }
+ rc = smbldap_add(ldap_state->smbldap_state,
+ dn, mods);
+ break;
+ case LDAP_MOD_REPLACE:
+ rc = smbldap_modify(ldap_state->smbldap_state,
+ dn ,mods);
+ break;
+ default:
+ DEBUG(0,("ldapsam_modify_entry: Wrong LDAP operation type: %d!\n",
+ ldap_op));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (rc!=LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Delete entry from LDAP for username.
+*********************************************************************/
+
+static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods,
+ struct samu * sam_acct)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)my_methods->private_data;
+ const char *sname;
+ int rc;
+ LDAPMessage *msg, *entry;
+ NTSTATUS result = NT_STATUS_NO_MEMORY;
+ const char **attr_list;
+ TALLOC_CTX *mem_ctx;
+
+ if (!sam_acct) {
+ DEBUG(0, ("ldapsam_delete_sam_account: sam_acct was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ sname = pdb_get_username(sam_acct);
+
+ DEBUG(3, ("ldapsam_delete_sam_account: Deleting user %s from "
+ "LDAP.\n", sname));
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ goto done;
+ }
+
+ attr_list = get_userattr_delete_list(mem_ctx, priv->schema_ver );
+ if (attr_list == NULL) {
+ goto done;
+ }
+
+ rc = ldapsam_search_suffix_by_name(priv, sname, &msg, attr_list);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(priv2ld(priv), msg) != 1) ||
+ ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) {
+ DEBUG(5, ("Could not find user %s\n", sname));
+ result = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ }
+
+ rc = ldapsam_delete_entry(
+ priv, mem_ctx, entry,
+ priv->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ?
+ LDAP_OBJ_SAMBASAMACCOUNT : 0,
+ attr_list);
+
+ result = (rc == LDAP_SUCCESS) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ Update struct samu.
+*********************************************************************/
+
+static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
+{
+ NTSTATUS ret;
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc = 0;
+ char *dn;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ const char **attr_list;
+
+ result = (LDAPMessage *)pdb_get_backend_private_data(newpwd, my_methods);
+ if (!result) {
+ attr_list = get_userattr_list(NULL, ldap_state->schema_ver);
+ if (pdb_get_username(newpwd) == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list );
+ TALLOC_FREE( attr_list );
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ pdb_set_backend_private_data(newpwd, result, NULL,
+ my_methods, PDB_CHANGED);
+ smbldap_talloc_autofree_ldapmsg(newpwd, result);
+ }
+
+ if (ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result) == 0) {
+ DEBUG(0, ("ldapsam_update_sam_account: No user to modify!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+ dn = smbldap_talloc_dn(talloc_tos(),
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(4, ("ldapsam_update_sam_account: user %s to be modified has dn: %s\n", pdb_get_username(newpwd), dn));
+
+ if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+ pdb_element_is_changed)) {
+ DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
+ TALLOC_FREE(dn);
+ if (mods != NULL)
+ ldap_mods_free(mods,True);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ((lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_ONLY)
+ && (mods == NULL)) {
+ DEBUG(4,("ldapsam_update_sam_account: mods is empty: nothing to update for user: %s\n",
+ pdb_get_username(newpwd)));
+ TALLOC_FREE(dn);
+ return NT_STATUS_OK;
+ }
+
+ ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, pdb_element_is_changed);
+
+ if (mods != NULL) {
+ ldap_mods_free(mods,True);
+ }
+
+ TALLOC_FREE(dn);
+
+ /*
+ * We need to set the backend private data to NULL here. For example
+ * setuserinfo level 25 does a pdb_update_sam_account twice on the
+ * same one, and with the explicit delete / add logic for attribute
+ * values the second time we would use the wrong "old" value which
+ * does not exist in LDAP anymore. Thus the LDAP server would refuse
+ * the update.
+ * The existing LDAPMessage is still being auto-freed by the
+ * destructor.
+ */
+ pdb_set_backend_private_data(newpwd, NULL, NULL, my_methods,
+ PDB_CHANGED);
+
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+
+ DEBUG(2, ("ldapsam_update_sam_account: successfully modified uid = %s in the LDAP database\n",
+ pdb_get_username(newpwd)));
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Renames a struct samu
+ - The "rename user script" has full responsibility for changing everything
+***************************************************************************/
+
+static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid);
+
+static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ struct dom_sid **pp_sids,
+ gid_t **pp_gids,
+ uint32_t *p_num_groups);
+
+static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ const char *oldname;
+ int rc;
+ char *rename_script = NULL;
+ fstring oldname_lower, newname_lower;
+
+ if (!old_acct) {
+ DEBUG(0, ("ldapsam_rename_sam_account: old_acct was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (!newname) {
+ DEBUG(0, ("ldapsam_rename_sam_account: newname was NULL!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ oldname = pdb_get_username(old_acct);
+
+ /* rename the posix user */
+ rename_script = lp_rename_user_script(talloc_tos(), lp_sub);
+ if (rename_script == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(*rename_script)) {
+ TALLOC_FREE(rename_script);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n",
+ oldname, newname));
+
+ /* We have to allow the account name to end with a '$'.
+ Also, follow the semantics in _samr_create_user() and lower case the
+ posix name but preserve the case in passdb */
+
+ fstrcpy( oldname_lower, oldname );
+ if (!strlower_m( oldname_lower )) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ fstrcpy( newname_lower, newname );
+ if (!strlower_m( newname_lower )) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ rename_script = realloc_string_sub2(rename_script,
+ "%unew",
+ newname_lower,
+ true,
+ true);
+ if (!rename_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ rename_script = realloc_string_sub2(rename_script,
+ "%uold",
+ oldname_lower,
+ true,
+ true);
+ rc = smbrun(rename_script, NULL, NULL);
+
+ DEBUG(rc ? 0 : 3,("Running the command `%s' gave %d\n",
+ rename_script, rc));
+
+ TALLOC_FREE(rename_script);
+
+ if (rc == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ if (rc)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Add struct samu to LDAP.
+*********************************************************************/
+
+static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ int rc;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ int ldap_op = LDAP_MOD_REPLACE;
+ uint32_t num_result;
+ const char **attr_list;
+ char *escape_user = NULL;
+ const char *username = pdb_get_username(newpwd);
+ const struct dom_sid *sid = pdb_get_user_sid(newpwd);
+ char *filter = NULL;
+ char *dn = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ TALLOC_CTX *ctx = talloc_init("ldapsam_add_sam_account");
+
+ if (!ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!username || !*username) {
+ DEBUG(0, ("ldapsam_add_sam_account: Cannot add user without a username!\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fn_exit;
+ }
+
+ /* free this list after the second search or in case we exit on failure */
+ attr_list = get_userattr_list(ctx, ldap_state->schema_ver);
+
+ rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
+
+ if (rc != LDAP_SUCCESS) {
+ goto fn_exit;
+ }
+
+ if (ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result) != 0) {
+ DEBUG(0,("ldapsam_add_sam_account: User '%s' already in the base, with samba attributes\n",
+ username));
+ goto fn_exit;
+ }
+ ldap_msgfree(result);
+ result = NULL;
+
+ if (pdb_element_is_set_or_changed(newpwd, PDB_USERSID)) {
+ rc = ldapsam_get_ldap_user_by_sid(ldap_state,
+ sid, &result);
+ if (rc == LDAP_SUCCESS) {
+ if (ldap_count_entries(
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ result) != 0) {
+ struct dom_sid_buf buf;
+ DEBUG(0,("ldapsam_add_sam_account: SID '%s' "
+ "already in the base, with samba "
+ "attributes\n",
+ dom_sid_str_buf(sid, &buf)));
+ goto fn_exit;
+ }
+ ldap_msgfree(result);
+ result = NULL;
+ }
+ }
+
+ /* does the entry already exist but without a samba attributes?
+ we need to return the samba attributes here */
+
+ escape_user = escape_ldap_string(talloc_tos(), username);
+ filter = talloc_strdup(attr_list, "(uid=%u)");
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ filter = talloc_all_string_sub(attr_list, filter, "%u", escape_user);
+ TALLOC_FREE(escape_user);
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr_list, &result);
+ if ( rc != LDAP_SUCCESS ) {
+ goto fn_exit;
+ }
+
+ num_result = ldap_count_entries(
+ smbldap_get_ldap(ldap_state->smbldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n"));
+ goto fn_exit;
+ }
+
+ /* Check if we need to update an existing entry */
+ if (num_result == 1) {
+ DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry(
+ smbldap_get_ldap(ldap_state->smbldap_state), result);
+ dn = smbldap_talloc_dn(
+ ctx, smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ } else if (ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT) {
+
+ struct dom_sid_buf buf;
+
+ /* There might be a SID for this account already - say an idmap entry */
+
+ filter = talloc_asprintf(ctx,
+ "(&(%s=%s)(|(objectClass=%s)(objectClass=%s)))",
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ dom_sid_str_buf(sid, &buf),
+ LDAP_OBJ_IDMAP_ENTRY,
+ LDAP_OBJ_SID_ENTRY);
+ if (!filter) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ /* free old result before doing a new search */
+ if (result != NULL) {
+ ldap_msgfree(result);
+ result = NULL;
+ }
+ rc = smbldap_search_suffix(ldap_state->smbldap_state,
+ filter, attr_list, &result);
+
+ if ( rc != LDAP_SUCCESS ) {
+ goto fn_exit;
+ }
+
+ num_result = ldap_count_entries(
+ smbldap_get_ldap(ldap_state->smbldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_add_sam_account: More than one user with specified Sid exists: bailing out!\n"));
+ goto fn_exit;
+ }
+
+ /* Check if we need to update an existing entry */
+ if (num_result == 1) {
+
+ DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+ dn = smbldap_talloc_dn (
+ ctx,
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ }
+ }
+
+ if (num_result == 0) {
+ char *escape_username;
+ /* Check if we need to add an entry */
+ DEBUG(3,("ldapsam_add_sam_account: Adding new user\n"));
+ ldap_op = LDAP_MOD_ADD;
+
+ escape_username = escape_rdn_val_string_alloc(username);
+ if (!escape_username) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+
+ if (username[strlen(username)-1] == '$') {
+ dn = talloc_asprintf(ctx,
+ "uid=%s,%s",
+ escape_username,
+ lp_ldap_machine_suffix(talloc_tos()));
+ } else {
+ dn = talloc_asprintf(ctx,
+ "uid=%s,%s",
+ escape_username,
+ lp_ldap_user_suffix(talloc_tos()));
+ }
+
+ SAFE_FREE(escape_username);
+ if (!dn) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fn_exit;
+ }
+ }
+
+ if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+ pdb_element_is_set_or_changed)) {
+ DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
+ if (mods != NULL) {
+ ldap_mods_free(mods, true);
+ }
+ goto fn_exit;
+ }
+
+ if (mods == NULL) {
+ DEBUG(0,("ldapsam_add_sam_account: mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
+ goto fn_exit;
+ }
+ switch ( ldap_state->schema_ver ) {
+ case SCHEMAVER_SAMBASAMACCOUNT:
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBASAMACCOUNT);
+ break;
+ default:
+ DEBUG(0,("ldapsam_add_sam_account: invalid schema version specified\n"));
+ break;
+ }
+
+ status = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, pdb_element_is_set_or_changed);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("ldapsam_add_sam_account: failed to modify/add user with uid = %s (dn = %s)\n",
+ pdb_get_username(newpwd),dn));
+ ldap_mods_free(mods, true);
+ goto fn_exit;
+ }
+
+ DEBUG(2,("ldapsam_add_sam_account: added: uid == %s in the LDAP database\n", pdb_get_username(newpwd)));
+ ldap_mods_free(mods, true);
+
+ status = NT_STATUS_OK;
+
+ fn_exit:
+
+ TALLOC_FREE(ctx);
+ if (result) {
+ ldap_msgfree(result);
+ }
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
+ const char *filter,
+ LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+ const char **attr_list;
+
+ attr_list = get_attr_list(NULL, groupmap_attr_list);
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_suffix(), scope,
+ filter, attr_list, 0, result);
+ TALLOC_FREE(attr_list);
+
+ return rc;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static bool init_group_from_ldap(struct ldapsam_privates *ldap_state,
+ GROUP_MAP *map, LDAPMessage *entry)
+{
+ char *temp = NULL;
+ TALLOC_CTX *ctx = talloc_init("init_group_from_ldap");
+
+ if (ldap_state == NULL || map == NULL || entry == NULL ||
+ smbldap_get_ldap(ldap_state->smbldap_state) == NULL) {
+ DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GIDNUMBER),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GIDNUMBER)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ DEBUG(2, ("init_group_from_ldap: Entry found for group: %s\n", temp));
+
+ map->gid = (gid_t)atol(temp);
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_SID),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ if (!string_to_sid(&map->sid, temp)) {
+ DEBUG(1, ("SID string [%s] could not be read as a valid SID\n", temp));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_TYPE),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
+ get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE)));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ map->sid_name_use = (enum lsa_SidType)atol(temp);
+
+ if ((map->sid_name_use < SID_NAME_USER) ||
+ (map->sid_name_use > SID_NAME_UNKNOWN)) {
+ DEBUG(0, ("init_group_from_ldap: Unknown Group type: %d\n", map->sid_name_use));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_DISPLAY_NAME),
+ ctx);
+ if (!temp) {
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_CN),
+ ctx);
+ if (!temp) {
+ DEBUG(0, ("init_group_from_ldap: Attributes cn not found either \
+for gidNumber(%lu)\n",(unsigned long)map->gid));
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ }
+ map->nt_name = talloc_strdup(map, temp);
+ if (!map->nt_name) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ TALLOC_FREE(temp);
+ temp = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_DESC),
+ ctx);
+ if (!temp) {
+ temp = talloc_strdup(ctx, "");
+ if (!temp) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+ }
+ map->comment = talloc_strdup(map, temp);
+ if (!map->comment) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", false)) {
+ struct unixid id;
+ id.id = map->gid;
+ id.type = ID_TYPE_GID;
+
+ idmap_cache_set_sid2unixid(&map->sid, &id);
+ }
+
+ TALLOC_FREE(ctx);
+ return true;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
+ const char *filter,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+
+ if (ldapsam_search_one_group(ldap_state, filter, &result)
+ != LDAP_SUCCESS) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_getgroup: Did not find group, filter was "
+ "%s\n", filter));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: "
+ "count=%d\n", filter, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!init_group_from_ldap(ldap_state, map, entry)) {
+ DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for "
+ "group filter %s\n", filter));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
+ struct dom_sid sid)
+{
+ char *filter = NULL;
+ NTSTATUS status;
+ struct dom_sid_buf tmp;
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID),
+ dom_sid_str_buf(&sid, &tmp)) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
+ gid_t gid)
+{
+ char *filter = NULL;
+ NTSTATUS status;
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%lu))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
+ (unsigned long)gid) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
+ const char *name)
+{
+ char *filter = NULL;
+ char *escape_name = escape_ldap_string(talloc_tos(), name);
+ NTSTATUS status;
+
+ if (!escape_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
+ LDAP_OBJ_GROUPMAP,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), escape_name,
+ get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN),
+ escape_name) < 0) {
+ TALLOC_FREE(escape_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ TALLOC_FREE(escape_name);
+ status = ldapsam_getgroup(methods, filter, map);
+ SAFE_FREE(filter);
+ return status;
+}
+
+static bool ldapsam_extract_rid_from_entry(LDAP *ldap_struct,
+ LDAPMessage *entry,
+ const struct dom_sid *domain_sid,
+ uint32_t *rid)
+{
+ fstring str;
+ struct dom_sid sid;
+
+ if (!smbldap_get_single_attribute(ldap_struct, entry, "sambaSID",
+ str, sizeof(str)-1)) {
+ DEBUG(10, ("Could not find sambaSID attribute\n"));
+ return False;
+ }
+
+ if (!string_to_sid(&sid, str)) {
+ DEBUG(10, ("Could not convert string %s to sid\n", str));
+ return False;
+ }
+
+ if (dom_sid_compare_domain(&sid, domain_sid) != 0) {
+ struct dom_sid_buf buf;
+ DEBUG(10, ("SID %s is not in expected domain %s\n",
+ str,
+ dom_sid_str_buf(domain_sid, &buf)));
+ return False;
+ }
+
+ if (!sid_peek_rid(&sid, rid)) {
+ DEBUG(10, ("Could not peek into RID\n"));
+ return False;
+ }
+
+ return True;
+}
+
+static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *group,
+ uint32_t **pp_member_rids,
+ size_t *p_num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct smbldap_state *conn = ldap_state->smbldap_state;
+ const char *id_attrs[] = { "memberUid", "gidNumber", NULL };
+ const char *sid_attrs[] = { "sambaSID", NULL };
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+ char *filter;
+ char **values = NULL;
+ char **memberuid;
+ char *gidstr;
+ int rc, count;
+ struct dom_sid_buf buf;
+
+ *pp_member_rids = NULL;
+ *p_num_members = 0;
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass="LDAP_OBJ_POSIXGROUP")"
+ "(objectClass="LDAP_OBJ_GROUPMAP")"
+ "(sambaSID=%s))",
+ dom_sid_str_buf(group, &buf));
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, id_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ count = ldap_count_entries(smbldap_get_ldap(conn), result);
+
+ if (count > 1) {
+ DEBUG(1, ("Found more than one groupmap entry for %s\n",
+ dom_sid_str_buf(group, &buf)));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (count == 0) {
+ ret = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ entry = ldap_first_entry(smbldap_get_ldap(conn), result);
+ if (entry == NULL)
+ goto done;
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_enum_group_members: Unable to find the group's gid!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ values = ldap_get_values(smbldap_get_ldap(conn), entry, "memberUid");
+
+ if ((values != NULL) && (values[0] != NULL)) {
+
+ filter = talloc_strdup(mem_ctx, "(&(objectClass="LDAP_OBJ_SAMBASAMACCOUNT")(|");
+
+ for (memberuid = values; *memberuid != NULL; memberuid += 1) {
+ char *escape_memberuid;
+
+ escape_memberuid = escape_ldap_string(talloc_tos(),
+ *memberuid);
+ if (escape_memberuid == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ filter = talloc_asprintf_append_buffer(filter, "(uid=%s)", escape_memberuid);
+ TALLOC_FREE(escape_memberuid);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ filter = talloc_asprintf_append_buffer(filter, "))");
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ count = ldap_count_entries(smbldap_get_ldap(conn), result);
+ DEBUG(10,("ldapsam_enum_group_members: found %d accounts\n", count));
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ for (entry = ldap_first_entry(smbldap_get_ldap(conn), result);
+ entry != NULL;
+ entry = ldap_next_entry(smbldap_get_ldap(conn), entry))
+ {
+ char *sidstr;
+ struct dom_sid sid;
+ uint32_t rid;
+
+ sidstr = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(conn), entry, "sambaSID",
+ mem_ctx);
+ if (!sidstr) {
+ DEBUG(0, ("Severe DB error, %s can't miss the sambaSID"
+ "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (!string_to_sid(&sid, sidstr))
+ goto done;
+
+ if (!sid_check_is_in_our_sam(&sid)) {
+ DEBUG(0, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ sid_peek_rid(&sid, &rid);
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
+ p_num_members)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)"
+ "(gidNumber=%s))",
+ LDAP_OBJ_SAMBASAMACCOUNT,
+ gidstr);
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
+ &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ for (entry = ldap_first_entry(smbldap_get_ldap(conn), result);
+ entry != NULL;
+ entry = ldap_next_entry(smbldap_get_ldap(conn), entry))
+ {
+ uint32_t rid;
+
+ if (!ldapsam_extract_rid_from_entry(smbldap_get_ldap(conn),
+ entry,
+ get_global_sam_sid(),
+ &rid)) {
+ DEBUG(0, ("Severe DB error, %s can't miss the samba SID"
+ "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
+ p_num_members)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ ret = NT_STATUS_OK;
+
+ done:
+
+ if (values)
+ ldap_value_free(values);
+
+ return ret;
+}
+
+static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ struct dom_sid **pp_sids,
+ gid_t **pp_gids,
+ uint32_t *p_num_groups)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct smbldap_state *conn = ldap_state->smbldap_state;
+ char *filter;
+ const char *attrs[] = { "gidNumber", "sambaSID", NULL };
+ char *escape_name;
+ int rc, count;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ uint32_t num_sids;
+ uint32_t num_gids;
+ char *gidstr;
+ gid_t primary_gid = -1;
+ int error = 0;
+
+ *pp_sids = NULL;
+ num_sids = 0;
+
+ if (pdb_get_username(user) == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ escape_name = escape_ldap_string(talloc_tos(), pdb_get_username(user));
+ if (escape_name == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (user->unix_pw) {
+ primary_gid = user->unix_pw->pw_gid;
+ } else {
+ /* retrieve the users primary gid */
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass="LDAP_OBJ_SAMBASAMACCOUNT")(uid=%s))",
+ escape_name);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+
+ switch (count) {
+ case 0:
+ DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user)));
+ ret = NT_STATUS_NO_SUCH_USER;
+ goto done;
+ case 1:
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
+ if (!gidstr) {
+ DEBUG (1, ("Unable to find the member's gid!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+ primary_gid = smb_strtoul(gidstr,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_ERR("Failed to convert GID\n");
+ goto done;
+ }
+ break;
+ default:
+ DEBUG(1, ("found more than one account with the same user name ?!\n"));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass="LDAP_OBJ_POSIXGROUP")(|(memberUid=%s)(gidNumber=%u)))",
+ escape_name, (unsigned int)primary_gid);
+ if (filter == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(conn, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ num_gids = 0;
+ *pp_gids = NULL;
+
+ num_sids = 0;
+ *pp_sids = NULL;
+
+ /* We need to add the primary group as the first gid/sid */
+
+ if (!add_gid_to_array_unique(mem_ctx, primary_gid, pp_gids, &num_gids)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* This sid will be replaced later */
+
+ ret = add_sid_to_array_unique(mem_ctx, &global_sid_NULL, pp_sids,
+ &num_sids);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+
+ for (entry = ldap_first_entry(smbldap_get_ldap(conn), result);
+ entry != NULL;
+ entry = ldap_next_entry(smbldap_get_ldap(conn), entry))
+ {
+ fstring str;
+ struct dom_sid sid;
+ gid_t gid;
+
+ if (!smbldap_get_single_attribute(smbldap_get_ldap(conn),
+ entry, "sambaSID",
+ str, sizeof(str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, str))
+ goto done;
+
+ if (!smbldap_get_single_attribute(smbldap_get_ldap(conn),
+ entry, "gidNumber",
+ str, sizeof(str)-1))
+ continue;
+
+ gid = smb_strtoul(str, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
+
+ if (error != 0) {
+ goto done;
+ }
+
+ if (gid == primary_gid) {
+ sid_copy(&(*pp_sids)[0], &sid);
+ } else {
+ if (!add_gid_to_array_unique(mem_ctx, gid, pp_gids,
+ &num_gids)) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ ret = add_sid_to_array_unique(mem_ctx, &sid, pp_sids,
+ &num_sids);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
+ }
+ }
+
+ if (dom_sid_compare(&global_sid_NULL, &(*pp_sids)[0]) == 0) {
+ DEBUG(3, ("primary group of [%s] not found\n",
+ pdb_get_username(user)));
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ *p_num_groups = num_sids;
+
+ ret = NT_STATUS_OK;
+
+ done:
+
+ TALLOC_FREE(escape_name);
+ return ret;
+}
+
+/**********************************************************************
+ * Augment a posixGroup object with a sambaGroupMapping domgroup
+ *********************************************************************/
+
+static NTSTATUS ldapsam_map_posixgroup(TALLOC_CTX *mem_ctx,
+ struct ldapsam_privates *ldap_state,
+ GROUP_MAP *map)
+{
+ const char *filter, *dn;
+ LDAPMessage *msg, *entry;
+ LDAPMod **mods;
+ struct dom_sid_buf buf;
+ int rc;
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass="LDAP_OBJ_POSIXGROUP")(gidNumber=%u))",
+ (unsigned int)map->gid);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ msg) != 1) ||
+ ((entry = ldap_first_entry(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ msg)) == NULL)) {
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ dn = smbldap_talloc_dn(mem_ctx,
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (dn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ mods = NULL;
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass",
+ LDAP_OBJ_GROUPMAP);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "sambaSid",
+ dom_sid_str_buf(&map->sid, &buf));
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "sambaGroupType",
+ talloc_asprintf(mem_ctx, "%d", map->sid_name_use));
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "displayName",
+ map->nt_name);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "description",
+ map->comment);
+ smbldap_talloc_autofree_ldapmod(mem_ctx, mods);
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg = NULL;
+ LDAPMod **mods = NULL;
+ const char *attrs[] = { NULL };
+ char *filter;
+
+ char *dn;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS result;
+
+ struct dom_sid sid;
+ struct dom_sid_buf buf;
+ struct unixid id;
+
+ int rc;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(sambaSid=%s)",
+ dom_sid_str_buf(&map->sid, &buf));
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, True, &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc == LDAP_SUCCESS) &&
+ (ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ msg) > 0)) {
+
+ DEBUG(3, ("SID %s already present in LDAP, refusing to add "
+ "group mapping entry\n",
+ dom_sid_str_buf(&map->sid, &buf)));
+ result = NT_STATUS_GROUP_EXISTS;
+ goto done;
+ }
+
+ switch (map->sid_name_use) {
+
+ case SID_NAME_DOM_GRP:
+ /* To map a domain group we need to have a posix group
+ to attach to. */
+ result = ldapsam_map_posixgroup(mem_ctx, ldap_state, map);
+ goto done;
+ break;
+
+ case SID_NAME_ALIAS:
+ if (!sid_check_is_in_our_sam(&map->sid)
+ && !sid_check_is_in_builtin(&map->sid) )
+ {
+ DEBUG(3, ("Refusing to map sid %s as an alias, not in our domain\n",
+ dom_sid_str_buf(&map->sid, &buf)));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ break;
+
+ default:
+ DEBUG(3, ("Got invalid use '%s' for mapping\n",
+ sid_type_lookup(map->sid_name_use)));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* Domain groups have been mapped in a separate routine, we have to
+ * create an alias now */
+
+ if (map->gid == -1) {
+ DEBUG(10, ("Refusing to map gid==-1\n"));
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ id.id = map->gid;
+ id.type = ID_TYPE_GID;
+
+ if (pdb_id_to_sid(&id, &sid)) {
+ DEBUG(3, ("Gid %u is already mapped to SID %s, refusing to "
+ "add\n",
+ (unsigned int)map->gid,
+ dom_sid_str_buf(&sid, &buf)));
+ result = NT_STATUS_GROUP_EXISTS;
+ goto done;
+ }
+
+ /* Ok, enough checks done. It's still racy to go ahead now, but that's
+ * the best we can get out of LDAP. */
+
+ dn = talloc_asprintf(mem_ctx, "sambaSid=%s,%s",
+ dom_sid_str_buf(&map->sid, &buf),
+ lp_ldap_group_suffix(talloc_tos()));
+ if (dn == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ mods = NULL;
+
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "objectClass", LDAP_OBJ_SID_ENTRY);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "sambaSid",
+ dom_sid_str_buf(&map->sid, &buf));
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "sambaGroupType",
+ talloc_asprintf(mem_ctx, "%d", map->sid_name_use));
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "displayName",
+ map->nt_name);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "description",
+ map->comment);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), NULL,
+ &mods, "gidNumber",
+ talloc_asprintf(mem_ctx, "%u",
+ (unsigned int)map->gid));
+ smbldap_talloc_autofree_ldapmod(mem_ctx, mods);
+
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+
+ result = (rc == LDAP_SUCCESS) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ * Update a group mapping entry. We're quite strict about what can be changed:
+ * Only the description and displayname may be changed. It simply does not
+ * make any sense to change the SID, gid or the type in a mapping.
+ *********************************************************************/
+
+static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
+ GROUP_MAP *map)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ int rc;
+ const char *filter, *dn;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS result;
+ struct dom_sid_buf buf;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Make 100% sure that sid, gid and type are not changed by looking up
+ * exactly the values we're given in LDAP. */
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass="LDAP_OBJ_GROUPMAP")"
+ "(sambaSid=%s)(gidNumber=%u)"
+ "(sambaGroupType=%d))",
+ dom_sid_str_buf(&map->sid, &buf),
+ (unsigned int)map->gid, map->sid_name_use);
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ msg) != 1) ||
+ ((entry = ldap_first_entry(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ msg)) == NULL)) {
+ result = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ dn = smbldap_talloc_dn(
+ mem_ctx, smbldap_get_ldap(ldap_state->smbldap_state), entry);
+
+ if (dn == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ mods = NULL;
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "displayName", map->nt_name);
+ smbldap_make_mod(smbldap_get_ldap(ldap_state->smbldap_state), entry,
+ &mods, "description", map->comment);
+ smbldap_talloc_autofree_ldapmod(mem_ctx, mods);
+
+ if (mods == NULL) {
+ DEBUG(4, ("ldapsam_update_group_mapping_entry: mods is empty: "
+ "nothing to do\n"));
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ if (rc != LDAP_SUCCESS) {
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ DEBUG(2, ("ldapsam_update_group_mapping_entry: successfully modified "
+ "group %lu in LDAP\n", (unsigned long)map->gid));
+
+ result = NT_STATUS_OK;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
+ struct dom_sid sid)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg, *entry;
+ int rc;
+ NTSTATUS result;
+ TALLOC_CTX *mem_ctx;
+ char *filter;
+ struct dom_sid_buf buf;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass="LDAP_OBJ_GROUPMAP")("LDAP_ATTRIBUTE_SID"=%s))",
+ dom_sid_str_buf(&sid, &buf));
+ if (filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ rc = smbldap_search_suffix(priv->smbldap_state, filter,
+ get_attr_list(mem_ctx, groupmap_attr_list),
+ &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+
+ if ((rc != LDAP_SUCCESS) ||
+ (ldap_count_entries(priv2ld(priv), msg) != 1) ||
+ ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) {
+ result = NT_STATUS_NO_SUCH_GROUP;
+ goto done;
+ }
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry, LDAP_OBJ_GROUPMAP,
+ get_attr_list(mem_ctx,
+ groupmap_attr_list_to_delete));
+
+ if ((rc == LDAP_NAMING_VIOLATION) ||
+ (rc == LDAP_NOT_ALLOWED_ON_RDN) ||
+ (rc == LDAP_OBJECT_CLASS_VIOLATION)) {
+ const char *attrs[] = { "sambaGroupType", "description",
+ "displayName", "sambaSIDList",
+ NULL };
+
+ /* Second try. Don't delete the sambaSID attribute, this is
+ for "old" entries that are tacked on a winbind
+ sambaIdmapEntry. */
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry,
+ LDAP_OBJ_GROUPMAP, attrs);
+ }
+
+ if ((rc == LDAP_NAMING_VIOLATION) ||
+ (rc == LDAP_NOT_ALLOWED_ON_RDN) ||
+ (rc == LDAP_OBJECT_CLASS_VIOLATION)) {
+ const char *attrs[] = { "sambaGroupType", "description",
+ "displayName", "sambaSIDList",
+ "gidNumber", NULL };
+
+ /* Third try. This is a post-3.0.21 alias (containing only
+ * sambaSidEntry and sambaGroupMapping classes), we also have
+ * to delete the gidNumber attribute, only the sambaSidEntry
+ * remains */
+
+ rc = ldapsam_delete_entry(priv, mem_ctx, entry,
+ LDAP_OBJ_GROUPMAP, attrs);
+ }
+
+ result = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+ }
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods,
+ bool update)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)my_methods->private_data;
+ const char *filter = NULL;
+ int rc;
+ const char **attr_list;
+
+ filter = "(objectclass="LDAP_OBJ_GROUPMAP")";
+ attr_list = get_attr_list( NULL, groupmap_attr_list );
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &ldap_state->result);
+ TALLOC_FREE(attr_list);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0, ("ldapsam_setsamgrent: LDAP search failed: %s\n",
+ ldap_err2string(rc)));
+ DEBUG(3, ("ldapsam_setsamgrent: Query was: %s, %s\n",
+ lp_ldap_suffix(), filter));
+ ldap_msgfree(ldap_state->result);
+ ldap_state->result = NULL;
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2, ("ldapsam_setsamgrent: %d entries in the base!\n",
+ ldap_count_entries(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ ldap_state->result)));
+
+ ldap_state->entry =
+ ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ ldap_state->result);
+ ldap_state->index = 0;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
+{
+ ldapsam_endsampwent(my_methods);
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
+ GROUP_MAP *map)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)my_methods->private_data;
+ bool bret = False;
+
+ while (!bret) {
+ if (!ldap_state->entry)
+ return ret;
+
+ ldap_state->index++;
+ bret = init_group_from_ldap(ldap_state, map,
+ ldap_state->entry);
+
+ ldap_state->entry = ldap_next_entry(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ ldap_state->entry);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
+ const struct dom_sid *domsid, enum lsa_SidType sid_name_use,
+ GROUP_MAP ***pp_rmap,
+ size_t *p_num_entries,
+ bool unix_only)
+{
+ GROUP_MAP *map = NULL;
+ size_t entries = 0;
+
+ *p_num_entries = 0;
+ *pp_rmap = NULL;
+
+ if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
+ DEBUG(0, ("ldapsam_enum_group_mapping: Unable to open "
+ "passdb\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ while (true) {
+
+ map = talloc_zero(NULL, GROUP_MAP);
+ if (!map) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!NT_STATUS_IS_OK(ldapsam_getsamgrent(methods, map))) {
+ TALLOC_FREE(map);
+ break;
+ }
+
+ if (sid_name_use != SID_NAME_UNKNOWN &&
+ sid_name_use != map->sid_name_use) {
+ DEBUG(11,("ldapsam_enum_group_mapping: group %s is "
+ "not of the requested type\n",
+ map->nt_name));
+ continue;
+ }
+ if (unix_only == ENUM_ONLY_MAPPED && map->gid == -1) {
+ DEBUG(11,("ldapsam_enum_group_mapping: group %s is "
+ "non mapped\n", map->nt_name));
+ continue;
+ }
+
+ *pp_rmap = talloc_realloc(NULL, *pp_rmap,
+ GROUP_MAP *, entries + 1);
+ if (!(*pp_rmap)) {
+ DEBUG(0,("ldapsam_enum_group_mapping: Unable to "
+ "enlarge group map!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ (*pp_rmap)[entries] = talloc_move((*pp_rmap), &map);
+
+ entries += 1;
+ }
+
+ ldapsam_endsamgrent(methods);
+
+ *p_num_entries = entries;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods,
+ const struct dom_sid *alias,
+ const struct dom_sid *member,
+ int modop)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ char *dn = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ LDAPMod **mods = NULL;
+ int rc;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+ struct dom_sid_buf tmp;
+
+ char *filter = NULL;
+
+ if (sid_check_is_in_builtin(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_in_our_sam(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ struct dom_sid_buf buf;
+ DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n",
+ dom_sid_str_buf(alias, &buf)));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (asprintf(&filter,
+ "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))",
+ LDAP_OBJ_GROUPMAP,
+ dom_sid_str_buf(alias, &tmp),
+ type) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS) {
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ count = ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_modify_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_modify_aliasmem: Duplicate entries for "
+ "filter %s: count=%d\n", filter, count));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ SAFE_FREE(filter);
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_talloc_dn(talloc_tos(),
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ smbldap_set_mod(&mods, modop,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST),
+ dom_sid_str_buf(member, &tmp));
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ ldap_mods_free(mods, True);
+ ldap_msgfree(result);
+ TALLOC_FREE(dn);
+
+ if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
+ return NT_STATUS_MEMBER_IN_ALIAS;
+ }
+
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
+ return NT_STATUS_MEMBER_NOT_IN_ALIAS;
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_aliasmem(struct pdb_methods *methods,
+ const struct dom_sid *alias,
+ const struct dom_sid *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member, LDAP_MOD_ADD);
+}
+
+static NTSTATUS ldapsam_del_aliasmem(struct pdb_methods *methods,
+ const struct dom_sid *alias,
+ const struct dom_sid *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member,
+ LDAP_MOD_DELETE);
+}
+
+static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods,
+ const struct dom_sid *alias,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid **pp_members,
+ size_t *p_num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ char **values = NULL;
+ int i;
+ char *filter = NULL;
+ uint32_t num_members = 0;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+ struct dom_sid_buf tmp;
+
+ *pp_members = NULL;
+ *p_num_members = 0;
+
+ if (sid_check_is_in_builtin(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_in_our_sam(alias)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ DEBUG(5, ("SID %s is neither in builtin nor in our domain!\n",
+ dom_sid_str_buf(alias, &tmp)));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (asprintf(&filter,
+ "(&(objectClass=%s)(sambaSid=%s)(sambaGroupType=%d))",
+ LDAP_OBJ_GROUPMAP,
+ dom_sid_str_buf(alias, &tmp),
+ type) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS) {
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ count = ldap_count_entries(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_enum_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_enum_aliasmem: Duplicate entries for "
+ "filter %s: count=%d\n", filter, count));
+ ldap_msgfree(result);
+ SAFE_FREE(filter);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ SAFE_FREE(filter);
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ values = ldap_get_values(smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST));
+
+ if (values == NULL) {
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+ }
+
+ count = ldap_count_values(values);
+
+ for (i=0; i<count; i++) {
+ struct dom_sid member;
+ NTSTATUS status;
+
+ if (!string_to_sid(&member, values[i]))
+ continue;
+
+ status = add_sid_to_array(mem_ctx, &member, pp_members,
+ &num_members);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldap_value_free(values);
+ ldap_msgfree(result);
+ return status;
+ }
+ }
+
+ *p_num_members = num_members;
+ ldap_value_free(values);
+ ldap_msgfree(result);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ const struct dom_sid *members,
+ size_t num_members,
+ uint32_t **pp_alias_rids,
+ size_t *p_num_alias_rids)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAP *ldap_struct;
+
+ const char *attrs[] = { LDAP_ATTRIBUTE_SID, NULL };
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int i;
+ int rc;
+ char *filter;
+ enum lsa_SidType type = SID_NAME_USE_NONE;
+ bool is_builtin = false;
+ bool sid_added = false;
+
+ *pp_alias_rids = NULL;
+ *p_num_alias_rids = 0;
+
+ if (sid_check_is_builtin(domain_sid)) {
+ is_builtin = true;
+ type = SID_NAME_ALIAS;
+ }
+
+ if (sid_check_is_our_sam(domain_sid)) {
+ type = SID_NAME_ALIAS;
+ }
+
+ if (type == SID_NAME_USE_NONE) {
+ struct dom_sid_buf buf;
+ DEBUG(5, ("SID %s is neither builtin nor domain!\n",
+ dom_sid_str_buf(domain_sid, &buf)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (num_members == 0) {
+ return NT_STATUS_OK;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectclass="LDAP_OBJ_GROUPMAP")(sambaGroupType=%d)(|",
+ type);
+
+ for (i=0; i<num_members; i++) {
+ struct dom_sid_buf buf;
+ filter = talloc_asprintf(mem_ctx, "%s(sambaSIDList=%s)",
+ filter,
+ dom_sid_str_buf(&members[i], &buf));
+ }
+
+ filter = talloc_asprintf(mem_ctx, "%s))", filter);
+
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (is_builtin &&
+ ldap_state->search_cache.filter &&
+ strcmp(ldap_state->search_cache.filter, filter) == 0) {
+ filter = talloc_move(filter, &ldap_state->search_cache.filter);
+ result = ldap_state->search_cache.result;
+ ldap_state->search_cache.result = NULL;
+ } else {
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(filter, result);
+ }
+
+ ldap_struct = smbldap_get_ldap(ldap_state->smbldap_state);
+
+ for (entry = ldap_first_entry(ldap_struct, result);
+ entry != NULL;
+ entry = ldap_next_entry(ldap_struct, entry))
+ {
+ fstring sid_str;
+ struct dom_sid sid;
+ uint32_t rid;
+
+ if (!smbldap_get_single_attribute(ldap_struct, entry,
+ LDAP_ATTRIBUTE_SID,
+ sid_str,
+ sizeof(sid_str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, sid_str))
+ continue;
+
+ if (!sid_peek_check_rid(domain_sid, &sid, &rid))
+ continue;
+
+ sid_added = true;
+
+ if (!add_rid_to_array_unique(mem_ctx, rid, pp_alias_rids,
+ p_num_alias_rids)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (!is_builtin && !sid_added) {
+ TALLOC_FREE(ldap_state->search_cache.filter);
+ /*
+ * Note: result is a talloc child of filter because of the
+ * smbldap_talloc_autofree_ldapmsg() usage
+ */
+ ldap_state->search_cache.filter = talloc_move(ldap_state, &filter);
+ ldap_state->search_cache.result = result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
+ enum pdb_policy_type type,
+ uint32_t 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;
+
+ DEBUG(10,("ldapsam_set_account_policy_in_ldap\n"));
+
+ if (!ldap_state->domain_dn) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ policy_attr = get_account_policy_attr(type);
+ if (policy_attr == NULL) {
+ DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid "
+ "policy\n"));
+ return ntstatus;
+ }
+
+ 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) {
+ return ntstatus;
+ }
+
+ if (!cache_account_policy_set(type, value)) {
+ DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to "
+ "update local tdb cache\n"));
+ return ntstatus;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods,
+ enum pdb_policy_type type,
+ uint32_t value)
+{
+ return ldapsam_set_account_policy_in_ldap(methods, type,
+ value);
+}
+
+static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods,
+ enum pdb_policy_type type,
+ uint32_t *value)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ int rc;
+ char **vals = NULL;
+ const char *filter;
+ 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(type);
+ if (!policy_attr) {
+ DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid "
+ "policy index: %d\n", type));
+ return ntstatus;
+ }
+
+ attrs[0] = policy_attr;
+ attrs[1] = NULL;
+
+ filter = "(objectClass="LDAP_OBJ_DOMINFO")";
+ rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn,
+ LDAP_SCOPE_BASE, filter, attrs, 0,
+ &result);
+ if (rc != LDAP_SUCCESS) {
+ return ntstatus;
+ }
+
+ count = ldap_count_entries(priv2ld(ldap_state), result);
+ if (count < 1) {
+ goto out;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (entry == NULL) {
+ goto out;
+ }
+
+ vals = ldap_get_values(priv2ld(ldap_state), entry, policy_attr);
+ if (vals == NULL) {
+ goto out;
+ }
+
+ *value = (uint32_t)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 user hasn't decided to use account policies inside LDAP just reuse the
+ old tdb values
+
+ - 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,
+ enum pdb_policy_type type,
+ uint32_t *value)
+{
+ NTSTATUS ntstatus;
+
+ if (cache_account_policy_get(type, 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, type,
+ value);
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ goto update_cache;
+ }
+
+ DEBUG(10,("ldapsam_get_account_policy: failed to retrieve from "
+ "ldap\n"));
+
+#if 0
+ /* should we automagically migrate old tdb value here ? */
+ if (account_policy_get(type, value))
+ goto update_ldap;
+
+ DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying "
+ "default\n", type));
+#endif
+
+ if (!account_policy_get_default(type, value)) {
+ return ntstatus;
+ }
+
+/* update_ldap: */
+
+ ntstatus = ldapsam_set_account_policy(methods, type, *value);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return ntstatus;
+ }
+
+ update_cache:
+
+ if (!cache_account_policy_set(type, *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,
+ const struct dom_sid *domain_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **names,
+ enum lsa_SidType *attrs)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry;
+ char *allsids = NULL;
+ size_t i, num_mapped;
+ int rc;
+ NTSTATUS result = NT_STATUS_NO_MEMORY;
+ TALLOC_CTX *mem_ctx;
+ LDAP *ld;
+ bool is_builtin;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ goto done;
+ }
+
+ if (!sid_check_is_builtin(domain_sid) &&
+ !sid_check_is_our_sam(domain_sid)) {
+ result = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (num_rids == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ for (i=0; i<num_rids; i++)
+ attrs[i] = SID_NAME_UNKNOWN;
+
+ allsids = talloc_strdup(mem_ctx, "");
+ if (allsids == NULL) {
+ goto done;
+ }
+
+ for (i=0; i<num_rids; i++) {
+ struct dom_sid sid;
+ struct dom_sid_buf buf;
+ sid_compose(&sid, domain_sid, rids[i]);
+ allsids = talloc_asprintf_append_buffer(
+ allsids,
+ "(sambaSid=%s)",
+ dom_sid_str_buf(&sid, &buf));
+ if (allsids == NULL) {
+ goto done;
+ }
+ }
+
+ /* First look for users */
+
+ {
+ char *filter;
+ const char *ldap_attrs[] = { "uid", "sambaSid", NULL };
+
+ filter = talloc_asprintf(
+ mem_ctx, ("(&(objectClass="LDAP_OBJ_SAMBASAMACCOUNT")(|%s))"),
+ allsids);
+
+ if (filter == NULL) {
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_user_suffix(talloc_tos()),
+ LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0,
+ &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ ld = smbldap_get_ldap(ldap_state->smbldap_state);
+ num_mapped = 0;
+
+ for (entry = ldap_first_entry(ld, msg);
+ entry != NULL;
+ entry = ldap_next_entry(ld, entry)) {
+ uint32_t rid;
+ int rid_index;
+ const char *name;
+
+ if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid,
+ &rid)) {
+ DEBUG(2, ("Could not find sid from ldap entry\n"));
+ continue;
+ }
+
+ name = smbldap_talloc_single_attribute(ld, entry, "uid",
+ names);
+ if (name == NULL) {
+ DEBUG(2, ("Could not retrieve uid attribute\n"));
+ continue;
+ }
+
+ for (rid_index = 0; rid_index < num_rids; rid_index++) {
+ if (rid == rids[rid_index])
+ break;
+ }
+
+ if (rid_index == num_rids) {
+ DEBUG(2, ("Got a RID not asked for: %d\n", rid));
+ continue;
+ }
+
+ attrs[rid_index] = SID_NAME_USER;
+ names[rid_index] = name;
+ num_mapped += 1;
+ }
+
+ if (num_mapped == num_rids) {
+ /* No need to look for groups anymore -- we're done */
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ /* Same game for groups */
+
+ {
+ char *filter;
+ const char *ldap_attrs[] = { "cn", "displayName", "sambaSid",
+ "sambaGroupType", NULL };
+
+ filter = talloc_asprintf(
+ mem_ctx, "(&(objectClass="LDAP_OBJ_GROUPMAP")(|%s))",
+ allsids);
+ if (filter == NULL) {
+ goto done;
+ }
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, ldap_attrs, 0,
+ &msg);
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ /* ldap_struct might have changed due to a reconnect */
+
+ ld = smbldap_get_ldap(ldap_state->smbldap_state);
+
+ /* For consistency checks, we already checked we're only domain or builtin */
+
+ is_builtin = sid_check_is_builtin(domain_sid);
+
+ for (entry = ldap_first_entry(ld, msg);
+ entry != NULL;
+ entry = ldap_next_entry(ld, entry))
+ {
+ uint32_t rid;
+ int rid_index;
+ const char *attr;
+ enum lsa_SidType type;
+ const char *dn = smbldap_talloc_dn(mem_ctx, ld, entry);
+
+ attr = smbldap_talloc_single_attribute(ld, entry, "sambaGroupType",
+ mem_ctx);
+ if (attr == NULL) {
+ DEBUG(2, ("Could not extract type from ldap entry %s\n",
+ dn));
+ continue;
+ }
+
+ type = (enum lsa_SidType)atol(attr);
+
+ /* Consistency checks */
+ if ((is_builtin && (type != SID_NAME_ALIAS)) ||
+ (!is_builtin && ((type != SID_NAME_ALIAS) &&
+ (type != SID_NAME_DOM_GRP)))) {
+ DEBUG(2, ("Rejecting invalid group mapping entry %s\n", dn));
+ }
+
+ if (!ldapsam_extract_rid_from_entry(ld, entry, domain_sid,
+ &rid)) {
+ DEBUG(2, ("Could not find sid from ldap entry %s\n", dn));
+ continue;
+ }
+
+ attr = smbldap_talloc_single_attribute(ld, entry, "displayName", names);
+
+ if (attr == NULL) {
+ DEBUG(10, ("Could not retrieve 'displayName' attribute from %s\n",
+ dn));
+ attr = smbldap_talloc_single_attribute(ld, entry, "cn", names);
+ }
+
+ if (attr == NULL) {
+ DEBUG(2, ("Could not retrieve naming attribute from %s\n",
+ dn));
+ continue;
+ }
+
+ for (rid_index = 0; rid_index < num_rids; rid_index++) {
+ if (rid == rids[rid_index])
+ break;
+ }
+
+ if (rid_index == num_rids) {
+ DEBUG(2, ("Got a RID not asked for: %d\n", rid));
+ continue;
+ }
+
+ attrs[rid_index] = type;
+ names[rid_index] = attr;
+ num_mapped += 1;
+ }
+
+ result = NT_STATUS_NONE_MAPPED;
+
+ if (num_mapped > 0)
+ result = (num_mapped == num_rids) ?
+ NT_STATUS_OK : STATUS_SOME_UNMAPPED;
+ done:
+ TALLOC_FREE(mem_ctx);
+ return result;
+}
+
+static char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username)
+{
+ char *filter = NULL;
+ char *escaped = NULL;
+ char *result = NULL;
+
+ if (asprintf(&filter, "(&%s(objectclass=%s))",
+ "(uid=%u)", LDAP_OBJ_SAMBASAMACCOUNT) < 0) {
+ goto done;
+ }
+
+ escaped = escape_ldap_string(talloc_tos(), username);
+ if (escaped == NULL) goto done;
+
+ result = talloc_string_sub(mem_ctx, filter, "%u", username);
+
+ done:
+ SAFE_FREE(filter);
+ TALLOC_FREE(escaped);
+
+ return result;
+}
+
+static const char **talloc_attrs(TALLOC_CTX *mem_ctx, ...)
+{
+ int i, num = 0;
+ va_list ap;
+ const char **result;
+
+ va_start(ap, mem_ctx);
+ while (va_arg(ap, const char *) != NULL)
+ num += 1;
+ va_end(ap);
+
+ if ((result = talloc_array(mem_ctx, const char *, num+1)) == NULL) {
+ return NULL;
+ }
+
+ va_start(ap, mem_ctx);
+ for (i=0; i<num; i++) {
+ result[i] = talloc_strdup(result, va_arg(ap, const char*));
+ if (result[i] == NULL) {
+ talloc_free(result);
+ va_end(ap);
+ return NULL;
+ }
+ }
+ va_end(ap);
+
+ result[num] = NULL;
+ return result;
+}
+
+struct ldap_search_state {
+ struct smbldap_state *connection;
+
+ uint32_t acct_flags;
+ uint16_t group_type;
+
+ const char *base;
+ int scope;
+ const char *filter;
+ const char **attrs;
+ int attrsonly;
+ void *pagedresults_cookie;
+
+ LDAPMessage *entries, *current_entry;
+ bool (*ldap2displayentry)(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result);
+};
+
+static bool ldapsam_search_firstpage(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ LDAP *ld;
+ int rc = LDAP_OPERATIONS_ERROR;
+
+ state->entries = NULL;
+
+ if (smbldap_get_paged_results(state->connection)) {
+ rc = smbldap_search_paged(state->connection, state->base,
+ state->scope, state->filter,
+ state->attrs, state->attrsonly,
+ lp_ldap_page_size(), &state->entries,
+ &state->pagedresults_cookie);
+ }
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) {
+
+ if (state->entries != NULL) {
+ /* Left over from unsuccessful paged attempt */
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ rc = smbldap_search(state->connection, state->base,
+ state->scope, state->filter, state->attrs,
+ state->attrsonly, &state->entries);
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL))
+ return False;
+
+ /* Ok, the server was lying. It told us it could do paged
+ * searches when it could not. */
+ smbldap_set_paged_results(state->connection, false);
+ }
+
+ ld = smbldap_get_ldap(state->connection);
+ if ( ld == NULL) {
+ DEBUG(5, ("Don't have an LDAP connection right after a "
+ "search\n"));
+ return False;
+ }
+ state->current_entry = ldap_first_entry(ld, state->entries);
+
+ return True;
+}
+
+static bool ldapsam_search_nextpage(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ int rc;
+
+ if (!smbldap_get_paged_results(state->connection)) {
+ /* There is no next page when there are no paged results */
+ return False;
+ }
+
+ rc = smbldap_search_paged(state->connection, state->base,
+ state->scope, state->filter, state->attrs,
+ state->attrsonly, lp_ldap_page_size(),
+ &state->entries,
+ &state->pagedresults_cookie);
+
+ if ((rc != LDAP_SUCCESS) || (state->entries == NULL))
+ return False;
+
+ state->current_entry = ldap_first_entry(
+ smbldap_get_ldap(state->connection), state->entries);
+
+ if (state->current_entry == NULL) {
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ return false;
+ }
+
+ return True;
+}
+
+static bool ldapsam_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ bool result;
+
+ retry:
+ if ((state->entries == NULL) && (state->pagedresults_cookie == NULL))
+ return False;
+
+ if ((state->entries == NULL) &&
+ !ldapsam_search_nextpage(search))
+ return False;
+
+ if (state->current_entry == NULL) {
+ return false;
+ }
+
+ result = state->ldap2displayentry(state, search,
+ smbldap_get_ldap(state->connection),
+ state->current_entry, entry);
+
+ if (!result) {
+ char *dn;
+ dn = ldap_get_dn(smbldap_get_ldap(state->connection),
+ state->current_entry);
+ DEBUG(5, ("Skipping entry %s\n", dn != NULL ? dn : "<NULL>"));
+ if (dn != NULL) ldap_memfree(dn);
+ }
+
+ state->current_entry = ldap_next_entry(
+ smbldap_get_ldap(state->connection), state->current_entry);
+
+ if (state->current_entry == NULL) {
+ ldap_msgfree(state->entries);
+ state->entries = NULL;
+ }
+
+ if (!result) goto retry;
+
+ return True;
+}
+
+static void ldapsam_search_end(struct pdb_search *search)
+{
+ struct ldap_search_state *state =
+ (struct ldap_search_state *)search->private_data;
+ int rc;
+
+ if (state->pagedresults_cookie == NULL)
+ return;
+
+ if (state->entries != NULL)
+ ldap_msgfree(state->entries);
+
+ state->entries = NULL;
+ state->current_entry = NULL;
+
+ if (!smbldap_get_paged_results(state->connection)) {
+ return;
+ }
+
+ /* Tell the LDAP server we're not interested in the rest anymore. */
+
+ rc = smbldap_search_paged(state->connection, state->base, state->scope,
+ state->filter, state->attrs,
+ state->attrsonly, 0, &state->entries,
+ &state->pagedresults_cookie);
+
+ if (rc != LDAP_SUCCESS)
+ DEBUG(5, ("Could not end search properly\n"));
+
+ return;
+}
+
+static bool ldapuser2displayentry(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result)
+{
+ char **vals;
+ size_t converted_size;
+ struct dom_sid sid;
+ uint32_t acct_flags;
+
+ vals = ldap_get_values(ld, entry, "sambaAcctFlags");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ acct_flags = ACB_NORMAL;
+ } else {
+ acct_flags = pdb_decode_acct_ctrl(vals[0]);
+ ldap_value_free(vals);
+ }
+
+ if ((state->acct_flags != 0) &&
+ ((state->acct_flags & acct_flags) == 0))
+ return False;
+
+ result->acct_flags = acct_flags;
+ result->account_name = "";
+ result->fullname = "";
+ result->description = "";
+
+ vals = ldap_get_values(ld, entry, "uid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"uid\" not found\n"));
+ return False;
+ }
+ if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *, &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s\n",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "displayName");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"displayName\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *, &result->fullname),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s\n",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "description");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"description\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *, &result->description),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapuser2displayentry: pull_utf8_talloc failed: %s\n",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ if ((result->account_name == NULL) ||
+ (result->fullname == NULL) ||
+ (result->description == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ vals = ldap_get_values(ld, entry, "sambaSid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(0, ("\"objectSid\" not found\n"));
+ return False;
+ }
+
+ if (!string_to_sid(&sid, vals[0])) {
+ DEBUG(0, ("Could not convert %s to SID\n", vals[0]));
+ ldap_value_free(vals);
+ return False;
+ }
+ ldap_value_free(vals);
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) {
+ struct dom_sid_buf buf;
+ DEBUG(0, ("sid %s does not belong to our domain\n",
+ dom_sid_str_buf(&sid, &buf)));
+ return False;
+ }
+
+ return True;
+}
+
+
+static bool ldapsam_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32_t acct_flags)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct ldap_search_state *state;
+
+ state = talloc(search, struct ldap_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ state->connection = ldap_state->smbldap_state;
+
+ if ((acct_flags != 0) && ((acct_flags & ACB_NORMAL) != 0))
+ state->base = lp_ldap_user_suffix(talloc_tos());
+ else if ((acct_flags != 0) &&
+ ((acct_flags & (ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) != 0))
+ state->base = lp_ldap_machine_suffix(talloc_tos());
+ else
+ state->base = lp_ldap_suffix();
+
+ state->acct_flags = acct_flags;
+ state->base = talloc_strdup(search, state->base);
+ state->scope = LDAP_SCOPE_SUBTREE;
+ state->filter = get_ldap_filter(search, "*");
+ state->attrs = talloc_attrs(search, "uid", "sambaSid",
+ "displayName", "description",
+ "sambaAcctFlags", NULL);
+ state->attrsonly = 0;
+ state->pagedresults_cookie = NULL;
+ state->entries = NULL;
+ state->ldap2displayentry = ldapuser2displayentry;
+
+ if ((state->filter == NULL) || (state->attrs == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ search->private_data = state;
+ search->next_entry = ldapsam_search_next_entry;
+ search->search_end = ldapsam_search_end;
+
+ return ldapsam_search_firstpage(search);
+}
+
+static bool ldapgroup2displayentry(struct ldap_search_state *state,
+ TALLOC_CTX *mem_ctx,
+ LDAP *ld, LDAPMessage *entry,
+ struct samr_displayentry *result)
+{
+ char **vals;
+ size_t converted_size;
+ struct dom_sid sid;
+ uint16_t group_type;
+
+ result->account_name = "";
+ result->fullname = "";
+ result->description = "";
+
+
+ vals = ldap_get_values(ld, entry, "sambaGroupType");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"sambaGroupType\" not found\n"));
+ if (vals != NULL) {
+ ldap_value_free(vals);
+ }
+ return False;
+ }
+
+ group_type = atoi(vals[0]);
+
+ if ((state->group_type != 0) &&
+ ((state->group_type != group_type))) {
+ ldap_value_free(vals);
+ return False;
+ }
+
+ ldap_value_free(vals);
+
+ /* display name is the NT group name */
+
+ vals = ldap_get_values(ld, entry, "displayName");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(8, ("\"displayName\" not found\n"));
+
+ /* fallback to the 'cn' attribute */
+ vals = ldap_get_values(ld, entry, "cn");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(5, ("\"cn\" not found\n"));
+ return False;
+ }
+ if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *,
+ &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc "
+ "failed: %s\n", strerror(errno)));
+ }
+ }
+ else if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *,
+ &result->account_name),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc failed: %s\n",
+ strerror(errno)));
+ }
+
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(ld, entry, "description");
+ if ((vals == NULL) || (vals[0] == NULL))
+ DEBUG(8, ("\"description\" not found\n"));
+ else if (!pull_utf8_talloc(mem_ctx,
+ discard_const_p(char *, &result->description),
+ vals[0], &converted_size))
+ {
+ DEBUG(0,("ldapgroup2displayentry: pull_utf8_talloc failed: %s\n",
+ strerror(errno)));
+ }
+ ldap_value_free(vals);
+
+ if ((result->account_name == NULL) ||
+ (result->fullname == NULL) ||
+ (result->description == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ vals = ldap_get_values(ld, entry, "sambaSid");
+ if ((vals == NULL) || (vals[0] == NULL)) {
+ DEBUG(0, ("\"objectSid\" not found\n"));
+ if (vals != NULL) {
+ ldap_value_free(vals);
+ }
+ return False;
+ }
+
+ if (!string_to_sid(&sid, vals[0])) {
+ DEBUG(0, ("Could not convert %s to SID\n", vals[0]));
+ return False;
+ }
+
+ ldap_value_free(vals);
+
+ switch (group_type) {
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)
+ && !sid_peek_check_rid(&global_sid_Builtin, &sid, &result->rid))
+ {
+ struct dom_sid_buf buf;
+ DEBUG(0, ("%s is not in our domain\n",
+ dom_sid_str_buf(&sid, &buf)));
+ return False;
+ }
+ break;
+
+ default:
+ DEBUG(0,("unknown group type: %d\n", group_type));
+ return False;
+ }
+
+ result->acct_flags = 0;
+
+ return True;
+}
+
+static bool ldapsam_search_grouptype(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const struct dom_sid *sid,
+ enum lsa_SidType type)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct ldap_search_state *state;
+ struct dom_sid_buf tmp;
+
+ state = talloc(search, struct ldap_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ state->connection = ldap_state->smbldap_state;
+
+ state->base = lp_ldap_suffix();
+ state->connection = ldap_state->smbldap_state;
+ state->scope = LDAP_SCOPE_SUBTREE;
+ state->filter = talloc_asprintf(search, "(&(objectclass="LDAP_OBJ_GROUPMAP")"
+ "(sambaGroupType=%d)(sambaSID=%s*))",
+ type,
+ dom_sid_str_buf(sid, &tmp));
+ state->attrs = talloc_attrs(search, "cn", "sambaSid",
+ "displayName", "description",
+ "sambaGroupType", NULL);
+ state->attrsonly = 0;
+ state->pagedresults_cookie = NULL;
+ state->entries = NULL;
+ state->group_type = type;
+ state->ldap2displayentry = ldapgroup2displayentry;
+
+ if ((state->filter == NULL) || (state->attrs == NULL)) {
+ DEBUG(0, ("talloc failed\n"));
+ return False;
+ }
+
+ search->private_data = state;
+ search->next_entry = ldapsam_search_next_entry;
+ search->search_end = ldapsam_search_end;
+
+ return ldapsam_search_firstpage(search);
+}
+
+static bool ldapsam_search_groups(struct pdb_methods *methods,
+ struct pdb_search *search)
+{
+ return ldapsam_search_grouptype(methods, search, get_global_sam_sid(), SID_NAME_DOM_GRP);
+}
+
+static bool ldapsam_search_aliases(struct pdb_methods *methods,
+ struct pdb_search *search,
+ const struct dom_sid *sid)
+{
+ return ldapsam_search_grouptype(methods, search, sid, SID_NAME_ALIAS);
+}
+
+static uint32_t ldapsam_capabilities(struct pdb_methods *methods)
+{
+ return PDB_CAP_STORE_RIDS;
+}
+
+static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv,
+ uint32_t *rid)
+{
+ struct smbldap_state *smbldap_state = priv->smbldap_state;
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ NTSTATUS status;
+ char *value;
+ int rc;
+ uint32_t nextRid = 0;
+ const char *dn;
+ uint32_t tmp;
+ int error = 0;
+
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = smbldap_search_domain_info(smbldap_state, &result,
+ get_global_sam_name(), False);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not get domain info: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+ if (entry == NULL) {
+ DEBUG(0, ("Could not get domain info entry\n"));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ /* Find the largest of the three attributes "sambaNextRid",
+ "sambaNextGroupRid" and "sambaNextUserRid". I gave up on the
+ concept of differentiating between user and group rids, and will
+ use only "sambaNextRid" in the future. But for compatibility
+ reasons I look if others have chosen different strategies -- VL */
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextRid", mem_ctx);
+ if (value != NULL) {
+ tmp = (uint32_t)smb_strtoul(value,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextUserRid", mem_ctx);
+ if (value != NULL) {
+ tmp = (uint32_t)smb_strtoul(value,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaNextGroupRid", mem_ctx);
+ if (value != NULL) {
+ tmp = (uint32_t)smb_strtoul(value,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+
+ nextRid = MAX(nextRid, tmp);
+ }
+
+ if (nextRid == 0) {
+ nextRid = BASE_RID-1;
+ }
+
+ nextRid += 1;
+
+ smbldap_make_mod(priv2ld(priv), entry, &mods, "sambaNextRid",
+ talloc_asprintf(mem_ctx, "%d", nextRid));
+ smbldap_talloc_autofree_ldapmod(mem_ctx, mods);
+
+ if ((dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry)) == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rc = smbldap_modify(smbldap_state, dn, mods);
+
+ /* ACCESS_DENIED is used as a placeholder for "the modify failed,
+ * please retry" */
+
+ status = (rc == LDAP_SUCCESS) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ done:
+ if (NT_STATUS_IS_OK(status)) {
+ *rid = nextRid;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return status;
+}
+
+static NTSTATUS ldapsam_new_rid_internal(struct pdb_methods *methods, uint32_t *rid)
+{
+ int i;
+
+ for (i=0; i<10; i++) {
+ NTSTATUS result = ldapsam_get_new_rid(
+ (struct ldapsam_privates *)methods->private_data, rid);
+ if (NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (!NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+ return result;
+ }
+
+ /* The ldap update failed (maybe a race condition), retry */
+ }
+
+ /* Tried 10 times, fail. */
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+static bool ldapsam_new_rid(struct pdb_methods *methods, uint32_t *rid)
+{
+ NTSTATUS result = ldapsam_new_rid_internal(methods, rid);
+ return NT_STATUS_IS_OK(result) ? True : False;
+}
+
+static bool ldapsam_sid_to_id(struct pdb_methods *methods,
+ const struct dom_sid *sid,
+ struct unixid *id)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ char *filter;
+ int error = 0;
+ struct dom_sid_buf buf;
+ const char *attrs[] = { "sambaGroupType", "gidNumber", "uidNumber",
+ NULL };
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ bool ret = False;
+ char *value;
+ int rc;
+
+ TALLOC_CTX *mem_ctx;
+
+ ret = pdb_sid_to_id_unix_users_and_groups(sid, id);
+ if (ret == true) {
+ return true;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return False;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(sambaSid=%s)"
+ "(|(objectClass="LDAP_OBJ_GROUPMAP")(objectClass="LDAP_OBJ_SAMBASAMACCOUNT")))",
+ dom_sid_str_buf(sid, &buf));
+ if (filter == NULL) {
+ DEBUG(5, ("talloc_asprintf failed\n"));
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(priv->smbldap_state, filter,
+ attrs, &result);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ if (ldap_count_entries(priv2ld(priv), result) != 1) {
+ DEBUG(10, ("Got %d entries, expected one\n",
+ ldap_count_entries(priv2ld(priv), result)));
+ goto done;
+ }
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaGroupType", mem_ctx);
+
+ if (value != NULL) {
+ const char *gid_str;
+ /* It's a group */
+
+ gid_str = smbldap_talloc_single_attribute(
+ priv2ld(priv), entry, "gidNumber", mem_ctx);
+ if (gid_str == NULL) {
+ DEBUG(1, ("%s has sambaGroupType but no gidNumber\n",
+ smbldap_talloc_dn(mem_ctx, priv2ld(priv),
+ entry)));
+ goto done;
+ }
+
+ id->id = smb_strtoul(gid_str,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+
+ id->type = ID_TYPE_GID;
+ ret = True;
+ goto done;
+ }
+
+ /* It must be a user */
+
+ value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "uidNumber", mem_ctx);
+ if (value == NULL) {
+ DEBUG(1, ("Could not find uidNumber in %s\n",
+ smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry)));
+ goto done;
+ }
+
+ id->id = smb_strtoul(value, NULL, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ goto done;
+ }
+
+ id->type = ID_TYPE_UID;
+ ret = True;
+ done:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/**
+ * Find the SID for a uid.
+ * This is shortcut is only used if ldapsam:trusted is set to true.
+ */
+static bool ldapsam_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+ struct dom_sid *sid)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ char *filter;
+ const char *attrs[] = { "sambaSID", NULL };
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ bool ret = false;
+ char *user_sid_string;
+ struct dom_sid user_sid;
+ int rc;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(uidNumber=%u)"
+ "(objectClass="LDAP_OBJ_POSIXACCOUNT")"
+ "(objectClass="LDAP_OBJ_SAMBASAMACCOUNT"))",
+ (unsigned int)uid);
+ if (filter == NULL) {
+ DEBUG(3, ("talloc_asprintf failed\n"));
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(priv->smbldap_state, filter, attrs, &result);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ if (ldap_count_entries(priv2ld(priv), result) != 1) {
+ DEBUG(3, ("ERROR: Got %d entries for uid %u, expected one\n",
+ ldap_count_entries(priv2ld(priv), result),
+ (unsigned int)uid));
+ goto done;
+ }
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+
+ user_sid_string = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaSID", tmp_ctx);
+ if (user_sid_string == NULL) {
+ DEBUG(1, ("Could not find sambaSID in object '%s'\n",
+ smbldap_talloc_dn(tmp_ctx, priv2ld(priv), entry)));
+ goto done;
+ }
+
+ if (!string_to_sid(&user_sid, user_sid_string)) {
+ DEBUG(3, ("Error calling string_to_sid for sid '%s'\n",
+ user_sid_string));
+ goto done;
+ }
+
+ sid_copy(sid, &user_sid);
+
+ ret = true;
+
+ done:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+/**
+ * Find the SID for a gid.
+ * This is shortcut is only used if ldapsam:trusted is set to true.
+ */
+static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid,
+ struct dom_sid *sid)
+{
+ struct ldapsam_privates *priv =
+ (struct ldapsam_privates *)methods->private_data;
+ char *filter;
+ const char *attrs[] = { "sambaSID", NULL };
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ bool ret = false;
+ char *group_sid_string;
+ struct dom_sid group_sid;
+ int rc;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(gidNumber=%u)"
+ "(objectClass="LDAP_OBJ_GROUPMAP"))",
+ (unsigned int)gid);
+ if (filter == NULL) {
+ DEBUG(3, ("talloc_asprintf failed\n"));
+ goto done;
+ }
+
+ rc = smbldap_search_suffix(priv->smbldap_state, filter, attrs, &result);
+ if (rc != LDAP_SUCCESS) {
+ goto done;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ if (ldap_count_entries(priv2ld(priv), result) != 1) {
+ DEBUG(3, ("ERROR: Got %d entries for gid %u, expected one\n",
+ ldap_count_entries(priv2ld(priv), result),
+ (unsigned int)gid));
+ goto done;
+ }
+
+ entry = ldap_first_entry(priv2ld(priv), result);
+
+ group_sid_string = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+ "sambaSID", tmp_ctx);
+ if (group_sid_string == NULL) {
+ DEBUG(1, ("Could not find sambaSID in object '%s'\n",
+ smbldap_talloc_dn(tmp_ctx, priv2ld(priv), entry)));
+ goto done;
+ }
+
+ if (!string_to_sid(&group_sid, group_sid_string)) {
+ DEBUG(3, ("Error calling string_to_sid for sid '%s'\n",
+ group_sid_string));
+ goto done;
+ }
+
+ sid_copy(sid, &group_sid);
+
+ ret = true;
+
+ done:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+static bool ldapsam_id_to_sid(struct pdb_methods *methods, struct unixid *id,
+ struct dom_sid *sid)
+{
+ switch (id->type) {
+ case ID_TYPE_UID:
+ return ldapsam_uid_to_sid(methods, id->id, sid);
+
+ case ID_TYPE_GID:
+ return ldapsam_gid_to_sid(methods, id->id, sid);
+
+ default:
+ return false;
+ }
+}
+
+
+/*
+ * The following functions are called only if
+ * ldapsam:trusted and ldapsam:editposix are
+ * set to true
+ */
+
+/*
+ * ldapsam_create_user creates a new
+ * posixAccount and sambaSamAccount object
+ * in the ldap users subtree
+ *
+ * The uid is allocated by winbindd.
+ */
+
+static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx, const char *name,
+ uint32_t acb_info, uint32_t *rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32_t num_result;
+ bool is_machine = False;
+ bool add_posix = False;
+ bool init_okay = False;
+ LDAPMod **mods = NULL;
+ struct samu *user;
+ char *filter;
+ char *username;
+ char *homedir;
+ char *gidstr;
+ char *uidstr;
+ char *shell;
+ const char *dn = NULL;
+ struct dom_sid group_sid;
+ struct dom_sid user_sid;
+ gid_t gid = -1;
+ uid_t uid = -1;
+ NTSTATUS ret;
+ int rc;
+
+ if (((acb_info & ACB_NORMAL) && name[strlen(name)-1] == '$') ||
+ acb_info & ACB_WSTRUST ||
+ acb_info & ACB_SVRTRUST ||
+ acb_info & ACB_DOMTRUST) {
+ is_machine = True;
+ }
+
+ username = escape_ldap_string(talloc_tos(), name);
+ filter = talloc_asprintf(tmp_ctx, "(&(uid=%s)(objectClass="LDAP_OBJ_POSIXACCOUNT"))",
+ username);
+ TALLOC_FREE(username);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_user: ldap search failed!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_create_user: More than one user with name [%s] ?!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (num_result == 1) {
+ char *tmp;
+ /* check if it is just a posix account.
+ * or if there is a sid attached to this entry
+ */
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx);
+ if (tmp) {
+ DEBUG (1, ("ldapsam_create_user: The user [%s] already exist!\n", name));
+ return NT_STATUS_USER_EXISTS;
+ }
+
+ /* it is just a posix account, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_create_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (num_result == 0) {
+ add_posix = True;
+ }
+
+ /* Create the basic samu structure and generate the mods for the ldap commit */
+ if (!NT_STATUS_IS_OK((ret = ldapsam_new_rid_internal(my_methods, rid)))) {
+ DEBUG(1, ("ldapsam_create_user: Could not allocate a new RID\n"));
+ return ret;
+ }
+
+ sid_compose(&user_sid, get_global_sam_sid(), *rid);
+
+ user = samu_new(tmp_ctx);
+ if (!user) {
+ DEBUG(1,("ldapsam_create_user: Unable to allocate user struct\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_username(user, name, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (!pdb_set_domain(user, get_global_sam_name(), PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (is_machine) {
+ if (acb_info & ACB_NORMAL) {
+ if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(user, acb_info, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(user, ACB_NORMAL | ACB_DISABLED, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (!pdb_set_user_sid(user, &user_sid, PDB_SET)) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ init_okay = init_ldap_from_sam(ldap_state, entry, &mods, user, pdb_element_is_set_or_changed);
+
+ if (!init_okay) {
+ DEBUG(1,("ldapsam_create_user: Unable to fill user structs\n"));
+ ldap_mods_free(mods, true);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT) {
+ DEBUG(1,("ldapsam_create_user: Unsupported schema version\n"));
+ }
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT);
+
+ if (add_posix) {
+ char *escape_name;
+
+ DEBUG(3,("ldapsam_create_user: Creating new posix user\n"));
+
+ /* retrieve the Domain Users group gid */
+ if (!sid_compose(&group_sid, get_global_sam_sid(), DOMAIN_RID_USERS) ||
+ !sid_to_gid(&group_sid, &gid)) {
+ DEBUG (0, ("ldapsam_create_user: Unable to get the Domain Users gid: bailing out!\n"));
+ ldap_mods_free(mods, true);
+ return NT_STATUS_INVALID_PRIMARY_GROUP;
+ }
+
+ /* lets allocate a new userid for this user */
+ if (!winbind_allocate_uid(&uid)) {
+ DEBUG (0, ("ldapsam_create_user: Unable to allocate a new user id: bailing out!\n"));
+ ldap_mods_free(mods, true);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+
+ if (is_machine) {
+ /* TODO: choose a more appropriate default for machines */
+ homedir = talloc_sub_specified(tmp_ctx,
+ lp_template_homedir(),
+ "SMB_workstations_home",
+ NULL,
+ ldap_state->domain_name,
+ uid,
+ gid);
+ shell = talloc_strdup(tmp_ctx, "/bin/false");
+ } else {
+ homedir = talloc_sub_specified(tmp_ctx,
+ lp_template_homedir(),
+ name,
+ NULL,
+ ldap_state->domain_name,
+ uid,
+ gid);
+ shell = talloc_sub_specified(tmp_ctx,
+ lp_template_shell(),
+ name,
+ NULL,
+ ldap_state->domain_name,
+ uid,
+ gid);
+ }
+ uidstr = talloc_asprintf(tmp_ctx, "%u", (unsigned int)uid);
+ gidstr = talloc_asprintf(tmp_ctx, "%u", (unsigned int)gid);
+
+ escape_name = escape_rdn_val_string_alloc(name);
+ if (!escape_name) {
+ DEBUG (0, ("ldapsam_create_user: Out of memory!\n"));
+ ldap_mods_free(mods, true);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (is_machine) {
+ dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_machine_suffix (talloc_tos()));
+ } else {
+ dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_user_suffix (talloc_tos()));
+ }
+
+ SAFE_FREE(escape_name);
+
+ if (!homedir || !shell || !uidstr || !gidstr || !dn) {
+ DEBUG (0, ("ldapsam_create_user: Out of memory!\n"));
+ ldap_mods_free(mods, true);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_ACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_POSIXACCOUNT);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", homedir);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", shell);
+ }
+
+ if (add_posix) {
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ }
+
+ ldap_mods_free(mods, true);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_user: failed to create a new user [%s] (dn = %s)\n", name ,dn));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("ldapsam_create_user: added account [%s] in the LDAP database\n", name));
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_delete_user(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, struct samu *sam_acct)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int num_result;
+ const char *dn;
+ char *filter;
+ int rc;
+
+ DEBUG(0,("ldapsam_delete_user: Attempt to delete user [%s]\n", pdb_get_username(sam_acct)));
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(uid=%s)"
+ "(objectClass="LDAP_OBJ_POSIXACCOUNT")"
+ "(objectClass="LDAP_OBJ_SAMBASAMACCOUNT"))",
+ pdb_get_username(sam_acct));
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_delete_user: user search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(0,("ldapsam_delete_user: user not found!\n"));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_delete_user: More than one user with name [%s] ?!\n", pdb_get_username(sam_acct)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* it is just a posix account, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_delete_user: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* try to remove memberships first */
+ {
+ NTSTATUS status;
+ struct dom_sid *sids = NULL;
+ gid_t *gids = NULL;
+ uint32_t num_groups = 0;
+ int i;
+ uint32_t user_rid = pdb_get_user_rid(sam_acct);
+
+ status = ldapsam_enum_group_memberships(my_methods,
+ tmp_ctx,
+ sam_acct,
+ &sids,
+ &gids,
+ &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto delete_dn;
+ }
+
+ for (i=0; i < num_groups; i++) {
+
+ uint32_t group_rid;
+
+ sid_peek_rid(&sids[i], &group_rid);
+
+ ldapsam_del_groupmem(my_methods,
+ tmp_ctx,
+ group_rid,
+ user_rid);
+ }
+ }
+
+ delete_dn:
+
+ rc = smbldap_delete(ldap_state->smbldap_state, dn);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * ldapsam_create_group creates a new
+ * posixGroup and sambaGroupMapping object
+ * in the ldap groups subtree
+ *
+ * The gid is allocated by winbindd.
+ */
+
+static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ const char *name,
+ uint32_t *rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ NTSTATUS ret;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32_t num_result;
+ bool is_new_entry = False;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *groupname;
+ const char *grouptype;
+ char *gidstr;
+ const char *dn = NULL;
+ struct dom_sid group_sid;
+ struct dom_sid_buf buf;
+ gid_t gid = -1;
+ int rc;
+ int error = 0;
+
+ groupname = escape_ldap_string(talloc_tos(), name);
+ filter = talloc_asprintf(tmp_ctx, "(&(cn=%s)(objectClass="LDAP_OBJ_POSIXGROUP"))",
+ groupname);
+ TALLOC_FREE(groupname);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_group: ldap search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_create_group: There exists more than one group with name [%s]: bailing out!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (num_result == 1) {
+ char *tmp;
+ /* check if it is just a posix group.
+ * or if there is a sid attached to this entry
+ */
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "sambaSID", tmp_ctx);
+ if (tmp) {
+ DEBUG (1, ("ldapsam_create_group: The group [%s] already exist!\n", name));
+ return NT_STATUS_GROUP_EXISTS;
+ }
+
+ /* it is just a posix group, retrieve the gid and the dn for later use */
+ tmp = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!tmp) {
+ DEBUG (1, ("ldapsam_create_group: Couldn't retrieve the gidNumber for [%s]?!?!\n", name));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ gid = smb_strtoul(tmp, NULL, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_ERR("Failed to convert gidNumber\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (num_result == 0) {
+ is_new_entry = true;
+ }
+
+ if (!NT_STATUS_IS_OK((ret = ldapsam_new_rid_internal(my_methods, rid)))) {
+ DEBUG(1, ("ldapsam_create_group: Could not allocate a new RID\n"));
+ return ret;
+ }
+
+ sid_compose(&group_sid, get_global_sam_sid(), *rid);
+
+ grouptype = talloc_asprintf(tmp_ctx, "%d", SID_NAME_DOM_GRP);
+
+ if (!grouptype) {
+ DEBUG(0,("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_GROUPMAP);
+ smbldap_set_mod(&mods,
+ LDAP_MOD_ADD,
+ "sambaSid",
+ dom_sid_str_buf(&group_sid, &buf));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaGroupType", grouptype);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", name);
+
+ if (is_new_entry) {
+ char *escape_name;
+
+ DEBUG(3,("ldapsam_create_user: Creating new posix group\n"));
+
+ /* lets allocate a new groupid for this group */
+ if (!winbind_allocate_gid(&gid)) {
+ DEBUG (0, ("ldapsam_create_group: Unable to allocate a new group id: bailing out!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ gidstr = talloc_asprintf(tmp_ctx, "%u", (unsigned int)gid);
+
+ escape_name = escape_rdn_val_string_alloc(name);
+ if (!escape_name) {
+ DEBUG (0, ("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dn = talloc_asprintf(tmp_ctx, "cn=%s,%s", escape_name, lp_ldap_group_suffix(talloc_tos()));
+
+ SAFE_FREE(escape_name);
+
+ if (!gidstr || !dn) {
+ DEBUG (0, ("ldapsam_create_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_POSIXGROUP);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "cn", name);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr);
+ }
+
+ smbldap_talloc_autofree_ldapmod(tmp_ctx, mods);
+
+ if (is_new_entry) {
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+#if 0
+ if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
+ /* This call may fail with rfc2307bis schema */
+ /* Retry adding a structural class */
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", "????");
+ rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
+ }
+#endif
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_create_group: failed to create a new group [%s] (dn = %s)\n", name ,dn));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("ldapsam_create_group: added group [%s] in the LDAP database\n", name));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_delete_dom_group(struct pdb_methods *my_methods, TALLOC_CTX *tmp_ctx, uint32_t rid)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int num_result;
+ const char *dn;
+ char *gidstr;
+ char *filter;
+ struct dom_sid group_sid;
+ struct dom_sid_buf buf;
+ int rc;
+
+ /* get the group sid */
+ sid_compose(&group_sid, get_global_sam_sid(), rid);
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass="LDAP_OBJ_POSIXGROUP")"
+ "(objectClass="LDAP_OBJ_GROUPMAP"))",
+ dom_sid_str_buf(&group_sid, &buf));
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_delete_dom_group: group search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_delete_dom_group: group not found!\n"));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_delete_dom_group: More than one group with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* here it is, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_delete_dom_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_delete_dom_group: Unable to find the group's gid!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* check no user have this group marked as primary group */
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(gidNumber=%s)"
+ "(objectClass="LDAP_OBJ_POSIXACCOUNT")"
+ "(objectClass="LDAP_OBJ_SAMBASAMACCOUNT"))",
+ gidstr);
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_delete_dom_group: accounts search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result != 0) {
+ DEBUG(3,("ldapsam_delete_dom_group: Can't delete group, it is a primary group for %d users\n", num_result));
+ return NT_STATUS_MEMBERS_PRIMARY_GROUP;
+ }
+
+ rc = smbldap_delete(ldap_state->smbldap_state, dn);
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_change_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid,
+ int modop)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32_t num_result;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *uidstr;
+ const char *dn = NULL;
+ struct dom_sid group_sid;
+ struct dom_sid member_sid;
+ struct dom_sid_buf buf;
+ int rc;
+ int error = 0;
+
+ switch (modop) {
+ case LDAP_MOD_ADD:
+ DEBUG(1,("ldapsam_change_groupmem: add new member(rid=%d) to a domain group(rid=%d)\n", member_rid, group_rid));
+ break;
+ case LDAP_MOD_DELETE:
+ DEBUG(1,("ldapsam_change_groupmem: delete member(rid=%d) from a domain group(rid=%d)\n", member_rid, group_rid));
+ break;
+ default:
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* get member sid */
+ sid_compose(&member_sid, get_global_sam_sid(), member_rid);
+
+ /* get the group sid */
+ sid_compose(&group_sid, get_global_sam_sid(), group_rid);
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass="LDAP_OBJ_POSIXACCOUNT")"
+ "(objectClass="LDAP_OBJ_SAMBASAMACCOUNT"))",
+ dom_sid_str_buf(&member_sid, &buf));
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the member uid */
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_change_groupmem: member search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_change_groupmem: member not found!\n"));
+ return NT_STATUS_NO_SUCH_MEMBER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_change_groupmem: More than one account with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (modop == LDAP_MOD_DELETE) {
+ /* check if we are trying to remove the member from his primary group */
+ char *gidstr;
+ gid_t user_gid, group_gid;
+
+ gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", tmp_ctx);
+ if (!gidstr) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's gid!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ user_gid = smb_strtoul(gidstr, NULL, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_ERR("Failed to convert user gid\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!sid_to_gid(&group_sid, &group_gid)) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to get group gid from SID!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (user_gid == group_gid) {
+ DEBUG (3, ("ldapsam_change_groupmem: can't remove user from its own primary group!\n"));
+ return NT_STATUS_MEMBERS_PRIMARY_GROUP;
+ }
+ }
+
+ /* here it is, retrieve the uid for later use */
+ uidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "uid", tmp_ctx);
+ if (!uidstr) {
+ DEBUG (0, ("ldapsam_change_groupmem: Unable to find the member's name!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(sambaSID=%s)"
+ "(objectClass="LDAP_OBJ_POSIXGROUP")"
+ "(objectClass="LDAP_OBJ_GROUPMAP"))",
+ dom_sid_str_buf(&group_sid, &buf));
+
+ /* get the group */
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1,("ldapsam_change_groupmem: group search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(tmp_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(1,("ldapsam_change_groupmem: group not found!\n"));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_change_groupmem: More than one group with the same SID ?!\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* here it is, retrieve the dn for later use */
+ dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_change_groupmem: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod(&mods, modop, "memberUid", uidstr);
+
+ smbldap_talloc_autofree_ldapmod(tmp_ctx, mods);
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ if (rc != LDAP_SUCCESS) {
+ if (rc == LDAP_TYPE_OR_VALUE_EXISTS && modop == LDAP_MOD_ADD) {
+ DEBUG(1,("ldapsam_change_groupmem: member is already in group, add failed!\n"));
+ return NT_STATUS_MEMBER_IN_GROUP;
+ }
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE && modop == LDAP_MOD_DELETE) {
+ DEBUG(1,("ldapsam_change_groupmem: member is not in group, delete failed!\n"));
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid)
+{
+ return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_ADD);
+}
+static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods,
+ TALLOC_CTX *tmp_ctx,
+ uint32_t group_rid,
+ uint32_t member_rid)
+{
+ return ldapsam_change_groupmem(my_methods, tmp_ctx, group_rid, member_rid, LDAP_MOD_DELETE);
+}
+
+static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sampass)
+{
+ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMessage *result = NULL;
+ uint32_t num_result;
+ LDAPMod **mods = NULL;
+ char *filter;
+ char *escape_username;
+ char *gidstr;
+ char *dn = NULL;
+ gid_t gid;
+ int rc;
+
+ DEBUG(0,("ldapsam_set_primary_group: Attempt to set primary group for user [%s]\n", pdb_get_username(sampass)));
+
+ if (!sid_to_gid(pdb_get_group_sid(sampass), &gid)) {
+ DEBUG(0,("ldapsam_set_primary_group: failed to retrieve gid from user's group SID!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ gidstr = talloc_asprintf(mem_ctx, "%u", (unsigned int)gid);
+ if (!gidstr) {
+ DEBUG(0,("ldapsam_set_primary_group: Out of Memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ escape_username = escape_ldap_string(talloc_tos(),
+ pdb_get_username(sampass));
+ if (escape_username== NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(uid=%s)"
+ "(objectClass="LDAP_OBJ_POSIXACCOUNT")"
+ "(objectClass="LDAP_OBJ_SAMBASAMACCOUNT"))",
+ escape_username);
+
+ TALLOC_FREE(escape_username);
+
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_set_primary_group: user search failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result == 0) {
+ DEBUG(0,("ldapsam_set_primary_group: user not found!\n"));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (num_result > 1) {
+ DEBUG (0, ("ldapsam_set_primary_group: More than one user with name [%s] ?!\n", pdb_get_username(sampass)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ entry = ldap_first_entry(priv2ld(ldap_state), result);
+ if (!entry) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* retrieve the dn for later use */
+ dn = smbldap_talloc_dn(mem_ctx, priv2ld(ldap_state), entry);
+ if (!dn) {
+ DEBUG(0,("ldapsam_set_primary_group: Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* remove the old one, and add the new one, this way we do not risk races */
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "gidNumber", gidstr);
+
+ if (mods == NULL) {
+ TALLOC_FREE(dn);
+ return NT_STATUS_OK;
+ }
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+ TALLOC_FREE(dn);
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldapsam_set_primary_group: failed to modify [%s] primary group to [%s]\n",
+ pdb_get_username(sampass), gidstr));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ flush_pwnam_cache();
+
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ trusted domains functions
+ *********************************************************************/
+
+static char *trusteddom_dn(struct ldapsam_privates *ldap_state,
+ const char *domain)
+{
+ return talloc_asprintf(talloc_tos(), "sambaDomainName=%s,%s", domain,
+ ldap_state->domain_dn);
+}
+
+static bool get_trusteddom_pw_int(struct ldapsam_privates *ldap_state,
+ TALLOC_CTX *mem_ctx,
+ const char *domain, LDAPMessage **entry)
+{
+ int rc;
+ char *filter;
+ int scope = LDAP_SCOPE_SUBTREE;
+ const char **attrs = NULL; /* NULL: get all attrs */
+ int attrsonly = 0; /* 0: return values too */
+ LDAPMessage *result = NULL;
+ char *trusted_dn;
+ uint32_t num_result;
+
+ filter = talloc_asprintf(talloc_tos(),
+ "(&(objectClass="LDAP_OBJ_TRUSTDOM_PASSWORD")(sambaDomainName=%s))",
+ domain);
+
+ trusted_dn = trusteddom_dn(ldap_state, domain);
+ if (trusted_dn == NULL) {
+ return False;
+ }
+ rc = smbldap_search(ldap_state->smbldap_state, trusted_dn, scope,
+ filter, attrs, attrsonly, &result);
+
+ if (result != NULL) {
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+ }
+
+ if (rc == LDAP_NO_SUCH_OBJECT) {
+ *entry = NULL;
+ return True;
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return False;
+ }
+
+ num_result = ldap_count_entries(priv2ld(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG(1, ("ldapsam_get_trusteddom_pw: more than one "
+ "%s object for domain '%s'?!\n",
+ LDAP_OBJ_TRUSTDOM_PASSWORD, domain));
+ return False;
+ }
+
+ if (num_result == 0) {
+ DEBUG(1, ("ldapsam_get_trusteddom_pw: no "
+ "%s object for domain %s.\n",
+ LDAP_OBJ_TRUSTDOM_PASSWORD, domain));
+ *entry = NULL;
+ } else {
+ *entry = ldap_first_entry(priv2ld(ldap_state), result);
+ }
+
+ return True;
+}
+
+static bool ldapsam_get_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain,
+ char** pwd,
+ struct dom_sid *sid,
+ time_t *pass_last_set_time)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+
+ DEBUG(10, ("ldapsam_get_trusteddom_pw called for domain %s\n", domain));
+
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry) ||
+ (entry == NULL))
+ {
+ return False;
+ }
+
+ /* password */
+ if (pwd != NULL) {
+ char *pwd_str;
+ pwd_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaClearTextPassword", talloc_tos());
+ if (pwd_str == NULL) {
+ return False;
+ }
+ /* trusteddom_pw routines do not use talloc yet... */
+ *pwd = SMB_STRDUP(pwd_str);
+ if (*pwd == NULL) {
+ return False;
+ }
+ }
+
+ /* last change time */
+ if (pass_last_set_time != NULL) {
+ char *time_str;
+ time_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaPwdLastSet", talloc_tos());
+ if (time_str == NULL) {
+ return False;
+ }
+ *pass_last_set_time = (time_t)atol(time_str);
+ }
+
+ /* domain sid */
+ if (sid != NULL) {
+ char *sid_str;
+ struct dom_sid dom_sid;
+ sid_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaSID",
+ talloc_tos());
+ if (sid_str == NULL) {
+ return False;
+ }
+ if (!string_to_sid(&dom_sid, sid_str)) {
+ return False;
+ }
+ sid_copy(sid, &dom_sid);
+ }
+
+ return True;
+}
+
+static bool ldapsam_set_trusteddom_pw(struct pdb_methods *methods,
+ const char* domain,
+ const char* pwd,
+ const struct dom_sid *sid)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+ LDAPMod **mods = NULL;
+ char *prev_pwd = NULL;
+ char *trusted_dn = NULL;
+ struct dom_sid_buf buf;
+ int rc;
+
+ DEBUG(10, ("ldapsam_set_trusteddom_pw called for domain %s\n", domain));
+
+ /*
+ * get the current entry (if there is one) in order to put the
+ * current password into the previous password attribute
+ */
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry)) {
+ return False;
+ }
+
+ mods = NULL;
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "objectClass",
+ LDAP_OBJ_TRUSTDOM_PASSWORD);
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaDomainName",
+ domain);
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaSID",
+ dom_sid_str_buf(sid, &buf));
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "sambaPwdLastSet",
+ talloc_asprintf(talloc_tos(), "%li", (long int)time(NULL)));
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
+ "sambaClearTextPassword", pwd);
+
+ if (entry != NULL) {
+ prev_pwd = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry, "sambaClearTextPassword", talloc_tos());
+ if (prev_pwd != NULL) {
+ smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
+ "sambaPreviousClearTextPassword",
+ prev_pwd);
+ }
+ }
+
+ smbldap_talloc_autofree_ldapmod(talloc_tos(), mods);
+
+ trusted_dn = trusteddom_dn(ldap_state, domain);
+ if (trusted_dn == NULL) {
+ return False;
+ }
+ if (entry == NULL) {
+ rc = smbldap_add(ldap_state->smbldap_state, trusted_dn, mods);
+ } else {
+ rc = smbldap_modify(ldap_state->smbldap_state, trusted_dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(1, ("error writing trusted domain password!\n"));
+ return False;
+ }
+
+ return True;
+}
+
+static bool ldapsam_del_trusteddom_pw(struct pdb_methods *methods,
+ const char *domain)
+{
+ int rc;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *entry = NULL;
+ const char *trusted_dn;
+
+ if (!get_trusteddom_pw_int(ldap_state, talloc_tos(), domain, &entry)) {
+ return False;
+ }
+
+ if (entry == NULL) {
+ DEBUG(5, ("ldapsam_del_trusteddom_pw: no such trusted domain: "
+ "%s\n", domain));
+ return True;
+ }
+
+ trusted_dn = smbldap_talloc_dn(talloc_tos(), priv2ld(ldap_state),
+ entry);
+ if (trusted_dn == NULL) {
+ DEBUG(0,("ldapsam_del_trusteddom_pw: Out of memory!\n"));
+ return False;
+ }
+
+ rc = smbldap_delete(ldap_state->smbldap_state, trusted_dn);
+ if (rc != LDAP_SUCCESS) {
+ return False;
+ }
+
+ return True;
+}
+
+static NTSTATUS ldapsam_enum_trusteddoms(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_domains,
+ struct trustdom_info ***domains)
+{
+ int rc;
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ const char *filter;
+ int scope = LDAP_SCOPE_SUBTREE;
+ const char *attrs[] = { "sambaDomainName", "sambaSID", NULL };
+ int attrsonly = 0; /* 0: return values too */
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+
+ filter = "(objectClass="LDAP_OBJ_TRUSTDOM_PASSWORD")";
+
+ rc = smbldap_search(ldap_state->smbldap_state,
+ ldap_state->domain_dn,
+ scope,
+ filter,
+ attrs,
+ attrsonly,
+ &result);
+
+ if (result != NULL) {
+ smbldap_talloc_autofree_ldapmsg(mem_ctx, result);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *num_domains = 0;
+ if (!(*domains = talloc_array(mem_ctx, struct trustdom_info *, 1))) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (entry = ldap_first_entry(priv2ld(ldap_state), result);
+ entry != NULL;
+ entry = ldap_next_entry(priv2ld(ldap_state), entry))
+ {
+ char *dom_name, *dom_sid_str;
+ struct trustdom_info *dom_info;
+
+ dom_info = talloc(*domains, struct trustdom_info);
+ if (dom_info == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dom_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
+ entry,
+ "sambaDomainName",
+ talloc_tos());
+ if (dom_name == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ dom_info->name = dom_name;
+
+ dom_sid_str = smbldap_talloc_single_attribute(
+ priv2ld(ldap_state), entry, "sambaSID",
+ talloc_tos());
+ if (dom_sid_str == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!string_to_sid(&dom_info->sid, dom_sid_str)) {
+ DEBUG(1, ("Error calling string_to_sid on SID %s\n",
+ dom_sid_str));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ADD_TO_ARRAY(*domains, struct trustdom_info *, dom_info,
+ domains, num_domains);
+
+ if (*domains == NULL) {
+ DEBUG(1, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ DEBUG(5, ("ldapsam_enum_trusteddoms: got %d domains\n", *num_domains));
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************************
+ Housekeeping
+ *********************************************************************/
+
+static void free_private_data(void **vp)
+{
+ struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+
+ smbldap_free_struct(&(*ldap_state)->smbldap_state);
+
+ if ((*ldap_state)->result != NULL) {
+ ldap_msgfree((*ldap_state)->result);
+ (*ldap_state)->result = NULL;
+ }
+ if ((*ldap_state)->domain_dn != NULL) {
+ SAFE_FREE((*ldap_state)->domain_dn);
+ }
+
+ *ldap_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+/*********************************************************************
+ Initialise the parts of the pdb_methods structure that are common to
+ all pdb_ldap modes
+*********************************************************************/
+
+static NTSTATUS pdb_init_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state;
+ char *bind_dn = NULL;
+ char *bind_secret = NULL;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam";
+
+ (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
+ (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
+ (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
+ (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
+ (*pdb_method)->rename_sam_account = ldapsam_rename_sam_account;
+
+ (*pdb_method)->getgrsid = ldapsam_getgrsid;
+ (*pdb_method)->getgrgid = ldapsam_getgrgid;
+ (*pdb_method)->getgrnam = ldapsam_getgrnam;
+ (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
+ (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
+ (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
+ (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
+
+ (*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;
+
+ (*pdb_method)->capabilities = ldapsam_capabilities;
+ (*pdb_method)->new_rid = ldapsam_new_rid;
+
+ (*pdb_method)->get_trusteddom_pw = ldapsam_get_trusteddom_pw;
+ (*pdb_method)->set_trusteddom_pw = ldapsam_set_trusteddom_pw;
+ (*pdb_method)->del_trusteddom_pw = ldapsam_del_trusteddom_pw;
+ (*pdb_method)->enum_trusteddoms = ldapsam_enum_trusteddoms;
+
+ /* TODO: Setup private data and free */
+
+ if ( !(ldap_state = talloc_zero(*pdb_method, struct ldapsam_privates)) ) {
+ DEBUG(0, ("pdb_init_ldapsam_common: talloc() failed for ldapsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!fetch_ldap_pw(&bind_dn, &bind_secret)) {
+ DEBUG(0, ("pdb_init_ldapsam_common: Failed to retrieve LDAP password from secrets.tdb\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = smbldap_init(*pdb_method, pdb_get_tevent_context(),
+ location, false, bind_dn, bind_secret,
+ &ldap_state->smbldap_state);
+ BURN_FREE_STR(bind_secret);
+ SAFE_FREE(bind_dn);
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ return nt_status;
+ }
+
+ if ( !(ldap_state->domain_name = talloc_strdup(*pdb_method, get_global_sam_name()) ) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*pdb_method)->private_data = ldap_state;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+static bool ldapsam_is_responsible_for_wellknown(struct pdb_methods *m)
+{
+ return true;
+}
+
+/**********************************************************************
+ Initialise the normal mode for pdb_ldap
+ *********************************************************************/
+
+NTSTATUS pdb_ldapsam_init_common(struct pdb_methods **pdb_method,
+ const char *location)
+{
+ NTSTATUS nt_status;
+ struct ldapsam_privates *ldap_state = NULL;
+ uint32_t alg_rid_base;
+ char *alg_rid_base_string = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ struct dom_sid ldap_domain_sid;
+ struct dom_sid secrets_domain_sid;
+ char *domain_sid_string = NULL;
+ char *dn = NULL;
+ char *uri = talloc_strdup( NULL, location );
+
+ trim_char( uri, '\"', '\"' );
+ nt_status = pdb_init_ldapsam_common(pdb_method, uri);
+
+ TALLOC_FREE(uri);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "ldapsam";
+
+ (*pdb_method)->add_aliasmem = ldapsam_add_aliasmem;
+ (*pdb_method)->del_aliasmem = ldapsam_del_aliasmem;
+ (*pdb_method)->enum_aliasmem = ldapsam_enum_aliasmem;
+ (*pdb_method)->enum_alias_memberships = ldapsam_alias_memberships;
+ (*pdb_method)->search_users = ldapsam_search_users;
+ (*pdb_method)->search_groups = ldapsam_search_groups;
+ (*pdb_method)->search_aliases = ldapsam_search_aliases;
+ (*pdb_method)->is_responsible_for_wellknown =
+ ldapsam_is_responsible_for_wellknown;
+
+ if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
+ (*pdb_method)->enum_group_members = ldapsam_enum_group_members;
+ (*pdb_method)->enum_group_memberships =
+ ldapsam_enum_group_memberships;
+ (*pdb_method)->lookup_rids = ldapsam_lookup_rids;
+ (*pdb_method)->sid_to_id = ldapsam_sid_to_id;
+ (*pdb_method)->id_to_sid = ldapsam_id_to_sid;
+
+ if (lp_parm_bool(-1, "ldapsam", "editposix", False)) {
+ (*pdb_method)->create_user = ldapsam_create_user;
+ (*pdb_method)->delete_user = ldapsam_delete_user;
+ (*pdb_method)->create_dom_group = ldapsam_create_dom_group;
+ (*pdb_method)->delete_dom_group = ldapsam_delete_dom_group;
+ (*pdb_method)->add_groupmem = ldapsam_add_groupmem;
+ (*pdb_method)->del_groupmem = ldapsam_del_groupmem;
+ (*pdb_method)->set_unix_primary_group = ldapsam_set_primary_group;
+ }
+ }
+
+ ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
+ ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
+
+ /* Try to setup the Domain Name, Domain SID, algorithmic rid base */
+
+ nt_status = smbldap_search_domain_info(ldap_state->smbldap_state,
+ &result,
+ ldap_state->domain_name, True);
+
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ DEBUG(0, ("pdb_init_ldapsam: WARNING: Could not get domain "
+ "info, nor add one to the domain. "
+ "We cannot work reliably without it.\n"));
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ /* Given that the above might fail, everything below this must be
+ * optional */
+
+ entry = ldap_first_entry(smbldap_get_ldap(ldap_state->smbldap_state),
+ result);
+ if (!entry) {
+ DEBUG(0, ("pdb_init_ldapsam: Could not get domain info "
+ "entry\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_talloc_dn(talloc_tos(),
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ldap_state->domain_dn = smb_xstrdup(dn);
+ TALLOC_FREE(dn);
+
+ domain_sid_string = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_userattr_key2string(ldap_state->schema_ver,
+ LDAP_ATTR_USER_SID),
+ talloc_tos());
+
+ if (domain_sid_string) {
+ bool found_sid;
+ if (!string_to_sid(&ldap_domain_sid, domain_sid_string)) {
+ DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be "
+ "read as a valid SID\n", domain_sid_string));
+ ldap_msgfree(result);
+ TALLOC_FREE(domain_sid_string);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ found_sid = PDB_secrets_fetch_domain_sid(ldap_state->domain_name,
+ &secrets_domain_sid);
+ if (!found_sid || !dom_sid_equal(&secrets_domain_sid,
+ &ldap_domain_sid)) {
+ struct dom_sid_buf buf1, buf2;
+ DEBUG(1, ("pdb_init_ldapsam: Resetting SID for domain "
+ "%s based on pdb_ldap results %s -> %s\n",
+ ldap_state->domain_name,
+ dom_sid_str_buf(&secrets_domain_sid, &buf1),
+ dom_sid_str_buf(&ldap_domain_sid, &buf2)));
+
+ /* reset secrets.tdb sid */
+ PDB_secrets_store_domain_sid(ldap_state->domain_name,
+ &ldap_domain_sid);
+ DEBUG(1, ("New global sam SID: %s\n",
+ dom_sid_str_buf(get_global_sam_sid(),
+ &buf1)));
+ }
+ sid_copy(&ldap_state->domain_sid, &ldap_domain_sid);
+ TALLOC_FREE(domain_sid_string);
+ }
+
+ alg_rid_base_string = smbldap_talloc_single_attribute(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ entry,
+ get_attr_key2string( dominfo_attr_list,
+ LDAP_ATTR_ALGORITHMIC_RID_BASE ),
+ talloc_tos());
+ if (alg_rid_base_string) {
+ alg_rid_base = (uint32_t)atol(alg_rid_base_string);
+ if (alg_rid_base != algorithmic_rid_base()) {
+ DEBUG(0, ("The value of 'algorithmic RID base' has "
+ "changed since the LDAP\n"
+ "database was initialised. Aborting. \n"));
+ ldap_msgfree(result);
+ TALLOC_FREE(alg_rid_base_string);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ TALLOC_FREE(alg_rid_base_string);
+ }
+ ldap_msgfree(result);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_ldapsam_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS nt_status;
+
+ nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION,
+ "ldapsam",
+ pdb_ldapsam_init_common);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ /* Let pdb_nds register backends */
+ pdb_nds_init(ctx);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_ldap.h b/source3/passdb/pdb_ldap.h
new file mode 100644
index 0000000..755574a
--- /dev/null
+++ b/source3/passdb/pdb_ldap.h
@@ -0,0 +1,71 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+ Copyright (C) Simo Sorce 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _PASSDB_PDB_LDAP_H_
+#define _PASSDB_PDB_LDAP_H_
+
+/* struct used by both pdb_ldap.c and pdb_nds.c */
+
+struct ldapsam_privates {
+ struct smbldap_state *smbldap_state;
+
+ /* Former statistics */
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ int index;
+
+ const char *domain_name;
+ struct dom_sid domain_sid;
+
+ /* configuration items */
+ int schema_ver;
+
+ char *domain_dn;
+
+ /* Is this NDS ldap? */
+ int is_nds_ldap;
+
+ /* ldap server location parameter */
+ char *location;
+
+ struct {
+ char *filter;
+ LDAPMessage *result;
+ } search_cache;
+};
+
+/* The following definitions come from passdb/pdb_ldap.c */
+
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver );
+NTSTATUS pdb_ldapsam_init_common(struct pdb_methods **pdb_method, const char *location);
+NTSTATUS pdb_ldapsam_init(TALLOC_CTX *);
+int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
+ const char *user,
+ LDAPMessage ** result,
+ const char **attr);
+const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver );
+LDAP *priv2ld(struct ldapsam_privates *priv);
+
+#endif /* _PASSDB_PDB_LDAP_H_ */
diff --git a/source3/passdb/pdb_ldap_schema.c b/source3/passdb/pdb_ldap_schema.c
new file mode 100644
index 0000000..da738d5
--- /dev/null
+++ b/source3/passdb/pdb_ldap_schema.c
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "passdb/pdb_ldap_schema.h"
+
+/* attributes used by Samba 3.0's sambaSamAccount */
+
+ATTRIB_MAP_ENTRY attrib_map_v30[] = {
+ { LDAP_ATTR_UID, "uid" },
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
+ { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
+ { LDAP_ATTR_CN, "cn" },
+ { LDAP_ATTR_SN, "sn" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
+ { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
+ { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
+ { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
+ { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
+ { LDAP_ATTR_LMPW, "sambaLMPassword" },
+ { LDAP_ATTR_NTPW, "sambaNTPassword" },
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
+ { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
+ { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
+ { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" },
+ { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" },
+ { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[] = {
+ { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
+ { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
+ { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
+ { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
+ { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
+ { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
+ { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
+ { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
+ { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
+ { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
+ { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
+ { LDAP_ATTR_LMPW, "sambaLMPassword" },
+ { LDAP_ATTR_NTPW, "sambaNTPassword" },
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
+ { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
+ { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
+ { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" },
+ { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/* attributes used for allocating RIDs */
+
+ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
+ { LDAP_ATTR_DOMAIN, "sambaDomainName" },
+ { LDAP_ATTR_NEXT_RID, "sambaNextRid" },
+ { LDAP_ATTR_NEXT_USERRID, "sambaNextUserRid" },
+ { LDAP_ATTR_NEXT_GROUPRID, "sambaNextGroupRid" },
+ { LDAP_ATTR_DOM_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_ALGORITHMIC_RID_BASE,"sambaAlgorithmicRidBase"},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL },
+};
+
+/* Samba 3.0 group mapping attributes */
+
+ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_CN, "cn" },
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
+ { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
+ { LDAP_ATTR_DESC, "description" },
+ { LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/* idmap_ldap sambaUnixIdPool */
+
+ATTRIB_MAP_ENTRY idpool_attr_list[] = {
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
+ { LDAP_ATTR_SID, LDAP_ATTRIBUTE_SID },
+ { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
+ { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
+ { LDAP_ATTR_OBJCLASS, "objectClass" },
+ { LDAP_ATTR_LIST_END, NULL }
+};
+
+/**********************************************************************
+ perform a simple table lookup and return the attribute name
+ **********************************************************************/
+
+ const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
+{
+ int i = 0;
+
+ while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
+ if ( table[i].attrib == key )
+ return table[i].name;
+ i++;
+ }
+
+ return NULL;
+}
+
+
+/**********************************************************************
+ Return the list of attribute names from a mapping table
+ **********************************************************************/
+
+ const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] )
+{
+ const char **names;
+ int i = 0;
+
+ while ( table[i].attrib != LDAP_ATTR_LIST_END )
+ i++;
+ i++;
+
+ names = talloc_array( mem_ctx, const char*, i );
+ if ( !names ) {
+ DEBUG(0,("get_attr_list: out of memory\n"));
+ return NULL;
+ }
+
+ i = 0;
+ while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
+ names[i] = talloc_strdup( names, table[i].name );
+ i++;
+ }
+ names[i] = NULL;
+
+ return names;
+}
diff --git a/source3/passdb/pdb_ldap_schema.h b/source3/passdb/pdb_ldap_schema.h
new file mode 100644
index 0000000..ea98db2
--- /dev/null
+++ b/source3/passdb/pdb_ldap_schema.h
@@ -0,0 +1,124 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Gerald Carter 2001-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _PASSDB_PDB_LDAP_SCHEMA_H_
+#define _PASSDB_PDB_LDAP_SCHEMA_H_
+
+/* Schema versions */
+#define SCHEMAVER_SAMBAACCOUNT 1 /* Samba 2.2 */
+#define SCHEMAVER_SAMBASAMACCOUNT 2 /* Samba 3.0 */
+
+/* objectclass names */
+
+#define LDAP_OBJ_SAMBASAMACCOUNT "sambaSamAccount"
+#define LDAP_OBJ_GROUPMAP "sambaGroupMapping"
+#define LDAP_OBJ_DOMINFO "sambaDomain"
+#define LDAP_OBJ_IDPOOL "sambaUnixIdPool"
+#define LDAP_OBJ_IDMAP_ENTRY "sambaIdmapEntry"
+#define LDAP_OBJ_SID_ENTRY "sambaSidEntry"
+#define LDAP_OBJ_TRUST_PASSWORD "sambaTrustPassword"
+#define LDAP_OBJ_TRUSTDOM_PASSWORD "sambaTrustedDomainPassword"
+#define LDAP_OBJ_TRUSTED_DOMAIN "sambaTrustedDomain"
+
+#define LDAP_OBJ_ACCOUNT "account"
+#define LDAP_OBJ_POSIXACCOUNT "posixAccount"
+#define LDAP_OBJ_POSIXGROUP "posixGroup"
+#define LDAP_OBJ_OU "organizationalUnit"
+
+/* some generic attributes that get reused a lot */
+
+#define LDAP_ATTRIBUTE_SID "sambaSID"
+#define LDAP_ATTRIBUTE_UIDNUMBER "uidNumber"
+#define LDAP_ATTRIBUTE_GIDNUMBER "gidNumber"
+#define LDAP_ATTRIBUTE_SID_LIST "sambaSIDList"
+
+/* attribute map table indexes */
+
+#define LDAP_ATTR_LIST_END 0
+#define LDAP_ATTR_UID 1
+#define LDAP_ATTR_UIDNUMBER 2
+#define LDAP_ATTR_GIDNUMBER 3
+#define LDAP_ATTR_UNIX_HOME 4
+#define LDAP_ATTR_PWD_LAST_SET 5
+#define LDAP_ATTR_PWD_CAN_CHANGE 6
+#define LDAP_ATTR_PWD_MUST_CHANGE 7
+#define LDAP_ATTR_LOGON_TIME 8
+#define LDAP_ATTR_LOGOFF_TIME 9
+#define LDAP_ATTR_KICKOFF_TIME 10
+#define LDAP_ATTR_CN 11
+#define LDAP_ATTR_DISPLAY_NAME 12
+#define LDAP_ATTR_HOME_PATH 13
+#define LDAP_ATTR_LOGON_SCRIPT 14
+#define LDAP_ATTR_PROFILE_PATH 15
+#define LDAP_ATTR_DESC 16
+#define LDAP_ATTR_USER_WKS 17
+#define LDAP_ATTR_USER_SID 18
+#define LDAP_ATTR_USER_RID 18
+#define LDAP_ATTR_PRIMARY_GROUP_SID 19
+#define LDAP_ATTR_PRIMARY_GROUP_RID 20
+#define LDAP_ATTR_LMPW 21
+#define LDAP_ATTR_NTPW 22
+#define LDAP_ATTR_DOMAIN 23
+#define LDAP_ATTR_OBJCLASS 24
+#define LDAP_ATTR_ACB_INFO 25
+#define LDAP_ATTR_NEXT_USERRID 26
+#define LDAP_ATTR_NEXT_GROUPRID 27
+#define LDAP_ATTR_DOM_SID 28
+#define LDAP_ATTR_HOME_DRIVE 29
+#define LDAP_ATTR_GROUP_SID 30
+#define LDAP_ATTR_GROUP_TYPE 31
+#define LDAP_ATTR_SID 32
+#define LDAP_ATTR_ALGORITHMIC_RID_BASE 33
+#define LDAP_ATTR_NEXT_RID 34
+#define LDAP_ATTR_BAD_PASSWORD_COUNT 35
+#define LDAP_ATTR_LOGON_COUNT 36
+#define LDAP_ATTR_MUNGED_DIAL 37
+#define LDAP_ATTR_BAD_PASSWORD_TIME 38
+#define LDAP_ATTR_PWD_HISTORY 39
+#define LDAP_ATTR_SID_LIST 40
+#define LDAP_ATTR_MOD_TIMESTAMP 41
+#define LDAP_ATTR_LOGON_HOURS 42
+#define LDAP_ATTR_TRUST_PASSWD_FLAGS 43
+#define LDAP_ATTR_SN 44
+
+
+typedef struct _attrib_map_entry {
+ int attrib;
+ const char *name;
+} ATTRIB_MAP_ENTRY;
+
+
+/* structures */
+
+extern ATTRIB_MAP_ENTRY attrib_map_v30[];
+extern ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[];
+extern ATTRIB_MAP_ENTRY dominfo_attr_list[];
+extern ATTRIB_MAP_ENTRY groupmap_attr_list[];
+extern ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[];
+extern ATTRIB_MAP_ENTRY idpool_attr_list[];
+extern ATTRIB_MAP_ENTRY sidmap_attr_list[];
+extern ATTRIB_MAP_ENTRY trustpw_attr_list[];
+
+/* The following definitions come from passdb/pdb_ldap_schema.c */
+
+const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key );
+const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] );
+
+#endif /* _PASSDB_PDB_LDAP_SCHEMA_H_ */
diff --git a/source3/passdb/pdb_ldap_util.c b/source3/passdb/pdb_ldap_util.c
new file mode 100644
index 0000000..0c1708d
--- /dev/null
+++ b/source3/passdb/pdb_ldap_util.c
@@ -0,0 +1,338 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+ Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "smbldap.h"
+#include "passdb.h"
+#include "passdb/pdb_ldap_util.h"
+#include "passdb/pdb_ldap_schema.h"
+#include "libcli/security/dom_sid.h"
+
+/**********************************************************************
+ Add the account-policies below the sambaDomain object to LDAP,
+*********************************************************************/
+
+static NTSTATUS add_new_domain_account_policies(struct smbldap_state *ldap_state,
+ const char *domain_name)
+{
+ NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
+ int i, rc;
+ uint32_t policy_default;
+ const char *policy_attr = NULL;
+ char *dn = NULL;
+ LDAPMod **mods = NULL;
+ char *escape_domain_name;
+
+ DEBUG(3,("add_new_domain_account_policies: Adding new account policies for domain\n"));
+
+ escape_domain_name = escape_rdn_val_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&dn, "%s=%s,%s",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, lp_ldap_suffix()) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ for (i=1; decode_account_policy_name(i) != NULL; i++) {
+ char *val = NULL;
+
+ policy_attr = get_account_policy_attr(i);
+ if (!policy_attr) {
+ DEBUG(0,("add_new_domain_account_policies: ops. no policy!\n"));
+ continue;
+ }
+
+ if (!account_policy_get_default(i, &policy_default)) {
+ DEBUG(0,("add_new_domain_account_policies: failed to get default account policy\n"));
+ SAFE_FREE(dn);
+ return ntstatus;
+ }
+
+ DEBUG(10,("add_new_domain_account_policies: adding \"%s\" with value: %d\n", policy_attr, policy_default));
+
+ if (asprintf(&val, "%d", policy_default) < 0) {
+ SAFE_FREE(dn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ smbldap_set_mod( &mods, LDAP_MOD_REPLACE, policy_attr, val);
+
+ rc = smbldap_modify(ldap_state, dn, mods);
+
+ SAFE_FREE(val);
+
+ if (rc!=LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(1,("add_new_domain_account_policies: failed to add account policies to dn= %s with: %s\n\t%s\n",
+ dn, ldap_err2string(rc),
+ ld_error ? ld_error : "unknown"));
+ SAFE_FREE(ld_error);
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+ return ntstatus;
+ }
+ }
+
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Add the sambaDomain to LDAP, so we don't have to search for this stuff
+ again. This is a once-add operation for now.
+
+ TODO: Add other attributes, and allow modification.
+*********************************************************************/
+
+static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state,
+ const char *domain_name)
+{
+ struct dom_sid_buf sid_string;
+ fstring algorithmic_rid_base_string;
+ char *filter = NULL;
+ char *dn = NULL;
+ LDAPMod **mods = NULL;
+ int rc;
+ LDAPMessage *result = NULL;
+ int num_result;
+ const char **attr_list;
+ char *escape_domain_name;
+
+ /* escape for filter */
+ escape_domain_name = escape_ldap_string(talloc_tos(), domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(%s=%s)(objectclass=%s))",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, LDAP_OBJ_DOMINFO) < 0) {
+ TALLOC_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ TALLOC_FREE(escape_domain_name);
+
+ attr_list = get_attr_list(NULL, dominfo_attr_list );
+ rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
+ TALLOC_FREE( attr_list );
+ SAFE_FREE(filter);
+
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ num_result = ldap_count_entries(smbldap_get_ldap(ldap_state), result);
+
+ if (num_result > 1) {
+ DEBUG (0, ("add_new_domain_info: More than domain with that name exists: bailing "
+ "out!\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Check if we need to add an entry */
+ DEBUG(3,("add_new_domain_info: Adding new domain\n"));
+
+ /* this time escape for DN */
+ escape_domain_name = escape_rdn_val_string_alloc(domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&dn, "%s=%s,%s",
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name, lp_ldap_suffix()) < 0) {
+ SAFE_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(escape_domain_name);
+
+ /* Free original search */
+ ldap_msgfree(result);
+
+ /* make the changes - the entry *must* not already have samba
+ * attributes */
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_DOMAIN),
+ domain_name);
+
+ /* If we don't have an entry, then ask secrets.tdb for what it thinks.
+ It may choose to make it up */
+
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_DOM_SID),
+ dom_sid_str_buf(get_global_sam_sid(), &sid_string));
+
+ slprintf(algorithmic_rid_base_string,
+ sizeof(algorithmic_rid_base_string) - 1, "%i",
+ algorithmic_rid_base());
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string);
+ smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
+
+ /* add the sambaNextUserRid attributes. */
+
+ {
+ uint32_t rid = BASE_RID;
+ fstring rid_str;
+
+ fstr_sprintf( rid_str, "%i", rid );
+ DEBUG(10,("add_new_domain_info: setting next available user rid [%s]\n", rid_str));
+ smbldap_set_mod(&mods, LDAP_MOD_ADD,
+ get_attr_key2string(dominfo_attr_list,
+ LDAP_ATTR_NEXT_USERRID),
+ rid_str);
+ }
+
+
+ rc = smbldap_add(ldap_state, dn, mods);
+
+ if (rc!=LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(1,("add_new_domain_info: failed to add domain dn= %s with: %s\n\t%s\n",
+ dn, ldap_err2string(rc),
+ ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ SAFE_FREE(dn);
+ ldap_mods_free(mods, True);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(2,("add_new_domain_info: added: domain = %s in the LDAP database\n", domain_name));
+ ldap_mods_free(mods, True);
+ SAFE_FREE(dn);
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+Search for the domain info entry
+*********************************************************************/
+
+NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
+ LDAPMessage ** result, const char *domain_name,
+ bool try_add)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *filter = NULL;
+ int rc;
+ const char **attr_list;
+ int count;
+ char *escape_domain_name;
+
+ escape_domain_name = escape_ldap_string(talloc_tos(), domain_name);
+ if (!escape_domain_name) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (asprintf(&filter, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_DOMINFO,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
+ escape_domain_name) < 0) {
+ TALLOC_FREE(escape_domain_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ TALLOC_FREE(escape_domain_name);
+
+ DEBUG(2, ("smbldap_search_domain_info: Searching for:[%s]\n", filter));
+
+ attr_list = get_attr_list( NULL, dominfo_attr_list );
+ rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
+ TALLOC_FREE( attr_list );
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(2,("smbldap_search_domain_info: Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
+ DEBUG(2,("smbldap_search_domain_info: Query was: %s, %s\n", lp_ldap_suffix(), filter));
+ goto failed;
+ }
+
+ SAFE_FREE(filter);
+
+ count = ldap_count_entries(smbldap_get_ldap(ldap_state), *result);
+
+ if (count == 1) {
+ return NT_STATUS_OK;
+ }
+
+ ldap_msgfree(*result);
+ *result = NULL;
+
+ if (count < 1) {
+
+ DEBUG(3, ("smbldap_search_domain_info: Got no domain info entries for domain\n"));
+
+ if (!try_add)
+ goto failed;
+
+ status = add_new_domain_info(ldap_state, domain_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbldap_search_domain_info: Adding domain info for %s failed with %s\n",
+ domain_name, nt_errstr(status)));
+ goto failed;
+ }
+
+ status = add_new_domain_account_policies(ldap_state, domain_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbldap_search_domain_info: Adding domain account policies for %s failed with %s\n",
+ domain_name, nt_errstr(status)));
+ goto failed;
+ }
+
+ return smbldap_search_domain_info(ldap_state, result, domain_name, False);
+
+ }
+
+ if (count > 1 ) {
+
+ DEBUG(0, ("smbldap_search_domain_info: Got too many (%d) domain info entries for domain %s\n",
+ count, domain_name));
+ goto failed;
+ }
+
+failed:
+ return status;
+}
diff --git a/source3/passdb/pdb_ldap_util.h b/source3/passdb/pdb_ldap_util.h
new file mode 100644
index 0000000..7e8967c
--- /dev/null
+++ b/source3/passdb/pdb_ldap_util.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Gerald Carter 2001-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _PASSDB_PDB_LDAP_UTIL_H_
+#define _PASSDB_PDB_LDAP_UTIL_H_
+
+/* The following definitions come from passdb/pdb_ldap_util.c */
+
+#ifdef HAVE_LDAP
+NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
+ LDAPMessage ** result, const char *domain_name,
+ bool try_add);
+#endif /* HAVE_LDAP */
+
+#endif /* _PASSDB_PDB_LDAP_UTIL_H_ */
diff --git a/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c
new file mode 100644
index 0000000..fc0d19b
--- /dev/null
+++ b/source3/passdb/pdb_nds.c
@@ -0,0 +1,908 @@
+/*
+ Unix SMB/CIFS Implementation.
+ NDS LDAP helper functions for SAMBA
+ Copyright (C) Vince Brimhall 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "passdb.h"
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "smbldap.h"
+#include "passdb/pdb_ldap.h"
+#include "passdb/pdb_nds.h"
+
+#define NMASLDAP_GET_LOGIN_CONFIG_REQUEST "2.16.840.1.113719.1.39.42.100.3"
+#define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE "2.16.840.1.113719.1.39.42.100.4"
+#define NMASLDAP_SET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.11"
+#define NMASLDAP_SET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.12"
+#define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
+#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
+
+#define NMAS_LDAP_EXT_VERSION 1
+
+/**********************************************************************
+ Take the request BER value and input data items and BER encodes the
+ data into the BER value
+**********************************************************************/
+
+static int berEncodePasswordData(
+ struct berval **requestBV,
+ const char *objectDN,
+ const char *password,
+ const char *password2)
+{
+ int err = 0, rc=0;
+ BerElement *requestBer = NULL;
+
+ const char * utf8ObjPtr = NULL;
+ int utf8ObjSize = 0;
+ const char * utf8PwdPtr = NULL;
+ int utf8PwdSize = 0;
+ const char * utf8Pwd2Ptr = NULL;
+ int utf8Pwd2Size = 0;
+
+
+ /* Convert objectDN and tag strings from Unicode to UTF-8 */
+ utf8ObjSize = strlen(objectDN)+1;
+ utf8ObjPtr = objectDN;
+
+ if (password != NULL)
+ {
+ utf8PwdSize = strlen(password)+1;
+ utf8PwdPtr = password;
+ }
+
+ if (password2 != NULL)
+ {
+ utf8Pwd2Size = strlen(password2)+1;
+ utf8Pwd2Ptr = password2;
+ }
+
+ /* Allocate a BerElement for the request parameters. */
+ if((requestBer = ber_alloc()) == NULL)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+ if (password != NULL && password2 != NULL)
+ {
+ /* BER encode the NMAS Version, the objectDN, and the password */
+ rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size);
+ }
+ else if (password != NULL)
+ {
+ /* BER encode the NMAS Version, the objectDN, and the password */
+ rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize);
+ }
+ else
+ {
+ /* BER encode the NMAS Version and the objectDN */
+ rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
+ }
+
+ if (rc < 0)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+ else
+ {
+ err = 0;
+ }
+
+ /* Convert the BER we just built to a berval that we'll send with the extended request. */
+ if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(requestBer)
+ {
+ ber_free(requestBer, 1);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Take the request BER value and input data items and BER encodes the
+ data into the BER value
+**********************************************************************/
+
+static int berEncodeLoginData(
+ struct berval **requestBV,
+ char *objectDN,
+ unsigned int methodIDLen,
+ unsigned int *methodID,
+ char *tag,
+ size_t putDataLen,
+ void *putData)
+{
+ int err = 0;
+ BerElement *requestBer = NULL;
+
+ unsigned int i;
+ unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
+
+ char *utf8ObjPtr=NULL;
+ int utf8ObjSize = 0;
+
+ char *utf8TagPtr = NULL;
+ int utf8TagSize = 0;
+
+ utf8ObjPtr = objectDN;
+ utf8ObjSize = strlen(utf8ObjPtr)+1;
+
+ utf8TagPtr = tag;
+ utf8TagSize = strlen(utf8TagPtr)+1;
+
+ /* Allocate a BerElement for the request parameters. */
+ if((requestBer = ber_alloc()) == NULL)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+ /* BER encode the NMAS Version and the objectDN */
+ err = (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) ? LDAP_ENCODING_ERROR : 0;
+
+ /* BER encode the MethodID Length and value */
+ if (!err)
+ {
+ err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ for (i = 0; !err && i < elemCnt; i++)
+ {
+ err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ if (!err)
+ {
+ err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0;
+ }
+
+ if (!err) {
+ if (putData) {
+ /* BER Encode the tag and data */
+ err = (ber_printf(requestBer, "oio}", utf8TagPtr,
+ utf8TagSize, putDataLen, putData,
+ putDataLen) < 0)
+ ? LDAP_ENCODING_ERROR : 0;
+ } else {
+ /* BER Encode the tag */
+ err = (ber_printf(requestBer, "o}", utf8TagPtr,
+ utf8TagSize) < 0)
+ ? LDAP_ENCODING_ERROR : 0;
+ }
+ }
+
+ if (err)
+ {
+ goto Cleanup;
+ }
+
+ /* Convert the BER we just built to a berval that we'll send with the extended request. */
+ if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
+ {
+ err = LDAP_ENCODING_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(requestBer)
+ {
+ ber_free(requestBer, 1);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Takes the reply BER Value and decodes the NMAS server version and
+ return code and if a non null retData buffer was supplied, tries to
+ decode the return data and length
+**********************************************************************/
+
+static int berDecodeLoginData(
+ struct berval *replyBV,
+ int *serverVersion,
+ size_t *retDataLen,
+ void *retData )
+{
+ int err = 0;
+ BerElement *replyBer = NULL;
+ char *retOctStr = NULL;
+ size_t retOctStrLen = 0;
+
+ if((replyBer = ber_init(replyBV)) == NULL)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if(retData)
+ {
+ retOctStrLen = *retDataLen + 1;
+ retOctStr = SMB_MALLOC_ARRAY(char, retOctStrLen);
+ if(!retOctStr)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if(ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != -1)
+ {
+ if (*retDataLen >= retOctStrLen)
+ {
+ memcpy(retData, retOctStr, retOctStrLen);
+ }
+ else if (!err)
+ {
+ err = LDAP_NO_MEMORY;
+ }
+
+ *retDataLen = retOctStrLen;
+ }
+ else if (!err)
+ {
+ err = LDAP_DECODING_ERROR;
+ }
+ }
+ else
+ {
+ if(ber_scanf(replyBer, "{ii}", serverVersion, &err) == -1)
+ {
+ if (!err)
+ {
+ err = LDAP_DECODING_ERROR;
+ }
+ }
+ }
+
+Cleanup:
+
+ if(replyBer)
+ {
+ ber_free(replyBer, 1);
+ }
+
+ if (retOctStr != NULL)
+ {
+ memset(retOctStr, 0, retOctStrLen);
+ free(retOctStr);
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ Retrieves data in the login configuration of the specified object
+ that is tagged with the specified methodID and tag.
+**********************************************************************/
+
+static int getLoginConfig(
+ LDAP *ld,
+ char *objectDN,
+ unsigned int methodIDLen,
+ unsigned int *methodID,
+ char *tag,
+ size_t *dataLen,
+ void *data )
+{
+ int err = 0;
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion = 0;
+
+ /* Validate unicode parameters. */
+ if((strlen(objectDN) == 0) || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST,
+ requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Attempts to get the Simple Password
+**********************************************************************/
+
+static int nmasldap_get_simple_pwd(
+ LDAP *ld,
+ char *objectDN,
+ size_t pwdLen,
+ char *pwd )
+{
+ int err = 0;
+ unsigned int methodID = 0;
+ unsigned int methodIDLen = sizeof(methodID);
+ char tag[] = {'P','A','S','S','W','O','R','D',' ','H','A','S','H',0};
+ char *pwdBuf=NULL;
+ size_t pwdBufLen, bufferLen;
+
+ bufferLen = pwdBufLen = pwdLen+2;
+ pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
+ if(pwdBuf == NULL)
+ {
+ return LDAP_NO_MEMORY;
+ }
+
+ err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf);
+ if (err == 0)
+ {
+ if (pwdBufLen !=0)
+ {
+ pwdBuf[pwdBufLen] = 0; /* null terminate */
+
+ switch (pwdBuf[0])
+ {
+ case 1: /* cleartext password */
+ break;
+ case 2: /* SHA1 HASH */
+ case 3: /* MD5_ID */
+ case 4: /* UNIXCrypt_ID */
+ case 8: /* SSHA_ID */
+ default: /* Unknown digest */
+ err = LDAP_INAPPROPRIATE_AUTH; /* only return clear text */
+ break;
+ }
+
+ if (!err)
+ {
+ if (pwdLen >= pwdBufLen-1)
+ {
+ memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */
+ }
+ else
+ {
+ err = LDAP_NO_MEMORY;
+ }
+ }
+ }
+ }
+
+ if (pwdBuf != NULL)
+ {
+ memset(pwdBuf, 0, bufferLen);
+ free(pwdBuf);
+ }
+
+ return err;
+}
+
+
+/**********************************************************************
+ Attempts to set the Universal Password
+**********************************************************************/
+
+static int nmasldap_set_password(
+ LDAP *ld,
+ const char *objectDN,
+ const char *pwd )
+{
+ int err = 0;
+
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion;
+
+ /* Validate char parameters. */
+ if(objectDN == NULL || (strlen(objectDN) == 0) || pwd == NULL || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ err = berEncodePasswordData(&requestBV, objectDN, pwd, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_SET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_SET_PASSWORD_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, NULL, NULL);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Attempts to get the Universal Password
+**********************************************************************/
+
+static int nmasldap_get_password(
+ LDAP *ld,
+ char *objectDN,
+ size_t *pwdSize, /* in bytes */
+ unsigned char *pwd )
+{
+ int err = 0;
+
+ struct berval *requestBV = NULL;
+ char *replyOID = NULL;
+ struct berval *replyBV = NULL;
+ int serverVersion;
+ char *pwdBuf;
+ size_t pwdBufLen, bufferLen;
+
+ /* Validate char parameters. */
+ if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
+ {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ bufferLen = pwdBufLen = *pwdSize;
+ pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen+2);
+ if(pwdBuf == NULL)
+ {
+ return LDAP_NO_MEMORY;
+ }
+
+ err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
+ if(err)
+ {
+ goto Cleanup;
+ }
+
+ /* Call the ldap_extended_operation (synchronously) */
+ if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
+ {
+ goto Cleanup;
+ }
+
+ /* Make sure there is a return OID */
+ if(!replyOID)
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
+ {
+ err = LDAP_NOT_SUPPORTED;
+ goto Cleanup;
+ }
+
+ /* Do we have a good returned berval? */
+ if(!replyBV)
+ {
+ /* No; returned berval means we experienced a rather drastic error. */
+ /* Return operations error. */
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
+
+ if(serverVersion != NMAS_LDAP_EXT_VERSION)
+ {
+ err = LDAP_OPERATIONS_ERROR;
+ goto Cleanup;
+ }
+
+ if (!err && pwdBufLen != 0)
+ {
+ if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
+ {
+ memcpy(pwd, pwdBuf, pwdBufLen);
+ pwd[pwdBufLen] = 0; /* add null termination */
+ }
+ *pwdSize = pwdBufLen; /* does not include null termination */
+ }
+
+Cleanup:
+
+ if(replyBV)
+ {
+ ber_bvfree(replyBV);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if(replyOID)
+ {
+ ldap_memfree(replyOID);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if(requestBV)
+ {
+ ber_bvfree(requestBV);
+ }
+
+ if (pwdBuf != NULL)
+ {
+ memset(pwdBuf, 0, bufferLen);
+ free(pwdBuf);
+ }
+
+ /* Return the appropriate error/success code. */
+ return err;
+}
+
+/**********************************************************************
+ Get the user's password from NDS.
+ *********************************************************************/
+
+int pdb_nds_get_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ size_t *pwd_len,
+ char *pwd )
+{
+ LDAP *ld = smbldap_get_ldap(ldap_state);
+ int rc = -1;
+
+ rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)pwd);
+ if (rc == LDAP_SUCCESS) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd, object_dn));
+#endif
+ DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn));
+ } else {
+ DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn));
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ rc = nmasldap_get_simple_pwd(ld, object_dn, *pwd_len, pwd);
+ if (rc == LDAP_SUCCESS) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd, object_dn));
+#endif
+ DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn));
+ } else {
+ /* We couldn't get the password */
+ DEBUG(3, ("NDS Simple Password NOT retrieved for %s\n", object_dn));
+ return LDAP_INVALID_CREDENTIALS;
+ }
+ }
+
+ /* We got the password */
+ return LDAP_SUCCESS;
+}
+
+/**********************************************************************
+ Set the users NDS, Universal and Simple passwords.
+ ********************************************************************/
+
+int pdb_nds_set_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ const char *pwd )
+{
+ LDAP *ld = smbldap_get_ldap(ldap_state);
+ int rc = -1;
+ LDAPMod **tmpmods = NULL;
+
+ rc = nmasldap_set_password(ld, object_dn, pwd);
+ if (rc == LDAP_SUCCESS) {
+ DEBUG(5,("NDS Universal Password changed for user %s\n", object_dn));
+ } else {
+ char *ld_error = NULL;
+ ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
+
+ /* This will fail if Universal Password is not enabled for the user's context */
+ DEBUG(3,("NDS Universal Password could not be changed for user %s: %s (%s)\n",
+ object_dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ }
+
+ /* Set eDirectory Password */
+ smbldap_set_mod(&tmpmods, LDAP_MOD_REPLACE, "userPassword", pwd);
+ rc = smbldap_modify(ldap_state, object_dn, tmpmods);
+
+ return rc;
+}
+
+/**********************************************************************
+ Allow ldap server to update internal login attempt counters by
+ performing a simple bind. If the samba authentication failed attempt
+ the bind with a bogus, randomly generated password to count the
+ failed attempt. If the bind fails even though samba authentication
+ succeeded, this would indicate that the user's account is disabled,
+ time restrictions are in place or some other password policy
+ violation.
+*********************************************************************/
+
+static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods,
+ struct samu *sam_acct, bool success)
+{
+ struct ldapsam_privates *ldap_state;
+
+ if ((!methods) || (!sam_acct)) {
+ DEBUG(3,("pdb_nds_update_login_attempts: invalid parameter.\n"));
+ return NT_STATUS_MEMORY_NOT_ALLOCATED;
+ }
+
+ ldap_state = (struct ldapsam_privates *)methods->private_data;
+
+ if (ldap_state) {
+ /* Attempt simple bind with user credentials to update eDirectory
+ password policy */
+ int rc = 0;
+ char *dn;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ const char **attr_list;
+ size_t pwd_len;
+ char clear_text_pw[512];
+ LDAP *ld = NULL;
+ const char *username = pdb_get_username(sam_acct);
+ bool got_clear_text_pw = False;
+
+ DEBUG(5,("pdb_nds_update_login_attempts: %s login for %s\n",
+ success ? "Successful" : "Failed", username));
+
+ result = (LDAPMessage *)pdb_get_backend_private_data(sam_acct, methods);
+ if (!result) {
+ attr_list = get_userattr_list(NULL,
+ ldap_state->schema_ver);
+ rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list );
+ TALLOC_FREE( attr_list );
+ if (rc != LDAP_SUCCESS) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ pdb_set_backend_private_data(sam_acct, result, NULL,
+ methods, PDB_CHANGED);
+ smbldap_talloc_autofree_ldapmsg(sam_acct, result);
+ }
+
+ if (ldap_count_entries(
+ smbldap_get_ldap(ldap_state->smbldap_state),
+ result) == 0) {
+ DEBUG(0, ("pdb_nds_update_login_attempts: No user to modify!\n"));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ entry = ldap_first_entry(
+ smbldap_get_ldap(ldap_state->smbldap_state), result);
+ dn = smbldap_talloc_dn(talloc_tos(),
+ smbldap_get_ldap(
+ ldap_state->smbldap_state),
+ entry);
+ if (!dn) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(3, ("pdb_nds_update_login_attempts: username %s found dn '%s'\n", username, dn));
+
+ pwd_len = sizeof(clear_text_pw);
+ if (success == True) {
+ if (pdb_nds_get_password(ldap_state->smbldap_state, dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
+ /* Got clear text password. Use simple ldap bind */
+ got_clear_text_pw = True;
+ }
+ } else {
+ /* This is a long term key */
+ generate_secret_buffer((unsigned char *)clear_text_pw, 24);
+ clear_text_pw[24] = '\0';
+ DEBUG(5,("pdb_nds_update_login_attempts: using random password %s\n", clear_text_pw));
+ }
+
+ if((success != True) || (got_clear_text_pw == True)) {
+
+ rc = smbldap_setup_full_conn(&ld, ldap_state->location);
+ if (rc) {
+ TALLOC_FREE(dn);
+ return NT_STATUS_INVALID_CONNECTION;
+ }
+
+ /* Attempt simple bind with real or bogus password */
+ rc = ldap_simple_bind_s(ld, dn, clear_text_pw);
+ ldap_unbind(ld);
+ if (rc == LDAP_SUCCESS) {
+ DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username));
+ } else {
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
+ DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username));
+ switch(rc) {
+ case LDAP_INVALID_CREDENTIALS:
+ nt_status = NT_STATUS_WRONG_PASSWORD;
+ break;
+ case LDAP_UNWILLING_TO_PERFORM:
+ /* eDir returns this if the account was disabled. */
+ /* The problem is we don't know if the given
+ password was correct for this account or
+ not. We have to return more info than we
+ should and tell the client NT_STATUS_ACCOUNT_DISABLED
+ so they don't think the password was bad. JRA. */
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ break;
+ default:
+ break;
+ }
+ return nt_status;
+ }
+ }
+ TALLOC_FREE(dn);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Initialise the parts of the pdb_methods structure that are common
+ to NDS_ldapsam modes
+ *********************************************************************/
+
+static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)((*pdb_method)->private_data);
+
+ /* Mark this as eDirectory ldap */
+ ldap_state->is_nds_ldap = True;
+
+ /* Add pdb_nds specific method for updating login attempts. */
+ (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts;
+
+ /* Save location for use in pdb_nds_update_login_attempts */
+ ldap_state->location = SMB_STRDUP(location);
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Initialise the 'nds' normal mode for pdb_ldap
+ *********************************************************************/
+
+static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status = pdb_ldapsam_init_common(pdb_method, location);
+
+ (*pdb_method)->name = "NDS_ldapsam";
+
+ pdb_init_NDS_ldapsam_common(pdb_method, location);
+
+ return nt_status;
+}
+
+NTSTATUS pdb_nds_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS nt_status;
+ if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam)))
+ return nt_status;
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/pdb_nds.h b/source3/passdb/pdb_nds.h
new file mode 100644
index 0000000..ee71c78
--- /dev/null
+++ b/source3/passdb/pdb_nds.h
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/CIFS Implementation.
+ NDS LDAP helper functions for SAMBA
+ Copyright (C) Vince Brimhall 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _PASSDB_PDB_NDS_H_
+#define _PASSDB_PDB_NDS_H_
+
+/* The following definitions come from passdb/pdb_nds.c */
+
+struct smbldap_state;
+
+int pdb_nds_get_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ size_t *pwd_len,
+ char *pwd );
+int pdb_nds_set_password(
+ struct smbldap_state *ldap_state,
+ char *object_dn,
+ const char *pwd );
+NTSTATUS pdb_nds_init(TALLOC_CTX *);
+
+#endif /* _PASSDB_PDB_NDS_H_ */
diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c
new file mode 100644
index 0000000..ef90ab7
--- /dev/null
+++ b/source3/passdb/pdb_samba_dsdb.c
@@ -0,0 +1,3895 @@
+/*
+ Unix SMB/CIFS implementation.
+ pdb glue module for direct access to the dsdb via LDB APIs
+ Copyright (C) Volker Lendecke 2009-2011
+ Copyright (C) Andrew Bartlett 2010-2012
+ Copyright (C) Matthias Dieter Wallnöfer 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This module, is a port of Volker's pdb_ads to ldb and DSDB APIs */
+
+#include "includes.h"
+#include "source3/include/passdb.h"
+#include "source4/dsdb/samdb/samdb.h"
+#include "ldb_errors.h"
+#include "libcli/security/dom_sid.h"
+#include "source4/winbind/idmap.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "libds/common/flag_mapping.h"
+#include "source4/lib/events/events.h"
+#include "source4/auth/session.h"
+#include "source4/auth/system_session_proto.h"
+#include "lib/param/param.h"
+#include "source4/dsdb/common/util.h"
+#include "source3/include/secrets.h"
+#include "source4/auth/auth_sam.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/base64.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "lib/util/util_ldb.h"
+
+struct pdb_samba_dsdb_state {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+ struct idmap_context *idmap_ctx;
+ struct loadparm_context *lp_ctx;
+};
+
+static NTSTATUS pdb_samba_dsdb_getsampwsid(struct pdb_methods *m,
+ struct samu *sam_acct,
+ const struct dom_sid *sid);
+static NTSTATUS pdb_samba_dsdb_getsamupriv(struct pdb_samba_dsdb_state *state,
+ const char *filter,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message **pmsg);
+static bool pdb_samba_dsdb_sid_to_id(struct pdb_methods *m, const struct dom_sid *sid,
+ struct unixid *id);
+
+static bool pdb_samba_dsdb_pull_time(struct ldb_message *msg, const char *attr,
+ time_t *ptime)
+{
+ uint64_t tmp;
+ if (! ldb_msg_find_element(msg, attr)) {
+ return false;
+ }
+ tmp = ldb_msg_find_attr_as_uint64(msg, attr, 0);
+ *ptime = nt_time_to_unix(tmp);
+ return true;
+}
+
+static struct pdb_domain_info *pdb_samba_dsdb_get_domain_info(
+ struct pdb_methods *m, TALLOC_CTX *mem_ctx)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct pdb_domain_info *info;
+ struct dom_sid *domain_sid;
+ struct ldb_dn *forest_dn, *domain_dn;
+ struct ldb_result *dom_res = NULL;
+ const char *dom_attrs[] = {
+ "objectSid",
+ "objectGUID",
+ "fSMORoleOwner",
+ NULL
+ };
+ char *p;
+ int ret;
+
+ info = talloc(mem_ctx, struct pdb_domain_info);
+ if (info == NULL) {
+ return NULL;
+ }
+
+ domain_dn = ldb_get_default_basedn(state->ldb);
+
+ ret = ldb_search(state->ldb, info, &dom_res,
+ domain_dn, LDB_SCOPE_BASE, dom_attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto fail;
+ }
+ if (dom_res->count != 1) {
+ goto fail;
+ }
+
+ info->guid = samdb_result_guid(dom_res->msgs[0], "objectGUID");
+
+ domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid");
+ if (!domain_sid) {
+ goto fail;
+ }
+ info->sid = *domain_sid;
+
+ TALLOC_FREE(dom_res);
+
+ info->name = talloc_strdup(info, lpcfg_sam_name(state->lp_ctx));
+ info->dns_domain = ldb_dn_canonical_string(info, domain_dn);
+
+ if (!info->dns_domain) {
+ goto fail;
+ }
+ p = strchr(info->dns_domain, '/');
+ if (p) {
+ *p = '\0';
+ }
+
+ forest_dn = ldb_get_root_basedn(state->ldb);
+ if (!forest_dn) {
+ goto fail;
+ }
+
+ info->dns_forest = ldb_dn_canonical_string(info, forest_dn);
+ if (!info->dns_forest) {
+ goto fail;
+ }
+ p = strchr(info->dns_forest, '/');
+ if (p) {
+ *p = '\0';
+ }
+
+ return info;
+
+fail:
+ TALLOC_FREE(dom_res);
+ TALLOC_FREE(info);
+ return NULL;
+}
+
+static struct ldb_message *pdb_samba_dsdb_get_samu_private(
+ struct pdb_methods *m, struct samu *sam)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_message *msg;
+ struct dom_sid_buf sidstr;
+ char *filter;
+ NTSTATUS status;
+
+ msg = (struct ldb_message *)
+ pdb_get_backend_private_data(sam, m);
+
+ if (msg != NULL) {
+ return talloc_get_type_abort(msg, struct ldb_message);
+ }
+
+ filter = talloc_asprintf(
+ talloc_tos(),
+ "(&(objectsid=%s)(objectclass=user))",
+ dom_sid_str_buf(pdb_get_user_sid(sam), &sidstr));
+ if (filter == NULL) {
+ return NULL;
+ }
+
+ status = pdb_samba_dsdb_getsamupriv(state, filter, sam, &msg);
+ TALLOC_FREE(filter);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return msg;
+}
+
+static NTSTATUS pdb_samba_dsdb_init_sam_from_priv(struct pdb_methods *m,
+ struct samu *sam,
+ struct ldb_message *msg)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ const char *str;
+ time_t tmp_time;
+ struct dom_sid *sid, group_sid;
+ uint64_t n;
+ const DATA_BLOB *blob;
+
+ str = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
+ if (str == NULL) {
+ DEBUG(10, ("no samAccountName\n"));
+ goto fail;
+ }
+ pdb_set_username(sam, str, PDB_SET);
+
+ if (pdb_samba_dsdb_pull_time(msg, "lastLogon", &tmp_time)) {
+ pdb_set_logon_time(sam, tmp_time, PDB_SET);
+ }
+ if (pdb_samba_dsdb_pull_time(msg, "lastLogoff", &tmp_time)) {
+ pdb_set_logoff_time(sam, tmp_time, PDB_SET);
+ }
+ if (pdb_samba_dsdb_pull_time(msg, "pwdLastSet", &tmp_time)) {
+ pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET);
+ }
+ if (pdb_samba_dsdb_pull_time(msg, "accountExpires", &tmp_time)) {
+ pdb_set_kickoff_time(sam, tmp_time, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "displayName",
+ NULL);
+ if (str != NULL) {
+ pdb_set_fullname(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "homeDirectory",
+ NULL);
+ if (str != NULL) {
+ pdb_set_homedir(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "homeDrive", NULL);
+ if (str != NULL) {
+ pdb_set_dir_drive(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "scriptPath", NULL);
+ if (str != NULL) {
+ pdb_set_logon_script(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "profilePath",
+ NULL);
+ if (str != NULL) {
+ pdb_set_profile_path(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "comment",
+ NULL);
+ if (str != NULL) {
+ pdb_set_comment(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "description",
+ NULL);
+ if (str != NULL) {
+ pdb_set_acct_desc(sam, str, PDB_SET);
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "userWorkstations",
+ NULL);
+ if (str != NULL) {
+ pdb_set_workstations(sam, str, PDB_SET);
+ }
+
+ blob = ldb_msg_find_ldb_val(msg, "userParameters");
+ if (blob != NULL) {
+ str = base64_encode_data_blob(frame, *blob);
+ if (str == NULL) {
+ DEBUG(0, ("base64_encode_data_blob() failed\n"));
+ goto fail;
+ }
+ pdb_set_munged_dial(sam, str, PDB_SET);
+ }
+
+ sid = samdb_result_dom_sid(talloc_tos(), msg, "objectSid");
+ if (!sid) {
+ DEBUG(10, ("Could not pull SID\n"));
+ goto fail;
+ }
+ pdb_set_user_sid(sam, sid, PDB_SET);
+
+ n = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
+ if (n == 0) {
+ DEBUG(10, ("Could not pull userAccountControl\n"));
+ goto fail;
+ }
+ pdb_set_acct_ctrl(sam, n, PDB_SET);
+
+ blob = ldb_msg_find_ldb_val(msg, "unicodePwd");
+ if (blob) {
+ if (blob->length != NT_HASH_LEN) {
+ DEBUG(0, ("Got NT hash of length %d, expected %d\n",
+ (int)blob->length, NT_HASH_LEN));
+ goto fail;
+ }
+ pdb_set_nt_passwd(sam, blob->data, PDB_SET);
+ }
+
+ blob = ldb_msg_find_ldb_val(msg, "dBCSPwd");
+ if (blob) {
+ if (blob->length != LM_HASH_LEN) {
+ DEBUG(0, ("Got LM hash of length %d, expected %d\n",
+ (int)blob->length, LM_HASH_LEN));
+ goto fail;
+ }
+ pdb_set_lanman_passwd(sam, blob->data, PDB_SET);
+ }
+
+ n = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", 0);
+ if (n == 0) {
+ DEBUG(10, ("Could not pull primaryGroupID\n"));
+ goto fail;
+ }
+ sid_compose(&group_sid, samdb_domain_sid(state->ldb), n);
+ pdb_set_group_sid(sam, &group_sid, PDB_SET);
+
+ status = NT_STATUS_OK;
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+static bool pdb_samba_dsdb_add_time(struct ldb_message *msg,
+ const char *attrib, time_t t)
+{
+ uint64_t nt_time;
+
+ unix_to_nt_time(&nt_time, t);
+
+ return ldb_msg_add_fmt(msg, attrib, "%llu", (unsigned long long) nt_time);
+}
+
+static int pdb_samba_dsdb_replace_by_sam(struct pdb_samba_dsdb_state *state,
+ bool (*need_update)(const struct samu *,
+ enum pdb_elements),
+ struct ldb_dn *dn,
+ struct samu *sam)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int ret = LDB_SUCCESS;
+ const char *pw;
+ struct ldb_message *msg;
+ struct ldb_request *req;
+ uint32_t dsdb_flags = 0;
+ /* TODO: All fields :-) */
+
+ msg = ldb_msg_new(frame);
+ if (!msg) {
+ talloc_free(frame);
+ return false;
+ }
+
+ msg->dn = dn;
+
+ /* build modify request */
+ ret = ldb_build_mod_req(&req, state->ldb, frame, msg, NULL, NULL,
+ ldb_op_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(frame);
+ return ret;
+ }
+
+ /* If we set a plaintext password, the system will
+ * force the pwdLastSet to now() */
+ if (need_update(sam, PDB_PASSLASTSET)) {
+ dsdb_flags |= DSDB_PASSWORD_BYPASS_LAST_SET;
+
+ ret |= pdb_samba_dsdb_add_time(msg, "pwdLastSet",
+ pdb_get_pass_last_set_time(sam));
+ }
+
+ pw = pdb_get_plaintext_passwd(sam);
+ if (need_update(sam, PDB_PLAINTEXT_PW)) {
+ struct ldb_val pw_utf16;
+ if (pw == NULL) {
+ talloc_free(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!convert_string_talloc(msg,
+ CH_UNIX, CH_UTF16,
+ pw, strlen(pw),
+ (void *)&pw_utf16.data,
+ &pw_utf16.length)) {
+ talloc_free(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret |= ldb_msg_add_value(msg, "clearTextPassword", &pw_utf16, NULL);
+ } else {
+ bool changed_lm_pw = false;
+ bool changed_nt_pw = false;
+ bool changed_history = false;
+ if (need_update(sam, PDB_LMPASSWD)) {
+ struct ldb_val val;
+ val.data = discard_const_p(uint8_t, pdb_get_lanman_passwd(sam));
+ if (!val.data) {
+ samdb_msg_add_delete(state->ldb, msg, msg,
+ "dBCSPwd");
+ } else {
+ val.length = LM_HASH_LEN;
+ ret |= ldb_msg_add_value(msg, "dBCSPwd", &val, NULL);
+ }
+ changed_lm_pw = true;
+ }
+ if (need_update(sam, PDB_NTPASSWD)) {
+ struct ldb_val val;
+ val.data = discard_const_p(uint8_t, pdb_get_nt_passwd(sam));
+ if (!val.data) {
+ samdb_msg_add_delete(state->ldb, msg, msg,
+ "unicodePwd");
+ } else {
+ val.length = NT_HASH_LEN;
+ ret |= ldb_msg_add_value(msg, "unicodePwd", &val, NULL);
+ }
+ changed_nt_pw = true;
+ }
+
+ /* Try to ensure we don't get out of sync */
+ if (changed_lm_pw && !changed_nt_pw) {
+ samdb_msg_add_delete(state->ldb, msg, msg,
+ "unicodePwd");
+ } else if (changed_nt_pw && !changed_lm_pw) {
+ samdb_msg_add_delete(state->ldb, msg, msg,
+ "dBCSPwd");
+ }
+ if (changed_lm_pw || changed_nt_pw) {
+ samdb_msg_add_delete(state->ldb, msg, msg,
+ "supplementalCredentials");
+
+ }
+
+ if (need_update(sam, PDB_PWHISTORY)) {
+ uint32_t current_hist_len;
+ const uint8_t *history = pdb_get_pw_history(sam, &current_hist_len);
+
+ bool invalid_history = false;
+ struct samr_Password *history_hashes = talloc_array(talloc_tos(), struct samr_Password,
+ current_hist_len);
+ if (!history) {
+ invalid_history = true;
+ } else {
+ unsigned int i;
+ /* Parse the history into the correct format */
+ for (i = 0; i < current_hist_len; i++) {
+ if (!all_zero(&history[i*PW_HISTORY_ENTRY_LEN],
+ 16)) {
+ /* If the history is in the old format, with a salted hash, then we can't migrate it to AD format */
+ invalid_history = true;
+ break;
+ }
+ /* Copy out the 2nd 16 bytes of the 32 byte password history, containing the NT hash */
+ memcpy(history_hashes[i].hash,
+ &history[(i*PW_HISTORY_ENTRY_LEN) + PW_HISTORY_SALT_LEN],
+ sizeof(history_hashes[i].hash));
+ }
+ }
+ if (invalid_history) {
+ ret |= samdb_msg_add_delete(state->ldb, msg, msg,
+ "ntPwdHistory");
+
+ ret |= samdb_msg_add_delete(state->ldb, msg, msg,
+ "lmPwdHistory");
+ } else {
+ ret |= samdb_msg_add_hashes(state->ldb, msg, msg,
+ "ntPwdHistory",
+ history_hashes,
+ current_hist_len);
+ }
+ changed_history = true;
+ }
+ if (changed_lm_pw || changed_nt_pw || changed_history) {
+ /* These attributes can only be modified directly by using a special control */
+ dsdb_flags |= DSDB_BYPASS_PASSWORD_HASH;
+ }
+ }
+
+ /* PDB_USERSID is only allowed on ADD, handled in caller */
+ if (need_update(sam, PDB_GROUPSID)) {
+ const struct dom_sid *sid = pdb_get_group_sid(sam);
+ uint32_t rid;
+ NTSTATUS status = dom_sid_split_rid(NULL, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (!dom_sid_in_domain(samdb_domain_sid(state->ldb), sid)) {
+ talloc_free(frame);
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ ret |= samdb_msg_add_uint(state->ldb, msg, msg, "primaryGroupID", rid);
+ }
+ if (need_update(sam, PDB_FULLNAME)) {
+ ret |= ldb_msg_add_string(msg, "displayName", pdb_get_fullname(sam));
+ }
+
+ if (need_update(sam, PDB_SMBHOME)) {
+ ret |= ldb_msg_add_string(msg, "homeDirectory",
+ pdb_get_homedir(sam));
+ }
+
+ if (need_update(sam, PDB_PROFILE)) {
+ ret |= ldb_msg_add_string(msg, "profilePath",
+ pdb_get_profile_path(sam));
+ }
+
+ if (need_update(sam, PDB_DRIVE)) {
+ ret |= ldb_msg_add_string(msg, "homeDrive",
+ pdb_get_dir_drive(sam));
+ }
+
+ if (need_update(sam, PDB_LOGONSCRIPT)) {
+ ret |= ldb_msg_add_string(msg, "scriptPath",
+ pdb_get_logon_script(sam));
+ }
+
+ if (need_update(sam, PDB_KICKOFFTIME)) {
+ ret |= pdb_samba_dsdb_add_time(msg, "accountExpires",
+ pdb_get_kickoff_time(sam));
+ }
+
+ if (need_update(sam, PDB_LOGONTIME)) {
+ ret |= pdb_samba_dsdb_add_time(msg, "lastLogon",
+ pdb_get_logon_time(sam));
+ }
+
+ if (need_update(sam, PDB_LOGOFFTIME)) {
+ ret |= pdb_samba_dsdb_add_time(msg, "lastLogoff",
+ pdb_get_logoff_time(sam));
+ }
+
+ if (need_update(sam, PDB_USERNAME)) {
+ ret |= ldb_msg_add_string(msg, "samAccountName",
+ pdb_get_username(sam));
+ }
+
+ if (need_update(sam, PDB_HOURSLEN) || need_update(sam, PDB_HOURS)) {
+ struct ldb_val hours = data_blob_const(pdb_get_hours(sam), pdb_get_hours_len(sam));
+ ret |= ldb_msg_add_value(msg, "logonHours",
+ &hours, NULL);
+ }
+
+ if (need_update(sam, PDB_ACCTCTRL)) {
+ ret |= samdb_msg_add_acct_flags(state->ldb, msg, msg,
+ "userAccountControl", pdb_get_acct_ctrl(sam));
+ }
+
+ if (need_update(sam, PDB_COMMENT)) {
+ ret |= ldb_msg_add_string(msg, "comment",
+ pdb_get_comment(sam));
+ }
+
+ if (need_update(sam, PDB_ACCTDESC)) {
+ ret |= ldb_msg_add_string(msg, "description",
+ pdb_get_acct_desc(sam));
+ }
+
+ if (need_update(sam, PDB_WORKSTATIONS)) {
+ ret |= ldb_msg_add_string(msg, "userWorkstations",
+ pdb_get_workstations(sam));
+ }
+
+ /* This will need work, it is actually a UTF8 'string' with internal NULLs, to handle TS parameters */
+ if (need_update(sam, PDB_MUNGEDDIAL)) {
+ const char *base64_munged_dial = NULL;
+
+ base64_munged_dial = pdb_get_munged_dial(sam);
+ if (base64_munged_dial != NULL && strlen(base64_munged_dial) > 0) {
+ struct ldb_val blob;
+
+ blob = base64_decode_data_blob_talloc(msg,
+ base64_munged_dial);
+ if (blob.data == NULL) {
+ DEBUG(0, ("Failed to decode userParameters from "
+ "munged dialback string[%s] for %s\n",
+ base64_munged_dial,
+ ldb_dn_get_linearized(msg->dn)));
+ talloc_free(frame);
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ ret |= ldb_msg_add_steal_value(msg, "userParameters",
+ &blob);
+ }
+ }
+
+ if (need_update(sam, PDB_COUNTRY_CODE)) {
+ ret |= ldb_msg_add_fmt(msg, "countryCode",
+ "%i", (int)pdb_get_country_code(sam));
+ }
+
+ if (need_update(sam, PDB_CODE_PAGE)) {
+ ret |= ldb_msg_add_fmt(msg, "codePage",
+ "%i", (int)pdb_get_code_page(sam));
+ }
+
+ /* Not yet handled here or not meaningful for modifies on a Samba_Dsdb backend:
+ PDB_BAD_PASSWORD_TIME,
+ PDB_CANCHANGETIME, - these are calculated per policy, not stored
+ PDB_DOMAIN,
+ PDB_NTUSERNAME, - this makes no sense, and never really did
+ PDB_LOGONDIVS,
+ PDB_USERSID, - Handled in pdb_samba_dsdb_add_sam_account()
+ PDB_FIELDS_PRESENT,
+ PDB_BAD_PASSWORD_COUNT,
+ PDB_LOGON_COUNT,
+ PDB_UNKNOWN6,
+ PDB_BACKEND_PRIVATE_DATA,
+
+ */
+ if (ret != LDB_SUCCESS) {
+ talloc_free(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (msg->num_elements == 0) {
+ talloc_free(frame);
+ /* Nothing to do, just return success */
+ return LDB_SUCCESS;
+ }
+
+ ret = dsdb_replace(state->ldb, msg, dsdb_flags);
+
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to modify account record %s to set user attributes: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(state->ldb)));
+ }
+
+ talloc_free(frame);
+ return ret;
+}
+
+static NTSTATUS pdb_samba_dsdb_getsamupriv(struct pdb_samba_dsdb_state *state,
+ const char *filter,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message **msg)
+{
+ const char * attrs[] = {
+ "lastLogon", "lastLogoff", "pwdLastSet", "accountExpires",
+ "sAMAccountName", "displayName", "homeDirectory",
+ "homeDrive", "scriptPath", "profilePath", "description",
+ "userWorkstations", "comment", "userParameters", "objectSid",
+ "primaryGroupID", "userAccountControl",
+ "msDS-User-Account-Control-Computed", "logonHours",
+ "badPwdCount", "logonCount", "countryCode", "codePage",
+ "unicodePwd", "dBCSPwd", NULL };
+
+ int rc = dsdb_search_one(state->ldb, mem_ctx, msg, ldb_get_default_basedn(state->ldb), LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
+ if (rc != LDB_SUCCESS) {
+ DEBUG(10, ("ldap_search failed %s\n",
+ ldb_errstring(state->ldb)));
+ return NT_STATUS_LDAP(rc);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_getsampwfilter(struct pdb_methods *m,
+ struct pdb_samba_dsdb_state *state,
+ struct samu *sam_acct,
+ const char *exp_fmt, ...)
+ PRINTF_ATTRIBUTE(4,5);
+
+static NTSTATUS pdb_samba_dsdb_getsampwfilter(struct pdb_methods *m,
+ struct pdb_samba_dsdb_state *state,
+ struct samu *sam_acct,
+ const char *exp_fmt, ...)
+{
+ struct ldb_message *priv;
+ NTSTATUS status;
+ va_list ap;
+ char *expression = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(state);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = pdb_samba_dsdb_getsamupriv(state, expression, sam_acct, &priv);
+ talloc_free(tmp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_samba_dsdb_getsamupriv failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = pdb_samba_dsdb_init_sam_from_priv(m, sam_acct, priv);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_samba_dsdb_init_sam_from_priv failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(priv);
+ return status;
+ }
+
+ pdb_set_backend_private_data(sam_acct, priv, NULL, m, PDB_SET);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_getsampwnam(struct pdb_methods *m,
+ struct samu *sam_acct,
+ const char *username)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+
+ return pdb_samba_dsdb_getsampwfilter(m, state, sam_acct,
+ "(&(samaccountname=%s)(objectclass=user))",
+ username);
+}
+
+static NTSTATUS pdb_samba_dsdb_getsampwsid(struct pdb_methods *m,
+ struct samu *sam_acct,
+ const struct dom_sid *sid)
+{
+ NTSTATUS status;
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct dom_sid_buf buf;
+
+ status = pdb_samba_dsdb_getsampwfilter(m, state, sam_acct,
+ "(&(objectsid=%s)(objectclass=user))",
+ dom_sid_str_buf(sid, &buf));
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_create_user(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ const char *name, uint32_t acct_flags,
+ uint32_t *rid)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct dom_sid *sid;
+ struct ldb_dn *dn;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ /* Internally this uses transactions to ensure all the steps
+ * happen or fail as one */
+ status = dsdb_add_user(state->ldb, tmp_ctx, name, acct_flags, NULL,
+ &sid, &dn);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ sid_peek_rid(sid, rid);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_delete_user(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ struct samu *sam)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_dn *dn;
+ int rc;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ dn = ldb_dn_new_fmt(
+ tmp_ctx,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(pdb_get_user_sid(sam), &buf));
+ if (!dn || !ldb_dn_validate(dn)) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ rc = ldb_delete(state->ldb, dn);
+
+ if (rc != LDB_SUCCESS) {
+ DEBUG(10, ("ldb_delete for %s failed: %s\n", ldb_dn_get_linearized(dn),
+ ldb_errstring(state->ldb)));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_LDAP(rc);
+ }
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/* This interface takes a fully populated struct samu and places it in
+ * the database. This is not implemented at this time as we need to
+ * be careful around the creation of arbitrary SIDs (ie, we must ensure
+ * they are not left in a RID pool */
+static NTSTATUS pdb_samba_dsdb_add_sam_account(struct pdb_methods *m,
+ struct samu *sampass)
+{
+ int ret;
+ NTSTATUS status;
+ struct ldb_dn *dn;
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ uint32_t acb_flags = pdb_get_acct_ctrl(sampass);
+ const char *username = pdb_get_username(sampass);
+ const struct dom_sid *user_sid = pdb_get_user_sid(sampass);
+ TALLOC_CTX *tframe = talloc_stackframe();
+
+ acb_flags &= (ACB_NORMAL|ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST);
+
+ ret = ldb_transaction_start(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tframe);
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+
+ status = dsdb_add_user(state->ldb, talloc_tos(), username,
+ acb_flags, user_sid, NULL, &dn);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_transaction_cancel(state->ldb);
+ talloc_free(tframe);
+ return status;
+ }
+
+ ret = pdb_samba_dsdb_replace_by_sam(state, pdb_element_is_set_or_changed,
+ dn, sampass);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(state->ldb);
+ talloc_free(tframe);
+ return dsdb_ldb_err_to_ntstatus(ret);
+ }
+
+ ret = ldb_transaction_commit(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
+ ldb_dn_get_linearized(dn),
+ ldb_errstring(state->ldb)));
+ talloc_free(tframe);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ talloc_free(tframe);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Update the Samba_Dsdb LDB with the changes from a struct samu.
+ *
+ * This takes care not to update elements that have not been changed
+ * by the caller
+ */
+static NTSTATUS pdb_samba_dsdb_update_sam_account(struct pdb_methods *m,
+ struct samu *sam)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_message *msg = pdb_samba_dsdb_get_samu_private(
+ m, sam);
+ int ret;
+
+ ret = pdb_samba_dsdb_replace_by_sam(state, pdb_element_is_changed, msg->dn,
+ sam);
+ return dsdb_ldb_err_to_ntstatus(ret);
+}
+
+static NTSTATUS pdb_samba_dsdb_delete_sam_account(struct pdb_methods *m,
+ struct samu *username)
+{
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+ status = pdb_samba_dsdb_delete_user(m, tmp_ctx, username);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_rename_sam_account(struct pdb_methods *m,
+ struct samu *oldname,
+ const char *newname)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/* This is not implemented, as this module is expected to be used
+ * with auth_samba_dsdb, and this is responsible for login counters etc
+ *
+ */
+static NTSTATUS pdb_samba_dsdb_update_login_attempts(struct pdb_methods *m,
+ struct samu *sam_acct,
+ bool success)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m,
+ GROUP_MAP *map,
+ const char *exp_fmt, ...)
+ PRINTF_ATTRIBUTE(3,4);
+
+static NTSTATUS pdb_samba_dsdb_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
+ const char *exp_fmt, ...)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ const char *attrs[] = { "objectClass", "objectSid", "description", "samAccountName", "groupType",
+ NULL };
+ struct ldb_message *msg;
+ va_list ap;
+ char *expression = NULL;
+ struct dom_sid *sid;
+ const char *str;
+ int rc;
+ struct id_map id_map;
+ struct id_map *id_maps[2];
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, ldb_get_default_basedn(state->ldb), LDB_SCOPE_SUBTREE, attrs, 0, "%s", expression);
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_SUCH_GROUP;
+ } else if (rc != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("dsdb_search_one failed %s\n",
+ ldb_errstring(state->ldb)));
+ return NT_STATUS_LDAP(rc);
+ }
+
+ sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
+ if (!sid) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("Could not pull SID\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ map->sid = *sid;
+
+ if (samdb_find_attribute(state->ldb, msg, "objectClass", "group")) {
+ NTSTATUS status;
+ uint32_t grouptype = ldb_msg_find_attr_as_uint(msg, "groupType", 0);
+ switch (grouptype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ map->sid_name_use = SID_NAME_ALIAS;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ map->sid_name_use = SID_NAME_DOM_GRP;
+ break;
+ default:
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("Could not pull groupType\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ ZERO_STRUCT(id_map);
+ id_map.sid = sid;
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
+ map->gid = id_map.xid.id;
+ } else {
+ DEBUG(1, (__location__ "Did not get GUID when mapping SID for %s\n", expression));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ } else if (samdb_find_attribute(state->ldb, msg, "objectClass", "user")) {
+ DEBUG(1, (__location__ "Got SID_NAME_USER when searching for a group with %s\n", expression));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "samAccountName",
+ NULL);
+ if (str == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ map->nt_name = talloc_strdup(map, str);
+ if (!map->nt_name) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "description",
+ NULL);
+ if (str != NULL) {
+ map->comment = talloc_strdup(map, str);
+ } else {
+ map->comment = talloc_strdup(map, "");
+ }
+ if (!map->comment) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_getgrsid(struct pdb_methods *m, GROUP_MAP *map,
+ struct dom_sid sid)
+{
+ char *filter;
+ NTSTATUS status;
+ struct dom_sid_buf buf;
+
+ filter = talloc_asprintf(talloc_tos(),
+ "(&(objectsid=%s)(objectclass=group))",
+ dom_sid_str_buf(&sid, &buf));
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = pdb_samba_dsdb_getgrfilter(m, map, "%s", filter);
+ TALLOC_FREE(filter);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_getgrgid(struct pdb_methods *m, GROUP_MAP *map,
+ gid_t gid)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ NTSTATUS status;
+ struct id_map id_map;
+ struct id_map *id_maps[2];
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ id_map.xid.id = gid;
+ id_map.xid.type = ID_TYPE_GID;
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ status = pdb_samba_dsdb_getgrsid(m, map, *id_map.sid);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_getgrnam(struct pdb_methods *m, GROUP_MAP *map,
+ const char *name)
+{
+ char *filter;
+ NTSTATUS status;
+
+ filter = talloc_asprintf(talloc_tos(),
+ "(&(samaccountname=%s)(objectclass=group))",
+ name);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = pdb_samba_dsdb_getgrfilter(m, map, "%s", filter);
+ TALLOC_FREE(filter);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_create_dom_group(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx, const char *name,
+ uint32_t *rid)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ NTSTATUS status;
+ struct dom_sid *sid;
+ struct ldb_dn *dn;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ status = dsdb_add_domain_group(state->ldb, tmp_ctx, name, &sid, &dn);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ sid_peek_rid(sid, rid);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_delete_dom_group(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx, uint32_t rid)
+{
+ const char *attrs[] = { NULL };
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct dom_sid sid;
+ struct ldb_message *msg;
+ struct ldb_dn *dn;
+ int rc;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ sid_compose(&sid, samdb_domain_sid(state->ldb), rid);
+
+ if (ldb_transaction_start(state->ldb) != LDB_SUCCESS) {
+ DEBUG(0, ("Unable to start transaction in pdb_samba_dsdb_delete_dom_group()\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ dn = ldb_dn_new_fmt(
+ tmp_ctx,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(&sid, &buf));
+ if (!dn || !ldb_dn_validate(dn)) {
+ talloc_free(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+ rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "objectclass=group");
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_NO_SUCH_GROUP;
+ } else if (rc != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("dsdb_search_one failed %s\n",
+ ldb_errstring(state->ldb)));
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_LDAP(rc);
+ }
+ rc = ldb_delete(state->ldb, dn);
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_NO_SUCH_GROUP;
+ } else if (rc != LDB_SUCCESS) {
+ DEBUG(10, ("ldb_delete failed %s\n",
+ ldb_errstring(state->ldb)));
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_LDAP(rc);
+ }
+
+ if (ldb_transaction_commit(state->ldb) != LDB_SUCCESS) {
+ DEBUG(0, ("Unable to commit transaction in pdb_samba_dsdb_delete_dom_group()\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_add_group_mapping_entry(struct pdb_methods *m,
+ GROUP_MAP *map)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_update_group_mapping_entry(struct pdb_methods *m,
+ GROUP_MAP *map)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_delete_group_mapping_entry(struct pdb_methods *m,
+ struct dom_sid sid)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_group_mapping(struct pdb_methods *m,
+ const struct dom_sid *sid,
+ enum lsa_SidType sid_name_use,
+ GROUP_MAP ***pp_rmap,
+ size_t *p_num_entries,
+ bool unix_only)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_group_members(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *group,
+ uint32_t **pmembers,
+ size_t *pnum_members)
+{
+ unsigned int i, num_sids, num_members;
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct dom_sid *members_as_sids;
+ struct dom_sid *dom_sid;
+ uint32_t *members;
+ struct ldb_dn *dn;
+ NTSTATUS status;
+ struct dom_sid_buf buf;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ dn = ldb_dn_new_fmt(
+ tmp_ctx,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(group, &buf));
+ if (!dn || !ldb_dn_validate(dn)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dsdb_enum_group_mem(state->ldb, tmp_ctx, dn, &members_as_sids, &num_sids);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ status = dom_sid_split_rid(tmp_ctx, group, &dom_sid, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ *pmembers = members = talloc_array(mem_ctx, uint32_t, num_sids);
+ if (*pmembers == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ num_members = 0;
+
+ for (i = 0; i < num_sids; i++) {
+ if (!dom_sid_in_domain(dom_sid, &members_as_sids[i])) {
+ continue;
+ }
+ status = dom_sid_split_rid(NULL, &members_as_sids[i],
+ NULL, &members[num_members]);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ num_members++;
+ }
+ *pnum_members = num_members;
+ return NT_STATUS_OK;
+}
+
+/* Just convert the primary group SID into a group */
+static NTSTATUS fake_enum_group_memberships(struct pdb_samba_dsdb_state *state,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ struct dom_sid **pp_sids,
+ gid_t **pp_gids,
+ uint32_t *p_num_groups)
+{
+ NTSTATUS status;
+ size_t num_groups = 0;
+ struct dom_sid *group_sids = NULL;
+ gid_t *gids = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ if (user->group_sid) {
+ struct id_map *id_maps[2];
+ struct id_map id_map;
+
+ num_groups = 1;
+
+ group_sids = talloc_array(tmp_ctx, struct dom_sid, num_groups);
+ if (group_sids == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ gids = talloc_array(tmp_ctx, gid_t, num_groups);
+ if (gids == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ group_sids[0] = *user->group_sid;
+
+ ZERO_STRUCT(id_map);
+ id_map.sid = &group_sids[0];
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
+ gids[0] = id_map.xid.id;
+ } else {
+ struct dom_sid_buf buf1, buf2;
+ DEBUG(1, (__location__
+ "Group %s, of which %s is a member, could not be converted to a GID\n",
+ dom_sid_str_buf(&group_sids[0], &buf1),
+ dom_sid_str_buf(&user->user_sid, &buf2)));
+ talloc_free(tmp_ctx);
+ /* We must error out, otherwise a user might
+ * avoid a DENY acl based on a group they
+ * missed out on */
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+ }
+
+ *pp_sids = talloc_steal(mem_ctx, group_sids);
+ *pp_gids = talloc_steal(mem_ctx, gids);
+ *p_num_groups = num_groups;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_group_memberships(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user,
+ struct dom_sid **pp_sids,
+ gid_t **pp_gids,
+ uint32_t *p_num_groups)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_message *msg = pdb_samba_dsdb_get_samu_private(
+ m, user);
+ const char *attrs[] = { "tokenGroups", NULL};
+ struct ldb_message *tokengroups_msg;
+ struct ldb_message_element *tokengroups;
+ int i, rc;
+ NTSTATUS status;
+ unsigned int count = 0;
+ size_t num_groups;
+ struct dom_sid *group_sids;
+ gid_t *gids;
+ TALLOC_CTX *tmp_ctx;
+
+ if (msg == NULL) {
+ /* Fake up some things here */
+ return fake_enum_group_memberships(state,
+ mem_ctx,
+ user, pp_sids,
+ pp_gids, p_num_groups);
+ }
+
+ tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ rc = dsdb_search_one(state->ldb, tmp_ctx, &tokengroups_msg, msg->dn, LDB_SCOPE_BASE, attrs, 0, NULL);
+
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_SUCH_USER;
+ } else if (rc != LDB_SUCCESS) {
+ DEBUG(10, ("dsdb_search_one failed %s\n",
+ ldb_errstring(state->ldb)));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_LDAP(rc);
+ }
+
+ tokengroups = ldb_msg_find_element(tokengroups_msg, "tokenGroups");
+
+ if (tokengroups) {
+ count = tokengroups->num_values;
+ }
+
+ group_sids = talloc_array(tmp_ctx, struct dom_sid, count);
+ if (group_sids == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ gids = talloc_array(tmp_ctx, gid_t, count);
+ if (gids == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ num_groups = 0;
+
+ for (i=0; i<count; i++) {
+ struct id_map *id_maps[2];
+ struct id_map id_map;
+ struct ldb_val *v = &tokengroups->values[i];
+ enum ndr_err_code ndr_err
+ = ndr_pull_struct_blob(v, group_sids, &group_sids[num_groups],
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ ZERO_STRUCT(id_map);
+ id_map.sid = &group_sids[num_groups];
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
+ gids[num_groups] = id_map.xid.id;
+ } else {
+ struct dom_sid_buf buf;
+ DEBUG(1, (__location__
+ "Group %s, of which %s is a member, could not be converted to a GID\n",
+ dom_sid_str_buf(&group_sids[num_groups],
+ &buf),
+ ldb_dn_get_linearized(msg->dn)));
+ talloc_free(tmp_ctx);
+ /* We must error out, otherwise a user might
+ * avoid a DENY acl based on a group they
+ * missed out on */
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ num_groups += 1;
+ if (num_groups == count) {
+ break;
+ }
+ }
+
+ *pp_sids = talloc_steal(mem_ctx, group_sids);
+ *pp_gids = talloc_steal(mem_ctx, gids);
+ *p_num_groups = num_groups;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_set_unix_primary_group(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ struct samu *user)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_mod_groupmem_by_sid(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *groupsid,
+ const struct dom_sid *membersid,
+ int mod_op)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_message *msg;
+ int ret;
+ struct ldb_message_element *el;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg->dn = ldb_dn_new_fmt(
+ msg,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(groupsid, &buf));
+ if (!msg->dn || !ldb_dn_validate(msg->dn)) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ret = ldb_msg_add_fmt(
+ msg,
+ "member",
+ "<SID=%s>",
+ dom_sid_str_buf(membersid, &buf));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ el = ldb_msg_find_element(msg, "member");
+ el->flags = mod_op;
+
+ /* No need for transactions here, the ldb auto-transaction
+ * code will handle things for the single operation */
+ ret = ldb_modify(state->ldb, msg);
+ talloc_free(tmp_ctx);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10, ("ldb_modify failed: %s\n",
+ ldb_errstring(state->ldb)));
+ if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ return NT_STATUS_MEMBER_IN_GROUP;
+ }
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+ return NT_STATUS_LDAP(ret);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_mod_groupmem(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ uint32_t grouprid, uint32_t memberrid,
+ int mod_op)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ const struct dom_sid *dom_sid, *groupsid, *membersid;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ dom_sid = samdb_domain_sid(state->ldb);
+
+ groupsid = dom_sid_add_rid(tmp_ctx, dom_sid, grouprid);
+ if (groupsid == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ membersid = dom_sid_add_rid(tmp_ctx, dom_sid, memberrid);
+ if (membersid == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = pdb_samba_dsdb_mod_groupmem_by_sid(m, tmp_ctx, groupsid, membersid, mod_op);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_add_groupmem(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ uint32_t group_rid, uint32_t member_rid)
+{
+ return pdb_samba_dsdb_mod_groupmem(m, mem_ctx, group_rid, member_rid,
+ LDB_FLAG_MOD_ADD);
+}
+
+static NTSTATUS pdb_samba_dsdb_del_groupmem(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ uint32_t group_rid, uint32_t member_rid)
+{
+ return pdb_samba_dsdb_mod_groupmem(m, mem_ctx, group_rid, member_rid,
+ LDB_FLAG_MOD_DELETE);
+}
+
+static NTSTATUS pdb_samba_dsdb_create_alias(struct pdb_methods *m,
+ const char *name, uint32_t *rid)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct dom_sid *sid;
+
+ struct ldb_dn *dn;
+ NTSTATUS status;
+
+ /* Internally this uses transactions to ensure all the steps
+ * happen or fail as one */
+ status = dsdb_add_domain_alias(state->ldb, frame, name, &sid, &dn);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ }
+
+ sid_peek_rid(sid, rid);
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_delete_alias(struct pdb_methods *m,
+ const struct dom_sid *sid)
+{
+ const char *attrs[] = { NULL };
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_message *msg;
+ struct ldb_dn *dn;
+ int rc;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ dn = ldb_dn_new_fmt(
+ tmp_ctx,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(sid, &buf));
+ if (!dn || !ldb_dn_validate(dn)) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldb_transaction_start(state->ldb) != LDB_SUCCESS) {
+ DBG_ERR("Failed to start transaction: %s\n",
+ ldb_errstring(state->ldb));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "(objectclass=group)"
+ "(|(grouptype=%d)(grouptype=%d)))",
+ GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+ GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ } else if (rc != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("dsdb_search_one failed %s\n",
+ ldb_errstring(state->ldb)));
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_LDAP(rc);
+ }
+ rc = ldb_delete(state->ldb, dn);
+ if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ } else if (rc != LDB_SUCCESS) {
+ DEBUG(10, ("ldb_delete failed %s\n",
+ ldb_errstring(state->ldb)));
+ ldb_transaction_cancel(state->ldb);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_LDAP(rc);
+ }
+
+ if (ldb_transaction_commit(state->ldb) != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to commit transaction in pdb_samba_dsdb_delete_alias(): %s\n",
+ ldb_errstring(state->ldb)));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_add_aliasmem(struct pdb_methods *m,
+ const struct dom_sid *alias,
+ const struct dom_sid *member)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ status = pdb_samba_dsdb_mod_groupmem_by_sid(m, frame, alias, member, LDB_FLAG_MOD_ADD);
+ talloc_free(frame);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_del_aliasmem(struct pdb_methods *m,
+ const struct dom_sid *alias,
+ const struct dom_sid *member)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ status = pdb_samba_dsdb_mod_groupmem_by_sid(m, frame, alias, member, LDB_FLAG_MOD_DELETE);
+ talloc_free(frame);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_aliasmem(struct pdb_methods *m,
+ const struct dom_sid *alias,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid **pmembers,
+ size_t *pnum_members)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct ldb_dn *dn;
+ unsigned int num_members;
+ NTSTATUS status;
+ struct dom_sid_buf buf;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ dn = ldb_dn_new_fmt(
+ tmp_ctx,
+ state->ldb,
+ "<SID=%s>",
+ dom_sid_str_buf(alias, &buf));
+ if (!dn || !ldb_dn_validate(dn)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dsdb_enum_group_mem(state->ldb, mem_ctx, dn, pmembers, &num_members);
+ if (NT_STATUS_IS_OK(status)) {
+ *pnum_members = num_members;
+ }
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_alias_memberships(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ const struct dom_sid *members,
+ size_t num_members,
+ uint32_t **palias_rids,
+ size_t *pnum_alias_rids)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ uint32_t *alias_rids = NULL;
+ size_t num_alias_rids = 0;
+ int i;
+ struct auth_SidAttr *groupSIDs = NULL;
+ uint32_t num_groupSIDs = 0;
+ char *filter;
+ NTSTATUS status;
+ const char *sid_dn;
+ DATA_BLOB sid_blob;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+ /*
+ * TODO: Get the filter right so that we only get the aliases from
+ * either the SAM or BUILTIN
+ */
+
+ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
+ GROUP_TYPE_BUILTIN_LOCAL_GROUP);
+ if (filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_members; i++) {
+ struct dom_sid_buf buf;
+
+ sid_dn = talloc_asprintf(
+ tmp_ctx,
+ "<SID=%s>",
+ dom_sid_str_buf(&members[i], &buf));
+ if (sid_dn == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid_blob = data_blob_string_const(sid_dn);
+
+ status = dsdb_expand_nested_groups(state->ldb, &sid_blob, true, filter,
+ tmp_ctx, &groupSIDs, &num_groupSIDs);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ }
+
+ alias_rids = talloc_array(mem_ctx, uint32_t, num_groupSIDs);
+ if (alias_rids == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_groupSIDs; i++) {
+ if (sid_peek_check_rid(domain_sid, &groupSIDs[i].sid,
+ &alias_rids[num_alias_rids])) {
+ num_alias_rids++;;
+ }
+ }
+
+ *palias_rids = alias_rids;
+ *pnum_alias_rids = num_alias_rids;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_lookup_rids(struct pdb_methods *m,
+ const struct dom_sid *domain_sid,
+ int num_rids,
+ uint32_t *rids,
+ const char **names,
+ enum lsa_SidType *lsa_attrs)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ NTSTATUS status;
+
+ TALLOC_CTX *tmp_ctx;
+
+ if (num_rids == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ tmp_ctx = talloc_stackframe();
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ status = dsdb_lookup_rids(state->ldb, tmp_ctx, domain_sid, num_rids, rids, names, lsa_attrs);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_lookup_names(struct pdb_methods *m,
+ const struct dom_sid *domain_sid,
+ int num_names,
+ const char **pp_names,
+ uint32_t *rids,
+ enum lsa_SidType *attrs)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_account_policy(struct pdb_methods *m,
+ enum pdb_policy_type type,
+ uint32_t *value)
+{
+ return account_policy_get(type, value)
+ ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_samba_dsdb_set_account_policy(struct pdb_methods *m,
+ enum pdb_policy_type type,
+ uint32_t value)
+{
+ return account_policy_set(type, value)
+ ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_seq_num(struct pdb_methods *m,
+ time_t *seq_num_out)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ uint64_t seq_num;
+ int ret = ldb_sequence_number(state->ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
+ if (ret == LDB_SUCCESS) {
+ *seq_num_out = seq_num;
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+}
+
+struct pdb_samba_dsdb_search_state {
+ uint32_t acct_flags;
+ struct samr_displayentry *entries;
+ uint32_t num_entries;
+ ssize_t array_size;
+ uint32_t current;
+};
+
+static bool pdb_samba_dsdb_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct pdb_samba_dsdb_search_state *state = talloc_get_type_abort(
+ search->private_data, struct pdb_samba_dsdb_search_state);
+
+ if (state->current == state->num_entries) {
+ return false;
+ }
+
+ entry->idx = state->entries[state->current].idx;
+ entry->rid = state->entries[state->current].rid;
+ entry->acct_flags = state->entries[state->current].acct_flags;
+
+ entry->account_name = talloc_strdup(
+ search, state->entries[state->current].account_name);
+ entry->fullname = talloc_strdup(
+ search, state->entries[state->current].fullname);
+ entry->description = talloc_strdup(
+ search, state->entries[state->current].description);
+
+ state->current += 1;
+ return true;
+}
+
+static void pdb_samba_dsdb_search_end(struct pdb_search *search)
+{
+ struct pdb_samba_dsdb_search_state *state = talloc_get_type_abort(
+ search->private_data, struct pdb_samba_dsdb_search_state);
+ talloc_free(state);
+}
+
+static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
+ struct pdb_search *search,
+ struct pdb_samba_dsdb_search_state **pstate,
+ const char *exp_fmt, ...)
+ PRINTF_ATTRIBUTE(4, 5);
+
+static bool pdb_samba_dsdb_search_filter(struct pdb_methods *m,
+ struct pdb_search *search,
+ struct pdb_samba_dsdb_search_state **pstate,
+ const char *exp_fmt, ...)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct pdb_samba_dsdb_search_state *sstate;
+ const char * attrs[] = { "objectSid", "sAMAccountName", "displayName",
+ "userAccountControl", "description", NULL };
+ struct ldb_result *res;
+ int i, rc, num_users;
+
+ va_list ap;
+ char *expression = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ if (!tmp_ctx) {
+ return false;
+ }
+
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ sstate = talloc_zero(tmp_ctx, struct pdb_samba_dsdb_search_state);
+ if (sstate == NULL) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ rc = dsdb_search(state->ldb, tmp_ctx, &res, ldb_get_default_basedn(state->ldb), LDB_SCOPE_SUBTREE, attrs, 0, "%s", expression);
+ if (rc != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("dsdb_search failed: %s\n",
+ ldb_errstring(state->ldb)));
+ return false;
+ }
+
+ num_users = res->count;
+
+ sstate->entries = talloc_array(sstate, struct samr_displayentry,
+ num_users);
+ if (sstate->entries == NULL) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("talloc failed\n"));
+ return false;
+ }
+
+ sstate->num_entries = 0;
+
+ for (i=0; i<num_users; i++) {
+ struct samr_displayentry *e;
+ struct dom_sid *sid;
+
+ e = &sstate->entries[sstate->num_entries];
+
+ e->idx = sstate->num_entries;
+ sid = samdb_result_dom_sid(tmp_ctx, res->msgs[i], "objectSid");
+ if (!sid) {
+ talloc_free(tmp_ctx);
+ DEBUG(10, ("Could not pull SID\n"));
+ return false;
+ }
+ sid_peek_rid(sid, &e->rid);
+
+ e->acct_flags = samdb_result_acct_flags(res->msgs[i], "userAccountControl");
+ e->account_name = ldb_msg_find_attr_as_string(
+ res->msgs[i], "samAccountName", NULL);
+ if (e->account_name == NULL) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+ e->fullname = ldb_msg_find_attr_as_string(
+ res->msgs[i], "displayName", "");
+ e->description = ldb_msg_find_attr_as_string(
+ res->msgs[i], "description", "");
+
+ sstate->num_entries += 1;
+ if (sstate->num_entries >= num_users) {
+ break;
+ }
+ }
+ talloc_steal(sstate->entries, res->msgs);
+ search->private_data = talloc_steal(search, sstate);
+ search->next_entry = pdb_samba_dsdb_next_entry;
+ search->search_end = pdb_samba_dsdb_search_end;
+ *pstate = sstate;
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool pdb_samba_dsdb_search_users(struct pdb_methods *m,
+ struct pdb_search *search,
+ uint32_t acct_flags)
+{
+ struct pdb_samba_dsdb_search_state *sstate;
+ bool ret;
+
+ ret = pdb_samba_dsdb_search_filter(m, search, &sstate, "(objectclass=user)");
+ if (!ret) {
+ return false;
+ }
+ sstate->acct_flags = acct_flags;
+ return true;
+}
+
+static bool pdb_samba_dsdb_search_groups(struct pdb_methods *m,
+ struct pdb_search *search)
+{
+ struct pdb_samba_dsdb_search_state *sstate;
+ bool ret;
+
+ ret = pdb_samba_dsdb_search_filter(m, search, &sstate,
+ "(&(grouptype=%d)(objectclass=group))",
+ GTYPE_SECURITY_GLOBAL_GROUP);
+ if (!ret) {
+ return false;
+ }
+ sstate->acct_flags = 0;
+ return true;
+}
+
+static bool pdb_samba_dsdb_search_aliases(struct pdb_methods *m,
+ struct pdb_search *search,
+ const struct dom_sid *sid)
+{
+ struct pdb_samba_dsdb_search_state *sstate;
+ bool ret;
+
+ ret = pdb_samba_dsdb_search_filter(m, search, &sstate,
+ "(&(grouptype=%d)(objectclass=group))",
+ sid_check_is_builtin(sid)
+ ? GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
+ : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+ if (!ret) {
+ return false;
+ }
+ sstate->acct_flags = 0;
+ return true;
+}
+
+/*
+ * Instead of taking a gid or uid, this function takes a pointer to a
+ * unixid.
+ *
+ * This acts as an in-out variable so that the idmap functions can correctly
+ * receive ID_TYPE_BOTH, and this function ensures cache details are filled
+ * correctly rather than forcing the cache to store ID_TYPE_UID or ID_TYPE_GID.
+ */
+static bool pdb_samba_dsdb_id_to_sid(struct pdb_methods *m, struct unixid *id,
+ struct dom_sid *sid)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ NTSTATUS status;
+ struct id_map id_map;
+ struct id_map *id_maps[2];
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ if (!tmp_ctx) {
+ return false;
+ }
+
+ id_map.xid = *id;
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ if (id_map.xid.type != ID_TYPE_NOT_SPECIFIED) {
+ id->type = id_map.xid.type;
+ }
+ *sid = *id_map.sid;
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool pdb_samba_dsdb_sid_to_id(struct pdb_methods *m, const struct dom_sid *sid,
+ struct unixid *id)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ struct id_map id_map;
+ struct id_map *id_maps[2];
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ if (!tmp_ctx) {
+ return false;
+ }
+
+ ZERO_STRUCT(id_map);
+ id_map.sid = discard_const_p(struct dom_sid, sid);
+ id_maps[0] = &id_map;
+ id_maps[1] = NULL;
+
+ status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+ talloc_free(tmp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ if (id_map.xid.type != ID_TYPE_NOT_SPECIFIED) {
+ *id = id_map.xid;
+ return true;
+ }
+ return false;
+}
+
+static uint32_t pdb_samba_dsdb_capabilities(struct pdb_methods *m)
+{
+ return PDB_CAP_STORE_RIDS | PDB_CAP_ADS | PDB_CAP_TRUSTED_DOMAINS_EX;
+}
+
+static bool pdb_samba_dsdb_new_rid(struct pdb_methods *m, uint32_t *rid)
+{
+ return false;
+}
+
+static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m,
+ const char *domain, char** pwd,
+ struct dom_sid *sid,
+ time_t *pass_last_set_time)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustPartner",
+ "trustAuthOutgoing",
+ "whenCreated",
+ "msDS-SupportedEncryptionTypes",
+ "trustAttributes",
+ "trustDirection",
+ "trustType",
+ NULL
+ };
+ struct ldb_message *msg;
+ const struct ldb_val *password_val;
+ int trust_direction_flags;
+ int trust_type;
+ int i;
+ DATA_BLOB password_utf16;
+ struct trustAuthInOutBlob password_blob;
+ struct AuthenticationInformationArray *auth_array;
+ char *password_talloc;
+ size_t password_len;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ const char *netbios_domain = NULL;
+ const struct dom_sid *domain_sid = NULL;
+
+ status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+ attrs, tmp_ctx, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * This can be called to work out of a domain is
+ * trusted, rather than just to get the password
+ */
+ DEBUG(2, ("Failed to get trusted domain password for %s - %s. "
+ "It may not be a trusted domain.\n", domain,
+ nt_errstr(status)));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+ if (netbios_domain == NULL) {
+ DEBUG(2, ("Trusted domain %s has to flatName defined.\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ domain_sid = samdb_result_dom_sid(tmp_ctx, msg, "securityIdentifier");
+ if (domain_sid == NULL) {
+ DEBUG(2, ("Trusted domain %s has no securityIdentifier defined.\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+ if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+ DBG_WARNING("Trusted domain %s is not an outbound trust.\n",
+ domain);
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+ if (trust_type == LSA_TRUST_TYPE_MIT) {
+ DBG_WARNING("Trusted domain %s is not an AD trust "
+ "(trustType == LSA_TRUST_TYPE_MIT).\n", domain);
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+ if (password_val == NULL) {
+ DEBUG(2, ("Failed to get trusted domain password for %s, "
+ "attribute trustAuthOutgoing not returned.\n", domain));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to get trusted domain password for %s, "
+ "attribute trustAuthOutgoing could not be parsed %s.\n",
+ domain,
+ ndr_map_error2string(ndr_err)));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ auth_array = &password_blob.current;
+
+ for (i=0; i < auth_array->count; i++) {
+ if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
+ break;
+ }
+ }
+
+ if (i == auth_array->count) {
+ DEBUG(0, ("Trusted domain %s does not have a "
+ "clear-text password stored\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password,
+ auth_array->array[i].AuthInfo.clear.size);
+
+ /*
+ * In the future, make this function return a
+ * cli_credentials that can store a MD4 hash with cli_credential_set_nt_hash()
+ * but for now convert to UTF8 and fail if the string can not be converted.
+ *
+ * We can't safely convert the random strings windows uses into
+ * utf8.
+ */
+ if (!convert_string_talloc(tmp_ctx,
+ CH_UTF16MUNGED, CH_UTF8,
+ password_utf16.data, password_utf16.length,
+ (void *)&password_talloc,
+ &password_len)) {
+ DEBUG(0, ("FIXME: Could not convert password for trusted domain %s"
+ " to UTF8. This may be a password set from Windows.\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+ *pwd = SMB_STRNDUP(password_talloc, password_len);
+ if (pass_last_set_time) {
+ *pass_last_set_time = nt_time_to_unix(auth_array->array[i].LastUpdateTime);
+ }
+
+ if (sid != NULL) {
+ sid_copy(sid, domain_sid);
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m,
+ const char *domain,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials **_creds)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustPartner",
+ "trustAuthOutgoing",
+ "whenCreated",
+ "msDS-SupportedEncryptionTypes",
+ "trustAttributes",
+ "trustDirection",
+ "trustType",
+ NULL
+ };
+ struct ldb_message *msg;
+ const struct ldb_val *password_val;
+ int trust_direction_flags;
+ int trust_type;
+ int i;
+ DATA_BLOB password_utf16 = {};
+ struct samr_Password *password_nt = NULL;
+ uint32_t password_version = 0;
+ DATA_BLOB old_password_utf16 = {};
+ struct samr_Password *old_password_nt = NULL;
+ struct trustAuthInOutBlob password_blob;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ time_t last_set_time = 0;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+ const char *my_netbios_name = NULL;
+ const char *my_netbios_domain = NULL;
+ const char *my_dns_domain = NULL;
+ const char *netbios_domain = NULL;
+ char *account_name = NULL;
+ char *principal_name = NULL;
+ const char *dns_domain = NULL;
+
+ status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+ attrs, tmp_ctx, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * This can be called to work out of a domain is
+ * trusted, rather than just to get the password
+ */
+ DEBUG(2, ("Failed to get trusted domain password for %s - %s "
+ "It may not be a trusted domain.\n", domain,
+ nt_errstr(status)));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+ if (netbios_domain == NULL) {
+ DEBUG(2, ("Trusted domain %s has to flatName defined.\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ dns_domain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+
+ trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+ if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+ DBG_WARNING("Trusted domain %s is not an outbound trust.\n",
+ domain);
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+ if (trust_type == LSA_TRUST_TYPE_MIT) {
+ DBG_WARNING("Trusted domain %s is not an AD trust "
+ "(trustType == LSA_TRUST_TYPE_MIT).\n", domain);
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+ if (password_val == NULL) {
+ DEBUG(2, ("Failed to get trusted domain password for %s, "
+ "attribute trustAuthOutgoing not returned.\n", domain));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to get trusted domain password for %s, "
+ "attribute trustAuthOutgoing could not be parsed %s.\n",
+ domain,
+ ndr_map_error2string(ndr_err)));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ for (i=0; i < password_blob.current.count; i++) {
+ struct AuthenticationInformation *a =
+ &password_blob.current.array[i];
+
+ switch (a->AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ break;
+
+ case TRUST_AUTH_TYPE_VERSION:
+ password_version = a->AuthInfo.version.version;
+ break;
+
+ case TRUST_AUTH_TYPE_CLEAR:
+ last_set_time = nt_time_to_unix(a->LastUpdateTime);
+
+ password_utf16 = data_blob_const(a->AuthInfo.clear.password,
+ a->AuthInfo.clear.size);
+ password_nt = NULL;
+ break;
+
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (password_utf16.length != 0) {
+ break;
+ }
+
+ last_set_time = nt_time_to_unix(a->LastUpdateTime);
+
+ password_nt = &a->AuthInfo.nt4owf.password;
+ break;
+ }
+ }
+
+ for (i=0; i < password_blob.previous.count; i++) {
+ struct AuthenticationInformation *a = &password_blob.previous.array[i];
+
+ switch (a->AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ break;
+
+ case TRUST_AUTH_TYPE_VERSION:
+ break;
+
+ case TRUST_AUTH_TYPE_CLEAR:
+ old_password_utf16 = data_blob_const(a->AuthInfo.clear.password,
+ a->AuthInfo.clear.size);
+ old_password_nt = NULL;
+ break;
+
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (old_password_utf16.length != 0) {
+ break;
+ }
+
+ old_password_nt = &a->AuthInfo.nt4owf.password;
+ break;
+ }
+ }
+
+ if (password_utf16.length == 0 && password_nt == NULL) {
+ DEBUG(0, ("Trusted domain %s does not have a "
+ "clear-text nor nt password stored\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ my_netbios_name = lpcfg_netbios_name(state->lp_ctx);
+ my_netbios_domain = lpcfg_workgroup(state->lp_ctx);
+ my_dns_domain = lpcfg_dnsdomain(state->lp_ctx);
+
+ creds = cli_credentials_init(tmp_ctx);
+ if (creds == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = cli_credentials_set_workstation(creds, my_netbios_name, CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ok = cli_credentials_set_realm(creds, dns_domain, CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (my_dns_domain != NULL && dns_domain != NULL) {
+ cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DNS_DOMAIN);
+ account_name = talloc_asprintf(tmp_ctx, "%s.", my_dns_domain);
+ if (account_name == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ principal_name = talloc_asprintf(tmp_ctx, "%s$@%s", my_netbios_domain,
+ cli_credentials_get_realm(creds));
+ if (principal_name == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DOMAIN);
+ account_name = talloc_asprintf(tmp_ctx, "%s$", my_netbios_domain);
+ if (account_name == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ principal_name = NULL;
+ }
+
+ ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (principal_name != NULL) {
+ ok = cli_credentials_set_principal(creds, principal_name,
+ CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (old_password_nt != NULL) {
+ ok = cli_credentials_set_old_nt_hash(creds, old_password_nt);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (old_password_utf16.length > 0) {
+ ok = cli_credentials_set_old_utf16_password(creds,
+ &old_password_utf16);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (password_nt != NULL) {
+ ok = cli_credentials_set_nt_hash(creds, password_nt,
+ CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (password_utf16.length > 0) {
+ ok = cli_credentials_set_utf16_password(creds,
+ &password_utf16,
+ CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ cli_credentials_set_password_last_changed_time(creds, last_set_time);
+ cli_credentials_set_kvno(creds, password_version);
+
+ if (password_utf16.length > 0 && dns_domain != NULL) {
+ /*
+ * Force kerberos if this is an active directory domain
+ */
+ cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+ } else {
+ /*
+ * TODO: we should allow krb5 with the raw nt hash.
+ */
+ cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+ }
+
+ *_creds = talloc_move(mem_ctx, &creds);
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
+ const char* domain, const char* pwd,
+ const struct dom_sid *sid)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "trustAuthOutgoing",
+ "trustDirection",
+ "trustType",
+ NULL
+ };
+ struct ldb_message *msg = NULL;
+ int trust_direction_flags;
+ int trust_type;
+ uint32_t i; /* The same type as old_blob.current.count */
+ const struct ldb_val *old_val = NULL;
+ struct trustAuthInOutBlob old_blob = {};
+ uint32_t old_version = 0;
+ uint32_t new_version = 0;
+ DATA_BLOB new_utf16 = {};
+ struct trustAuthInOutBlob new_blob = {};
+ struct ldb_val new_val = {};
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ bool ok;
+ int ret;
+
+ ret = ldb_transaction_start(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(2, ("Failed to start transaction.\n"));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ ok = samdb_is_pdc(state->ldb);
+ if (!ok) {
+ DEBUG(2, ("Password changes for domain %s are only allowed on a PDC.\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+ attrs, tmp_ctx, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * This can be called to work out of a domain is
+ * trusted, rather than just to get the password
+ */
+ DEBUG(2, ("Failed to get trusted domain password for %s - %s. "
+ "It may not be a trusted domain.\n", domain,
+ nt_errstr(status)));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+ if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
+ DBG_WARNING("Trusted domain %s is not an outbound trust, can't set a password.\n",
+ domain);
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+ switch (trust_type) {
+ case LSA_TRUST_TYPE_DOWNLEVEL:
+ case LSA_TRUST_TYPE_UPLEVEL:
+ break;
+ default:
+ DEBUG(0, ("Trusted domain %s is of type 0x%X - "
+ "password changes are not supported\n",
+ domain, (unsigned)trust_type));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ old_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+ if (old_val != NULL) {
+ ndr_err = ndr_pull_struct_blob(old_val, tmp_ctx, &old_blob,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to get trusted domain password for %s, "
+ "attribute trustAuthOutgoing could not be parsed %s.\n",
+ domain,
+ ndr_map_error2string(ndr_err)));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+ }
+
+ for (i=0; i < old_blob.current.count; i++) {
+ struct AuthenticationInformation *a =
+ &old_blob.current.array[i];
+
+ switch (a->AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ break;
+
+ case TRUST_AUTH_TYPE_VERSION:
+ old_version = a->AuthInfo.version.version;
+ break;
+
+ case TRUST_AUTH_TYPE_CLEAR:
+ break;
+
+ case TRUST_AUTH_TYPE_NT4OWF:
+ break;
+ }
+ }
+
+ new_version = old_version + 1;
+ ok = convert_string_talloc(tmp_ctx,
+ CH_UNIX, CH_UTF16,
+ pwd, strlen(pwd),
+ (void *)&new_utf16.data,
+ &new_utf16.length);
+ if (!ok) {
+ DEBUG(0, ("Failed to generate new_utf16 password for domain %s\n",
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ if (new_utf16.length < 28) {
+ DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to short.\n",
+ new_utf16.length,
+ (unsigned)new_version,
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+ if (new_utf16.length > 498) {
+ DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to long.\n",
+ new_utf16.length,
+ (unsigned)new_version,
+ domain));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ new_blob.count = MAX(old_blob.current.count, 2);
+ new_blob.current.array = talloc_zero_array(tmp_ctx,
+ struct AuthenticationInformation,
+ new_blob.count);
+ if (new_blob.current.array == NULL) {
+ DEBUG(0, ("talloc_zero_array(%u) failed\n",
+ (unsigned)new_blob.count));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+ new_blob.previous.array = talloc_zero_array(tmp_ctx,
+ struct AuthenticationInformation,
+ new_blob.count);
+ if (new_blob.current.array == NULL) {
+ DEBUG(0, ("talloc_zero_array(%u) failed\n",
+ (unsigned)new_blob.count));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ for (i = 0; i < old_blob.current.count; i++) {
+ new_blob.previous.array[i] = old_blob.current.array[i];
+ new_blob.previous.count++;
+ }
+ for (; i < new_blob.count; i++) {
+ struct AuthenticationInformation *pi =
+ &new_blob.previous.array[i];
+
+ if (i == 0) {
+ /*
+ * new_blob.previous is still empty so
+ * we'll do new_blob.previous = new_blob.current
+ * below.
+ */
+ break;
+ }
+
+ pi->LastUpdateTime = now;
+ pi->AuthType = TRUST_AUTH_TYPE_NONE;
+ new_blob.previous.count++;
+ }
+
+ for (i = 0; i < new_blob.count; i++) {
+ struct AuthenticationInformation *ci =
+ &new_blob.current.array[i];
+
+ ci->LastUpdateTime = now;
+ switch (i) {
+ case 0:
+ ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ci->AuthInfo.clear.size = new_utf16.length;
+ ci->AuthInfo.clear.password = new_utf16.data;
+ break;
+ case 1:
+ ci->AuthType = TRUST_AUTH_TYPE_VERSION;
+ ci->AuthInfo.version.version = new_version;
+ break;
+ default:
+ ci->AuthType = TRUST_AUTH_TYPE_NONE;
+ break;
+ }
+
+ new_blob.current.count++;
+ }
+
+ if (new_blob.previous.count == 0) {
+ TALLOC_FREE(new_blob.previous.array);
+ new_blob.previous = new_blob.current;
+ }
+
+ ndr_err = ndr_push_struct_blob(&new_val, tmp_ctx, &new_blob,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to generate trustAuthOutgoing for "
+ "trusted domain password for %s: %s.\n",
+ domain, ndr_map_error2string(ndr_err)));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ msg->num_elements = 0;
+ ret = ldb_msg_append_value(msg, "trustAuthOutgoing",
+ &new_val, LDB_FLAG_MOD_REPLACE);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("ldb_msg_append_value() failed\n"));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ ret = ldb_modify(state->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to replace trustAuthOutgoing for "
+ "trusted domain password for %s: %s - %s\n",
+ domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
+ TALLOC_FREE(tmp_ctx);
+ ldb_transaction_cancel(state->ldb);
+ return false;
+ }
+
+ ret = ldb_transaction_commit(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("Failed to commit trustAuthOutgoing for "
+ "trusted domain password for %s: %s - %s\n",
+ domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ DEBUG(1, ("Added new_version[%u] to trustAuthOutgoing for "
+ "trusted domain password for %s.\n",
+ (unsigned)new_version, domain));
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,
+ const char *domain)
+{
+ return false;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_trusteddoms(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *_num_domains,
+ struct trustdom_info ***_domains)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustDirection",
+ NULL
+ };
+ struct ldb_result *res = NULL;
+ unsigned int i;
+ struct trustdom_info **domains = NULL;
+ NTSTATUS status;
+ uint32_t di = 0;
+
+ *_num_domains = 0;
+ *_domains = NULL;
+
+ status = dsdb_trust_search_tdos(state->ldb, NULL,
+ attrs, tmp_ctx, &res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("dsdb_trust_search_tdos() - %s\n", nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ if (res->count == 0) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ domains = talloc_zero_array(tmp_ctx, struct trustdom_info *,
+ res->count);
+ if (domains == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < res->count; i++) {
+ struct ldb_message *msg = res->msgs[i];
+ struct trustdom_info *d = NULL;
+ const char *name = NULL;
+ struct dom_sid *sid = NULL;
+ uint32_t direction;
+
+ d = talloc_zero(domains, struct trustdom_info);
+ if (d == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ name = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+ if (name == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ sid = samdb_result_dom_sid(msg, msg, "securityIdentifier");
+ if (sid == NULL) {
+ continue;
+ }
+
+ direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+ if (!(direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
+ continue;
+ }
+
+ d->name = talloc_strdup(d, name);
+ if (d->name == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ d->sid = *sid;
+
+ domains[di++] = d;
+ }
+
+ domains = talloc_realloc(domains, domains, struct trustdom_info *, di);
+ *_domains = talloc_move(mem_ctx, &domains);
+ *_num_domains = di;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_msg_to_trusted_domain(const struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ struct pdb_trusted_domain **_d)
+{
+ struct pdb_trusted_domain *d = NULL;
+ const char *str = NULL;
+ struct dom_sid *sid = NULL;
+ const struct ldb_val *val = NULL;
+ uint64_t val64;
+
+ *_d = NULL;
+
+ d = talloc_zero(mem_ctx, struct pdb_trusted_domain);
+ if (d == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "flatName", NULL);
+ if (str == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ d->netbios_name = talloc_strdup(d, str);
+ if (d->netbios_name == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ str = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+ if (str != NULL) {
+ d->domain_name = talloc_strdup(d, str);
+ if (d->domain_name == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ sid = samdb_result_dom_sid(d, msg, "securityIdentifier");
+ if (sid != NULL) {
+ d->security_identifier = *sid;
+ TALLOC_FREE(sid);
+ }
+
+ val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
+ if (val != NULL) {
+ d->trust_auth_outgoing = data_blob_dup_talloc(d, *val);
+ if (d->trust_auth_outgoing.data == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
+ if (val != NULL) {
+ d->trust_auth_incoming = data_blob_dup_talloc(d, *val);
+ if (d->trust_auth_incoming.data == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ d->trust_direction = ldb_msg_find_attr_as_uint(msg, "trustDirection", 0);
+ d->trust_type = ldb_msg_find_attr_as_uint(msg, "trustType", 0);
+ d->trust_attributes = ldb_msg_find_attr_as_uint(msg, "trustAttributes", 0);
+
+ val64 = ldb_msg_find_attr_as_uint64(msg, "trustPosixOffset", UINT64_MAX);
+ if (val64 != UINT64_MAX) {
+ d->trust_posix_offset = talloc(d, uint32_t);
+ if (d->trust_posix_offset == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *d->trust_posix_offset = (uint32_t)val64;
+ }
+
+ val64 = ldb_msg_find_attr_as_uint64(msg, "msDS-SupportedEncryptionTypes", UINT64_MAX);
+ if (val64 != UINT64_MAX) {
+ d->supported_enc_type = talloc(d, uint32_t);
+ if (d->supported_enc_type == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *d->supported_enc_type = (uint32_t)val64;
+ }
+
+ val = ldb_msg_find_ldb_val(msg, "msDS-TrustForestTrustInfo");
+ if (val != NULL) {
+ d->trust_forest_trust_info = data_blob_dup_talloc(d, *val);
+ if (d->trust_forest_trust_info.data == NULL) {
+ TALLOC_FREE(d);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ *_d = d;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ const char *domain,
+ struct pdb_trusted_domain **td)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustPartner",
+ "trustAuthOutgoing",
+ "trustAuthIncoming",
+ "trustAttributes",
+ "trustDirection",
+ "trustType",
+ "trustPosixOffset",
+ "msDS-SupportedEncryptionTypes",
+ "msDS-TrustForestTrustInfo",
+ NULL
+ };
+ struct ldb_message *msg = NULL;
+ struct pdb_trusted_domain *d = NULL;
+ NTSTATUS status;
+
+ status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
+ attrs, tmp_ctx, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("dsdb_trust_search_tdo(%s) - %s\n",
+ domain, nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s\n",
+ domain, nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ *td = d;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_get_trusted_domain_by_sid(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid *sid,
+ struct pdb_trusted_domain **td)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustPartner",
+ "trustAuthOutgoing",
+ "trustAuthIncoming",
+ "trustAttributes",
+ "trustDirection",
+ "trustType",
+ "trustPosixOffset",
+ "msDS-SupportedEncryptionTypes",
+ "msDS-TrustForestTrustInfo",
+ NULL
+ };
+ struct ldb_message *msg = NULL;
+ struct pdb_trusted_domain *d = NULL;
+ struct dom_sid_buf buf;
+ NTSTATUS status;
+
+ status = dsdb_trust_search_tdo_by_sid(state->ldb, sid,
+ attrs, tmp_ctx, &msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("dsdb_trust_search_tdo_by_sid(%s) - %s\n",
+ dom_sid_str_buf(sid, &buf),
+ nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ status = pdb_samba_dsdb_msg_to_trusted_domain(msg, mem_ctx, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain(%s) - %s\n",
+ dom_sid_str_buf(sid, &buf),
+ nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ *td = d;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
+ struct ldb_context *sam_ldb,
+ struct ldb_dn *base_dn,
+ const char *netbios_name,
+ struct trustAuthInOutBlob *taiob)
+{
+ struct ldb_request *req = NULL;
+ struct ldb_message *msg = NULL;
+ struct ldb_dn *dn = NULL;
+ uint32_t i;
+ int ret;
+ bool ok;
+
+ dn = ldb_dn_copy(mem_ctx, base_dn);
+ if (dn == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ok = ldb_dn_add_child_fmt(dn, "cn=%s$,cn=users", netbios_name);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ msg->dn = dn;
+
+ ret = ldb_msg_add_string(msg, "objectClass", "user");
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_msg_add_fmt(msg, "samAccountName", "%s$", netbios_name);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = samdb_msg_add_uint(sam_ldb, msg, msg, "userAccountControl",
+ UF_INTERDOMAIN_TRUST_ACCOUNT);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < taiob->count; i++) {
+ struct AuthenticationInformation *auth_info =
+ &taiob->current.array[i];
+ const char *attribute = NULL;
+ struct ldb_val v;
+
+ switch (taiob->current.array[i].AuthType) {
+ case TRUST_AUTH_TYPE_NT4OWF:
+ attribute = "unicodePwd";
+ v.data = (uint8_t *)&auth_info->AuthInfo.nt4owf.password;
+ v.length = 16;
+ break;
+
+ case TRUST_AUTH_TYPE_CLEAR:
+ attribute = "clearTextPassword";
+ v.data = auth_info->AuthInfo.clear.password;
+ v.length = auth_info->AuthInfo.clear.size;
+ break;
+
+ default:
+ continue;
+ }
+
+ ret = ldb_msg_add_value(msg, attribute, &v, NULL);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* create the trusted_domain user account */
+ ret = ldb_build_add_req(&req, sam_ldb, mem_ctx, msg, NULL, NULL,
+ ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_request_add_control(
+ req, DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = dsdb_autotransaction_request(sam_ldb, req);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to create user record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(sam_ldb)));
+
+ switch (ret) {
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ return NT_STATUS_DOMAIN_EXISTS;
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_set_trusted_domain(struct pdb_methods *methods,
+ const char* domain,
+ const struct pdb_trusted_domain *td)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ methods->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ bool in_txn = false;
+ struct ldb_dn *base_dn = NULL;
+ struct ldb_message *msg = NULL;
+ const char *attrs[] = {
+ NULL
+ };
+ char *netbios_encoded = NULL;
+ char *dns_encoded = NULL;
+ char *sid_encoded = NULL;
+ int ret;
+ struct trustAuthInOutBlob taiob;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ bool ok;
+
+ base_dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->ldb));
+ if (base_dn == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ /*
+ * We expect S-1-5-21-A-B-C, but we don't
+ * allow S-1-5-21-0-0-0 as this is used
+ * for claims and compound identities.
+ */
+ ok = dom_sid_is_valid_account_domain(&td->security_identifier);
+ if (!ok) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (strequal(td->netbios_name, "BUILTIN")) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+ if (strequal(td->domain_name, "BUILTIN")) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ dns_encoded = ldb_binary_encode_string(tmp_ctx, td->domain_name);
+ if (dns_encoded == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ netbios_encoded = ldb_binary_encode_string(tmp_ctx, td->netbios_name);
+ if (netbios_encoded == NULL) {
+ status =NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ sid_encoded = ldap_encode_ndr_dom_sid(tmp_ctx, &td->security_identifier);
+ if (sid_encoded == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ok = samdb_is_pdc(state->ldb);
+ if (!ok) {
+ DBG_ERR("Adding TDO is only allowed on a PDC.\n");
+ TALLOC_FREE(tmp_ctx);
+ status = NT_STATUS_INVALID_DOMAIN_ROLE;
+ goto out;
+ }
+
+ status = dsdb_trust_search_tdo(state->ldb,
+ td->netbios_name,
+ td->domain_name,
+ attrs,
+ tmp_ctx,
+ &msg);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ DBG_ERR("dsdb_trust_search_tdo returned %s\n",
+ nt_errstr(status));
+ status = NT_STATUS_INVALID_DOMAIN_STATE;
+ goto out;
+ }
+
+ ret = ldb_transaction_start(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto out;
+ }
+ in_txn = true;
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ msg->dn = samdb_system_container_dn(state->ldb, tmp_ctx);
+ if (msg->dn == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ok = ldb_dn_add_child_fmt(msg->dn, "cn=%s", td->domain_name);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = ldb_msg_add_string(msg, "objectClass", "trustedDomain");
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = ldb_msg_add_string(msg, "flatname", td->netbios_name);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = ldb_msg_add_string(msg, "trustPartner", td->domain_name);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = samdb_msg_add_dom_sid(state->ldb,
+ tmp_ctx,
+ msg,
+ "securityIdentifier",
+ &td->security_identifier);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = samdb_msg_add_int(state->ldb,
+ tmp_ctx,
+ msg,
+ "trustType",
+ td->trust_type);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = samdb_msg_add_int(state->ldb,
+ tmp_ctx,
+ msg,
+ "trustAttributes",
+ td->trust_attributes);
+ if (ret != LDB_SUCCESS) {
+ status =NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = samdb_msg_add_int(state->ldb,
+ tmp_ctx,
+ msg,
+ "trustDirection",
+ td->trust_direction);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ if (td->trust_auth_incoming.data != NULL) {
+ ret = ldb_msg_add_value(msg,
+ "trustAuthIncoming",
+ &td->trust_auth_incoming,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ }
+ if (td->trust_auth_outgoing.data != NULL) {
+ ret = ldb_msg_add_value(msg,
+ "trustAuthOutgoing",
+ &td->trust_auth_outgoing,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ /* create the trusted_domain */
+ ret = ldb_add(state->ldb, msg);
+ switch (ret) {
+ case LDB_SUCCESS:
+ break;
+
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ DBG_ERR("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(state->ldb));
+ status = NT_STATUS_DOMAIN_EXISTS;
+ goto out;
+
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ DBG_ERR("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(state->ldb));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto out;
+
+ default:
+ DBG_ERR("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(state->ldb));
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto out;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &td->trust_auth_outgoing,
+ tmp_ctx,
+ &taiob,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto out;
+ }
+
+ if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+ status = add_trust_user(tmp_ctx,
+ state->ldb,
+ base_dn,
+ td->netbios_name,
+ &taiob);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ ret = ldb_transaction_commit(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ in_txn = false;
+
+ /*
+ * TODO: Notify winbindd that we have a new trust
+ */
+
+ status = NT_STATUS_OK;
+
+out:
+ if (in_txn) {
+ ldb_transaction_cancel(state->ldb);
+ }
+ TALLOC_FREE(tmp_ctx);
+ return status;
+}
+
+static NTSTATUS delete_trust_user(TALLOC_CTX *mem_ctx,
+ struct pdb_samba_dsdb_state *state,
+ const char *trust_user)
+{
+ const char *attrs[] = { "userAccountControl", NULL };
+ struct ldb_message **msgs;
+ uint32_t uac;
+ int ret;
+
+ ret = gendb_search(state->ldb,
+ mem_ctx,
+ ldb_get_default_basedn(state->ldb),
+ &msgs,
+ attrs,
+ "samAccountName=%s$",
+ trust_user);
+ if (ret > 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (ret == 0) {
+ return NT_STATUS_OK;
+ }
+
+ uac = ldb_msg_find_attr_as_uint(msgs[0],
+ "userAccountControl",
+ 0);
+ if (!(uac & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ ret = ldb_delete(state->ldb, msgs[0]->dn);
+ switch (ret) {
+ case LDB_SUCCESS:
+ break;
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba_dsdb_del_trusted_domain(struct pdb_methods *methods,
+ const char *domain)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ methods->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ struct pdb_trusted_domain *td = NULL;
+ struct ldb_dn *tdo_dn = NULL;
+ bool in_txn = false;
+ NTSTATUS status;
+ int ret;
+ bool ok;
+
+ status = pdb_samba_dsdb_get_trusted_domain(methods,
+ tmp_ctx,
+ domain,
+ &td);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ DBG_ERR("Searching TDO for %s returned %s\n",
+ domain, nt_errstr(status));
+ return status;
+ }
+ DBG_NOTICE("No TDO object for %s\n", domain);
+ return NT_STATUS_OK;
+ }
+
+ tdo_dn = samdb_system_container_dn(state->ldb, tmp_ctx);
+ if (tdo_dn == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ok = ldb_dn_add_child_fmt(tdo_dn, "cn=%s", domain);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = ldb_transaction_start(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto out;
+ }
+ in_txn = true;
+
+ ret = ldb_delete(state->ldb, tdo_dn);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_INVALID_HANDLE;
+ goto out;
+ }
+
+ if (td->trust_direction == LSA_TRUST_DIRECTION_INBOUND) {
+ status = delete_trust_user(tmp_ctx, state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ ret = ldb_transaction_commit(state->ldb);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto out;
+ }
+ in_txn = false;
+
+ status = NT_STATUS_OK;
+
+out:
+ if (in_txn) {
+ ldb_transaction_cancel(state->ldb);
+ }
+ TALLOC_FREE(tmp_ctx);
+
+ return status;
+}
+
+static NTSTATUS pdb_samba_dsdb_enum_trusted_domains(struct pdb_methods *m,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *_num_domains,
+ struct pdb_trusted_domain ***_domains)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ m->private_data, struct pdb_samba_dsdb_state);
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char * const attrs[] = {
+ "securityIdentifier",
+ "flatName",
+ "trustPartner",
+ "trustAuthOutgoing",
+ "trustAuthIncoming",
+ "trustAttributes",
+ "trustDirection",
+ "trustType",
+ "trustPosixOffset",
+ "msDS-SupportedEncryptionTypes",
+ "msDS-TrustForestTrustInfo",
+ NULL
+ };
+ struct ldb_result *res = NULL;
+ unsigned int i;
+ struct pdb_trusted_domain **domains = NULL;
+ NTSTATUS status;
+ uint32_t di = 0;
+
+ *_num_domains = 0;
+ *_domains = NULL;
+
+ status = dsdb_trust_search_tdos(state->ldb, NULL,
+ attrs, tmp_ctx, &res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("dsdb_trust_search_tdos() - %s\n", nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ if (res->count == 0) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ domains = talloc_zero_array(tmp_ctx, struct pdb_trusted_domain *,
+ res->count);
+ if (domains == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < res->count; i++) {
+ struct ldb_message *msg = res->msgs[i];
+ struct pdb_trusted_domain *d = NULL;
+
+ status = pdb_samba_dsdb_msg_to_trusted_domain(msg, domains, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("pdb_samba_dsdb_msg_to_trusted_domain() - %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ domains[di++] = d;
+ }
+
+ domains = talloc_realloc(domains, domains, struct pdb_trusted_domain *,
+ di);
+ *_domains = talloc_move(mem_ctx, &domains);
+ *_num_domains = di;
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+static bool pdb_samba_dsdb_is_responsible_for_wellknown(struct pdb_methods *m)
+{
+ return true;
+}
+
+static bool pdb_samba_dsdb_is_responsible_for_everything_else(struct pdb_methods *m)
+{
+ return true;
+}
+
+static void pdb_samba_dsdb_init_methods(struct pdb_methods *m)
+{
+ m->name = "samba_dsdb";
+ m->get_domain_info = pdb_samba_dsdb_get_domain_info;
+ m->getsampwnam = pdb_samba_dsdb_getsampwnam;
+ m->getsampwsid = pdb_samba_dsdb_getsampwsid;
+ m->create_user = pdb_samba_dsdb_create_user;
+ m->delete_user = pdb_samba_dsdb_delete_user;
+ m->add_sam_account = pdb_samba_dsdb_add_sam_account;
+ m->update_sam_account = pdb_samba_dsdb_update_sam_account;
+ m->delete_sam_account = pdb_samba_dsdb_delete_sam_account;
+ m->rename_sam_account = pdb_samba_dsdb_rename_sam_account;
+ m->update_login_attempts = pdb_samba_dsdb_update_login_attempts;
+ m->getgrsid = pdb_samba_dsdb_getgrsid;
+ m->getgrgid = pdb_samba_dsdb_getgrgid;
+ m->getgrnam = pdb_samba_dsdb_getgrnam;
+ m->create_dom_group = pdb_samba_dsdb_create_dom_group;
+ m->delete_dom_group = pdb_samba_dsdb_delete_dom_group;
+ m->add_group_mapping_entry = pdb_samba_dsdb_add_group_mapping_entry;
+ m->update_group_mapping_entry = pdb_samba_dsdb_update_group_mapping_entry;
+ m->delete_group_mapping_entry = pdb_samba_dsdb_delete_group_mapping_entry;
+ m->enum_group_mapping = pdb_samba_dsdb_enum_group_mapping;
+ m->enum_group_members = pdb_samba_dsdb_enum_group_members;
+ m->enum_group_memberships = pdb_samba_dsdb_enum_group_memberships;
+ m->set_unix_primary_group = pdb_samba_dsdb_set_unix_primary_group;
+ m->add_groupmem = pdb_samba_dsdb_add_groupmem;
+ m->del_groupmem = pdb_samba_dsdb_del_groupmem;
+ m->create_alias = pdb_samba_dsdb_create_alias;
+ m->delete_alias = pdb_samba_dsdb_delete_alias;
+ m->get_aliasinfo = pdb_default_get_aliasinfo;
+ m->add_aliasmem = pdb_samba_dsdb_add_aliasmem;
+ m->del_aliasmem = pdb_samba_dsdb_del_aliasmem;
+ m->enum_aliasmem = pdb_samba_dsdb_enum_aliasmem;
+ m->enum_alias_memberships = pdb_samba_dsdb_enum_alias_memberships;
+ m->lookup_rids = pdb_samba_dsdb_lookup_rids;
+ m->lookup_names = pdb_samba_dsdb_lookup_names;
+ m->get_account_policy = pdb_samba_dsdb_get_account_policy;
+ m->set_account_policy = pdb_samba_dsdb_set_account_policy;
+ m->get_seq_num = pdb_samba_dsdb_get_seq_num;
+ m->search_users = pdb_samba_dsdb_search_users;
+ m->search_groups = pdb_samba_dsdb_search_groups;
+ m->search_aliases = pdb_samba_dsdb_search_aliases;
+ m->id_to_sid = pdb_samba_dsdb_id_to_sid;
+ m->sid_to_id = pdb_samba_dsdb_sid_to_id;
+ m->capabilities = pdb_samba_dsdb_capabilities;
+ m->new_rid = pdb_samba_dsdb_new_rid;
+ m->get_trusteddom_pw = pdb_samba_dsdb_get_trusteddom_pw;
+ m->get_trusteddom_creds = pdb_samba_dsdb_get_trusteddom_creds;
+ m->set_trusteddom_pw = pdb_samba_dsdb_set_trusteddom_pw;
+ m->del_trusteddom_pw = pdb_samba_dsdb_del_trusteddom_pw;
+ m->enum_trusteddoms = pdb_samba_dsdb_enum_trusteddoms;
+ m->get_trusted_domain = pdb_samba_dsdb_get_trusted_domain;
+ m->get_trusted_domain_by_sid = pdb_samba_dsdb_get_trusted_domain_by_sid;
+ m->set_trusted_domain = pdb_samba_dsdb_set_trusted_domain;
+ m->del_trusted_domain = pdb_samba_dsdb_del_trusted_domain;
+ m->enum_trusted_domains = pdb_samba_dsdb_enum_trusted_domains;
+ m->is_responsible_for_wellknown =
+ pdb_samba_dsdb_is_responsible_for_wellknown;
+ m->is_responsible_for_everything_else =
+ pdb_samba_dsdb_is_responsible_for_everything_else;
+}
+
+static void free_private_data(void **vp)
+{
+ struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
+ *vp, struct pdb_samba_dsdb_state);
+ talloc_unlink(state, state->ldb);
+ return;
+}
+
+static NTSTATUS pdb_samba_dsdb_init_secrets(struct pdb_methods *m)
+{
+ struct pdb_domain_info *dom_info;
+ struct dom_sid stored_sid;
+ struct GUID stored_guid;
+ bool sid_exists_and_matches = false;
+ bool guid_exists_and_matches = false;
+ bool ret;
+
+ dom_info = pdb_samba_dsdb_get_domain_info(m, m);
+ if (!dom_info) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ret = secrets_fetch_domain_sid(dom_info->name, &stored_sid);
+ if (ret) {
+ if (dom_sid_equal(&stored_sid, &dom_info->sid)) {
+ sid_exists_and_matches = true;
+ }
+ }
+
+ if (sid_exists_and_matches == false) {
+ secrets_clear_domain_protection(dom_info->name);
+ ret = secrets_store_domain_sid(dom_info->name,
+ &dom_info->sid);
+ ret &= secrets_mark_domain_protected(dom_info->name);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+ ret = secrets_fetch_domain_guid(dom_info->name, &stored_guid);
+ if (ret) {
+ if (GUID_equal(&stored_guid, &dom_info->guid)) {
+ guid_exists_and_matches = true;
+ }
+ }
+
+ if (guid_exists_and_matches == false) {
+ secrets_clear_domain_protection(dom_info->name);
+ ret = secrets_store_domain_guid(dom_info->name,
+ &dom_info->guid);
+ ret &= secrets_mark_domain_protected(dom_info->name);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+done:
+ TALLOC_FREE(dom_info);
+ if (!ret) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_init_samba_dsdb(struct pdb_methods **pdb_method,
+ const char *location)
+{
+ struct pdb_methods *m;
+ struct pdb_samba_dsdb_state *state;
+ NTSTATUS status;
+ char *errstring = NULL;
+ int ret;
+
+ if ( !NT_STATUS_IS_OK(status = make_pdb_method( &m )) ) {
+ return status;
+ }
+
+ state = talloc_zero(m, struct pdb_samba_dsdb_state);
+ if (state == NULL) {
+ goto nomem;
+ }
+ m->private_data = state;
+ m->free_private_data = free_private_data;
+ pdb_samba_dsdb_init_methods(m);
+
+ state->ev = s4_event_context_init(state);
+ if (!state->ev) {
+ DEBUG(0, ("s4_event_context_init failed\n"));
+ goto nomem;
+ }
+
+ state->lp_ctx = loadparm_init_s3(state, loadparm_s3_helpers());
+ if (state->lp_ctx == NULL) {
+ DEBUG(0, ("loadparm_init_s3 failed\n"));
+ goto nomem;
+ }
+
+ if (location == NULL) {
+ location = "sam.ldb";
+ }
+
+ ret = samdb_connect_url(state,
+ state->ev,
+ state->lp_ctx,
+ system_session(state->lp_ctx),
+ 0,
+ location,
+ NULL,
+ &state->ldb,
+ &errstring);
+
+ if (!state->ldb) {
+ DEBUG(0, ("samdb_connect failed: %s: %s\n",
+ errstring, ldb_strerror(ret)));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ state->idmap_ctx = idmap_init(state, state->ev,
+ state->lp_ctx);
+ if (!state->idmap_ctx) {
+ DEBUG(0, ("idmap failed\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ status = pdb_samba_dsdb_init_secrets(m);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("pdb_samba_dsdb_init_secrets failed!\n"));
+ goto fail;
+ }
+
+ *pdb_method = m;
+ return NT_STATUS_OK;
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+fail:
+ TALLOC_FREE(m);
+ return status;
+}
+
+NTSTATUS pdb_samba_dsdb_init(TALLOC_CTX *);
+NTSTATUS pdb_samba_dsdb_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "samba_dsdb",
+ pdb_init_samba_dsdb);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "samba4",
+ pdb_init_samba_dsdb);
+}
diff --git a/source3/passdb/pdb_secrets.c b/source3/passdb/pdb_secrets.c
new file mode 100644
index 0000000..2e98305
--- /dev/null
+++ b/source3/passdb/pdb_secrets.c
@@ -0,0 +1,172 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+#include "passdb.h"
+#include "passdb/pdb_secrets.h"
+#include "librpc/gen_ndr/ndr_secrets.h"
+#include "secrets.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "../libcli/security/security.h"
+#include "util_tdb.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/**
+ * Get trusted domains info from secrets.tdb.
+ **/
+
+struct list_trusted_domains_state {
+ uint32_t num_domains;
+ struct trustdom_info **domains;
+};
+
+static int list_trusted_domain(struct db_record *rec, void *private_data)
+{
+ const size_t prefix_len = strlen(SECRETS_DOMTRUST_ACCT_PASS);
+ struct TRUSTED_DOM_PASS pass;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct trustdom_info *dom_info;
+ TDB_DATA key;
+ TDB_DATA value;
+
+ struct list_trusted_domains_state *state =
+ (struct list_trusted_domains_state *)private_data;
+
+ key = dbwrap_record_get_key(rec);
+ value = dbwrap_record_get_value(rec);
+
+ if ((key.dsize < prefix_len)
+ || (strncmp((char *)key.dptr, SECRETS_DOMTRUST_ACCT_PASS,
+ prefix_len) != 0)) {
+ return 0;
+ }
+
+ blob = data_blob_const(value.dptr, value.dsize);
+
+ ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &pass,
+ (ndr_pull_flags_fn_t)ndr_pull_TRUSTED_DOM_PASS);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ if (pass.domain_sid.num_auths != 4) {
+ struct dom_sid_buf buf;
+ DEBUG(0, ("SID %s is not a domain sid, has %d "
+ "auths instead of 4\n",
+ dom_sid_str_buf(&pass.domain_sid, &buf),
+ pass.domain_sid.num_auths));
+ return 0;
+ }
+
+ if (!(dom_info = talloc(state->domains, struct trustdom_info))) {
+ DEBUG(0, ("talloc failed\n"));
+ return 0;
+ }
+
+ dom_info->name = talloc_strdup(dom_info, pass.uni_name);
+ if (!dom_info->name) {
+ TALLOC_FREE(dom_info);
+ return 0;
+ }
+
+ sid_copy(&dom_info->sid, &pass.domain_sid);
+
+ ADD_TO_ARRAY(state->domains, struct trustdom_info *, dom_info,
+ &state->domains, &state->num_domains);
+
+ if (state->domains == NULL) {
+ state->num_domains = 0;
+ return -1;
+ }
+ return 0;
+}
+
+NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32_t *num_domains,
+ struct trustdom_info ***domains)
+{
+ struct list_trusted_domains_state state;
+ struct db_context *db_ctx;
+
+ if (!secrets_init()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ db_ctx = secrets_db_ctx();
+
+ state.num_domains = 0;
+
+ /*
+ * Make sure that a talloc context for the trustdom_info structs
+ * exists
+ */
+
+ if (!(state.domains = talloc_array(
+ mem_ctx, struct trustdom_info *, 1))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dbwrap_traverse_read(db_ctx, list_trusted_domain, (void *)&state, NULL);
+
+ *num_domains = state.num_domains;
+ *domains = state.domains;
+ return NT_STATUS_OK;
+}
+
+/* In order to avoid direct linking against libsecrets for pdb modules
+ * following helpers are provided for pdb module writers.
+ * To differentiate them from pdb_* API, they are prefixed by PDB upper case
+ */
+bool PDB_secrets_store_domain_sid(const char *domain, const struct dom_sid *sid)
+{
+ return secrets_store_domain_sid(domain, sid);
+}
+
+bool PDB_secrets_mark_domain_protected(const char *domain)
+{
+ return secrets_mark_domain_protected(domain);
+}
+
+bool PDB_secrets_clear_domain_protection(const char *domain)
+{
+ return secrets_clear_domain_protection(domain);
+}
+
+bool PDB_secrets_fetch_domain_sid(const char *domain, struct dom_sid *sid)
+{
+ return secrets_fetch_domain_sid(domain, sid);
+}
+
+bool PDB_secrets_store_domain_guid(const char *domain, struct GUID *guid)
+{
+ return secrets_store_domain_guid(domain, guid);
+}
+
+bool PDB_secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
+{
+ return secrets_fetch_domain_guid(domain, guid);
+}
diff --git a/source3/passdb/pdb_secrets.h b/source3/passdb/pdb_secrets.h
new file mode 100644
index 0000000..d9b1ace
--- /dev/null
+++ b/source3/passdb/pdb_secrets.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PASSDB_PDB_SECRETS_H_
+#define _PASSDB_PDB_SECRETS_H_
+
+/* The following definitions come from passdb/pdb_secrets.c */
+
+NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32_t *num_domains,
+ struct trustdom_info ***domains);
+
+#endif /* _PASSDB_PDB_SECRETS_H_ */
diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c
new file mode 100644
index 0000000..adeb0e3
--- /dev/null
+++ b/source3/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1750 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001,2003
+ * Modified by Andrew Bartlett 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "passdb.h"
+#include "system/passwd.h"
+#include "system/filesys.h"
+#include "../librpc/gen_ndr/samr.h"
+#include "../libcli/security/security.h"
+#include "passdb/pdb_smbpasswd.h"
+#include "lib/util/string_wrappers.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+/*
+ smb_passwd is analogous to sam_passwd used everywhere
+ else. However, smb_passwd is limited to the information
+ stored by an smbpasswd entry
+ */
+
+struct smb_passwd
+{
+ uint32_t smb_userid; /* this is actually the unix uid_t */
+ const char *smb_name; /* username string */
+
+ const unsigned char *smb_passwd; /* Null if no password */
+ const unsigned char *smb_nt_passwd; /* Null if no password */
+
+ uint16_t acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ time_t pass_last_set_time; /* password last set time */
+};
+
+struct smbpasswd_privates
+{
+ /* used for maintain locks on the smbpasswd file */
+ int pw_file_lock_depth;
+
+ /* Global File pointer */
+ FILE *pw_file;
+
+ /* formerly static variables */
+ struct smb_passwd pw_buf;
+ fstring user_name;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+ /* retrieve-once info */
+ const char *smbpasswd_file;
+};
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(int signum)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ Lock or unlock a fd for a known lock type. Abandon after waitsecs
+ seconds.
+****************************************************************/
+
+static bool do_file_lock(int fd, int waitsecs, int type)
+{
+ struct flock lock;
+ int ret;
+ void (*oldsig_handler)(int);
+
+ gotalarm = 0;
+ oldsig_handler = CatchSignal(SIGALRM, gotalarm_sig);
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ lock.l_pid = 0;
+
+ alarm(waitsecs);
+ /* Note we must *NOT* use sys_fcntl here ! JRA */
+ ret = fcntl(fd, F_SETLKW, &lock);
+ alarm(0);
+ CatchSignal(SIGALRM, oldsig_handler);
+
+ if (gotalarm && ret == -1) {
+ DEBUG(0, ("do_file_lock: failed to %s file.\n",
+ type == F_UNLCK ? "unlock" : "lock"));
+ return False;
+ }
+
+ return (ret == 0);
+}
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static bool pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0) {
+ return False;
+ }
+
+ if(*plock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ (*plock_depth)++;
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static bool pw_file_unlock(int fd, int *plock_depth)
+{
+ bool ret=True;
+
+ if (fd == 0 || *plock_depth == 0) {
+ return True;
+ }
+
+ if(*plock_depth == 1) {
+ ret = do_file_lock(fd, 5, F_UNLCK);
+ }
+
+ if (*plock_depth > 0) {
+ (*plock_depth)--;
+ }
+
+ if(!ret) {
+ DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ }
+ return ret;
+}
+
+/**************************************************************
+ Initialize a smb_passwd struct
+ *************************************************************/
+
+static void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL)
+ return;
+ ZERO_STRUCTP (user);
+
+ user->pass_last_set_time = (time_t)0;
+}
+
+/***************************************************************
+ Internal fn to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module. Checks for atomic
+ rename of smbpasswd file on update or create once the lock has
+ been granted to prevent race conditions. JRA.
+****************************************************************/
+
+static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
+{
+ FILE *fp = NULL;
+ const char *open_mode = NULL;
+ int race_loop = 0;
+ int lock_type = F_RDLCK;
+ struct stat st;
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+
+ switch(type) {
+ case PWF_READ:
+ open_mode = "rb";
+ lock_type = F_RDLCK;
+ break;
+ case PWF_UPDATE:
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ case PWF_CREATE:
+ /*
+ * Ensure atomic file creation.
+ */
+ {
+ int i, fd = -1;
+
+ for(i = 0; i < 5; i++) {
+ if((fd = open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) {
+ break;
+ }
+ usleep(200); /* Spin, spin... */
+ }
+ if(fd == -1) {
+ DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
+creating file %s\n", pfile));
+ return NULL;
+ }
+ close(fd);
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ }
+ default:
+ DEBUG(10, ("Invalid open mode: %d\n", type));
+ return NULL;
+ }
+
+ for(race_loop = 0; race_loop < 5; race_loop++) {
+ DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+ if((fp = fopen(pfile, open_mode)) == NULL) {
+
+ /*
+ * If smbpasswd file doesn't exist, then create new one. This helps to avoid
+ * confusing error msg when adding user account first time.
+ */
+ if (errno == ENOENT) {
+ if ((fp = fopen(pfile, "a+")) != NULL) {
+ DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. File successfully created.\n", pfile));
+ } else {
+ DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. Couldn't create new one. Error was: %s\n",
+ pfile, strerror(errno)));
+ return NULL;
+ }
+ } else {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
+Error was: %s\n", pfile, strerror(errno)));
+ return NULL;
+ }
+ }
+
+ if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
+Error was %s\n", pfile, strerror(errno) ));
+ fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Only check for replacement races on update or create.
+ * For read we don't mind if the data is one record out of date.
+ */
+
+ if(type == PWF_READ) {
+ break;
+ } else {
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ /*
+ * Avoid the potential race condition between the open and the lock
+ * by doing a stat on the filename and an fstat on the fd. If the
+ * two inodes differ then someone did a rename between the open and
+ * the lock. Back off and try the open again. Only do this 5 times to
+ * prevent infinite loops. JRA.
+ */
+
+ if (sys_stat(pfile, &sbuf1, false) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (sys_fstat(fileno(fp), &sbuf2, false) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if( sbuf1.st_ex_ino == sbuf2.st_ex_ino) {
+ /* No race. */
+ break;
+ }
+
+ /*
+ * Race occurred - back off and try again...
+ */
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ }
+ }
+
+ if(race_loop == 5) {
+ DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+ /* Ensure we have a valid stat. */
+ if (fstat(fileno(fp), &st) != 0) {
+ DBG_ERR("Unable to fstat file %s. Error was %s\n",
+ pfile,
+ strerror(errno));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* If file has invalid permissions != 0600, then [f]chmod(). */
+ if ((st.st_mode & 0777) != (S_IRUSR|S_IWUSR)) {
+ DBG_WARNING("file %s has invalid permissions 0%o should "
+ "be 0600.\n",
+ pfile,
+ (unsigned int)st.st_mode & 0777);
+ /* Make sure it is only rw by the owner */
+#ifdef HAVE_FCHMOD
+ if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+#else
+ if (chmod(pfile, S_IRUSR|S_IWUSR) == -1) {
+#endif
+ DBG_ERR("Failed to set 0600 permissions on password file %s. "
+ "Error was %s\n.",
+ pfile,
+ strerror(errno));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+ }
+
+ /* We have a lock on the file. */
+ return fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+
+static void endsmbfilepwent(FILE *fp, int *lock_depth)
+{
+ if (!fp) {
+ return;
+ }
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+
+static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
+{
+ /* Static buffers we will return. */
+ struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
+ char *user_name = smbpasswd_state->user_name;
+ unsigned char *smbpwd = smbpasswd_state->smbpwd;
+ unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
+ char linebuf[256];
+ unsigned char *p;
+ long uidval;
+ size_t linebuf_len;
+ char *status;
+
+ if(fp == NULL) {
+ DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pdb_init_smb(pw_buf);
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ status = linebuf;
+ while (status && !feof(fp)) {
+ linebuf[0] = '\0';
+
+ status = fgets(linebuf, 256, fp);
+ if (status == NULL && ferror(fp)) {
+ return NULL;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ if ((linebuf_len = strlen(linebuf)) == 0) {
+ continue;
+ }
+
+ if (linebuf[linebuf_len - 1] != '\n') {
+ while (!ferror(fp) && !feof(fp)) {
+ int c;
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ * [Account type] is an ascii encoding of the type of account.
+ * LCT-(8 hex digits) is the time_t value of the last change time.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+ continue;
+ }
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+
+ p++; /* Go past ':' */
+
+ if(*p == '-') {
+ DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name));
+ continue;
+ }
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
+ user_name));
+ continue;
+ }
+
+ uidval = atoi((char *) p);
+
+ while (*p && isdigit(*p)) {
+ p++;
+ }
+
+ if (*p != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
+ user_name));
+ continue;
+ }
+
+ pw_buf->smb_name = user_name;
+ pw_buf->smb_userid = uidval;
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+
+ /* Skip the ':' */
+ p++;
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
+ user_name ));
+ continue;
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
+ user_name));
+ continue;
+ }
+
+ if (strnequal((char *) p, "NO PASSWORD", 11)) {
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (*p == '*' || *p == 'X') {
+ /* NULL LM password */
+ pw_buf->smb_passwd = NULL;
+ DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
+ } else if (pdb_gethexpwd((char *)p, smbpwd)) {
+ pw_buf->smb_passwd = smbpwd;
+ } else {
+ pw_buf->smb_passwd = NULL;
+ DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
+(non hex chars)\n", user_name));
+ }
+ }
+
+ /*
+ * Now check if the NT compatible password is
+ * available.
+ */
+ pw_buf->smb_nt_passwd = NULL;
+ p += 33; /* Move to the first character of the line after the lanman password. */
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if(pdb_gethexpwd((char *)p,smbntpwd)) {
+ pw_buf->smb_nt_passwd = smbntpwd;
+ }
+ }
+ p += 33; /* Move to the first character of the line after the NT password. */
+ }
+
+ DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+ user_name, uidval));
+
+ if (*p == '[') {
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+ pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+ /* Must have some account type set. */
+ if(pw_buf->acct_ctrl == 0) {
+ pw_buf->acct_ctrl = ACB_NORMAL;
+ }
+
+ /* Now try and get the last change time. */
+ if(end_p) {
+ p = end_p + 1;
+ }
+ if(*p == ':') {
+ p++;
+ if(*p && (strncasecmp_m((char *)p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) {
+ break;
+ }
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
+ pw_buf->acct_ctrl &= ~ACB_NORMAL;
+ pw_buf->acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ return pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Create a new smbpasswd entry - malloced space returned.
+*************************************************************************/
+
+static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
+{
+ int new_entry_length;
+ char *new_entry;
+ char *p;
+
+ new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 +
+ NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
+
+ if((new_entry = (char *)SMB_MALLOC( new_entry_length )) == NULL) {
+ DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
+ newpwd->smb_name ));
+ return NULL;
+ }
+
+ slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
+
+ p = new_entry+strlen(new_entry);
+ pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
+ p+=strlen(p);
+ *p = ':';
+ p++;
+
+ pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+ p+=strlen(p);
+ *p = ':';
+ p++;
+
+ /* Add the account encoding and the last change time. */
+ slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
+ pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32_t)newpwd->pass_last_set_time);
+
+ return new_entry;
+}
+
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static NTSTATUS add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state,
+ struct smb_passwd *newpwd)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ int wr_len;
+ int fd;
+ size_t new_entry_length;
+ char *new_entry;
+ off_t offpos;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth);
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth);
+ }
+
+ if (fp == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+ return map_nt_error_from_unix(errno);
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ if (strequal(newpwd->smb_name, pwd->smb_name)) {
+ DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_USER_EXISTS;
+ }
+ }
+
+ /* Ok - entry doesn't exist. We can add it */
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ /*
+ * The add user write needs to be atomic - so get the fd from
+ * the fp and do a raw write() call.
+ */
+ fd = fileno(fp);
+
+ if((offpos = lseek(fd, 0, SEEK_END)) == -1) {
+ NTSTATUS result = map_nt_error_from_unix(errno);
+ DEBUG(0, ("add_smbfilepwd_entry(lseek): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return result;
+ }
+
+ if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
+ fd, (int)new_entry_length, new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) {
+ NTSTATUS result = map_nt_error_from_unix(errno);
+ DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
+Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
+
+ /* Remove the entry we just wrote. */
+ if(ftruncate(fd, offpos) == -1) {
+ DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ newpwd->smb_name, strerror(errno)));
+ }
+
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ free(new_entry);
+ return result;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return NT_STATUS_OK;
+}
+
+/************************************************************************
+ Routine to search the smbpasswd file for an entry matching the username.
+ and then modify its password entry. We can't use the startsmbpwent()/
+ getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+************************************************************************/
+
+static bool mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
+{
+ /* Static buffers we will return. */
+ fstring user_name;
+
+ char *status;
+#define LINEBUF_SIZE 255
+ char linebuf[LINEBUF_SIZE + 1];
+ char readbuf[1024];
+ char ascii_p16[FSTRING_LEN + 20];
+ fstring encode_bits;
+ unsigned char *p = NULL;
+ size_t linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ bool found_entry = False;
+ bool got_pass_last_set_time = False;
+
+ off_t pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile) {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+ fp = fopen(pfile, "r+");
+
+ if (fp == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ lockfd = fileno(fp);
+
+ if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ status = linebuf;
+ while (status && !feof(fp)) {
+ pwd_seekpos = ftell(fp);
+
+ linebuf[0] = '\0';
+
+ status = fgets(linebuf, LINEBUF_SIZE, fp);
+ if (status == NULL && ferror(fp)) {
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n') {
+ while (!ferror(fp) && !feof(fp)) {
+ int c;
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+
+ if (p == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name)) {
+ found_entry = True;
+ break;
+ }
+ }
+
+ if (!found_entry) {
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+
+ DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
+ pwd->smb_name));
+ return False;
+ }
+
+ DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ while (*p && isdigit(*p)) {
+ p++;
+ }
+ if (*p != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+ p++;
+
+ /* Record exact password position */
+ pwd_seekpos += PTR_DIFF(p, linebuf);
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Now check if the NT compatible password is available. */
+ p += 33; /* Move to the first character of the line after the lanman password. */
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+ pwd->smb_name));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+ p += 33; /* Move to the first character of the line after the NT password. */
+
+ if (*p == '[') {
+ i = 0;
+ encode_bits[i++] = *p++;
+ while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) {
+ encode_bits[i++] = *p++;
+ }
+
+ encode_bits[i++] = ']';
+ encode_bits[i++] = '\0';
+
+ if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ } else {
+ DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format for user %s. \
+This is no longer supported.!\n", pwd->smb_name));
+ DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
+ pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Go past the ']' */
+ if(linebuf_len > PTR_DIFF(p, linebuf)) {
+ p++;
+ }
+
+ if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+ p++;
+
+ /* We should be pointing at the LCT entry. */
+ if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (strncasecmp_m((char *)p, "LCT-", 4) == 0)) {
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) {
+ break;
+ }
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* *p && strncasecmp_m() */
+ } /* p == ':' */
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+ /* Create the 32 byte representation of the new p16 */
+ pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
+
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ wr_len = 66;
+ pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
+ ascii_p16[65] = ':';
+ ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+ /* Add on the account info bits and the time of last password change. */
+ if(got_pass_last_set_time) {
+ slprintf(&ascii_p16[strlen(ascii_p16)],
+ sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+ "%s:LCT-%08X:",
+ encode_bits, (uint32_t)pwd->pass_last_set_time );
+ wr_len = strlen(ascii_p16);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbfilepwd_entry: "));
+ dump_data(100, (uint8_t *)ascii_p16, wr_len);
+#endif
+
+ if(wr_len > LINEBUF_SIZE) {
+ DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ /*
+ * Do an atomic write into the file at the position defined by
+ * seekpos.
+ */
+
+ /* The mod user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+
+ fd = fileno(fp);
+
+ if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Sanity check - ensure the areas we are writing are framed by ':' */
+ if (read(fd, linebuf, wr_len+1) != wr_len+1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
+ DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (write(fd, ascii_p16, wr_len) != wr_len) {
+ DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static bool del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
+{
+ const char *pfile = smbpasswd_state->smbpasswd_file;
+ char *pfile2 = NULL;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ FILE *fp_write = NULL;
+ int pfile2_lockdepth = 0;
+
+ pfile2 = talloc_asprintf(talloc_tos(),
+ "%s.%u",
+ pfile, (unsigned)getpid());
+ if (!pfile2) {
+ return false;
+ }
+
+ /*
+ * Open the smbpassword file - for update. It needs to be update
+ * as we need any other processes to wait until we have replaced
+ * it.
+ */
+
+ if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ return False;
+ }
+
+ /*
+ * Create the replacement password file.
+ */
+ if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ char *new_entry;
+ size_t new_entry_length;
+
+ if (strequal(name, pwd->smb_name)) {
+ DEBUG(10, ("del_smbfilepwd_entry: found entry with "
+ "name %s - deleting it.\n", name));
+ continue;
+ }
+
+ /*
+ * We need to copy the entry out into the second file.
+ */
+
+ if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+ if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) {
+ DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ }
+
+ /*
+ * Ensure pfile2 is flushed before rename.
+ */
+
+ if(fflush(fp_write) != 0) {
+ DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return False;
+ }
+
+ /*
+ * Do an atomic rename - then release the locks.
+ */
+
+ if(rename(pfile2,pfile) != 0) {
+ unlink(pfile2);
+ }
+
+ endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return True;
+}
+
+/*********************************************************************
+ Create a smb_passwd struct from a struct samu.
+ We will not allocate any new memory. The smb_passwd struct
+ should only stay around as long as the struct samu does.
+ ********************************************************************/
+
+static bool build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
+{
+ uint32_t rid;
+
+ if (sampass == NULL)
+ return False;
+ ZERO_STRUCTP(smb_pw);
+
+ if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
+ rid = pdb_get_user_rid(sampass);
+
+ /* If the user specified a RID, make sure its able to be both stored and retrieved */
+ if (rid == DOMAIN_RID_GUEST) {
+ struct passwd *passwd = Get_Pwnam_alloc(NULL, lp_guest_account());
+ if (!passwd) {
+ DEBUG(0, ("Could not find guest account via Get_Pwnam_alloc()! (%s)\n", lp_guest_account()));
+ return False;
+ }
+ smb_pw->smb_userid=passwd->pw_uid;
+ TALLOC_FREE(passwd);
+ } else if (algorithmic_pdb_rid_is_user(rid)) {
+ smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
+ } else {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
+ return False;
+ }
+ }
+
+ smb_pw->smb_name=(const char*)pdb_get_username(sampass);
+
+ smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
+ smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
+
+ smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
+ smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
+
+ return True;
+}
+
+/*********************************************************************
+ Create a struct samu from a smb_passwd struct
+ ********************************************************************/
+
+static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state,
+ struct samu *sam_pass, const struct smb_passwd *pw_buf)
+{
+ struct passwd *pwfile;
+
+ if ( !sam_pass ) {
+ DEBUG(5,("build_sam_account: struct samu is NULL\n"));
+ return False;
+ }
+
+ /* verify the user account exists */
+
+ if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
+ DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid "
+ "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
+ return False;
+ }
+
+ if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
+ return False;
+
+ TALLOC_FREE(pwfile);
+
+ /* set remaining fields */
+
+ if (!pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET))
+ return False;
+ if (!pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET))
+ return False;
+ pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
+ pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
+ pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
+
+ return True;
+}
+
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+
+/****************************************************************
+ Search smbpasswd file by iterating over the entries. Do not
+ call getpwnam() for unix account information until we have found
+ the correct entry
+ ***************************************************************/
+
+static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
+ struct samu *sam_acct, const char *username)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd *smb_pw;
+ FILE *fp = NULL;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
+
+ /* startsmbfilepwent() is used here as we don't want to lookup
+ the UNIX account in the local system password file until
+ we have a match. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("Unable to open passdb database.\n"));
+ return nt_status;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return nt_status;
+
+ DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
+ return nt_status;
+ }
+
+ /* now build the struct samu */
+ if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
+ return nt_status;
+
+ /* success */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const struct dom_sid *sid)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd *smb_pw;
+ struct dom_sid_buf buf;
+ FILE *fp = NULL;
+ uint32_t rid;
+
+ DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
+ dom_sid_str_buf(sid, &buf)));
+
+ if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /* More special case 'guest account' hacks... */
+ if (rid == DOMAIN_RID_GUEST) {
+ const char *guest_account = lp_guest_account();
+ if (!(guest_account && *guest_account)) {
+ DEBUG(1, ("Guest account not specified!\n"));
+ return nt_status;
+ }
+ return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account);
+ }
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
+
+ if (fp == NULL) {
+ DEBUG(0, ("Unable to open passdb database.\n"));
+ return nt_status;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return nt_status;
+
+ DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
+ return nt_status;
+ }
+
+ /* now build the struct samu */
+ if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
+ return nt_status;
+
+ /* build_sam_account might change the SID on us, if the name was for the guest account */
+ if (NT_STATUS_IS_OK(nt_status) && !dom_sid_equal(pdb_get_user_sid(sam_acct), sid)) {
+ struct dom_sid_buf buf1, buf2;
+ DEBUG(1, ("looking for user with sid %s instead returned %s "
+ "for account %s!?!\n",
+ dom_sid_str_buf(sid, &buf1),
+ dom_sid_str_buf(pdb_get_user_sid(sam_acct), &buf2),
+ pdb_get_username(sam_acct)));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* success */
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the struct samu */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* add the entry */
+ return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
+}
+
+static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+ struct smb_passwd smb_pw;
+
+ /* convert the struct samu */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
+ DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
+{
+ struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
+
+ const char *username = pdb_get_username(sampass);
+
+ if (del_smbfilepwd_entry(smbpasswd_state, username))
+ return NT_STATUS_OK;
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ char *rename_script = NULL;
+ struct samu *new_acct = NULL;
+ bool interim_account = False;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if (!*(lp_rename_user_script(talloc_tos(), lp_sub)))
+ goto done;
+
+ if ( !(new_acct = samu_new( NULL )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( !pdb_copy_sam_account( new_acct, old_acct )
+ || !pdb_set_username(new_acct, newname, PDB_CHANGED))
+ {
+ goto done;
+ }
+
+ ret = smbpasswd_add_sam_account(my_methods, new_acct);
+ if (!NT_STATUS_IS_OK(ret))
+ goto done;
+
+ interim_account = True;
+
+ /* rename the posix user */
+ rename_script = lp_rename_user_script(ctx, lp_sub);
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (*rename_script) {
+ int rename_ret;
+
+ rename_script = talloc_string_sub2(ctx,
+ rename_script,
+ "%unew",
+ newname,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ rename_script = talloc_string_sub2(ctx,
+ rename_script,
+ "%uold",
+ pdb_get_username(old_acct),
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ rename_ret = smbrun(rename_script, NULL, NULL);
+
+ DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
+
+ if (rename_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+
+ if (rename_ret)
+ goto done;
+ } else {
+ goto done;
+ }
+
+ smbpasswd_delete_sam_account(my_methods, old_acct);
+ interim_account = False;
+
+done:
+ /* cleanup */
+ if (interim_account)
+ smbpasswd_delete_sam_account(my_methods, new_acct);
+
+ if (new_acct)
+ TALLOC_FREE(new_acct);
+
+ return (ret);
+}
+
+static uint32_t smbpasswd_capabilities(struct pdb_methods *methods)
+{
+ return 0;
+}
+
+static void free_private_data(void **vp)
+{
+ struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
+
+ endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
+
+ *privates = NULL;
+ /* No need to free any further, as it is talloc()ed */
+}
+
+struct smbpasswd_search_state {
+ uint32_t acct_flags;
+
+ struct samr_displayentry *entries;
+ uint32_t num_entries;
+ ssize_t array_size;
+ uint32_t current;
+};
+
+static void smbpasswd_search_end(struct pdb_search *search)
+{
+ struct smbpasswd_search_state *state = talloc_get_type_abort(
+ search->private_data, struct smbpasswd_search_state);
+ TALLOC_FREE(state);
+}
+
+static bool smbpasswd_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct smbpasswd_search_state *state = talloc_get_type_abort(
+ search->private_data, struct smbpasswd_search_state);
+
+ if (state->current == state->num_entries) {
+ return false;
+ }
+
+ entry->idx = state->entries[state->current].idx;
+ entry->rid = state->entries[state->current].rid;
+ entry->acct_flags = state->entries[state->current].acct_flags;
+
+ entry->account_name = talloc_strdup(
+ search, state->entries[state->current].account_name);
+ entry->fullname = talloc_strdup(
+ search, state->entries[state->current].fullname);
+ entry->description = talloc_strdup(
+ search, state->entries[state->current].description);
+
+ if ((entry->account_name == NULL) || (entry->fullname == NULL)
+ || (entry->description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return false;
+ }
+
+ state->current += 1;
+ return true;
+}
+
+static bool smbpasswd_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32_t acct_flags)
+{
+ struct smbpasswd_privates *smbpasswd_state =
+ (struct smbpasswd_privates*)methods->private_data;
+
+ struct smbpasswd_search_state *search_state;
+ struct smb_passwd *pwd;
+ FILE *fp;
+
+ search_state = talloc_zero(search, struct smbpasswd_search_state);
+ if (search_state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ search_state->acct_flags = acct_flags;
+
+ fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ,
+ &smbpasswd_state->pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(10, ("Unable to open smbpasswd file.\n"));
+ TALLOC_FREE(search_state);
+ return false;
+ }
+
+ while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+ struct samr_displayentry entry;
+ struct samu *user;
+
+ if ((acct_flags != 0)
+ && ((acct_flags & pwd->acct_ctrl) == 0)) {
+ continue;
+ }
+
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0, ("samu_new failed\n"));
+ break;
+ }
+
+ if (!build_sam_account(smbpasswd_state, user, pwd)) {
+ /* Already got debug msgs... */
+ break;
+ }
+
+ ZERO_STRUCT(entry);
+
+ entry.acct_flags = pdb_get_acct_ctrl(user);
+ sid_peek_rid(pdb_get_user_sid(user), &entry.rid);
+ entry.account_name = talloc_strdup(
+ search_state, pdb_get_username(user));
+ entry.fullname = talloc_strdup(
+ search_state, pdb_get_fullname(user));
+ entry.description = talloc_strdup(
+ search_state, pdb_get_acct_desc(user));
+
+ TALLOC_FREE(user);
+
+ if ((entry.account_name == NULL) || (entry.fullname == NULL)
+ || (entry.description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ break;
+ }
+
+ ADD_TO_LARGE_ARRAY(search_state, struct samr_displayentry,
+ entry, &search_state->entries,
+ &search_state->num_entries,
+ &search_state->array_size);
+ }
+
+ endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+ search->private_data = search_state;
+ search->next_entry = smbpasswd_search_next_entry;
+ search->search_end = smbpasswd_search_end;
+
+ return true;
+}
+
+static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
+{
+ NTSTATUS nt_status;
+ struct smbpasswd_privates *privates;
+
+ if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "smbpasswd";
+
+ (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
+ (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
+ (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
+ (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
+ (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
+ (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
+ (*pdb_method)->search_users = smbpasswd_search_users;
+
+ (*pdb_method)->capabilities = smbpasswd_capabilities;
+
+ /* Setup private data and free function */
+
+ if ( !(privates = talloc_zero( *pdb_method, struct smbpasswd_privates )) ) {
+ DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Store some config details */
+
+ if (location) {
+ privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
+ } else {
+ privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
+ }
+
+ if (!privates->smbpasswd_file) {
+ DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*pdb_method)->private_data = privates;
+
+ (*pdb_method)->free_private_data = free_private_data;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_smbpasswd_init(TALLOC_CTX *ctx)
+{
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd);
+}
diff --git a/source3/passdb/pdb_smbpasswd.h b/source3/passdb/pdb_smbpasswd.h
new file mode 100644
index 0000000..5dd7c8c
--- /dev/null
+++ b/source3/passdb/pdb_smbpasswd.h
@@ -0,0 +1,30 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001,2003
+ * Modified by Andrew Bartlett 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PASSDB_PDB_SMBPASSWD_H_
+#define _PASSDB_PDB_SMBPASSWD_H_
+
+/* The following definitions come from passdb/pdb_smbpasswd.c */
+
+NTSTATUS pdb_smbpasswd_init(TALLOC_CTX *) ;
+
+#endif /* _PASSDB_PDB_SMBPASSWD_H_ */
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
new file mode 100644
index 0000000..f9ba193
--- /dev/null
+++ b/source3/passdb/pdb_tdb.c
@@ -0,0 +1,1369 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000-2003
+ * Copyright (C) Gerald Carter 2000-2006
+ * Copyright (C) Jeremy Allison 2001-2009
+ * Copyright (C) Andrew Bartlett 2002
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "passdb.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "../libcli/security/security.h"
+#include "util_tdb.h"
+#include "passdb/pdb_tdb.h"
+#include "lib/util/smb_strtox.h"
+#include "lib/util/string_wrappers.h"
+
+#if 0 /* when made a module use this */
+
+static int tdbsam_debug_level = DBGC_ALL;
+#undef DBGC_CLASS
+#define DBGC_CLASS tdbsam_debug_level
+
+#else
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+#endif
+
+#define TDBSAM_VERSION 4 /* Most recent TDBSAM version */
+#define TDBSAM_MINOR_VERSION 0 /* Most recent TDBSAM minor version */
+#define TDBSAM_VERSION_STRING "INFO/version"
+#define TDBSAM_MINOR_VERSION_STRING "INFO/minor_version"
+#define PASSDB_FILE_NAME "passdb.tdb"
+#define USERPREFIX "USER_"
+#define USERPREFIX_LEN 5
+#define RIDPREFIX "RID_"
+#define PRIVPREFIX "PRIV_"
+#define NEXT_RID_STRING "NEXT_RID"
+
+/* GLOBAL TDB SAM CONTEXT */
+
+static struct db_context *db_sam;
+static char *tdbsam_filename;
+static bool map_builtin;
+
+struct tdbsam_convert_state {
+ int32_t from;
+ bool success;
+};
+
+static int tdbsam_convert_one(struct db_record *rec, void *priv)
+{
+ struct tdbsam_convert_state *state =
+ (struct tdbsam_convert_state *)priv;
+ struct samu *user;
+ TDB_DATA data;
+ NTSTATUS status;
+ bool ret;
+ TDB_DATA key;
+ TDB_DATA value;
+
+ key = dbwrap_record_get_key(rec);
+
+ if (key.dsize < USERPREFIX_LEN) {
+ return 0;
+ }
+ if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
+ return 0;
+ }
+
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
+ state->success = false;
+ return -1;
+ }
+
+ DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
+ "(version:%d)\n", (char *)key.dptr, state->from));
+
+ value = dbwrap_record_get_value(rec);
+
+ switch (state->from) {
+ case 0:
+ ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
+ (uint8_t *)value.dptr,
+ value.dsize);
+ break;
+ case 1:
+ ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
+ (uint8_t *)value.dptr,
+ value.dsize);
+ break;
+ case 2:
+ ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
+ (uint8_t *)value.dptr,
+ value.dsize);
+ break;
+ case 3:
+ ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
+ (uint8_t *)value.dptr,
+ value.dsize);
+ break;
+ case 4:
+ ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
+ (uint8_t *)value.dptr,
+ value.dsize);
+ break;
+ default:
+ /* unknown tdbsam version */
+ ret = False;
+ }
+ if (!ret) {
+ DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
+ "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
+ state->from));
+ TALLOC_FREE(user);
+ state->success = false;
+ return -1;
+ }
+
+ data.dsize = init_buffer_from_samu(&data.dptr, user, false);
+ TALLOC_FREE(user);
+
+ if (data.dsize == -1) {
+ DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
+ "the new format\n"));
+ state->success = false;
+ return -1;
+ }
+
+ status = dbwrap_record_store(rec, data, TDB_MODIFY);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not store the new record: %s\n",
+ nt_errstr(status)));
+ state->success = false;
+ return -1;
+ }
+
+ return 0;
+}
+
+/**********************************************************************
+ Struct and function to backup an old record.
+ *********************************************************************/
+
+struct tdbsam_backup_state {
+ struct db_context *new_db;
+ bool success;
+};
+
+static int backup_copy_fn(struct db_record *orig_rec, void *state)
+{
+ struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
+ struct db_record *new_rec;
+ NTSTATUS status;
+ TDB_DATA key;
+ TDB_DATA value;
+
+ key = dbwrap_record_get_key(orig_rec);
+
+ new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
+ if (new_rec == NULL) {
+ bs->success = false;
+ return 1;
+ }
+
+ value = dbwrap_record_get_value(orig_rec);
+
+ status = dbwrap_record_store(new_rec, value, TDB_INSERT);
+
+ TALLOC_FREE(new_rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ bs->success = false;
+ return 1;
+ }
+ return 0;
+}
+
+/**********************************************************************
+ Make a backup of an old passdb and replace the new one with it. We
+ have to do this as between 3.0.x and 3.2.x the hash function changed
+ by mistake (used unsigned char * instead of char *). This means the
+ previous simple update code will fail due to not being able to find
+ existing records to replace in the tdbsam_convert_one() function. JRA.
+ *********************************************************************/
+
+static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *tmp_fname = NULL;
+ struct db_context *tmp_db = NULL;
+ struct db_context *orig_db = *pp_db;
+ struct tdbsam_backup_state bs;
+ NTSTATUS status;
+
+ tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
+ if (!tmp_fname) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ unlink(tmp_fname);
+
+ /* Remember to open this on the NULL context. We need
+ * it to stay around after we return from here. */
+
+ tmp_db = db_open(NULL, tmp_fname, 0,
+ TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+ if (tmp_db == NULL) {
+ DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
+ "[%s]\n", tmp_fname));
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ if (dbwrap_transaction_start(orig_db) != 0) {
+ DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
+ unlink(tmp_fname);
+ TALLOC_FREE(tmp_db);
+ TALLOC_FREE(frame);
+ return false;
+ }
+ if (dbwrap_transaction_start(tmp_db) != 0) {
+ DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
+ dbwrap_transaction_cancel(orig_db);
+ unlink(tmp_fname);
+ TALLOC_FREE(tmp_db);
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ bs.new_db = tmp_db;
+ bs.success = true;
+
+ status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
+ goto cancel;
+ }
+
+ if (!bs.success) {
+ DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
+ goto cancel;
+ }
+
+ if (dbwrap_transaction_commit(orig_db) != 0) {
+ smb_panic("tdbsam_convert_backup: orig commit failed\n");
+ }
+ if (dbwrap_transaction_commit(tmp_db) != 0) {
+ smb_panic("tdbsam_convert_backup: orig commit failed\n");
+ }
+
+ /* be sure to close the DBs _before_ renaming the file */
+
+ TALLOC_FREE(orig_db);
+ TALLOC_FREE(tmp_db);
+
+ /* This is safe from other users as we know we're
+ * under a mutex here. */
+
+ if (rename(tmp_fname, dbname) == -1) {
+ DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
+ tmp_fname,
+ dbname,
+ strerror(errno)));
+ smb_panic("tdbsam_convert_backup: replace passdb failed\n");
+ }
+
+ TALLOC_FREE(frame);
+
+ /* re-open the converted TDB */
+
+ orig_db = db_open(NULL, dbname, 0,
+ TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+ if (orig_db == NULL) {
+ DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
+ "converted passdb TDB [%s]\n", dbname));
+ return false;
+ }
+
+ DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
+ dbname ));
+
+ /* Replace the global db pointer. */
+ *pp_db = orig_db;
+ return true;
+
+ cancel:
+
+ if (dbwrap_transaction_cancel(orig_db) != 0) {
+ smb_panic("tdbsam_convert: transaction_cancel failed");
+ }
+
+ if (dbwrap_transaction_cancel(tmp_db) != 0) {
+ smb_panic("tdbsam_convert: transaction_cancel failed");
+ }
+
+ unlink(tmp_fname);
+ TALLOC_FREE(tmp_db);
+ TALLOC_FREE(frame);
+ return false;
+}
+
+static bool tdbsam_upgrade_next_rid(struct db_context *db)
+{
+ TDB_CONTEXT *tdb;
+ uint32_t rid;
+ bool ok = false;
+ NTSTATUS status;
+ char *db_path;
+
+ status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
+ if (NT_STATUS_IS_OK(status)) {
+ return true;
+ }
+
+ db_path = state_path(talloc_tos(), "winbindd_idmap.tdb");
+ if (db_path == NULL) {
+ return false;
+ }
+
+ tdb = tdb_open_log(db_path, 0,
+ TDB_DEFAULT, O_RDONLY, 0644);
+ TALLOC_FREE(db_path);
+ if (tdb) {
+ ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
+ if (!ok) {
+ rid = BASE_RID;
+ }
+ tdb_close(tdb);
+ } else {
+ rid = BASE_RID;
+ }
+
+ status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32_t from)
+{
+ struct tdbsam_convert_state state;
+ struct db_context *db = NULL;
+ NTSTATUS status;
+
+ /* We only need the update backup for local db's. */
+ if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
+ DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
+ return false;
+ }
+
+ db = *pp_db;
+ state.from = from;
+ state.success = true;
+
+ if (dbwrap_transaction_start(db) != 0) {
+ DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
+ return false;
+ }
+
+ if (!tdbsam_upgrade_next_rid(db)) {
+ DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
+ goto cancel;
+ }
+
+ status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("tdbsam_convert: traverse failed\n"));
+ goto cancel;
+ }
+
+ if (!state.success) {
+ DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
+ goto cancel;
+ }
+
+ status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
+ TDBSAM_VERSION);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
+ "%s\n", nt_errstr(status)));
+ goto cancel;
+ }
+
+ status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
+ TDBSAM_MINOR_VERSION);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
+ "version: %s\n", nt_errstr(status)));
+ goto cancel;
+ }
+
+ if (dbwrap_transaction_commit(db) != 0) {
+ DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
+ return false;
+ }
+
+ return true;
+
+ cancel:
+ if (dbwrap_transaction_cancel(db) != 0) {
+ smb_panic("tdbsam_convert: transaction_cancel failed");
+ }
+
+ return false;
+}
+
+/*********************************************************************
+ Open the tdbsam file based on the absolute path specified.
+ Uses a reference count to allow multiple open calls.
+*********************************************************************/
+
+static bool tdbsam_open( const char *name )
+{
+ int32_t version;
+ int32_t minor_version;
+ NTSTATUS status;
+
+ /* check if we are already open */
+
+ if ( db_sam ) {
+ return true;
+ }
+
+ /* Try to open tdb passwd. Create a new one if necessary */
+
+ db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+ if (db_sam == NULL) {
+ DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
+ "[%s]\n", name));
+ return false;
+ }
+
+ /* Check the version */
+ status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
+ &version);
+ if (!NT_STATUS_IS_OK(status)) {
+ version = 0; /* Version not found, assume version 0 */
+ }
+
+ /* Get the minor version */
+ status = dbwrap_fetch_int32_bystring(
+ db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
+ if (!NT_STATUS_IS_OK(status)) {
+ minor_version = 0; /* Minor version not found, assume 0 */
+ }
+
+ /* Compare the version */
+ if (version > TDBSAM_VERSION) {
+ /* Version more recent than the latest known */
+ DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
+ TALLOC_FREE(db_sam);
+ return false;
+ }
+
+ if ( version < TDBSAM_VERSION ||
+ (version == TDBSAM_VERSION &&
+ minor_version < TDBSAM_MINOR_VERSION) ) {
+ /*
+ * Ok - we think we're going to have to convert.
+ * Due to the backup process we now must do to
+ * upgrade we have to get a mutex and re-check
+ * the version. Someone else may have upgraded
+ * whilst we were checking.
+ */
+
+ struct named_mutex *mtx = grab_named_mutex(NULL,
+ "tdbsam_upgrade_mutex",
+ 600);
+
+ if (!mtx) {
+ DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
+ TALLOC_FREE(db_sam);
+ return false;
+ }
+
+ /* Re-check the version */
+ status = dbwrap_fetch_int32_bystring(
+ db_sam, TDBSAM_VERSION_STRING, &version);
+ if (!NT_STATUS_IS_OK(status)) {
+ version = 0; /* Version not found, assume version 0 */
+ }
+
+ /* Re-check the minor version */
+ status = dbwrap_fetch_int32_bystring(
+ db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
+ if (!NT_STATUS_IS_OK(status)) {
+ minor_version = 0; /* Minor version not found, assume 0 */
+ }
+
+ /* Compare the version */
+ if (version > TDBSAM_VERSION) {
+ /* Version more recent than the latest known */
+ DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
+ TALLOC_FREE(db_sam);
+ TALLOC_FREE(mtx);
+ return false;
+ }
+
+ if ( version < TDBSAM_VERSION ||
+ (version == TDBSAM_VERSION &&
+ minor_version < TDBSAM_MINOR_VERSION) ) {
+ /*
+ * Note that minor versions we read that are greater
+ * than the current minor version we have hard coded
+ * are assumed to be compatible if they have the same
+ * major version. That allows previous versions of the
+ * passdb code that don't know about minor versions to
+ * still use this database. JRA.
+ */
+
+ DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
+ "version %d.%d.\n",
+ version,
+ minor_version,
+ TDBSAM_VERSION,
+ TDBSAM_MINOR_VERSION));
+
+ if ( !tdbsam_convert(&db_sam, name, version) ) {
+ DEBUG(0, ("tdbsam_open: Error when trying to convert "
+ "tdbsam [%s]\n",name));
+ TALLOC_FREE(db_sam);
+ TALLOC_FREE(mtx);
+ return false;
+ }
+
+ DEBUG(3, ("TDBSAM converted successfully.\n"));
+ }
+ TALLOC_FREE(mtx);
+ }
+
+ DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
+
+ return true;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
+ struct samu *user, const char *sname)
+{
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+ NTSTATUS status;
+
+ if ( !user ) {
+ DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Data is stored in all lower-case */
+ fstrcpy(name, sname);
+ if (!strlower_m(name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* set search key */
+ fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* get the record */
+
+ status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Key: %s\n", keystr));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (data.dsize == 0) {
+ DEBUG(5, ("%s: Got 0-sized record for key %s\n", __func__,
+ keystr));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* unpack the buffer */
+
+ if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
+ DBG_ERR("Bad struct samu entry returned from TDB!\n");
+ TALLOC_FREE(data.dptr);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* success */
+
+ TALLOC_FREE(data.dptr);
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
+ struct samu *user, uint32_t rid)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+
+ if ( !user ) {
+ DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
+ return nt_status;
+ }
+
+ /* set search key */
+
+ fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* get the record */
+
+ nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
+ return nt_status;
+ }
+
+ fstrcpy(name, (const char *)data.dptr);
+ TALLOC_FREE(data.dptr);
+
+ return tdbsam_getsampwnam (my_methods, user, name);
+}
+
+static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
+ struct samu * user, const struct dom_sid *sid)
+{
+ uint32_t rid;
+
+ if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return tdbsam_getsampwrid(my_methods, user, rid);
+}
+
+static bool tdb_delete_samacct_only( struct samu *sam_pass )
+{
+ fstring keystr;
+ fstring name;
+ NTSTATUS status;
+
+ fstrcpy(name, pdb_get_username(sam_pass));
+ if (!strlower_m(name)) {
+ return false;
+ }
+
+ /* set the search key */
+
+ fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
+
+ /* it's outaa here! 8^) */
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
+ tdbsam_filename));
+ return false;
+ }
+
+ status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Error deleting entry from tdb passwd "
+ "database: %s!\n", nt_errstr(status)));
+ return false;
+ }
+
+ return true;
+}
+
+/***************************************************************************
+ Delete a struct samu records for the username and RID key
+****************************************************************************/
+
+static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
+ struct samu *sam_pass)
+{
+ NTSTATUS nt_status;
+ fstring keystr;
+ uint32_t rid;
+ fstring name;
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
+ tdbsam_filename));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ fstrcpy(name, pdb_get_username(sam_pass));
+ if (!strlower_m(name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* set the search key */
+
+ fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ /* it's outaa here! 8^) */
+
+ if (dbwrap_transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ nt_status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("Error deleting entry from tdb passwd "
+ "database: %s!\n", nt_errstr(nt_status)));
+ goto cancel;
+ }
+
+ /* set the search key */
+
+ fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
+
+ /* it's outaa here! 8^) */
+
+ nt_status = dbwrap_delete_bystring(db_sam, keystr);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("Error deleting entry from tdb rid "
+ "database: %s!\n", nt_errstr(nt_status)));
+ goto cancel;
+ }
+
+ if (dbwrap_transaction_commit(db_sam) != 0) {
+ DEBUG(0, ("Could not commit transaction\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ return NT_STATUS_OK;
+
+ cancel:
+ if (dbwrap_transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ return nt_status;
+}
+
+
+/***************************************************************************
+ Update the TDB SAM account record only
+ Assumes that the tdbsam is already open
+****************************************************************************/
+static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
+{
+ TDB_DATA data;
+ uint8_t *buf = NULL;
+ fstring keystr;
+ fstring name;
+ bool ret = false;
+ NTSTATUS status;
+
+ /* copy the struct samu struct into a BYTE buffer for storage */
+
+ if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
+ DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
+ goto done;
+ }
+ data.dptr = buf;
+
+ fstrcpy(name, pdb_get_username(newpwd));
+ if (!strlower_m(name)) {
+ goto done;
+ }
+
+ DEBUG(5, ("Storing %saccount %s with RID %d\n",
+ flag == TDB_INSERT ? "(new) " : "", name,
+ pdb_get_user_rid(newpwd)));
+
+ /* setup the USER index key */
+ fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
+
+ /* add the account */
+
+ status = dbwrap_store_bystring(db_sam, keystr, data, flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Unable to modify passwd TDB: %s!\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ ret = true;
+
+done:
+ /* cleanup */
+ SAFE_FREE(buf);
+ return ret;
+}
+
+/***************************************************************************
+ Update the TDB SAM RID record only
+ Assumes that the tdbsam is already open
+****************************************************************************/
+static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
+{
+ TDB_DATA data;
+ fstring keystr;
+ fstring name;
+ NTSTATUS status;
+
+ fstrcpy(name, pdb_get_username(newpwd));
+ if (!strlower_m(name)) {
+ return false;
+ }
+
+ /* setup RID data */
+ data = string_term_tdb_data(name);
+
+ /* setup the RID index key */
+ fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
+
+ /* add the reference */
+ status = dbwrap_store_bystring(db_sam, keystr, data, flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
+ nt_errstr(status)));
+ return false;
+ }
+
+ return true;
+
+}
+
+/***************************************************************************
+ Update the TDB SAM
+****************************************************************************/
+
+static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
+ int flag)
+{
+ uint32_t oldrid;
+ uint32_t newrid;
+
+ if (!(newrid = pdb_get_user_rid(newpwd))) {
+ DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
+ pdb_get_username(newpwd)));
+ return False;
+ }
+
+ oldrid = newrid;
+
+ /* open the database */
+
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
+ return False;
+ }
+
+ if (dbwrap_transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ return false;
+ }
+
+ /* If we are updating, we may be changing this users RID. Retrieve the old RID
+ so we can check. */
+
+ if (flag == TDB_MODIFY) {
+ struct samu *account = samu_new(talloc_tos());
+ if (account == NULL) {
+ DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
+ goto cancel;
+ }
+ if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
+ DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
+ pdb_get_username(newpwd)));
+ TALLOC_FREE(account);
+ goto cancel;
+ }
+ if (!(oldrid = pdb_get_user_rid(account))) {
+ DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
+ TALLOC_FREE(account);
+ goto cancel;
+ }
+ TALLOC_FREE(account);
+ }
+
+ /* Update the new samu entry. */
+ if (!tdb_update_samacct_only(newpwd, flag)) {
+ goto cancel;
+ }
+
+ /* Now take care of the case where the RID changed. We need
+ * to delete the old RID key and add the new. */
+
+ if (flag == TDB_MODIFY && newrid != oldrid) {
+ fstring keystr;
+
+ /* Delete old RID key */
+ DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
+ fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, oldrid);
+ if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
+ DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
+ goto cancel;
+ }
+ /* Insert new RID key */
+ DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
+ if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
+ goto cancel;
+ }
+ } else {
+ DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
+ flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
+ if (!tdb_update_ridrec_only(newpwd, flag)) {
+ goto cancel;
+ }
+ }
+
+ if (dbwrap_transaction_commit(db_sam) != 0) {
+ DEBUG(0, ("Could not commit transaction\n"));
+ return false;
+ }
+
+ return true;
+
+ cancel:
+ if (dbwrap_transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+ return false;
+}
+
+/***************************************************************************
+ Modifies an existing struct samu
+****************************************************************************/
+
+static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
+{
+ if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Adds an existing struct samu
+****************************************************************************/
+
+static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
+{
+ if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Renames a struct samu
+ - check for the posix user/rename user script
+ - Add and lock the new user record
+ - rename the posix user
+ - rewrite the rid->username record
+ - delete the old user
+ - unlock the new user record
+***************************************************************************/
+static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
+ struct samu *old_acct,
+ const char *newname)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ struct samu *new_acct = NULL;
+ char *rename_script = NULL;
+ int rename_ret;
+ fstring oldname_lower;
+ fstring newname_lower;
+
+ /* can't do anything without an external script */
+
+ if ( !(new_acct = samu_new( talloc_tos() )) ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rename_script = lp_rename_user_script(new_acct, lp_sub);
+ if (!rename_script) {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!*rename_script) {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ( !pdb_copy_sam_account(new_acct, old_acct)
+ || !pdb_set_username(new_acct, newname, PDB_CHANGED))
+ {
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* open the database */
+ if ( !tdbsam_open( tdbsam_filename ) ) {
+ DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
+ tdbsam_filename));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (dbwrap_transaction_start(db_sam) != 0) {
+ DEBUG(0, ("Could not start transaction\n"));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_ACCESS_DENIED;
+
+ }
+
+ /* add the new account and lock it */
+ if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
+ goto cancel;
+ }
+
+ /* Rename the posix user. Follow the semantics of _samr_create_user()
+ so that we lower case the posix name but preserve the case in passdb */
+
+ fstrcpy( oldname_lower, pdb_get_username(old_acct) );
+ if (!strlower_m( oldname_lower )) {
+ goto cancel;
+ }
+
+ fstrcpy( newname_lower, newname );
+ if (!strlower_m( newname_lower )) {
+ goto cancel;
+ }
+
+ rename_script = talloc_string_sub2(new_acct,
+ rename_script,
+ "%unew",
+ newname_lower,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ goto cancel;
+ }
+ rename_script = talloc_string_sub2(new_acct,
+ rename_script,
+ "%uold",
+ oldname_lower,
+ true,
+ false,
+ true);
+ if (!rename_script) {
+ goto cancel;
+ }
+ rename_ret = smbrun(rename_script, NULL, NULL);
+
+ DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
+ rename_script, rename_ret));
+
+ if (rename_ret != 0) {
+ goto cancel;
+ }
+
+ smb_nscd_flush_user_cache();
+
+ /* rewrite the rid->username record */
+
+ if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
+ goto cancel;
+ }
+
+ tdb_delete_samacct_only( old_acct );
+
+ if (dbwrap_transaction_commit(db_sam) != 0) {
+ /*
+ * Ok, we're screwed. We've changed the posix account, but
+ * could not adapt passdb.tdb. Shall we change the posix
+ * account back?
+ */
+ DEBUG(0, ("transaction_commit failed\n"));
+ TALLOC_FREE(new_acct);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ TALLOC_FREE(new_acct );
+ return NT_STATUS_OK;
+
+ cancel:
+ if (dbwrap_transaction_cancel(db_sam) != 0) {
+ smb_panic("transaction_cancel failed");
+ }
+
+ TALLOC_FREE(new_acct);
+
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
+{
+ return PDB_CAP_STORE_RIDS;
+}
+
+static bool tdbsam_new_rid(struct pdb_methods *methods, uint32_t *prid)
+{
+ uint32_t rid;
+ NTSTATUS status;
+
+ rid = BASE_RID; /* Default if not set */
+
+ if (!tdbsam_open(tdbsam_filename)) {
+ DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
+ tdbsam_filename));
+ return false;
+ }
+
+ status = dbwrap_trans_change_uint32_atomic_bystring(
+ db_sam, NEXT_RID_STRING, &rid, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
+ NEXT_RID_STRING, nt_errstr(status)));
+ return false;
+ }
+
+ *prid = rid;
+
+ return true;
+}
+
+struct tdbsam_search_state {
+ struct pdb_methods *methods;
+ uint32_t acct_flags;
+
+ uint32_t *rids;
+ uint32_t num_rids;
+ ssize_t array_size;
+ uint32_t current;
+};
+
+static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ private_data, struct tdbsam_search_state);
+ size_t prefixlen = strlen(RIDPREFIX);
+ uint32_t rid;
+ int error = 0;
+ TDB_DATA key;
+
+ key = dbwrap_record_get_key(rec);
+
+ if ((key.dsize < prefixlen)
+ || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
+ return 0;
+ }
+
+ rid = smb_strtoul((char *)key.dptr+prefixlen,
+ NULL,
+ 16,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ return 0;
+ }
+
+ ADD_TO_LARGE_ARRAY(state, uint32_t, rid, &state->rids, &state->num_rids,
+ &state->array_size);
+
+ return 0;
+}
+
+static void tdbsam_search_end(struct pdb_search *search)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ search->private_data, struct tdbsam_search_state);
+ TALLOC_FREE(state);
+}
+
+static bool tdbsam_search_next_entry(struct pdb_search *search,
+ struct samr_displayentry *entry)
+{
+ struct tdbsam_search_state *state = talloc_get_type_abort(
+ search->private_data, struct tdbsam_search_state);
+ struct samu *user = NULL;
+ NTSTATUS status;
+ uint32_t rid;
+
+ again:
+ TALLOC_FREE(user);
+ user = samu_new(talloc_tos());
+ if (user == NULL) {
+ DEBUG(0, ("samu_new failed\n"));
+ return false;
+ }
+
+ if (state->current == state->num_rids) {
+ TALLOC_FREE(user);
+ return false;
+ }
+
+ rid = state->rids[state->current++];
+
+ status = tdbsam_getsampwrid(state->methods, user, rid);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+ /*
+ * Someone has deleted that user since we listed the RIDs
+ */
+ goto again;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(user);
+ return false;
+ }
+
+ if ((state->acct_flags != 0) &&
+ ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
+ goto again;
+ }
+
+ entry->acct_flags = pdb_get_acct_ctrl(user);
+ entry->rid = rid;
+ entry->account_name = talloc_strdup(search, pdb_get_username(user));
+ entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
+ entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
+
+ TALLOC_FREE(user);
+
+ if ((entry->account_name == NULL) || (entry->fullname == NULL)
+ || (entry->description == NULL)) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return false;
+ }
+
+ return true;
+}
+
+static bool tdbsam_search_users(struct pdb_methods *methods,
+ struct pdb_search *search,
+ uint32_t acct_flags)
+{
+ struct tdbsam_search_state *state;
+
+ if (!tdbsam_open(tdbsam_filename)) {
+ DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
+ tdbsam_filename));
+ return false;
+ }
+
+ state = talloc_zero(search, struct tdbsam_search_state);
+ if (state == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ state->acct_flags = acct_flags;
+ state->methods = methods;
+
+ dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
+
+ search->private_data = state;
+ search->next_entry = tdbsam_search_next_entry;
+ search->search_end = tdbsam_search_end;
+
+ return true;
+}
+
+static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
+{
+ return map_builtin;
+}
+
+/*********************************************************************
+ Initialize the tdb sam backend. Setup the dispatch table of methods,
+ open the tdb, etc...
+*********************************************************************/
+
+static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+ char *tdbfile = NULL;
+ const char *pfile = location;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "tdbsam";
+
+ (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
+ (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
+ (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
+ (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
+ (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
+ (*pdb_method)->search_users = tdbsam_search_users;
+
+ (*pdb_method)->capabilities = tdbsam_capabilities;
+ (*pdb_method)->new_rid = tdbsam_new_rid;
+
+ (*pdb_method)->is_responsible_for_builtin =
+ tdbsam_is_responsible_for_builtin;
+ map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
+
+ /* save the path for later */
+
+ if (!location) {
+ if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
+ PASSDB_FILE_NAME) < 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pfile = tdbfile;
+ }
+
+ /* Do not leak memory if the init function is called more than once */
+ SAFE_FREE(tdbsam_filename);
+ tdbsam_filename = SMB_STRDUP(pfile);
+ if (!tdbsam_filename) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(tdbfile);
+
+ /* no private data */
+
+ (*pdb_method)->private_data = NULL;
+ (*pdb_method)->free_private_data = NULL;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_tdbsam_init(TALLOC_CTX *ctx)
+{
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
+}
diff --git a/source3/passdb/pdb_tdb.h b/source3/passdb/pdb_tdb.h
new file mode 100644
index 0000000..b90beb7
--- /dev/null
+++ b/source3/passdb/pdb_tdb.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000-2003
+ * Copyright (C) Gerald Carter 2000-2006
+ * Copyright (C) Jeremy Allison 2001-2009
+ * Copyright (C) Andrew Bartlett 2002
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The following definitions come from passdb/pdb_tdb.c */
+
+#ifndef _PASSDB_PDB_TDB_H_
+#define _PASSDB_PDB_TDB_H_
+
+NTSTATUS pdb_tdbsam_init(TALLOC_CTX *);
+
+#endif /* _PASSDB_PDB_TDB_H_ */
diff --git a/source3/passdb/pdb_util.c b/source3/passdb/pdb_util.c
new file mode 100644
index 0000000..b732aca
--- /dev/null
+++ b/source3/passdb/pdb_util.c
@@ -0,0 +1,245 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Authentication utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Jeremy Allison 2000-2001
+ * Copyright (C) Rafal Szczesniak 2002
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Michael Adam 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "../libcli/security/security.h"
+#include "passdb.h"
+#include "lib/winbind_util.h"
+#include "../librpc/gen_ndr/idmap.h"
+
+/**
+ * Add sid as a member of builtin_sid.
+ *
+ * @param[in] builtin_sid An existing builtin group.
+ * @param[in] dom_sid sid to add as a member of builtin_sid.
+ * @return Normal NTSTATUS return
+ */
+static NTSTATUS add_sid_to_builtin(const struct dom_sid *builtin_sid,
+ const struct dom_sid *dom_sid)
+{
+ NTSTATUS status;
+
+ if (!dom_sid || !builtin_sid) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = pdb_add_aliasmem(builtin_sid, dom_sid);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MEMBER_IN_ALIAS)) {
+ struct dom_sid_buf buf1, buf2;
+ DEBUG(5, ("add_sid_to_builtin %s is already a member of %s\n",
+ dom_sid_str_buf(dom_sid, &buf1),
+ dom_sid_str_buf(builtin_sid, &buf2)));
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ struct dom_sid_buf buf1, buf2;
+ DEBUG(4, ("add_sid_to_builtin %s could not be added to %s: "
+ "%s\n",
+ dom_sid_str_buf(dom_sid, &buf1),
+ dom_sid_str_buf(builtin_sid, &buf2),
+ nt_errstr(status)));
+ }
+ return status;
+}
+
+/**
+ * Create the requested BUILTIN if it doesn't already exist. This requires
+ * winbindd to be running.
+ *
+ * @param[in] rid BUILTIN rid to create
+ * @return Normal NTSTATUS return.
+ */
+NTSTATUS pdb_create_builtin(uint32_t rid)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct dom_sid sid;
+ gid_t gid;
+ bool mapresult;
+
+ if (!sid_compose(&sid, &global_sid_Builtin, rid)) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (!pdb_is_responsible_for_builtin()) {
+ /*
+ * if this backend is not responsible for BUILTIN
+ *
+ * Use the gid from the mapping request for entry.
+ * If the mapping fails, bail out
+ */
+ mapresult = sid_to_gid(&sid, &gid);
+ if (!mapresult) {
+ status = NT_STATUS_NO_SUCH_GROUP;
+ } else {
+ status = pdb_create_builtin_alias(rid, gid);
+ }
+ } else {
+ /*
+ * this backend is responsible for BUILTIN
+ *
+ * a failed mapping result means that the entry
+ * does not exist yet, so create it
+ *
+ * we use pdb_sid_to_id intentionally here to
+ * directly query the passdb backend (sid_to_gid
+ * would finally do the same)
+ */
+ struct unixid id;
+ mapresult = pdb_sid_to_id(&sid, &id);
+ if (!mapresult) {
+ if (!lp_winbind_nested_groups() || !winbind_ping()) {
+ return NT_STATUS_PROTOCOL_UNREACHABLE;
+ }
+ status = pdb_create_builtin_alias(rid, 0);
+ }
+ }
+ return status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+NTSTATUS create_builtin_users(const struct dom_sid *dom_sid)
+{
+ NTSTATUS status;
+ struct dom_sid dom_users;
+
+ status = pdb_create_builtin(BUILTIN_RID_USERS);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("create_builtin_users: Failed to create Users\n"));
+ return status;
+ }
+
+ /* add domain users */
+ if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) &&
+ (dom_sid != NULL) &&
+ sid_compose(&dom_users, dom_sid, DOMAIN_RID_USERS))
+ {
+ status = add_sid_to_builtin(&global_sid_Builtin_Users,
+ &dom_users);
+ }
+
+ return status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+NTSTATUS create_builtin_administrators(const struct dom_sid *dom_sid)
+{
+ NTSTATUS status;
+ struct dom_sid dom_admins, root_sid;
+ fstring root_name;
+ enum lsa_SidType type;
+ TALLOC_CTX *ctx;
+ bool ret;
+
+ status = pdb_create_builtin(BUILTIN_RID_ADMINISTRATORS);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ DEBUG(5,("create_builtin_administrators: Failed to create Administrators\n"));
+ return status;
+ }
+
+ /* add domain admins */
+ if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) &&
+ (dom_sid != NULL) &&
+ sid_compose(&dom_admins, dom_sid, DOMAIN_RID_ADMINS))
+ {
+ status = add_sid_to_builtin(&global_sid_Builtin_Administrators,
+ &dom_admins);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* add root */
+ if ( (ctx = talloc_init("create_builtin_administrators")) == NULL ) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ fstr_sprintf( root_name, "%s\\root", get_global_sam_name() );
+ ret = lookup_name(ctx, root_name, LOOKUP_NAME_DOMAIN, NULL, NULL,
+ &root_sid, &type);
+ TALLOC_FREE( ctx );
+
+ if ( ret ) {
+ status = add_sid_to_builtin(&global_sid_Builtin_Administrators,
+ &root_sid);
+ }
+
+ return status;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+NTSTATUS create_builtin_guests(const struct dom_sid *dom_sid)
+{
+ NTSTATUS status;
+ struct dom_sid tmp_sid = { 0, };
+
+ status = pdb_create_builtin(BUILTIN_RID_GUESTS);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("create_builtin_guests: Failed to create Guests\n"));
+ return status;
+ }
+
+ /* add local guest */
+ if (sid_compose(&tmp_sid, get_global_sam_sid(), DOMAIN_RID_GUEST)) {
+ status = add_sid_to_builtin(&global_sid_Builtin_Guests,
+ &tmp_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* add local guests */
+ if (sid_compose(&tmp_sid, get_global_sam_sid(), DOMAIN_RID_GUESTS)) {
+ status = add_sid_to_builtin(&global_sid_Builtin_Guests,
+ &tmp_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (lp_server_role() != ROLE_DOMAIN_MEMBER) {
+ return NT_STATUS_OK;
+ }
+
+ if (dom_sid == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* add domain guests */
+ if (sid_compose(&tmp_sid, dom_sid, DOMAIN_RID_GUESTS)) {
+ status = add_sid_to_builtin(&global_sid_Builtin_Guests,
+ &tmp_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/py_passdb.c b/source3/passdb/py_passdb.c
new file mode 100644
index 0000000..02d1d55
--- /dev/null
+++ b/source3/passdb/py_passdb.c
@@ -0,0 +1,4074 @@
+/*
+ Python interface to passdb
+
+ Copyright (C) Amitay Isaacs 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include <pytalloc.h>
+#include "includes.h"
+#include "python/py3compat.h"
+#include "lib/util/talloc_stack.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/idmap.h"
+#include "passdb.h"
+#include "secrets.h"
+#include "idmap.h"
+#include "lib/util/string_wrappers.h"
+
+#ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+#ifndef PY_CHECK_TYPE
+#define PY_CHECK_TYPE(type, var, fail) \
+ if (!PyObject_TypeCheck(var, type)) {\
+ PyErr_Format(PyExc_TypeError, __location__ ": Expected type '%s' for '%s' of type '%s'", (type)->tp_name, #var, Py_TYPE(var)->tp_name); \
+ fail; \
+ }
+#endif
+
+
+static PyTypeObject *dom_sid_Type = NULL;
+static PyTypeObject *security_Type = NULL;
+static PyTypeObject *guid_Type = NULL;
+
+static PyTypeObject PySamu;
+static PyTypeObject PyGroupmap;
+static PyTypeObject PyPDB;
+
+static PyObject *py_pdb_error;
+
+void initpassdb(void);
+
+
+/************************** PIDL Autogeneratd ******************************/
+
+static PyObject *py_samu_get_logon_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_logon_time;
+
+ py_logon_time = PyLong_FromLong(pdb_get_logon_time(sam_acct));
+ talloc_free(frame);
+ return py_logon_time;
+}
+
+static int py_samu_set_logon_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_logon_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_logoff_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_logoff_time;
+
+ py_logoff_time = PyLong_FromLong(pdb_get_logoff_time(sam_acct));
+ talloc_free(frame);
+ return py_logoff_time;
+}
+
+static int py_samu_set_logoff_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_logoff_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_kickoff_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_kickoff_time;
+
+ py_kickoff_time = PyLong_FromLong(pdb_get_kickoff_time(sam_acct));
+ talloc_free(frame);
+ return py_kickoff_time;
+}
+
+static int py_samu_set_kickoff_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_kickoff_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_bad_password_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_bad_password_time;
+
+ py_bad_password_time = PyLong_FromLong(pdb_get_bad_password_time(sam_acct));
+ talloc_free(frame);
+ return py_bad_password_time;
+}
+
+static int py_samu_set_bad_password_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_bad_password_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_pass_last_set_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_pass_last_set_time;
+
+ py_pass_last_set_time = PyLong_FromLong(pdb_get_pass_last_set_time(sam_acct));
+ talloc_free(frame);
+ return py_pass_last_set_time;
+}
+
+static int py_samu_set_pass_last_set_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_pass_last_set_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_pass_can_change_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_pass_can_change_time;
+
+ py_pass_can_change_time = PyLong_FromLong(pdb_get_pass_can_change_time(sam_acct));
+ talloc_free(frame);
+ return py_pass_can_change_time;
+}
+
+static int py_samu_set_pass_can_change_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_pass_can_change_time(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_pass_must_change_time(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_pass_must_change_time;
+
+ py_pass_must_change_time = PyLong_FromLong(pdb_get_pass_must_change_time(sam_acct));
+ talloc_free(frame);
+ return py_pass_must_change_time;
+}
+
+static int py_samu_set_pass_must_change_time(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+
+ /* TODO: make this not a get/set or give a better exception */
+ talloc_free(frame);
+ return -1;
+}
+
+static PyObject *py_samu_get_username(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_username;
+ const char *username;
+
+ username = pdb_get_username(sam_acct);
+ if (username == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_username = PyUnicode_FromString(username);
+ talloc_free(frame);
+ return py_username;
+}
+
+static int py_samu_set_username(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_username(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_domain(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_domain;
+ const char *domain;
+
+ domain = pdb_get_domain(sam_acct);
+ if (domain == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_domain = PyUnicode_FromString(domain);
+ talloc_free(frame);
+ return py_domain;
+}
+
+static int py_samu_set_domain(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_domain(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_nt_username(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_nt_username;
+ const char *nt_username;
+
+ nt_username = pdb_get_nt_username(sam_acct);
+ if (nt_username == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_nt_username = PyUnicode_FromString(nt_username);
+ talloc_free(frame);
+ return py_nt_username;
+}
+
+static int py_samu_set_nt_username(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_nt_username(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_full_name(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_full_name;
+ const char *full_name;
+
+ full_name = pdb_get_fullname(sam_acct);
+ if (full_name == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_full_name = PyUnicode_FromString(full_name);
+ talloc_free(frame);
+ return py_full_name;
+}
+
+static int py_samu_set_full_name(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_fullname(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_home_dir(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_home_dir;
+ const char *home_dir;
+
+ home_dir = pdb_get_homedir(sam_acct);
+ if (home_dir == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_home_dir = PyUnicode_FromString(home_dir);
+ talloc_free(frame);
+ return py_home_dir;
+}
+
+static int py_samu_set_home_dir(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_homedir(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_dir_drive(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_dir_drive;
+ const char *dir_drive;
+
+ dir_drive = pdb_get_dir_drive(sam_acct);
+ if (dir_drive == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_dir_drive = PyUnicode_FromString(dir_drive);
+ talloc_free(frame);
+ return py_dir_drive;
+}
+
+static int py_samu_set_dir_drive(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_dir_drive(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_logon_script(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_logon_script;
+ const char *logon_script;
+
+ logon_script = pdb_get_logon_script(sam_acct);
+ if (logon_script == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_logon_script = PyUnicode_FromString(logon_script);
+ talloc_free(frame);
+ return py_logon_script;
+}
+
+static int py_samu_set_logon_script(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_logon_script(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_profile_path(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_profile_path;
+ const char *profile_path;
+
+ profile_path = pdb_get_profile_path(sam_acct);
+ if (profile_path == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_profile_path = PyUnicode_FromString(profile_path);
+ talloc_free(frame);
+ return py_profile_path;
+}
+
+static int py_samu_set_profile_path(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_profile_path(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_acct_desc(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_acct_desc;
+ const char *acct_desc;
+
+ acct_desc = pdb_get_acct_desc(sam_acct);
+ if (acct_desc == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_acct_desc = PyUnicode_FromString(acct_desc);
+ talloc_free(frame);
+ return py_acct_desc;
+}
+
+static int py_samu_set_acct_desc(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_acct_desc(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_workstations(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_workstations;
+ const char *workstations;
+
+ workstations = pdb_get_workstations(sam_acct);
+ if (workstations == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_workstations = PyUnicode_FromString(workstations);
+ talloc_free(frame);
+ return py_workstations;
+}
+
+static int py_samu_set_workstations(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_workstations(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_comment(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_comment;
+ const char *comment;
+
+ comment = pdb_get_comment(sam_acct);
+ if (comment == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_comment = PyUnicode_FromString(comment);
+ talloc_free(frame);
+ return py_comment;
+}
+
+static int py_samu_set_comment(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_comment(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_munged_dial(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_munged_dial;
+ const char *munged_dial;
+
+ munged_dial = pdb_get_munged_dial(sam_acct);
+ if (munged_dial == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_munged_dial = PyUnicode_FromString(munged_dial);
+ talloc_free(frame);
+ return py_munged_dial;
+}
+
+static int py_samu_set_munged_dial(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (!pdb_set_munged_dial(sam_acct, PyUnicode_AsUTF8(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_user_sid(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_user_sid;
+ const struct dom_sid *user_sid;
+ struct dom_sid *copy_user_sid;
+ TALLOC_CTX *mem_ctx;
+
+ user_sid = pdb_get_user_sid(sam_acct);
+ if(user_sid == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+ copy_user_sid = dom_sid_dup(mem_ctx, user_sid);
+ if (copy_user_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_user_sid = pytalloc_steal(dom_sid_Type, copy_user_sid);
+
+ talloc_free(mem_ctx);
+
+ talloc_free(frame);
+ return py_user_sid;
+}
+
+static int py_samu_set_user_sid(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(dom_sid_Type, value, return -1;);
+ if (!pdb_set_user_sid(sam_acct, (struct dom_sid *)pytalloc_get_ptr(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_group_sid(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ const struct dom_sid *group_sid;
+ struct dom_sid *copy_group_sid;
+
+ group_sid = pdb_get_group_sid(sam_acct);
+ if (group_sid == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ copy_group_sid = dom_sid_dup(NULL, group_sid);
+ if (copy_group_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return pytalloc_steal(dom_sid_Type, copy_group_sid);
+}
+
+static int py_samu_set_group_sid(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(dom_sid_Type, value, return -1;);
+ if (!pdb_set_group_sid(sam_acct, (struct dom_sid *)pytalloc_get_ptr(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_lanman_passwd(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_lm_pw;
+ const char *lm_pw;
+
+ lm_pw = (const char *)pdb_get_lanman_passwd(sam_acct);
+ if (lm_pw == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_lm_pw = PyBytes_FromStringAndSize(lm_pw, LM_HASH_LEN);
+ talloc_free(frame);
+ return py_lm_pw;
+}
+
+static int py_samu_set_lanman_passwd(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyBytes_Type, value, return -1;);
+ if (!pdb_set_lanman_passwd(sam_acct, (uint8_t *)PyBytes_AsString(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_nt_passwd(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_nt_pw;
+ const char *nt_pw;
+
+ nt_pw = (const char *)pdb_get_nt_passwd(sam_acct);
+ if (nt_pw == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_nt_pw = PyBytes_FromStringAndSize(nt_pw, NT_HASH_LEN);
+ talloc_free(frame);
+ return py_nt_pw;
+}
+
+static int py_samu_set_nt_passwd(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ if (!pdb_set_nt_passwd(sam_acct, (uint8_t *)PyBytes_AsString(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_pw_history(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_nt_pw_his;
+ const char *nt_pw_his;
+ uint32_t hist_len;
+
+ nt_pw_his = (const char *)pdb_get_pw_history(sam_acct, &hist_len);
+ if (nt_pw_his == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_nt_pw_his = PyBytes_FromStringAndSize(nt_pw_his, hist_len*PW_HISTORY_ENTRY_LEN);
+ talloc_free(frame);
+ return py_nt_pw_his;
+}
+
+static int py_samu_set_pw_history(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ char *nt_pw_his;
+ Py_ssize_t len;
+ uint32_t hist_len;
+
+ PyBytes_AsStringAndSize(value, &nt_pw_his, &len);
+ hist_len = len / PW_HISTORY_ENTRY_LEN;
+ if (!pdb_set_pw_history(sam_acct, (uint8_t *)nt_pw_his, hist_len, PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_plaintext_passwd(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_plaintext_pw;
+ const char *plaintext_pw;
+
+ plaintext_pw = pdb_get_plaintext_passwd(sam_acct);
+ if (plaintext_pw == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ py_plaintext_pw = PyUnicode_FromString(plaintext_pw);
+
+ BURN_STR(discard_const_p(char, plaintext_pw));
+ talloc_free(frame);
+ return py_plaintext_pw;
+}
+
+static int py_samu_set_plaintext_passwd(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ if (!pdb_set_plaintext_passwd(sam_acct, PyUnicode_AsUTF8(value))) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_acct_ctrl(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_acct_ctrl;
+
+ py_acct_ctrl = PyLong_FromLong(pdb_get_acct_ctrl(sam_acct));
+ talloc_free(frame);
+ return py_acct_ctrl;
+}
+
+static int py_samu_set_acct_ctrl(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_acct_ctrl(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_logon_divs(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_logon_divs;
+
+ py_logon_divs = PyLong_FromLong(pdb_get_logon_divs(sam_acct));
+ talloc_free(frame);
+ return py_logon_divs;
+}
+
+static int py_samu_set_logon_divs(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_logon_divs(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_hours_len(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_hours_len;
+
+ py_hours_len = PyLong_FromLong(pdb_get_hours_len(sam_acct));
+ talloc_free(frame);
+ return py_hours_len;
+}
+
+static int py_samu_set_hours_len(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_hours_len(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_hours(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_hours;
+ const char *hours;
+ int hours_len, i;
+
+ hours = (const char *)pdb_get_hours(sam_acct);
+ if(! hours) {
+ Py_RETURN_NONE;
+ }
+
+ hours_len = pdb_get_hours_len(sam_acct);
+ if ((py_hours = PyList_New(hours_len)) == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for (i=0; i<hours_len; i++) {
+ PyList_SetItem(py_hours, i, PyLong_FromLong(hours[i]));
+ }
+ talloc_free(frame);
+ return py_hours;
+}
+
+static int py_samu_set_hours(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ int i;
+ uint8_t *hours;
+ int hours_len;
+ bool status;
+
+ PY_CHECK_TYPE(&PyList_Type, value, return -1;);
+
+ hours_len = PyList_GET_SIZE(value);
+
+ hours = talloc_array(pytalloc_get_mem_ctx(obj), uint8_t, hours_len);
+ if (!hours) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return -1;
+ }
+
+ for (i=0; i < hours_len; i++) {
+ PY_CHECK_TYPE(&PyLong_Type, PyList_GET_ITEM(value,i), return -1;);
+ hours[i] = PyLong_AsLong(PyList_GET_ITEM(value, i));
+ }
+
+ status = pdb_set_hours(sam_acct, hours, hours_len, PDB_CHANGED);
+ talloc_free(hours);
+
+ if(! status) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_bad_password_count(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_bad_password_count;
+
+ py_bad_password_count = PyLong_FromLong(pdb_get_bad_password_count(sam_acct));
+ talloc_free(frame);
+ return py_bad_password_count;
+}
+
+static int py_samu_set_bad_password_count(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_bad_password_count(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_logon_count(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_logon_count;
+
+ py_logon_count = PyLong_FromLong(pdb_get_logon_count(sam_acct));
+ talloc_free(frame);
+ return py_logon_count;
+}
+
+static int py_samu_set_logon_count(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_logon_count(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_country_code(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_country_code;
+
+ py_country_code = PyLong_FromLong(pdb_get_country_code(sam_acct));
+ talloc_free(frame);
+ return py_country_code;
+}
+
+static int py_samu_set_country_code(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_country_code(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_samu_get_code_page(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+ PyObject *py_code_page;
+
+ py_code_page = PyLong_FromLong(pdb_get_code_page(sam_acct));
+ talloc_free(frame);
+ return py_code_page;
+}
+
+static int py_samu_set_code_page(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct = (struct samu *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ if (!pdb_set_code_page(sam_acct, PyLong_AsLong(value), PDB_CHANGED)) {
+ talloc_free(frame);
+ return -1;
+ }
+ talloc_free(frame);
+ return 0;
+}
+
+static PyGetSetDef py_samu_getsetters[] = {
+ {
+ .name = discard_const_p(char, "logon_time"),
+ .get = py_samu_get_logon_time,
+ .set = py_samu_set_logon_time,
+ },
+ {
+ .name = discard_const_p(char, "logoff_time"),
+ .get = py_samu_get_logoff_time,
+ .set = py_samu_set_logoff_time,
+ },
+ {
+ .name = discard_const_p(char, "kickoff_time"),
+ .get = py_samu_get_kickoff_time,
+ .set = py_samu_set_kickoff_time,
+ },
+ {
+ .name = discard_const_p(char, "bad_password_time"),
+ .get = py_samu_get_bad_password_time,
+ .set = py_samu_set_bad_password_time,
+ },
+ {
+ .name = discard_const_p(char, "pass_last_set_time"),
+ .get = py_samu_get_pass_last_set_time,
+ .set = py_samu_set_pass_last_set_time,
+ },
+ {
+ .name = discard_const_p(char, "pass_can_change_time"),
+ .get = py_samu_get_pass_can_change_time,
+ .set = py_samu_set_pass_can_change_time,
+ },
+ {
+ .name = discard_const_p(char, "pass_must_change_time"),
+ .get = py_samu_get_pass_must_change_time,
+ .set = py_samu_set_pass_must_change_time,
+ },
+ {
+ .name = discard_const_p(char, "username"),
+ .get = py_samu_get_username,
+ .set = py_samu_set_username,
+ },
+ {
+ .name = discard_const_p(char, "domain"),
+ .get = py_samu_get_domain,
+ .set = py_samu_set_domain,
+ },
+ {
+ .name = discard_const_p(char, "nt_username"),
+ .get = py_samu_get_nt_username,
+ .set = py_samu_set_nt_username,
+ },
+ {
+ .name = discard_const_p(char, "full_name"),
+ .get = py_samu_get_full_name,
+ .set = py_samu_set_full_name,
+ },
+ {
+ .name = discard_const_p(char, "home_dir"),
+ .get = py_samu_get_home_dir,
+ .set = py_samu_set_home_dir,
+ },
+ {
+ .name = discard_const_p(char, "dir_drive"),
+ .get = py_samu_get_dir_drive,
+ .set = py_samu_set_dir_drive,
+ },
+ {
+ .name = discard_const_p(char, "logon_script"),
+ .get = py_samu_get_logon_script,
+ .set = py_samu_set_logon_script,
+ },
+ {
+ .name = discard_const_p(char, "profile_path"),
+ .get = py_samu_get_profile_path,
+ .set = py_samu_set_profile_path,
+ },
+ {
+ .name = discard_const_p(char, "acct_desc"),
+ .get = py_samu_get_acct_desc,
+ .set = py_samu_set_acct_desc,
+ },
+ {
+ .name = discard_const_p(char, "workstations"),
+ .get = py_samu_get_workstations,
+ .set = py_samu_set_workstations,
+ },
+ {
+ .name = discard_const_p(char, "comment"),
+ .get = py_samu_get_comment,
+ .set = py_samu_set_comment,
+ },
+ {
+ .name = discard_const_p(char, "munged_dial"),
+ .get = py_samu_get_munged_dial,
+ .set = py_samu_set_munged_dial,
+ },
+ {
+ .name = discard_const_p(char, "user_sid"),
+ .get = py_samu_get_user_sid,
+ .set = py_samu_set_user_sid,
+ },
+ {
+ .name = discard_const_p(char, "group_sid"),
+ .get = py_samu_get_group_sid,
+ .set = py_samu_set_group_sid,
+ },
+ {
+ .name = discard_const_p(char, "lanman_passwd"),
+ .get = py_samu_get_lanman_passwd,
+ .set = py_samu_set_lanman_passwd,
+ },
+ {
+ .name = discard_const_p(char, "nt_passwd"),
+ .get = py_samu_get_nt_passwd,
+ .set = py_samu_set_nt_passwd,
+ },
+ {
+ .name = discard_const_p(char, "pw_history"),
+ .get = py_samu_get_pw_history,
+ .set = py_samu_set_pw_history,
+ },
+ {
+ .name = discard_const_p(char, "plaintext_passwd"),
+ .get = py_samu_get_plaintext_passwd,
+ .set = py_samu_set_plaintext_passwd,
+ },
+ {
+ .name = discard_const_p(char, "acct_ctrl"),
+ .get = py_samu_get_acct_ctrl,
+ .set = py_samu_set_acct_ctrl,
+ },
+ {
+ .name = discard_const_p(char, "logon_divs"),
+ .get = py_samu_get_logon_divs,
+ .set = py_samu_set_logon_divs,
+ },
+ {
+ .name = discard_const_p(char, "hours_len"),
+ .get = py_samu_get_hours_len,
+ .set = py_samu_set_hours_len,
+ },
+ {
+ .name = discard_const_p(char, "hours"),
+ .get = py_samu_get_hours,
+ .set = py_samu_set_hours,
+ },
+ {
+ .name = discard_const_p(char, "bad_password_count"),
+ .get = py_samu_get_bad_password_count,
+ .set = py_samu_set_bad_password_count,
+ },
+ {
+ .name = discard_const_p(char, "logon_count"),
+ .get = py_samu_get_logon_count,
+ .set = py_samu_set_logon_count,
+ },
+ {
+ .name = discard_const_p(char, "country_code"),
+ .get = py_samu_get_country_code,
+ .set = py_samu_set_country_code,
+ },
+ {
+ .name = discard_const_p(char, "code_page"),
+ .get = py_samu_get_code_page,
+ .set = py_samu_set_code_page,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+
+/************************** PIDL Autogeneratd ******************************/
+
+static PyObject *py_samu_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct samu *sam_acct;
+
+ sam_acct = samu_new(NULL);
+ if (!sam_acct) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return pytalloc_steal(type, sam_acct);
+}
+
+static PyTypeObject PySamu = {
+ .tp_name = "passdb.Samu",
+ .tp_getset = py_samu_getsetters,
+ .tp_methods = NULL,
+ .tp_new = py_samu_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_doc = "Samu() -> samu object\n",
+};
+
+
+static PyObject *py_groupmap_get_gid(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+ PyObject *py_gid;
+
+ py_gid = Py_BuildValue("i", group_map->gid);
+ talloc_free(frame);
+ return py_gid;
+}
+
+static int py_groupmap_set_gid(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ group_map->gid = PyLong_AsLong(value);
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_groupmap_get_sid(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+ PyObject *py_sid;
+ struct dom_sid *group_sid;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ group_sid = dom_sid_dup(mem_ctx, &group_map->sid);
+ if (group_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid = pytalloc_steal(dom_sid_Type, group_sid);
+
+ talloc_free(mem_ctx);
+
+ talloc_free(frame);
+ return py_sid;
+}
+
+static int py_groupmap_set_sid(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(dom_sid_Type, value, return -1;);
+ group_map->sid = *pytalloc_get_type(value, struct dom_sid);
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_groupmap_get_sid_name_use(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+ PyObject *py_sid_name_use;
+
+ py_sid_name_use = PyLong_FromLong(group_map->sid_name_use);
+ talloc_free(frame);
+ return py_sid_name_use;
+}
+
+static int py_groupmap_set_sid_name_use(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyLong_Type, value, return -1;);
+ group_map->sid_name_use = PyLong_AsLong(value);
+ talloc_free(frame);
+ return 0;
+}
+
+static PyObject *py_groupmap_get_nt_name(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+ PyObject *py_nt_name;
+ if (group_map->nt_name == NULL) {
+ py_nt_name = Py_None;
+ Py_INCREF(py_nt_name);
+ } else {
+ py_nt_name = PyUnicode_FromString(group_map->nt_name);
+ }
+ talloc_free(frame);
+ return py_nt_name;
+}
+
+static int py_groupmap_set_nt_name(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (group_map->nt_name != NULL) {
+ TALLOC_FREE(group_map->nt_name);
+ }
+ if (value == Py_None) {
+ group_map->nt_name = talloc_strdup(group_map, "");
+ } else {
+ group_map->nt_name = talloc_strdup(group_map,
+ PyUnicode_AsUTF8(value));
+ }
+ TALLOC_FREE(frame);
+ if (group_map->nt_name == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *py_groupmap_get_comment(PyObject *obj, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+ PyObject *py_comment;
+ if (group_map->comment == NULL) {
+ py_comment = Py_None;
+ Py_INCREF(py_comment);
+ } else {
+ py_comment = PyUnicode_FromString(group_map->comment);
+ }
+ talloc_free(frame);
+ return py_comment;
+}
+
+static int py_groupmap_set_comment(PyObject *obj, PyObject *value, void *closure)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map = (GROUP_MAP *)pytalloc_get_ptr(obj);
+
+ PY_CHECK_TYPE(&PyUnicode_Type, value, return -1;);
+ if (group_map->comment != NULL) {
+ TALLOC_FREE(group_map->comment);
+ }
+ if (value == Py_None) {
+ group_map->comment = talloc_strdup(group_map, "");
+ } else {
+ group_map->comment = talloc_strdup(group_map,
+ PyUnicode_AsUTF8(value));
+ }
+ TALLOC_FREE(frame);
+ if (group_map->comment == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static PyGetSetDef py_groupmap_getsetters[] = {
+ {
+ .name = discard_const_p(char, "gid"),
+ .get = py_groupmap_get_gid,
+ .set = py_groupmap_set_gid,
+ },
+ {
+ .name = discard_const_p(char, "sid"),
+ .get = py_groupmap_get_sid,
+ .set = py_groupmap_set_sid,
+ },
+ {
+ .name = discard_const_p(char, "sid_name_use"),
+ .get = py_groupmap_get_sid_name_use,
+ .set = py_groupmap_set_sid_name_use,
+ },
+ {
+ .name = discard_const_p(char, "nt_name"),
+ .get = py_groupmap_get_nt_name,
+ .set = py_groupmap_set_nt_name,
+ },
+ {
+ .name = discard_const_p(char, "comment"),
+ .get = py_groupmap_get_comment,
+ .set = py_groupmap_set_comment,
+ },
+ {
+ .name = NULL,
+ },
+};
+
+static PyObject *py_groupmap_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ GROUP_MAP *group_map;
+ TALLOC_CTX *mem_ctx;
+ PyObject *py_group_map;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ group_map = talloc_zero(mem_ctx, GROUP_MAP);
+ if (group_map == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_group_map = pytalloc_steal(type, group_map);
+ if (py_group_map == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(mem_ctx);
+
+ talloc_free(frame);
+ return py_group_map;
+}
+
+
+static PyTypeObject PyGroupmap = {
+ .tp_name = "passdb.Groupmap",
+ .tp_getset = py_groupmap_getsetters,
+ .tp_methods = NULL,
+ .tp_new = py_groupmap_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_doc = "Groupmap() -> group map object\n",
+};
+
+
+static PyObject *py_pdb_domain_info(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ struct pdb_domain_info *domain_info;
+ PyObject *py_domain_info;
+ struct dom_sid *sid;
+ struct GUID *guid;
+ PyObject *py_dom_sid = NULL;
+ PyObject *py_guid = NULL;
+
+ methods = pytalloc_get_ptr(self);
+
+ domain_info = methods->get_domain_info(methods, frame);
+ if (! domain_info) {
+ Py_RETURN_NONE;
+ }
+
+ sid = dom_sid_dup(frame, &domain_info->sid);
+ if (sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ guid = talloc(frame, struct GUID);
+ if (guid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+ *guid = domain_info->guid;
+
+ py_dom_sid = pytalloc_steal(dom_sid_Type, sid);
+ py_guid = pytalloc_steal(guid_Type, guid);
+
+ py_domain_info = Py_BuildValue(
+ "{s:s, s:s, s:s, s:O, s:O}",
+ "name", domain_info->name,
+ "dns_domain", domain_info->dns_domain,
+ "dns_forest", domain_info->dns_forest,
+ "dom_sid", py_dom_sid,
+ "guid", py_guid);
+
+
+ Py_CLEAR(py_dom_sid);
+ Py_CLEAR(py_guid);
+ talloc_free(frame);
+ return py_domain_info;
+}
+
+
+static PyObject *py_pdb_getsampwnam(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ const char *username;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "s:getsampwnam", &username)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ py_sam_acct = py_samu_new(&PySamu, NULL, NULL);
+ if (py_sam_acct == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+ sam_acct = (struct samu *)pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->getsampwnam(methods, sam_acct, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get user information for '%s', (%d,%s)",
+ username,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ Py_DECREF(py_sam_acct);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_sam_acct;
+}
+
+static PyObject *py_pdb_getsampwsid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+ PyObject *py_user_sid;
+
+ if (!PyArg_ParseTuple(args, "O:getsampwsid", &py_user_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ py_sam_acct = py_samu_new(&PySamu, NULL, NULL);
+ if (py_sam_acct == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+ sam_acct = (struct samu *)pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->getsampwsid(methods, sam_acct, pytalloc_get_ptr(py_user_sid));
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get user information from SID, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ Py_DECREF(py_sam_acct);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_sam_acct;
+}
+
+static PyObject *py_pdb_create_user(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *username;
+ unsigned int acct_flags;
+ unsigned int rid;
+
+ if (!PyArg_ParseTuple(args, "sI:create_user", &username, &acct_flags)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->create_user(methods, frame, username, acct_flags, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to create user (%s), (%d,%s)",
+ username,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return PyLong_FromLong(rid);
+}
+
+static PyObject *py_pdb_delete_user(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "O!:delete_user", &PySamu, &py_sam_acct)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->delete_user(methods, frame, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete user, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_pdb_add_sam_account(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "O!:add_sam_account", &PySamu, &py_sam_acct)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->add_sam_account(methods, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to add sam account '%s', (%d,%s)",
+ sam_acct->username,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_pdb_update_sam_account(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "O!:update_sam_account", &PySamu, &py_sam_acct)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->update_sam_account(methods, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to update sam account, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_pdb_delete_sam_account(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "O!:delete_sam_account", &PySamu, &py_sam_acct)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->delete_sam_account(methods, sam_acct);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete sam account, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_pdb_rename_sam_account(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ struct samu *sam_acct;
+ const char *new_username;
+ PyObject *py_sam_acct;
+
+ if (!PyArg_ParseTuple(args, "O!s:rename_sam_account", &PySamu, &py_sam_acct,
+ &new_username)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->rename_sam_account(methods, sam_acct, new_username);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to rename sam account, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_getgrsid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ GROUP_MAP *group_map;
+ struct dom_sid *domain_sid;
+ PyObject *py_domain_sid, *py_group_map;
+
+ if (!PyArg_ParseTuple(args, "O!:getgrsid", dom_sid_Type, &py_domain_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ domain_sid = pytalloc_get_ptr(py_domain_sid);
+
+ py_group_map = py_groupmap_new(&PyGroupmap, NULL, NULL);
+ if (py_group_map == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ group_map = pytalloc_get_ptr(py_group_map);
+
+ status = methods->getgrsid(methods, group_map, *domain_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get group information by sid, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_group_map;
+}
+
+
+static PyObject *py_pdb_getgrgid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ GROUP_MAP *group_map;
+ PyObject *py_group_map;
+ unsigned int gid_value;
+
+ if (!PyArg_ParseTuple(args, "I:getgrgid", &gid_value)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ py_group_map = py_groupmap_new(&PyGroupmap, NULL, NULL);
+ if (py_group_map == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ group_map = pytalloc_get_ptr(py_group_map);
+
+ status = methods->getgrgid(methods, group_map, gid_value);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get group information by gid, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_group_map;
+}
+
+
+static PyObject *py_pdb_getgrnam(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ GROUP_MAP *group_map;
+ PyObject *py_group_map;
+ const char *groupname;
+
+ if (!PyArg_ParseTuple(args, "s:getgrnam", &groupname)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ py_group_map = py_groupmap_new(&PyGroupmap, NULL, NULL);
+ if (py_group_map == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ group_map = pytalloc_get_ptr(py_group_map);
+
+ status = methods->getgrnam(methods, group_map, groupname);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get group information by name, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_group_map;
+}
+
+
+static PyObject *py_pdb_create_dom_group(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *groupname;
+ uint32_t group_rid;
+
+ if (!PyArg_ParseTuple(args, "s:create_dom_group", &groupname)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->create_dom_group(methods, frame, groupname, &group_rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to create domain group (%s), (%d,%s)",
+ groupname,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return PyLong_FromLong(group_rid);
+}
+
+
+static PyObject *py_pdb_delete_dom_group(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ unsigned int group_rid;
+
+ if (!PyArg_ParseTuple(args, "I:delete_dom_group", &group_rid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->delete_dom_group(methods, frame, group_rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete domain group (rid=%d), (%d,%s)",
+ group_rid,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_add_group_mapping_entry(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_group_map;
+ GROUP_MAP *group_map;
+
+ if (!PyArg_ParseTuple(args, "O!:add_group_mapping_entry", &PyGroupmap, &py_group_map)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ group_map = pytalloc_get_ptr(py_group_map);
+
+ status = methods->add_group_mapping_entry(methods, group_map);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to add group mapping entry, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_update_group_mapping_entry(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_group_map;
+ GROUP_MAP *group_map;
+
+ if (!PyArg_ParseTuple(args, "O!:update_group_mapping_entry", &PyGroupmap, &py_group_map)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ group_map = pytalloc_get_ptr(py_group_map);
+
+ status = methods->update_group_mapping_entry(methods, group_map);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to update group mapping entry, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_delete_group_mapping_entry(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_group_sid;
+ struct dom_sid *group_sid;
+
+ if (!PyArg_ParseTuple(args, "O!:delete_group_mapping_entry", dom_sid_Type, &py_group_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ group_sid = pytalloc_get_ptr(py_group_sid);
+
+ status = methods->delete_group_mapping_entry(methods, *group_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete group mapping entry, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_enum_group_mapping(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ enum lsa_SidType sid_name_use;
+ int lsa_sidtype_value = SID_NAME_UNKNOWN;
+ int unix_only = 0;
+ PyObject *py_domain_sid = Py_None;
+ struct dom_sid *domain_sid = NULL;
+ GROUP_MAP **gmap = NULL;
+ GROUP_MAP *group_map;
+ size_t i, num_entries;
+ PyObject *py_gmap_list, *py_group_map;
+
+ if (!PyArg_ParseTuple(args, "|O!ii:enum_group_mapping", dom_sid_Type, &py_domain_sid,
+ &lsa_sidtype_value, &unix_only)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sid_name_use = lsa_sidtype_value;
+
+ if (py_domain_sid != Py_None) {
+ domain_sid = pytalloc_get_ptr(py_domain_sid);
+ }
+
+ status = methods->enum_group_mapping(methods, domain_sid, sid_name_use,
+ &gmap, &num_entries, unix_only);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to enumerate group mappings, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_gmap_list = PyList_New(0);
+ if (py_gmap_list == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for(i=0; i<num_entries; i++) {
+ py_group_map = py_groupmap_new(&PyGroupmap, NULL, NULL);
+ if (py_group_map) {
+ int res = 0;
+ group_map = pytalloc_get_ptr(py_group_map);
+ *group_map = *gmap[i];
+ talloc_steal(group_map, gmap[i]->nt_name);
+ talloc_steal(group_map, gmap[i]->comment);
+
+ res = PyList_Append(py_gmap_list, py_group_map);
+ Py_CLEAR(py_group_map);
+ if (res == -1) {
+ Py_CLEAR(py_gmap_list);
+ talloc_free(frame);
+ return NULL;
+ }
+ }
+ }
+
+ talloc_free(gmap);
+
+ talloc_free(frame);
+ return py_gmap_list;
+}
+
+
+static PyObject *py_pdb_enum_group_members(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_group_sid;
+ struct dom_sid *group_sid;
+ uint32_t *member_rids;
+ size_t i, num_members;
+ PyObject *py_sid_list;
+ struct dom_sid *domain_sid, *member_sid;
+
+ if (!PyArg_ParseTuple(args, "O!:enum_group_members", dom_sid_Type, &py_group_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ group_sid = pytalloc_get_ptr(py_group_sid);
+
+ status = methods->enum_group_members(methods, frame, group_sid,
+ &member_rids, &num_members);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to enumerate group members, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid_list = PyList_New(0);
+ if (py_sid_list == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ domain_sid = get_global_sam_sid();
+
+ for(i=0; i<num_members; i++) {
+ int res = 0;
+ PyObject *py_member_sid = NULL;
+ member_sid = dom_sid_add_rid(frame, domain_sid, member_rids[i]);
+ py_member_sid = pytalloc_steal(dom_sid_Type, member_sid);
+ res = PyList_Append(py_sid_list,
+ py_member_sid);
+ Py_CLEAR(py_member_sid);
+ if (res == -1) {
+ talloc_free(frame);
+ Py_CLEAR(py_sid_list);
+ return NULL;
+ }
+ }
+
+ talloc_free(frame);
+ return py_sid_list;
+}
+
+
+static PyObject *py_pdb_enum_group_memberships(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ uint32_t i;
+
+ struct samu *sam_acct;
+ PyObject *py_sam_acct;
+ PyObject *py_sid_list;
+ struct dom_sid *user_group_sids = NULL;
+ gid_t *user_group_ids = NULL;
+ uint32_t num_groups = 0;
+
+ if (!PyArg_ParseTuple(args, "O!:enum_group_memberships", &PySamu, &py_sam_acct)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sam_acct = pytalloc_get_ptr(py_sam_acct);
+
+ status = methods->enum_group_memberships(methods, frame, sam_acct,
+ &user_group_sids, &user_group_ids, &num_groups);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to enumerate group memberships, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid_list = PyList_New(0);
+ if (py_sid_list == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for(i=0; i<num_groups; i++) {
+ PyObject *py_sid =
+ pytalloc_steal(dom_sid_Type,
+ dom_sid_dup(NULL, &user_group_sids[i]));
+ PyList_Append(py_sid_list, py_sid);
+ Py_CLEAR(py_sid);
+ }
+
+ talloc_free(frame);
+ return py_sid_list;
+}
+
+
+static PyObject *py_pdb_add_groupmem(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ uint32_t group_rid, member_rid;
+
+ if (!PyArg_ParseTuple(args, "II:add_groupmem", &group_rid, &member_rid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->add_groupmem(methods, frame, group_rid, member_rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to add group member, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_del_groupmem(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ uint32_t group_rid, member_rid;
+
+ if (!PyArg_ParseTuple(args, "II:del_groupmem", &group_rid, &member_rid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->del_groupmem(methods, frame, group_rid, member_rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to rename sam account, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_create_alias(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *alias_name;
+ uint32_t rid;
+
+ if (!PyArg_ParseTuple(args, "s:create_alias", &alias_name)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->create_alias(methods, alias_name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to create alias (%s), (%d,%s)",
+ alias_name,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return PyLong_FromLong(rid);
+}
+
+
+static PyObject *py_pdb_delete_alias(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid;
+ struct dom_sid *alias_sid;
+
+ if (!PyArg_ParseTuple(args, "O!:delete_alias", dom_sid_Type, &py_alias_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+
+ status = methods->delete_alias(methods, alias_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete alias, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_get_aliasinfo(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid;
+ struct dom_sid *alias_sid;
+ struct acct_info *alias_info;
+ PyObject *py_alias_info;
+
+ if (!PyArg_ParseTuple(args, "O!:get_aliasinfo", dom_sid_Type, &py_alias_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+
+ alias_info = talloc_zero(frame, struct acct_info);
+ if (!alias_info) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ status = methods->get_aliasinfo(methods, alias_sid, alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get alias information, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_alias_info = Py_BuildValue(
+ "{s:s, s:s, s:l}",
+ "acct_name", alias_info->acct_name,
+ "acct_desc", alias_info->acct_desc,
+ "rid", alias_info->rid);
+
+ talloc_free(frame);
+ return py_alias_info;
+}
+
+
+static PyObject *py_pdb_set_aliasinfo(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid, *py_alias_info;
+ struct dom_sid *alias_sid;
+ struct acct_info alias_info;
+
+ if (!PyArg_ParseTuple(args, "O!O:set_alias_info", dom_sid_Type, &py_alias_sid,
+ &py_alias_info)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+
+ alias_info.acct_name = talloc_strdup(frame, PyUnicode_AsUTF8(PyDict_GetItemString(py_alias_info, "acct_name")));
+ if (alias_info.acct_name == NULL) {
+ PyErr_Format(py_pdb_error, "Unable to allocate memory");
+ talloc_free(frame);
+ return NULL;
+ }
+ alias_info.acct_desc = talloc_strdup(frame, PyUnicode_AsUTF8(PyDict_GetItemString(py_alias_info, "acct_desc")));
+ if (alias_info.acct_desc == NULL) {
+ PyErr_Format(py_pdb_error, "Unable to allocate memory");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ status = methods->set_aliasinfo(methods, alias_sid, &alias_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to set alias information, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_add_aliasmem(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid, *py_member_sid;
+ struct dom_sid *alias_sid, *member_sid;
+
+ if (!PyArg_ParseTuple(args, "O!O!:add_aliasmem", dom_sid_Type, &py_alias_sid,
+ dom_sid_Type, &py_member_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+ member_sid = pytalloc_get_ptr(py_member_sid);
+
+ status = methods->add_aliasmem(methods, alias_sid, member_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to add member to alias, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_del_aliasmem(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid, *py_member_sid;
+ const struct dom_sid *alias_sid, *member_sid;
+
+ if (!PyArg_ParseTuple(args, "O!O!:del_aliasmem", dom_sid_Type, &py_alias_sid,
+ dom_sid_Type, &py_member_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+ member_sid = pytalloc_get_ptr(py_member_sid);
+
+ status = methods->del_aliasmem(methods, alias_sid, member_sid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete member from alias, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_enum_aliasmem(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_alias_sid;
+ struct dom_sid *alias_sid, *member_sid, *tmp_sid;
+ PyObject *py_member_list, *py_member_sid;
+ size_t i, num_members;
+
+ if (!PyArg_ParseTuple(args, "O!:enum_aliasmem", dom_sid_Type, &py_alias_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ alias_sid = pytalloc_get_ptr(py_alias_sid);
+
+ status = methods->enum_aliasmem(methods, alias_sid, frame, &member_sid, &num_members);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to enumerate members for alias, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_member_list = PyList_New(0);
+ if (py_member_list == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for(i=0; i<num_members; i++) {
+ int res = 0;
+ py_member_sid = pytalloc_new(struct dom_sid, dom_sid_Type);
+ if (py_member_sid == NULL) {
+ PyErr_NoMemory();
+ Py_CLEAR(py_member_list);
+ talloc_free(frame);
+ return NULL;
+ }
+ tmp_sid = pytalloc_get_ptr(py_member_sid);
+ *tmp_sid = member_sid[i];
+ res = PyList_Append(py_member_list, py_member_sid);
+ Py_CLEAR(py_member_sid);
+ if (res == -1) {
+ Py_CLEAR(py_member_list);
+ talloc_free(frame);
+ return NULL;
+ }
+ }
+
+ talloc_free(frame);
+ return py_member_list;
+}
+
+
+static PyObject *py_pdb_get_account_policy(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_acct_policy;
+ uint32_t value;
+ const char **names;
+ int count, i;
+ enum pdb_policy_type type;
+
+ methods = pytalloc_get_ptr(self);
+
+ py_acct_policy = PyDict_New();
+ if (py_acct_policy == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ account_policy_names_list(frame, &names, &count);
+ for (i=0; i<count; i++) {
+ type = account_policy_name_to_typenum(names[i]);
+ status = methods->get_account_policy(methods, type, &value);
+ if (NT_STATUS_IS_OK(status)) {
+ int res = 0;
+ PyObject *py_value = Py_BuildValue("i", value);
+ if (py_value == NULL) {
+ Py_CLEAR(py_acct_policy);
+ break;
+ }
+ res = PyDict_SetItemString(py_acct_policy,
+ names[i],
+ py_value);
+ Py_CLEAR(py_value);
+ if (res == -1) {
+ Py_CLEAR(py_acct_policy);
+ break;
+ }
+ }
+ }
+
+ talloc_free(frame);
+ return py_acct_policy;
+}
+
+
+static PyObject *py_pdb_set_account_policy(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_acct_policy, *py_value;
+ const char **names;
+ int count, i;
+ enum pdb_policy_type type;
+
+ if (!PyArg_ParseTuple(args, "O!:set_account_policy", PyDict_Type, &py_acct_policy)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ account_policy_names_list(frame, &names, &count);
+ for (i=0; i<count; i++) {
+ if ((py_value = PyDict_GetItemString(py_acct_policy, names[i])) != NULL) {
+ type = account_policy_name_to_typenum(names[i]);
+ status = methods->set_account_policy(methods, type, PyLong_AsLong(py_value));
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Error setting account policy (%s), (%d,%s)",
+ names[i],
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ }
+ }
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_pdb_search_users(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ unsigned int acct_flags;
+ struct pdb_search *search;
+ struct samr_displayentry *entry;
+ PyObject *py_userlist, *py_dict;
+
+ if (!PyArg_ParseTuple(args, "I:search_users", &acct_flags)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ search = talloc_zero(frame, struct pdb_search);
+ if (search == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if (!methods->search_users(methods, search, acct_flags)) {
+ PyErr_Format(py_pdb_error, "Unable to search users");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ entry = talloc_zero(frame, struct samr_displayentry);
+ if (entry == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_userlist = PyList_New(0);
+ if (py_userlist == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ while (search->next_entry(search, entry)) {
+ int res = 1;
+ py_dict = Py_BuildValue(
+ "{s:l, s:l, s:l, s:s, s:s, s:s}",
+ "idx", entry->idx,
+ "rid", entry->rid,
+ "acct_flags", entry->acct_flags,
+ "account_name", entry->account_name,
+ "fullname", entry->fullname,
+ "description", entry->description);
+ if (py_dict == NULL) {
+ Py_CLEAR(py_userlist);
+ goto out;
+ }
+
+ res = PyList_Append(py_userlist, py_dict);
+ Py_CLEAR(py_dict);
+ if (res == -1) {
+ Py_CLEAR(py_userlist);
+ goto out;
+ }
+ }
+ search->search_end(search);
+
+out:
+ talloc_free(frame);
+ return py_userlist;
+}
+
+
+static PyObject *py_pdb_search_groups(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ struct pdb_search *search;
+ struct samr_displayentry *entry;
+ PyObject *py_grouplist, *py_dict;
+
+ methods = pytalloc_get_ptr(self);
+
+ search = talloc_zero(frame, struct pdb_search);
+ if (search == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if (!methods->search_groups(methods, search)) {
+ PyErr_Format(py_pdb_error, "Unable to search groups");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ entry = talloc_zero(frame, struct samr_displayentry);
+ if (entry == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_grouplist = PyList_New(0);
+ if (py_grouplist == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ while (search->next_entry(search, entry)) {
+ int res = 0;
+ py_dict = Py_BuildValue(
+ "{s:l, s:l, s:l, s:s, s:s, s:s}",
+ "idx", entry->idx,
+ "rid", entry->rid,
+ "acct_flags", entry->acct_flags,
+ "account_name", entry->account_name,
+ "fullname", entry->fullname,
+ "description", entry->description);
+
+ if (py_dict == NULL) {
+ Py_CLEAR(py_grouplist);
+ goto out;
+ }
+
+ res = PyList_Append(py_grouplist, py_dict);
+ Py_CLEAR(py_dict);
+ if (res == -1) {
+ Py_CLEAR(py_grouplist);
+ goto out;
+ }
+ }
+ search->search_end(search);
+out:
+ talloc_free(frame);
+ return py_grouplist;
+}
+
+
+static PyObject *py_pdb_search_aliases(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ struct pdb_search *search;
+ struct samr_displayentry *entry;
+ PyObject *py_aliaslist, *py_dict;
+ PyObject *py_domain_sid = Py_None;
+ struct dom_sid *domain_sid = NULL;
+
+ if (!PyArg_ParseTuple(args, "|O!:search_aliases", dom_sid_Type, &py_domain_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ if (py_domain_sid != Py_None) {
+ domain_sid = pytalloc_get_ptr(py_domain_sid);
+ }
+
+ search = talloc_zero(frame, struct pdb_search);
+ if (search == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if (!methods->search_aliases(methods, search, domain_sid)) {
+ PyErr_Format(py_pdb_error, "Unable to search aliases");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ entry = talloc_zero(frame, struct samr_displayentry);
+ if (entry == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_aliaslist = PyList_New(0);
+ if (py_aliaslist == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ while (search->next_entry(search, entry)) {
+ int res = 0;
+
+ py_dict = Py_BuildValue(
+ "{s:l, s:l, s:l, s:s, s:s, s:s}",
+ "idx", entry->idx,
+ "rid", entry->rid,
+ "acct_flags", entry->acct_flags,
+ "account_name", entry->account_name,
+ "fullname", entry->fullname,
+ "description", entry->description);
+
+ if (py_dict == NULL) {
+ Py_CLEAR(py_aliaslist);
+ goto out;
+ }
+ res = PyList_Append(py_aliaslist, py_dict);
+ Py_CLEAR(py_dict);
+ if (res == -1) {
+ Py_CLEAR(py_aliaslist);
+ goto out;
+ }
+ }
+ search->search_end(search);
+out:
+ talloc_free(frame);
+ return py_aliaslist;
+}
+
+
+static PyObject *py_pdb_uid_to_sid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ struct unixid id;
+ unsigned int uid;
+ struct dom_sid user_sid, *copy_user_sid;
+ PyObject *py_user_sid;
+
+ if (!PyArg_ParseTuple(args, "I:uid_to_sid", &uid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ id.id = uid;
+ id.type = ID_TYPE_UID;
+
+ if (!methods->id_to_sid(methods, &id, &user_sid)) {
+ PyErr_Format(py_pdb_error, "Unable to get sid for uid=%d", uid);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ copy_user_sid = dom_sid_dup(frame, &user_sid);
+ if (copy_user_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_user_sid = pytalloc_steal(dom_sid_Type, copy_user_sid);
+
+ talloc_free(frame);
+ return py_user_sid;
+}
+
+
+static PyObject *py_pdb_gid_to_sid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ struct unixid id;
+ unsigned int gid;
+ struct dom_sid group_sid, *copy_group_sid;
+ PyObject *py_group_sid;
+
+ if (!PyArg_ParseTuple(args, "I:gid_to_sid", &gid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ id.id = gid;
+ id.type = ID_TYPE_GID;
+
+ methods = pytalloc_get_ptr(self);
+
+ if (!methods->id_to_sid(methods, &id, &group_sid)) {
+ PyErr_Format(py_pdb_error, "Unable to get sid for gid=%d", gid);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ copy_group_sid = dom_sid_dup(frame, &group_sid);
+ if (copy_group_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_group_sid = pytalloc_steal(dom_sid_Type, copy_group_sid);
+
+ talloc_free(frame);
+ return py_group_sid;
+}
+
+
+static PyObject *py_pdb_sid_to_id(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ PyObject *py_sid;
+ struct dom_sid *sid;
+ struct unixid id;
+
+ if (!PyArg_ParseTuple(args, "O!:sid_to_id", dom_sid_Type, &py_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ sid = pytalloc_get_ptr(py_sid);
+
+ if (!methods->sid_to_id(methods, sid, &id)) {
+ PyErr_Format(py_pdb_error, "Unable to get id for sid");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return Py_BuildValue("(II)", id.id, id.type);
+}
+
+
+static PyObject *py_pdb_new_rid(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ uint32_t rid;
+
+ methods = pytalloc_get_ptr(self);
+
+ if (!methods->new_rid(methods, &rid)) {
+ PyErr_Format(py_pdb_error, "Unable to get new rid");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return PyLong_FromLong(rid);
+}
+
+
+static PyObject *py_pdb_get_trusteddom_pw(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ const char *domain;
+ char *pwd;
+ struct dom_sid sid, *copy_sid;
+ PyObject *py_sid;
+ time_t last_set_time;
+ PyObject *py_value;
+
+ if (!PyArg_ParseTuple(args, "s:get_trusteddom_pw", &domain)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ if (!methods->get_trusteddom_pw(methods, domain, &pwd, &sid, &last_set_time)) {
+ PyErr_Format(py_pdb_error, "Unable to get trusted domain password");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ copy_sid = dom_sid_dup(frame, &sid);
+ if (copy_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid = pytalloc_steal(dom_sid_Type, copy_sid);
+ if (py_sid == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_value = Py_BuildValue(
+ "{s:s, s:O, s:l}",
+ "pwd", pwd,
+ "sid", py_sid,
+ "last_set_tim", last_set_time);
+
+ Py_CLEAR(py_sid);
+ talloc_free(frame);
+ return py_value;
+}
+
+
+static PyObject *py_pdb_set_trusteddom_pw(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ const char *domain;
+ const char *pwd;
+ const struct dom_sid *domain_sid;
+ PyObject *py_domain_sid;
+
+ if (!PyArg_ParseTuple(args, "ssO!:set_trusteddom_pw", &domain, &pwd,
+ dom_sid_Type, &py_domain_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ domain_sid = pytalloc_get_ptr(py_domain_sid);
+
+ if (!methods->set_trusteddom_pw(methods, domain, pwd, domain_sid)) {
+ PyErr_Format(py_pdb_error, "Unable to set trusted domain password");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_del_trusteddom_pw(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct pdb_methods *methods;
+ const char *domain;
+
+ if (!PyArg_ParseTuple(args, "s:del_trusteddom_pw", &domain)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ if (!methods->del_trusteddom_pw(methods, domain)) {
+ PyErr_Format(py_pdb_error, "Unable to delete trusted domain password");
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_enum_trusteddoms(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ uint32_t i, num_domains;
+ struct trustdom_info **domains;
+ PyObject *py_domain_list, *py_dict;
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->enum_trusteddoms(methods, frame, &num_domains, &domains);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to enumerate trusted domains, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_domain_list = PyList_New(0);
+ if (py_domain_list == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for(i=0; i<num_domains; i++) {
+ int res = 0;
+ PyObject *py_sid =
+ pytalloc_steal(dom_sid_Type, &domains[i]->sid);
+ py_dict = Py_BuildValue(
+ "{s:s, s:O}",
+ "name", domains[i]->name,
+ "sid", py_sid);
+ Py_CLEAR(py_sid);
+ if (py_dict == NULL) {
+ DBG_ERR("Failed to insert entry to dict\n");
+ Py_CLEAR(py_domain_list);
+ break;
+ }
+
+ res = PyList_Append(py_domain_list, py_dict);
+ Py_CLEAR(py_dict);
+ if (res == -1) {
+ Py_CLEAR(py_domain_list);
+ break;
+ }
+ }
+
+ talloc_free(frame);
+ return py_domain_list;
+}
+
+
+static PyObject *py_pdb_get_trusted_domain(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *domain;
+ struct pdb_trusted_domain *td;
+ PyObject *py_domain_info;
+ PyObject *py_sid = NULL;
+
+ if (!PyArg_ParseTuple(args, "s:get_trusted_domain", &domain)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->get_trusted_domain(methods, frame, domain, &td);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get trusted domain information, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid = pytalloc_steal(dom_sid_Type, &td->security_identifier);
+
+ py_domain_info = Py_BuildValue(
+ "{s:s, s:s, s:O,"
+ " s:"PYARG_BYTES_LEN","
+ " s:"PYARG_BYTES_LEN","
+ " s:l, s:l, s:l,"
+ " s:"PYARG_BYTES_LEN"}",
+ "domain_name", td->domain_name,
+ "netbios_name", td->netbios_name,
+ "security_identifier", py_sid,
+ "trust_auth_incoming",
+ (const char *)td->trust_auth_incoming.data,
+ td->trust_auth_incoming.length,
+ "trust_auth_outgoing",
+ (const char *)td->trust_auth_outgoing.data,
+ td->trust_auth_outgoing.length,
+ "trust_direction", td->trust_direction,
+ "trust_type", td->trust_type,
+ "trust_attributes", td->trust_attributes,
+ "trust_forest_trust_info",
+ (const char *)td->trust_forest_trust_info.data,
+ td->trust_forest_trust_info.length);
+ Py_CLEAR(py_sid);
+
+ talloc_free(frame);
+ return py_domain_info;
+}
+
+
+static PyObject *py_pdb_get_trusted_domain_by_sid(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ PyObject *py_domain_sid;
+ struct dom_sid *domain_sid;
+ struct pdb_trusted_domain *td;
+ PyObject *py_domain_info;
+ PyObject *py_sid = NULL;
+
+ if (!PyArg_ParseTuple(args, "O!:get_trusted_domain_by_sid", dom_sid_Type, &py_domain_sid)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ domain_sid = pytalloc_get_ptr(py_domain_sid);
+
+ status = methods->get_trusted_domain_by_sid(methods, frame, domain_sid, &td);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get trusted domain information, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_sid = pytalloc_steal(dom_sid_Type, &td->security_identifier);
+
+ py_domain_info = Py_BuildValue(
+ "{s:s, s:s, s:O,"
+ " s:"PYARG_BYTES_LEN","
+ " s:"PYARG_BYTES_LEN","
+ " s:l, s:l, s:l,"
+ " s:"PYARG_BYTES_LEN"}",
+ "domain_name", td->domain_name,
+ "netbios_name", td->netbios_name,
+ "security_identifier", py_sid,
+ "trust_auth_incoming",
+ (const char *)td->trust_auth_incoming.data,
+ td->trust_auth_incoming.length,
+ "trust_auth_outgoing",
+ (const char *)td->trust_auth_outgoing.data,
+ td->trust_auth_outgoing.length,
+ "trust_direction", td->trust_direction,
+ "trust_type", td->trust_type,
+ "trust_attributes", td->trust_attributes,
+ "trust_forest_trust_info",
+ (const char *)td->trust_forest_trust_info.data,
+ td->trust_forest_trust_info.length);
+ Py_CLEAR(py_sid);
+
+ talloc_free(frame);
+ return py_domain_info;
+}
+
+
+static PyObject *py_pdb_set_trusted_domain(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *domain;
+ PyObject *py_td_info;
+ struct pdb_trusted_domain td_info;
+ PyObject *py_tmp;
+ Py_ssize_t len;
+
+ if (!PyArg_ParseTuple(args, "sO!:set_trusted_domain", &domain, &PyDict_Type, &py_td_info)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_tmp = PyDict_GetItemString(py_td_info, "domain_name");
+ td_info.domain_name = discard_const_p(char, PyUnicode_AsUTF8(py_tmp));
+
+ py_tmp = PyDict_GetItemString(py_td_info, "netbios_name");
+ td_info.netbios_name = discard_const_p(char, PyUnicode_AsUTF8(py_tmp));
+
+ py_tmp = PyDict_GetItemString(py_td_info, "security_identifier");
+ td_info.security_identifier = *pytalloc_get_type(py_tmp, struct dom_sid);
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_auth_incoming");
+ PyBytes_AsStringAndSize(py_tmp, (char **)&td_info.trust_auth_incoming.data, &len);
+ td_info.trust_auth_incoming.length = len;
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_auth_outgoing");
+ PyBytes_AsStringAndSize(py_tmp, (char **)&td_info.trust_auth_outgoing.data, &len);
+ td_info.trust_auth_outgoing.length = len;
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_direction");
+ td_info.trust_direction = PyLong_AsLong(py_tmp);
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_type");
+ td_info.trust_type = PyLong_AsLong(py_tmp);
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_attributes");
+ td_info.trust_attributes = PyLong_AsLong(py_tmp);
+
+ py_tmp = PyDict_GetItemString(py_td_info, "trust_forest_trust_info");
+ PyBytes_AsStringAndSize(py_tmp, (char **)&td_info.trust_forest_trust_info.data, &len);
+ td_info.trust_forest_trust_info.length = len;
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->set_trusted_domain(methods, domain, &td_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to set trusted domain information, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_del_trusted_domain(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *domain;
+
+ if (!PyArg_ParseTuple(args, "s:del_trusted_domain", &domain)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->del_trusted_domain(methods, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete trusted domain, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_enum_trusted_domains(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ uint32_t i, num_domains;
+ struct pdb_trusted_domain **td_info;
+ PyObject *py_td_info, *py_domain_info;
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->enum_trusted_domains(methods, frame, &num_domains, &td_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete trusted domain, (%d,%s)",
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_td_info = PyList_New(0);
+ if (py_td_info == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ int res = 0;
+ struct pdb_trusted_domain *td = td_info[i];
+ PyObject *py_sid =
+ pytalloc_steal(dom_sid_Type, &td->security_identifier);
+
+ py_domain_info = Py_BuildValue(
+ "{s:s, s:s, s:O,"
+ " s:"PYARG_BYTES_LEN","
+ " s:"PYARG_BYTES_LEN","
+ " s:l, s:l, s:l,"
+ " s:"PYARG_BYTES_LEN"}",
+ "domain_name", td->domain_name,
+ "netbios_name", td->netbios_name,
+ "security_identifier", py_sid,
+ "trust_auth_incoming",
+ (const char *)td->trust_auth_incoming.data,
+ td->trust_auth_incoming.length,
+ "trust_auth_outgoing",
+ (const char *)td->trust_auth_outgoing.data,
+ td->trust_auth_outgoing.length,
+ "trust_direction", td->trust_direction,
+ "trust_type", td->trust_type,
+ "trust_attributes", td->trust_attributes,
+ "trust_forest_trust_info",
+ (const char *)td->trust_forest_trust_info.data,
+ td->trust_forest_trust_info.length);
+ Py_CLEAR(py_sid);
+
+ if (py_domain_info == NULL) {
+ Py_CLEAR(py_td_info);
+ break;
+ }
+ res = PyList_Append(py_td_info, py_domain_info);
+ Py_CLEAR(py_domain_info);
+ if (res == -1) {
+ Py_CLEAR(py_td_info);
+ break;
+ }
+ }
+
+ talloc_free(frame);
+ return py_td_info;
+}
+
+
+static PyObject *py_pdb_get_secret(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *secret_name;
+ DATA_BLOB secret_current, secret_old;
+ NTTIME secret_current_lastchange, secret_old_lastchange;
+ PyObject *py_sd;
+ struct security_descriptor *sd;
+ PyObject *py_secret;
+
+ if (!PyArg_ParseTuple(args, "s:get_secret_name", &secret_name)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ py_sd = pytalloc_new(struct security_descriptor, security_Type);
+ if (py_sd == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+ sd = pytalloc_get_ptr(py_sd);
+
+ status = methods->get_secret(methods, frame, secret_name,
+ &secret_current,
+ &secret_current_lastchange,
+ &secret_old,
+ &secret_old_lastchange,
+ &sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to get information for secret (%s), (%d,%s)",
+ secret_name,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_secret = Py_BuildValue(
+ "{s:"PYARG_BYTES_LEN","
+ " s:K"
+ " s:"PYARG_BYTES_LEN","
+ " s:K, s:O}",
+ "secret_current", (const char*)secret_current.data,
+ secret_current.length,
+ "secret_current_lastchange", secret_current_lastchange,
+ "secret_old", (const char*)secret_old.data,
+ secret_old.length,
+ "secret_old_lastchange", secret_old_lastchange,
+ "sd", py_sd);
+
+ Py_CLEAR(py_sd);
+ if (py_secret == NULL) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return py_secret;
+}
+
+
+static PyObject *py_pdb_set_secret(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *secret_name;
+ PyObject *py_secret;
+ PyObject *py_secret_cur, *py_secret_old, *py_sd;
+ DATA_BLOB secret_current, secret_old;
+ struct security_descriptor *sd;
+ Py_ssize_t len;
+
+ if (!PyArg_ParseTuple(args, "sO!:set_secret_name", &secret_name, PyDict_Type, &py_secret)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_secret_cur = PyDict_GetItemString(py_secret, "secret_current");
+ py_secret_old = PyDict_GetItemString(py_secret, "secret_old");
+ py_sd = PyDict_GetItemString(py_secret, "sd");
+
+ PY_CHECK_TYPE(&PyBytes_Type, py_secret_cur, return NULL;);
+ PY_CHECK_TYPE(&PyBytes_Type, py_secret_old, return NULL;);
+ PY_CHECK_TYPE(security_Type, py_sd, return NULL;);
+
+ methods = pytalloc_get_ptr(self);
+
+ PyBytes_AsStringAndSize(py_secret_cur, (char **)&secret_current.data, &len);
+ secret_current.length = len;
+ PyBytes_AsStringAndSize(py_secret_old, (char **)&secret_old.data, &len);
+ secret_current.length = len;
+ sd = pytalloc_get_ptr(py_sd);
+
+ status = methods->set_secret(methods, secret_name, &secret_current, &secret_old, sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to set information for secret (%s), (%d,%s)",
+ secret_name,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_pdb_delete_secret(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct pdb_methods *methods;
+ const char *secret_name;
+
+ if (!PyArg_ParseTuple(args, "s:delete_secret", &secret_name)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ methods = pytalloc_get_ptr(self);
+
+ status = methods->delete_secret(methods, secret_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Unable to delete secret (%s), (%d,%s)",
+ secret_name,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_pdb_methods[] = {
+ { "domain_info", py_pdb_domain_info, METH_NOARGS,
+ "domain_info() -> str\n\n \
+ Get domain information for the database." },
+ { "getsampwnam", py_pdb_getsampwnam, METH_VARARGS,
+ "getsampwnam(username) -> samu object\n\n \
+ Get user information by name." },
+ { "getsampwsid", py_pdb_getsampwsid, METH_VARARGS,
+ "getsampwsid(user_sid) -> samu object\n\n \
+ Get user information by sid (dcerpc.security.dom_sid object)." },
+ { "create_user", py_pdb_create_user, METH_VARARGS,
+ "create_user(username, acct_flags) -> rid\n\n \
+ Create user. acct_flags are samr account control flags." },
+ { "delete_user", py_pdb_delete_user, METH_VARARGS,
+ "delete_user(samu object) -> None\n\n \
+ Delete user." },
+ { "add_sam_account", py_pdb_add_sam_account, METH_VARARGS,
+ "add_sam_account(samu object) -> None\n\n \
+ Add SAM account." },
+ { "update_sam_account", py_pdb_update_sam_account, METH_VARARGS,
+ "update_sam_account(samu object) -> None\n\n \
+ Update SAM account." },
+ { "delete_sam_account", py_pdb_delete_sam_account, METH_VARARGS,
+ "delete_sam_account(samu object) -> None\n\n \
+ Delete SAM account." },
+ { "rename_sam_account", py_pdb_rename_sam_account, METH_VARARGS,
+ "rename_sam_account(samu object1, new_username) -> None\n\n \
+ Rename SAM account." },
+ /* update_login_attempts */
+ { "getgrsid", py_pdb_getgrsid, METH_VARARGS,
+ "getgrsid(group_sid) -> groupmap object\n\n \
+ Get group information by sid (dcerpc.security.dom_sid object)." },
+ { "getgrgid", py_pdb_getgrgid, METH_VARARGS,
+ "getgrsid(gid) -> groupmap object\n\n \
+ Get group information by gid." },
+ { "getgrnam", py_pdb_getgrnam, METH_VARARGS,
+ "getgrsid(groupname) -> groupmap object\n\n \
+ Get group information by name." },
+ { "create_dom_group", py_pdb_create_dom_group, METH_VARARGS,
+ "create_dom_group(groupname) -> group_rid\n\n \
+ Create new domain group by name." },
+ { "delete_dom_group", py_pdb_delete_dom_group, METH_VARARGS,
+ "delete_dom_group(group_rid) -> None\n\n \
+ Delete domain group identified by rid" },
+ { "add_group_mapping_entry", py_pdb_add_group_mapping_entry, METH_VARARGS,
+ "add_group_mapping_entry(groupmap) -> None\n \
+ Add group mapping entry for groupmap object." },
+ { "update_group_mapping_entry", py_pdb_update_group_mapping_entry, METH_VARARGS,
+ "update_group_mapping_entry(groupmap) -> None\n\n \
+ Update group mapping entry for groupmap object." },
+ { "delete_group_mapping_entry", py_pdb_delete_group_mapping_entry, METH_VARARGS,
+ "delete_group_mapping_entry(groupmap) -> None\n\n \
+ Delete group mapping entry for groupmap object." },
+ { "enum_group_mapping", py_pdb_enum_group_mapping, METH_VARARGS,
+ "enum_group_mapping([domain_sid, [type, [unix_only]]]) -> List\n\n \
+ Return list of group mappings as groupmap objects. Optional arguments are domain_sid object, type of group, unix only flag." },
+ { "enum_group_members", py_pdb_enum_group_members, METH_VARARGS,
+ "enum_group_members(group_sid) -> List\n\n \
+ Return list of users (dom_sid object) in group." },
+ { "enum_group_memberships", py_pdb_enum_group_memberships, METH_VARARGS,
+ "enum_group_memberships(samu object) -> List\n\n \
+ Return list of groups (dom_sid object) this user is part of." },
+ /* set_unix_primary_group */
+ { "add_groupmem", py_pdb_add_groupmem, METH_VARARGS,
+ "add_groupmem(group_rid, member_rid) -> None\n\n \
+ Add user to group." },
+ { "del_groupmem", py_pdb_del_groupmem, METH_VARARGS,
+ "del_groupmem(group_rid, member_rid) -> None\n\n \
+ Remove user from group." },
+ { "create_alias", py_pdb_create_alias, METH_VARARGS,
+ "create_alias(alias_name) -> alias_rid\n\n \
+ Create alias entry." },
+ { "delete_alias", py_pdb_delete_alias, METH_VARARGS,
+ "delete_alias(alias_sid) -> None\n\n \
+ Delete alias entry." },
+ { "get_aliasinfo", py_pdb_get_aliasinfo, METH_VARARGS,
+ "get_aliasinfo(alias_sid) -> Mapping\n\n \
+ Get alias information as a dictionary with keys - acct_name, acct_desc, rid." },
+ { "set_aliasinfo", py_pdb_set_aliasinfo, METH_VARARGS,
+ "set_alias_info(alias_sid, Mapping) -> None\n\n \
+ Set alias information from a dictionary with keys - acct_name, acct_desc." },
+ { "add_aliasmem", py_pdb_add_aliasmem, METH_VARARGS,
+ "add_aliasmem(alias_sid, member_sid) -> None\n\n \
+ Add user to alias entry." },
+ { "del_aliasmem", py_pdb_del_aliasmem, METH_VARARGS,
+ "del_aliasmem(alias_sid, member_sid) -> None\n\n \
+ Remove a user from alias entry." },
+ { "enum_aliasmem", py_pdb_enum_aliasmem, METH_VARARGS,
+ "enum_aliasmem(alias_sid) -> List\n\n \
+ Return a list of members (dom_sid object) for alias entry." },
+ /* enum_alias_memberships */
+ /* lookup_rids */
+ /* lookup_names */
+ { "get_account_policy", py_pdb_get_account_policy, METH_NOARGS,
+ "get_account_policy() -> Mapping\n\n \
+ Get account policy information as a dictionary." },
+ { "set_account_policy", py_pdb_set_account_policy, METH_VARARGS,
+ "get_account_policy(Mapping) -> None\n\n \
+ Set account policy settings from a dictionary." },
+ /* get_seq_num */
+ { "search_users", py_pdb_search_users, METH_VARARGS,
+ "search_users(acct_flags) -> List\n\n \
+ Search users. acct_flags are samr account control flags.\n \
+ Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
+ { "search_groups", py_pdb_search_groups, METH_NOARGS,
+ "search_groups() -> List\n\n \
+ Search unix only groups. \n \
+ Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
+ { "search_aliases", py_pdb_search_aliases, METH_VARARGS,
+ "search_aliases([domain_sid]) -> List\n\n \
+ Search aliases. domain_sid is dcerpc.security.dom_sid object.\n \
+ Each list entry is dictionary with keys - idx, rid, acct_flags, account_name, fullname, description." },
+ { "uid_to_sid", py_pdb_uid_to_sid, METH_VARARGS,
+ "uid_to_sid(uid) -> sid\n\n \
+ Return sid for given user id." },
+ { "gid_to_sid", py_pdb_gid_to_sid, METH_VARARGS,
+ "gid_to_sid(gid) -> sid\n\n \
+ Return sid for given group id." },
+ { "sid_to_id", py_pdb_sid_to_id, METH_VARARGS,
+ "sid_to_id(sid) -> Tuple\n\n \
+ Return id and type for given sid." },
+ /* capabilities */
+ { "new_rid", py_pdb_new_rid, METH_NOARGS,
+ "new_rid() -> rid\n\n \
+ Get a new rid." },
+ { "get_trusteddom_pw", py_pdb_get_trusteddom_pw, METH_VARARGS,
+ "get_trusteddom_pw(domain) -> Mapping\n\n \
+ Get trusted domain password, sid and last set time in a dictionary." },
+ { "set_trusteddom_pw", py_pdb_set_trusteddom_pw, METH_VARARGS,
+ "set_trusteddom_pw(domain, pwd, sid) -> None\n\n \
+ Set trusted domain password." },
+ { "del_trusteddom_pw", py_pdb_del_trusteddom_pw, METH_VARARGS,
+ "del_trusteddom_pw(domain) -> None\n\n \
+ Delete trusted domain password." },
+ { "enum_trusteddoms", py_pdb_enum_trusteddoms, METH_NOARGS,
+ "enum_trusteddoms() -> List\n\n \
+ Get list of trusted domains. Each item is a dictionary with name and sid keys" },
+ { "get_trusted_domain", py_pdb_get_trusted_domain, METH_VARARGS,
+ "get_trusted_domain(domain) -> Mapping\n\n \
+ Get trusted domain information by name. Information is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
+ { "get_trusted_domain_by_sid", py_pdb_get_trusted_domain_by_sid, METH_VARARGS,
+ "get_trusted_domain_by_sid(domain_sid) -> Mapping\n\n \
+ Get trusted domain information by sid. Information is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info" },
+ { "set_trusted_domain", py_pdb_set_trusted_domain, METH_VARARGS,
+ "set_trusted_domain(domain, Mapping) -> None\n\n \
+ Set trusted domain information for domain. Mapping is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
+ { "del_trusted_domain", py_pdb_del_trusted_domain, METH_VARARGS,
+ "del_trusted_domain(domain) -> None\n\n \
+ Delete trusted domain." },
+ { "enum_trusted_domains", py_pdb_enum_trusted_domains, METH_VARARGS,
+ "enum_trusted_domains() -> List\n\n \
+ Get list of trusted domains. Each entry is a dictionary with keys - domain_name, netbios_name, security_identifier, trust_auth_incoming, trust_auth_outgoing, trust_direction, trust_type, trust_attributes, trust_forest_trust_info." },
+ { "get_secret", py_pdb_get_secret, METH_VARARGS,
+ "get_secret(secret_name) -> Mapping\n\n \
+ Get secret information for secret_name. Information is a dictionary with keys - secret_current, secret_current_lastchange, secret_old, secret_old_lastchange, sd." },
+ { "set_secret", py_pdb_set_secret, METH_VARARGS,
+ "set_secret(secret_name, Mapping) -> None\n\n \
+ Set secret information for secret_name using dictionary with keys - secret_current, sd." },
+ { "delete_secret", py_pdb_delete_secret, METH_VARARGS,
+ "delete_secret(secret_name) -> None\n\n \
+ Delete secret information for secret_name." },
+ {0},
+};
+
+
+static PyObject *py_pdb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *url = NULL;
+ PyObject *pypdb;
+ NTSTATUS status;
+ struct pdb_methods *methods;
+
+ if (!PyArg_ParseTuple(args, "s", &url)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Initialize list of methods */
+ status = make_pdb_method_name(&methods, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(py_pdb_error, "Cannot load backend methods for '%s' backend (%d,%s)",
+ url,
+ NT_STATUS_V(status),
+ get_friendly_nt_error_msg(status));
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if ((pypdb = pytalloc_steal(type, methods)) == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ return pypdb;
+}
+
+
+static PyTypeObject PyPDB = {
+ .tp_name = "passdb.PDB",
+ .tp_new = py_pdb_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = py_pdb_methods,
+ .tp_doc = "PDB(url[, read_write_flags]) -> Password DB object\n",
+};
+
+
+/*
+ * Return a list of passdb backends
+ */
+static PyObject *py_passdb_backends(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ PyObject *py_blist;
+ const struct pdb_init_function_entry *entry;
+
+ entry = pdb_get_backends();
+ if(! entry) {
+ Py_RETURN_NONE;
+ }
+
+ if((py_blist = PyList_New(0)) == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ while(entry) {
+ int res = 0;
+ PyObject *entry_name = PyUnicode_FromString(entry->name);
+ if (entry_name) {
+ res = PyList_Append(py_blist, entry_name);
+ } else {
+ Py_CLEAR(entry_name);
+ Py_CLEAR(py_blist);
+ break;
+ }
+ Py_CLEAR(entry_name);
+ if (res == -1) {
+ Py_CLEAR(py_blist);
+ break;
+ }
+ entry = entry->next;
+ }
+
+ talloc_free(frame);
+ return py_blist;
+}
+
+
+static PyObject *py_set_smb_config(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *smb_config;
+
+ if (!PyArg_ParseTuple(args, "s", &smb_config)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Load smbconf parameters */
+ if (!lp_load_global(smb_config)) {
+ PyErr_Format(py_pdb_error, "Cannot open '%s'", smb_config);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_set_secrets_dir(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *private_dir;
+
+ if (!PyArg_ParseTuple(args, "s", &private_dir)) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Initialize secrets database */
+ if (!secrets_init_path(private_dir)) {
+ PyErr_Format(py_pdb_error, "Cannot open secrets file database in '%s'",
+ private_dir);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_reload_static_pdb(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* Initialize secrets database */
+ if (!initialize_password_db(true, NULL)) {
+ PyErr_Format(py_pdb_error, "Cannot re-open passdb backend %s", lp_passdb_backend());
+ talloc_free(frame);
+ return NULL;
+ }
+
+ talloc_free(frame);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_get_domain_sid(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct dom_sid domain_sid, *domain_sid_copy;
+ PyObject *py_dom_sid = Py_None;
+ bool ret = false;
+
+ ret = secrets_fetch_domain_sid(lp_workgroup(), &domain_sid);
+ if (!ret) {
+ talloc_free(frame);
+ return PyErr_NoMemory();
+ }
+
+ domain_sid_copy = dom_sid_dup(frame, &domain_sid);
+ if (domain_sid_copy == NULL) {
+ talloc_free(frame);
+ return PyErr_NoMemory();
+ }
+
+ py_dom_sid = pytalloc_steal(dom_sid_Type, domain_sid_copy);
+
+ talloc_free(frame);
+ return py_dom_sid;
+}
+
+static PyObject *py_get_global_sam_sid(PyObject *self, PyObject *unused)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct dom_sid *domain_sid, *domain_sid_copy;
+ PyObject *py_dom_sid;
+
+ domain_sid = get_global_sam_sid();
+
+ domain_sid_copy = dom_sid_dup(frame, domain_sid);
+ if (domain_sid_copy == NULL) {
+ PyErr_NoMemory();
+ talloc_free(frame);
+ return NULL;
+ }
+
+ py_dom_sid = pytalloc_steal(dom_sid_Type, domain_sid_copy);
+
+ talloc_free(frame);
+ return py_dom_sid;
+}
+
+
+static PyMethodDef py_passdb_methods[] = {
+ { "get_backends", py_passdb_backends, METH_NOARGS,
+ "get_backends() -> list\n\n \
+ Get a list of password database backends supported." },
+ { "set_smb_config", py_set_smb_config, METH_VARARGS,
+ "set_smb_config(path) -> None\n\n \
+ Set path to smb.conf file to load configuration parameters." },
+ { "set_secrets_dir", py_set_secrets_dir, METH_VARARGS,
+ "set_secrets_dir(private_dir) -> None\n\n \
+ Set path to private directory to load secrets database from non-default location." },
+ { "get_global_sam_sid", py_get_global_sam_sid, METH_NOARGS,
+ "get_global_sam_sid() -> dom_sid\n\n \
+ Return domain SID." },
+ { "get_domain_sid", py_get_domain_sid, METH_NOARGS,
+ "get_domain_sid() -> dom_sid\n\n \
+ Return domain SID from secrets database." },
+ { "reload_static_pdb", py_reload_static_pdb, METH_NOARGS,
+ "reload_static_pdb() -> None\n\n \
+ Re-initialise the static pdb used internally. Needed if 'passdb backend' is changed." },
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "passdb",
+ .m_doc = "SAMBA Password Database",
+ .m_size = -1,
+ .m_methods = py_passdb_methods,
+};
+
+MODULE_INIT_FUNC(passdb)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ PyObject *m = NULL, *mod = NULL;
+ char exception_name[] = "passdb.error";
+
+ if (pytalloc_BaseObject_PyType_Ready(&PyPDB) < 0) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if (pytalloc_BaseObject_PyType_Ready(&PySamu) < 0) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ if (pytalloc_BaseObject_PyType_Ready(&PyGroupmap) < 0) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Create new exception for passdb module */
+ py_pdb_error = PyErr_NewException(exception_name, NULL, NULL);
+ Py_INCREF(py_pdb_error);
+ PyModule_AddObject(m, "error", py_pdb_error);
+
+ Py_INCREF(&PyPDB);
+ PyModule_AddObject(m, "PDB", (PyObject *)&PyPDB);
+
+ Py_INCREF(&PySamu);
+ PyModule_AddObject(m, "Samu", (PyObject *)&PySamu);
+
+ Py_INCREF(&PyGroupmap);
+ PyModule_AddObject(m, "Groupmap", (PyObject *)&PyGroupmap);
+
+ /* Import dom_sid type from dcerpc.security */
+ mod = PyImport_ImportModule("samba.dcerpc.security");
+ if (mod == NULL) {
+ talloc_free(frame);
+ return NULL;
+ }
+
+ dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
+ if (dom_sid_Type == NULL) {
+ Py_DECREF(mod);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Import security_descriptor type from dcerpc.security */
+ security_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "descriptor");
+ Py_DECREF(mod);
+ if (security_Type == NULL) {
+ Py_DECREF(dom_sid_Type);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ /* Import GUID type from dcerpc.misc */
+ mod = PyImport_ImportModule("samba.dcerpc.misc");
+ if (mod == NULL) {
+ Py_DECREF(security_Type);
+ Py_DECREF(dom_sid_Type);
+ talloc_free(frame);
+ return NULL;
+ }
+
+ guid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "GUID");
+ Py_DECREF(mod);
+ if (guid_Type == NULL) {
+ Py_DECREF(security_Type);
+ Py_DECREF(dom_sid_Type);
+ talloc_free(frame);
+ return NULL;
+ }
+ talloc_free(frame);
+ return m;
+}
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
new file mode 100644
index 0000000..6bbc21a
--- /dev/null
+++ b/source3/passdb/secrets.c
@@ -0,0 +1,546 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Rafal Szczesniak 2002
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_secrets.h"
+#include "secrets.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "../libcli/security/security.h"
+#include "util_tdb.h"
+#include "auth/credentials/credentials.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
+
+static struct db_context *db_ctx;
+
+/* open up the secrets database with specified private_dir path */
+bool secrets_init_path(const char *private_dir)
+{
+ char *fname = NULL;
+ TALLOC_CTX *frame;
+
+ if (db_ctx != NULL) {
+ return True;
+ }
+
+ if (private_dir == NULL) {
+ return False;
+ }
+
+ frame = talloc_stackframe();
+ fname = talloc_asprintf(frame, "%s/secrets.tdb", private_dir);
+ if (fname == NULL) {
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ db_ctx = db_open(NULL, fname, 0,
+ TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+
+ if (db_ctx == NULL) {
+ DEBUG(0,("Failed to open %s\n", fname));
+ TALLOC_FREE(frame);
+ return False;
+ }
+
+ TALLOC_FREE(frame);
+ return True;
+}
+
+/* open up the secrets database */
+bool secrets_init(void)
+{
+ return secrets_init_path(lp_private_dir());
+}
+
+struct db_context *secrets_db_ctx(void)
+{
+ if (!secrets_init()) {
+ return NULL;
+ }
+
+ return db_ctx;
+}
+
+/*
+ * close secrets.tdb
+ */
+void secrets_shutdown(void)
+{
+ TALLOC_FREE(db_ctx);
+}
+
+/* read a entry from the secrets database - the caller must free the result
+ if size is non-null then the size of the entry is put in there
+ */
+void *secrets_fetch(const char *key, size_t *size)
+{
+ TDB_DATA dbuf;
+ void *result;
+ NTSTATUS status;
+
+ if (!secrets_init()) {
+ return NULL;
+ }
+
+ status = dbwrap_fetch(db_ctx, talloc_tos(), string_tdb_data(key),
+ &dbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ result = smb_memdup(dbuf.dptr, dbuf.dsize);
+ if (result == NULL) {
+ return NULL;
+ }
+ /*
+ * secrets_fetch() is a generic code and may be used for sensitive data,
+ * so clear the local dbuf.dptr memory via BURN_PTR_SIZE().
+ * The future plan is to convert secrets_fetch() to talloc.
+ * That would improve performance via:
+ * - avoid smb_memdup() above, instead directly return dbuf.dptr
+ * - BURN_PTR_SIZE() will be done not here but in the caller and only
+ * if the caller asks for sensitive data.
+ */
+ BURN_PTR_SIZE(dbuf.dptr, dbuf.dsize);
+ TALLOC_FREE(dbuf.dptr);
+
+ if (size) {
+ *size = dbuf.dsize;
+ }
+
+ return result;
+}
+
+/* store a secrets entry
+ */
+bool secrets_store(const char *key, const void *data, size_t size)
+{
+ NTSTATUS status;
+
+ if (!secrets_init()) {
+ return false;
+ }
+
+ status = dbwrap_trans_store(db_ctx, string_tdb_data(key),
+ make_tdb_data((const uint8_t *)data, size),
+ TDB_REPLACE);
+ return NT_STATUS_IS_OK(status);
+}
+
+bool secrets_store_creds(struct cli_credentials *creds)
+{
+ const char *p = NULL;
+ bool ok;
+
+ p = cli_credentials_get_username(creds);
+ if (p == NULL) {
+ return false;
+ }
+
+ ok = secrets_store(SECRETS_AUTH_USER, p, strlen(p) + 1);
+ if (!ok) {
+ DBG_ERR("Failed storing auth user name\n");
+ return false;
+ }
+
+
+ p = cli_credentials_get_domain(creds);
+ if (p == NULL) {
+ return false;
+ }
+
+ ok = secrets_store(SECRETS_AUTH_DOMAIN, p, strlen(p) + 1);
+ if (!ok) {
+ DBG_ERR("Failed storing auth domain name\n");
+ return false;
+ }
+
+
+ p = cli_credentials_get_password(creds);
+ if (p == NULL) {
+ return false;
+ }
+
+ ok = secrets_store(SECRETS_AUTH_PASSWORD, p, strlen(p) + 1);
+ if (!ok) {
+ DBG_ERR("Failed storing auth password\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+/* delete a secets database entry
+ */
+bool secrets_delete_entry(const char *key)
+{
+ NTSTATUS status;
+ if (!secrets_init()) {
+ return false;
+ }
+
+ status = dbwrap_trans_delete(db_ctx, string_tdb_data(key));
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/*
+ * Deletes the key if it exists.
+ */
+bool secrets_delete(const char *key)
+{
+ bool exists;
+
+ if (!secrets_init()) {
+ return false;
+ }
+
+ exists = dbwrap_exists(db_ctx, string_tdb_data(key));
+ if (!exists) {
+ return true;
+ }
+
+ return secrets_delete_entry(key);
+}
+
+/**
+ * Form a key for fetching a trusted domain password
+ *
+ * @param domain trusted domain name
+ *
+ * @return stored password's key
+ **/
+static char *trustdom_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_DOMTRUST_ACCT_PASS,
+ domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get account password to trusted domain
+************************************************************************/
+
+bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
+ struct dom_sid *sid, time_t *pass_last_set_time)
+{
+ struct TRUSTED_DOM_PASS pass;
+ enum ndr_err_code ndr_err;
+
+ /* unpacking structures */
+ DATA_BLOB blob;
+
+ /* fetching trusted domain password structure */
+ if (!(blob.data = (uint8_t *)secrets_fetch(trustdom_keystr(domain),
+ &blob.length))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ /* unpack trusted domain password */
+ ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &pass,
+ (ndr_pull_flags_fn_t)ndr_pull_TRUSTED_DOM_PASS);
+
+ /* This blob is NOT talloc based! */
+ BURN_FREE(blob.data, blob.length);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ if (pass.pass != NULL) {
+ talloc_keep_secret(discard_const_p(char, pass.pass));
+ }
+
+ /* the trust's password */
+ if (pwd) {
+ *pwd = SMB_STRDUP(pass.pass);
+ if (!*pwd) {
+ return False;
+ }
+ }
+
+ /* last change time */
+ if (pass_last_set_time) *pass_last_set_time = pass.mod_time;
+
+ /* domain sid */
+ if (sid != NULL) sid_copy(sid, &pass.domain_sid);
+
+ return True;
+}
+
+/**
+ * Routine to store the password for trusted domain
+ *
+ * @param domain remote domain name
+ * @param pwd plain text password of trust relationship
+ * @param sid remote domain sid
+ *
+ * @return true if succeeded
+ **/
+
+bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
+ const struct dom_sid *sid)
+{
+ bool ret;
+
+ /* packing structures */
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct TRUSTED_DOM_PASS pass;
+ ZERO_STRUCT(pass);
+
+ pass.uni_name = domain;
+ pass.uni_name_len = strlen(domain)+1;
+
+ /* last change time */
+ pass.mod_time = time(NULL);
+
+ /* password of the trust */
+ pass.pass_len = strlen(pwd);
+ pass.pass = pwd;
+
+ /* domain sid */
+ sid_copy(&pass.domain_sid, sid);
+
+ ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass,
+ (ndr_push_flags_fn_t)ndr_push_TRUSTED_DOM_PASS);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ ret = secrets_store(trustdom_keystr(domain), blob.data, blob.length);
+
+ /* This blob is talloc based. */
+ data_blob_clear_free(&blob);
+
+ return ret;
+}
+
+/************************************************************************
+ Routine to delete the password for trusted domain
+************************************************************************/
+
+bool trusted_domain_password_delete(const char *domain)
+{
+ return secrets_delete_entry(trustdom_keystr(domain));
+}
+
+bool secrets_store_ldap_pw(const char* dn, char* pw)
+{
+ char *key = NULL;
+ bool ret;
+
+ if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
+ DEBUG(0, ("secrets_store_ldap_pw: asprintf failed!\n"));
+ return False;
+ }
+
+ ret = secrets_store(key, pw, strlen(pw)+1);
+
+ SAFE_FREE(key);
+ return ret;
+}
+
+/*******************************************************************
+ Find the ldap password.
+******************************************************************/
+
+bool fetch_ldap_pw(char **dn, char** pw)
+{
+ char *key = NULL;
+ size_t size = 0;
+
+ *dn = smb_xstrdup(lp_ldap_admin_dn());
+
+ if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
+ SAFE_FREE(*dn);
+ DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
+ return false;
+ }
+
+ *pw=(char *)secrets_fetch(key, &size);
+ SAFE_FREE(key);
+
+ if (*pw == NULL || size == 0 || (*pw)[size-1] != '\0') {
+ DBG_ERR("No valid password for %s\n", *dn);
+ BURN_FREE_STR(*pw);
+ SAFE_FREE(*dn);
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ Store a complete AFS keyfile into secrets.tdb.
+*******************************************************************************/
+
+bool secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile)
+{
+ fstring key;
+
+ if ((cell == NULL) || (keyfile == NULL))
+ return False;
+
+ if (ntohl(keyfile->nkeys) > SECRETS_AFS_MAXKEYS)
+ return False;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+ return secrets_store(key, keyfile, sizeof(struct afs_keyfile));
+}
+
+/*******************************************************************************
+ Fetch the current (highest) AFS key from secrets.tdb
+*******************************************************************************/
+bool secrets_fetch_afs_key(const char *cell, struct afs_key *result)
+{
+ fstring key;
+ struct afs_keyfile *keyfile;
+ size_t size = 0;
+ uint32_t i;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+
+ keyfile = (struct afs_keyfile *)secrets_fetch(key, &size);
+
+ if (keyfile == NULL)
+ return False;
+
+ if (size != sizeof(struct afs_keyfile)) {
+ BURN_FREE(keyfile, sizeof(*keyfile));
+ return False;
+ }
+
+ i = ntohl(keyfile->nkeys);
+
+ if (i > SECRETS_AFS_MAXKEYS) {
+ BURN_FREE(keyfile, sizeof(*keyfile));
+ return False;
+ }
+
+ *result = keyfile->entry[i-1];
+
+ result->kvno = ntohl(result->kvno);
+
+ BURN_FREE(keyfile, sizeof(*keyfile));
+
+ return True;
+}
+
+/******************************************************************************
+ When kerberos is not available, choose between anonymous or
+ authenticated connections.
+
+ We need to use an authenticated connection if DCs have the
+ RestrictAnonymous registry entry set > 0, or the "Additional
+ restrictions for anonymous connections" set in the win2k Local
+ Security Policy.
+
+ Caller to free() result in domain, username, password
+*******************************************************************************/
+void secrets_fetch_ipc_userpass(char **username, char **domain, char **password)
+{
+ *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
+ *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
+ *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+
+ if (*username && **username) {
+
+ if (!*domain || !**domain) {
+ SAFE_FREE(*domain);
+ *domain = smb_xstrdup(lp_workgroup());
+ }
+
+ if (!*password || !**password) {
+ BURN_FREE_STR(*password);
+ *password = smb_xstrdup("");
+ }
+
+ DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
+ *domain, *username));
+
+ } else {
+ DEBUG(3, ("IPC$ connections done anonymously\n"));
+ SAFE_FREE(*username);
+ SAFE_FREE(*domain);
+ BURN_FREE_STR(*password);
+ *username = smb_xstrdup("");
+ *domain = smb_xstrdup("");
+ *password = smb_xstrdup("");
+ }
+}
+
+bool secrets_store_generic(const char *owner, const char *key, const char *secret)
+{
+ char *tdbkey = NULL;
+ bool ret;
+
+ if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
+ DEBUG(0, ("asprintf failed!\n"));
+ return False;
+ }
+
+ ret = secrets_store(tdbkey, secret, strlen(secret)+1);
+
+ SAFE_FREE(tdbkey);
+ return ret;
+}
+
+/*******************************************************************
+ Find the ldap password.
+******************************************************************/
+
+char *secrets_fetch_generic(const char *owner, const char *key)
+{
+ char *secret = NULL;
+ char *tdbkey = NULL;
+
+ if (( ! owner) || ( ! key)) {
+ DEBUG(1, ("Invalid Parameters\n"));
+ return NULL;
+ }
+
+ if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NULL;
+ }
+
+ secret = (char *)secrets_fetch(tdbkey, NULL);
+ SAFE_FREE(tdbkey);
+
+ return secret;
+}
+
diff --git a/source3/passdb/secrets_lsa.c b/source3/passdb/secrets_lsa.c
new file mode 100644
index 0000000..7ff6d51
--- /dev/null
+++ b/source3/passdb/secrets_lsa.c
@@ -0,0 +1,245 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_secrets.h"
+#include "secrets.h"
+
+/******************************************************************************
+*******************************************************************************/
+
+static char *lsa_secret_key(TALLOC_CTX *mem_ctx,
+ const char *secret_name)
+{
+ return talloc_asprintf_strupper_m(mem_ctx, "SECRETS/LSA/%s",
+ secret_name);
+}
+
+/******************************************************************************
+*******************************************************************************/
+
+static NTSTATUS lsa_secret_get_common(TALLOC_CTX *mem_ctx,
+ const char *secret_name,
+ struct lsa_secret *secret)
+{
+ char *key;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ZERO_STRUCTP(secret);
+
+ key = lsa_secret_key(mem_ctx, secret_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob.data = (uint8_t *)secrets_fetch(key, &blob.length);
+ talloc_free(key);
+
+ if (!blob.data) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, secret,
+ (ndr_pull_flags_fn_t)ndr_pull_lsa_secret);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ SAFE_FREE(blob.data);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ /* This is NOT a talloc blob */
+ BURN_FREE(blob.data, blob.length);
+
+ if (secret->secret_current != NULL &&
+ secret->secret_current->data != NULL) {
+ talloc_keep_secret(secret->secret_current->data);
+ }
+ if (secret->secret_old != NULL && secret->secret_old->data != NULL) {
+ talloc_keep_secret(secret->secret_old->data);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+*******************************************************************************/
+
+NTSTATUS lsa_secret_get(TALLOC_CTX *mem_ctx,
+ const char *secret_name,
+ DATA_BLOB *secret_current,
+ NTTIME *secret_current_lastchange,
+ DATA_BLOB *secret_old,
+ NTTIME *secret_old_lastchange,
+ struct security_descriptor **sd)
+{
+ NTSTATUS status;
+ struct lsa_secret secret;
+
+ status = lsa_secret_get_common(mem_ctx, secret_name, &secret);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (secret_current) {
+ *secret_current = data_blob_null;
+ if (secret.secret_current) {
+ *secret_current = *secret.secret_current;
+ }
+ }
+ if (secret_current_lastchange) {
+ *secret_current_lastchange = secret.secret_current_lastchange;
+ }
+ if (secret_old) {
+ *secret_old = data_blob_null;
+ if (secret.secret_old) {
+ *secret_old = *secret.secret_old;
+ }
+ }
+ if (secret_old_lastchange) {
+ *secret_old_lastchange = secret.secret_old_lastchange;
+ }
+ if (sd) {
+ *sd = secret.sd;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+*******************************************************************************/
+
+static NTSTATUS lsa_secret_set_common(TALLOC_CTX *mem_ctx,
+ const char *key,
+ struct lsa_secret *secret,
+ DATA_BLOB *secret_current,
+ DATA_BLOB *secret_old,
+ struct security_descriptor *sd)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct timeval now = timeval_current();
+
+ if (!secret) {
+ secret = talloc_zero(mem_ctx, struct lsa_secret);
+ }
+
+ if (!secret) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (secret_old) {
+ secret->secret_old = secret_old;
+ secret->secret_old_lastchange = timeval_to_nttime(&now);
+ } else {
+ if (secret->secret_current) {
+ secret->secret_old = secret->secret_current;
+ secret->secret_old_lastchange = secret->secret_current_lastchange;
+ } else {
+ secret->secret_old = NULL;
+ secret->secret_old_lastchange = timeval_to_nttime(&now);
+ }
+ }
+ if (secret_current) {
+ secret->secret_current = secret_current;
+ secret->secret_current_lastchange = timeval_to_nttime(&now);
+ } else {
+ secret->secret_current = NULL;
+ secret->secret_current_lastchange = timeval_to_nttime(&now);
+ }
+ if (sd) {
+ secret->sd = sd;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, secret,
+ (ndr_push_flags_fn_t)ndr_push_lsa_secret);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (!secrets_store(key, blob.data, blob.length)) {
+ data_blob_clear(&blob);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ data_blob_clear(&blob);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+*******************************************************************************/
+
+NTSTATUS lsa_secret_set(const char *secret_name,
+ DATA_BLOB *secret_current,
+ DATA_BLOB *secret_old,
+ struct security_descriptor *sd)
+{
+ char *key;
+ struct lsa_secret secret;
+ NTSTATUS status;
+
+ key = lsa_secret_key(talloc_tos(), secret_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = lsa_secret_get_common(talloc_tos(), secret_name, &secret);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ talloc_free(key);
+ return status;
+ }
+
+ status = lsa_secret_set_common(talloc_tos(), key,
+ &secret,
+ secret_current,
+ secret_old,
+ sd);
+ talloc_free(key);
+
+ return status;
+}
+
+/******************************************************************************
+*******************************************************************************/
+
+NTSTATUS lsa_secret_delete(const char *secret_name)
+{
+ char *key;
+ struct lsa_secret secret;
+ NTSTATUS status;
+
+ key = lsa_secret_key(talloc_tos(), secret_name);
+ if (!key) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = lsa_secret_get_common(talloc_tos(), secret_name, &secret);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(key);
+ return status;
+ }
+
+ if (!secrets_delete_entry(key)) {
+ talloc_free(key);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ talloc_free(key);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/passdb/wscript_build b/source3/passdb/wscript_build
new file mode 100644
index 0000000..7facc1f
--- /dev/null
+++ b/source3/passdb/wscript_build
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_MODULE('pdb_tdbsam',
+ subsystem='pdb',
+ source='pdb_tdb.c',
+ deps='samba-util dbwrap tdb-wrap3',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_tdbsam'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_tdbsam'))
+
+bld.SAMBA3_MODULE('pdb_ldapsam',
+ subsystem='pdb',
+ deps='smbldap smbldaphelper LIBCLI_AUTH',
+ source='pdb_ldap.c pdb_nds.c',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_ldapsam'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_ldapsam') and bld.CONFIG_SET('HAVE_LDAP'))
+
+bld.SAMBA3_MODULE('pdb_smbpasswd',
+ subsystem='pdb',
+ source='pdb_smbpasswd.c',
+ deps='samba-util',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_smbpasswd'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_smbpasswd'))
+
+bld.SAMBA3_MODULE('pdb_samba_dsdb',
+ subsystem='pdb',
+ source='pdb_samba_dsdb.c',
+ init_function='',
+ deps='IDMAP samdb',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_samba_dsdb') and bld.AD_DC_BUILD_IS_ENABLED(),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_samba_dsdb') and bld.AD_DC_BUILD_IS_ENABLED())
+
+pyrpc_util = bld.pyembed_libname('pyrpc_util')
+pytalloc_util = bld.pyembed_libname('pytalloc-util')
+bld.SAMBA3_PYTHON('pypassdb',
+ source='py_passdb.c',
+ deps='pdb',
+ public_deps=' '.join(['samba-util', 'tdb', 'talloc', pyrpc_util, pytalloc_util]),
+ realname='samba/samba3/passdb.so'
+ )