Merge ldb_search() and ldb_search_exp_fmt() into a simgle function.
[ira/wip.git] / source4 / winbind / idmap.c
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/proto.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  */
43 static 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
80 failed:
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  */
96 static 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  */
123 static 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  */
158 struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
159                                  struct event_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
205 NTSTATUS 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
273 failed:
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  */
295 NTSTATUS 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
619 failed:
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
638 NTSTATUS 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
683 NTSTATUS 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