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