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