s4:idmap Adjust code to new idmap structure names and layout.
[Samba/gebeck_regimport.git] / source4 / winbind / idmap.c
blobb024777cf00810cad9aa32cd209232f1ceed6d15
1 /*
2 Unix SMB/CIFS implementation.
4 Map SIDs to unixids and back
6 Copyright (C) Kai Blin 2008
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.
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.
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/>.
22 #include "includes.h"
23 #include "auth/auth.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb_wrap.h"
27 #include "param/param.h"
28 #include "winbind/idmap.h"
29 #include "libcli/security/security.h"
30 #include "libcli/ldap/ldap_ndr.h"
32 /**
33 * Get uid/gid bounds from idmap database
35 * \param idmap_ctx idmap context to use
36 * \param low lower uid/gid bound is stored here
37 * \param high upper uid/gid bound is stored here
38 * \return 0 on success, nonzero on failure
40 static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low,
41 uint32_t *high)
43 int ret = -1;
44 struct ldb_context *ldb = idmap_ctx->ldb_ctx;
45 struct ldb_dn *dn;
46 struct ldb_result *res = NULL;
47 TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx);
48 uint32_t lower_bound = (uint32_t) -1;
49 uint32_t upper_bound = (uint32_t) -1;
51 dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
52 if (dn == NULL) goto failed;
54 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
55 if (ret != LDB_SUCCESS) goto failed;
57 if (res->count != 1) {
58 ret = -1;
59 goto failed;
62 lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1);
63 if (lower_bound != (uint32_t) -1) {
64 ret = LDB_SUCCESS;
65 } else {
66 ret = -1;
67 goto failed;
70 upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1);
71 if (upper_bound != (uint32_t) -1) {
72 ret = LDB_SUCCESS;
73 } else {
74 ret = -1;
77 failed:
78 talloc_free(tmp_ctx);
79 *low = lower_bound;
80 *high = upper_bound;
81 return ret;
84 /**
85 * Add a dom_sid structure to a ldb_message
86 * \param idmap_ctx idmap context to use
87 * \param mem_ctx talloc context to use
88 * \param ldb_message ldb message to add dom_sid to
89 * \param attr_name name of the attribute to store the dom_sid in
90 * \param sid dom_sid to store
91 * \return 0 on success, an ldb error code on failure.
93 static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx,
94 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
95 const char *attr_name, const struct dom_sid *sid)
97 struct ldb_val val;
98 enum ndr_err_code ndr_err;
100 ndr_err = ndr_push_struct_blob(&val, mem_ctx, sid,
101 (ndr_push_flags_fn_t)ndr_push_dom_sid);
103 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
104 return -1;
107 return ldb_msg_add_value(msg, attr_name, &val, NULL);
111 * Get a dom_sid structure from a ldb message.
113 * \param mem_ctx talloc context to allocate dom_sid memory in
114 * \param msg ldb_message to get dom_sid from
115 * \param attr_name key that has the dom_sid as data
116 * \return dom_sid structure on success, NULL on failure
118 static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
119 struct ldb_message *msg, const char *attr_name)
121 struct dom_sid *sid;
122 const struct ldb_val *val;
123 enum ndr_err_code ndr_err;
125 val = ldb_msg_find_ldb_val(msg, attr_name);
126 if (val == NULL) {
127 return NULL;
130 sid = talloc(mem_ctx, struct dom_sid);
131 if (sid == NULL) {
132 return NULL;
135 ndr_err = ndr_pull_struct_blob(val, sid, sid,
136 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
137 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
138 talloc_free(sid);
139 return NULL;
142 return sid;
146 * Initialize idmap context
148 * talloc_free to close.
150 * \param mem_ctx talloc context to use.
151 * \return allocated idmap_context on success, NULL on error
153 struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
154 struct tevent_context *ev_ctx,
155 struct loadparm_context *lp_ctx)
157 struct idmap_context *idmap_ctx;
159 idmap_ctx = talloc(mem_ctx, struct idmap_context);
160 if (idmap_ctx == NULL) {
161 return NULL;
164 idmap_ctx->lp_ctx = lp_ctx;
166 idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx,
167 lp_idmap_url(lp_ctx),
168 system_session(lp_ctx),
169 NULL, 0);
170 if (idmap_ctx->ldb_ctx == NULL) {
171 return NULL;
174 idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2");
175 if (idmap_ctx->unix_groups_sid == NULL) {
176 return NULL;
179 idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1");
180 if (idmap_ctx->unix_users_sid == NULL) {
181 return NULL;
184 return idmap_ctx;
188 * Convert an unixid to the corresponding SID
190 * \param idmap_ctx idmap context to use
191 * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
192 * from.
193 * \param unixid pointer to a unixid struct to convert
194 * \param sid pointer that will take the struct dom_sid pointer if the mapping
195 * succeeds.
196 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
197 * possible or some other NTSTATUS that is more descriptive on failure.
200 static NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx,
201 TALLOC_CTX *mem_ctx,
202 const struct unixid *unixid,
203 struct dom_sid **sid)
205 int ret;
206 NTSTATUS status = NT_STATUS_NONE_MAPPED;
207 struct ldb_context *ldb = idmap_ctx->ldb_ctx;
208 struct ldb_result *res = NULL;
209 struct dom_sid *unix_sid, *new_sid;
210 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
211 const char *id_type;
213 switch (unixid->type) {
214 case ID_TYPE_UID:
215 id_type = "ID_TYPE_UID";
216 break;
217 case ID_TYPE_GID:
218 id_type = "ID_TYPE_GID";
219 break;
220 default:
221 DEBUG(1, ("unixid->type must be type gid or uid\n"));
222 status = NT_STATUS_NONE_MAPPED;
223 goto failed;
226 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
227 NULL, "(&(|(type=ID_TYPE_BOTH)(type=%s))"
228 "(xidNumber=%u))", id_type, unixid->id);
229 if (ret != LDB_SUCCESS) {
230 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
231 status = NT_STATUS_NONE_MAPPED;
232 goto failed;
235 if (res->count == 1) {
236 *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
237 "objectSid");
238 if (*sid == NULL) {
239 DEBUG(1, ("Failed to get sid from db: %u\n", ret));
240 status = NT_STATUS_NONE_MAPPED;
241 goto failed;
243 talloc_free(tmp_ctx);
244 return NT_STATUS_OK;
247 DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n"));
249 /* For local users/groups , we just create a rid = uid/gid */
250 if (unixid->type == ID_TYPE_UID) {
251 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1");
252 } else {
253 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2");
255 if (unix_sid == NULL) {
256 status = NT_STATUS_NO_MEMORY;
257 goto failed;
260 new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id);
261 if (new_sid == NULL) {
262 status = NT_STATUS_NO_MEMORY;
263 goto failed;
266 *sid = new_sid;
267 talloc_free(tmp_ctx);
268 return NT_STATUS_OK;
270 failed:
271 talloc_free(tmp_ctx);
272 return status;
277 * Map a SID to an unixid struct.
279 * If no mapping exists, a new mapping will be created.
281 * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true
282 * \todo Fix backwards compatibility for Samba3
284 * \param idmap_ctx idmap context to use
285 * \param mem_ctx talloc context to use
286 * \param sid SID to map to an unixid struct
287 * \param unixid pointer to a unixid struct
288 * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from
289 * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the
290 * mapping failed.
292 static NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx,
293 TALLOC_CTX *mem_ctx,
294 const struct dom_sid *sid,
295 struct unixid *unixid)
297 int ret;
298 NTSTATUS status = NT_STATUS_NONE_MAPPED;
299 struct ldb_context *ldb = idmap_ctx->ldb_ctx;
300 struct ldb_dn *dn;
301 struct ldb_message *hwm_msg, *map_msg;
302 struct ldb_result *res = NULL;
303 int trans;
304 uint32_t low, high, hwm, new_xid;
305 char *sid_string, *unixid_string, *hwm_string;
306 bool hwm_entry_exists;
307 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
309 if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) {
310 uint32_t rid;
311 DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
312 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
313 if (!NT_STATUS_IS_OK(status)) goto failed;
315 unixid->id = rid;
316 unixid->type = ID_TYPE_UID;
318 talloc_free(tmp_ctx);
319 return NT_STATUS_OK;
322 if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) {
323 uint32_t rid;
324 DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
325 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
326 if (!NT_STATUS_IS_OK(status)) goto failed;
328 unixid->id = rid;
329 unixid->type = ID_TYPE_GID;
331 talloc_free(tmp_ctx);
332 return NT_STATUS_OK;
335 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
336 NULL, "(&(objectClass=sidMap)(objectSid=%s))",
337 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
338 if (ret != LDB_SUCCESS) {
339 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
340 status = NT_STATUS_NONE_MAPPED;
341 goto failed;
344 if (res->count == 1) {
345 const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
346 "type", NULL);
347 new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
348 -1);
349 if (new_xid == (uint32_t) -1) {
350 DEBUG(1, ("Invalid xid mapping.\n"));
351 status = NT_STATUS_NONE_MAPPED;
352 goto failed;
355 if (type == NULL) {
356 DEBUG(1, ("Invalid type for mapping entry.\n"));
357 status = NT_STATUS_NONE_MAPPED;
358 goto failed;
361 unixid->id = new_xid;
363 if (strcmp(type, "ID_TYPE_BOTH") == 0) {
364 unixid->type = ID_TYPE_BOTH;
365 } else if (strcmp(type, "ID_TYPE_UID") == 0) {
366 unixid->type = ID_TYPE_UID;
367 } else {
368 unixid->type = ID_TYPE_GID;
371 talloc_free(tmp_ctx);
372 return NT_STATUS_OK;
375 DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
377 trans = ldb_transaction_start(ldb);
378 if (trans != LDB_SUCCESS) {
379 status = NT_STATUS_NONE_MAPPED;
380 goto failed;
383 /* Redo the search to make sure noone changed the mapping while we
384 * weren't looking */
385 ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
386 NULL, "(&(objectClass=sidMap)(objectSid=%s))",
387 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
388 if (ret != LDB_SUCCESS) {
389 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
390 status = NT_STATUS_NONE_MAPPED;
391 goto failed;
394 if (res->count > 0) {
395 DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
396 status = NT_STATUS_RETRY;
397 goto failed;
400 /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be
401 * resolved here. */
403 ret = idmap_get_bounds(idmap_ctx, &low, &high);
404 if (ret != LDB_SUCCESS) {
405 status = NT_STATUS_NONE_MAPPED;
406 goto failed;
409 dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
410 if (dn == NULL) {
411 status = NT_STATUS_NO_MEMORY;
412 goto failed;
415 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
416 if (ret != LDB_SUCCESS) {
417 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
418 status = NT_STATUS_NONE_MAPPED;
419 goto failed;
422 if (res->count != 1) {
423 DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
424 status = NT_STATUS_NONE_MAPPED;
425 goto failed;
428 hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
429 if (hwm == (uint32_t)-1) {
430 hwm = low;
431 hwm_entry_exists = false;
432 } else {
433 hwm_entry_exists = true;
436 if (hwm > high) {
437 DEBUG(1, ("Out of xids to allocate.\n"));
438 status = NT_STATUS_NONE_MAPPED;
439 goto failed;
442 hwm_msg = ldb_msg_new(tmp_ctx);
443 if (hwm_msg == NULL) {
444 DEBUG(1, ("Out of memory when creating ldb_message\n"));
445 status = NT_STATUS_NO_MEMORY;
446 goto failed;
449 hwm_msg->dn = dn;
451 new_xid = hwm;
452 hwm++;
454 hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
455 if (hwm_string == NULL) {
456 status = NT_STATUS_NO_MEMORY;
457 goto failed;
460 sid_string = dom_sid_string(tmp_ctx, sid);
461 if (sid_string == NULL) {
462 status = NT_STATUS_NO_MEMORY;
463 goto failed;
466 unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
467 if (unixid_string == NULL) {
468 status = NT_STATUS_NO_MEMORY;
469 goto failed;
472 if (hwm_entry_exists) {
473 struct ldb_message_element *els;
474 struct ldb_val *vals;
476 /* We're modifying the entry, not just adding a new one. */
477 els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
478 if (els == NULL) {
479 status = NT_STATUS_NO_MEMORY;
480 goto failed;
483 vals = talloc_array(tmp_ctx, struct ldb_val, 2);
484 if (els == NULL) {
485 status = NT_STATUS_NO_MEMORY;
486 goto failed;
489 hwm_msg->num_elements = 2;
490 hwm_msg->elements = els;
492 els[0].num_values = 1;
493 els[0].values = &vals[0];
494 els[0].flags = LDB_FLAG_MOD_DELETE;
495 els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
496 if (els[0].name == NULL) {
497 status = NT_STATUS_NO_MEMORY;
498 goto failed;
501 els[1].num_values = 1;
502 els[1].values = &vals[1];
503 els[1].flags = LDB_FLAG_MOD_ADD;
504 els[1].name = els[0].name;
506 vals[0].data = (uint8_t *)unixid_string;
507 vals[0].length = strlen(unixid_string);
508 vals[1].data = (uint8_t *)hwm_string;
509 vals[1].length = strlen(hwm_string);
510 } else {
511 ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
512 NULL);
513 if (ret != LDB_SUCCESS) {
514 status = NT_STATUS_NONE_MAPPED;
515 goto failed;
518 ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
519 if (ret != LDB_SUCCESS)
521 status = NT_STATUS_NONE_MAPPED;
522 goto failed;
526 ret = ldb_modify(ldb, hwm_msg);
527 if (ret != LDB_SUCCESS) {
528 DEBUG(1, ("Updating the xid high water mark failed: %s\n",
529 ldb_errstring(ldb)));
530 status = NT_STATUS_NONE_MAPPED;
531 goto failed;
534 map_msg = ldb_msg_new(tmp_ctx);
535 if (map_msg == NULL) {
536 status = NT_STATUS_NO_MEMORY;
537 goto failed;
540 map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string);
541 if (map_msg->dn == NULL) {
542 status = NT_STATUS_NO_MEMORY;
543 goto failed;
546 ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
547 if (ret != LDB_SUCCESS) {
548 status = NT_STATUS_NONE_MAPPED;
549 goto failed;
552 ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
553 sid);
554 if (ret != LDB_SUCCESS) {
555 status = NT_STATUS_NONE_MAPPED;
556 goto failed;
559 ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
560 if (ret != LDB_SUCCESS) {
561 status = NT_STATUS_NONE_MAPPED;
562 goto failed;
565 ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH");
566 if (ret != LDB_SUCCESS) {
567 status = NT_STATUS_NONE_MAPPED;
568 goto failed;
571 ret = ldb_msg_add_string(map_msg, "cn", sid_string);
572 if (ret != LDB_SUCCESS) {
573 status = NT_STATUS_NONE_MAPPED;
574 goto failed;
577 ret = ldb_add(ldb, map_msg);
578 if (ret != LDB_SUCCESS) {
579 DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb)));
580 status = NT_STATUS_NONE_MAPPED;
581 goto failed;
584 trans = ldb_transaction_commit(ldb);
585 if (trans != LDB_SUCCESS) {
586 DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb)));
587 status = NT_STATUS_NONE_MAPPED;
588 goto failed;
591 unixid->id = new_xid;
592 unixid->type = ID_TYPE_BOTH;
593 talloc_free(tmp_ctx);
594 return NT_STATUS_OK;
596 failed:
597 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
598 talloc_free(tmp_ctx);
599 return status;
603 * Convert an array of unixids to the corresponding array of SIDs
605 * \param idmap_ctx idmap context to use
606 * \param mem_ctx talloc context the memory for the dom_sids is allocated
607 * from.
608 * \param count length of id_mapping array.
609 * \param id array of id_mappings.
610 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
611 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
612 * did not.
615 NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx,
616 TALLOC_CTX *mem_ctx, int count,
617 struct id_map *id)
619 int i;
620 int error_count = 0;
621 NTSTATUS status;
623 for (i = 0; i < count; ++i) {
624 status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
625 &id[i].xid, &id[i].sid);
626 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
627 status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
628 &id[i].xid,
629 &id[i].sid);
631 if (!NT_STATUS_IS_OK(status)) {
632 DEBUG(1, ("idmapping xid_to_sid failed for id[%d]\n", i));
633 error_count++;
634 id[i].status = ID_UNMAPPED;
635 } else {
636 id[i].status = ID_MAPPED;
640 if (error_count == count) {
641 /* Mapping did not work at all. */
642 return NT_STATUS_NONE_MAPPED;
643 } else if (error_count > 0) {
644 /* Some mappings worked, some did not. */
645 return STATUS_SOME_UNMAPPED;
646 } else {
647 return NT_STATUS_OK;
652 * Convert an array of SIDs to the corresponding array of unixids
654 * \param idmap_ctx idmap context to use
655 * \param mem_ctx talloc context the memory for the unixids is allocated
656 * from.
657 * \param count length of id_mapping array.
658 * \param id array of id_mappings.
659 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
660 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
661 * did not.
664 NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx,
665 TALLOC_CTX *mem_ctx, int count,
666 struct id_map *id)
668 int i;
669 int error_count = 0;
670 NTSTATUS status;
672 for (i = 0; i < count; ++i) {
673 status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
674 id[i].sid, &id[i].xid);
675 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
676 status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
677 id[i].sid,
678 &id[i].xid);
680 if (!NT_STATUS_IS_OK(status)) {
681 DEBUG(1, ("idmapping sid_to_xid failed for id[%d]\n", i));
682 error_count++;
683 id[i].status = ID_UNMAPPED;
684 } else {
685 id[i].status = ID_MAPPED;
689 if (error_count == count) {
690 /* Mapping did not work at all. */
691 return NT_STATUS_NONE_MAPPED;
692 } else if (error_count > 0) {
693 /* Some mappings worked, some did not. */
694 return STATUS_SOME_UNMAPPED;
695 } else {
696 return NT_STATUS_OK;