~ubuntu-branches/ubuntu/vivid/samba/vivid

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
#include "auth/auth.h"
25
25
#include "smbd/service.h"
26
26
#include "lib/events/events.h"
27
 
#include "lib/messaging/irpc.h"
28
27
#include "dsdb/repl/drepl_service.h"
29
 
#include "lib/ldb/include/ldb_errors.h"
 
28
#include <ldb_errors.h>
30
29
#include "../lib/util/dlinklist.h"
31
30
#include "librpc/gen_ndr/ndr_misc.h"
32
31
#include "librpc/gen_ndr/ndr_drsuapi.h"
33
32
#include "librpc/gen_ndr/ndr_drsblobs.h"
 
33
#include "libcli/security/security.h"
34
34
#include "param/param.h"
35
35
 
36
36
WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
37
37
{
38
38
        WERROR status;
39
 
        struct ldb_dn *basedn;
40
 
        struct ldb_result *r;
 
39
        static const char *attrs[] = { "namingContexts", NULL };
 
40
        unsigned int i;
 
41
        int ret;
 
42
        TALLOC_CTX *tmp_ctx;
 
43
        struct ldb_result *res;
41
44
        struct ldb_message_element *el;
42
 
        static const char *attrs[] = { "namingContexts", NULL };
43
 
        uint32_t i;
44
 
        int ret;
45
 
 
46
 
        basedn = ldb_dn_new(s, s->samdb, NULL);
47
 
        W_ERROR_HAVE_NO_MEMORY(basedn);
48
 
 
49
 
        ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
50
 
                         "(objectClass=*)");
51
 
        talloc_free(basedn);
 
45
 
 
46
        tmp_ctx = talloc_new(s);
 
47
        W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
 
48
 
 
49
        ret = ldb_search(s->samdb, tmp_ctx, &res,
 
50
                         ldb_dn_new(tmp_ctx, s->samdb, ""), LDB_SCOPE_BASE, attrs, NULL);
52
51
        if (ret != LDB_SUCCESS) {
53
 
                return WERR_FOOBAR;
54
 
        } else if (r->count != 1) {
55
 
                talloc_free(r);
56
 
                return WERR_FOOBAR;
57
 
        }
58
 
 
59
 
        el = ldb_msg_find_element(r->msgs[0], "namingContexts");
60
 
        if (!el) {
61
 
                return WERR_FOOBAR;
62
 
        }
63
 
 
64
 
        for (i=0; el && i < el->num_values; i++) {
65
 
                const char *v = (const char *)el->values[i].data;
66
 
                struct ldb_dn *pdn;
67
 
                struct dreplsrv_partition *p;
68
 
 
69
 
                pdn = ldb_dn_new(s, s->samdb, v);
70
 
                if (!ldb_dn_validate(pdn)) {
71
 
                        return WERR_FOOBAR;
72
 
                }
73
 
 
74
 
                p = talloc_zero(s, struct dreplsrv_partition);
75
 
                W_ERROR_HAVE_NO_MEMORY(p);
76
 
 
77
 
                p->dn = talloc_steal(p, pdn);
78
 
 
79
 
                DLIST_ADD(s->partitions, p);
80
 
 
81
 
                DEBUG(2, ("dreplsrv_partition[%s] loaded\n", v));
82
 
        }
83
 
 
84
 
        talloc_free(r);
 
52
                DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(s->samdb)));
 
53
                talloc_free(tmp_ctx);
 
54
                return WERR_DS_DRA_INTERNAL_ERROR;
 
55
       }
 
56
 
 
57
       el = ldb_msg_find_element(res->msgs[0], "namingContexts");
 
58
       if (!el) {
 
59
               DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
 
60
                        ldb_errstring(s->samdb)));
 
61
               talloc_free(tmp_ctx);
 
62
               return WERR_DS_DRA_INTERNAL_ERROR;
 
63
       }
 
64
 
 
65
       for (i=0; i<el->num_values; i++) {
 
66
               struct ldb_dn *pdn;
 
67
               struct dreplsrv_partition *p;
 
68
 
 
69
               pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
 
70
               if (pdn == NULL) {
 
71
                       talloc_free(tmp_ctx);
 
72
                       return WERR_DS_DRA_INTERNAL_ERROR;
 
73
               }
 
74
               if (!ldb_dn_validate(pdn)) {
 
75
                       return WERR_DS_DRA_INTERNAL_ERROR;
 
76
               }
 
77
 
 
78
               p = talloc_zero(s, struct dreplsrv_partition);
 
79
               W_ERROR_HAVE_NO_MEMORY(p);
 
80
 
 
81
               p->dn = talloc_steal(p, pdn);
 
82
 
 
83
               DLIST_ADD(s->partitions, p);
 
84
 
 
85
               DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn)));
 
86
        }
 
87
 
 
88
        talloc_free(tmp_ctx);
85
89
 
86
90
        status = dreplsrv_refresh_partitions(s);
87
91
        W_ERROR_NOT_OK_RETURN(status);
89
93
        return WERR_OK;
90
94
}
91
95
 
92
 
static WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
93
 
                                             const struct repsFromTo1 *rft,
94
 
                                             struct dreplsrv_out_connection **_conn)
 
96
/*
 
97
  work out the principal to use for DRS replication connections
 
98
 */
 
99
NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
 
100
                                       TALLOC_CTX *mem_ctx,
 
101
                                       const struct repsFromTo1 *rft,
 
102
                                       const char **target_principal)
 
103
{
 
104
        TALLOC_CTX *tmp_ctx;
 
105
        struct ldb_result *res;
 
106
        const char *attrs[] = { "dNSHostName", NULL };
 
107
        int ret;
 
108
        const char *hostname;
 
109
        struct ldb_dn *dn;
 
110
 
 
111
        *target_principal = NULL;
 
112
 
 
113
        tmp_ctx = talloc_new(mem_ctx);
 
114
 
 
115
        /* we need to find their hostname */
 
116
        ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &dn);
 
117
        if (ret != LDB_SUCCESS) {
 
118
                talloc_free(tmp_ctx);
 
119
                /* its OK for their NTDSDSA DN not to be in our database */
 
120
                return NT_STATUS_OK;
 
121
        }
 
122
 
 
123
        /* strip off the NTDS Settings */
 
124
        if (!ldb_dn_remove_child_components(dn, 1)) {
 
125
                talloc_free(tmp_ctx);
 
126
                return NT_STATUS_OK;
 
127
        }
 
128
 
 
129
        ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, dn, attrs, 0);
 
130
        if (ret != LDB_SUCCESS) {
 
131
                talloc_free(tmp_ctx);
 
132
                /* its OK for their account DN not to be in our database */
 
133
                return NT_STATUS_OK;
 
134
        }
 
135
 
 
136
        hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
 
137
        if (hostname == NULL) {
 
138
                talloc_free(tmp_ctx);
 
139
                /* its OK to not have a dnshostname */
 
140
                return NT_STATUS_OK;
 
141
        }
 
142
 
 
143
        /* All DCs have the GC/hostname/realm name, but if some of the
 
144
         * preconditions are not satisfied, then we will fall back to
 
145
         * the
 
146
         * E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN}
 
147
         * name.  This means that if a AD server has a dnsHostName set
 
148
         * on it's record, it must also have GC/hostname/realm
 
149
         * servicePrincipalName */
 
150
 
 
151
        *target_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
 
152
                                            hostname,
 
153
                                            lpcfg_dnsdomain(s->task->lp_ctx));
 
154
        talloc_free(tmp_ctx);
 
155
        return NT_STATUS_OK;
 
156
}
 
157
 
 
158
 
 
159
WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
 
160
                                      const struct repsFromTo1 *rft,
 
161
                                      struct dreplsrv_out_connection **_conn)
95
162
{
96
163
        struct dreplsrv_out_connection *cur, *conn = NULL;
97
164
        const char *hostname;
131
198
                        return ntstatus_to_werror(nt_status);
132
199
                }
133
200
 
 
201
                /* use the GC principal for DRS replication */
 
202
                nt_status = dreplsrv_get_target_principal(s, conn->binding,
 
203
                                                          rft, &conn->binding->target_principal);
 
204
                if (!NT_STATUS_IS_OK(nt_status)) {
 
205
                        return ntstatus_to_werror(nt_status);
 
206
                }
 
207
 
134
208
                DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
135
209
 
136
 
                DEBUG(2,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
 
210
                DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
137
211
        } else {
138
 
                DEBUG(2,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
 
212
                DEBUG(4,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
139
213
        }
140
214
 
141
215
        *_conn = conn;
142
216
        return WERR_OK;
143
217
}
144
218
 
 
219
/*
 
220
  find an existing source dsa in a list
 
221
 */
 
222
static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa *list,
 
223
                                                                      struct GUID *guid)
 
224
{
 
225
        struct dreplsrv_partition_source_dsa *s;
 
226
        for (s=list; s; s=s->next) {
 
227
                if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
 
228
                        return s;
 
229
                }
 
230
        }
 
231
        return NULL;    
 
232
}
 
233
 
 
234
 
 
235
 
145
236
static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
146
237
                                                struct dreplsrv_partition *p,
 
238
                                                struct dreplsrv_partition_source_dsa **listp,
 
239
                                                struct dreplsrv_partition_source_dsa *check_list,
147
240
                                                const struct ldb_val *val)
148
241
{
149
242
        WERROR status;
154
247
        W_ERROR_HAVE_NO_MEMORY(source);
155
248
 
156
249
        ndr_err = ndr_pull_struct_blob(val, source, 
157
 
                                       lp_iconv_convenience(s->task->lp_ctx), &source->_repsFromBlob,
 
250
                                       &source->_repsFromBlob,
158
251
                                       (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
159
252
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160
253
                NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
173
266
        status = dreplsrv_out_connection_attach(s, source->repsFrom1, &source->conn);
174
267
        W_ERROR_NOT_OK_RETURN(status);
175
268
 
176
 
        /* remove any existing source with the same GUID */
177
 
        for (s2=p->sources; s2; s2=s2->next) {
 
269
        if (check_list && 
 
270
            dreplsrv_find_source_dsa(check_list, &source->repsFrom1->source_dsa_obj_guid)) {
 
271
                /* its in the check list, don't add it again */
 
272
                talloc_free(source);
 
273
                return WERR_OK;
 
274
        }
 
275
 
 
276
        /* re-use an existing source if found */
 
277
        for (s2=*listp; s2; s2=s2->next) {
178
278
                if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid, 
179
279
                                 &source->repsFrom1->source_dsa_obj_guid) == 0) {
180
280
                        talloc_free(s2->repsFrom1->other_info);
185
285
                }
186
286
        }
187
287
 
188
 
        DLIST_ADD_END(p->sources, source, struct dreplsrv_partition_source_dsa *);
 
288
        DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
189
289
        return WERR_OK;
190
290
}
191
291
 
 
292
WERROR dreplsrv_partition_find_for_nc(struct dreplsrv_service *s,
 
293
                                      const struct GUID *nc_guid,
 
294
                                      const struct dom_sid *nc_sid,
 
295
                                      const char *nc_dn_str,
 
296
                                      struct dreplsrv_partition **_p)
 
297
{
 
298
        struct dreplsrv_partition *p;
 
299
        bool valid_sid, valid_guid;
 
300
        struct dom_sid null_sid;
 
301
        ZERO_STRUCT(null_sid);
 
302
 
 
303
        SMB_ASSERT(_p);
 
304
 
 
305
        valid_sid  = nc_sid && !dom_sid_equal(&null_sid, nc_sid);
 
306
        valid_guid = nc_guid && !GUID_all_zero(nc_guid);
 
307
 
 
308
        if (!valid_sid && !valid_guid && !nc_dn_str) {
 
309
                return WERR_DS_DRA_INVALID_PARAMETER;
 
310
        }
 
311
 
 
312
        for (p = s->partitions; p; p = p->next) {
 
313
                if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
 
314
                    || strequal(p->nc.dn, nc_dn_str)
 
315
                    || (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
 
316
                {
 
317
                        *_p = p;
 
318
                        return WERR_OK;
 
319
                }
 
320
        }
 
321
 
 
322
        return WERR_DS_DRA_BAD_NC;
 
323
}
 
324
 
 
325
WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
 
326
                                             const struct GUID *dsa_guid,
 
327
                                             struct dreplsrv_partition_source_dsa **_dsa)
 
328
{
 
329
        struct dreplsrv_partition_source_dsa *dsa;
 
330
 
 
331
        SMB_ASSERT(dsa_guid != NULL);
 
332
        SMB_ASSERT(!GUID_all_zero(dsa_guid));
 
333
        SMB_ASSERT(_dsa);
 
334
 
 
335
        for (dsa = p->sources; dsa; dsa = dsa->next) {
 
336
                if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
 
337
                        *_dsa = dsa;
 
338
                        return WERR_OK;
 
339
                }
 
340
        }
 
341
 
 
342
        return WERR_DS_DRA_NO_REPLICA;
 
343
}
 
344
 
 
345
WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
 
346
                                            const char *dsa_dns,
 
347
                                            struct dreplsrv_partition_source_dsa **_dsa)
 
348
{
 
349
        struct dreplsrv_partition_source_dsa *dsa;
 
350
 
 
351
        SMB_ASSERT(dsa_dns != NULL);
 
352
        SMB_ASSERT(_dsa);
 
353
 
 
354
        for (dsa = p->sources; dsa; dsa = dsa->next) {
 
355
                if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
 
356
                        *_dsa = dsa;
 
357
                        return WERR_OK;
 
358
                }
 
359
        }
 
360
 
 
361
        return WERR_DS_DRA_NO_REPLICA;
 
362
}
 
363
 
 
364
 
192
365
static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
193
366
                                         struct dreplsrv_partition *p)
194
367
{
195
368
        WERROR status;
196
 
        const struct ldb_val *ouv_value;
197
 
        struct replUpToDateVectorBlob ouv;
198
369
        struct dom_sid *nc_sid;
199
370
        struct ldb_message_element *orf_el = NULL;
200
371
        struct ldb_result *r;
201
 
        uint32_t i;
 
372
        unsigned int i;
202
373
        int ret;
203
374
        TALLOC_CTX *mem_ctx = talloc_new(p);
204
375
        static const char *attrs[] = {
205
376
                "objectSid",
206
377
                "objectGUID",
207
 
                "replUpToDateVector",
208
378
                "repsFrom",
 
379
                "repsTo",
209
380
                NULL
210
381
        };
211
382
 
212
 
        DEBUG(2, ("dreplsrv_refresh_partition(%s)\n",
 
383
        DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
213
384
                ldb_dn_get_linearized(p->dn)));
214
385
 
215
386
        ret = ldb_search(s->samdb, mem_ctx, &r, p->dn, LDB_SCOPE_BASE, attrs,
217
388
        if (ret != LDB_SUCCESS) {
218
389
                talloc_free(mem_ctx);
219
390
                return WERR_FOOBAR;
220
 
        } else if (r->count != 1) {
221
 
                talloc_free(mem_ctx);
222
 
                return WERR_FOOBAR;
223
391
        }
224
392
        
225
393
        talloc_free(discard_const(p->nc.dn));
233
401
                talloc_free(nc_sid);
234
402
        }
235
403
 
236
 
        ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
237
 
        if (ouv_value) {
238
 
                enum ndr_err_code ndr_err;
239
 
                ndr_err = ndr_pull_struct_blob(ouv_value, mem_ctx, 
240
 
                                               lp_iconv_convenience(s->task->lp_ctx), &ouv,
241
 
                                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
242
 
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243
 
                        NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
244
 
                        talloc_free(mem_ctx);
245
 
                        return ntstatus_to_werror(nt_status);
246
 
                }
247
 
                /* NDR_PRINT_DEBUG(replUpToDateVectorBlob, &ouv); */
248
 
                if (ouv.version != 2) {
249
 
                        talloc_free(mem_ctx);
250
 
                        return WERR_DS_DRA_INTERNAL_ERROR;
251
 
                }
 
404
        talloc_free(p->uptodatevector.cursors);
 
405
        talloc_free(p->uptodatevector_ex.cursors);
 
406
        ZERO_STRUCT(p->uptodatevector);
 
407
        ZERO_STRUCT(p->uptodatevector_ex);
252
408
 
253
 
                p->uptodatevector.count         = ouv.ctr.ctr2.count;
254
 
                p->uptodatevector.reserved      = ouv.ctr.ctr2.reserved;
255
 
                talloc_free(p->uptodatevector.cursors);
256
 
                p->uptodatevector.cursors       = talloc_steal(p, ouv.ctr.ctr2.cursors);
 
409
        ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
 
410
        if (ret != LDB_SUCCESS) {
 
411
                DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
257
412
        }
258
413
 
259
 
        /*
260
 
         * TODO: add our own uptodatevector cursor
261
 
         */
262
 
 
263
 
 
264
414
        orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom");
265
415
        if (orf_el) {
266
416
                for (i=0; i < orf_el->num_values; i++) {
267
 
                        status = dreplsrv_partition_add_source_dsa(s, p, &orf_el->values[i]);
 
417
                        status = dreplsrv_partition_add_source_dsa(s, p, &p->sources, 
 
418
                                                                   NULL, &orf_el->values[i]);
 
419
                        W_ERROR_NOT_OK_RETURN(status);  
 
420
                }
 
421
        }
 
422
 
 
423
        orf_el = ldb_msg_find_element(r->msgs[0], "repsTo");
 
424
        if (orf_el) {
 
425
                for (i=0; i < orf_el->num_values; i++) {
 
426
                        status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies, 
 
427
                                                                   p->sources, &orf_el->values[i]);
268
428
                        W_ERROR_NOT_OK_RETURN(status);  
269
429
                }
270
430
        }