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