• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/rpc_server/drsuapi/
1/*
2   Unix SMB/CIFS implementation.
3
4   implement the DsAddEntry call
5
6   Copyright (C) Stefan Metzmacher 2009
7   Copyright (C) Andrew Tridgell   2009
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "includes.h"
24#include "rpc_server/dcerpc_server.h"
25#include "rpc_server/common/common.h"
26#include "dsdb/samdb/samdb.h"
27#include "lib/ldb/include/ldb_errors.h"
28#include "param/param.h"
29#include "librpc/gen_ndr/ndr_drsblobs.h"
30#include "auth/auth.h"
31#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
32#include "libcli/security/security.h"
33#include "librpc/gen_ndr/ndr_drsblobs.h"
34#include "librpc/gen_ndr/ndr_drsuapi.h"
35
36
37/*
38  add special SPNs needed for DRS replication to machine accounts when
39  an AddEntry is done to create a nTDSDSA object
40 */
41static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state,
42			       struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
43			       const struct drsuapi_DsReplicaObjectListItem *first_object)
44{
45	int ret;
46	const struct drsuapi_DsReplicaObjectListItem *obj;
47	const char *attrs[] = { "serverReference", "objectGUID", NULL };
48
49	for (obj = first_object; obj; obj=obj->next_object) {
50		const char *dn_string = obj->object.identifier->dn;
51		struct ldb_dn *dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, dn_string);
52		struct ldb_result *res;
53		struct ldb_dn *ref_dn;
54		struct GUID ntds_guid;
55		struct ldb_message *msg;
56		struct ldb_message_element *el;
57		const char *ntds_guid_str;
58		const char *dom_string;
59
60		DEBUG(6,(__location__ ": Adding SPNs for %s\n",
61			 ldb_dn_get_linearized(dn)));
62
63		ret = ldb_search(b_state->sam_ctx, mem_ctx, &res,
64				 dn, LDB_SCOPE_BASE, attrs,
65				 "(objectClass=ntDSDSA)");
66		if (ret != LDB_SUCCESS || res->count < 1) {
67			DEBUG(0,(__location__ ": Failed to find dn '%s'\n", dn_string));
68			return WERR_DS_DRA_INTERNAL_ERROR;
69		}
70
71		ref_dn = samdb_result_dn(b_state->sam_ctx, mem_ctx, res->msgs[0], "serverReference", NULL);
72		if (ref_dn == NULL) {
73			/* we only add SPNs for objects with a
74			   serverReference */
75			continue;
76		}
77
78		DEBUG(6,(__location__ ": serverReference %s\n",
79			 ldb_dn_get_linearized(ref_dn)));
80
81		ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
82
83		ntds_guid_str = GUID_string(res, &ntds_guid);
84
85		dom_string = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
86
87		/*
88		 * construct a modify request to add the new SPNs to
89		 * the machine account
90		 */
91		msg = ldb_msg_new(mem_ctx);
92		if (msg == NULL) {
93			return WERR_NOMEM;
94		}
95
96		msg->dn = ref_dn;
97		ret = ldb_msg_add_empty(msg, "servicePrincipalName",
98					LDB_FLAG_MOD_ADD, &el);
99		if (ret != LDB_SUCCESS) {
100			return WERR_NOMEM;
101		}
102
103		el->num_values = 2;
104		el->values = talloc_array(msg->elements, struct ldb_val, 2);
105		if (el->values == NULL) {
106			return WERR_NOMEM;
107		}
108		/* the magic constant is the GUID of the DRSUAPI RPC
109		   interface */
110		el->values[0].data = (uint8_t *)talloc_asprintf(el->values,
111								"E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
112								ntds_guid_str, dom_string);
113		el->values[0].length = strlen((char *)el->values[0].data);
114		el->values[1].data = (uint8_t *)talloc_asprintf(el->values, "ldap/%s._msdcs.%s",
115								ntds_guid_str, dom_string);
116		el->values[1].length = strlen((char *)el->values[1].data);
117
118		ret = ldb_modify(b_state->sam_ctx, msg);
119		if (ret != LDB_SUCCESS) {
120			DEBUG(0,(__location__ ": Failed to add SPNs - %s\n",
121				 ldb_errstring(b_state->sam_ctx)));
122			return WERR_DS_DRA_INTERNAL_ERROR;
123		}
124	}
125
126	return WERR_OK;
127}
128
129
130
131
132/*
133  drsuapi_DsAddEntry
134*/
135WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
136				 struct drsuapi_DsAddEntry *r)
137{
138	WERROR status;
139	struct drsuapi_bind_state *b_state;
140	struct dcesrv_handle *h;
141	uint32_t num = 0;
142	struct drsuapi_DsReplicaObjectIdentifier2 *ids = NULL;
143	int ret;
144	const struct drsuapi_DsReplicaObjectListItem *first_object;
145
146	if (DEBUGLVL(4)) {
147		NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsAddEntry, NDR_IN, r);
148	}
149
150	/* TODO: check which out level the client supports */
151
152	ZERO_STRUCTP(r->out.ctr);
153	*r->out.level_out = 3;
154	r->out.ctr->ctr3.level = 1;
155	r->out.ctr->ctr3.error = talloc_zero(mem_ctx, union drsuapi_DsAddEntryError);
156
157	DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
158	b_state = h->data;
159
160	status = drs_security_level_check(dce_call, "DsAddEntry");
161	if (!W_ERROR_IS_OK(status)) {
162		return status;
163	}
164
165	switch (r->in.level) {
166	case 2:
167		ret = ldb_transaction_start(b_state->sam_ctx);
168		if (ret != LDB_SUCCESS) {
169			return WERR_DS_DRA_INTERNAL_ERROR;
170		}
171
172
173		first_object = &r->in.req->req2.first_object;
174
175		status = dsdb_origin_objects_commit(b_state->sam_ctx,
176						    mem_ctx,
177						    first_object,
178						    &num,
179						    &ids);
180		if (!W_ERROR_IS_OK(status)) {
181			r->out.ctr->ctr3.error->info1.status = status;
182			ldb_transaction_cancel(b_state->sam_ctx);
183			return status;
184		}
185
186		r->out.ctr->ctr3.count = num;
187		r->out.ctr->ctr3.objects = ids;
188
189		break;
190	default:
191		return WERR_FOOBAR;
192	}
193
194	/* if any of the added entries are nTDSDSA objects then we
195	 * need to add the SPNs to the machine account
196	 */
197	status = drsuapi_add_SPNs(b_state, dce_call, mem_ctx, first_object);
198	if (!W_ERROR_IS_OK(status)) {
199		r->out.ctr->ctr3.error->info1.status = status;
200		ldb_transaction_cancel(b_state->sam_ctx);
201		return status;
202	}
203
204	ret = ldb_transaction_commit(b_state->sam_ctx);
205	if (ret != LDB_SUCCESS) {
206		return WERR_DS_DRA_INTERNAL_ERROR;
207	}
208
209	return WERR_OK;
210}
211