diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/passdb | |
parent | Initial commit. (diff) | |
download | samba-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')
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, ®val); + 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, + ¤t_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, ¤t_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, ¤t_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' + ) |