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 + -
显示快捷键?