Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SCHEMA::schemaInfo implementation
5 :
6 : Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "dsdb/common/util.h"
24 : #include "dsdb/samdb/samdb.h"
25 : #include "dsdb/samdb/ldb_modules/util.h"
26 : #include <ldb_module.h>
27 : #include "librpc/gen_ndr/ndr_drsuapi.h"
28 : #include "librpc/gen_ndr/ndr_drsblobs.h"
29 : #include "param/param.h"
30 :
31 :
32 : /**
33 : * Creates and initializes new dsdb_schema_info value.
34 : * Initial schemaInfo values is with:
35 : * revision = 0
36 : * invocationId = GUID_ZERO
37 : */
38 16 : WERROR dsdb_schema_info_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
39 : {
40 : struct dsdb_schema_info *schema_info;
41 :
42 16 : schema_info = talloc_zero(mem_ctx, struct dsdb_schema_info);
43 16 : W_ERROR_HAVE_NO_MEMORY(schema_info);
44 :
45 16 : *_schema_info = schema_info;
46 :
47 16 : return WERR_OK;
48 : }
49 :
50 : /**
51 : * Creates and initializes new dsdb_schema_info blob value.
52 : * Initial schemaInfo values is with:
53 : * revision = 0
54 : * invocationId = GUID_ZERO
55 : */
56 6450 : WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob)
57 : {
58 : DATA_BLOB blob;
59 :
60 6450 : blob = data_blob_talloc_zero(mem_ctx, 21);
61 6450 : W_ERROR_HAVE_NO_MEMORY(blob.data);
62 :
63 : /* Set the schemaInfo marker to 0xFF */
64 6450 : blob.data[0] = 0xFF;
65 :
66 6450 : *_schema_info_blob = blob;
67 :
68 6450 : return WERR_OK;
69 : }
70 :
71 :
72 : /**
73 : * Verify the 'blob' is a valid schemaInfo blob
74 : */
75 53504 : bool dsdb_schema_info_blob_is_valid(const DATA_BLOB *blob)
76 : {
77 53504 : if (!blob || !blob->data) {
78 0 : return false;
79 : }
80 :
81 : /* schemaInfo blob must be 21 bytes long */
82 53504 : if (blob->length != 21) {
83 0 : return false;
84 : }
85 :
86 : /* schemaInfo blob should start with 0xFF */
87 53504 : if (blob->data[0] != 0xFF) {
88 0 : return false;
89 : }
90 :
91 53504 : return true;
92 : }
93 :
94 : /**
95 : * Parse schemaInfo structure from a data_blob
96 : * (DATA_BLOB or ldb_val).
97 : * Suitable for parsing blobs that comes from
98 : * DRS interface of from LDB database
99 : */
100 24547 : WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
101 : TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
102 : {
103 : TALLOC_CTX *temp_ctx;
104 : enum ndr_err_code ndr_err;
105 : struct dsdb_schema_info *schema_info;
106 : struct schemaInfoBlob schema_info_blob;
107 :
108 : /* verify schemaInfo blob is valid */
109 24547 : if (!dsdb_schema_info_blob_is_valid(blob)) {
110 0 : return WERR_INVALID_PARAMETER;
111 : }
112 :
113 24547 : temp_ctx = talloc_new(mem_ctx);
114 24547 : W_ERROR_HAVE_NO_MEMORY(temp_ctx);
115 :
116 24547 : ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
117 : &schema_info_blob,
118 : (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
119 24547 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
120 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
121 0 : talloc_free(temp_ctx);
122 0 : return ntstatus_to_werror(nt_status);
123 : }
124 :
125 24547 : schema_info = talloc(mem_ctx, struct dsdb_schema_info);
126 24547 : if (!schema_info) {
127 0 : talloc_free(temp_ctx);
128 0 : return WERR_NOT_ENOUGH_MEMORY;
129 : }
130 :
131 : /* note that we accept revision numbers of zero now - w2k8r2
132 : sends a revision of zero on initial vampire */
133 24547 : schema_info->revision = schema_info_blob.revision;
134 24547 : schema_info->invocation_id = schema_info_blob.invocation_id;
135 24547 : *_schema_info = schema_info;
136 :
137 24547 : talloc_free(temp_ctx);
138 24547 : return WERR_OK;
139 : }
140 :
141 : /**
142 : * Creates a blob from schemaInfo structure
143 : * Suitable for packing schemaInfo into a blob
144 : * which is to be used in DRS interface of LDB database
145 : */
146 8992 : WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
147 : TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
148 : {
149 : enum ndr_err_code ndr_err;
150 : struct schemaInfoBlob schema_info_blob;
151 :
152 8992 : schema_info_blob.marker = 0xFF;
153 8992 : schema_info_blob.revision = schema_info->revision;
154 8992 : schema_info_blob.invocation_id = schema_info->invocation_id;
155 :
156 8992 : ndr_err = ndr_push_struct_blob(blob, mem_ctx,
157 : &schema_info_blob,
158 : (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
159 8992 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
161 0 : return ntstatus_to_werror(nt_status);
162 : }
163 :
164 8992 : return WERR_OK;
165 : }
166 :
167 : /**
168 : * Compares schemaInfo signatures in dsdb_schema and prefixMap.
169 : * NOTE: At present function compares schemaInfo values
170 : * as string without taking into account schemVersion field
171 : *
172 : * @return WERR_OK if schemaInfos are equal
173 : * WERR_DS_DRA_SCHEMA_MISMATCH if schemaInfos are different
174 : */
175 3396 : WERROR dsdb_schema_info_cmp(const struct dsdb_schema *schema,
176 : const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
177 : {
178 3396 : TALLOC_CTX *frame = NULL;
179 3396 : DATA_BLOB blob = data_blob_null;
180 3396 : struct dsdb_schema_info *schema_info = NULL;
181 3396 : const struct drsuapi_DsReplicaOIDMapping *mapping = NULL;
182 : WERROR werr;
183 :
184 : /* we should have at least schemaInfo element */
185 3396 : if (ctr->num_mappings < 1) {
186 0 : return WERR_INVALID_PARAMETER;
187 : }
188 :
189 : /* verify schemaInfo element is valid */
190 3396 : mapping = &ctr->mappings[ctr->num_mappings - 1];
191 3396 : if (mapping->id_prefix != 0) {
192 0 : return WERR_INVALID_PARAMETER;
193 : }
194 :
195 3396 : blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
196 3396 : if (!dsdb_schema_info_blob_is_valid(&blob)) {
197 0 : return WERR_INVALID_PARAMETER;
198 : }
199 :
200 3396 : frame = talloc_stackframe();
201 3396 : werr = dsdb_schema_info_from_blob(&blob, frame, &schema_info);
202 3396 : if (!W_ERROR_IS_OK(werr)) {
203 0 : TALLOC_FREE(frame);
204 0 : return werr;
205 : }
206 :
207 : /*
208 : * shouldn't really be possible is dsdb_schema_info_from_blob
209 : * succeeded, this check is just to satisfy static checker
210 : */
211 3396 : if (schema_info == NULL) {
212 0 : TALLOC_FREE(frame);
213 0 : return WERR_INVALID_PARAMETER;
214 : }
215 :
216 3396 : if (schema->schema_info->revision > schema_info->revision) {
217 : /*
218 : * It's ok if our schema is newer than the remote one
219 : */
220 0 : werr = WERR_OK;
221 3396 : } else if (schema->schema_info->revision < schema_info->revision) {
222 17 : werr = WERR_DS_DRA_SCHEMA_MISMATCH;
223 3379 : } else if (!GUID_equal(&schema->schema_info->invocation_id,
224 3379 : &schema_info->invocation_id))
225 : {
226 0 : werr = WERR_DS_DRA_SCHEMA_CONFLICT;
227 : } else {
228 3379 : werr = WERR_OK;
229 : }
230 :
231 3396 : TALLOC_FREE(frame);
232 3396 : return werr;
233 : }
234 :
235 :
|