Merge branch 'v4-0-logon' of git://git.id10ts.net/samba into 4-0-local
[samba.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, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
58         if (ret != LDB_SUCCESS) goto failed;
59
60         talloc_steal(tmp_ctx, res);
61
62         if (res->count != 1) {
63                 ret = -1;
64                 goto failed;
65         }
66
67         lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1);
68         if (lower_bound != (uint32_t) -1) {
69                 ret = LDB_SUCCESS;
70         } else {
71                 ret = -1;
72                 goto failed;
73         }
74
75         upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1);
76         if (upper_bound != (uint32_t) -1) {
77                 ret = LDB_SUCCESS;
78         } else {
79                 ret = -1;
80         }
81
82 failed:
83         talloc_free(tmp_ctx);
84         *low  = lower_bound;
85         *high = upper_bound;
86         return ret;
87 }
88
89 /**
90  * Add a dom_sid structure to a ldb_message
91  * \param idmap_ctx idmap context to use
92  * \param mem_ctx talloc context to use
93  * \param ldb_message ldb message to add dom_sid to
94  * \param attr_name name of the attribute to store the dom_sid in
95  * \param sid dom_sid to store
96  * \return 0 on success, an ldb error code on failure.
97  */
98 static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx,
99                 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
100                 const char *attr_name, const struct dom_sid *sid)
101 {
102         struct ldb_val val;
103         enum ndr_err_code ndr_err;
104
105         ndr_err = ndr_push_struct_blob(&val, mem_ctx,
106                                        lp_iconv_convenience(idmap_ctx->lp_ctx),
107                                        sid,
108                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
109
110         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
111                 return -1;
112         }
113
114         return ldb_msg_add_value(msg, attr_name, &val, NULL);
115 }
116
117 /**
118  * Get a dom_sid structure from a ldb message.
119  *
120  * \param mem_ctx talloc context to allocate dom_sid memory in
121  * \param msg ldb_message to get dom_sid from
122  * \param attr_name key that has the dom_sid as data
123  * \return dom_sid structure on success, NULL on failure
124  */
125 static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
126                 struct ldb_message *msg, const char *attr_name)
127 {
128         struct dom_sid *sid;
129         const struct ldb_val *val;
130         enum ndr_err_code ndr_err;
131
132         val = ldb_msg_find_ldb_val(msg, attr_name);
133         if (val == NULL) {
134                 return NULL;
135         }
136
137         sid = talloc(mem_ctx, struct dom_sid);
138         if (sid == NULL) {
139                 return NULL;
140         }
141
142         ndr_err = ndr_pull_struct_blob(val, sid, NULL, sid,
143                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
144         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145                 talloc_free(sid);
146                 return NULL;
147         }
148
149         return sid;
150 }
151
152 /**
153  * Initialize idmap context
154  *
155  * talloc_free to close.
156  *
157  * \param mem_ctx talloc context to use.
158  * \return allocated idmap_context on success, NULL on error
159  */
160 struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
161                 struct loadparm_context *lp_ctx)
162 {
163         struct idmap_context *idmap_ctx;
164
165         idmap_ctx = talloc(mem_ctx, struct idmap_context);
166         if (idmap_ctx == NULL) {
167                 return NULL;
168         }
169
170         idmap_ctx->lp_ctx = lp_ctx;
171
172         idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, lp_ctx,
173                                               lp_idmap_url(lp_ctx),
174                                               system_session(mem_ctx, lp_ctx),
175                                               NULL, 0, NULL);
176         if (idmap_ctx->ldb_ctx == NULL) {
177                 return NULL;
178         }
179
180         idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2");
181         if (idmap_ctx->unix_groups_sid == NULL) {
182                 return NULL;
183         }
184
185         idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1");
186         if (idmap_ctx->unix_users_sid == NULL) {
187                 return NULL;
188         }
189
190         return idmap_ctx;
191 }
192
193 /**
194  * Convert an unixid to the corresponding SID
195  *
196  * \param idmap_ctx idmap context to use
197  * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
198  * from.
199  * \param unixid pointer to a unixid struct to convert
200  * \param sid pointer that will take the struct dom_sid pointer if the mapping
201  * succeeds.
202  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
203  * possible or some other NTSTATUS that is more descriptive on failure.
204  */
205
206 NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
207                 const struct unixid *unixid, struct dom_sid **sid)
208 {
209         int ret;
210         NTSTATUS status = NT_STATUS_NONE_MAPPED;
211         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
212         struct ldb_result *res = NULL;
213         uint32_t low, high;
214         struct dom_sid *unix_sid, *new_sid;
215         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
216
217         ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
218                                  NULL, "(&(objectClass=sidMap)(xidNumber=%u))",
219                                  unixid->id);
220         if (ret != LDB_SUCCESS) {
221                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
222                 status = NT_STATUS_NONE_MAPPED;
223                 goto failed;
224         }
225
226         if (res->count == 1) {
227                 *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
228                                              "objectSid");
229                 if (*sid == NULL) {
230                         DEBUG(1, ("Failed to get sid from db: %u\n", ret));
231                         status = NT_STATUS_NONE_MAPPED;
232                         goto failed;
233                 }
234                 talloc_free(tmp_ctx);
235                 return NT_STATUS_OK;
236         }
237
238         DEBUG(6, ("xid not found in idmap db, trying to allocate SID.\n"));
239
240         /* Now redo the search to make sure noone added a mapping for that SID
241          * while we weren't looking.*/
242         ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
243                                  NULL, "(&(objectClass=sidMap)(xidNumber=%u))",
244                                  unixid->id);
245         if (ret != LDB_SUCCESS) {
246                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
247                 status = NT_STATUS_NONE_MAPPED;
248                 goto failed;
249         }
250
251         if (res->count > 0) {
252                 DEBUG(1, ("sidMap modified while trying to add a mapping.\n"));
253                 status = NT_STATUS_RETRY;
254                 goto failed;
255         }
256
257         ret = idmap_get_bounds(idmap_ctx, &low, &high);
258         if (ret != LDB_SUCCESS) {
259                 DEBUG(1, ("Failed to get id bounds from db: %u\n", ret));
260                 status = NT_STATUS_NONE_MAPPED;
261                 goto failed;
262         }
263
264         if (unixid->id >= low && unixid->id <= high) {
265                 /* An existing xid would have been mapped before */
266                 status = NT_STATUS_NONE_MAPPED;
267                 goto failed;
268         }
269
270         /* For local users, we just create a rid = uid +1, so root doesn't end
271          * up with a 0 rid */
272         if (unixid->type == ID_TYPE_UID) {
273                 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1");
274         } else {
275                 unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2");
276         }
277         if (unix_sid == NULL) {
278                 status = NT_STATUS_NO_MEMORY;
279                 goto failed;
280         }
281
282         new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id + 1);
283         if (new_sid == NULL) {
284                 status = NT_STATUS_NO_MEMORY;
285                 goto failed;
286         }
287
288         *sid = new_sid;
289         talloc_free(tmp_ctx);
290         return NT_STATUS_OK;
291
292 failed:
293         talloc_free(tmp_ctx);
294         return status;
295 }
296
297
298 /**
299  * Map a SID to an unixid struct.
300  *
301  * If no mapping exists, a new mapping will be created.
302  *
303  * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true
304  * \todo Fix backwards compatibility for Samba3
305  *
306  * \param idmap_ctx idmap context to use
307  * \param mem_ctx talloc context to use
308  * \param sid SID to map to an unixid struct
309  * \param unixid pointer to a unixid struct pointer
310  * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from
311  * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the
312  * mapping failed.
313  */
314 NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
315                 const struct dom_sid *sid, struct unixid **unixid)
316 {
317         int ret;
318         NTSTATUS status = NT_STATUS_NONE_MAPPED;
319         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
320         struct ldb_dn *dn;
321         struct ldb_message *hwm_msg, *map_msg;
322         struct ldb_result *res = NULL;
323         int trans;
324         uint32_t low, high, hwm, new_xid;
325         char *sid_string, *unixid_string, *hwm_string;
326         bool hwm_entry_exists;
327         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
328
329         ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
330                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
331                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
332         if (ret != LDB_SUCCESS) {
333                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
334                 status = NT_STATUS_NONE_MAPPED;
335                 goto failed;
336         }
337
338         if (res->count == 1) {
339                 new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
340                                                     -1);
341                 if (new_xid == (uint32_t) -1) {
342                         DEBUG(1, ("Invalid xid mapping.\n"));
343                         status = NT_STATUS_NONE_MAPPED;
344                         goto failed;
345                 }
346
347                 *unixid = talloc(mem_ctx, struct unixid);
348                 if (*unixid == NULL) {
349                         status = NT_STATUS_NO_MEMORY;
350                         goto failed;
351                 }
352
353                 (*unixid)->id = new_xid;
354                 (*unixid)->type = ID_TYPE_BOTH;
355
356                 talloc_free(tmp_ctx);
357                 return NT_STATUS_OK;
358         }
359
360         DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
361
362         if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) {
363                 uint32_t rid;
364                 DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
365                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
366                 if (!NT_STATUS_IS_OK(status)) goto failed;
367
368                 *unixid = talloc(mem_ctx, struct unixid);
369                 if (*unixid == NULL) {
370                         status = NT_STATUS_NO_MEMORY;
371                         goto failed;
372                 }
373                 (*unixid)->id = rid - 1;
374                 (*unixid)->type = ID_TYPE_UID;
375
376                 talloc_free(tmp_ctx);
377                 return NT_STATUS_OK;
378         }
379
380         if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) {
381                 uint32_t rid;
382                 DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
383                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
384                 if (!NT_STATUS_IS_OK(status)) goto failed;
385
386                 *unixid = talloc(mem_ctx, struct unixid);
387                 if (*unixid == NULL) {
388                         status = NT_STATUS_NO_MEMORY;
389                         goto failed;
390                 }
391                 (*unixid)->id = rid - 1;
392                 (*unixid)->type = ID_TYPE_GID;
393
394                 talloc_free(tmp_ctx);
395                 return NT_STATUS_OK;
396          }
397
398         trans = ldb_transaction_start(ldb);
399         if (trans != LDB_SUCCESS) {
400                 status = NT_STATUS_NONE_MAPPED;
401                 goto failed;
402         }
403
404         /* Redo the search to make sure noone changed the mapping while we
405          * weren't looking */
406         ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
407                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
408                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
409         if (ret != LDB_SUCCESS) {
410                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
411                 status = NT_STATUS_NONE_MAPPED;
412                 goto failed;
413         }
414
415         if (res->count > 0) {
416                 DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
417                 status = NT_STATUS_RETRY;
418                 goto failed;
419         }
420
421         /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be
422          * resolved here. */
423
424         ret = idmap_get_bounds(idmap_ctx, &low, &high);
425         if (ret != LDB_SUCCESS) {
426                 status = NT_STATUS_NONE_MAPPED;
427                 goto failed;
428         }
429
430         dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
431         if (dn == NULL) {
432                 status = NT_STATUS_NO_MEMORY;
433                 goto failed;
434         }
435
436         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
437         if (ret != LDB_SUCCESS) {
438                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
439                 status = NT_STATUS_NONE_MAPPED;
440                 goto failed;
441         }
442
443         talloc_steal(tmp_ctx, res);
444
445         if (res->count != 1) {
446                 DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
447                 status = NT_STATUS_NONE_MAPPED;
448                 goto failed;
449         }
450
451         hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
452         if (hwm == (uint32_t)-1) {
453                 hwm = low;
454                 hwm_entry_exists = false;
455         } else {
456                 hwm_entry_exists = true;
457         }
458
459         if (hwm > high) {
460                 DEBUG(1, ("Out of xids to allocate.\n"));
461                 status = NT_STATUS_NONE_MAPPED;
462                 goto failed;
463         }
464
465         hwm_msg = ldb_msg_new(tmp_ctx);
466         if (hwm_msg == NULL) {
467                 DEBUG(1, ("Out of memory when creating ldb_message\n"));
468                 status = NT_STATUS_NO_MEMORY;
469                 goto failed;
470         }
471
472         hwm_msg->dn = dn;
473
474         new_xid = hwm;
475         hwm++;
476
477         hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
478         if (hwm_string == NULL) {
479                 status = NT_STATUS_NO_MEMORY;
480                 goto failed;
481         }
482
483         sid_string = dom_sid_string(tmp_ctx, sid);
484         if (sid_string == NULL) {
485                 status = NT_STATUS_NO_MEMORY;
486                 goto failed;
487         }
488
489         unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
490         if (unixid_string == NULL) {
491                 status = NT_STATUS_NO_MEMORY;
492                 goto failed;
493         }
494
495         if (hwm_entry_exists) {
496                 struct ldb_message_element *els;
497                 struct ldb_val *vals;
498
499                 /* We're modifying the entry, not just adding a new one. */
500                 els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
501                 if (els == NULL) {
502                         status = NT_STATUS_NO_MEMORY;
503                         goto failed;
504                 }
505
506                 vals = talloc_array(tmp_ctx, struct ldb_val, 2);
507                 if (els == NULL) {
508                         status = NT_STATUS_NO_MEMORY;
509                         goto failed;
510                 }
511
512                 hwm_msg->num_elements = 2;
513                 hwm_msg->elements = els;
514
515                 els[0].num_values = 1;
516                 els[0].values = &vals[0];
517                 els[0].flags = LDB_FLAG_MOD_DELETE;
518                 els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
519                 if (els[0].name == NULL) {
520                         status = NT_STATUS_NO_MEMORY;
521                         goto failed;
522                 }
523
524                 els[1].num_values = 1;
525                 els[1].values = &vals[1];
526                 els[1].flags = LDB_FLAG_MOD_ADD;
527                 els[1].name = els[0].name;
528
529                 vals[0].data = (uint8_t *)unixid_string;
530                 vals[0].length = strlen(unixid_string);
531                 vals[1].data = (uint8_t *)hwm_string;
532                 vals[1].length = strlen(hwm_string);
533         } else {
534                 ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
535                                         NULL);
536                 if (ret != LDB_SUCCESS) {
537                         status = NT_STATUS_NONE_MAPPED;
538                         goto failed;
539                 }
540
541                 ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
542                 if (ret != LDB_SUCCESS)
543                 {
544                         status = NT_STATUS_NONE_MAPPED;
545                         goto failed;
546                 }
547         }
548
549         ret = ldb_modify(ldb, hwm_msg);
550         if (ret != LDB_SUCCESS) {
551                 DEBUG(1, ("Updating the xid high water mark failed: %s\n",
552                           ldb_errstring(ldb)));
553                 status = NT_STATUS_NONE_MAPPED;
554                 goto failed;
555         }
556
557         map_msg = ldb_msg_new(tmp_ctx);
558         if (map_msg == NULL) {
559                 status = NT_STATUS_NO_MEMORY;
560                 goto failed;
561         }
562
563         map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string);
564         if (map_msg->dn == NULL) {
565                 status = NT_STATUS_NO_MEMORY;
566                 goto failed;
567         }
568
569         ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
570         if (ret != LDB_SUCCESS) {
571                 status = NT_STATUS_NONE_MAPPED;
572                 goto failed;
573         }
574
575         ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
576                         sid);
577         if (ret != LDB_SUCCESS) {
578                 status = NT_STATUS_NONE_MAPPED;
579                 goto failed;
580         }
581
582         ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
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 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 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