diff options
-rw-r--r-- | source3/Makefile.in | 4 | ||||
-rw-r--r-- | source3/configure.in | 3 | ||||
-rw-r--r-- | source3/passdb/pdb_ads.c | 1284 |
3 files changed, 1290 insertions, 1 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index e02b021fe9..49c3e2acdf 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -2570,6 +2570,10 @@ bin/ldapsam.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_ldap.o passdb/pdb_nds.o @echo "Building plugin $@" @$(SHLD_MODULE) passdb/pdb_ldap.o passdb/pdb_nds.o $(LDAP_LIBS) +bin/ads.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_ads.o + @echo "Building plugin $@" + @$(SHLD_MODULE) passdb/pdb_ads.o + bin/tdbsam.@SHLIBEXT@: $(BINARY_PREREQS) passdb/pdb_tdb.o @echo "Building plugin $@" @$(SHLD_MODULE) passdb/pdb_tdb.o diff --git a/source3/configure.in b/source3/configure.in index f980911666..bbd40dbefe 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -438,7 +438,7 @@ dnl These are preferably build shared, and static if dlopen() is not available default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer vfs_preopen" if test "x$developer" = xyes; then - default_static_modules="$default_static_modules rpc_rpcecho" + default_static_modules="$default_static_modules rpc_rpcecho pdb_ads" default_shared_modules="$default_shared_modules charset_weird perfcount_test" fi @@ -6212,6 +6212,7 @@ fi SMB_MODULE(pdb_ldap, passdb/pdb_ldap.o passdb/pdb_nds.o, "bin/ldapsam.$SHLIBEXT", PDB, [ PASSDB_LIBS="$PASSDB_LIBS $LDAP_LIBS" ] ) +SMB_MODULE(pdb_ads, passdb/pdb_ads.o \$(TLDAP_OBJ), "bin/ads.$SHLIBEXT", PDB) SMB_MODULE(pdb_smbpasswd, passdb/pdb_smbpasswd.o, "bin/smbpasswd.$SHLIBEXT", PDB) SMB_MODULE(pdb_tdbsam, passdb/pdb_tdb.o, "bin/tdbsam.$SHLIBEXT", PDB) SMB_MODULE(pdb_wbc_sam, passdb/pdb_wbc_sam.o, "bin/wbc_sam.$SHLIBEXT", PDB) diff --git a/source3/passdb/pdb_ads.c b/source3/passdb/pdb_ads.c new file mode 100644 index 0000000000..c55140ed93 --- /dev/null +++ b/source3/passdb/pdb_ads.c @@ -0,0 +1,1284 @@ +/* + Unix SMB/CIFS implementation. + pdb_ldap with ads schema + Copyright (C) Volker Lendecke 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" + +static NTSTATUS pdb_ads_getsampwsid(struct pdb_methods *m, + struct samu *sam_acct, + const DOM_SID *sid); + +struct pdb_ads_state { + struct tldap_context *ld; + struct dom_sid domainsid; + char *domaindn; + char *configdn; + char *netbiosname; +}; + +static bool pdb_ads_pull_time(struct tldap_message *msg, const char *attr, + time_t *ptime) +{ + uint64_t tmp; + + if (!tldap_pull_uint64(msg, attr, &tmp)) { + return false; + } + *ptime = uint64s_nt_time_to_unix_abs(&tmp); + return true; +} + +static gid_t pdb_ads_sid2gid(const struct dom_sid *sid) +{ + uint32_t rid; + sid_peek_rid(sid, &rid); + return rid; +} + +struct pdb_ads_samu_private { + char *dn; + struct tldap_message *ldapmsg; +}; + +static struct samu *pdb_ads_init_guest(TALLOC_CTX *mem_ctx, + struct pdb_methods *m) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct dom_sid guest_sid; + struct samu *guest; + NTSTATUS status; + + sid_compose(&guest_sid, &state->domainsid, DOMAIN_USER_RID_GUEST); + + guest = samu_new(mem_ctx); + if (guest == NULL) { + return NULL; + } + + status = pdb_ads_getsampwsid(m, guest, &guest_sid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Could not init guest account: %s\n", + nt_errstr(status))); + TALLOC_FREE(guest); + return NULL; + } + return guest; +} + +static struct pdb_ads_samu_private *pdb_ads_get_samu_private( + struct pdb_methods *m, struct samu *sam) +{ + struct pdb_ads_samu_private *result; + uint32_t rid; + + result = (struct pdb_ads_samu_private *) + pdb_get_backend_private_data(sam, m); + + if (result != NULL) { + return talloc_get_type_abort( + result, struct pdb_ads_samu_private); + } + + /* + * This is now a weirdness of the passdb API. For the guest user we + * are not asked first. + */ + sid_peek_rid(pdb_get_user_sid(sam), &rid); + + if (rid == DOMAIN_USER_RID_GUEST) { + struct samu *guest = pdb_ads_init_guest(talloc_tos(), m); + + if (guest == NULL) { + return NULL; + } + result = talloc_get_type_abort( + pdb_get_backend_private_data(guest, m), + struct pdb_ads_samu_private); + pdb_set_backend_private_data( + sam, talloc_move(sam, &result), NULL, m, PDB_SET); + TALLOC_FREE(guest); + return talloc_get_type_abort( + pdb_get_backend_private_data(sam, m), + struct pdb_ads_samu_private); + } + + return NULL; +} + +static NTSTATUS pdb_ads_init_sam_from_ads(struct pdb_methods *m, + struct samu *sam, + struct tldap_message *entry) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + TALLOC_CTX *frame = talloc_stackframe(); + struct pdb_ads_samu_private *priv; + NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION; + char *str; + time_t tmp_time; + struct dom_sid sid; + uint64_t n; + DATA_BLOB blob; + + priv = talloc(sam, struct pdb_ads_samu_private); + if (priv == NULL) { + return NT_STATUS_NO_MEMORY; + } + if (!tldap_entry_dn(entry, &priv->dn)) { + TALLOC_FREE(priv); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + str = tldap_talloc_single_attribute(entry, "samAccountName", sam); + if (str == NULL) { + DEBUG(10, ("no samAccountName\n")); + goto fail; + } + pdb_set_username(sam, str, PDB_SET); + TALLOC_FREE(str); + + if (pdb_ads_pull_time(entry, "lastLogon", &tmp_time)) { + pdb_set_logon_time(sam, tmp_time, PDB_SET); + } + if (pdb_ads_pull_time(entry, "lastLogoff", &tmp_time)) { + pdb_set_logoff_time(sam, tmp_time, PDB_SET); + } + if (pdb_ads_pull_time(entry, "pwdLastSet", &tmp_time)) { + pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET); + } + if (pdb_ads_pull_time(entry, "accountExpires", &tmp_time)) { + pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "samAccoutName", + talloc_tos()); + if (str != NULL) { + pdb_set_username(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "displayName", + talloc_tos()); + if (str != NULL) { + pdb_set_fullname(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "homeDirectory", + talloc_tos()); + if (str != NULL) { + pdb_set_homedir(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "homeDrive", talloc_tos()); + if (str != NULL) { + pdb_set_dir_drive(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "scriptPath", talloc_tos()); + if (str != NULL) { + pdb_set_logon_script(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "profilePath", + talloc_tos()); + if (str != NULL) { + pdb_set_profile_path(sam, str, PDB_SET); + } + + str = tldap_talloc_single_attribute(entry, "profilePath", + talloc_tos()); + if (str != NULL) { + pdb_set_profile_path(sam, str, PDB_SET); + } + + if (!tldap_pull_binsid(entry, "objectSid", &sid)) { + DEBUG(10, ("Could not pull SID\n")); + goto fail; + } + pdb_set_user_sid(sam, &sid, PDB_SET); + + if (!tldap_pull_uint64(entry, "userAccountControl", &n)) { + DEBUG(10, ("Could not pull userAccountControl\n")); + goto fail; + } + pdb_set_acct_ctrl(sam, ads_uf2acb(n), PDB_SET); + + if (tldap_get_single_valueblob(entry, "unicodePwd", &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); + } + + if (tldap_get_single_valueblob(entry, "dBCSPwd", &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); + } + + if (tldap_pull_uint64(entry, "primaryGroupID", &n)) { + sid_compose(&sid, &state->domainsid, n); + pdb_set_group_sid(sam, &sid, PDB_SET); + + } + + priv->ldapmsg = talloc_move(priv, &entry); + pdb_set_backend_private_data(sam, priv, NULL, m, PDB_SET); + + status = NT_STATUS_OK; +fail: + TALLOC_FREE(frame); + return status; +} + +static bool pdb_ads_init_ads_from_sam(struct pdb_ads_state *state, + struct tldap_message *existing, + TALLOC_CTX *mem_ctx, + int *pnum_mods, struct tldap_mod **pmods, + struct samu *sam) +{ + bool ret = true; + + /* TODO: All fields :-) */ + + ret &= tldap_make_mod_fmt( + existing, mem_ctx, pnum_mods, pmods, "displayName", + pdb_get_fullname(sam)); + + ret &= tldap_make_mod_blob( + existing, mem_ctx, pnum_mods, pmods, "unicodePwd", + data_blob_const(pdb_get_nt_passwd(sam), NT_HASH_LEN)); + + ret &= tldap_make_mod_blob( + existing, mem_ctx, pnum_mods, pmods, "dBCSPwd", + data_blob_const(pdb_get_lanman_passwd(sam), NT_HASH_LEN)); + + return ret; +} + +static NTSTATUS pdb_ads_getsampwfilter(struct pdb_methods *m, + struct pdb_ads_state *state, + struct samu *sam_acct, + const char *filter) +{ + const char * attrs[] = { + "lastLogon", "lastLogoff", "pwdLastSet", "accountExpires", + "sAMAccountName", "displayName", "homeDirectory", + "homeDrive", "scriptPath", "profilePath", "description", + "userWorkstations", "comment", "userParameters", "objectSid", + "primaryGroupID", "userAccountControl", "logonHours", + "badPwdCount", "logonCount", "countryCode", "codePage", + "unicodePwd", "dBCSPwd" }; + struct tldap_message **users; + int rc, count; + + rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB, + attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), + &users, filter); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_search failed %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + return NT_STATUS_LDAP(rc); + } + + count = talloc_array_length(users); + if (count != 1) { + DEBUG(10, ("Expected 1 user, got %d\n", count)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + return pdb_ads_init_sam_from_ads(m, sam_acct, users[0]); +} + +static NTSTATUS pdb_ads_getsampwnam(struct pdb_methods *m, + struct samu *sam_acct, + const char *username) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + char *filter; + + filter = talloc_asprintf( + talloc_tos(), "(&(samaccountname=%s)(objectclass=user))", + username); + NT_STATUS_HAVE_NO_MEMORY(filter); + + return pdb_ads_getsampwfilter(m, state, sam_acct, filter); +} + +static NTSTATUS pdb_ads_getsampwsid(struct pdb_methods *m, + struct samu *sam_acct, + const DOM_SID *sid) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + char *sidstr, *filter; + + sidstr = sid_binstring(talloc_tos(), sid); + NT_STATUS_HAVE_NO_MEMORY(sidstr); + + filter = talloc_asprintf( + talloc_tos(), "(&(objectsid=%s)(objectclass=user))", sidstr); + TALLOC_FREE(sidstr); + NT_STATUS_HAVE_NO_MEMORY(filter); + + return pdb_ads_getsampwfilter(m, state, sam_acct, filter); +} + +static NTSTATUS pdb_ads_create_user(struct pdb_methods *m, + TALLOC_CTX *tmp_ctx, + const char *name, uint32 acct_flags, + uint32 *rid) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + const char *attrs[1] = { "objectSid" }; + struct tldap_mod *mods = NULL; + int num_mods = 0; + struct tldap_message **user; + struct dom_sid sid; + char *dn; + int rc; + bool ok; + + dn = talloc_asprintf(talloc_tos(), "cn=%s,cn=users,%s", name, + state->domaindn); + if (dn == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* TODO: Create machines etc */ + + ok = true; + ok &= tldap_make_mod_fmt( + NULL, talloc_tos(), &num_mods, &mods, "objectClass", "user"); + ok &= tldap_make_mod_fmt( + NULL, talloc_tos(), &num_mods, &mods, "samAccountName", "%s", + name); + if (!ok) { + return NT_STATUS_NO_MEMORY; + } + + rc = tldap_add(state->ld, dn, num_mods, mods, NULL, NULL); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_add failed %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + TALLOC_FREE(dn); + return NT_STATUS_LDAP(rc); + } + + rc = tldap_search_fmt(state->ld, state->domaindn, TLDAP_SCOPE_SUB, + attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &user, + "(&(objectclass=user)(samaccountname=%s))", + name); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("Could not find just created user %s: %s\n", + name, tldap_errstr(debug_ctx(), state->ld, rc))); + TALLOC_FREE(dn); + return NT_STATUS_LDAP(rc); + } + + if (talloc_array_length(user) != 1) { + DEBUG(10, ("Got %d users, expected one\n", + (int)talloc_array_length(user))); + TALLOC_FREE(dn); + return NT_STATUS_LDAP(rc); + } + + if (!tldap_pull_binsid(user[0], "objectSid", &sid)) { + DEBUG(10, ("Could not fetch objectSid from user %s\n", + name)); + TALLOC_FREE(dn); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + sid_peek_rid(&sid, rid); + TALLOC_FREE(dn); + return NT_STATUS_OK; +} + +static NTSTATUS pdb_ads_delete_user(struct pdb_methods *m, + TALLOC_CTX *tmp_ctx, + struct samu *sam) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct pdb_ads_samu_private *priv = pdb_ads_get_samu_private(m, sam); + int rc; + + rc = tldap_delete(state->ld, priv->dn, NULL, NULL); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_delete for %s failed: %s\n", priv->dn, + tldap_errstr(debug_ctx(), state->ld, rc))); + return NT_STATUS_LDAP(rc); + } + return NT_STATUS_OK; +} + +static NTSTATUS pdb_ads_add_sam_account(struct pdb_methods *m, + struct samu *sampass) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_update_sam_account(struct pdb_methods *m, + struct samu *sam) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct pdb_ads_samu_private *priv = pdb_ads_get_samu_private(m, sam); + struct tldap_mod *mods = NULL; + int rc, num_mods = 0; + + if (!pdb_ads_init_ads_from_sam(state, priv->ldapmsg, talloc_tos(), + &num_mods, &mods, sam)) { + return NT_STATUS_NO_MEMORY; + } + + rc = tldap_modify(state->ld, priv->dn, num_mods, mods, NULL, NULL); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_modify for %s failed: %s\n", priv->dn, + tldap_errstr(debug_ctx(), state->ld, rc))); + return NT_STATUS_LDAP(rc); + } + + TALLOC_FREE(mods); + + return NT_STATUS_OK; +} + +static NTSTATUS pdb_ads_delete_sam_account(struct pdb_methods *m, + struct samu *username) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_rename_sam_account(struct pdb_methods *m, + struct samu *oldname, + const char *newname) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_update_login_attempts(struct pdb_methods *m, + struct samu *sam_acct, + bool success) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_getgrsid(struct pdb_methods *m, GROUP_MAP *map, + DOM_SID sid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_getgrgid(struct pdb_methods *m, GROUP_MAP *map, + gid_t gid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_getgrnam(struct pdb_methods *m, GROUP_MAP *map, + const char *name) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_create_dom_group(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, const char *name, + uint32 *rid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_delete_dom_group(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, uint32 rid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_add_group_mapping_entry(struct pdb_methods *m, + GROUP_MAP *map) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_update_group_mapping_entry(struct pdb_methods *m, + GROUP_MAP *map) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_delete_group_mapping_entry(struct pdb_methods *m, + DOM_SID sid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_enum_group_mapping(struct pdb_methods *m, + const 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_ads_enum_group_members(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + const DOM_SID *group, + uint32 **pp_member_rids, + size_t *p_num_members) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_enum_group_memberships(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + struct samu *user, + DOM_SID **pp_sids, + gid_t **pp_gids, + size_t *p_num_groups) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct pdb_ads_samu_private *priv = pdb_ads_get_samu_private( + m, user); + const char *attrs[1] = { "objectSid" }; + struct tldap_message **groups; + int i, rc, count; + size_t num_groups; + struct dom_sid *group_sids; + gid_t *gids; + + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_SUB, + attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &groups, + "(&(member=%s)(grouptype=%d)(objectclass=group))", + priv->dn, GTYPE_SECURITY_GLOBAL_GROUP); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_search failed %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + return NT_STATUS_LDAP(rc); + } + + count = talloc_array_length(groups); + + group_sids = talloc_array(mem_ctx, struct dom_sid, count); + if (group_sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + gids = talloc_array(mem_ctx, gid_t, count); + if (gids == NULL) { + TALLOC_FREE(group_sids); + return NT_STATUS_NO_MEMORY; + } + num_groups = 0; + + for (i=0; i<count; i++) { + if (!tldap_pull_binsid(groups[i], "objectSid", + &group_sids[num_groups])) { + continue; + } + gids[num_groups] = pdb_ads_sid2gid(&group_sids[num_groups]); + + num_groups += 1; + if (num_groups == count) { + break; + } + } + + *pp_sids = group_sids; + *pp_gids = gids; + *p_num_groups = num_groups; + return NT_STATUS_OK; +} + +static NTSTATUS pdb_ads_set_unix_primary_group(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + struct samu *user) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_add_groupmem(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + uint32 group_rid, uint32 member_rid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_del_groupmem(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + uint32 group_rid, uint32 member_rid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_create_alias(struct pdb_methods *m, + const char *name, uint32 *rid) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + const char *attrs[1] = { "objectSid" }; + int num_mods = 0; + struct tldap_mod *mods = NULL; + struct tldap_message **alias; + struct dom_sid sid; + char *dn; + int rc; + bool ok = true; + + dn = talloc_asprintf(talloc_tos(), "cn=%s,cn=users,%s", name, + state->domaindn); + if (dn == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + ok &= tldap_make_mod_fmt( + NULL, talloc_tos(), &num_mods, &mods, "samAccountName", "%s", + name); + ok &= tldap_make_mod_fmt( + NULL, talloc_tos(), &num_mods, &mods, "objectClass", "group"); + ok &= tldap_make_mod_fmt( + NULL, talloc_tos(), &num_mods, &mods, "groupType", + "%d", (int)GTYPE_SECURITY_DOMAIN_LOCAL_GROUP); + + if (!ok) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + rc = tldap_add(state->ld, dn, num_mods, mods, NULL, NULL); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_add failed %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + TALLOC_FREE(frame); + return NT_STATUS_LDAP(rc); + } + + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_SUB, + attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &alias, + "(&(objectclass=group)(samaccountname=%s))", name); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("Could not find just created alias %s: %s\n", + name, tldap_errstr(debug_ctx(), state->ld, rc))); + TALLOC_FREE(frame); + return NT_STATUS_LDAP(rc); + } + + if (talloc_array_length(alias) != 1) { + DEBUG(10, ("Got %d alias, expected one\n", + (int)talloc_array_length(alias))); + TALLOC_FREE(frame); + return NT_STATUS_LDAP(rc); + } + + if (!tldap_pull_binsid(alias[0], "objectSid", &sid)) { + DEBUG(10, ("Could not fetch objectSid from alias %s\n", + name)); + TALLOC_FREE(frame); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + sid_peek_rid(&sid, rid); + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + +static NTSTATUS pdb_ads_delete_alias(struct pdb_methods *m, + const DOM_SID *sid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_get_aliasinfo(struct pdb_methods *m, + const DOM_SID *sid, + struct acct_info *info) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_set_aliasinfo(struct pdb_methods *m, + const DOM_SID *sid, + struct acct_info *info) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_add_aliasmem(struct pdb_methods *m, + const DOM_SID *alias, + const DOM_SID *member) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_del_aliasmem(struct pdb_methods *m, + const DOM_SID *alias, + const DOM_SID *member) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_enum_aliasmem(struct pdb_methods *m, + const DOM_SID *alias, DOM_SID **members, + size_t *p_num_members) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_enum_alias_memberships(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + const DOM_SID *domain_sid, + const DOM_SID *members, + size_t num_members, + uint32 **pp_alias_rids, + size_t *p_num_alias_rids) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_lookup_rids(struct pdb_methods *m, + const DOM_SID *domain_sid, + int num_rids, + uint32 *rids, + const char **pp_names, + enum lsa_SidType *attrs) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_lookup_names(struct pdb_methods *m, + const DOM_SID *domain_sid, + int num_names, + const char **pp_names, + uint32 *rids, + enum lsa_SidType *attrs) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_ads_get_account_policy(struct pdb_methods *m, + int policy_index, uint32 *value) +{ + return account_policy_get(policy_index, value) + ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; +} + +static NTSTATUS pdb_ads_set_account_policy(struct pdb_methods *m, + int policy_index, uint32 value) +{ + return account_policy_set(policy_index, value) + ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; +} + +static NTSTATUS pdb_ads_get_seq_num(struct pdb_methods *m, + time_t *seq_num) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +struct pdb_ads_search_state { + uint32_t acct_flags; + struct samr_displayentry *entries; + uint32_t num_entries; + ssize_t array_size; + uint32_t current; +}; + +static bool pdb_ads_next_entry(struct pdb_search *search, + struct samr_displayentry *entry) +{ + struct pdb_ads_search_state *state = talloc_get_type_abort( + search->private_data, struct pdb_ads_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 void pdb_ads_search_end(struct pdb_search *search) +{ + struct pdb_ads_search_state *state = talloc_get_type_abort( + search->private_data, struct pdb_ads_search_state); + TALLOC_FREE(state); +} + +static bool pdb_ads_search_users(struct pdb_methods *m, + struct pdb_search *search, + uint32 acct_flags) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct pdb_ads_search_state *sstate; + const char * attrs[] = { "objectSid", "sAMAccountName", + "userAccountControl" }; + struct tldap_message **users; + int i, rc, num_users; + + sstate = talloc_zero(search, struct pdb_ads_search_state); + if (sstate == NULL) { + return false; + } + sstate->acct_flags = acct_flags; + + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_SUB, + attrs, ARRAY_SIZE(attrs), 0, talloc_tos(), &users, + "(objectclass=user)"); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("ldap_search_ext_s failed: %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + return false; + } + + num_users = talloc_array_length(users); + + sstate->entries = talloc_array(sstate, struct samr_displayentry, + num_users); + if (sstate->entries == NULL) { + 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; + if (!tldap_pull_binsid(users[i], "objectSid", &sid)) { + DEBUG(10, ("Could not pull sid\n")); + continue; + } + sid_peek_rid(&sid, &e->rid); + e->acct_flags = ACB_NORMAL; + e->account_name = "Name"; + e->fullname = "Full Name"; + e->description = "Beschreibung"; + + sstate->num_entries += 1; + if (sstate->num_entries >= num_users) { + break; + } + } + + search->private_data = sstate; + search->next_entry = pdb_ads_next_entry; + search->search_end = pdb_ads_search_end; + return true; +} + +static bool pdb_ads_search_groups(struct pdb_methods *m, + struct pdb_search *search) +{ + return false; +} + +static bool pdb_ads_search_aliases(struct pdb_methods *m, + struct pdb_search *search, + const DOM_SID *sid) +{ + return false; +} + +static bool pdb_ads_uid_to_rid(struct pdb_methods *m, uid_t uid, + uint32 *rid) +{ + return false; +} + +static bool pdb_ads_uid_to_sid(struct pdb_methods *m, uid_t uid, + DOM_SID *sid) +{ + return false; +} + +static bool pdb_ads_gid_to_sid(struct pdb_methods *m, gid_t gid, + DOM_SID *sid) +{ + return false; +} + +static bool pdb_ads_sid_to_id(struct pdb_methods *m, const DOM_SID *sid, + union unid_t *id, enum lsa_SidType *type) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + m->private_data, struct pdb_ads_state); + struct tldap_message **msg; + char *sidstr; + uint32_t rid; + int rc; + + /* + * This is a big, big hack: Just hard-code the rid as uid/gid. + */ + + sid_peek_rid(sid, &rid); + + sidstr = sid_binstring(talloc_tos(), sid); + if (sidstr == NULL) { + return false; + } + + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_SUB, + NULL, 0, 0, talloc_tos(), &msg, + "(&(objectsid=%s)(objectclass=user))", sidstr); + if ((rc == TLDAP_SUCCESS) && (talloc_array_length(msg) > 0)) { + id->uid = rid; + *type = SID_NAME_USER; + TALLOC_FREE(sidstr); + return true; + } + + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_SUB, + NULL, 0, 0, talloc_tos(), &msg, + "(&(objectsid=%s)(objectclass=group))", sidstr); + if ((rc == TLDAP_SUCCESS) && (talloc_array_length(msg) > 0)) { + id->gid = rid; + *type = SID_NAME_DOM_GRP; + TALLOC_FREE(sidstr); + return true; + } + + TALLOC_FREE(sidstr); + return false; +} + +static bool pdb_ads_rid_algorithm(struct pdb_methods *m) +{ + return false; +} + +static bool pdb_ads_new_rid(struct pdb_methods *m, uint32 *rid) +{ + return false; +} + +static bool pdb_ads_get_trusteddom_pw(struct pdb_methods *m, + const char *domain, char** pwd, + DOM_SID *sid, + time_t *pass_last_set_time) +{ + return false; +} + +static bool pdb_ads_set_trusteddom_pw(struct pdb_methods *m, + const char* domain, const char* pwd, + const DOM_SID *sid) +{ + return false; +} + +static bool pdb_ads_del_trusteddom_pw(struct pdb_methods *m, + const char *domain) +{ + return false; +} + +static NTSTATUS pdb_ads_enum_trusteddoms(struct pdb_methods *m, + TALLOC_CTX *mem_ctx, + uint32 *num_domains, + struct trustdom_info ***domains) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static void pdb_ads_init_methods(struct pdb_methods *m) +{ + m->name = "ads"; + m->getsampwnam = pdb_ads_getsampwnam; + m->getsampwsid = pdb_ads_getsampwsid; + m->create_user = pdb_ads_create_user; + m->delete_user = pdb_ads_delete_user; + m->add_sam_account = pdb_ads_add_sam_account; + m->update_sam_account = pdb_ads_update_sam_account; + m->delete_sam_account = pdb_ads_delete_sam_account; + m->rename_sam_account = pdb_ads_rename_sam_account; + m->update_login_attempts = pdb_ads_update_login_attempts; + m->getgrsid = pdb_ads_getgrsid; + m->getgrgid = pdb_ads_getgrgid; + m->getgrnam = pdb_ads_getgrnam; + m->create_dom_group = pdb_ads_create_dom_group; + m->delete_dom_group = pdb_ads_delete_dom_group; + m->add_group_mapping_entry = pdb_ads_add_group_mapping_entry; + m->update_group_mapping_entry = pdb_ads_update_group_mapping_entry; + m->delete_group_mapping_entry = pdb_ads_delete_group_mapping_entry; + m->enum_group_mapping = pdb_ads_enum_group_mapping; + m->enum_group_members = pdb_ads_enum_group_members; + m->enum_group_memberships = pdb_ads_enum_group_memberships; + m->set_unix_primary_group = pdb_ads_set_unix_primary_group; + m->add_groupmem = pdb_ads_add_groupmem; + m->del_groupmem = pdb_ads_del_groupmem; + m->create_alias = pdb_ads_create_alias; + m->delete_alias = pdb_ads_delete_alias; + m->get_aliasinfo = pdb_ads_get_aliasinfo; + m->set_aliasinfo = pdb_ads_set_aliasinfo; + m->add_aliasmem = pdb_ads_add_aliasmem; + m->del_aliasmem = pdb_ads_del_aliasmem; + m->enum_aliasmem = pdb_ads_enum_aliasmem; + m->enum_alias_memberships = pdb_ads_enum_alias_memberships; + m->lookup_rids = pdb_ads_lookup_rids; + m->lookup_names = pdb_ads_lookup_names; + m->get_account_policy = pdb_ads_get_account_policy; + m->set_account_policy = pdb_ads_set_account_policy; + m->get_seq_num = pdb_ads_get_seq_num; + m->search_users = pdb_ads_search_users; + m->search_groups = pdb_ads_search_groups; + m->search_aliases = pdb_ads_search_aliases; + m->uid_to_rid = pdb_ads_uid_to_rid; + m->uid_to_sid = pdb_ads_uid_to_sid; + m->gid_to_sid = pdb_ads_gid_to_sid; + m->sid_to_id = pdb_ads_sid_to_id; + m->rid_algorithm = pdb_ads_rid_algorithm; + m->new_rid = pdb_ads_new_rid; + m->get_trusteddom_pw = pdb_ads_get_trusteddom_pw; + m->set_trusteddom_pw = pdb_ads_set_trusteddom_pw; + m->del_trusteddom_pw = pdb_ads_del_trusteddom_pw; + m->enum_trusteddoms = pdb_ads_enum_trusteddoms; +} + +static void free_private_data(void **vp) +{ + struct pdb_ads_state *state = talloc_get_type_abort( + *vp, struct pdb_ads_state); + + TALLOC_FREE(state->ld); + return; +} + +static NTSTATUS pdb_ads_connect(struct pdb_ads_state *state, + const char *location) +{ + const char *rootdse_attrs[2] = { + "defaultNamingContext", "configurationNamingContext" }; + const char *domain_attrs[1] = { "objectSid" }; + const char *ncname_attrs[1] = { "netbiosname" }; + struct tldap_message **rootdse, **domain, **ncname; + TALLOC_CTX *frame = talloc_stackframe(); + struct sockaddr_un sunaddr; + NTSTATUS status; + int num_domains; + int fd, rc; + + ZERO_STRUCT(sunaddr); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, location, sizeof(sunaddr.sun_path) - 1); + + status = open_socket_out((struct sockaddr_storage *)(void *)&sunaddr, + 0, 0, &fd); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Could not connect to %s: %s\n", location, + nt_errstr(status))); + goto done; + } + + state->ld = tldap_context_create(state, fd); + if (state->ld == NULL) { + close(fd); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + rc = tldap_search_fmt( + state->ld, "", TLDAP_SCOPE_BASE, + rootdse_attrs, ARRAY_SIZE(rootdse_attrs), 0, + talloc_tos(), &rootdse, "(objectclass=*)"); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("Could not retrieve rootdse: %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + status = NT_STATUS_LDAP(rc); + goto done; + } + if (talloc_array_length(rootdse) != 1) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + state->domaindn = tldap_talloc_single_attribute( + rootdse[0], "defaultNamingContext", state); + if (state->domaindn == NULL) { + DEBUG(10, ("Could not get defaultNamingContext\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + DEBUG(10, ("defaultNamingContext = %s\n", state->domaindn)); + + state->configdn = tldap_talloc_single_attribute( + rootdse[0], "configurationNamingContext", state); + if (state->domaindn == NULL) { + DEBUG(10, ("Could not get configurationNamingContext\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + DEBUG(10, ("configurationNamingContext = %s\n", state->configdn)); + + /* + * Figure out our domain's SID + */ + rc = tldap_search_fmt( + state->ld, state->domaindn, TLDAP_SCOPE_BASE, + domain_attrs, ARRAY_SIZE(domain_attrs), 0, + talloc_tos(), &domain, "(objectclass=*)"); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("Could not retrieve domain: %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + status = NT_STATUS_LDAP(rc); + goto done; + } + + num_domains = talloc_array_length(domain); + if (num_domains != 1) { + DEBUG(10, ("Got %d domains, expected one\n", num_domains)); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + if (!tldap_pull_binsid(domain[0], "objectSid", &state->domainsid)) { + DEBUG(10, ("Could not retrieve domain SID\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + DEBUG(10, ("Domain SID: %s\n", sid_string_dbg(&state->domainsid))); + + /* + * Figure out our domain's short name + */ + rc = tldap_search_fmt( + state->ld, state->configdn, TLDAP_SCOPE_SUB, + ncname_attrs, ARRAY_SIZE(ncname_attrs), 0, + talloc_tos(), &ncname, "(ncname=%s)", state->domaindn); + if (rc != TLDAP_SUCCESS) { + DEBUG(10, ("Could not retrieve ncname: %s\n", + tldap_errstr(debug_ctx(), state->ld, rc))); + status = NT_STATUS_LDAP(rc); + goto done; + } + if (talloc_array_length(ncname) != 1) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + state->netbiosname = tldap_talloc_single_attribute( + ncname[0], "netbiosname", state); + if (state->netbiosname == NULL) { + DEBUG(10, ("Could not get netbiosname\n")); + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + DEBUG(10, ("netbiosname: %s\n", state->netbiosname)); + + if (!strequal(lp_workgroup(), state->netbiosname)) { + DEBUG(1, ("ADS is different domain (%s) than ours (%s)\n", + state->netbiosname, lp_workgroup())); + status = NT_STATUS_NO_SUCH_DOMAIN; + goto done; + } + + secrets_store_domain_sid(state->netbiosname, &state->domainsid); + + status = NT_STATUS_OK; +done: + TALLOC_FREE(frame); + return status; +} + +static NTSTATUS pdb_init_ads(struct pdb_methods **pdb_method, + const char *location) +{ + struct pdb_methods *m; + struct pdb_ads_state *state; + char *tmp = NULL; + NTSTATUS status; + + m = talloc(talloc_autofree_context(), struct pdb_methods); + if (m == NULL) { + return NT_STATUS_NO_MEMORY; + } + state = talloc(m, struct pdb_ads_state); + if (state == NULL) { + goto nomem; + } + m->private_data = state; + m->free_private_data = free_private_data; + pdb_ads_init_methods(m); + + if (location == NULL) { + tmp = talloc_asprintf(talloc_tos(), "/%s/ldap_priv/ldapi", + lp_private_dir()); + location = tmp; + } + if (location == NULL) { + goto nomem; + } + + status = pdb_ads_connect(state, location); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_ads_connect failed: %s\n", nt_errstr(status))); + goto fail; + } + + *pdb_method = m; + return NT_STATUS_OK; +nomem: + status = NT_STATUS_NO_MEMORY; +fail: + TALLOC_FREE(m); + return status; +} + +NTSTATUS pdb_ads_init(void); +NTSTATUS pdb_ads_init(void) +{ + return smb_register_passdb(PASSDB_INTERFACE_VERSION, "ads", + pdb_init_ads); +} |