~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/repl/replicated_objects.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS mplementation.
 
3
   Helper functions for applying replicated objects
 
4
   
 
5
   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
 
6
    
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
   
 
20
*/
 
21
 
 
22
#include "includes.h"
 
23
#include "dsdb/samdb/samdb.h"
 
24
#include "lib/ldb/include/ldb_errors.h"
 
25
#include "../lib/util/dlinklist.h"
 
26
#include "librpc/gen_ndr/ndr_misc.h"
 
27
#include "librpc/gen_ndr/ndr_drsuapi.h"
 
28
#include "librpc/gen_ndr/ndr_drsblobs.h"
 
29
#include "../lib/crypto/crypto.h"
 
30
#include "libcli/auth/libcli_auth.h"
 
31
#include "param/param.h"
 
32
 
 
33
static WERROR dsdb_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
 
34
                                           const DATA_BLOB *gensec_skey,
 
35
                                           bool rid_crypt,
 
36
                                           uint32_t rid,
 
37
                                           DATA_BLOB *in,
 
38
                                           DATA_BLOB *out)
 
39
{
 
40
        DATA_BLOB confounder;
 
41
        DATA_BLOB enc_buffer;
 
42
 
 
43
        struct MD5Context md5;
 
44
        uint8_t _enc_key[16];
 
45
        DATA_BLOB enc_key;
 
46
 
 
47
        DATA_BLOB dec_buffer;
 
48
 
 
49
        uint32_t crc32_given;
 
50
        uint32_t crc32_calc;
 
51
        DATA_BLOB checked_buffer;
 
52
 
 
53
        DATA_BLOB plain_buffer;
 
54
 
 
55
        /*
 
56
         * users with rid == 0 should not exist
 
57
         */
 
58
        if (rid_crypt && rid == 0) {
 
59
                return WERR_DS_DRA_INVALID_PARAMETER;
 
60
        }
 
61
 
 
62
        /* 
 
63
         * the first 16 bytes at the beginning are the confounder
 
64
         * followed by the 4 byte crc32 checksum
 
65
         */
 
66
        if (in->length < 20) {
 
67
                return WERR_DS_DRA_INVALID_PARAMETER;
 
68
        }
 
69
        confounder = data_blob_const(in->data, 16);
 
70
        enc_buffer = data_blob_const(in->data + 16, in->length - 16);
 
71
 
 
72
        /* 
 
73
         * build the encryption key md5 over the session key followed
 
74
         * by the confounder
 
75
         * 
 
76
         * here the gensec session key is used and
 
77
         * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
 
78
         */
 
79
        enc_key = data_blob_const(_enc_key, sizeof(_enc_key));
 
80
        MD5Init(&md5);
 
81
        MD5Update(&md5, gensec_skey->data, gensec_skey->length);
 
82
        MD5Update(&md5, confounder.data, confounder.length);
 
83
        MD5Final(enc_key.data, &md5);
 
84
 
 
85
        /*
 
86
         * copy the encrypted buffer part and 
 
87
         * decrypt it using the created encryption key using arcfour
 
88
         */
 
89
        dec_buffer = data_blob_const(enc_buffer.data, enc_buffer.length);
 
90
        arcfour_crypt_blob(dec_buffer.data, dec_buffer.length, &enc_key);
 
91
 
 
92
        /* 
 
93
         * the first 4 byte are the crc32 checksum
 
94
         * of the remaining bytes
 
95
         */
 
96
        crc32_given = IVAL(dec_buffer.data, 0);
 
97
        crc32_calc = crc32_calc_buffer(dec_buffer.data + 4 , dec_buffer.length - 4);
 
98
        if (crc32_given != crc32_calc) {
 
99
                return WERR_SEC_E_DECRYPT_FAILURE;
 
100
        }
 
101
        checked_buffer = data_blob_const(dec_buffer.data + 4, dec_buffer.length - 4);
 
102
 
 
103
        plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
 
104
        W_ERROR_HAVE_NO_MEMORY(plain_buffer.data);
 
105
 
 
106
        /*
 
107
         * The following rid_crypt obfuscation isn't session specific
 
108
         * and not really needed here, because we allways know the rid of the
 
109
         * user account.
 
110
         *
 
111
         * But for the rest of samba it's easier when we remove this static
 
112
         * obfuscation here
 
113
         */
 
114
        if (rid_crypt) {
 
115
                uint32_t i, num_hashes;
 
116
 
 
117
                if ((checked_buffer.length % 16) != 0) {
 
118
                        return WERR_DS_DRA_INVALID_PARAMETER;
 
119
                }
 
120
 
 
121
                num_hashes = plain_buffer.length / 16;
 
122
                for (i = 0; i < num_hashes; i++) {
 
123
                        uint32_t offset = i * 16;
 
124
                        sam_rid_crypt(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0);
 
125
                }
 
126
        }
 
127
 
 
128
        *out = plain_buffer;
 
129
        return WERR_OK;
 
130
}
 
131
 
 
132
static WERROR dsdb_decrypt_attribute(const DATA_BLOB *gensec_skey,
 
133
                                     uint32_t rid,
 
134
                                     struct drsuapi_DsReplicaAttribute *attr)
 
135
{
 
136
        WERROR status;
 
137
        TALLOC_CTX *mem_ctx;
 
138
        DATA_BLOB *enc_data;
 
139
        DATA_BLOB plain_data;
 
140
        bool rid_crypt = false;
 
141
 
 
142
        if (attr->value_ctr.num_values == 0) {
 
143
                return WERR_OK;
 
144
        }
 
145
 
 
146
        switch (attr->attid) {
 
147
        case DRSUAPI_ATTRIBUTE_dBCSPwd:
 
148
        case DRSUAPI_ATTRIBUTE_unicodePwd:
 
149
        case DRSUAPI_ATTRIBUTE_ntPwdHistory:
 
150
        case DRSUAPI_ATTRIBUTE_lmPwdHistory:
 
151
                rid_crypt = true;
 
152
                break;
 
153
        case DRSUAPI_ATTRIBUTE_supplementalCredentials:
 
154
        case DRSUAPI_ATTRIBUTE_priorValue:
 
155
        case DRSUAPI_ATTRIBUTE_currentValue:
 
156
        case DRSUAPI_ATTRIBUTE_trustAuthOutgoing:
 
157
        case DRSUAPI_ATTRIBUTE_trustAuthIncoming:
 
158
        case DRSUAPI_ATTRIBUTE_initialAuthOutgoing:
 
159
        case DRSUAPI_ATTRIBUTE_initialAuthIncoming:
 
160
                break;
 
161
        default:
 
162
                return WERR_OK;
 
163
        }
 
164
 
 
165
        if (attr->value_ctr.num_values > 1) {
 
166
                return WERR_DS_DRA_INVALID_PARAMETER;
 
167
        }
 
168
 
 
169
        if (!attr->value_ctr.values[0].blob) {
 
170
                return WERR_DS_DRA_INVALID_PARAMETER;
 
171
        }
 
172
 
 
173
        mem_ctx         = attr->value_ctr.values[0].blob;
 
174
        enc_data        = attr->value_ctr.values[0].blob;
 
175
 
 
176
        status = dsdb_decrypt_attribute_value(mem_ctx,
 
177
                                              gensec_skey,
 
178
                                              rid_crypt,
 
179
                                              rid,
 
180
                                              enc_data,
 
181
                                              &plain_data);
 
182
        W_ERROR_NOT_OK_RETURN(status);
 
183
 
 
184
        talloc_free(attr->value_ctr.values[0].blob->data);
 
185
        *attr->value_ctr.values[0].blob = plain_data;
 
186
 
 
187
        return WERR_OK;
 
188
}
 
189
 
 
190
static WERROR dsdb_convert_object(struct ldb_context *ldb,
 
191
                                  const struct dsdb_schema *schema,
 
192
                                  struct dsdb_extended_replicated_objects *ctr,
 
193
                                  const struct drsuapi_DsReplicaObjectListItemEx *in,
 
194
                                  const DATA_BLOB *gensec_skey,
 
195
                                  TALLOC_CTX *mem_ctx,
 
196
                                  struct dsdb_extended_replicated_object *out)
 
197
{
 
198
        NTSTATUS nt_status;
 
199
        enum ndr_err_code ndr_err;
 
200
        WERROR status;
 
201
        uint32_t i;
 
202
        struct ldb_message *msg;
 
203
        struct replPropertyMetaDataBlob *md;
 
204
        struct ldb_val guid_value;
 
205
        NTTIME whenChanged = 0;
 
206
        time_t whenChanged_t;
 
207
        const char *whenChanged_s;
 
208
        const char *rdn_name = NULL;
 
209
        const struct ldb_val *rdn_value = NULL;
 
210
        const struct dsdb_attribute *rdn_attr = NULL;
 
211
        uint32_t rdn_attid;
 
212
        struct drsuapi_DsReplicaAttribute *name_a = NULL;
 
213
        struct drsuapi_DsReplicaMetaData *name_d = NULL;
 
214
        struct replPropertyMetaData1 *rdn_m = NULL;
 
215
        struct dom_sid *sid = NULL;
 
216
        uint32_t rid = 0;
 
217
        int ret;
 
218
 
 
219
        if (!in->object.identifier) {
 
220
                return WERR_FOOBAR;
 
221
        }
 
222
 
 
223
        if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
 
224
                return WERR_FOOBAR;
 
225
        }
 
226
 
 
227
        if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
 
228
                return WERR_FOOBAR;
 
229
        }
 
230
 
 
231
        if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
 
232
                return WERR_FOOBAR;
 
233
        }
 
234
 
 
235
        sid = &in->object.identifier->sid;
 
236
        if (sid->num_auths > 0) {
 
237
                rid = sid->sub_auths[sid->num_auths - 1];
 
238
        }
 
239
 
 
240
        msg = ldb_msg_new(mem_ctx);
 
241
        W_ERROR_HAVE_NO_MEMORY(msg);
 
242
 
 
243
        msg->dn                 = ldb_dn_new(msg, ldb, in->object.identifier->dn);
 
244
        W_ERROR_HAVE_NO_MEMORY(msg->dn);
 
245
 
 
246
        rdn_name        = ldb_dn_get_rdn_name(msg->dn);
 
247
        rdn_attr        = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
 
248
        if (!rdn_attr) {
 
249
                return WERR_FOOBAR;
 
250
        }
 
251
        rdn_attid       = rdn_attr->attributeID_id;
 
252
        rdn_value       = ldb_dn_get_rdn_val(msg->dn);
 
253
 
 
254
        msg->num_elements       = in->object.attribute_ctr.num_attributes;
 
255
        msg->elements           = talloc_array(msg, struct ldb_message_element,
 
256
                                               msg->num_elements);
 
257
        W_ERROR_HAVE_NO_MEMORY(msg->elements);
 
258
 
 
259
        md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
 
260
        W_ERROR_HAVE_NO_MEMORY(md);
 
261
 
 
262
        md->version             = 1;
 
263
        md->reserved            = 0;
 
264
        md->ctr.ctr1.count      = in->meta_data_ctr->count;
 
265
        md->ctr.ctr1.reserved   = 0;
 
266
        md->ctr.ctr1.array      = talloc_array(mem_ctx,
 
267
                                               struct replPropertyMetaData1,
 
268
                                               md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */
 
269
        W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
 
270
 
 
271
        for (i=0; i < in->meta_data_ctr->count; i++) {
 
272
                struct drsuapi_DsReplicaAttribute *a;
 
273
                struct drsuapi_DsReplicaMetaData *d;
 
274
                struct replPropertyMetaData1 *m;
 
275
                struct ldb_message_element *e;
 
276
 
 
277
                a = &in->object.attribute_ctr.attributes[i];
 
278
                d = &in->meta_data_ctr->meta_data[i];
 
279
                m = &md->ctr.ctr1.array[i];
 
280
                e = &msg->elements[i];
 
281
 
 
282
                status = dsdb_decrypt_attribute(gensec_skey, rid, a);
 
283
                W_ERROR_NOT_OK_RETURN(status);
 
284
 
 
285
                status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
 
286
                W_ERROR_NOT_OK_RETURN(status);
 
287
 
 
288
                m->attid                        = a->attid;
 
289
                m->version                      = d->version;
 
290
                m->originating_change_time      = d->originating_change_time;
 
291
                m->originating_invocation_id    = d->originating_invocation_id;
 
292
                m->originating_usn              = d->originating_usn;
 
293
                m->local_usn                    = 0;
 
294
 
 
295
                if (d->originating_change_time > whenChanged) {
 
296
                        whenChanged = d->originating_change_time;
 
297
                }
 
298
 
 
299
                if (a->attid == DRSUAPI_ATTRIBUTE_name) {
 
300
                        name_a = a;
 
301
                        name_d = d;
 
302
                        rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
 
303
                }
 
304
        }
 
305
 
 
306
        if (rdn_m) {
 
307
                ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
 
308
                if (ret != LDB_SUCCESS) {
 
309
                        return WERR_FOOBAR;
 
310
                }
 
311
 
 
312
                rdn_m->attid                            = rdn_attid;
 
313
                rdn_m->version                          = name_d->version;
 
314
                rdn_m->originating_change_time          = name_d->originating_change_time;
 
315
                rdn_m->originating_invocation_id        = name_d->originating_invocation_id;
 
316
                rdn_m->originating_usn                  = name_d->originating_usn;
 
317
                rdn_m->local_usn                        = 0;
 
318
                md->ctr.ctr1.count++;
 
319
 
 
320
        }
 
321
 
 
322
        whenChanged_t = nt_time_to_unix(whenChanged);
 
323
        whenChanged_s = ldb_timestring(msg, whenChanged_t);
 
324
        W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
 
325
 
 
326
        ndr_err = ndr_push_struct_blob(&guid_value, msg, 
 
327
                                       lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
 
328
                                       &in->object.identifier->guid,
 
329
                                         (ndr_push_flags_fn_t)ndr_push_GUID);
 
330
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
331
                nt_status = ndr_map_error2ntstatus(ndr_err);
 
332
                return ntstatus_to_werror(nt_status);
 
333
        }
 
334
 
 
335
        out->msg                = msg;
 
336
        out->guid_value         = guid_value;
 
337
        out->when_changed       = whenChanged_s;
 
338
        out->meta_data          = md;
 
339
        return WERR_OK;
 
340
}
 
341
 
 
342
WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
 
343
                                               const char *partition_dn,
 
344
                                               const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
 
345
                                               uint32_t object_count,
 
346
                                               const struct drsuapi_DsReplicaObjectListItemEx *first_object,
 
347
                                               uint32_t linked_attributes_count,
 
348
                                               const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
 
349
                                               const struct repsFromTo1 *source_dsa,
 
350
                                               const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
 
351
                                               const DATA_BLOB *gensec_skey,
 
352
                                               TALLOC_CTX *mem_ctx,
 
353
                                               struct dsdb_extended_replicated_objects **_out)
 
354
{
 
355
        WERROR status;
 
356
        const struct dsdb_schema *schema;
 
357
        struct dsdb_extended_replicated_objects *out;
 
358
        struct ldb_result *ext_res;
 
359
        const struct drsuapi_DsReplicaObjectListItemEx *cur;
 
360
        uint32_t i;
 
361
        int ret;
 
362
 
 
363
        schema = dsdb_get_schema(ldb);
 
364
        if (!schema) {
 
365
                return WERR_DS_SCHEMA_NOT_LOADED;
 
366
        }
 
367
 
 
368
        status = dsdb_verify_oid_mappings_drsuapi(schema, mapping_ctr);
 
369
        W_ERROR_NOT_OK_RETURN(status);
 
370
 
 
371
        out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
 
372
        W_ERROR_HAVE_NO_MEMORY(out);
 
373
        out->version            = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
 
374
 
 
375
        out->partition_dn       = ldb_dn_new(out, ldb, partition_dn);
 
376
        W_ERROR_HAVE_NO_MEMORY(out->partition_dn);
 
377
 
 
378
        out->source_dsa         = source_dsa;
 
379
        out->uptodateness_vector= uptodateness_vector;
 
380
 
 
381
        out->num_objects        = object_count;
 
382
        out->objects            = talloc_array(out,
 
383
                                               struct dsdb_extended_replicated_object,
 
384
                                               out->num_objects);
 
385
        W_ERROR_HAVE_NO_MEMORY(out->objects);
 
386
 
 
387
        for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
 
388
                if (i == out->num_objects) {
 
389
                        return WERR_FOOBAR;
 
390
                }
 
391
 
 
392
                status = dsdb_convert_object(ldb, schema, out, cur, gensec_skey, out->objects, &out->objects[i]);
 
393
                W_ERROR_NOT_OK_RETURN(status);
 
394
        }
 
395
        if (i != out->num_objects) {
 
396
                return WERR_FOOBAR;
 
397
        }
 
398
 
 
399
        /* TODO: handle linked attributes */
 
400
 
 
401
        ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, out, &ext_res);
 
402
        if (ret != LDB_SUCCESS) {
 
403
                DEBUG(0,("Failed to apply records: %s: %s\n",
 
404
                         ldb_errstring(ldb), ldb_strerror(ret)));
 
405
                talloc_free(out);
 
406
                return WERR_FOOBAR;
 
407
        }
 
408
        talloc_free(ext_res);
 
409
 
 
410
        if (_out) {
 
411
                *_out = out;
 
412
        } else {
 
413
                talloc_free(out);
 
414
        }
 
415
 
 
416
        return WERR_OK;
 
417
}