dcesrv_samr.c
来自「samba最新软件」· C语言 代码 · 共 2,389 行 · 第 1/5 页
C
2,389 行
/* Unix SMB/CIFS implementation. endpoint server for the samr pipe Copyright (C) Andrew Tridgell 2004 Copyright (C) Volker Lendecke 2004 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "librpc/gen_ndr/ndr_samr.h"#include "rpc_server/dcerpc_server.h"#include "rpc_server/common/common.h"#include "rpc_server/samr/dcesrv_samr.h"#include "system/time.h"#include "lib/ldb/include/ldb.h"#include "lib/ldb/include/ldb_errors.h"#include "dsdb/common/flags.h"#include "dsdb/samdb/samdb.h"#include "libcli/ldap/ldap_ndr.h"#include "libcli/security/security.h"#include "rpc_server/samr/proto.h"#include "util/util_ldb.h"#include "param/param.h"/* these query macros make samr_Query[User|Group]Info a bit easier to read */#define QUERY_STRING(msg, field, attr) \ r->out.info->field.string = samdb_result_string(msg, attr, "");#define QUERY_UINT(msg, field, attr) \ r->out.info->field = samdb_result_uint(msg, attr, 0);#define QUERY_RID(msg, field, attr) \ r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);#define QUERY_UINT64(msg, field, attr) \ r->out.info->field = samdb_result_uint64(msg, attr, 0);#define QUERY_APASSC(msg, field, attr) \ r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \ a_state->domain_state->domain_dn, msg, attr);#define QUERY_FPASSC(msg, field, attr) \ r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \ a_state->domain_state->domain_dn, msg);#define QUERY_LHOURS(msg, field, attr) \ r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);#define QUERY_AFLAGS(msg, field, attr) \ r->out.info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);/* these are used to make the Set[User|Group]Info code easier to follow */#define SET_STRING(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \ if (r->in.info->field.string[0] == '\0') { \ if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \ return NT_STATUS_NO_MEMORY; \ } \ } \ if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0)#define SET_UINT(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0) #define SET_INT64(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0) #define SET_UINT64(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0) #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \ do { \ if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \ return NT_STATUS_INVALID_PARAMETER; \ } \ } while (0) \ /* Set account flags, discarding flags that cannot be set with SAMR */ #define SET_AFLAGS(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \ return NT_STATUS_INVALID_PARAMETER; \ } \ CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \ if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0) #define SET_LHOURS(msg, field, attr) do { \ struct ldb_message_element *set_el; \ if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \ return NT_STATUS_NO_MEMORY; \ } \ set_el = ldb_msg_find_element(msg, attr); \ set_el->flags = LDB_FLAG_MOD_REPLACE; \} while (0)/* samr_Connect create a connection to the SAM database*/static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_Connect *r){ struct samr_connect_state *c_state; struct dcesrv_handle *handle; ZERO_STRUCTP(r->out.connect_handle); c_state = talloc(dce_call->conn, struct samr_connect_state); if (!c_state) { return NT_STATUS_NO_MEMORY; } /* make sure the sam database is accessible */ c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); if (c_state->sam_ctx == NULL) { talloc_free(c_state); return NT_STATUS_INVALID_SYSTEM_SERVICE; } handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT); if (!handle) { talloc_free(c_state); return NT_STATUS_NO_MEMORY; } handle->data = talloc_steal(handle, c_state); c_state->access_mask = r->in.access_mask; *r->out.connect_handle = handle->wire_handle; return NT_STATUS_OK;}/* samr_Close */static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_Close *r){ struct dcesrv_handle *h; *r->out.handle = *r->in.handle; DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY); talloc_free(h); ZERO_STRUCTP(r->out.handle); return NT_STATUS_OK;}/* samr_SetSecurity */static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_SetSecurity *r){ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);}/* samr_QuerySecurity */static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_QuerySecurity *r){ struct dcesrv_handle *h; struct sec_desc_buf *sd; r->out.sdbuf = NULL; DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY); sd = talloc(mem_ctx, struct sec_desc_buf); if (sd == NULL) { return NT_STATUS_NO_MEMORY; } sd->sd = samdb_default_security_descriptor(mem_ctx); r->out.sdbuf = sd; return NT_STATUS_OK;}/* samr_Shutdown we refuse this operation completely. If a admin wants to shutdown samr in Samba then they should use the samba admin tools to disable the samr pipe*/static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_Shutdown *r){ return NT_STATUS_ACCESS_DENIED;}/* samr_LookupDomain this maps from a domain name to a SID*/static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_LookupDomain *r){ struct samr_connect_state *c_state; 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; DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT); c_state = h->data; if (r->in.domain_name->string == NULL) { 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), &dom_msgs, dom_attrs); } if (ret != 1) { return NT_STATUS_NO_SUCH_DOMAIN; } sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0], "objectSid"); if (sid == NULL) { return NT_STATUS_NO_SUCH_DOMAIN; } r->out.sid = sid; return NT_STATUS_OK;}/* samr_EnumDomains list the domains in the SAM*/static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_EnumDomains *r){ 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; *r->out.resume_handle = 0; r->out.sam = NULL; r->out.num_entries = 0; DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT); c_state = h->data; partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx); ret = ldb_search_exp_fmt(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; start_i = *r->in.resume_handle; if (start_i >= dom_res->count) { /* search past end of list is not an error for this call */ return NT_STATUS_OK; } array = talloc(mem_ctx, struct samr_SamArray); if (array == NULL) { return NT_STATUS_NO_MEMORY; } array->count = 0; array->entries = NULL; array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i); if (array->entries == NULL) { return NT_STATUS_NO_MEMORY; } for (i=0;i<dom_res->count-start_i;i++) { array->entries[i].idx = start_i + i; /* try and find the domain */ ret = ldb_search_exp_fmt(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); } else { array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL); } } r->out.sam = array; r->out.num_entries = i; array->count = r->out.num_entries; return NT_STATUS_OK;}/* samr_OpenDomain */static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 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); DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT); c_state = h_conn->data; if (r->in.sid == NULL) { return NT_STATUS_INVALID_PARAMETER; } partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx); ret = gendb_search(c_state->sam_ctx, mem_ctx, NULL, &dom_msgs, dom_attrs, "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid)); if (ret == 0) { return NT_STATUS_NO_SUCH_DOMAIN; } else if (ret > 1) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } else if (ret == -1) { 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->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))) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?