97
/**********************************************************************
98
*********************************************************************/
100
static NTSTATUS gc_add_forest(const char *forest)
96
/**********************************************************************
97
*********************************************************************/
99
NTSTATUS gc_find_forest_root(struct gc_info *gc, const char *domain)
101
ADS_STRUCT *ads = NULL;
102
ADS_STATUS ads_status;
103
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
104
struct cldap_netlogon_reply cldap_reply;
106
if (!gc || !domain) {
107
return NT_STATUS_INVALID_PARAMETER;
110
ZERO_STRUCT(cldap_reply);
112
ads = ads_init(domain, NULL, NULL);
113
BAIL_ON_PTR_ERROR(ads, nt_status);
115
ads->auth.flags = ADS_AUTH_NO_BIND;
116
ads_status = ads_connect(ads);
117
if (!ADS_ERR_OK(ads_status)) {
118
DEBUG(4, ("find_forest_root: ads_connect(%s) failed! (%s)\n",
119
domain, ads_errstr(ads_status)));
121
nt_status = ads_ntstatus(ads_status);
122
BAIL_ON_NTSTATUS_ERROR(nt_status);
124
if (!ads_cldap_netlogon(ads->config.ldap_server_name,
128
DEBUG(4,("find_forest_root: Failed to get a CLDAP reply from %s!\n",
129
ads->server.ldap_server));
130
nt_status = NT_STATUS_IO_TIMEOUT;
131
BAIL_ON_NTSTATUS_ERROR(nt_status);
134
gc->forest_name = talloc_strdup(gc, cldap_reply.forest);
135
BAIL_ON_PTR_ERROR(gc->forest_name, nt_status);
145
/**********************************************************************
146
*********************************************************************/
148
static NTSTATUS gc_add_forest(const char *domain)
102
150
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
103
151
struct gc_info *gc = NULL;
152
struct gc_info *find_gc = NULL;
105
154
ADS_STRUCT *ads = NULL;
106
155
struct likewise_cell *primary_cell = NULL;
111
160
BAIL_ON_NTSTATUS_ERROR(nt_status);
114
/* Check for duplicates */
163
/* Check for duplicates based on domain name first as this
164
requires no connection */
118
if (strequal (gc->forest_name, forest))
166
find_gc = gc_list_head();
168
if (strequal (find_gc->forest_name, domain))
170
find_gc = find_gc->next;
124
DEBUG(10,("gc_add_forest: %s already in list\n", forest));
174
DEBUG(10,("gc_add_forest: %s already in list\n", find_gc->forest_name));
125
175
return NT_STATUS_OK;
130
180
BAIL_ON_NTSTATUS_ERROR(nt_status);
133
gc->forest_name = talloc_strdup(gc, forest);
134
BAIL_ON_PTR_ERROR(gc->forest_name, nt_status);
183
/* Query the rootDSE for the forest root naming conect first.
184
Check that the a GC server for the forest has not already
187
nt_status = gc_find_forest_root(gc, domain);
188
BAIL_ON_NTSTATUS_ERROR(nt_status);
190
find_gc = gc_list_head();
192
if (strequal (find_gc->forest_name, gc->forest_name))
194
find_gc = find_gc->next;
198
DEBUG(10,("gc_add_forest: Forest %s already in list\n",
199
find_gc->forest_name));
203
/* Not found, so add it here. Make sure we connect to
204
a DC in _this_ domain and not the forest root. */
136
206
dn = ads_build_dn(gc->forest_name);
137
207
BAIL_ON_PTR_ERROR(dn, nt_status);
139
209
gc->search_base = talloc_strdup(gc, dn);
141
BAIL_ON_PTR_ERROR(gc->search_base, nt_status);
143
/* Connect to the cell to find the forest settings. This must
144
be done before we mark the cell as a GC cell connection to
145
get the correct information. */
147
nt_status = cell_connect_dn(&gc->forest_cell, gc->search_base);
211
BAIL_ON_PTR_ERROR(gc->search_base, nt_status);
214
/* Can't use cell_connect_dn() here as there is no way to
215
specifiy the LWCELL_FLAG_GC_CELL flag setting for cell_connect() */
217
nt_status = cell_connect_dn(&gc->forest_cell, gc->search_base);
148
218
BAIL_ON_NTSTATUS_ERROR(nt_status);
221
gc->forest_cell = cell_new();
222
BAIL_ON_PTR_ERROR(gc->forest_cell, nt_status);
224
/* Set the DNS domain, dn, etc ... and add it to the list */
226
cell_set_dns_domain(gc->forest_cell, gc->forest_name);
227
cell_set_dn(gc->forest_cell, gc->search_base);
228
cell_set_flags(gc->forest_cell, LWCELL_FLAG_GC_CELL);
150
231
/* It is possible to belong to a non-forest cell and a
151
232
non-provisioned forest (at our domain levele). In that
153
234
cell since the GC searches will match our own schema
156
if (is_subdomain(primary_cell->dns_domain, gc->forest_name)) {
237
if (strequal(primary_cell->forest_name, gc->forest_name)
238
|| is_subdomain(primary_cell->dns_domain, gc->forest_name))
157
240
cell_set_flags(gc->forest_cell, cell_flags(primary_cell));
159
242
/* outside of our domain */
244
nt_status = cell_connect(gc->forest_cell);
245
BAIL_ON_NTSTATUS_ERROR(nt_status);
160
247
nt_status = cell_lookup_settings(gc->forest_cell);
161
248
BAIL_ON_NTSTATUS_ERROR(nt_status);
250
/* Drop the connection now that we have the settings */
252
ads = cell_connection(gc->forest_cell);
254
cell_set_connection(gc->forest_cell, NULL);
164
/* Drop the connection now that we have the settings */
166
ads = cell_connection(gc->forest_cell);
168
cell_set_connection(gc->forest_cell, NULL);
170
/* Set a couple of necessary flags to mark this for
173
cell_set_flags(gc->forest_cell, LWCELL_FLAG_GC_CELL);
175
257
DLIST_ADD_END(_gc_server_list, gc, struct gc_info*);
259
DEBUG(10,("gc_add_forest: Added %s to Global Catalog list of servers\n",
177
262
nt_status = NT_STATUS_OK;
180
265
if (!NT_STATUS_IS_OK(nt_status)) {
181
266
talloc_destroy(gc);
182
DEBUG(0,("LWI: Failed to add new GC connection for %s (%s)\n",
183
forest, nt_errstr(nt_status)));
267
DEBUG(3,("LWI: Failed to add new GC connection for %s (%s)\n",
268
domain, nt_errstr(nt_status)));
186
271
return nt_status;
228
313
BAIL_ON_NTSTATUS_ERROR(nt_status);
231
/* Find our forst first */
316
/* Find our forest first. Have to try all domains here starting
317
with our own. gc_add_forest() filters duplicates */
319
nt_status = gc_add_forest(lp_realm());
320
WARN_ON_NTSTATUS_ERROR(nt_status);
233
322
for (i=0; i<num_domains; i++) {
234
uint32_t flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
323
uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST);
325
/* I think we should be able to break out of loop once
326
we add a GC for our forest and not have to test every one.
327
In fact, this entire loop is probably irrelevant since
328
the GC location code should always find a GC given lp_realm().
329
Will have to spend time testing before making the change.
236
332
if ((domains[i].trust_flags & flags) == flags) {
237
333
nt_status = gc_add_forest(domains[i].dns_name);
238
BAIL_ON_NTSTATUS_ERROR(nt_status);
334
WARN_ON_NTSTATUS_ERROR(nt_status);
335
/* Don't BAIL here since not every domain may
244
340
/* Now add trusted forests. gc_add_forest() will filter out
341
duplicates. Check everything with an incoming trust path
342
that is not in our own forest. */
247
344
for (i=0; i<num_domains; i++) {
248
345
uint32_t flags = domains[i].trust_flags;
249
uint32_t attribs = domains[i].trust_attribs;
346
uint32_t attribs = domains[i].trust_attribs;
348
/* Skip non_AD domains */
350
if (strlen(domains[i].dns_name) == 0) {
354
/* Only add a GC for a forest outside of our own.
355
Ignore QUARANTINED/EXTERNAL trusts */
251
357
if ((flags & NETR_TRUST_FLAG_INBOUND)
358
&& !(flags & NETR_TRUST_FLAG_IN_FOREST)
252
359
&& (attribs & NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE))
254
361
nt_status = gc_add_forest(domains[i].dns_name);
315
422
BAIL_ON_NTSTATUS_ERROR(nt_status);
318
ads_status = cell_do_search(gc->forest_cell, gc->search_base,
425
/* When you have multiple domain trees in a forest, the
426
GC will search all naming contexts when you send it
427
and empty ("") base search suffix. Tested against
430
ads_status = cell_do_search(gc->forest_cell, "",
319
431
LDAP_SCOPE_SUBTREE, filter, attrs, &m);
320
432
nt_status = ads_ntstatus(ads_status);
321
433
BAIL_ON_NTSTATUS_ERROR(nt_status);