s4:Fix regression in dsdb_dn code - all parses of the DN would be rejected
[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/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"
31
32 /**
33  * Get uid/gid bounds from idmap database
34  *
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
39  */
40 static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low,
41                 uint32_t *high)
42 {
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;
50
51         dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
52         if (dn == NULL) goto failed;
53
54         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
55         if (ret != LDB_SUCCESS) goto failed;
56
57         if (res->count != 1) {
58                 ret = -1;
59                 goto failed;
60         }
61
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;
68         }
69
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;
75         }
76
77 failed:
78         talloc_free(tmp_ctx);
79         *low  = lower_bound;
80         *high = upper_bound;
81         return ret;
82 }
83
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.
92  */
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)
96 {
97         struct ldb_val val;
98         enum ndr_err_code ndr_err;
99
100         ndr_err = ndr_push_struct_blob(&val, mem_ctx,
101                                        lp_iconv_convenience(idmap_ctx->lp_ctx),
102                                        sid,
103                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
104
105         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
106                 return -1;
107         }
108
109         return ldb_msg_add_value(msg, attr_name, &val, NULL);
110 }
111
112 /**
113  * Get a dom_sid structure from a ldb message.
114  *
115  * \param mem_ctx talloc context to allocate dom_sid memory in
116  * \param msg ldb_message to get dom_sid from
117  * \param attr_name key that has the dom_sid as data
118  * \return dom_sid structure on success, NULL on failure
119  */
120 static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
121                 struct ldb_message *msg, const char *attr_name)
122 {
123         struct dom_sid *sid;
124         const struct ldb_val *val;
125         enum ndr_err_code ndr_err;
126
127         val = ldb_msg_find_ldb_val(msg, attr_name);
128         if (val == NULL) {
129                 return NULL;
130         }
131
132         sid = talloc(mem_ctx, struct dom_sid);
133         if (sid == NULL) {
134                 return NULL;
135         }
136
137         ndr_err = ndr_pull_struct_blob(val, sid, NULL, sid,
138                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
139         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
140                 talloc_free(sid);
141                 return NULL;
142         }
143
144         return sid;
145 }
146
147 /**
148  * Initialize idmap context
149  *
150  * talloc_free to close.
151  *
152  * \param mem_ctx talloc context to use.
153  * \return allocated idmap_context on success, NULL on error
154  */
155 struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
156                                  struct tevent_context *ev_ctx,
157                 struct loadparm_context *lp_ctx)
158 {
159         struct idmap_context *idmap_ctx;
160
161         idmap_ctx = talloc(mem_ctx, struct idmap_context);
162         if (idmap_ctx == NULL) {
163                 return NULL;
164         }
165
166         idmap_ctx->lp_ctx = lp_ctx;
167
168         idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx,
169                                               lp_idmap_url(lp_ctx),
170                                               system_session(lp_ctx),
171                                               NULL, 0);
172         if (idmap_ctx->ldb_ctx == NULL) {
173                 return NULL;
174         }
175
176         idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2");
177         if (idmap_ctx->unix_groups_sid == NULL) {
178                 return NULL;
179         }
180
181         idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1");
182         if (idmap_ctx->unix_users_sid == NULL) {
183                 return NULL;
184         }
185
186         return idmap_ctx;
187 }
188
189 /**
190  * Convert an unixid to the corresponding SID
191  *
192  * \param idmap_ctx idmap context to use
193  * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
194  * from.
195  * \param unixid pointer to a unixid struct to convert
196  * \param sid pointer that will take the struct dom_sid pointer if the mapping
197  * succeeds.
198  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
199  * possible or some other NTSTATUS that is more descriptive on failure.
200  */
201
202 NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
203                 const struct unixid *unixid, struct dom_sid **sid)
204 {
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;
212
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;
224         }
225
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;
233         }
234
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;
242                 }
243                 talloc_free(tmp_ctx);
244                 return NT_STATUS_OK;
245         }
246
247         DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n"));
248
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");
254         }
255         if (unix_sid == NULL) {
256                 status = NT_STATUS_NO_MEMORY;
257                 goto failed;
258         }
259
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;
264         }
265
266         *sid = new_sid;
267         talloc_free(tmp_ctx);
268         return NT_STATUS_OK;
269
270 failed:
271         talloc_free(tmp_ctx);
272         return status;
273 }
274
275
276 /**
277  * Map a SID to an unixid struct.
278  *
279  * If no mapping exists, a new mapping will be created.
280  *
281  * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true
282  * \todo Fix backwards compatibility for Samba3
283  *
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 pointer
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.
291  */
292 NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
293                 const struct dom_sid *sid, struct unixid **unixid)
294 {
295         int ret;
296         NTSTATUS status = NT_STATUS_NONE_MAPPED;
297         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
298         struct ldb_dn *dn;
299         struct ldb_message *hwm_msg, *map_msg;
300         struct ldb_result *res = NULL;
301         int trans;
302         uint32_t low, high, hwm, new_xid;
303         char *sid_string, *unixid_string, *hwm_string;
304         bool hwm_entry_exists;
305         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
306
307         if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) {
308                 uint32_t rid;
309                 DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
310                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
311                 if (!NT_STATUS_IS_OK(status)) goto failed;
312
313                 *unixid = talloc(mem_ctx, struct unixid);
314                 if (*unixid == NULL) {
315                         status = NT_STATUS_NO_MEMORY;
316                         goto failed;
317                 }
318                 (*unixid)->id = rid;
319                 (*unixid)->type = ID_TYPE_UID;
320
321                 talloc_free(tmp_ctx);
322                 return NT_STATUS_OK;
323         }
324
325         if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) {
326                 uint32_t rid;
327                 DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
328                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
329                 if (!NT_STATUS_IS_OK(status)) goto failed;
330
331                 *unixid = talloc(mem_ctx, struct unixid);
332                 if (*unixid == NULL) {
333                         status = NT_STATUS_NO_MEMORY;
334                         goto failed;
335                 }
336                 (*unixid)->id = rid;
337                 (*unixid)->type = ID_TYPE_GID;
338
339                 talloc_free(tmp_ctx);
340                 return NT_STATUS_OK;
341          }
342
343         ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
344                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
345                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
346         if (ret != LDB_SUCCESS) {
347                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
348                 status = NT_STATUS_NONE_MAPPED;
349                 goto failed;
350         }
351
352         if (res->count == 1) {
353                 const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
354                                                                "type", NULL);
355                 new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
356                                                     -1);
357                 if (new_xid == (uint32_t) -1) {
358                         DEBUG(1, ("Invalid xid mapping.\n"));
359                         status = NT_STATUS_NONE_MAPPED;
360                         goto failed;
361                 }
362
363                 if (type == NULL) {
364                         DEBUG(1, ("Invalid type for mapping entry.\n"));
365                         status = NT_STATUS_NONE_MAPPED;
366                         goto failed;
367                 }
368
369                 *unixid = talloc(mem_ctx, struct unixid);
370                 if (*unixid == NULL) {
371                         status = NT_STATUS_NO_MEMORY;
372                         goto failed;
373                 }
374
375                 (*unixid)->id = new_xid;
376
377                 if (strcmp(type, "ID_TYPE_BOTH") == 0) {
378                         (*unixid)->type = ID_TYPE_BOTH;
379                 } else if (strcmp(type, "ID_TYPE_UID") == 0) {
380                         (*unixid)->type = ID_TYPE_UID;
381                 } else {
382                         (*unixid)->type = ID_TYPE_GID;
383                 }
384
385                 talloc_free(tmp_ctx);
386                 return NT_STATUS_OK;
387         }
388
389         DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
390
391         trans = ldb_transaction_start(ldb);
392         if (trans != LDB_SUCCESS) {
393                 status = NT_STATUS_NONE_MAPPED;
394                 goto failed;
395         }
396
397         /* Redo the search to make sure noone changed the mapping while we
398          * weren't looking */
399         ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
400                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
401                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
402         if (ret != LDB_SUCCESS) {
403                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
404                 status = NT_STATUS_NONE_MAPPED;
405                 goto failed;
406         }
407
408         if (res->count > 0) {
409                 DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
410                 status = NT_STATUS_RETRY;
411                 goto failed;
412         }
413
414         /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be
415          * resolved here. */
416
417         ret = idmap_get_bounds(idmap_ctx, &low, &high);
418         if (ret != LDB_SUCCESS) {
419                 status = NT_STATUS_NONE_MAPPED;
420                 goto failed;
421         }
422
423         dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
424         if (dn == NULL) {
425                 status = NT_STATUS_NO_MEMORY;
426                 goto failed;
427         }
428
429         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
430         if (ret != LDB_SUCCESS) {
431                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
432                 status = NT_STATUS_NONE_MAPPED;
433                 goto failed;
434         }
435
436         if (res->count != 1) {
437                 DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
438                 status = NT_STATUS_NONE_MAPPED;
439                 goto failed;
440         }
441
442         hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
443         if (hwm == (uint32_t)-1) {
444                 hwm = low;
445                 hwm_entry_exists = false;
446         } else {
447                 hwm_entry_exists = true;
448         }
449
450         if (hwm > high) {
451                 DEBUG(1, ("Out of xids to allocate.\n"));
452                 status = NT_STATUS_NONE_MAPPED;
453                 goto failed;
454         }
455
456         hwm_msg = ldb_msg_new(tmp_ctx);
457         if (hwm_msg == NULL) {
458                 DEBUG(1, ("Out of memory when creating ldb_message\n"));
459                 status = NT_STATUS_NO_MEMORY;
460                 goto failed;
461         }
462
463         hwm_msg->dn = dn;
464
465         new_xid = hwm;
466         hwm++;
467
468         hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
469         if (hwm_string == NULL) {
470                 status = NT_STATUS_NO_MEMORY;
471                 goto failed;
472         }
473
474         sid_string = dom_sid_string(tmp_ctx, sid);
475         if (sid_string == NULL) {
476                 status = NT_STATUS_NO_MEMORY;
477                 goto failed;
478         }
479
480         unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
481         if (unixid_string == NULL) {
482                 status = NT_STATUS_NO_MEMORY;
483                 goto failed;
484         }
485
486         if (hwm_entry_exists) {
487                 struct ldb_message_element *els;
488                 struct ldb_val *vals;
489
490                 /* We're modifying the entry, not just adding a new one. */
491                 els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
492                 if (els == NULL) {
493                         status = NT_STATUS_NO_MEMORY;
494                         goto failed;
495                 }
496
497                 vals = talloc_array(tmp_ctx, struct ldb_val, 2);
498                 if (els == NULL) {
499                         status = NT_STATUS_NO_MEMORY;
500                         goto failed;
501                 }
502
503                 hwm_msg->num_elements = 2;
504                 hwm_msg->elements = els;
505
506                 els[0].num_values = 1;
507                 els[0].values = &vals[0];
508                 els[0].flags = LDB_FLAG_MOD_DELETE;
509                 els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
510                 if (els[0].name == NULL) {
511                         status = NT_STATUS_NO_MEMORY;
512                         goto failed;
513                 }
514
515                 els[1].num_values = 1;
516                 els[1].values = &vals[1];
517                 els[1].flags = LDB_FLAG_MOD_ADD;
518                 els[1].name = els[0].name;
519
520                 vals[0].data = (uint8_t *)unixid_string;
521                 vals[0].length = strlen(unixid_string);
522                 vals[1].data = (uint8_t *)hwm_string;
523                 vals[1].length = strlen(hwm_string);
524         } else {
525                 ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
526                                         NULL);
527                 if (ret != LDB_SUCCESS) {
528                         status = NT_STATUS_NONE_MAPPED;
529                         goto failed;
530                 }
531
532                 ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
533                 if (ret != LDB_SUCCESS)
534                 {
535                         status = NT_STATUS_NONE_MAPPED;
536                         goto failed;
537                 }
538         }
539
540         ret = ldb_modify(ldb, hwm_msg);
541         if (ret != LDB_SUCCESS) {
542                 DEBUG(1, ("Updating the xid high water mark failed: %s\n",
543                           ldb_errstring(ldb)));
544                 status = NT_STATUS_NONE_MAPPED;
545                 goto failed;
546         }
547
548         map_msg = ldb_msg_new(tmp_ctx);
549         if (map_msg == NULL) {
550                 status = NT_STATUS_NO_MEMORY;
551                 goto failed;
552         }
553
554         map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string);
555         if (map_msg->dn == NULL) {
556                 status = NT_STATUS_NO_MEMORY;
557                 goto failed;
558         }
559
560         ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
561         if (ret != LDB_SUCCESS) {
562                 status = NT_STATUS_NONE_MAPPED;
563                 goto failed;
564         }
565
566         ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
567                         sid);
568         if (ret != LDB_SUCCESS) {
569                 status = NT_STATUS_NONE_MAPPED;
570                 goto failed;
571         }
572
573         ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
574         if (ret != LDB_SUCCESS) {
575                 status = NT_STATUS_NONE_MAPPED;
576                 goto failed;
577         }
578
579         ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH");
580         if (ret != LDB_SUCCESS) {
581                 status = NT_STATUS_NONE_MAPPED;
582                 goto failed;
583         }
584
585         ret = ldb_msg_add_string(map_msg, "cn", sid_string);
586         if (ret != LDB_SUCCESS) {
587                 status = NT_STATUS_NONE_MAPPED;
588                 goto failed;
589         }
590
591         ret = ldb_add(ldb, map_msg);
592         if (ret != LDB_SUCCESS) {
593                 DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb)));
594                 status = NT_STATUS_NONE_MAPPED;
595                 goto failed;
596         }
597
598         trans = ldb_transaction_commit(ldb);
599         if (trans != LDB_SUCCESS) {
600                 DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb)));
601                 status = NT_STATUS_NONE_MAPPED;
602                 goto failed;
603         }
604
605         *unixid = talloc(mem_ctx, struct unixid);
606         if (*unixid == NULL) {
607                 status = NT_STATUS_NO_MEMORY;
608                 goto failed;
609         }
610
611         (*unixid)->id = new_xid;
612         (*unixid)->type = ID_TYPE_BOTH;
613         talloc_free(tmp_ctx);
614         return NT_STATUS_OK;
615
616 failed:
617         if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
618         talloc_free(tmp_ctx);
619         return status;
620 }
621
622 /**
623  * Convert an array of unixids to the corresponding array of SIDs
624  *
625  * \param idmap_ctx idmap context to use
626  * \param mem_ctx talloc context the memory for the dom_sids is allocated
627  * from.
628  * \param count length of id_mapping array.
629  * \param id array of id_mappings.
630  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
631  * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
632  * did not.
633  */
634
635 NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx,
636                             TALLOC_CTX *mem_ctx, int count,
637                             struct id_mapping *id)
638 {
639         int i;
640         int error_count = 0;
641
642         for (i = 0; i < count; ++i) {
643                 id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
644                                                 id[i].unixid, &id[i].sid);
645                 if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) {
646                         id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
647                                                         id[i].unixid,
648                                                         &id[i].sid);
649                 }
650                 if (!NT_STATUS_IS_OK(id[i].status)) {
651                         DEBUG(1, ("idmapping xid_to_sid failed for id[%d]\n", i));
652                         error_count++;
653                 }
654         }
655
656         if (error_count == count) {
657                 /* Mapping did not work at all. */
658                 return NT_STATUS_NONE_MAPPED;
659         } else if (error_count > 0) {
660                 /* Some mappings worked, some did not. */
661                 return STATUS_SOME_UNMAPPED;
662         } else {
663                 return NT_STATUS_OK;
664         }
665 }
666
667 /**
668  * Convert an array of SIDs to the corresponding array of unixids
669  *
670  * \param idmap_ctx idmap context to use
671  * \param mem_ctx talloc context the memory for the unixids is allocated
672  * from.
673  * \param count length of id_mapping array.
674  * \param id array of id_mappings.
675  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
676  * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
677  * did not.
678  */
679
680 NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx,
681                             TALLOC_CTX *mem_ctx, int count,
682                             struct id_mapping *id)
683 {
684         int i;
685         int error_count = 0;
686
687         for (i = 0; i < count; ++i) {
688                 id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
689                                                 id[i].sid, &id[i].unixid);
690                 if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) {
691                         id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
692                                                         id[i].sid,
693                                                         &id[i].unixid);
694                 }
695                 if (!NT_STATUS_IS_OK(id[i].status)) {
696                         DEBUG(1, ("idmapping sid_to_xid failed for id[%d]\n", i));
697                         error_count++;
698                 }
699         }
700
701         if (error_count == count) {
702                 /* Mapping did not work at all. */
703                 return NT_STATUS_NONE_MAPPED;
704         } else if (error_count > 0) {
705                 /* Some mappings worked, some did not. */
706                 return STATUS_SOME_UNMAPPED;
707         } else {
708                 return NT_STATUS_OK;
709         }
710 }
711