1/* 2 * idmap_adex: Support for AD Forests 3 * 4 * Copyright (C) Gerald (Jerry) Carter 2006-2008 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#include "includes.h" 22#include "idmap_adex.h" 23 24#undef DBGC_CLASS 25#define DBGC_CLASS DBGC_IDMAP 26 27static struct likewise_cell *_lw_cell_list = NULL; 28 29/********************************************************************** 30 Return the current HEAD of the list 31 *********************************************************************/ 32 33 struct likewise_cell *cell_list_head(void) 34{ 35 return _lw_cell_list; 36} 37 38 39/********************************************************************** 40 *********************************************************************/ 41 42 void cell_destroy(struct likewise_cell *c) 43{ 44 if (!c) 45 return; 46 47 if (c->conn) 48 ads_destroy(&c->conn); 49 50 talloc_destroy(c); 51} 52 53/********************************************************************** 54 Free all cell entries and reset the list head to NULL 55 *********************************************************************/ 56 57 void cell_list_destroy(void) 58{ 59 struct likewise_cell *p = _lw_cell_list; 60 61 while (p) { 62 struct likewise_cell *q = p->next; 63 64 cell_destroy(p); 65 66 p = q; 67 } 68 69 _lw_cell_list = NULL; 70 71 return; 72} 73 74/********************************************************************** 75 Add a new cell structure to the list 76 *********************************************************************/ 77 78 struct likewise_cell* cell_new(void) 79{ 80 struct likewise_cell *c; 81 82 /* Each cell struct is a TALLOC_CTX* */ 83 84 c = TALLOC_ZERO_P(NULL, struct likewise_cell); 85 if (!c) { 86 DEBUG(0,("cell_new: memory allocation failure!\n")); 87 return NULL; 88 } 89 90 return c; 91} 92 93/********************************************************************** 94 Add a new cell structure to the list 95 *********************************************************************/ 96 97 bool cell_list_add(struct likewise_cell * cell) 98{ 99 if (!cell) { 100 return false; 101 } 102 103 /* Always add to the end */ 104 105 DLIST_ADD_END(_lw_cell_list, cell, struct likewise_cell *); 106 107 return true; 108} 109 110/********************************************************************** 111 Add a new cell structure to the list 112 *********************************************************************/ 113 114 bool cell_list_remove(struct likewise_cell * cell) 115{ 116 if (!cell) { 117 return false; 118 } 119 120 /* Remove and drop the cell structure */ 121 122 DLIST_REMOVE(_lw_cell_list, cell); 123 talloc_destroy(cell); 124 125 return true; 126} 127 128/********************************************************************** 129 Set the containing DNS domain for a cell 130 *********************************************************************/ 131 132 void cell_set_dns_domain(struct likewise_cell *c, const char *dns_domain) 133{ 134 c->dns_domain = talloc_strdup(c, dns_domain); 135} 136 137/********************************************************************** 138 Set ADS connection for a cell 139 *********************************************************************/ 140 141 void cell_set_connection(struct likewise_cell *c, ADS_STRUCT *ads) 142{ 143 c->conn = ads; 144} 145 146/********************************************************************** 147 *********************************************************************/ 148 149 void cell_set_flags(struct likewise_cell *c, uint32_t flags) 150{ 151 c->flags |= flags; 152} 153 154/********************************************************************** 155 *********************************************************************/ 156 157 void cell_clear_flags(struct likewise_cell *c, uint32_t flags) 158{ 159 c->flags &= ~flags; 160} 161 162/********************************************************************** 163 Set the Cell's DN 164 *********************************************************************/ 165 166 void cell_set_dn(struct likewise_cell *c, const char *dn) 167{ 168 if ( c->dn) { 169 talloc_free(c->dn); 170 c->dn = NULL; 171 } 172 173 c->dn = talloc_strdup(c, dn); 174} 175 176/********************************************************************** 177 *********************************************************************/ 178 179 void cell_set_domain_sid(struct likewise_cell *c, DOM_SID *sid) 180{ 181 sid_copy(&c->domain_sid, sid); 182} 183 184/* 185 * Query Routines 186 */ 187 188/********************************************************************** 189 *********************************************************************/ 190 191 const char* cell_search_base(struct likewise_cell *c) 192{ 193 if (!c) 194 return NULL; 195 196 return talloc_asprintf(c, "cn=%s,%s", ADEX_CELL_RDN, c->dn); 197} 198 199/********************************************************************** 200 *********************************************************************/ 201 202 bool cell_search_forest(struct likewise_cell *c) 203{ 204 uint32_t test_flags = LWCELL_FLAG_SEARCH_FOREST; 205 206 return ((c->flags & test_flags) == test_flags); 207} 208 209/********************************************************************** 210 *********************************************************************/ 211 212 uint32_t cell_flags(struct likewise_cell *c) 213{ 214 if (!c) 215 return 0; 216 217 return c->flags; 218} 219 220/********************************************************************** 221 *********************************************************************/ 222 223 const char *cell_dns_domain(struct likewise_cell *c) 224{ 225 if (!c) 226 return NULL; 227 228 return c->dns_domain; 229} 230 231/********************************************************************** 232 *********************************************************************/ 233 234 ADS_STRUCT *cell_connection(struct likewise_cell *c) 235{ 236 if (!c) 237 return NULL; 238 239 return c->conn; 240} 241 242/* 243 * Connection functions 244 */ 245 246/******************************************************************** 247 *******************************************************************/ 248 249 NTSTATUS cell_connect(struct likewise_cell *c) 250{ 251 ADS_STRUCT *ads = NULL; 252 ADS_STATUS ads_status; 253 fstring dc_name; 254 struct sockaddr_storage dcip; 255 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 256 257 /* have to at least have the AD domain name */ 258 259 if (!c->dns_domain) { 260 nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 261 BAIL_ON_NTSTATUS_ERROR(nt_status); 262 } 263 264 /* clear out any old information */ 265 266 if (c->conn) { 267 ads_destroy(&c->conn); 268 c->conn = NULL; 269 } 270 271 /* now setup the new connection */ 272 273 ads = ads_init(c->dns_domain, NULL, NULL); 274 BAIL_ON_PTR_ERROR(ads, nt_status); 275 276 ads->auth.password = 277 secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); 278 ads->auth.realm = SMB_STRDUP(lp_realm()); 279 280 /* Make the connection. We should already have an initial 281 TGT using the machine creds */ 282 283 if (cell_flags(c) & LWCELL_FLAG_GC_CELL) { 284 ads_status = ads_connect_gc(ads); 285 } else { 286 /* Set up server affinity for normal cells and the client 287 site name cache */ 288 289 if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) { 290 nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; 291 BAIL_ON_NTSTATUS_ERROR(nt_status); 292 } 293 294 ads_status = ads_connect(ads); 295 } 296 297 298 c->conn = ads; 299 300 nt_status = ads_ntstatus(ads_status); 301 302done: 303 if (!NT_STATUS_IS_OK(nt_status)) { 304 ads_destroy(&ads); 305 c->conn = NULL; 306 } 307 308 return nt_status; 309} 310 311/******************************************************************** 312 *******************************************************************/ 313 314 NTSTATUS cell_connect_dn(struct likewise_cell **c, const char *dn) 315{ 316 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 317 struct likewise_cell *new_cell = NULL; 318 char *dns_domain = NULL; 319 320 if (*c || !dn) { 321 nt_status = NT_STATUS_INVALID_PARAMETER; 322 BAIL_ON_NTSTATUS_ERROR(nt_status); 323 } 324 325 if ((new_cell = cell_new()) == NULL) { 326 nt_status = NT_STATUS_NO_MEMORY; 327 BAIL_ON_NTSTATUS_ERROR(nt_status); 328 } 329 330 /* Set the DNS domain, dn, etc ... and add it to the list */ 331 332 dns_domain = cell_dn_to_dns(dn); 333 cell_set_dns_domain(new_cell, dns_domain); 334 SAFE_FREE(dns_domain); 335 336 cell_set_dn(new_cell, dn); 337 338 nt_status = cell_connect(new_cell); 339 BAIL_ON_NTSTATUS_ERROR(nt_status); 340 341 *c = new_cell; 342 343done: 344 if (!NT_STATUS_IS_OK(nt_status)) { 345 DEBUG(1,("LWI: Failled to connect to cell \"%s\" (%s)\n", 346 dn ? dn : "NULL", nt_errstr(nt_status))); 347 talloc_destroy(new_cell); 348 } 349 350 return nt_status; 351} 352 353 354/******************************************************************** 355 *******************************************************************/ 356 357#define MAX_SEARCH_COUNT 2 358 359 ADS_STATUS cell_do_search(struct likewise_cell *c, 360 const char *search_base, 361 int scope, 362 const char *expr, 363 const char **attrs, 364 LDAPMessage ** msg) 365{ 366 int search_count = 0; 367 ADS_STATUS status; 368 NTSTATUS nt_status; 369 370 /* check for a NULL connection */ 371 372 if (!c->conn) { 373 nt_status = cell_connect(c); 374 if (!NT_STATUS_IS_OK(nt_status)) { 375 status = ADS_ERROR_NT(nt_status); 376 return status; 377 } 378 } 379 380 DEBUG(10, ("cell_do_search: Base = %s, Filter = %s, Scope = %d, GC = %s\n", 381 search_base, expr, scope, 382 c->conn->server.gc ? "yes" : "no")); 383 384 /* we try multiple times in case the ADS_STRUCT is bad 385 and we need to reconnect */ 386 387 while (search_count < MAX_SEARCH_COUNT) { 388 *msg = NULL; 389 status = ads_do_search(c->conn, search_base, 390 scope, expr, attrs, msg); 391 if (ADS_ERR_OK(status)) { 392 if (DEBUGLEVEL >= 10) { 393 LDAPMessage *e = NULL; 394 395 int n = ads_count_replies(c->conn, *msg); 396 397 DEBUG(10,("cell_do_search: Located %d entries\n", n)); 398 399 for (e=ads_first_entry(c->conn, *msg); 400 e!=NULL; 401 e = ads_next_entry(c->conn, e)) 402 { 403 char *dn = ads_get_dn(c->conn, talloc_tos(), e); 404 405 DEBUGADD(10,(" dn: %s\n", dn ? dn : "<NULL>")); 406 TALLOC_FREE(dn); 407 } 408 } 409 410 return status; 411 } 412 413 414 DEBUG(5, ("cell_do_search: search[%d] failed (%s)\n", 415 search_count, ads_errstr(status))); 416 417 search_count++; 418 419 /* Houston, we have a problem */ 420 421 if (status.error_type == ENUM_ADS_ERROR_LDAP) { 422 switch (status.err.rc) { 423 case LDAP_TIMELIMIT_EXCEEDED: 424 case LDAP_TIMEOUT: 425 case -1: /* we get this error if we cannot contact 426 the LDAP server */ 427 nt_status = cell_connect(c); 428 if (!NT_STATUS_IS_OK(nt_status)) { 429 status = ADS_ERROR_NT(nt_status); 430 return status; 431 } 432 break; 433 default: 434 /* we're all done here */ 435 return status; 436 } 437 } 438 } 439 440 DEBUG(5, ("cell_do_search: exceeded maximum search count!\n")); 441 442 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 443} 444