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