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 19 : WERROR dsdb_schema_info_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info) 39 : { 40 1 : struct dsdb_schema_info *schema_info; 41 : 42 19 : schema_info = talloc_zero(mem_ctx, struct dsdb_schema_info); 43 19 : W_ERROR_HAVE_NO_MEMORY(schema_info); 44 : 45 19 : *_schema_info = schema_info; 46 : 47 19 : 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 11147 : WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob) 57 : { 58 341 : DATA_BLOB blob; 59 : 60 11147 : blob = data_blob_talloc_zero(mem_ctx, 21); 61 11147 : W_ERROR_HAVE_NO_MEMORY(blob.data); 62 : 63 : /* Set the schemaInfo marker to 0xFF */ 64 11147 : blob.data[0] = 0xFF; 65 : 66 11147 : *_schema_info_blob = blob; 67 : 68 11147 : return WERR_OK; 69 : } 70 : 71 : 72 : /** 73 : * Verify the 'blob' is a valid schemaInfo blob 74 : */ 75 71306 : bool dsdb_schema_info_blob_is_valid(const DATA_BLOB *blob) 76 : { 77 71306 : if (!blob || !blob->data) { 78 0 : return false; 79 : } 80 : 81 : /* schemaInfo blob must be 21 bytes long */ 82 71305 : if (blob->length != 21) { 83 0 : return false; 84 : } 85 : 86 : /* schemaInfo blob should start with 0xFF */ 87 71303 : if (blob->data[0] != 0xFF) { 88 2 : return false; 89 : } 90 : 91 70593 : 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 come from 98 : * DRS interface or from LDB database 99 : */ 100 33567 : WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob, 101 : TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info) 102 : { 103 360 : TALLOC_CTX *temp_ctx; 104 360 : enum ndr_err_code ndr_err; 105 360 : struct dsdb_schema_info *schema_info; 106 360 : struct schemaInfoBlob schema_info_blob; 107 : 108 : /* verify schemaInfo blob is valid */ 109 33567 : if (!dsdb_schema_info_blob_is_valid(blob)) { 110 2 : return WERR_INVALID_PARAMETER; 111 : } 112 : 113 33565 : temp_ctx = talloc_new(mem_ctx); 114 33565 : W_ERROR_HAVE_NO_MEMORY(temp_ctx); 115 : 116 33565 : ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx, 117 : &schema_info_blob, 118 : (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob); 119 33565 : 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 33565 : schema_info = talloc(mem_ctx, struct dsdb_schema_info); 126 33565 : 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 33565 : schema_info->revision = schema_info_blob.revision; 134 33565 : schema_info->invocation_id = schema_info_blob.invocation_id; 135 33565 : *_schema_info = schema_info; 136 : 137 33565 : talloc_free(temp_ctx); 138 33565 : 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 12137 : WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info, 147 : TALLOC_CTX *mem_ctx, DATA_BLOB *blob) 148 : { 149 13 : enum ndr_err_code ndr_err; 150 13 : struct schemaInfoBlob schema_info_blob; 151 : 152 12137 : schema_info_blob.marker = 0xFF; 153 12137 : schema_info_blob.revision = schema_info->revision; 154 12137 : schema_info_blob.invocation_id = schema_info->invocation_id; 155 : 156 12137 : ndr_err = ndr_push_struct_blob(blob, mem_ctx, 157 : &schema_info_blob, 158 : (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob); 159 12137 : 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 12137 : 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 schemaVersion field 171 : * 172 : * @return WERR_OK if schemaInfos are equal 173 : * WERR_DS_DRA_SCHEMA_MISMATCH if schemaInfos are different 174 : */ 175 3574 : WERROR dsdb_schema_info_cmp(const struct dsdb_schema *schema, 176 : const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr) 177 : { 178 3574 : TALLOC_CTX *frame = NULL; 179 3574 : DATA_BLOB blob = data_blob_null; 180 3574 : struct dsdb_schema_info *schema_info = NULL; 181 3574 : const struct drsuapi_DsReplicaOIDMapping *mapping = NULL; 182 12 : WERROR werr; 183 : 184 : /* we should have at least schemaInfo element */ 185 3574 : if (ctr->num_mappings < 1) { 186 1 : return WERR_INVALID_PARAMETER; 187 : } 188 : 189 : /* verify schemaInfo element is valid */ 190 3573 : mapping = &ctr->mappings[ctr->num_mappings - 1]; 191 3573 : if (mapping->id_prefix != 0) { 192 1 : return WERR_INVALID_PARAMETER; 193 : } 194 : 195 3572 : blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length); 196 3572 : if (!dsdb_schema_info_blob_is_valid(&blob)) { 197 3 : return WERR_INVALID_PARAMETER; 198 : } 199 : 200 3569 : frame = talloc_stackframe(); 201 3569 : werr = dsdb_schema_info_from_blob(&blob, frame, &schema_info); 202 3569 : 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 3569 : if (schema_info == NULL) { 212 0 : TALLOC_FREE(frame); 213 0 : return WERR_INVALID_PARAMETER; 214 : } 215 : 216 3569 : 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 3566 : } else if (schema->schema_info->revision < schema_info->revision) { 222 10 : werr = WERR_DS_DRA_SCHEMA_MISMATCH; 223 3554 : } else if (!GUID_equal(&schema->schema_info->invocation_id, 224 3554 : &schema_info->invocation_id)) 225 : { 226 0 : werr = WERR_DS_DRA_SCHEMA_CONFLICT; 227 : } else { 228 3553 : werr = WERR_OK; 229 : } 230 : 231 3569 : TALLOC_FREE(frame); 232 3569 : return werr; 233 : } 234 : 235 :