idmap4: Use sid_check_is_in_unix_users()
[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    Copyright (C) Andrew Bartlett 2012
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "librpc/gen_ndr/ndr_security.h"
26 #include "lib/util_unixsids.h"
27 #include <ldb.h>
28 #include "ldb_wrap.h"
29 #include "param/param.h"
30 #include "winbind/idmap.h"
31 #include "libcli/security/security.h"
32 #include "libcli/ldap/ldap_ndr.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "../libds/common/flags.h"
35
36 /**
37  * Get uid/gid bounds from idmap database
38  *
39  * \param idmap_ctx idmap context to use
40  * \param low lower uid/gid bound is stored here
41  * \param high upper uid/gid bound is stored here
42  * \return 0 on success, nonzero on failure
43  */
44 static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low,
45                 uint32_t *high)
46 {
47         int ret = -1;
48         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
49         struct ldb_dn *dn;
50         struct ldb_result *res = NULL;
51         TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx);
52         uint32_t lower_bound = (uint32_t) -1;
53         uint32_t upper_bound = (uint32_t) -1;
54
55         dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
56         if (dn == NULL) goto failed;
57
58         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
59         if (ret != LDB_SUCCESS) goto failed;
60
61         if (res->count != 1) {
62                 ret = -1;
63                 goto failed;
64         }
65
66         lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1);
67         if (lower_bound != (uint32_t) -1) {
68                 ret = LDB_SUCCESS;
69         } else {
70                 ret = -1;
71                 goto failed;
72         }
73
74         upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1);
75         if (upper_bound != (uint32_t) -1) {
76                 ret = LDB_SUCCESS;
77         } else {
78                 ret = -1;
79         }
80
81 failed:
82         talloc_free(tmp_ctx);
83         *low  = lower_bound;
84         *high = upper_bound;
85         return ret;
86 }
87
88 /**
89  * Add a dom_sid structure to a ldb_message
90  * \param idmap_ctx idmap context to use
91  * \param mem_ctx talloc context to use
92  * \param ldb_message ldb message to add dom_sid to
93  * \param attr_name name of the attribute to store the dom_sid in
94  * \param sid dom_sid to store
95  * \return 0 on success, an ldb error code on failure.
96  */
97 static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx,
98                 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
99                 const char *attr_name, const struct dom_sid *sid)
100 {
101         struct ldb_val val;
102         enum ndr_err_code ndr_err;
103
104         ndr_err = ndr_push_struct_blob(&val, mem_ctx, sid,
105                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
106
107         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
108                 return -1;
109         }
110
111         return ldb_msg_add_value(msg, attr_name, &val, NULL);
112 }
113
114 /**
115  * Get a dom_sid structure from a ldb message.
116  *
117  * \param mem_ctx talloc context to allocate dom_sid memory in
118  * \param msg ldb_message to get dom_sid from
119  * \param attr_name key that has the dom_sid as data
120  * \return dom_sid structure on success, NULL on failure
121  */
122 static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
123                 struct ldb_message *msg, const char *attr_name)
124 {
125         struct dom_sid *sid;
126         const struct ldb_val *val;
127         enum ndr_err_code ndr_err;
128
129         val = ldb_msg_find_ldb_val(msg, attr_name);
130         if (val == NULL) {
131                 return NULL;
132         }
133
134         sid = talloc(mem_ctx, struct dom_sid);
135         if (sid == NULL) {
136                 return NULL;
137         }
138
139         ndr_err = ndr_pull_struct_blob(val, sid, sid,
140                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
141         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
142                 talloc_free(sid);
143                 return NULL;
144         }
145
146         return sid;
147 }
148
149 /**
150  * Initialize idmap context
151  *
152  * talloc_free to close.
153  *
154  * \param mem_ctx talloc context to use.
155  * \return allocated idmap_context on success, NULL on error
156  */
157 struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
158                                  struct tevent_context *ev_ctx,
159                                  struct loadparm_context *lp_ctx)
160 {
161         struct idmap_context *idmap_ctx;
162
163         idmap_ctx = talloc(mem_ctx, struct idmap_context);
164         if (idmap_ctx == NULL) {
165                 return NULL;
166         }
167
168         idmap_ctx->lp_ctx = lp_ctx;
169
170         idmap_ctx->ldb_ctx = ldb_wrap_connect(idmap_ctx, ev_ctx, lp_ctx,
171                                               "idmap.ldb",
172                                               system_session(lp_ctx),
173                                               NULL, 0);
174         if (idmap_ctx->ldb_ctx == NULL) {
175                 goto fail;
176         }
177
178         idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(
179                 idmap_ctx, "S-1-22-2");
180         if (idmap_ctx->unix_groups_sid == NULL) {
181                 goto fail;
182         }
183
184         idmap_ctx->samdb = samdb_connect(idmap_ctx, ev_ctx, lp_ctx, system_session(lp_ctx), 0);
185         if (idmap_ctx->samdb == NULL) {
186                 DEBUG(0, ("Failed to load sam.ldb in idmap_init\n"));
187                 goto fail;
188         }
189
190         return idmap_ctx;
191 fail:
192         TALLOC_FREE(idmap_ctx);
193         return NULL;
194 }
195
196 /**
197  * Convert an unixid to the corresponding SID
198  *
199  * \param idmap_ctx idmap context to use
200  * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
201  * from.
202  * \param unixid pointer to a unixid struct to convert
203  * \param sid pointer that will take the struct dom_sid pointer if the mapping
204  * succeeds.
205  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
206  * possible or some other NTSTATUS that is more descriptive on failure.
207  */
208
209 static NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx,
210                                  TALLOC_CTX *mem_ctx,
211                                  struct unixid *unixid,
212                                  struct dom_sid **sid)
213 {
214         int ret;
215         NTSTATUS status = NT_STATUS_NONE_MAPPED;
216         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
217         struct ldb_result *res = NULL;
218         struct ldb_message *msg;
219         const struct dom_sid *unix_sid;
220         struct dom_sid *new_sid;
221         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
222         const char *id_type;
223
224         const char *sam_attrs[] = {"objectSid", NULL};
225         
226         /* 
227          * First check against our local DB, to see if this user has a
228          * mapping there.  This means that the Samba4 AD DC behaves
229          * much like a winbindd member server running idmap_ad
230          */
231         
232         switch (unixid->type) {
233                 case ID_TYPE_UID:
234                         if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
235                                 ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
236                                                       ldb_get_default_basedn(idmap_ctx->samdb),
237                                                       LDB_SCOPE_SUBTREE,
238                                                       sam_attrs, 0,
239                                                       "(&(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u))"
240                                                       "(uidNumber=%u)(objectSid=*))",
241                                                       ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST, unixid->id);
242                         } else {
243                                 /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
244                                 ret = LDB_ERR_NO_SUCH_OBJECT;
245                         }
246
247                         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
248                                 DEBUG(1, ("Search for uidNumber=%lu gave duplicate results, failing to map to a SID!\n",
249                                           (unsigned long)unixid->id));
250                                 status = NT_STATUS_NONE_MAPPED;
251                                 goto failed;
252                         } else if (ret == LDB_SUCCESS) {
253                                 *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
254                                 if (*sid == NULL) {
255                                         DEBUG(1, ("Search for uidNumber=%lu did not return an objectSid!\n",
256                                                   (unsigned long)unixid->id));
257                                         status = NT_STATUS_NONE_MAPPED;
258                                         goto failed;
259                                 }
260                                 talloc_free(tmp_ctx);
261                                 return NT_STATUS_OK;
262                         } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
263                                 DEBUG(1, ("Search for uidNumber=%lu gave '%s', failing to map to a SID!\n",
264                                           (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
265                                 status = NT_STATUS_NONE_MAPPED;
266                                 goto failed;
267                         }
268
269                         id_type = "ID_TYPE_UID";
270                         break;
271                 case ID_TYPE_GID:
272                         if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
273                                 ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
274                                                       ldb_get_default_basedn(idmap_ctx->samdb),
275                                                       LDB_SCOPE_SUBTREE,
276                                                       sam_attrs, 0,
277                                                       "(&(|(sAMaccountType=%u)(sAMaccountType=%u))(gidNumber=%u))",
278                                                       ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
279                                                       unixid->id);
280                         } else {
281                                 /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
282                                 ret = LDB_ERR_NO_SUCH_OBJECT;
283                         }
284                         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
285                                 DEBUG(1, ("Search for gidNumber=%lu gave duplicate results, failing to map to a SID!\n",
286                                           (unsigned long)unixid->id));
287                                 status = NT_STATUS_NONE_MAPPED;
288                                 goto failed;
289                         } else if (ret == LDB_SUCCESS) {
290                                 *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
291                                 if (*sid == NULL) {
292                                         DEBUG(1, ("Search for gidNumber=%lu did not return an objectSid!\n",
293                                                   (unsigned long)unixid->id));
294                                         status = NT_STATUS_NONE_MAPPED;
295                                         goto failed;
296                                 }
297                                 talloc_free(tmp_ctx);
298                                 return NT_STATUS_OK;
299                         } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
300                                 DEBUG(1, ("Search for gidNumber=%lu gave '%s', failing to map to a SID!\n",
301                                           (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
302                                 status = NT_STATUS_NONE_MAPPED;
303                                 goto failed;
304                         }
305
306                         id_type = "ID_TYPE_GID";
307                         break;
308                 default:
309                         DEBUG(1, ("unixid->type must be type gid or uid (got %u) for lookup with id %lu\n",
310                                   (unsigned)unixid->type, (unsigned long)unixid->id));
311                         status = NT_STATUS_NONE_MAPPED;
312                         goto failed;
313         }
314
315         ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
316                                  NULL, "(&(|(type=ID_TYPE_BOTH)(type=%s))"
317                                  "(xidNumber=%u))", id_type, unixid->id);
318         if (ret != LDB_SUCCESS) {
319                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
320                 status = NT_STATUS_NONE_MAPPED;
321                 goto failed;
322         }
323
324         if (res->count == 1) {
325                 const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
326                                                                "type", NULL);
327
328                 *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
329                                              "objectSid");
330                 if (*sid == NULL) {
331                         DEBUG(1, ("Failed to get sid from db: %u\n", ret));
332                         status = NT_STATUS_NONE_MAPPED;
333                         goto failed;
334                 }
335
336                 if (type == NULL) {
337                         DEBUG(1, ("Invalid type for mapping entry.\n"));
338                         talloc_free(tmp_ctx);
339                         return NT_STATUS_NONE_MAPPED;
340                 }
341
342                 if (strcmp(type, "ID_TYPE_BOTH") == 0) {
343                         unixid->type = ID_TYPE_BOTH;
344                 } else if (strcmp(type, "ID_TYPE_UID") == 0) {
345                         unixid->type = ID_TYPE_UID;
346                 } else {
347                         unixid->type = ID_TYPE_GID;
348                 }
349
350                 talloc_free(tmp_ctx);
351                 return NT_STATUS_OK;
352         }
353
354         DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n"));
355
356         /* For local users/groups , we just create a rid = uid/gid */
357         if (unixid->type == ID_TYPE_UID) {
358                 unix_sid = &global_sid_Unix_Users;
359         } else {
360                 unix_sid = &global_sid_Unix_Groups;
361         }
362
363         new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id);
364         if (new_sid == NULL) {
365                 status = NT_STATUS_NO_MEMORY;
366                 goto failed;
367         }
368
369         *sid = new_sid;
370         talloc_free(tmp_ctx);
371         return NT_STATUS_OK;
372
373 failed:
374         talloc_free(tmp_ctx);
375         return status;
376 }
377
378
379 /**
380  * Map a SID to an unixid struct.
381  *
382  * If no mapping exists, a new mapping will be created.
383  *
384  * \param idmap_ctx idmap context to use
385  * \param mem_ctx talloc context to use
386  * \param sid SID to map to an unixid struct
387  * \param unixid pointer to a unixid struct
388  * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from
389  * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the
390  * mapping failed.
391  */
392 static NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx,
393                                  TALLOC_CTX *mem_ctx,
394                                  const struct dom_sid *sid,
395                                  struct unixid *unixid)
396 {
397         int ret;
398         NTSTATUS status = NT_STATUS_NONE_MAPPED;
399         struct ldb_context *ldb = idmap_ctx->ldb_ctx;
400         struct ldb_dn *dn;
401         struct ldb_message *hwm_msg, *map_msg, *sam_msg;
402         struct ldb_result *res = NULL;
403         int trans = -1;
404         uint32_t low, high, hwm, new_xid;
405         char *sid_string, *unixid_string, *hwm_string;
406         bool hwm_entry_exists;
407         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
408         const char *sam_attrs[] = {"uidNumber", "gidNumber", "samAccountType", NULL};
409
410         if (sid_check_is_in_unix_users(sid)) {
411                 uint32_t rid;
412                 DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
413                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
414                 if (!NT_STATUS_IS_OK(status)) {
415                         talloc_free(tmp_ctx);
416                         return status;
417                 }
418
419                 unixid->id = rid;
420                 unixid->type = ID_TYPE_UID;
421
422                 talloc_free(tmp_ctx);
423                 return NT_STATUS_OK;
424         }
425
426         if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) {
427                 uint32_t rid;
428                 DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
429                 status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
430                 if (!NT_STATUS_IS_OK(status)) {
431                         talloc_free(tmp_ctx);
432                         return status;
433                 }
434
435                 unixid->id = rid;
436                 unixid->type = ID_TYPE_GID;
437
438                 talloc_free(tmp_ctx);
439                 return NT_STATUS_OK;
440         }
441
442         /* 
443          * First check against our local DB, to see if this user has a
444          * mapping there.  This means that the Samba4 AD DC behaves
445          * much like a winbindd member server running idmap_ad
446          */
447         
448         if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
449                 ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &sam_msg,
450                                       ldb_get_default_basedn(idmap_ctx->samdb),
451                                       LDB_SCOPE_SUBTREE, sam_attrs, 0,
452                                       "(&(objectSid=%s)"
453                                       "(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u)"
454                                       "(sAMaccountType=%u)(sAMaccountType=%u))"
455                                       "(|(uidNumber=*)(gidNumber=*)))",
456                                       dom_sid_string(tmp_ctx, sid),
457                                       ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
458                                       ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
459         } else {
460                 /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
461                 ret = LDB_ERR_NO_SUCH_OBJECT;
462         }
463
464         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
465                 DEBUG(1, ("Search for objectSid=%s gave duplicate results, failing to map to a unix ID!\n",
466                           dom_sid_string(tmp_ctx, sid)));
467                 status = NT_STATUS_NONE_MAPPED;
468                 goto failed;
469         } else if (ret == LDB_SUCCESS) {
470                 uint32_t account_type = ldb_msg_find_attr_as_uint(sam_msg, "sAMaccountType", 0);
471                 if ((account_type == ATYPE_ACCOUNT) ||
472                     (account_type == ATYPE_WORKSTATION_TRUST ) ||
473                     (account_type == ATYPE_INTERDOMAIN_TRUST ))
474                 {
475                         const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "uidNumber");
476                         if (v) {
477                                 unixid->type = ID_TYPE_UID;
478                                 unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "uidNumber", -1);
479                                 talloc_free(tmp_ctx);
480                                 return NT_STATUS_OK;
481                         }
482
483                 } else if ((account_type == ATYPE_SECURITY_GLOBAL_GROUP) ||
484                            (account_type == ATYPE_SECURITY_LOCAL_GROUP))
485                 {
486                         const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "gidNumber");
487                         if (v) {
488                                 unixid->type = ID_TYPE_GID;
489                                 unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "gidNumber", -1);
490                                 talloc_free(tmp_ctx);
491                                 return NT_STATUS_OK;
492                         }
493                 }
494         } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
495                 DEBUG(1, ("Search for objectSid=%s gave '%s', failing to map to a SID!\n",
496                           dom_sid_string(tmp_ctx, sid), ldb_errstring(idmap_ctx->samdb)));
497
498                 status = NT_STATUS_NONE_MAPPED;
499                 goto failed;
500         }
501
502         ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
503                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
504                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
505         if (ret != LDB_SUCCESS) {
506                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
507                 talloc_free(tmp_ctx);
508                 return NT_STATUS_NONE_MAPPED;
509         }
510
511         if (res->count == 1) {
512                 const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
513                                                                "type", NULL);
514                 new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
515                                                     -1);
516                 if (new_xid == (uint32_t) -1) {
517                         DEBUG(1, ("Invalid xid mapping.\n"));
518                         talloc_free(tmp_ctx);
519                         return NT_STATUS_NONE_MAPPED;
520                 }
521
522                 if (type == NULL) {
523                         DEBUG(1, ("Invalid type for mapping entry.\n"));
524                         talloc_free(tmp_ctx);
525                         return NT_STATUS_NONE_MAPPED;
526                 }
527
528                 unixid->id = new_xid;
529
530                 if (strcmp(type, "ID_TYPE_BOTH") == 0) {
531                         unixid->type = ID_TYPE_BOTH;
532                 } else if (strcmp(type, "ID_TYPE_UID") == 0) {
533                         unixid->type = ID_TYPE_UID;
534                 } else {
535                         unixid->type = ID_TYPE_GID;
536                 }
537
538                 talloc_free(tmp_ctx);
539                 return NT_STATUS_OK;
540         }
541
542         DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
543
544         trans = ldb_transaction_start(ldb);
545         if (trans != LDB_SUCCESS) {
546                 status = NT_STATUS_NONE_MAPPED;
547                 goto failed;
548         }
549
550         /* Redo the search to make sure noone changed the mapping while we
551          * weren't looking */
552         ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
553                                  NULL, "(&(objectClass=sidMap)(objectSid=%s))",
554                                  ldap_encode_ndr_dom_sid(tmp_ctx, sid));
555         if (ret != LDB_SUCCESS) {
556                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
557                 status = NT_STATUS_NONE_MAPPED;
558                 goto failed;
559         }
560
561         if (res->count > 0) {
562                 DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
563                 status = NT_STATUS_RETRY;
564                 goto failed;
565         }
566
567         ret = idmap_get_bounds(idmap_ctx, &low, &high);
568         if (ret != LDB_SUCCESS) {
569                 status = NT_STATUS_NONE_MAPPED;
570                 goto failed;
571         }
572
573         dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
574         if (dn == NULL) {
575                 status = NT_STATUS_NO_MEMORY;
576                 goto failed;
577         }
578
579         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
580         if (ret != LDB_SUCCESS) {
581                 DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
582                 status = NT_STATUS_NONE_MAPPED;
583                 goto failed;
584         }
585
586         if (res->count != 1) {
587                 DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
588                 status = NT_STATUS_NONE_MAPPED;
589                 goto failed;
590         }
591
592         hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
593         if (hwm == (uint32_t)-1) {
594                 hwm = low;
595                 hwm_entry_exists = false;
596         } else {
597                 hwm_entry_exists = true;
598         }
599
600         if (hwm > high) {
601                 DEBUG(1, ("Out of xids to allocate.\n"));
602                 status = NT_STATUS_NONE_MAPPED;
603                 goto failed;
604         }
605
606         hwm_msg = ldb_msg_new(tmp_ctx);
607         if (hwm_msg == NULL) {
608                 DEBUG(1, ("Out of memory when creating ldb_message\n"));
609                 status = NT_STATUS_NO_MEMORY;
610                 goto failed;
611         }
612
613         hwm_msg->dn = dn;
614
615         new_xid = hwm;
616         hwm++;
617
618         hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
619         if (hwm_string == NULL) {
620                 status = NT_STATUS_NO_MEMORY;
621                 goto failed;
622         }
623
624         sid_string = dom_sid_string(tmp_ctx, sid);
625         if (sid_string == NULL) {
626                 status = NT_STATUS_NO_MEMORY;
627                 goto failed;
628         }
629
630         unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
631         if (unixid_string == NULL) {
632                 status = NT_STATUS_NO_MEMORY;
633                 goto failed;
634         }
635
636         if (hwm_entry_exists) {
637                 struct ldb_message_element *els;
638                 struct ldb_val *vals;
639
640                 /* We're modifying the entry, not just adding a new one. */
641                 els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
642                 if (els == NULL) {
643                         status = NT_STATUS_NO_MEMORY;
644                         goto failed;
645                 }
646
647                 vals = talloc_array(tmp_ctx, struct ldb_val, 2);
648                 if (els == NULL) {
649                         status = NT_STATUS_NO_MEMORY;
650                         goto failed;
651                 }
652
653                 hwm_msg->num_elements = 2;
654                 hwm_msg->elements = els;
655
656                 els[0].num_values = 1;
657                 els[0].values = &vals[0];
658                 els[0].flags = LDB_FLAG_MOD_DELETE;
659                 els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
660                 if (els[0].name == NULL) {
661                         status = NT_STATUS_NO_MEMORY;
662                         goto failed;
663                 }
664
665                 els[1].num_values = 1;
666                 els[1].values = &vals[1];
667                 els[1].flags = LDB_FLAG_MOD_ADD;
668                 els[1].name = els[0].name;
669
670                 vals[0].data = (uint8_t *)unixid_string;
671                 vals[0].length = strlen(unixid_string);
672                 vals[1].data = (uint8_t *)hwm_string;
673                 vals[1].length = strlen(hwm_string);
674         } else {
675                 ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
676                                         NULL);
677                 if (ret != LDB_SUCCESS) {
678                         status = NT_STATUS_NONE_MAPPED;
679                         goto failed;
680                 }
681
682                 ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
683                 if (ret != LDB_SUCCESS)
684                 {
685                         status = NT_STATUS_NONE_MAPPED;
686                         goto failed;
687                 }
688         }
689
690         ret = ldb_modify(ldb, hwm_msg);
691         if (ret != LDB_SUCCESS) {
692                 DEBUG(1, ("Updating the xid high water mark failed: %s\n",
693                           ldb_errstring(ldb)));
694                 status = NT_STATUS_NONE_MAPPED;
695                 goto failed;
696         }
697
698         map_msg = ldb_msg_new(tmp_ctx);
699         if (map_msg == NULL) {
700                 status = NT_STATUS_NO_MEMORY;
701                 goto failed;
702         }
703
704         map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string);
705         if (map_msg->dn == NULL) {
706                 status = NT_STATUS_NO_MEMORY;
707                 goto failed;
708         }
709
710         ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
711         if (ret != LDB_SUCCESS) {
712                 status = NT_STATUS_NONE_MAPPED;
713                 goto failed;
714         }
715
716         ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
717                         sid);
718         if (ret != LDB_SUCCESS) {
719                 status = NT_STATUS_NONE_MAPPED;
720                 goto failed;
721         }
722
723         ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
724         if (ret != LDB_SUCCESS) {
725                 status = NT_STATUS_NONE_MAPPED;
726                 goto failed;
727         }
728
729         ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH");
730         if (ret != LDB_SUCCESS) {
731                 status = NT_STATUS_NONE_MAPPED;
732                 goto failed;
733         }
734
735         ret = ldb_msg_add_string(map_msg, "cn", sid_string);
736         if (ret != LDB_SUCCESS) {
737                 status = NT_STATUS_NONE_MAPPED;
738                 goto failed;
739         }
740
741         ret = ldb_add(ldb, map_msg);
742         if (ret != LDB_SUCCESS) {
743                 DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb)));
744                 status = NT_STATUS_NONE_MAPPED;
745                 goto failed;
746         }
747
748         trans = ldb_transaction_commit(ldb);
749         if (trans != LDB_SUCCESS) {
750                 DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb)));
751                 status = NT_STATUS_NONE_MAPPED;
752                 goto failed;
753         }
754
755         unixid->id = new_xid;
756         unixid->type = ID_TYPE_BOTH;
757         talloc_free(tmp_ctx);
758         return NT_STATUS_OK;
759
760 failed:
761         if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
762         talloc_free(tmp_ctx);
763         return status;
764 }
765
766 /**
767  * Convert an array of unixids to the corresponding array of SIDs
768  *
769  * \param idmap_ctx idmap context to use
770  * \param mem_ctx talloc context the memory for the dom_sids is allocated
771  * from.
772  * \param count length of id_mapping array.
773  * \param id array of id_mappings.
774  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
775  * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
776  * did not.
777  */
778
779 NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx,
780                             TALLOC_CTX *mem_ctx,
781                             struct id_map **id)
782 {
783         unsigned int i, error_count = 0;
784         NTSTATUS status;
785
786         for (i = 0; id && id[i]; i++) {
787                 status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
788                                                 &id[i]->xid, &id[i]->sid);
789                 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
790                         status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
791                                                         &id[i]->xid,
792                                                         &id[i]->sid);
793                 }
794                 if (!NT_STATUS_IS_OK(status)) {
795                         DEBUG(1, ("idmapping xid_to_sid failed for id[%d]=%lu: %s\n",
796                                   i, (unsigned long)id[i]->xid.id, nt_errstr(status)));
797                         error_count++;
798                         id[i]->status = ID_UNMAPPED;
799                 } else {
800                         id[i]->status = ID_MAPPED;
801                 }
802         }
803
804         if (error_count == i) {
805                 /* Mapping did not work at all. */
806                 return NT_STATUS_NONE_MAPPED;
807         } else if (error_count > 0) {
808                 /* Some mappings worked, some did not. */
809                 return STATUS_SOME_UNMAPPED;
810         } else {
811                 return NT_STATUS_OK;
812         }
813 }
814
815 /**
816  * Convert an array of SIDs to the corresponding array of unixids
817  *
818  * \param idmap_ctx idmap context to use
819  * \param mem_ctx talloc context the memory for the unixids is allocated
820  * from.
821  * \param count length of id_mapping array.
822  * \param id array of id_mappings.
823  * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
824  * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
825  * did not.
826  */
827
828 NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx,
829                             TALLOC_CTX *mem_ctx,
830                             struct id_map **id)
831 {
832         unsigned int i, error_count = 0;
833         NTSTATUS status;
834
835         for (i = 0; id && id[i]; i++) {
836                 status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
837                                           id[i]->sid, &id[i]->xid);
838                 if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
839                         status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
840                                                   id[i]->sid,
841                                                   &id[i]->xid);
842                 }
843                 if (!NT_STATUS_IS_OK(status)) {
844                         char *str = dom_sid_string(mem_ctx, id[i]->sid);
845                         DEBUG(1, ("idmapping sid_to_xid failed for id[%d]=%s: %s\n",
846                                   i, str, nt_errstr(status)));
847                         talloc_free(str);
848                         error_count++;
849                         id[i]->status = ID_UNMAPPED;
850                 } else {
851                         id[i]->status = ID_MAPPED;
852                 }
853         }
854
855         if (error_count == i) {
856                 /* Mapping did not work at all. */
857                 return NT_STATUS_NONE_MAPPED;
858         } else if (error_count > 0) {
859                 /* Some mappings worked, some did not. */
860                 return STATUS_SOME_UNMAPPED;
861         } else {
862                 return NT_STATUS_OK;
863         }
864 }
865