1/* 2 Unix SMB/CIFS implementation. 3 4 Map SIDs to unixids and back 5 6 Copyright (C) Kai Blin 2008 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "auth/auth.h" 24#include "librpc/gen_ndr/lsa.h" 25#include "librpc/gen_ndr/samr.h" 26#include "librpc/gen_ndr/ndr_security.h" 27#include "lib/ldb/include/ldb.h" 28#include "lib/ldb/include/ldb_errors.h" 29#include "lib/ldb_wrap.h" 30#include "param/param.h" 31#include "winbind/idmap.h" 32#include "libcli/security/security.h" 33#include "libcli/ldap/ldap_ndr.h" 34 35/** 36 * Get uid/gid bounds from idmap database 37 * 38 * \param idmap_ctx idmap context to use 39 * \param low lower uid/gid bound is stored here 40 * \param high upper uid/gid bound is stored here 41 * \return 0 on success, nonzero on failure 42 */ 43static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low, 44 uint32_t *high) 45{ 46 int ret = -1; 47 struct ldb_context *ldb = idmap_ctx->ldb_ctx; 48 struct ldb_dn *dn; 49 struct ldb_result *res = NULL; 50 TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx); 51 uint32_t lower_bound = (uint32_t) -1; 52 uint32_t upper_bound = (uint32_t) -1; 53 54 dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG"); 55 if (dn == NULL) goto failed; 56 57 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL); 58 if (ret != LDB_SUCCESS) goto failed; 59 60 if (res->count != 1) { 61 ret = -1; 62 goto failed; 63 } 64 65 lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1); 66 if (lower_bound != (uint32_t) -1) { 67 ret = LDB_SUCCESS; 68 } else { 69 ret = -1; 70 goto failed; 71 } 72 73 upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1); 74 if (upper_bound != (uint32_t) -1) { 75 ret = LDB_SUCCESS; 76 } else { 77 ret = -1; 78 } 79 80failed: 81 talloc_free(tmp_ctx); 82 *low = lower_bound; 83 *high = upper_bound; 84 return ret; 85} 86 87/** 88 * Add a dom_sid structure to a ldb_message 89 * \param idmap_ctx idmap context to use 90 * \param mem_ctx talloc context to use 91 * \param ldb_message ldb message to add dom_sid to 92 * \param attr_name name of the attribute to store the dom_sid in 93 * \param sid dom_sid to store 94 * \return 0 on success, an ldb error code on failure. 95 */ 96static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx, 97 TALLOC_CTX *mem_ctx, struct ldb_message *msg, 98 const char *attr_name, const struct dom_sid *sid) 99{ 100 struct ldb_val val; 101 enum ndr_err_code ndr_err; 102 103 ndr_err = ndr_push_struct_blob(&val, mem_ctx, 104 lp_iconv_convenience(idmap_ctx->lp_ctx), 105 sid, 106 (ndr_push_flags_fn_t)ndr_push_dom_sid); 107 108 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 109 return -1; 110 } 111 112 return ldb_msg_add_value(msg, attr_name, &val, NULL); 113} 114 115/** 116 * Get a dom_sid structure from a ldb message. 117 * 118 * \param mem_ctx talloc context to allocate dom_sid memory in 119 * \param msg ldb_message to get dom_sid from 120 * \param attr_name key that has the dom_sid as data 121 * \return dom_sid structure on success, NULL on failure 122 */ 123static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx, 124 struct ldb_message *msg, const char *attr_name) 125{ 126 struct dom_sid *sid; 127 const struct ldb_val *val; 128 enum ndr_err_code ndr_err; 129 130 val = ldb_msg_find_ldb_val(msg, attr_name); 131 if (val == NULL) { 132 return NULL; 133 } 134 135 sid = talloc(mem_ctx, struct dom_sid); 136 if (sid == NULL) { 137 return NULL; 138 } 139 140 ndr_err = ndr_pull_struct_blob(val, sid, NULL, sid, 141 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 143 talloc_free(sid); 144 return NULL; 145 } 146 147 return sid; 148} 149 150/** 151 * Initialize idmap context 152 * 153 * talloc_free to close. 154 * 155 * \param mem_ctx talloc context to use. 156 * \return allocated idmap_context on success, NULL on error 157 */ 158struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx, 159 struct tevent_context *ev_ctx, 160 struct loadparm_context *lp_ctx) 161{ 162 struct idmap_context *idmap_ctx; 163 164 idmap_ctx = talloc(mem_ctx, struct idmap_context); 165 if (idmap_ctx == NULL) { 166 return NULL; 167 } 168 169 idmap_ctx->lp_ctx = lp_ctx; 170 171 idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, 172 lp_idmap_url(lp_ctx), 173 system_session(mem_ctx, lp_ctx), 174 NULL, 0, NULL); 175 if (idmap_ctx->ldb_ctx == NULL) { 176 return NULL; 177 } 178 179 idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2"); 180 if (idmap_ctx->unix_groups_sid == NULL) { 181 return NULL; 182 } 183 184 idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1"); 185 if (idmap_ctx->unix_users_sid == NULL) { 186 return NULL; 187 } 188 189 return idmap_ctx; 190} 191 192/** 193 * Convert an unixid to the corresponding SID 194 * 195 * \param idmap_ctx idmap context to use 196 * \param mem_ctx talloc context the memory for the struct dom_sid is allocated 197 * from. 198 * \param unixid pointer to a unixid struct to convert 199 * \param sid pointer that will take the struct dom_sid pointer if the mapping 200 * succeeds. 201 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not 202 * possible or some other NTSTATUS that is more descriptive on failure. 203 */ 204 205NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, 206 const struct unixid *unixid, struct dom_sid **sid) 207{ 208 int ret; 209 NTSTATUS status = NT_STATUS_NONE_MAPPED; 210 struct ldb_context *ldb = idmap_ctx->ldb_ctx; 211 struct ldb_result *res = NULL; 212 struct dom_sid *unix_sid, *new_sid; 213 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 214 const char *id_type; 215 216 switch (unixid->type) { 217 case ID_TYPE_UID: 218 id_type = "ID_TYPE_UID"; 219 break; 220 case ID_TYPE_GID: 221 id_type = "ID_TYPE_GID"; 222 break; 223 default: 224 DEBUG(1, ("unixid->type must be type gid or uid\n")); 225 status = NT_STATUS_NONE_MAPPED; 226 goto failed; 227 } 228 229 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, 230 NULL, "(&(|(type=ID_TYPE_BOTH)(type=%s))" 231 "(xidNumber=%u))", id_type, unixid->id); 232 if (ret != LDB_SUCCESS) { 233 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); 234 status = NT_STATUS_NONE_MAPPED; 235 goto failed; 236 } 237 238 if (res->count == 1) { 239 *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0], 240 "objectSid"); 241 if (*sid == NULL) { 242 DEBUG(1, ("Failed to get sid from db: %u\n", ret)); 243 status = NT_STATUS_NONE_MAPPED; 244 goto failed; 245 } 246 talloc_free(tmp_ctx); 247 return NT_STATUS_OK; 248 } 249 250 DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n")); 251 252 /* For local users/groups , we just create a rid = uid/gid */ 253 if (unixid->type == ID_TYPE_UID) { 254 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1"); 255 } else { 256 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2"); 257 } 258 if (unix_sid == NULL) { 259 status = NT_STATUS_NO_MEMORY; 260 goto failed; 261 } 262 263 new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id); 264 if (new_sid == NULL) { 265 status = NT_STATUS_NO_MEMORY; 266 goto failed; 267 } 268 269 *sid = new_sid; 270 talloc_free(tmp_ctx); 271 return NT_STATUS_OK; 272 273failed: 274 talloc_free(tmp_ctx); 275 return status; 276} 277 278 279/** 280 * Map a SID to an unixid struct. 281 * 282 * If no mapping exists, a new mapping will be created. 283 * 284 * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true 285 * \todo Fix backwards compatibility for Samba3 286 * 287 * \param idmap_ctx idmap context to use 288 * \param mem_ctx talloc context to use 289 * \param sid SID to map to an unixid struct 290 * \param unixid pointer to a unixid struct pointer 291 * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from 292 * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the 293 * mapping failed. 294 */ 295NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, 296 const struct dom_sid *sid, struct unixid **unixid) 297{ 298 int ret; 299 NTSTATUS status = NT_STATUS_NONE_MAPPED; 300 struct ldb_context *ldb = idmap_ctx->ldb_ctx; 301 struct ldb_dn *dn; 302 struct ldb_message *hwm_msg, *map_msg; 303 struct ldb_result *res = NULL; 304 int trans; 305 uint32_t low, high, hwm, new_xid; 306 char *sid_string, *unixid_string, *hwm_string; 307 bool hwm_entry_exists; 308 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 309 310 if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) { 311 uint32_t rid; 312 DEBUG(6, ("This is a local unix uid, just calculate that.\n")); 313 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid); 314 if (!NT_STATUS_IS_OK(status)) goto failed; 315 316 *unixid = talloc(mem_ctx, struct unixid); 317 if (*unixid == NULL) { 318 status = NT_STATUS_NO_MEMORY; 319 goto failed; 320 } 321 (*unixid)->id = rid; 322 (*unixid)->type = ID_TYPE_UID; 323 324 talloc_free(tmp_ctx); 325 return NT_STATUS_OK; 326 } 327 328 if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) { 329 uint32_t rid; 330 DEBUG(6, ("This is a local unix gid, just calculate that.\n")); 331 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid); 332 if (!NT_STATUS_IS_OK(status)) goto failed; 333 334 *unixid = talloc(mem_ctx, struct unixid); 335 if (*unixid == NULL) { 336 status = NT_STATUS_NO_MEMORY; 337 goto failed; 338 } 339 (*unixid)->id = rid; 340 (*unixid)->type = ID_TYPE_GID; 341 342 talloc_free(tmp_ctx); 343 return NT_STATUS_OK; 344 } 345 346 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, 347 NULL, "(&(objectClass=sidMap)(objectSid=%s))", 348 ldap_encode_ndr_dom_sid(tmp_ctx, sid)); 349 if (ret != LDB_SUCCESS) { 350 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); 351 status = NT_STATUS_NONE_MAPPED; 352 goto failed; 353 } 354 355 if (res->count == 1) { 356 const char *type = ldb_msg_find_attr_as_string(res->msgs[0], 357 "type", NULL); 358 new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", 359 -1); 360 if (new_xid == (uint32_t) -1) { 361 DEBUG(1, ("Invalid xid mapping.\n")); 362 status = NT_STATUS_NONE_MAPPED; 363 goto failed; 364 } 365 366 if (type == NULL) { 367 DEBUG(1, ("Invalid type for mapping entry.\n")); 368 status = NT_STATUS_NONE_MAPPED; 369 goto failed; 370 } 371 372 *unixid = talloc(mem_ctx, struct unixid); 373 if (*unixid == NULL) { 374 status = NT_STATUS_NO_MEMORY; 375 goto failed; 376 } 377 378 (*unixid)->id = new_xid; 379 380 if (strcmp(type, "ID_TYPE_BOTH") == 0) { 381 (*unixid)->type = ID_TYPE_BOTH; 382 } else if (strcmp(type, "ID_TYPE_UID") == 0) { 383 (*unixid)->type = ID_TYPE_UID; 384 } else { 385 (*unixid)->type = ID_TYPE_GID; 386 } 387 388 talloc_free(tmp_ctx); 389 return NT_STATUS_OK; 390 } 391 392 DEBUG(6, ("No existing mapping found, attempting to create one.\n")); 393 394 trans = ldb_transaction_start(ldb); 395 if (trans != LDB_SUCCESS) { 396 status = NT_STATUS_NONE_MAPPED; 397 goto failed; 398 } 399 400 /* Redo the search to make sure noone changed the mapping while we 401 * weren't looking */ 402 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, 403 NULL, "(&(objectClass=sidMap)(objectSid=%s))", 404 ldap_encode_ndr_dom_sid(tmp_ctx, sid)); 405 if (ret != LDB_SUCCESS) { 406 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); 407 status = NT_STATUS_NONE_MAPPED; 408 goto failed; 409 } 410 411 if (res->count > 0) { 412 DEBUG(1, ("Database changed while trying to add a sidmap.\n")); 413 status = NT_STATUS_RETRY; 414 goto failed; 415 } 416 417 /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be 418 * resolved here. */ 419 420 ret = idmap_get_bounds(idmap_ctx, &low, &high); 421 if (ret != LDB_SUCCESS) { 422 status = NT_STATUS_NONE_MAPPED; 423 goto failed; 424 } 425 426 dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG"); 427 if (dn == NULL) { 428 status = NT_STATUS_NO_MEMORY; 429 goto failed; 430 } 431 432 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL); 433 if (ret != LDB_SUCCESS) { 434 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); 435 status = NT_STATUS_NONE_MAPPED; 436 goto failed; 437 } 438 439 if (res->count != 1) { 440 DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n")); 441 status = NT_STATUS_NONE_MAPPED; 442 goto failed; 443 } 444 445 hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1); 446 if (hwm == (uint32_t)-1) { 447 hwm = low; 448 hwm_entry_exists = false; 449 } else { 450 hwm_entry_exists = true; 451 } 452 453 if (hwm > high) { 454 DEBUG(1, ("Out of xids to allocate.\n")); 455 status = NT_STATUS_NONE_MAPPED; 456 goto failed; 457 } 458 459 hwm_msg = ldb_msg_new(tmp_ctx); 460 if (hwm_msg == NULL) { 461 DEBUG(1, ("Out of memory when creating ldb_message\n")); 462 status = NT_STATUS_NO_MEMORY; 463 goto failed; 464 } 465 466 hwm_msg->dn = dn; 467 468 new_xid = hwm; 469 hwm++; 470 471 hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm); 472 if (hwm_string == NULL) { 473 status = NT_STATUS_NO_MEMORY; 474 goto failed; 475 } 476 477 sid_string = dom_sid_string(tmp_ctx, sid); 478 if (sid_string == NULL) { 479 status = NT_STATUS_NO_MEMORY; 480 goto failed; 481 } 482 483 unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid); 484 if (unixid_string == NULL) { 485 status = NT_STATUS_NO_MEMORY; 486 goto failed; 487 } 488 489 if (hwm_entry_exists) { 490 struct ldb_message_element *els; 491 struct ldb_val *vals; 492 493 /* We're modifying the entry, not just adding a new one. */ 494 els = talloc_array(tmp_ctx, struct ldb_message_element, 2); 495 if (els == NULL) { 496 status = NT_STATUS_NO_MEMORY; 497 goto failed; 498 } 499 500 vals = talloc_array(tmp_ctx, struct ldb_val, 2); 501 if (els == NULL) { 502 status = NT_STATUS_NO_MEMORY; 503 goto failed; 504 } 505 506 hwm_msg->num_elements = 2; 507 hwm_msg->elements = els; 508 509 els[0].num_values = 1; 510 els[0].values = &vals[0]; 511 els[0].flags = LDB_FLAG_MOD_DELETE; 512 els[0].name = talloc_strdup(tmp_ctx, "xidNumber"); 513 if (els[0].name == NULL) { 514 status = NT_STATUS_NO_MEMORY; 515 goto failed; 516 } 517 518 els[1].num_values = 1; 519 els[1].values = &vals[1]; 520 els[1].flags = LDB_FLAG_MOD_ADD; 521 els[1].name = els[0].name; 522 523 vals[0].data = (uint8_t *)unixid_string; 524 vals[0].length = strlen(unixid_string); 525 vals[1].data = (uint8_t *)hwm_string; 526 vals[1].length = strlen(hwm_string); 527 } else { 528 ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD, 529 NULL); 530 if (ret != LDB_SUCCESS) { 531 status = NT_STATUS_NONE_MAPPED; 532 goto failed; 533 } 534 535 ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string); 536 if (ret != LDB_SUCCESS) 537 { 538 status = NT_STATUS_NONE_MAPPED; 539 goto failed; 540 } 541 } 542 543 ret = ldb_modify(ldb, hwm_msg); 544 if (ret != LDB_SUCCESS) { 545 DEBUG(1, ("Updating the xid high water mark failed: %s\n", 546 ldb_errstring(ldb))); 547 status = NT_STATUS_NONE_MAPPED; 548 goto failed; 549 } 550 551 map_msg = ldb_msg_new(tmp_ctx); 552 if (map_msg == NULL) { 553 status = NT_STATUS_NO_MEMORY; 554 goto failed; 555 } 556 557 map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string); 558 if (map_msg->dn == NULL) { 559 status = NT_STATUS_NO_MEMORY; 560 goto failed; 561 } 562 563 ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string); 564 if (ret != LDB_SUCCESS) { 565 status = NT_STATUS_NONE_MAPPED; 566 goto failed; 567 } 568 569 ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid", 570 sid); 571 if (ret != LDB_SUCCESS) { 572 status = NT_STATUS_NONE_MAPPED; 573 goto failed; 574 } 575 576 ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap"); 577 if (ret != LDB_SUCCESS) { 578 status = NT_STATUS_NONE_MAPPED; 579 goto failed; 580 } 581 582 ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH"); 583 if (ret != LDB_SUCCESS) { 584 status = NT_STATUS_NONE_MAPPED; 585 goto failed; 586 } 587 588 ret = ldb_msg_add_string(map_msg, "cn", sid_string); 589 if (ret != LDB_SUCCESS) { 590 status = NT_STATUS_NONE_MAPPED; 591 goto failed; 592 } 593 594 ret = ldb_add(ldb, map_msg); 595 if (ret != LDB_SUCCESS) { 596 DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb))); 597 status = NT_STATUS_NONE_MAPPED; 598 goto failed; 599 } 600 601 trans = ldb_transaction_commit(ldb); 602 if (trans != LDB_SUCCESS) { 603 DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb))); 604 status = NT_STATUS_NONE_MAPPED; 605 goto failed; 606 } 607 608 *unixid = talloc(mem_ctx, struct unixid); 609 if (*unixid == NULL) { 610 status = NT_STATUS_NO_MEMORY; 611 goto failed; 612 } 613 614 (*unixid)->id = new_xid; 615 (*unixid)->type = ID_TYPE_BOTH; 616 talloc_free(tmp_ctx); 617 return NT_STATUS_OK; 618 619failed: 620 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb); 621 talloc_free(tmp_ctx); 622 return status; 623} 624 625/** 626 * Convert an array of unixids to the corresponding array of SIDs 627 * 628 * \param idmap_ctx idmap context to use 629 * \param mem_ctx talloc context the memory for the dom_sids is allocated 630 * from. 631 * \param count length of id_mapping array. 632 * \param id array of id_mappings. 633 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not 634 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some 635 * did not. 636 */ 637 638NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx, 639 TALLOC_CTX *mem_ctx, int count, 640 struct id_mapping *id) 641{ 642 int i; 643 int error_count = 0; 644 645 for (i = 0; i < count; ++i) { 646 id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx, 647 id[i].unixid, &id[i].sid); 648 if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) { 649 id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx, 650 id[i].unixid, 651 &id[i].sid); 652 } 653 if (!NT_STATUS_IS_OK(id[i].status)) { 654 DEBUG(1, ("idmapping xid_to_sid failed for id[%d]\n", i)); 655 error_count++; 656 } 657 } 658 659 if (error_count == count) { 660 /* Mapping did not work at all. */ 661 return NT_STATUS_NONE_MAPPED; 662 } else if (error_count > 0) { 663 /* Some mappings worked, some did not. */ 664 return STATUS_SOME_UNMAPPED; 665 } else { 666 return NT_STATUS_OK; 667 } 668} 669 670/** 671 * Convert an array of SIDs to the corresponding array of unixids 672 * 673 * \param idmap_ctx idmap context to use 674 * \param mem_ctx talloc context the memory for the unixids is allocated 675 * from. 676 * \param count length of id_mapping array. 677 * \param id array of id_mappings. 678 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not 679 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some 680 * did not. 681 */ 682 683NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx, 684 TALLOC_CTX *mem_ctx, int count, 685 struct id_mapping *id) 686{ 687 int i; 688 int error_count = 0; 689 690 for (i = 0; i < count; ++i) { 691 id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx, 692 id[i].sid, &id[i].unixid); 693 if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) { 694 id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx, 695 id[i].sid, 696 &id[i].unixid); 697 } 698 if (!NT_STATUS_IS_OK(id[i].status)) { 699 DEBUG(1, ("idmapping sid_to_xid failed for id[%d]\n", i)); 700 error_count++; 701 } 702 } 703 704 if (error_count == count) { 705 /* Mapping did not work at all. */ 706 return NT_STATUS_NONE_MAPPED; 707 } else if (error_count > 0) { 708 /* Some mappings worked, some did not. */ 709 return STATUS_SOME_UNMAPPED; 710 } else { 711 return NT_STATUS_OK; 712 } 713} 714 715