X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Frpc_server%2Fsamr%2Fdcesrv_samr.c;h=2ab5155c1070924868907c03bee8523e8c088c56;hb=9f9529886499acc80ad7316d5eab590545643b87;hp=df23e11a67b553ae2f5d3217797a507d8981047a;hpb=91bfd5f201f302156fac7f1bc7a685e6f3c22cf3;p=samba.git diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index df23e11a67b..2ab5155c107 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -6,6 +6,7 @@ Copyright (C) Andrew Tridgell 2004 Copyright (C) Volker Lendecke 2004 Copyright (C) Andrew Bartlett 2004-2005 + 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 @@ -29,13 +30,15 @@ #include "system/time.h" #include "lib/ldb/include/ldb.h" #include "lib/ldb/include/ldb_errors.h" -#include "dsdb/common/flags.h" +#include "../libds/common/flags.h" #include "dsdb/samdb/samdb.h" +#include "dsdb/common/util.h" #include "libcli/ldap/ldap_ndr.h" #include "libcli/security/security.h" #include "rpc_server/samr/proto.h" #include "../lib/util/util_ldb.h" #include "param/param.h" +#include "lib/util/tsort.h" /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */ @@ -164,7 +167,7 @@ static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_C ZERO_STRUCTP(r->out.connect_handle); - c_state = talloc(dce_call->conn, struct samr_connect_state); + c_state = talloc(mem_ctx, struct samr_connect_state); if (!c_state) { return NT_STATUS_NO_MEMORY; } @@ -273,11 +276,8 @@ static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TAL struct dcesrv_handle *h; struct dom_sid *sid; const char * const dom_attrs[] = { "objectSid", NULL}; - const char * const ref_attrs[] = { "ncName", NULL}; struct ldb_message **dom_msgs; - struct ldb_message **ref_msgs; int ret; - struct ldb_dn *partitions_basedn; *r->out.sid = NULL; @@ -289,27 +289,17 @@ static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TAL return NT_STATUS_INVALID_PARAMETER; } - partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx); - if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) { ret = gendb_search(c_state->sam_ctx, mem_ctx, NULL, &dom_msgs, dom_attrs, "(objectClass=builtinDomain)"); - } else { - ret = gendb_search(c_state->sam_ctx, - mem_ctx, partitions_basedn, &ref_msgs, ref_attrs, - "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", - ldb_binary_encode_string(mem_ctx, r->in.domain_name->string)); - if (ret != 1) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - ret = gendb_search_dn(c_state->sam_ctx, mem_ctx, - samdb_result_dn(c_state->sam_ctx, mem_ctx, - ref_msgs[0], "ncName", NULL), + } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) { + ret = gendb_search_dn(c_state->sam_ctx, + mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs); + } else { + return NT_STATUS_NO_SUCH_DOMAIN; } - if (ret != 1) { return NT_STATUS_NO_SUCH_DOMAIN; } @@ -338,12 +328,7 @@ static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALL struct samr_connect_state *c_state; struct dcesrv_handle *h; struct samr_SamArray *array; - int i, start_i, ret; - const char * const dom_attrs[] = { "cn", NULL}; - const char * const ref_attrs[] = { "nETBIOSName", NULL}; - struct ldb_result *dom_res; - struct ldb_result *ref_res; - struct ldb_dn *partitions_basedn; + uint32_t i, start_i; *r->out.resume_handle = 0; *r->out.sam = NULL; @@ -353,20 +338,11 @@ static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALL c_state = h->data; - partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx); - - ret = ldb_search(c_state->sam_ctx, mem_ctx, &dom_res, ldb_get_default_basedn(c_state->sam_ctx), - LDB_SCOPE_SUBTREE, dom_attrs, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))"); - if (ret != LDB_SUCCESS) { - DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - *r->out.resume_handle = dom_res->count; + *r->out.resume_handle = 2; start_i = *r->in.resume_handle; - if (start_i >= dom_res->count) { + if (start_i >= 2) { /* search past end of list is not an error for this call */ return NT_STATUS_OK; } @@ -379,27 +355,17 @@ static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALL array->count = 0; array->entries = NULL; - array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i); + array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i); if (array->entries == NULL) { return NT_STATUS_NO_MEMORY; } - for (i=0;icount-start_i;i++) { + for (i=0;i<2-start_i;i++) { array->entries[i].idx = start_i + i; - /* try and find the domain */ - ret = ldb_search(c_state->sam_ctx, mem_ctx, &ref_res, partitions_basedn, - LDB_SCOPE_SUBTREE, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))", - ldb_dn_get_linearized(dom_res->msgs[i]->dn)); - - if (ret != LDB_SUCCESS) { - DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ref_res->count == 1) { - array->entries[i].name.string = samdb_result_string(ref_res->msgs[0], "nETBIOSName", NULL); + if (i == 0) { + array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx); } else { - array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL); + array->entries[i].name.string = "BUILTIN"; } } @@ -418,15 +384,11 @@ static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLO struct samr_OpenDomain *r) { struct dcesrv_handle *h_conn, *h_domain; - const char *domain_name; struct samr_connect_state *c_state; struct samr_domain_state *d_state; const char * const dom_attrs[] = { "cn", NULL}; - const char * const ref_attrs[] = { "nETBIOSName", NULL}; struct ldb_message **dom_msgs; - struct ldb_message **ref_msgs; int ret; - struct ldb_dn *partitions_basedn; ZERO_STRUCTP(r->out.domain_handle); @@ -438,63 +400,44 @@ static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLO return NT_STATUS_INVALID_PARAMETER; } - partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx); + d_state = talloc(mem_ctx, struct samr_domain_state); + if (!d_state) { + return NT_STATUS_NO_MEMORY; + } + + d_state->domain_sid = talloc_steal(d_state, r->in.sid); + + if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) { + d_state->builtin = true; + d_state->domain_name = "BUILTIN"; + } else { + d_state->builtin = false; + d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx); + } ret = gendb_search(c_state->sam_ctx, - mem_ctx, NULL, &dom_msgs, dom_attrs, - "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", + mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs, + "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid)); + if (ret == 0) { + talloc_free(d_state); return NT_STATUS_NO_SUCH_DOMAIN; } else if (ret > 1) { + talloc_free(d_state); return NT_STATUS_INTERNAL_DB_CORRUPTION; } else if (ret == -1) { + talloc_free(d_state); DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx))); return NT_STATUS_INTERNAL_DB_CORRUPTION; - } else { - ret = gendb_search(c_state->sam_ctx, - mem_ctx, partitions_basedn, &ref_msgs, ref_attrs, - "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))", - ldb_dn_get_linearized(dom_msgs[0]->dn)); - if (ret == 0) { - domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL); - if (domain_name == NULL) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - } else if (ret == 1) { - - domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL); - if (domain_name == NULL) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - } else { - return NT_STATUS_NO_SUCH_DOMAIN; - } - } - - d_state = talloc(c_state, struct samr_domain_state); - if (!d_state) { - return NT_STATUS_NO_MEMORY; } + d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn); d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx); d_state->connect_state = talloc_reference(d_state, c_state); d_state->sam_ctx = c_state->sam_ctx; - d_state->domain_sid = dom_sid_dup(d_state, r->in.sid); - d_state->domain_name = talloc_strdup(d_state, domain_name); - d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn); - if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) { - talloc_free(d_state); - return NT_STATUS_NO_MEMORY; - } d_state->access_mask = r->in.access_mask; - if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) { - d_state->builtin = true; - } else { - d_state->builtin = false; - } - d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx; h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN); @@ -577,14 +520,14 @@ static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state } /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */ - info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, + info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn, "(objectClass=user)"); - info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, - "(&(objectClass=group)(sAMAccountType=%u))", - ATYPE_GLOBAL_GROUP); - info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, - "(&(objectClass=group)(sAMAccountType=%u))", - ATYPE_LOCAL_GROUP); + info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn, + "(&(objectClass=group)(groupType=%u))", + GTYPE_SECURITY_GLOBAL_GROUP); + info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn, + "(&(objectClass=group)(groupType=%u))", + GTYPE_SECURITY_DOMAIN_LOCAL_GROUP); return NT_STATUS_OK; } @@ -797,9 +740,12 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, switch (r->in.level) { case 1: { - static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength", - "pwdProperties", "maxPwdAge", - "minPwdAge", NULL }; + static const char * const attrs2[] = { "minPwdLength", + "pwdHistoryLength", + "pwdProperties", + "maxPwdAge", + "minPwdAge", + NULL }; attrs = attrs2; break; } @@ -853,11 +799,14 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, break; } case 9: + { attrs = NULL; - break; + break; + } case 11: { - static const char * const attrs2[] = { "oEMInformation", "forceLogoff", + static const char * const attrs2[] = { "oEMInformation", + "forceLogoff", "modifiedCount", "lockoutDuration", "lockOutObservationWindow", @@ -883,6 +832,10 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, attrs = attrs2; break; } + default: + { + return NT_STATUS_INVALID_INFO_CLASS; + } } /* some levels don't need a search */ @@ -936,9 +889,9 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, case 13: return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, &info->info13); + default: + return NT_STATUS_INVALID_INFO_CLASS; } - - return NT_STATUS_INVALID_INFO_CLASS; } @@ -991,7 +944,28 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA return NT_STATUS_OK; case 12: - + /* + * It is not possible to set lockout_duration < lockout_window. + * (The test is the other way around since the negative numbers + * are stored...) + * + * TODO: + * This check should be moved to the backend, i.e. to some + * ldb module under dsdb/samdb/ldb_modules/ . + * + * This constraint is documented here for the samr rpc service: + * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates + * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx + * + * And here for the ldap backend: + * MS-ADTS 3.1.1.5.3.2 Constraints + * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx + */ + if (r->in.info->info12.lockout_duration > + r->in.info->info12.lockout_window) + { + return NT_STATUS_INVALID_PARAMETER; + } SET_INT64 (msg, info12.lockout_duration, "lockoutDuration"); SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow"); SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold"); @@ -1004,7 +978,7 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA /* modify the samdb record */ ret = ldb_modify(sam_ctx, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to modify record %s: %s\n", ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(sam_ctx))); @@ -1022,15 +996,14 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_CreateDomainGroup *r) { + NTSTATUS status; struct samr_domain_state *d_state; struct samr_account_state *a_state; struct dcesrv_handle *h; - const char *name; - struct ldb_message *msg; - struct dom_sid *sid; const char *groupname; + struct dom_sid *group_sid; + struct ldb_dn *group_dn; struct dcesrv_handle *g_handle; - int ret; ZERO_STRUCTP(r->out.group_handle); *r->out.rid = 0; @@ -1050,71 +1023,21 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call return NT_STATUS_INVALID_PARAMETER; } - /* check if the group already exists */ - name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, - "sAMAccountName", - "(&(sAMAccountName=%s)(objectclass=group))", - ldb_binary_encode_string(mem_ctx, groupname)); - if (name != NULL) { - return NT_STATUS_GROUP_EXISTS; - } - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* add core elements to the ldb_message for the user */ - msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn); - ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname); - if (!msg->dn) { - return NT_STATUS_NO_MEMORY; - } - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname); - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group"); - - /* create the group */ - ret = ldb_add(d_state->sam_ctx, msg); - switch (ret) { - case LDB_SUCCESS: - break; - case LDB_ERR_ENTRY_ALREADY_EXISTS: - DEBUG(0,("Failed to create group record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_GROUP_EXISTS; - case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: - DEBUG(0,("Failed to create group record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_ACCESS_DENIED; - default: - DEBUG(0,("Failed to create group record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn); + if (!NT_STATUS_IS_OK(status)) { + return status; } - a_state = talloc(d_state, struct samr_account_state); + a_state = talloc(mem_ctx, struct samr_account_state); if (!a_state) { return NT_STATUS_NO_MEMORY; } a_state->sam_ctx = d_state->sam_ctx; a_state->access_mask = r->in.access_mask; a_state->domain_state = talloc_reference(a_state, d_state); - a_state->account_dn = talloc_steal(a_state, msg->dn); - - /* retrieve the sid for the group just created */ - sid = samdb_search_dom_sid(d_state->sam_ctx, a_state, - msg->dn, "objectSid", NULL); - if (sid == NULL) { - return NT_STATUS_UNSUCCESSFUL; - } + a_state->account_dn = talloc_steal(a_state, group_dn); - a_state->account_name = talloc_strdup(a_state, groupname); - if (!a_state->account_name) { - return NT_STATUS_NO_MEMORY; - } + a_state->account_name = talloc_steal(a_state, groupname); /* create the policy handle */ g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP); @@ -1125,7 +1048,7 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call g_handle->data = talloc_steal(g_handle, a_state); *r->out.group_handle = g_handle->wire_handle; - *r->out.rid = sid->sub_auths[sid->num_auths-1]; + *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1]; return NT_STATUS_OK; } @@ -1148,7 +1071,8 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_message **res; - int ldb_cnt, count, i, first; + int i, ldb_cnt; + uint32_t first, count; struct samr_SamEntry *entries; const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL }; struct samr_SamArray *sam; @@ -1166,7 +1090,8 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, d_state->domain_sid, - "(&(grouptype=%d)(objectclass=group))", + "(&(|(groupType=%d)(groupType=%d))(objectClass=group))", + GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP); if (ldb_cnt == -1) { return NT_STATUS_INTERNAL_DB_CORRUPTION; @@ -1196,8 +1121,7 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, } /* sort the results by rid */ - qsort(entries, count, sizeof(struct samr_SamEntry), - (comparison_fn_t)compare_SamEntry); + TYPESAFE_QSORT(entries, count, compare_SamEntry); /* find the first entry to return */ for (first=0; @@ -1239,28 +1163,14 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_CreateUser2 *r) { + NTSTATUS status; struct samr_domain_state *d_state; struct samr_account_state *a_state; struct dcesrv_handle *h; - const char *name; - struct ldb_message *msg; + struct ldb_dn *dn; struct dom_sid *sid; - const char *account_name; struct dcesrv_handle *u_handle; - int ret; - const char *container, *obj_class=NULL; - char *cn_name; - int cn_name_len; - - const char *attrs[] = { - "objectSid", - "userAccountControl", - NULL - }; - - uint32_t user_account_control; - - struct ldb_message **msgs; + const char *account_name; ZERO_STRUCTP(r->out.user_handle); *r->out.access_granted = 0; @@ -1273,6 +1183,9 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL if (d_state->builtin) { DEBUG(5, ("Cannot create a user in the BUILTIN domain")); return NT_STATUS_ACCESS_DENIED; + } else if (r->in.acct_flags == ACB_DOMTRUST) { + /* Domain trust accounts must be created by the LSA calls */ + return NT_STATUS_ACCESS_DENIED; } account_name = r->in.account_name->string; @@ -1280,108 +1193,11 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL return NT_STATUS_INVALID_PARAMETER; } - ret = ldb_transaction_start(d_state->sam_ctx); - if (ret != 0) { - DEBUG(0,("Failed to start a transaction for user creation: %s\n", - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - /* check if the user already exists */ - name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, - "sAMAccountName", - "(&(sAMAccountName=%s)(objectclass=user))", - ldb_binary_encode_string(mem_ctx, account_name)); - if (name != NULL) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_USER_EXISTS; - } - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_NO_MEMORY; - } - - cn_name = talloc_strdup(mem_ctx, account_name); - if (!cn_name) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_NO_MEMORY; - } - - cn_name_len = strlen(cn_name); - - /* This must be one of these values *only* */ - if (r->in.acct_flags == ACB_NORMAL) { - container = "CN=Users"; - obj_class = "user"; - - } else if (r->in.acct_flags == ACB_WSTRUST) { - if (cn_name[cn_name_len - 1] != '$') { - return NT_STATUS_FOOBAR; - } - cn_name[cn_name_len - 1] = '\0'; - container = "CN=Computers"; - obj_class = "computer"; - samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS); - - } else if (r->in.acct_flags == ACB_SVRTRUST) { - if (cn_name[cn_name_len - 1] != '$') { - return NT_STATUS_FOOBAR; - } - cn_name[cn_name_len - 1] = '\0'; - container = "OU=Domain Controllers"; - obj_class = "computer"; - samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS); - - } else if (r->in.acct_flags == ACB_DOMTRUST) { - container = "CN=Users"; - obj_class = "user"; - - } else { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_INVALID_PARAMETER; - } - - /* add core elements to the ldb_message for the user */ - msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn); - if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_FOOBAR; - } - - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name); - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class); - - /* Start a transaction, so we can query and do a subsequent atomic modify */ - - /* create the user */ - ret = ldb_add(d_state->sam_ctx, msg); - switch (ret) { - case LDB_SUCCESS: - break; - case LDB_ERR_ENTRY_ALREADY_EXISTS: - ldb_transaction_cancel(d_state->sam_ctx); - DEBUG(0,("Failed to create user record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_USER_EXISTS; - case LDB_ERR_UNWILLING_TO_PERFORM: - case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: - ldb_transaction_cancel(d_state->sam_ctx); - DEBUG(0,("Failed to create user record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_ACCESS_DENIED; - default: - ldb_transaction_cancel(d_state->sam_ctx); - DEBUG(0,("Failed to create user record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, &sid, &dn); + if (!NT_STATUS_IS_OK(status)) { + return status; } - - a_state = talloc(d_state, struct samr_account_state); + a_state = talloc(mem_ctx, struct samr_account_state); if (!a_state) { ldb_transaction_cancel(d_state->sam_ctx); return NT_STATUS_NO_MEMORY; @@ -1389,71 +1205,7 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL a_state->sam_ctx = d_state->sam_ctx; a_state->access_mask = r->in.access_mask; a_state->domain_state = talloc_reference(a_state, d_state); - a_state->account_dn = talloc_steal(a_state, msg->dn); - - /* retrieve the sid and account control bits for the user just created */ - ret = gendb_search_dn(d_state->sam_ctx, a_state, - msg->dn, &msgs, attrs); - - if (ret != 1) { - ldb_transaction_cancel(d_state->sam_ctx); - DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n", - ldb_dn_get_linearized(msg->dn))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid"); - if (sid == NULL) { - ldb_transaction_cancel(d_state->sam_ctx); - DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n", - ldb_dn_get_linearized(msg->dn))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - /* Change the account control to be the correct account type. - * The default is for a workstation account */ - user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0); - user_account_control = (user_account_control & - ~(UF_NORMAL_ACCOUNT | - UF_INTERDOMAIN_TRUST_ACCOUNT | - UF_WORKSTATION_TRUST_ACCOUNT | - UF_SERVER_TRUST_ACCOUNT)); - user_account_control |= samdb_acb2uf(r->in.acct_flags); - - talloc_free(msg); - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_NO_MEMORY; - } - - msg->dn = ldb_dn_copy(msg, a_state->account_dn); - - if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, - "userAccountControl", - user_account_control) != 0) { - ldb_transaction_cancel(d_state->sam_ctx); - return NT_STATUS_NO_MEMORY; - } - - /* modify the samdb record */ - ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg); - if (ret != 0) { - DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - ldb_transaction_cancel(d_state->sam_ctx); - - /* we really need samdb.c to return NTSTATUS */ - return NT_STATUS_UNSUCCESSFUL; - } - - ret = ldb_transaction_commit(d_state->sam_ctx); - if (ret != 0) { - DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + a_state->account_dn = talloc_steal(a_state, dn); a_state->account_name = talloc_steal(a_state, account_name); if (!a_state->account_name) { @@ -1508,9 +1260,12 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_result *res; - int ret, num_filtered_entries, i, first; + int ret; + unsigned int i; + uint32_t num_filtered_entries, first; struct samr_SamEntry *entries; - const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL }; + const char * const attrs[] = { "objectSid", "sAMAccountName", + "userAccountControl", NULL }; struct samr_SamArray *sam; *r->out.resume_handle = 0; @@ -1549,8 +1304,7 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, } /* sort the results by rid */ - qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), - (comparison_fn_t)compare_SamEntry); + TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry); /* find the first entry to return */ for (first=0; @@ -1595,11 +1349,11 @@ static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, T struct samr_domain_state *d_state; struct samr_account_state *a_state; struct dcesrv_handle *h; - const char *alias_name, *name; - struct ldb_message *msg; + const char *alias_name; struct dom_sid *sid; struct dcesrv_handle *a_handle; - int ret; + struct ldb_dn *dn; + NTSTATUS status; ZERO_STRUCTP(r->out.alias_handle); *r->out.rid = 0; @@ -1619,49 +1373,12 @@ static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, T return NT_STATUS_INVALID_PARAMETER; } - /* Check if alias already exists */ - name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, - "sAMAccountName", - "(sAMAccountName=%s)(objectclass=group))", - ldb_binary_encode_string(mem_ctx, alias_name)); - - if (name != NULL) { - return NT_STATUS_ALIAS_EXISTS; - } - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* add core elements to the ldb_message for the alias */ - msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn); - ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name); - if (!msg->dn) { - return NT_STATUS_NO_MEMORY; - } - - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name); - samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group"); - samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP); - - /* create the alias */ - ret = ldb_add(d_state->sam_ctx, msg); - switch (ret) { - case LDB_SUCCESS: - break; - case LDB_ERR_ENTRY_ALREADY_EXISTS: - return NT_STATUS_ALIAS_EXISTS; - case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: - return NT_STATUS_ACCESS_DENIED; - default: - DEBUG(0,("Failed to create alias record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(d_state->sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn); + if (!NT_STATUS_IS_OK(status)) { + return status; } - a_state = talloc(d_state, struct samr_account_state); + a_state = talloc(mem_ctx, struct samr_account_state); if (!a_state) { return NT_STATUS_NO_MEMORY; } @@ -1669,16 +1386,9 @@ static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, T a_state->sam_ctx = d_state->sam_ctx; a_state->access_mask = r->in.access_mask; a_state->domain_state = talloc_reference(a_state, d_state); - a_state->account_dn = talloc_steal(a_state, msg->dn); + a_state->account_dn = talloc_steal(a_state, dn); - /* retrieve the sid for the alias just created */ - sid = samdb_search_dom_sid(d_state->sam_ctx, a_state, - msg->dn, "objectSid", NULL); - - a_state->account_name = talloc_strdup(a_state, alias_name); - if (!a_state->account_name) { - return NT_STATUS_NO_MEMORY; - } + a_state->account_name = talloc_steal(a_state, alias_name); /* create the policy handle */ a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS); @@ -1704,7 +1414,8 @@ static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_message **res; - int ldb_cnt, count, i, first; + int i, ldb_cnt; + uint32_t first, count; struct samr_SamEntry *entries; const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL }; struct samr_SamArray *sam; @@ -1759,8 +1470,7 @@ static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call } /* sort the results by rid */ - qsort(entries, count, sizeof(struct samr_SamEntry), - (comparison_fn_t)compare_SamEntry); + TYPESAFE_QSORT(entries, count, compare_SamEntry); /* find the first entry to return */ for (first=0; @@ -1803,7 +1513,8 @@ static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_cal struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_message **res; - int i, count = 0; + uint32_t i; + int count = 0; DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN); @@ -1826,7 +1537,8 @@ static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_cal memberdn = samdb_search_string(d_state->sam_ctx, - mem_ctx, NULL, "distinguishedName", + mem_ctx, NULL, + "distinguishedName", "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, r->in.sids->sids[i].sid)); @@ -1879,7 +1591,7 @@ static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALL { struct dcesrv_handle *h; struct samr_domain_state *d_state; - int i, num_mapped; + uint32_t i, num_mapped; NTSTATUS status = NT_STATUS_OK; const char * const attrs[] = { "sAMAccountType", "objectSid", NULL }; int count; @@ -1933,7 +1645,7 @@ static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALL continue; } - rtype = samdb_atype_map(atype); + rtype = ds_atype_map(atype); if (rtype == SID_NAME_UNKNOWN) { status = STATUS_SOME_UNMAPPED; @@ -1958,11 +1670,11 @@ static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALL static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_LookupRids *r) { + NTSTATUS status; struct dcesrv_handle *h; struct samr_domain_state *d_state; - int i, total; - NTSTATUS status = NT_STATUS_OK; - struct lsa_String *names; + const char **names; + struct lsa_String *lsa_names; uint32_t *ids; ZERO_STRUCTP(r->out.names); @@ -1975,64 +1687,27 @@ static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLO if (r->in.num_rids == 0) return NT_STATUS_OK; - names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids); - ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids); + lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids); + names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids); + ids = talloc_zero_array(mem_ctx, uint32_t, r->in.num_rids); - if ((names == NULL) || (ids == NULL)) + if ((lsa_names == NULL) || (names == NULL) || (ids == NULL)) return NT_STATUS_NO_MEMORY; - total = 0; - - for (i=0; iin.num_rids; i++) { - struct ldb_message **res; - int count; - const char * const attrs[] = { "sAMAccountType", - "sAMAccountName", NULL }; - uint32_t atype; - struct dom_sid *sid; - - ids[i] = SID_NAME_UNKNOWN; - - sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]); - if (sid == NULL) { - names[i].string = NULL; - status = STATUS_SOME_UNMAPPED; - continue; - } - - count = gendb_search(d_state->sam_ctx, mem_ctx, - d_state->domain_dn, &res, attrs, - "(objectSid=%s)", - ldap_encode_ndr_dom_sid(mem_ctx, sid)); - if (count != 1) { - names[i].string = NULL; - status = STATUS_SOME_UNMAPPED; - continue; - } - - names[i].string = samdb_result_string(res[0], "sAMAccountName", - NULL); - - atype = samdb_result_uint(res[0], "sAMAccountType", 0); - if (atype == 0) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - ids[i] = samdb_atype_map(atype); - - if (ids[i] == SID_NAME_UNKNOWN) { - status = STATUS_SOME_UNMAPPED; - continue; - } - } - - r->out.names->names = names; + r->out.names->names = lsa_names; r->out.names->count = r->in.num_rids; r->out.types->ids = ids; r->out.types->count = r->in.num_rids; + status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid, + r->in.num_rids, r->in.rids, names, ids); + if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) { + uint32_t i; + for (i = 0; i < r->in.num_rids; i++) { + lsa_names[i].string = names[i]; + } + } return status; } @@ -2068,9 +1743,10 @@ static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC /* search for the group record */ ret = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &msgs, attrs, - "(&(objectSid=%s)(objectclass=group)" - "(grouptype=%d))", + "(&(objectSid=%s)(objectClass=group)" + "(|(groupType=%d)(groupType=%d)))", ldap_encode_ndr_dom_sid(mem_ctx, sid), + GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP); if (ret == 0) { return NT_STATUS_NO_SUCH_GROUP; @@ -2088,7 +1764,7 @@ static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC return NT_STATUS_INTERNAL_DB_CORRUPTION; } - a_state = talloc(d_state, struct samr_account_state); + a_state = talloc(mem_ctx, struct samr_account_state); if (!a_state) { return NT_STATUS_NO_MEMORY; } @@ -2136,7 +1812,8 @@ static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, T a_state = h->data; - ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*"); + ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, + LDB_SCOPE_SUBTREE, attrs, "objectClass=*"); if (ret == LDB_ERR_NO_SUCH_OBJECT) { return NT_STATUS_NO_SUCH_GROUP; @@ -2237,7 +1914,7 @@ static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TAL /* modify the samdb record */ ret = ldb_modify(g_state->sam_ctx, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { /* we really need samdb.c to return NTSTATUS */ return NT_STATUS_UNSUCCESSFUL; } @@ -2268,17 +1945,17 @@ static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, T d_state = a_state->domain_state; membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid); - if (membersid == NULL) + if (membersid == NULL) { return NT_STATUS_NO_MEMORY; + } - /* In native mode, AD can also nest domain groups. Not sure yet - * whether this is also available via RPC. */ + /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */ ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, - d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, - "(&(objectSid=%s)(objectclass=user))", - ldap_encode_ndr_dom_sid(mem_ctx, membersid)); + d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, + "(objectSid=%s)", + ldap_encode_ndr_dom_sid(mem_ctx, membersid)); - if (ret != 0) { + if (ret != LDB_SUCCESS) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } @@ -2302,22 +1979,24 @@ static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, T mod->dn = talloc_reference(mem_ctx, a_state->account_dn); - if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member", - memberdn) != 0) + ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member", + memberdn); + if (ret != LDB_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; + } ret = ldb_modify(a_state->sam_ctx, mod); switch (ret) { case LDB_SUCCESS: return NT_STATUS_OK; case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: + case LDB_ERR_ENTRY_ALREADY_EXISTS: return NT_STATUS_MEMBER_IN_GROUP; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: return NT_STATUS_ACCESS_DENIED; default: return NT_STATUS_UNSUCCESSFUL; } - } @@ -2338,10 +2017,11 @@ static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call a_state = h->data; ret = ldb_delete(a_state->sam_ctx, a_state->account_dn); - if (ret != 0) { + if (ret != LDB_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; } + talloc_free(h); ZERO_STRUCTP(r->out.group_handle); return NT_STATUS_OK; @@ -2370,17 +2050,17 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call d_state = a_state->domain_state; membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid); - if (membersid == NULL) + if (membersid == NULL) { return NT_STATUS_NO_MEMORY; + } - /* In native mode, AD can also nest domain groups. Not sure yet - * whether this is also available via RPC. */ + /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */ ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, - d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, - "(&(objectSid=%s)(objectclass=user))", - ldap_encode_ndr_dom_sid(mem_ctx, membersid)); + d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, + "(objectSid=%s)", + ldap_encode_ndr_dom_sid(mem_ctx, membersid)); - if (ret != 0) { + if (ret != LDB_SUCCESS) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } @@ -2404,8 +2084,9 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call mod->dn = talloc_reference(mem_ctx, a_state->account_dn); - if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member", - memberdn) != 0) { + ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member", + memberdn); + if (ret != LDB_SUCCESS) { return NT_STATUS_NO_MEMORY; } @@ -2420,7 +2101,6 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call default: return NT_STATUS_UNSUCCESSFUL; } - } @@ -2430,68 +2110,57 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_QueryGroupMember *r) { + NTSTATUS status; struct dcesrv_handle *h; struct samr_account_state *a_state; - struct ldb_message **res; - struct ldb_message_element *el; struct samr_RidTypeArray *array; - const char * const attrs[2] = { "member", NULL }; - int ret; + unsigned int i, num_members; + struct dom_sid *members_as_sids; + struct dom_sid *dom_sid; DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP); a_state = h->data; - /* pull the member attribute */ - ret = gendb_search_dn(a_state->sam_ctx, mem_ctx, - a_state->account_dn, &res, attrs); + dom_sid = a_state->domain_state->domain_sid; + status = dsdb_enum_group_mem(a_state->sam_ctx, mem_ctx, a_state->account_dn, &members_as_sids, &num_members); - if (ret != 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + if (!NT_STATUS_IS_OK(status)) { + return status; } - array = talloc(mem_ctx, struct samr_RidTypeArray); + array = talloc_zero(mem_ctx, struct samr_RidTypeArray); if (array == NULL) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(array); - - el = ldb_msg_find_element(res[0], "member"); - - if (el != NULL) { - int i; - - array->count = el->num_values; + if (num_members == 0) { + *r->out.rids = array; - array->rids = talloc_array(mem_ctx, uint32_t, - el->num_values); - if (array->rids == NULL) - return NT_STATUS_NO_MEMORY; - - array->types = talloc_array(mem_ctx, uint32_t, - el->num_values); - if (array->types == NULL) - return NT_STATUS_NO_MEMORY; - - for (i=0; inum_values; i++) { - struct ldb_message **res2; - const char * const attrs2[2] = { "objectSid", NULL }; - ret = gendb_search_dn(a_state->sam_ctx, mem_ctx, - ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]), - &res2, attrs2); - if (ret != 1) - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return NT_STATUS_OK; + } - array->rids[i] = - samdb_result_rid_from_sid(mem_ctx, res2[0], - "objectSid", 0); + array->count = 0; + array->rids = talloc_array(array, uint32_t, + num_members); + if (array->rids == NULL) + return NT_STATUS_NO_MEMORY; - if (array->rids[i] == 0) - return NT_STATUS_INTERNAL_DB_CORRUPTION; + array->types = talloc_array(array, uint32_t, + num_members); + if (array->types == NULL) + return NT_STATUS_NO_MEMORY; - array->types[i] = 7; /* RID type of some kind, not sure what the value means. */ + for (i=0; irids[array->count]); + if (!NT_STATUS_IS_OK(status)) { + return status; } + array->types[array->count] = 7; /* RID type of some kind, not sure what the value means. */ + array->count++; } *r->out.rids = array; @@ -2561,7 +2230,7 @@ static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC return NT_STATUS_INTERNAL_DB_CORRUPTION; } - a_state = talloc(d_state, struct samr_account_state); + a_state = talloc(mem_ctx, struct samr_account_state); if (!a_state) { return NT_STATUS_NO_MEMORY; } @@ -2688,7 +2357,7 @@ static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TAL /* modify the samdb record */ ret = ldb_modify(a_state->sam_ctx, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { /* we really need samdb.c to return NTSTATUS */ return NT_STATUS_UNSUCCESSFUL; } @@ -2714,10 +2383,11 @@ static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, T a_state = h->data; ret = ldb_delete(a_state->sam_ctx, a_state->account_dn); - if (ret != 0) { + if (ret != LDB_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; } + talloc_free(h); ZERO_STRUCTP(r->out.alias_handle); return NT_STATUS_OK; @@ -2751,18 +2421,16 @@ static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, T if (ret == 1) { memberdn = msgs[0]->dn; - } else if (ret > 1) { - DEBUG(0,("Found %d records matching sid %s\n", - ret, dom_sid_string(mem_ctx, r->in.sid))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; } else if (ret == 0) { - status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, - r->in.sid, &memberdn); + status = samdb_create_foreign_security_principal( + d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn); if (!NT_STATUS_IS_OK(status)) { return status; } } else { - DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx))); + DEBUG(0,("Found %d records matching sid %s\n", + ret, dom_sid_string(mem_ctx, r->in.sid))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (memberdn == NULL) { @@ -2777,14 +2445,24 @@ static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, T mod->dn = talloc_reference(mem_ctx, a_state->account_dn); - if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member", - ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0) + ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member", + ldb_dn_alloc_linearized(mem_ctx, memberdn)); + if (ret != LDB_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; + } - if (ldb_modify(a_state->sam_ctx, mod) != 0) + ret = ldb_modify(a_state->sam_ctx, mod); + switch (ret) { + case LDB_SUCCESS: + return NT_STATUS_OK; + case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: + case LDB_ERR_ENTRY_ALREADY_EXISTS: + return NT_STATUS_MEMBER_IN_GROUP; + case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: + return NT_STATUS_ACCESS_DENIED; + default: return NT_STATUS_UNSUCCESSFUL; - - return NT_STATUS_OK; + } } @@ -2799,6 +2477,7 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call struct samr_domain_state *d_state; struct ldb_message *mod; const char *memberdn; + int ret; DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS); @@ -2808,9 +2487,9 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, "distinguishedName", "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid)); - - if (memberdn == NULL) + if (memberdn == NULL) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { @@ -2819,14 +2498,23 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call mod->dn = talloc_reference(mem_ctx, a_state->account_dn); - if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member", - memberdn) != 0) + ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member", + memberdn); + if (ret != LDB_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; + } - if (ldb_modify(a_state->sam_ctx, mod) != 0) + ret = ldb_modify(a_state->sam_ctx, mod); + switch (ret) { + case LDB_SUCCESS: + return NT_STATUS_OK; + case LDB_ERR_NO_SUCH_ATTRIBUTE: + return NT_STATUS_MEMBER_NOT_IN_GROUP; + case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: + return NT_STATUS_ACCESS_DENIED; + default: return NT_STATUS_UNSUCCESSFUL; - - return NT_STATUS_OK; + } } @@ -2839,61 +2527,43 @@ static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call struct dcesrv_handle *h; struct samr_account_state *a_state; struct samr_domain_state *d_state; - struct ldb_message **msgs; struct lsa_SidPtr *sids; - struct ldb_message_element *el; - const char * const attrs[2] = { "member", NULL}; - int ret; - + unsigned int i, num_members; + struct dom_sid *members; + NTSTATUS status; DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS); a_state = h->data; d_state = a_state->domain_state; - ret = gendb_search_dn(d_state->sam_ctx, mem_ctx, - a_state->account_dn, &msgs, attrs); - - if (ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } else if (ret == 0) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } else if (ret != 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx, + a_state->account_dn, &members, &num_members); + if (!NT_STATUS_IS_OK(status)) { + return status; } - r->out.sids->num_sids = 0; r->out.sids->sids = NULL; - el = ldb_msg_find_element(msgs[0], "member"); + if (num_members == 0) { + return NT_STATUS_OK; + } - if (el != NULL) { - int i; + sids = talloc_array(mem_ctx, struct lsa_SidPtr, + num_members); - sids = talloc_array(mem_ctx, struct lsa_SidPtr, - el->num_values); + if (sids == NULL) + return NT_STATUS_NO_MEMORY; - if (sids == NULL) + for (i=0; inum_values; i++) { - struct ldb_message **msgs2; - const char * const attrs2[2] = { "objectSid", NULL }; - ret = gendb_search_dn(a_state->sam_ctx, mem_ctx, - ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]), - &msgs2, attrs2); - if (ret != 1) - return NT_STATUS_INTERNAL_DB_CORRUPTION; - - sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0], - "objectSid"); - - if (sids[i].sid == NULL) - return NT_STATUS_INTERNAL_DB_CORRUPTION; } - r->out.sids->num_sids = el->num_values; - r->out.sids->sids = sids; } + r->out.sids->num_sids = num_members; + r->out.sids->sids = sids; + return NT_STATUS_OK; } @@ -2992,13 +2662,14 @@ static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLO a_state = h->data; ret = ldb_delete(a_state->sam_ctx, a_state->account_dn); - if (ret != 0) { + if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to delete user: %s: %s\n", ldb_dn_get_linearized(a_state->account_dn), ldb_errstring(a_state->sam_ctx))); return NT_STATUS_UNSUCCESSFUL; } + talloc_free(h); ZERO_STRUCTP(r->out.user_handle); return NT_STATUS_OK; @@ -3031,15 +2702,21 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA switch (r->in.level) { case 1: { - static const char * const attrs2[] = {"sAMAccountName", "displayName", - "primaryroupID", "description", - "comment", NULL}; + static const char * const attrs2[] = {"sAMAccountName", + "displayName", + "primaryroupID", + "description", + "comment", + NULL}; attrs = attrs2; break; } case 2: { - static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL}; + static const char * const attrs2[] = {"comment", + "countryCode", + "codePage", + NULL}; attrs = attrs2; break; } @@ -3060,13 +2737,15 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA "logonHours", "badPwdCount", "logonCount", - "userAccountControl", NULL}; + "userAccountControl", + NULL}; attrs = attrs2; break; } case 4: { - static const char * const attrs2[] = {"logonHours", NULL}; + static const char * const attrs2[] = {"logonHours", + NULL}; attrs = attrs2; break; } @@ -3096,73 +2775,92 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA } case 6: { - static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL}; + static const char * const attrs2[] = {"sAMAccountName", + "displayName", + NULL}; attrs = attrs2; break; } case 7: { - static const char * const attrs2[] = {"sAMAccountName", NULL}; + static const char * const attrs2[] = {"sAMAccountName", + NULL}; attrs = attrs2; break; } case 8: { - static const char * const attrs2[] = {"displayName", NULL}; + static const char * const attrs2[] = {"displayName", + NULL}; attrs = attrs2; break; } case 9: { - static const char * const attrs2[] = {"primaryGroupID", NULL}; + static const char * const attrs2[] = {"primaryGroupID", + NULL}; attrs = attrs2; break; } case 10: { - static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL}; + static const char * const attrs2[] = {"homeDirectory", + "homeDrive", + NULL}; attrs = attrs2; break; } case 11: { - static const char * const attrs2[] = {"scriptPath", NULL}; + static const char * const attrs2[] = {"scriptPath", + NULL}; attrs = attrs2; break; } case 12: { - static const char * const attrs2[] = {"profilePath", NULL}; + static const char * const attrs2[] = {"profilePath", + NULL}; attrs = attrs2; break; } case 13: { - static const char * const attrs2[] = {"description", NULL}; + static const char * const attrs2[] = {"description", + NULL}; attrs = attrs2; break; } case 14: { - static const char * const attrs2[] = {"userWorkstations", NULL}; + static const char * const attrs2[] = {"userWorkstations", + NULL}; attrs = attrs2; break; } case 16: { - static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL}; + static const char * const attrs2[] = {"userAccountControl", + "pwdLastSet", + NULL}; attrs = attrs2; break; } case 17: { - static const char * const attrs2[] = {"accountExpires", NULL}; + static const char * const attrs2[] = {"accountExpires", + NULL}; attrs = attrs2; break; } + case 18: + { + return NT_STATUS_NOT_SUPPORTED; + } case 20: { - static const char * const attrs2[] = {"userParameters", NULL}; + static const char * const attrs2[] = {"userParameters", + NULL}; attrs = attrs2; break; } @@ -3194,6 +2892,17 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA attrs = attrs2; break; } + case 23: + case 24: + case 25: + case 26: + { + return NT_STATUS_NOT_SUPPORTED; + } + default: + { + return NT_STATUS_INVALID_INFO_CLASS; + } } /* pull all the user attributes */ @@ -3402,6 +3111,7 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL break; case 6: + SET_STRING(msg, info6.account_name, "samAccountName"); SET_STRING(msg, info6.full_name, "displayName"); break; @@ -3451,81 +3161,90 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL break; case 21: -#define IFSET(bit) if (bit & r->in.info->info21.fields_present) +#define IFSET(bit) if (bit & r->in.info->info21.fields_present) IFSET(SAMR_FIELD_ACCT_EXPIRY) - SET_UINT64(msg, info21.acct_expiry, "accountExpires"); + SET_UINT64(msg, info21.acct_expiry, "accountExpires"); IFSET(SAMR_FIELD_ACCOUNT_NAME) SET_STRING(msg, info21.account_name, "samAccountName"); IFSET(SAMR_FIELD_FULL_NAME) SET_STRING(msg, info21.full_name, "displayName"); - IFSET(SAMR_FIELD_DESCRIPTION) - SET_STRING(msg, info21.description, "description"); - IFSET(SAMR_FIELD_COMMENT) - SET_STRING(msg, info21.comment, "comment"); - IFSET(SAMR_FIELD_LOGON_SCRIPT) - SET_STRING(msg, info21.logon_script, "scriptPath"); - IFSET(SAMR_FIELD_PROFILE_PATH) - SET_STRING(msg, info21.profile_path, "profilePath"); IFSET(SAMR_FIELD_HOME_DIRECTORY) SET_STRING(msg, info21.home_directory, "homeDirectory"); IFSET(SAMR_FIELD_HOME_DRIVE) SET_STRING(msg, info21.home_drive, "homeDrive"); + IFSET(SAMR_FIELD_LOGON_SCRIPT) + SET_STRING(msg, info21.logon_script, "scriptPath"); + IFSET(SAMR_FIELD_PROFILE_PATH) + SET_STRING(msg, info21.profile_path, "profilePath"); + IFSET(SAMR_FIELD_DESCRIPTION) + SET_STRING(msg, info21.description, "description"); IFSET(SAMR_FIELD_WORKSTATIONS) SET_STRING(msg, info21.workstations, "userWorkstations"); - IFSET(SAMR_FIELD_LOGON_HOURS) - SET_LHOURS(msg, info21.logon_hours, "logonHours"); - IFSET(SAMR_FIELD_ACCT_FLAGS) - SET_AFLAGS(msg, info21.acct_flags, "userAccountControl"); + IFSET(SAMR_FIELD_COMMENT) + SET_STRING(msg, info21.comment, "comment"); IFSET(SAMR_FIELD_PARAMETERS) SET_PARAMETERS(msg, info21.parameters, "userParameters"); + IFSET(SAMR_FIELD_PRIMARY_GID) + SET_UINT(msg, info21.primary_gid, "primaryGroupID"); + IFSET(SAMR_FIELD_ACCT_FLAGS) + SET_AFLAGS(msg, info21.acct_flags, "userAccountControl"); + IFSET(SAMR_FIELD_LOGON_HOURS) + SET_LHOURS(msg, info21.logon_hours, "logonHours"); IFSET(SAMR_FIELD_COUNTRY_CODE) SET_UINT (msg, info21.country_code, "countryCode"); IFSET(SAMR_FIELD_CODE_PAGE) - SET_UINT (msg, info21.code_page, "codePage"); + SET_UINT (msg, info21.code_page, "codePage"); #undef IFSET break; case 23: #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present) IFSET(SAMR_FIELD_ACCT_EXPIRY) - SET_UINT64(msg, info23.info.acct_expiry, "accountExpires"); + SET_UINT64(msg, info23.info.acct_expiry, "accountExpires"); IFSET(SAMR_FIELD_ACCOUNT_NAME) - SET_STRING(msg, info23.info.account_name, "samAccountName"); - IFSET(SAMR_FIELD_FULL_NAME) - SET_STRING(msg, info23.info.full_name, "displayName"); - IFSET(SAMR_FIELD_DESCRIPTION) - SET_STRING(msg, info23.info.description, "description"); - IFSET(SAMR_FIELD_COMMENT) - SET_STRING(msg, info23.info.comment, "comment"); - IFSET(SAMR_FIELD_LOGON_SCRIPT) - SET_STRING(msg, info23.info.logon_script, "scriptPath"); - IFSET(SAMR_FIELD_PROFILE_PATH) - SET_STRING(msg, info23.info.profile_path, "profilePath"); - IFSET(SAMR_FIELD_WORKSTATIONS) - SET_STRING(msg, info23.info.workstations, "userWorkstations"); - IFSET(SAMR_FIELD_LOGON_HOURS) - SET_LHOURS(msg, info23.info.logon_hours, "logonHours"); - IFSET(SAMR_FIELD_ACCT_FLAGS) - SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl"); - IFSET(SAMR_FIELD_PARAMETERS) + SET_STRING(msg, info23.info.account_name, "samAccountName"); + IFSET(SAMR_FIELD_FULL_NAME) + SET_STRING(msg, info23.info.full_name, "displayName"); + IFSET(SAMR_FIELD_HOME_DIRECTORY) + SET_STRING(msg, info23.info.home_directory, "homeDirectory"); + IFSET(SAMR_FIELD_HOME_DRIVE) + SET_STRING(msg, info23.info.home_drive, "homeDrive"); + IFSET(SAMR_FIELD_LOGON_SCRIPT) + SET_STRING(msg, info23.info.logon_script, "scriptPath"); + IFSET(SAMR_FIELD_PROFILE_PATH) + SET_STRING(msg, info23.info.profile_path, "profilePath"); + IFSET(SAMR_FIELD_DESCRIPTION) + SET_STRING(msg, info23.info.description, "description"); + IFSET(SAMR_FIELD_WORKSTATIONS) + SET_STRING(msg, info23.info.workstations, "userWorkstations"); + IFSET(SAMR_FIELD_COMMENT) + SET_STRING(msg, info23.info.comment, "comment"); + IFSET(SAMR_FIELD_PARAMETERS) SET_PARAMETERS(msg, info23.info.parameters, "userParameters"); - IFSET(SAMR_FIELD_COUNTRY_CODE) - SET_UINT (msg, info23.info.country_code, "countryCode"); - IFSET(SAMR_FIELD_CODE_PAGE) - SET_UINT (msg, info23.info.code_page, "codePage"); + IFSET(SAMR_FIELD_PRIMARY_GID) + SET_UINT(msg, info23.info.primary_gid, "primaryGroupID"); + IFSET(SAMR_FIELD_ACCT_FLAGS) + SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl"); + IFSET(SAMR_FIELD_LOGON_HOURS) + SET_LHOURS(msg, info23.info.logon_hours, "logonHours"); + IFSET(SAMR_FIELD_COUNTRY_CODE) + SET_UINT (msg, info23.info.country_code, "countryCode"); + IFSET(SAMR_FIELD_CODE_PAGE) + SET_UINT (msg, info23.info.code_page, "codePage"); + IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) { status = samr_set_password(dce_call, a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info23.password); } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) { status = samr_set_password(dce_call, a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info23.password); } #undef IFSET @@ -3537,51 +3256,58 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info24.password); break; case 25: #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present) IFSET(SAMR_FIELD_ACCT_EXPIRY) - SET_UINT64(msg, info25.info.acct_expiry, "accountExpires"); + SET_UINT64(msg, info25.info.acct_expiry, "accountExpires"); IFSET(SAMR_FIELD_ACCOUNT_NAME) - SET_STRING(msg, info25.info.account_name, "samAccountName"); - IFSET(SAMR_FIELD_FULL_NAME) - SET_STRING(msg, info25.info.full_name, "displayName"); - IFSET(SAMR_FIELD_DESCRIPTION) - SET_STRING(msg, info25.info.description, "description"); - IFSET(SAMR_FIELD_COMMENT) - SET_STRING(msg, info25.info.comment, "comment"); - IFSET(SAMR_FIELD_LOGON_SCRIPT) - SET_STRING(msg, info25.info.logon_script, "scriptPath"); - IFSET(SAMR_FIELD_PROFILE_PATH) - SET_STRING(msg, info25.info.profile_path, "profilePath"); - IFSET(SAMR_FIELD_WORKSTATIONS) - SET_STRING(msg, info25.info.workstations, "userWorkstations"); - IFSET(SAMR_FIELD_LOGON_HOURS) - SET_LHOURS(msg, info25.info.logon_hours, "logonHours"); - IFSET(SAMR_FIELD_ACCT_FLAGS) - SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl"); - IFSET(SAMR_FIELD_PARAMETERS) + SET_STRING(msg, info25.info.account_name, "samAccountName"); + IFSET(SAMR_FIELD_FULL_NAME) + SET_STRING(msg, info25.info.full_name, "displayName"); + IFSET(SAMR_FIELD_HOME_DIRECTORY) + SET_STRING(msg, info25.info.home_directory, "homeDirectory"); + IFSET(SAMR_FIELD_HOME_DRIVE) + SET_STRING(msg, info25.info.home_drive, "homeDrive"); + IFSET(SAMR_FIELD_LOGON_SCRIPT) + SET_STRING(msg, info25.info.logon_script, "scriptPath"); + IFSET(SAMR_FIELD_PROFILE_PATH) + SET_STRING(msg, info25.info.profile_path, "profilePath"); + IFSET(SAMR_FIELD_DESCRIPTION) + SET_STRING(msg, info25.info.description, "description"); + IFSET(SAMR_FIELD_WORKSTATIONS) + SET_STRING(msg, info25.info.workstations, "userWorkstations"); + IFSET(SAMR_FIELD_COMMENT) + SET_STRING(msg, info25.info.comment, "comment"); + IFSET(SAMR_FIELD_PARAMETERS) SET_PARAMETERS(msg, info25.info.parameters, "userParameters"); - IFSET(SAMR_FIELD_COUNTRY_CODE) - SET_UINT (msg, info25.info.country_code, "countryCode"); - IFSET(SAMR_FIELD_CODE_PAGE) - SET_UINT (msg, info25.info.code_page, "codePage"); + IFSET(SAMR_FIELD_PRIMARY_GID) + SET_UINT(msg, info25.info.primary_gid, "primaryGroupID"); + IFSET(SAMR_FIELD_ACCT_FLAGS) + SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl"); + IFSET(SAMR_FIELD_LOGON_HOURS) + SET_LHOURS(msg, info25.info.logon_hours, "logonHours"); + IFSET(SAMR_FIELD_COUNTRY_CODE) + SET_UINT (msg, info25.info.country_code, "countryCode"); + IFSET(SAMR_FIELD_CODE_PAGE) + SET_UINT (msg, info25.info.code_page, "codePage"); + IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) { status = samr_set_password_ex(dce_call, a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info25.password); } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) { status = samr_set_password_ex(dce_call, a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info25.password); } #undef IFSET @@ -3593,7 +3319,7 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - mem_ctx, msg, + mem_ctx, &r->in.info->info26.password); break; @@ -3608,14 +3334,16 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL } /* modify the samdb record */ - ret = ldb_modify(a_state->sam_ctx, msg); - if (ret != 0) { - DEBUG(1,("Failed to modify record %s: %s\n", - ldb_dn_get_linearized(a_state->account_dn), - ldb_errstring(a_state->sam_ctx))); + if (msg->num_elements > 0) { + ret = ldb_modify(a_state->sam_ctx, msg); + if (ret != LDB_SUCCESS) { + DEBUG(1,("Failed to modify record %s: %s\n", + ldb_dn_get_linearized(a_state->account_dn), + ldb_errstring(a_state->sam_ctx))); - /* we really need samdb.c to return NTSTATUS */ - return NT_STATUS_UNSUCCESSFUL; + /* we really need samdb.c to return NTSTATUS */ + return NT_STATUS_UNSUCCESSFUL; + } } return NT_STATUS_OK; @@ -3634,14 +3362,15 @@ static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, struct ldb_message **res; const char * const attrs[2] = { "objectSid", NULL }; struct samr_RidWithAttributeArray *array; - int count; + int i, count; DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER); a_state = h->data; d_state = a_state->domain_state; - count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, + count = samdb_search_domain(a_state->sam_ctx, mem_ctx, + d_state->domain_dn, &res, attrs, d_state->domain_sid, "(&(member=%s)(grouptype=%d)(objectclass=group))", ldb_dn_get_linearized(a_state->account_dn), @@ -3656,29 +3385,34 @@ static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, array->count = 0; array->rids = NULL; - if (count > 0) { - int i; - array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, - count); - - if (array->rids == NULL) - return NT_STATUS_NO_MEMORY; + array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, + count + 1); + if (array->rids == NULL) + return NT_STATUS_NO_MEMORY; - for (i=0; irids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx, + ~0, a_state->account_dn, + "primaryGroupID", NULL); + array->rids[0].attributes = SE_GROUP_MANDATORY + | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; + array->count += 1; - group_sid = samdb_result_dom_sid(mem_ctx, res[i], - "objectSid"); - if (group_sid == NULL) { - DEBUG(0, ("Couldn't find objectSid attrib\n")); - continue; - } + /* Adds the additional groups */ + for (i = 0; i < count; i++) { + struct dom_sid *group_sid; - array->rids[array->count].rid = - group_sid->sub_auths[group_sid->num_auths-1]; - array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; - array->count += 1; + group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); + if (group_sid == NULL) { + DEBUG(0, ("Couldn't find objectSid attrib\n")); + continue; } + + array->rids[i + 1].rid = + group_sid->sub_auths[group_sid->num_auths-1]; + array->rids[i + 1].attributes = SE_GROUP_MANDATORY + | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; + array->count += 1; } *r->out.rids = array; @@ -3696,13 +3430,15 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_message **res; - int ldb_cnt, count, i; - const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName", - "description", "userAccountControl", "pwdLastSet", NULL }; + int i, ldb_cnt; + uint32_t count; + const char * const attrs[] = { "objectSid", "sAMAccountName", + "displayName", "description", "userAccountControl", + "pwdLastSet", NULL }; struct samr_DispEntryFull *entriesFull = NULL; struct samr_DispEntryFullGroup *entriesFullGroup = NULL; struct samr_DispEntryAscii *entriesAscii = NULL; - struct samr_DispEntryGeneral * entriesGeneral = NULL; + struct samr_DispEntryGeneral *entriesGeneral = NULL; const char *filter; DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN); @@ -3723,8 +3459,10 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, break; case 3: case 5: - filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)" - "(objectclass=group))", + filter = talloc_asprintf(mem_ctx, + "(&(|(groupType=%d)(groupType=%d))" + "(objectClass=group))", + GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP); break; default: @@ -3746,8 +3484,8 @@ static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, switch (r->in.level) { case 1: entriesGeneral = talloc_array(mem_ctx, - struct samr_DispEntryGeneral, - ldb_cnt); + struct samr_DispEntryGeneral, + ldb_cnt); break; case 2: entriesFull = talloc_array(mem_ctx, @@ -3947,12 +3685,12 @@ static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TA a_state = h->data; - r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, - a_state->domain_state->domain_dn, "minPwdLength", - NULL); - r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, - a_state->account_dn, - "pwdProperties", NULL); + r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx, + mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength", + NULL); + r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx, + mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL); + return NT_STATUS_OK; } @@ -4012,10 +3750,10 @@ static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_sta } if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, - "member", memberdn) != 0) + "member", memberdn) != LDB_SUCCESS) return NT_STATUS_NO_MEMORY; - if (ldb_modify(d_state->sam_ctx, mod) != 0) + if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS) return NT_STATUS_UNSUCCESSFUL; talloc_free(mod); @@ -4164,7 +3902,9 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL ZERO_STRUCTP(r->out.info); - sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); + sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, + dce_call->conn->dce_ctx->lp_ctx, + dce_call->conn->auth_state.session_info); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } @@ -4173,19 +3913,25 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL ret = gendb_search_dn(sam_ctx, mem_ctx, NULL, &msgs, attrs); if (ret <= 0) { + talloc_free(sam_ctx); + return NT_STATUS_NO_SUCH_DOMAIN; } if (ret > 1) { talloc_free(msgs); + talloc_free(sam_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; } - r->out.info->min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0); - r->out.info->password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1); + r->out.info->min_password_length = samdb_result_uint(msgs[0], + "minPwdLength", 0); + r->out.info->password_properties = samdb_result_uint(msgs[0], + "pwdProperties", 1); talloc_free(msgs); + talloc_unlink(mem_ctx, sam_ctx); - talloc_free(sam_ctx); return NT_STATUS_OK; } @@ -4333,12 +4079,57 @@ static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, /* - samr_ValidatePassword + samr_ValidatePassword + + For now the call checks the password complexity (if active) and the minimum + password length on level 2 and 3. Level 1 is ignored for now. */ -static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_ValidatePassword *r) +static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct samr_ValidatePassword *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct samr_GetDomPwInfo r2; + struct samr_PwInfo pwInfo; + DATA_BLOB password; + enum samr_ValidationStatus res; + NTSTATUS status; + + (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep); + + r2.in.domain_name = NULL; + r2.out.info = &pwInfo; + status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (r->in.level) { + case NetValidateAuthentication: + /* we don't support this yet */ + return NT_STATUS_NOT_SUPPORTED; + break; + case NetValidatePasswordChange: + password = data_blob_const(r->in.req->req2.password.string, + r->in.req->req2.password.length); + res = samdb_check_password(&password, + pwInfo.password_properties, + pwInfo.min_password_length); + (*r->out.rep)->ctr2.status = res; + break; + case NetValidatePasswordReset: + password = data_blob_const(r->in.req->req3.password.string, + r->in.req->req3.password.length); + res = samdb_check_password(&password, + pwInfo.password_properties, + pwInfo.min_password_length); + (*r->out.rep)->ctr3.status = res; + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + break; + } + + return NT_STATUS_OK; }