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