Line data Source code
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 "dsdb/samdb/samdb.h"
26 : #include "dsdb/common/util.h"
27 : #include "param/param.h"
28 : #include "libcli/security/security.h"
29 : #include "libcli/security/session.h"
30 : #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
31 : #include "librpc/gen_ndr/ndr_drsuapi.h"
32 :
33 : #undef DBGC_CLASS
34 : #define DBGC_CLASS DBGC_DRS_REPL
35 :
36 : /*
37 : add special SPNs needed for DRS replication to machine accounts when
38 : an AddEntry is done to create a nTDSDSA object
39 : */
40 94 : static WERROR drsuapi_add_SPNs(struct drsuapi_bind_state *b_state,
41 : struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
42 : const struct drsuapi_DsReplicaObjectListItem *first_object)
43 : {
44 0 : int ret;
45 0 : const struct drsuapi_DsReplicaObjectListItem *obj;
46 94 : const char *attrs[] = { "serverReference", "objectGUID", NULL };
47 :
48 188 : for (obj = first_object; obj; obj=obj->next_object) {
49 94 : const char *dn_string = obj->object.identifier->dn;
50 94 : struct ldb_dn *dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, dn_string);
51 0 : struct ldb_result *res, *res2;
52 0 : struct ldb_dn *ref_dn;
53 0 : struct GUID ntds_guid;
54 0 : struct ldb_message *msg;
55 0 : struct ldb_message_element *el;
56 0 : const char *ntds_guid_str;
57 0 : const char *dom_string;
58 94 : const char *attrs2[] = { "dNSHostName", "cn", NULL };
59 0 : const char *dNSHostName, *cn;
60 :
61 94 : DEBUG(6,(__location__ ": Adding SPNs for %s\n",
62 : ldb_dn_get_linearized(dn)));
63 :
64 94 : ret = ldb_search(b_state->sam_ctx, mem_ctx, &res,
65 : dn, LDB_SCOPE_BASE, attrs,
66 : "(objectClass=ntDSDSA)");
67 94 : if (ret != LDB_SUCCESS) {
68 0 : DEBUG(0,(__location__ ": Failed to find dn '%s'\n", dn_string));
69 0 : return WERR_DS_DRA_INTERNAL_ERROR;
70 : }
71 :
72 94 : if (res->count < 1) {
73 : /* we only add SPNs for nTDSDSA objects */
74 90 : continue;
75 : }
76 :
77 94 : ref_dn = samdb_result_dn(b_state->sam_ctx, mem_ctx, res->msgs[0], "serverReference", NULL);
78 94 : if (ref_dn == NULL) {
79 : /* we only add SPNs for objects with a
80 : serverReference */
81 90 : continue;
82 : }
83 :
84 4 : DEBUG(6,(__location__ ": serverReference %s\n",
85 : ldb_dn_get_linearized(ref_dn)));
86 :
87 4 : ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
88 :
89 4 : ntds_guid_str = GUID_string(res, &ntds_guid);
90 :
91 4 : dom_string = lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx);
92 :
93 : /* get the dNSHostName and cn */
94 4 : ret = ldb_search(b_state->sam_ctx, mem_ctx, &res2,
95 : ref_dn, LDB_SCOPE_BASE, attrs2, NULL);
96 4 : if (ret != LDB_SUCCESS) {
97 0 : DEBUG(0,(__location__ ": Failed to find ref_dn '%s'\n",
98 : ldb_dn_get_linearized(ref_dn)));
99 0 : return WERR_DS_DRA_INTERNAL_ERROR;
100 : }
101 :
102 4 : dNSHostName = ldb_msg_find_attr_as_string(res2->msgs[0], "dNSHostName", NULL);
103 4 : cn = ldb_msg_find_attr_as_string(res2->msgs[0], "cn", NULL);
104 :
105 : /*
106 : * construct a modify request to add the new SPNs to
107 : * the machine account
108 : */
109 4 : msg = ldb_msg_new(mem_ctx);
110 4 : if (msg == NULL) {
111 0 : return WERR_NOT_ENOUGH_MEMORY;
112 : }
113 :
114 4 : msg->dn = ref_dn;
115 4 : ret = ldb_msg_add_empty(msg, "servicePrincipalName",
116 : LDB_FLAG_MOD_ADD, &el);
117 4 : if (ret != LDB_SUCCESS) {
118 0 : return WERR_NOT_ENOUGH_MEMORY;
119 : }
120 :
121 :
122 4 : ldb_msg_add_steal_string(msg, "servicePrincipalName",
123 4 : talloc_asprintf(el->values,
124 : "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
125 : ntds_guid_str, dom_string));
126 4 : ldb_msg_add_steal_string(msg, "servicePrincipalName",
127 4 : talloc_asprintf(el->values, "ldap/%s._msdcs.%s",
128 : ntds_guid_str, dom_string));
129 4 : if (cn) {
130 4 : ldb_msg_add_steal_string(msg, "servicePrincipalName",
131 4 : talloc_asprintf(el->values, "ldap/%s", cn));
132 : }
133 4 : if (dNSHostName) {
134 4 : ldb_msg_add_steal_string(msg, "servicePrincipalName",
135 4 : talloc_asprintf(el->values, "ldap/%s", dNSHostName));
136 : }
137 4 : if (el->num_values < 2) {
138 0 : return WERR_NOT_ENOUGH_MEMORY;
139 : }
140 :
141 4 : ret = dsdb_modify(b_state->sam_ctx, msg, DSDB_MODIFY_PERMISSIVE);
142 4 : if (ret != LDB_SUCCESS) {
143 0 : DEBUG(0,(__location__ ": Failed to add SPNs - %s\n",
144 : ldb_errstring(b_state->sam_ctx)));
145 0 : return WERR_DS_DRA_INTERNAL_ERROR;
146 : }
147 : }
148 :
149 94 : return WERR_OK;
150 : }
151 :
152 :
153 :
154 :
155 : /*
156 : drsuapi_DsAddEntry
157 : */
158 94 : WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
159 : struct drsuapi_DsAddEntry *r)
160 : {
161 0 : WERROR status;
162 0 : struct drsuapi_bind_state *b_state;
163 0 : struct dcesrv_handle *h;
164 94 : uint32_t num = 0;
165 94 : struct drsuapi_DsReplicaObjectIdentifier2 *ids = NULL;
166 0 : int ret;
167 0 : const struct drsuapi_DsReplicaObjectListItem *first_object;
168 :
169 94 : if (DEBUGLVL(4)) {
170 0 : NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsAddEntry, NDR_IN, r);
171 : }
172 :
173 : /* TODO: check which out level the client supports */
174 :
175 94 : ZERO_STRUCTP(r->out.ctr);
176 94 : *r->out.level_out = 3;
177 94 : r->out.ctr->ctr3.err_ver = 1;
178 94 : r->out.ctr->ctr3.err_data = talloc_zero(mem_ctx, union drsuapi_DsAddEntry_ErrData);
179 :
180 94 : DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
181 94 : b_state = h->data;
182 :
183 94 : status = drs_security_level_check(dce_call, "DsAddEntry", SECURITY_DOMAIN_CONTROLLER, NULL);
184 94 : if (!W_ERROR_IS_OK(status)) {
185 0 : return status;
186 : }
187 :
188 94 : switch (r->in.level) {
189 94 : case 2:
190 94 : ret = ldb_transaction_start(b_state->sam_ctx);
191 94 : if (ret != LDB_SUCCESS) {
192 0 : DBG_ERR("DsAddEntry start transaction failed: %s\n",
193 : ldb_errstring(b_state->sam_ctx));
194 0 : return WERR_DS_DRA_INTERNAL_ERROR;
195 : }
196 :
197 :
198 94 : first_object = &r->in.req->req2.first_object;
199 :
200 94 : status = dsdb_origin_objects_commit(b_state->sam_ctx,
201 : mem_ctx,
202 : first_object,
203 : &num,
204 : DSDB_REPL_FLAG_ADD_NCNAME,
205 : &ids);
206 94 : if (!W_ERROR_IS_OK(status)) {
207 0 : r->out.ctr->ctr3.err_data->v1.status = status;
208 0 : ldb_transaction_cancel(b_state->sam_ctx);
209 0 : DEBUG(0,(__location__ ": DsAddEntry failed - %s\n", win_errstr(status)));
210 0 : return status;
211 : }
212 :
213 94 : r->out.ctr->ctr3.count = num;
214 94 : r->out.ctr->ctr3.objects = ids;
215 :
216 94 : break;
217 0 : default:
218 0 : return WERR_FOOBAR;
219 : }
220 :
221 : /* if any of the added entries are nTDSDSA objects then we
222 : * need to add the SPNs to the machine account
223 : */
224 94 : status = drsuapi_add_SPNs(b_state, dce_call, mem_ctx, first_object);
225 94 : if (!W_ERROR_IS_OK(status)) {
226 0 : r->out.ctr->ctr3.err_data->v1.status = status;
227 0 : ldb_transaction_cancel(b_state->sam_ctx);
228 0 : DEBUG(0,(__location__ ": DsAddEntry add SPNs failed - %s\n", win_errstr(status)));
229 0 : return status;
230 : }
231 :
232 94 : ret = ldb_transaction_commit(b_state->sam_ctx);
233 94 : if (ret != LDB_SUCCESS) {
234 0 : DEBUG(0,(__location__ ": DsAddEntry commit failed: %s\n",
235 : ldb_errstring(b_state->sam_ctx)));
236 0 : return WERR_DS_DRA_INTERNAL_ERROR;
237 : }
238 :
239 94 : return WERR_OK;
240 : }
|