1/* 2 * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts 3 * 4 * Unix SMB/CIFS implementation. 5 * 6 * Winbind ADS backend functions 7 * 8 * Copyright (C) Andrew Tridgell 2001 9 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 10 * Copyright (C) Gerald (Jerry) Carter 2004-2007 11 * Copyright (C) Luke Howard 2001-2004 12 * Copyright (C) Michael Adam 2008 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 3 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, see <http://www.gnu.org/licenses/>. 26 */ 27 28#include "includes.h" 29#include "winbindd.h" 30 31#undef DBGC_CLASS 32#define DBGC_CLASS DBGC_IDMAP 33 34#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" 35 36#define IDMAP_AD_MAX_IDS 30 37#define CHECK_ALLOC_DONE(mem) do { \ 38 if (!mem) { \ 39 DEBUG(0, ("Out of memory!\n")); \ 40 ret = NT_STATUS_NO_MEMORY; \ 41 goto done; \ 42 } \ 43} while (0) 44 45struct idmap_ad_context { 46 uint32_t filter_low_id; 47 uint32_t filter_high_id; 48 ADS_STRUCT *ads; 49 struct posix_schema *ad_schema; 50 enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */ 51}; 52 53NTSTATUS init_module(void); 54 55/************************************************************************ 56 ***********************************************************************/ 57 58static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom) 59{ 60 ADS_STRUCT *ads; 61 ADS_STATUS status; 62 bool local = False; 63 fstring dc_name; 64 struct sockaddr_storage dc_ip; 65 struct idmap_ad_context *ctx; 66 char *ldap_server = NULL; 67 char *realm = NULL; 68 struct winbindd_domain *wb_dom; 69 70 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n", 71 dom->name)); 72 73 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 74 75 if (ctx->ads != NULL) { 76 77 time_t expire; 78 time_t now = time(NULL); 79 80 ads = ctx->ads; 81 82 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire); 83 84 /* check for a valid structure */ 85 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n", 86 (uint32)expire-(uint32)now, (uint32) expire, (uint32) now)); 87 88 if ( ads->config.realm && (expire > time(NULL))) { 89 return ADS_SUCCESS; 90 } else { 91 /* we own this ADS_STRUCT so make sure it goes away */ 92 DEBUG(7,("Deleting expired krb5 credential cache\n")); 93 ads->is_mine = True; 94 ads_destroy( &ads ); 95 ads_kdestroy(WINBIND_CCACHE_NAME); 96 ctx->ads = NULL; 97 TALLOC_FREE( ctx->ad_schema ); 98 } 99 } 100 101 if (!local) { 102 /* we don't want this to affect the users ccache */ 103 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); 104 } 105 106 /* 107 * At this point we only have the NetBIOS domain name. 108 * Check if we can get server nam and realm from SAF cache 109 * and the domain list. 110 */ 111 ldap_server = saf_fetch(dom->name); 112 DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:"")); 113 114 wb_dom = find_domain_from_name_noinit(dom->name); 115 if (wb_dom == NULL) { 116 DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n", 117 dom->name)); 118 realm = NULL; 119 } else { 120 DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for " 121 " domain '%s'\n", wb_dom->alt_name, dom->name)); 122 realm = wb_dom->alt_name; 123 } 124 125 if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) { 126 DEBUG(1,("ads_init failed\n")); 127 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); 128 } 129 130 /* the machine acct password might have change - fetch it every time */ 131 SAFE_FREE(ads->auth.password); 132 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); 133 134 SAFE_FREE(ads->auth.realm); 135 ads->auth.realm = SMB_STRDUP(lp_realm()); 136 137 /* setup server affinity */ 138 139 get_dc_name(dom->name, realm, dc_name, &dc_ip ); 140 141 status = ads_connect(ads); 142 if (!ADS_ERR_OK(status)) { 143 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n")); 144 ads_destroy(&ads); 145 return status; 146 } 147 148 ads->is_mine = False; 149 150 ctx->ads = ads; 151 152 return ADS_SUCCESS; 153} 154 155/************************************************************************ 156 ***********************************************************************/ 157 158static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom) 159{ 160 ADS_STATUS status; 161 struct idmap_ad_context * ctx; 162 163 status = ad_idmap_cached_connection_internal(dom); 164 if (!ADS_ERR_OK(status)) { 165 return status; 166 } 167 168 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 169 170 /* if we have a valid ADS_STRUCT and the schema model is 171 defined, then we can return here. */ 172 173 if ( ctx->ad_schema ) { 174 return ADS_SUCCESS; 175 } 176 177 /* Otherwise, set the schema model */ 178 179 if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) || 180 (ctx->ad_map_type == WB_POSIX_MAP_SFU20) || 181 (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) ) 182 { 183 status = ads_check_posix_schema_mapping(NULL, ctx->ads, ctx->ad_map_type, &ctx->ad_schema); 184 if ( !ADS_ERR_OK(status) ) { 185 DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n")); 186 } 187 } 188 189 return status; 190} 191 192/************************************************************************ 193 ***********************************************************************/ 194 195static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, 196 const char *params) 197{ 198 struct idmap_ad_context *ctx; 199 char *config_option; 200 const char *range = NULL; 201 const char *schema_mode = NULL; 202 203 if ( (ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context)) == NULL ) { 204 DEBUG(0, ("Out of memory!\n")); 205 return NT_STATUS_NO_MEMORY; 206 } 207 208 if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) { 209 DEBUG(0, ("Out of memory!\n")); 210 talloc_free(ctx); 211 return NT_STATUS_NO_MEMORY; 212 } 213 214 /* load ranges */ 215 range = lp_parm_const_string(-1, config_option, "range", NULL); 216 if (range && range[0]) { 217 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) || 218 (ctx->filter_low_id > ctx->filter_high_id)) { 219 DEBUG(1, ("ERROR: invalid filter range [%s]", range)); 220 ctx->filter_low_id = 0; 221 ctx->filter_high_id = 0; 222 } 223 } 224 225 /* default map type */ 226 ctx->ad_map_type = WB_POSIX_MAP_RFC2307; 227 228 /* schema mode */ 229 schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL); 230 if ( schema_mode && schema_mode[0] ) { 231 if ( strequal(schema_mode, "sfu") ) 232 ctx->ad_map_type = WB_POSIX_MAP_SFU; 233 else if ( strequal(schema_mode, "sfu20" ) ) 234 ctx->ad_map_type = WB_POSIX_MAP_SFU20; 235 else if ( strequal(schema_mode, "rfc2307" ) ) 236 ctx->ad_map_type = WB_POSIX_MAP_RFC2307; 237 else 238 DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n", 239 schema_mode)); 240 } 241 242 dom->private_data = ctx; 243 244 talloc_free(config_option); 245 246 return NT_STATUS_OK; 247} 248 249/************************************************************************ 250 Search up to IDMAP_AD_MAX_IDS entries in maps for a match. 251 ***********************************************************************/ 252 253static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id) 254{ 255 int i; 256 257 for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) { 258 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) { 259 return maps[i]; 260 } 261 } 262 263 return NULL; 264} 265 266/************************************************************************ 267 Search up to IDMAP_AD_MAX_IDS entries in maps for a match 268 ***********************************************************************/ 269 270static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid) 271{ 272 int i; 273 274 for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) { 275 if (sid_equal(maps[i]->sid, sid)) { 276 return maps[i]; 277 } 278 } 279 280 return NULL; 281} 282 283/************************************************************************ 284 ***********************************************************************/ 285 286static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) 287{ 288 NTSTATUS ret; 289 TALLOC_CTX *memctx; 290 struct idmap_ad_context *ctx; 291 ADS_STATUS rc; 292 const char *attrs[] = { "sAMAccountType", 293 "objectSid", 294 NULL, /* uidnumber */ 295 NULL, /* gidnumber */ 296 NULL }; 297 LDAPMessage *res = NULL; 298 LDAPMessage *entry = NULL; 299 char *filter = NULL; 300 int idx = 0; 301 int bidx = 0; 302 int count; 303 int i; 304 char *u_filter = NULL; 305 char *g_filter = NULL; 306 307 /* initialize the status to avoid suprise */ 308 for (i = 0; ids[i]; i++) { 309 ids[i]->status = ID_UNKNOWN; 310 } 311 312 /* Only do query if we are online */ 313 if (idmap_is_offline()) { 314 return NT_STATUS_FILE_IS_OFFLINE; 315 } 316 317 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 318 319 if ( (memctx = talloc_new(ctx)) == NULL ) { 320 DEBUG(0, ("Out of memory!\n")); 321 return NT_STATUS_NO_MEMORY; 322 } 323 324 rc = ad_idmap_cached_connection(dom); 325 if (!ADS_ERR_OK(rc)) { 326 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc))); 327 ret = NT_STATUS_UNSUCCESSFUL; 328 /* ret = ads_ntstatus(rc); */ 329 goto done; 330 } 331 332 attrs[2] = ctx->ad_schema->posix_uidnumber_attr; 333 attrs[3] = ctx->ad_schema->posix_gidnumber_attr; 334 335again: 336 bidx = idx; 337 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) { 338 switch (ids[idx]->xid.type) { 339 case ID_TYPE_UID: 340 if ( ! u_filter) { 341 u_filter = talloc_asprintf(memctx, "(&(|" 342 "(sAMAccountType=%d)" 343 "(sAMAccountType=%d)" 344 "(sAMAccountType=%d))(|", 345 ATYPE_NORMAL_ACCOUNT, 346 ATYPE_WORKSTATION_TRUST, 347 ATYPE_INTERDOMAIN_TRUST); 348 } 349 u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)", 350 ctx->ad_schema->posix_uidnumber_attr, 351 (unsigned long)ids[idx]->xid.id); 352 CHECK_ALLOC_DONE(u_filter); 353 break; 354 355 case ID_TYPE_GID: 356 if ( ! g_filter) { 357 g_filter = talloc_asprintf(memctx, "(&(|" 358 "(sAMAccountType=%d)" 359 "(sAMAccountType=%d))(|", 360 ATYPE_SECURITY_GLOBAL_GROUP, 361 ATYPE_SECURITY_LOCAL_GROUP); 362 } 363 g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)", 364 ctx->ad_schema->posix_gidnumber_attr, 365 (unsigned long)ids[idx]->xid.id); 366 CHECK_ALLOC_DONE(g_filter); 367 break; 368 369 default: 370 DEBUG(3, ("Error: mapping requested but Unknown ID type\n")); 371 ids[idx]->status = ID_UNKNOWN; 372 continue; 373 } 374 } 375 filter = talloc_asprintf(memctx, "(|"); 376 CHECK_ALLOC_DONE(filter); 377 if ( u_filter) { 378 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter); 379 CHECK_ALLOC_DONE(filter); 380 TALLOC_FREE(u_filter); 381 } 382 if ( g_filter) { 383 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter); 384 CHECK_ALLOC_DONE(filter); 385 TALLOC_FREE(g_filter); 386 } 387 filter = talloc_asprintf_append_buffer(filter, ")"); 388 CHECK_ALLOC_DONE(filter); 389 390 rc = ads_search_retry(ctx->ads, &res, filter, attrs); 391 if (!ADS_ERR_OK(rc)) { 392 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); 393 ret = NT_STATUS_UNSUCCESSFUL; 394 goto done; 395 } 396 397 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { 398 DEBUG(10, ("No IDs found\n")); 399 } 400 401 entry = res; 402 for (i = 0; (i < count) && entry; i++) { 403 DOM_SID sid; 404 enum id_type type; 405 struct id_map *map; 406 uint32_t id; 407 uint32_t atype; 408 409 if (i == 0) { /* first entry */ 410 entry = ads_first_entry(ctx->ads, entry); 411 } else { /* following ones */ 412 entry = ads_next_entry(ctx->ads, entry); 413 } 414 415 if ( !entry ) { 416 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); 417 break; 418 } 419 420 /* first check if the SID is present */ 421 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) { 422 DEBUG(2, ("Could not retrieve SID from entry\n")); 423 continue; 424 } 425 426 /* get type */ 427 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { 428 DEBUG(1, ("could not get SAM account type\n")); 429 continue; 430 } 431 432 switch (atype & 0xF0000000) { 433 case ATYPE_SECURITY_GLOBAL_GROUP: 434 case ATYPE_SECURITY_LOCAL_GROUP: 435 type = ID_TYPE_GID; 436 break; 437 case ATYPE_NORMAL_ACCOUNT: 438 case ATYPE_WORKSTATION_TRUST: 439 case ATYPE_INTERDOMAIN_TRUST: 440 type = ID_TYPE_UID; 441 break; 442 default: 443 DEBUG(1, ("unrecognized SAM account type %08x\n", atype)); 444 continue; 445 } 446 447 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? 448 ctx->ad_schema->posix_uidnumber_attr : 449 ctx->ad_schema->posix_gidnumber_attr, 450 &id)) 451 { 452 DEBUG(1, ("Could not get unix ID\n")); 453 continue; 454 } 455 456 if ((id == 0) || 457 (ctx->filter_low_id && (id < ctx->filter_low_id)) || 458 (ctx->filter_high_id && (id > ctx->filter_high_id))) { 459 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", 460 id, ctx->filter_low_id, ctx->filter_high_id)); 461 continue; 462 } 463 464 map = find_map_by_id(&ids[bidx], type, id); 465 if (!map) { 466 DEBUG(2, ("WARNING: couldn't match result with requested ID\n")); 467 continue; 468 } 469 470 sid_copy(map->sid, &sid); 471 472 /* mapped */ 473 map->status = ID_MAPPED; 474 475 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid), 476 (unsigned long)map->xid.id, 477 map->xid.type)); 478 } 479 480 if (res) { 481 ads_msgfree(ctx->ads, res); 482 } 483 484 if (ids[idx]) { /* still some values to map */ 485 goto again; 486 } 487 488 ret = NT_STATUS_OK; 489 490 /* mark all unknown/expired ones as unmapped */ 491 for (i = 0; ids[i]; i++) { 492 if (ids[i]->status != ID_MAPPED) 493 ids[i]->status = ID_UNMAPPED; 494 } 495 496done: 497 talloc_free(memctx); 498 return ret; 499} 500 501/************************************************************************ 502 ***********************************************************************/ 503 504static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) 505{ 506 NTSTATUS ret; 507 TALLOC_CTX *memctx; 508 struct idmap_ad_context *ctx; 509 ADS_STATUS rc; 510 const char *attrs[] = { "sAMAccountType", 511 "objectSid", 512 NULL, /* attr_uidnumber */ 513 NULL, /* attr_gidnumber */ 514 NULL }; 515 LDAPMessage *res = NULL; 516 LDAPMessage *entry = NULL; 517 char *filter = NULL; 518 int idx = 0; 519 int bidx = 0; 520 int count; 521 int i; 522 char *sidstr; 523 524 /* initialize the status to avoid suprise */ 525 for (i = 0; ids[i]; i++) { 526 ids[i]->status = ID_UNKNOWN; 527 } 528 529 /* Only do query if we are online */ 530 if (idmap_is_offline()) { 531 return NT_STATUS_FILE_IS_OFFLINE; 532 } 533 534 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 535 536 if ( (memctx = talloc_new(ctx)) == NULL ) { 537 DEBUG(0, ("Out of memory!\n")); 538 return NT_STATUS_NO_MEMORY; 539 } 540 541 rc = ad_idmap_cached_connection(dom); 542 if (!ADS_ERR_OK(rc)) { 543 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc))); 544 ret = NT_STATUS_UNSUCCESSFUL; 545 /* ret = ads_ntstatus(rc); */ 546 goto done; 547 } 548 549 if (ctx->ad_schema == NULL) { 550 DEBUG(0, ("haven't got ctx->ad_schema ! \n")); 551 ret = NT_STATUS_UNSUCCESSFUL; 552 goto done; 553 } 554 555 attrs[2] = ctx->ad_schema->posix_uidnumber_attr; 556 attrs[3] = ctx->ad_schema->posix_gidnumber_attr; 557 558again: 559 filter = talloc_asprintf(memctx, "(&(|" 560 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */ 561 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */ 562 ")(|", 563 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST, 564 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP); 565 566 CHECK_ALLOC_DONE(filter); 567 568 bidx = idx; 569 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) { 570 571 ids[idx]->status = ID_UNKNOWN; 572 573 sidstr = sid_binstring(talloc_tos(), ids[idx]->sid); 574 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr); 575 576 TALLOC_FREE(sidstr); 577 CHECK_ALLOC_DONE(filter); 578 } 579 filter = talloc_asprintf_append_buffer(filter, "))"); 580 CHECK_ALLOC_DONE(filter); 581 DEBUG(10, ("Filter: [%s]\n", filter)); 582 583 rc = ads_search_retry(ctx->ads, &res, filter, attrs); 584 if (!ADS_ERR_OK(rc)) { 585 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); 586 ret = NT_STATUS_UNSUCCESSFUL; 587 goto done; 588 } 589 590 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { 591 DEBUG(10, ("No IDs found\n")); 592 } 593 594 entry = res; 595 for (i = 0; (i < count) && entry; i++) { 596 DOM_SID sid; 597 enum id_type type; 598 struct id_map *map; 599 uint32_t id; 600 uint32_t atype; 601 602 if (i == 0) { /* first entry */ 603 entry = ads_first_entry(ctx->ads, entry); 604 } else { /* following ones */ 605 entry = ads_next_entry(ctx->ads, entry); 606 } 607 608 if ( !entry ) { 609 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); 610 break; 611 } 612 613 /* first check if the SID is present */ 614 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) { 615 DEBUG(2, ("Could not retrieve SID from entry\n")); 616 continue; 617 } 618 619 map = find_map_by_sid(&ids[bidx], &sid); 620 if (!map) { 621 DEBUG(2, ("WARNING: couldn't match result with requested SID\n")); 622 continue; 623 } 624 625 /* get type */ 626 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { 627 DEBUG(1, ("could not get SAM account type\n")); 628 continue; 629 } 630 631 switch (atype & 0xF0000000) { 632 case ATYPE_SECURITY_GLOBAL_GROUP: 633 case ATYPE_SECURITY_LOCAL_GROUP: 634 type = ID_TYPE_GID; 635 break; 636 case ATYPE_NORMAL_ACCOUNT: 637 case ATYPE_WORKSTATION_TRUST: 638 case ATYPE_INTERDOMAIN_TRUST: 639 type = ID_TYPE_UID; 640 break; 641 default: 642 DEBUG(1, ("unrecognized SAM account type %08x\n", atype)); 643 continue; 644 } 645 646 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? 647 ctx->ad_schema->posix_uidnumber_attr : 648 ctx->ad_schema->posix_gidnumber_attr, 649 &id)) 650 { 651 DEBUG(1, ("Could not get unix ID\n")); 652 continue; 653 } 654 if ((id == 0) || 655 (ctx->filter_low_id && (id < ctx->filter_low_id)) || 656 (ctx->filter_high_id && (id > ctx->filter_high_id))) { 657 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", 658 id, ctx->filter_low_id, ctx->filter_high_id)); 659 continue; 660 } 661 662 /* mapped */ 663 map->xid.type = type; 664 map->xid.id = id; 665 map->status = ID_MAPPED; 666 667 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid), 668 (unsigned long)map->xid.id, 669 map->xid.type)); 670 } 671 672 if (res) { 673 ads_msgfree(ctx->ads, res); 674 } 675 676 if (ids[idx]) { /* still some values to map */ 677 goto again; 678 } 679 680 ret = NT_STATUS_OK; 681 682 /* mark all unknwoni/expired ones as unmapped */ 683 for (i = 0; ids[i]; i++) { 684 if (ids[i]->status != ID_MAPPED) 685 ids[i]->status = ID_UNMAPPED; 686 } 687 688done: 689 talloc_free(memctx); 690 return ret; 691} 692 693/************************************************************************ 694 ***********************************************************************/ 695 696static NTSTATUS idmap_ad_close(struct idmap_domain *dom) 697{ 698 struct idmap_ad_context * ctx; 699 700 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 701 702 if (ctx->ads != NULL) { 703 /* we own this ADS_STRUCT so make sure it goes away */ 704 ctx->ads->is_mine = True; 705 ads_destroy( &ctx->ads ); 706 ctx->ads = NULL; 707 } 708 709 TALLOC_FREE( ctx->ad_schema ); 710 711 return NT_STATUS_OK; 712} 713 714/* 715 * nss_info_{sfu,sfu20,rfc2307} 716 */ 717 718/************************************************************************ 719 Initialize the {sfu,sfu20,rfc2307} state 720 ***********************************************************************/ 721 722static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN"; 723static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE"; 724static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU"; 725static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20"; 726static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307"; 727static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO"; 728 729static const char *ad_map_type_string(enum wb_posix_mapping map_type) 730{ 731 switch (map_type) { 732 case WB_POSIX_MAP_TEMPLATE: 733 return wb_posix_map_template_string; 734 case WB_POSIX_MAP_SFU: 735 return wb_posix_map_sfu_string; 736 case WB_POSIX_MAP_SFU20: 737 return wb_posix_map_sfu20_string; 738 case WB_POSIX_MAP_RFC2307: 739 return wb_posix_map_rfc2307_string; 740 case WB_POSIX_MAP_UNIXINFO: 741 return wb_posix_map_unixinfo_string; 742 default: 743 return wb_posix_map_unknown_string; 744 } 745} 746 747static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e, 748 enum wb_posix_mapping new_ad_map_type) 749{ 750 struct idmap_domain *dom; 751 struct idmap_ad_context *ctx; 752 753 if (e->state != NULL) { 754 dom = talloc_get_type(e->state, struct idmap_domain); 755 } else { 756 dom = TALLOC_ZERO_P(e, struct idmap_domain); 757 if (dom == NULL) { 758 DEBUG(0, ("Out of memory!\n")); 759 return NT_STATUS_NO_MEMORY; 760 } 761 e->state = dom; 762 } 763 764 if (e->domain != NULL) { 765 dom->name = talloc_strdup(dom, e->domain); 766 if (dom->name == NULL) { 767 DEBUG(0, ("Out of memory!\n")); 768 return NT_STATUS_NO_MEMORY; 769 } 770 } 771 772 if (dom->private_data != NULL) { 773 ctx = talloc_get_type(dom->private_data, 774 struct idmap_ad_context); 775 } else { 776 ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context); 777 if (ctx == NULL) { 778 DEBUG(0, ("Out of memory!\n")); 779 return NT_STATUS_NO_MEMORY; 780 } 781 ctx->ad_map_type = WB_POSIX_MAP_RFC2307; 782 dom->private_data = ctx; 783 } 784 785 if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) && 786 (ctx->ad_map_type != new_ad_map_type)) 787 { 788 DEBUG(2, ("nss_ad_generic_init: " 789 "Warning: overriding previously set posix map type " 790 "%s for domain %s with map type %s.\n", 791 ad_map_type_string(ctx->ad_map_type), 792 dom->name, 793 ad_map_type_string(new_ad_map_type))); 794 } 795 796 ctx->ad_map_type = new_ad_map_type; 797 798 return NT_STATUS_OK; 799} 800 801static NTSTATUS nss_sfu_init( struct nss_domain_entry *e ) 802{ 803 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU); 804} 805 806static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e ) 807{ 808 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20); 809} 810 811static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e ) 812{ 813 return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307); 814} 815 816 817/************************************************************************ 818 ***********************************************************************/ 819 820static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 821 const DOM_SID *sid, 822 TALLOC_CTX *mem_ctx, 823 ADS_STRUCT *ads, 824 LDAPMessage *msg, 825 const char **homedir, 826 const char **shell, 827 const char **gecos, 828 uint32 *gid ) 829{ 830 const char *attrs[] = {NULL, /* attr_homedir */ 831 NULL, /* attr_shell */ 832 NULL, /* attr_gecos */ 833 NULL, /* attr_gidnumber */ 834 NULL }; 835 char *filter = NULL; 836 LDAPMessage *msg_internal = NULL; 837 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 838 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 839 char *sidstr = NULL; 840 struct idmap_domain *dom; 841 struct idmap_ad_context *ctx; 842 843 DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n", 844 sid_string_dbg(sid), e->domain?e->domain:"NULL")); 845 846 /* Only do query if we are online */ 847 if (idmap_is_offline()) { 848 return NT_STATUS_FILE_IS_OFFLINE; 849 } 850 851 dom = talloc_get_type(e->state, struct idmap_domain); 852 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 853 854 ads_status = ad_idmap_cached_connection(dom); 855 if (!ADS_ERR_OK(ads_status)) { 856 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 857 } 858 859 if (!ctx->ad_schema) { 860 DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n")); 861 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 862 } 863 864 if (!sid || !homedir || !shell || !gecos) { 865 return NT_STATUS_INVALID_PARAMETER; 866 } 867 868 /* See if we can use the ADS connection struct swe were given */ 869 870 if (ads) { 871 DEBUG(10, ("nss_ad_get_info: using given ads connection and " 872 "LDAP message (%p)\n", msg)); 873 874 *homedir = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_homedir_attr ); 875 *shell = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_shell_attr ); 876 *gecos = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_gecos_attr ); 877 878 if (gid) { 879 if ( !ads_pull_uint32(ads, msg, ctx->ad_schema->posix_gidnumber_attr, gid ) ) 880 *gid = (uint32)-1; 881 } 882 883 nt_status = NT_STATUS_OK; 884 goto done; 885 } 886 887 /* Have to do our own query */ 888 889 DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our " 890 "own query\n")); 891 892 attrs[0] = ctx->ad_schema->posix_homedir_attr; 893 attrs[1] = ctx->ad_schema->posix_shell_attr; 894 attrs[2] = ctx->ad_schema->posix_gecos_attr; 895 attrs[3] = ctx->ad_schema->posix_gidnumber_attr; 896 897 sidstr = sid_binstring(mem_ctx, sid); 898 filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr); 899 TALLOC_FREE(sidstr); 900 901 if (!filter) { 902 nt_status = NT_STATUS_NO_MEMORY; 903 goto done; 904 } 905 906 ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs); 907 if (!ADS_ERR_OK(ads_status)) { 908 nt_status = ads_ntstatus(ads_status); 909 goto done; 910 } 911 912 *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr); 913 *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr); 914 *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr); 915 916 if (gid) { 917 if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid)) 918 *gid = (uint32)-1; 919 } 920 921 nt_status = NT_STATUS_OK; 922 923done: 924 if (msg_internal) { 925 ads_msgfree(ctx->ads, msg_internal); 926 } 927 928 return nt_status; 929} 930 931/********************************************************************** 932 *********************************************************************/ 933 934static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, 935 struct nss_domain_entry *e, 936 const char *name, 937 char **alias) 938{ 939 const char *attrs[] = {NULL, /* attr_uid */ 940 NULL }; 941 char *filter = NULL; 942 LDAPMessage *msg = NULL; 943 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 944 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 945 struct idmap_domain *dom; 946 struct idmap_ad_context *ctx = NULL; 947 948 /* Check incoming parameters */ 949 950 if ( !e || !e->domain || !name || !*alias) { 951 nt_status = NT_STATUS_INVALID_PARAMETER; 952 goto done; 953 } 954 955 /* Only do query if we are online */ 956 957 if (idmap_is_offline()) { 958 nt_status = NT_STATUS_FILE_IS_OFFLINE; 959 goto done; 960 } 961 962 dom = talloc_get_type(e->state, struct idmap_domain); 963 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 964 965 ads_status = ad_idmap_cached_connection(dom); 966 if (!ADS_ERR_OK(ads_status)) { 967 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 968 } 969 970 if (!ctx->ad_schema) { 971 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; 972 goto done; 973 } 974 975 attrs[0] = ctx->ad_schema->posix_uid_attr; 976 977 filter = talloc_asprintf(mem_ctx, 978 "(sAMAccountName=%s)", 979 name); 980 if (!filter) { 981 nt_status = NT_STATUS_NO_MEMORY; 982 goto done; 983 } 984 985 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); 986 if (!ADS_ERR_OK(ads_status)) { 987 nt_status = ads_ntstatus(ads_status); 988 goto done; 989 } 990 991 *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr); 992 993 if (!*alias) { 994 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 995 } 996 997 nt_status = NT_STATUS_OK; 998 999done: 1000 if (filter) { 1001 talloc_destroy(filter); 1002 } 1003 if (msg) { 1004 ads_msgfree(ctx->ads, msg); 1005 } 1006 1007 return nt_status; 1008} 1009 1010/********************************************************************** 1011 *********************************************************************/ 1012 1013static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx, 1014 struct nss_domain_entry *e, 1015 const char *alias, 1016 char **name ) 1017{ 1018 const char *attrs[] = {"sAMAccountName", 1019 NULL }; 1020 char *filter = NULL; 1021 LDAPMessage *msg = NULL; 1022 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 1023 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 1024 char *username; 1025 struct idmap_domain *dom; 1026 struct idmap_ad_context *ctx = NULL; 1027 1028 /* Check incoming parameters */ 1029 1030 if ( !alias || !name) { 1031 nt_status = NT_STATUS_INVALID_PARAMETER; 1032 goto done; 1033 } 1034 1035 /* Only do query if we are online */ 1036 1037 if (idmap_is_offline()) { 1038 nt_status = NT_STATUS_FILE_IS_OFFLINE; 1039 goto done; 1040 } 1041 1042 dom = talloc_get_type(e->state, struct idmap_domain); 1043 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); 1044 1045 ads_status = ad_idmap_cached_connection(dom); 1046 if (!ADS_ERR_OK(ads_status)) { 1047 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 1048 } 1049 1050 if (!ctx->ad_schema) { 1051 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; 1052 goto done; 1053 } 1054 1055 filter = talloc_asprintf(mem_ctx, 1056 "(%s=%s)", 1057 ctx->ad_schema->posix_uid_attr, 1058 alias); 1059 if (!filter) { 1060 nt_status = NT_STATUS_NO_MEMORY; 1061 goto done; 1062 } 1063 1064 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); 1065 if (!ADS_ERR_OK(ads_status)) { 1066 nt_status = ads_ntstatus(ads_status); 1067 goto done; 1068 } 1069 1070 username = ads_pull_string(ctx->ads, mem_ctx, msg, 1071 "sAMAccountName"); 1072 if (!username) { 1073 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 1074 } 1075 1076 *name = talloc_asprintf(mem_ctx, "%s\\%s", 1077 lp_workgroup(), 1078 username); 1079 if (!*name) { 1080 nt_status = NT_STATUS_NO_MEMORY; 1081 goto done; 1082 } 1083 1084 nt_status = NT_STATUS_OK; 1085 1086done: 1087 if (filter) { 1088 talloc_destroy(filter); 1089 } 1090 if (msg) { 1091 ads_msgfree(ctx->ads, msg); 1092 } 1093 1094 return nt_status; 1095} 1096 1097 1098/************************************************************************ 1099 ***********************************************************************/ 1100 1101static NTSTATUS nss_ad_close( void ) 1102{ 1103 /* nothing to do. All memory is free()'d by the idmap close_fn() */ 1104 1105 return NT_STATUS_OK; 1106} 1107 1108/************************************************************************ 1109 Function dispatch tables for the idmap and nss plugins 1110 ***********************************************************************/ 1111 1112static struct idmap_methods ad_methods = { 1113 .init = idmap_ad_initialize, 1114 .unixids_to_sids = idmap_ad_unixids_to_sids, 1115 .sids_to_unixids = idmap_ad_sids_to_unixids, 1116 .close_fn = idmap_ad_close 1117}; 1118 1119/* The SFU and RFC2307 NSS plugins share everything but the init 1120 function which sets the intended schema model to use */ 1121 1122static struct nss_info_methods nss_rfc2307_methods = { 1123 .init = nss_rfc2307_init, 1124 .get_nss_info = nss_ad_get_info, 1125 .map_to_alias = nss_ad_map_to_alias, 1126 .map_from_alias = nss_ad_map_from_alias, 1127 .close_fn = nss_ad_close 1128}; 1129 1130static struct nss_info_methods nss_sfu_methods = { 1131 .init = nss_sfu_init, 1132 .get_nss_info = nss_ad_get_info, 1133 .map_to_alias = nss_ad_map_to_alias, 1134 .map_from_alias = nss_ad_map_from_alias, 1135 .close_fn = nss_ad_close 1136}; 1137 1138static struct nss_info_methods nss_sfu20_methods = { 1139 .init = nss_sfu20_init, 1140 .get_nss_info = nss_ad_get_info, 1141 .map_to_alias = nss_ad_map_to_alias, 1142 .map_from_alias = nss_ad_map_from_alias, 1143 .close_fn = nss_ad_close 1144}; 1145 1146 1147 1148/************************************************************************ 1149 Initialize the plugins 1150 ***********************************************************************/ 1151 1152NTSTATUS idmap_ad_init(void) 1153{ 1154 static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL; 1155 static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL; 1156 static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL; 1157 static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL; 1158 1159 /* Always register the AD method first in order to get the 1160 idmap_domain interface called */ 1161 1162 if ( !NT_STATUS_IS_OK(status_idmap_ad) ) { 1163 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 1164 "ad", &ad_methods); 1165 if ( !NT_STATUS_IS_OK(status_idmap_ad) ) 1166 return status_idmap_ad; 1167 } 1168 1169 if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) { 1170 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, 1171 "rfc2307", &nss_rfc2307_methods ); 1172 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) ) 1173 return status_nss_rfc2307; 1174 } 1175 1176 if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) { 1177 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, 1178 "sfu", &nss_sfu_methods ); 1179 if ( !NT_STATUS_IS_OK(status_nss_sfu) ) 1180 return status_nss_sfu; 1181 } 1182 1183 if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) { 1184 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, 1185 "sfu20", &nss_sfu20_methods ); 1186 if ( !NT_STATUS_IS_OK(status_nss_sfu20) ) 1187 return status_nss_sfu20; 1188 } 1189 1190 return NT_STATUS_OK; 1191} 1192 1193