s3:smbd/oplock: use talloc_get_type_abort() as private_data can't be NULL
[kai/samba.git] / source3 / winbindd / idmap_tdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    idmap TDB backend
5
6    Copyright (C) Tim Potter 2000
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8    Copyright (C) Jeremy Allison 2006
9    Copyright (C) Simo Sorce 2003-2006
10    Copyright (C) Michael Adam 2009-2010
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "system/filesys.h"
28 #include "winbindd.h"
29 #include "idmap.h"
30 #include "idmap_rw.h"
31 #include "dbwrap/dbwrap.h"
32 #include "dbwrap/dbwrap_open.h"
33 #include "../libcli/security/security.h"
34 #include "util_tdb.h"
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_IDMAP
38
39 /* idmap version determines auto-conversion - this is the database
40    structure version specifier. */
41
42 #define IDMAP_VERSION 2
43
44 struct idmap_tdb_context {
45         struct db_context *db;
46         struct idmap_rw_ops *rw_ops;
47 };
48
49 /* High water mark keys */
50 #define HWM_GROUP  "GROUP HWM"
51 #define HWM_USER   "USER HWM"
52
53 struct convert_fn_state {
54         struct db_context *db;
55         bool failed;
56 };
57
58 /*****************************************************************************
59  For idmap conversion: convert one record to new format
60  Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
61  instead of the SID.
62 *****************************************************************************/
63 static int convert_fn(struct db_record *rec, void *private_data)
64 {
65         struct winbindd_domain *domain;
66         char *p;
67         NTSTATUS status;
68         struct dom_sid sid;
69         uint32 rid;
70         fstring keystr;
71         fstring dom_name;
72         TDB_DATA key;
73         TDB_DATA key2;
74         TDB_DATA value;
75         struct convert_fn_state *s = (struct convert_fn_state *)private_data;
76
77         key = dbwrap_record_get_key(rec);
78
79         DEBUG(10,("Converting %s\n", (const char *)key.dptr));
80
81         p = strchr((const char *)key.dptr, '/');
82         if (!p)
83                 return 0;
84
85         *p = 0;
86         fstrcpy(dom_name, (const char *)key.dptr);
87         *p++ = '/';
88
89         domain = find_domain_from_name(dom_name);
90         if (domain == NULL) {
91                 /* We must delete the old record. */
92                 DEBUG(0,("Unable to find domain %s\n", dom_name ));
93                 DEBUG(0,("deleting record %s\n", (const char *)key.dptr ));
94
95                 status = dbwrap_record_delete(rec);
96                 if (!NT_STATUS_IS_OK(status)) {
97                         DEBUG(0, ("Unable to delete record %s:%s\n",
98                                 (const char *)key.dptr,
99                                 nt_errstr(status)));
100                         s->failed = true;
101                         return -1;
102                 }
103
104                 return 0;
105         }
106
107         rid = atoi(p);
108
109         sid_compose(&sid, &domain->sid, rid);
110
111         sid_to_fstring(keystr, &sid);
112         key2 = string_term_tdb_data(keystr);
113
114         value = dbwrap_record_get_value(rec);
115
116         status = dbwrap_store(s->db, key2, value, TDB_INSERT);
117         if (!NT_STATUS_IS_OK(status)) {
118                 DEBUG(0,("Unable to add record %s:%s\n",
119                         (const char *)key2.dptr,
120                         nt_errstr(status)));
121                 s->failed = true;
122                 return -1;
123         }
124
125         status = dbwrap_store(s->db, value, key2, TDB_REPLACE);
126         if (!NT_STATUS_IS_OK(status)) {
127                 DEBUG(0,("Unable to update record %s:%s\n",
128                         (const char *)value.dptr,
129                         nt_errstr(status)));
130                 s->failed = true;
131                 return -1;
132         }
133
134         status = dbwrap_record_delete(rec);
135         if (!NT_STATUS_IS_OK(status)) {
136                 DEBUG(0,("Unable to delete record %s:%s\n",
137                         (const char *)key.dptr,
138                         nt_errstr(status)));
139                 s->failed = true;
140                 return -1;
141         }
142
143         return 0;
144 }
145
146 /*****************************************************************************
147  Convert the idmap database from an older version.
148 *****************************************************************************/
149
150 static bool idmap_tdb_upgrade(struct idmap_domain *dom, struct db_context *db)
151 {
152         int32 vers;
153         bool bigendianheader;
154         struct convert_fn_state s;
155         NTSTATUS status;
156
157 #if BUILD_TDB2
158         /* If we are bigendian, tdb is bigendian if NOT converted. */
159         union {
160                 uint16 large;
161                 unsigned char small[2];
162         } u;
163         u.large = 0x0102;
164         if (u.small[0] == 0x01)
165                 bigendianheader = !(dbwrap_get_flags(db) & TDB_CONVERT);
166         else {
167                 assert(u.small[0] == 0x02);
168                 bigendianheader = (dbwrap_get_flags(db) & TDB_CONVERT);
169         }
170 #else
171         bigendianheader = (dbwrap_get_flags(db) & TDB_BIGENDIAN) ? True : False;
172 #endif
173         DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
174
175         status = dbwrap_fetch_int32(db, "IDMAP_VERSION", &vers);
176         if (!NT_STATUS_IS_OK(status)) {
177                 vers = -1;
178         }
179
180         if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
181                 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
182                 /*
183                  * high and low records were created on a
184                  * big endian machine and will need byte-reversing.
185                  */
186
187                 int32 wm;
188
189                 status = dbwrap_fetch_int32(db, HWM_USER, &wm);
190                 if (!NT_STATUS_IS_OK(status)) {
191                         wm = -1;
192                 }
193
194                 if (wm != -1) {
195                         wm = IREV(wm);
196                 }  else {
197                         wm = dom->low_id;
198                 }
199
200                 status = dbwrap_store_int32(db, HWM_USER, wm);
201                 if (!NT_STATUS_IS_OK(status)) {
202                         DEBUG(0, ("Unable to byteswap user hwm in idmap "
203                                   "database: %s\n", nt_errstr(status)));
204                         return False;
205                 }
206
207                 status = dbwrap_fetch_int32(db, HWM_GROUP, &wm);
208                 if (!NT_STATUS_IS_OK(status)) {
209                         wm = -1;
210                 }
211
212                 if (wm != -1) {
213                         wm = IREV(wm);
214                 } else {
215                         wm = dom->low_id;
216                 }
217
218                 status = dbwrap_store_int32(db, HWM_GROUP, wm);
219                 if (!NT_STATUS_IS_OK(status)) {
220                         DEBUG(0, ("Unable to byteswap group hwm in idmap "
221                                   "database: %s\n", nt_errstr(status)));
222                         return False;
223                 }
224         }
225
226         s.db = db;
227         s.failed = false;
228
229         /* the old format stored as DOMAIN/rid - now we store the SID direct */
230         status = dbwrap_traverse(db, convert_fn, &s, NULL);
231
232         if (!NT_STATUS_IS_OK(status)) {
233                 DEBUG(0, ("Database traverse failed during conversion\n"));
234                 return false;
235         }
236
237         if (s.failed) {
238                 DEBUG(0, ("Problem during conversion\n"));
239                 return False;
240         }
241
242         status = dbwrap_store_int32(db, "IDMAP_VERSION", IDMAP_VERSION);
243         if (!NT_STATUS_IS_OK(status)) {
244                 DEBUG(0, ("Unable to store idmap version in database: %s\n",
245                           nt_errstr(status)));
246                 return False;
247         }
248
249         return True;
250 }
251
252 static NTSTATUS idmap_tdb_init_hwm(struct idmap_domain *dom)
253 {
254         uint32_t low_uid;
255         uint32_t low_gid;
256         bool update_uid = false;
257         bool update_gid = false;
258         struct idmap_tdb_context *ctx;
259         NTSTATUS status;
260
261         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
262
263         status = dbwrap_fetch_uint32(ctx->db, HWM_USER, &low_uid);
264         if (!NT_STATUS_IS_OK(status) || low_uid < dom->low_id) {
265                 update_uid = true;
266         }
267
268         status = dbwrap_fetch_uint32(ctx->db, HWM_GROUP, &low_gid);
269         if (!NT_STATUS_IS_OK(status) || low_gid < dom->low_id) {
270                 update_gid = true;
271         }
272
273         if (!update_uid && !update_gid) {
274                 return NT_STATUS_OK;
275         }
276
277         if (dbwrap_transaction_start(ctx->db) != 0) {
278                 DEBUG(0, ("Unable to start upgrade transaction!\n"));
279                 return NT_STATUS_INTERNAL_DB_ERROR;
280         }
281
282         if (update_uid) {
283                 status = dbwrap_store_uint32(ctx->db, HWM_USER, dom->low_id);
284                 if (!NT_STATUS_IS_OK(status)) {
285                         dbwrap_transaction_cancel(ctx->db);
286                         DEBUG(0, ("Unable to initialise user hwm in idmap "
287                                   "database: %s\n", nt_errstr(status)));
288                         return NT_STATUS_INTERNAL_DB_ERROR;
289                 }
290         }
291
292         if (update_gid) {
293                 status = dbwrap_store_uint32(ctx->db, HWM_GROUP, dom->low_id);
294                 if (!NT_STATUS_IS_OK(status)) {
295                         dbwrap_transaction_cancel(ctx->db);
296                         DEBUG(0, ("Unable to initialise group hwm in idmap "
297                                   "database: %s\n", nt_errstr(status)));
298                         return NT_STATUS_INTERNAL_DB_ERROR;
299                 }
300         }
301
302         if (dbwrap_transaction_commit(ctx->db) != 0) {
303                 DEBUG(0, ("Unable to commit upgrade transaction!\n"));
304                 return NT_STATUS_INTERNAL_DB_ERROR;
305         }
306
307         return NT_STATUS_OK;
308 }
309
310 static NTSTATUS idmap_tdb_open_db(struct idmap_domain *dom)
311 {
312         NTSTATUS ret;
313         TALLOC_CTX *mem_ctx;
314         char *tdbfile = NULL;
315         struct db_context *db = NULL;
316         int32_t version;
317         bool config_error = false;
318         struct idmap_tdb_context *ctx;
319
320         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
321
322         if (ctx->db) {
323                 /* it is already open */
324                 return NT_STATUS_OK;
325         }
326
327         /* use our own context here */
328         mem_ctx = talloc_stackframe();
329
330         /* use the old database if present */
331         tdbfile = state_path("winbindd_idmap.tdb");
332         if (!tdbfile) {
333                 DEBUG(0, ("Out of memory!\n"));
334                 ret = NT_STATUS_NO_MEMORY;
335                 goto done;
336         }
337
338         DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
339
340         /* Open idmap repository */
341         db = db_open(mem_ctx, tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
342         if (!db) {
343                 DEBUG(0, ("Unable to open idmap database\n"));
344                 ret = NT_STATUS_UNSUCCESSFUL;
345                 goto done;
346         }
347
348         /* check against earlier versions */
349         ret = dbwrap_fetch_int32(db, "IDMAP_VERSION", &version);
350         if (!NT_STATUS_IS_OK(ret)) {
351                 version = -1;
352         }
353
354         if (version != IDMAP_VERSION) {
355                 if (config_error) {
356                         DEBUG(0,("Upgrade of IDMAP_VERSION from %d to %d is not "
357                                  "possible with incomplete configuration\n",
358                                  version, IDMAP_VERSION));
359                         ret = NT_STATUS_UNSUCCESSFUL;
360                         goto done;
361                 }
362                 if (dbwrap_transaction_start(db) != 0) {
363                         DEBUG(0, ("Unable to start upgrade transaction!\n"));
364                         ret = NT_STATUS_INTERNAL_DB_ERROR;
365                         goto done;
366                 }
367
368                 if (!idmap_tdb_upgrade(dom, db)) {
369                         dbwrap_transaction_cancel(db);
370                         DEBUG(0, ("Unable to open idmap database, it's in an old format, and upgrade failed!\n"));
371                         ret = NT_STATUS_INTERNAL_DB_ERROR;
372                         goto done;
373                 }
374
375                 if (dbwrap_transaction_commit(db) != 0) {
376                         DEBUG(0, ("Unable to commit upgrade transaction!\n"));
377                         ret = NT_STATUS_INTERNAL_DB_ERROR;
378                         goto done;
379                 }
380         }
381
382         ctx->db = talloc_move(ctx, &db);
383
384         ret = idmap_tdb_init_hwm(dom);
385
386 done:
387         talloc_free(mem_ctx);
388         return ret;
389 }
390
391 /**********************************************************************
392  IDMAP ALLOC TDB BACKEND
393 **********************************************************************/
394
395 /**********************************
396  Allocate a new id. 
397 **********************************/
398
399 struct idmap_tdb_allocate_id_context {
400         const char *hwmkey;
401         const char *hwmtype;
402         uint32_t high_hwm;
403         uint32_t hwm;
404 };
405
406 static NTSTATUS idmap_tdb_allocate_id_action(struct db_context *db,
407                                              void *private_data)
408 {
409         NTSTATUS ret;
410         struct idmap_tdb_allocate_id_context *state;
411         uint32_t hwm;
412
413         state = (struct idmap_tdb_allocate_id_context *)private_data;
414
415         ret = dbwrap_fetch_uint32(db, state->hwmkey, &hwm);
416         if (!NT_STATUS_IS_OK(ret)) {
417                 ret = NT_STATUS_INTERNAL_DB_ERROR;
418                 goto done;
419         }
420
421         /* check it is in the range */
422         if (hwm > state->high_hwm) {
423                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
424                           state->hwmtype, (unsigned long)state->high_hwm));
425                 ret = NT_STATUS_UNSUCCESSFUL;
426                 goto done;
427         }
428
429         /* fetch a new id and increment it */
430         ret = dbwrap_trans_change_uint32_atomic(db, state->hwmkey, &hwm, 1);
431         if (!NT_STATUS_IS_OK(ret)) {
432                 DEBUG(0, ("Fatal error while fetching a new %s value: %s\n!",
433                           state->hwmtype, nt_errstr(ret)));
434                 goto done;
435         }
436
437         /* recheck it is in the range */
438         if (hwm > state->high_hwm) {
439                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
440                           state->hwmtype, (unsigned long)state->high_hwm));
441                 ret = NT_STATUS_UNSUCCESSFUL;
442                 goto done;
443         }
444
445         ret = NT_STATUS_OK;
446         state->hwm = hwm;
447
448 done:
449         return ret;
450 }
451
452 static NTSTATUS idmap_tdb_allocate_id(struct idmap_domain *dom,
453                                       struct unixid *xid)
454 {
455         const char *hwmkey;
456         const char *hwmtype;
457         uint32_t high_hwm;
458         uint32_t hwm = 0;
459         NTSTATUS status;
460         struct idmap_tdb_allocate_id_context state;
461         struct idmap_tdb_context *ctx;
462
463         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
464
465         /* Get current high water mark */
466         switch (xid->type) {
467
468         case ID_TYPE_UID:
469                 hwmkey = HWM_USER;
470                 hwmtype = "UID";
471                 break;
472
473         case ID_TYPE_GID:
474                 hwmkey = HWM_GROUP;
475                 hwmtype = "GID";
476                 break;
477
478         default:
479                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
480                 return NT_STATUS_INVALID_PARAMETER;
481         }
482
483         high_hwm = dom->high_id;
484
485         state.hwm = hwm;
486         state.high_hwm = high_hwm;
487         state.hwmtype = hwmtype;
488         state.hwmkey = hwmkey;
489
490         status = dbwrap_trans_do(ctx->db, idmap_tdb_allocate_id_action,
491                                  &state);
492
493         if (NT_STATUS_IS_OK(status)) {
494                 xid->id = state.hwm;
495                 DEBUG(10,("New %s = %d\n", hwmtype, state.hwm));
496         } else {
497                 DEBUG(1, ("Error allocating a new %s\n", hwmtype));
498         }
499
500         return status;
501 }
502
503 /**
504  * Allocate a new unix-ID.
505  * For now this is for the default idmap domain only.
506  * Should be extended later on.
507  */
508 static NTSTATUS idmap_tdb_get_new_id(struct idmap_domain *dom,
509                                      struct unixid *id)
510 {
511         NTSTATUS ret;
512
513         if (!strequal(dom->name, "*")) {
514                 DEBUG(3, ("idmap_tdb_get_new_id: "
515                           "Refusing allocation of a new unixid for domain'%s'. "
516                           "Currently only supported for the default "
517                           "domain \"*\".\n",
518                            dom->name));
519                 return NT_STATUS_NOT_IMPLEMENTED;
520         }
521
522         ret = idmap_tdb_allocate_id(dom, id);
523
524         return ret;
525 }
526
527 /**********************************************************************
528  IDMAP MAPPING TDB BACKEND
529 **********************************************************************/
530
531 /*****************************
532  Initialise idmap database. 
533 *****************************/
534
535 static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom,
536                                       const struct id_map *map);
537
538 static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom)
539 {
540         NTSTATUS ret;
541         struct idmap_tdb_context *ctx;
542
543         DEBUG(10, ("idmap_tdb_db_init called for domain '%s'\n", dom->name));
544
545         ctx = talloc_zero(dom, struct idmap_tdb_context);
546         if ( ! ctx) {
547                 DEBUG(0, ("Out of memory!\n"));
548                 return NT_STATUS_NO_MEMORY;
549         }
550
551         /* load backend specific configuration here: */
552 #if 0
553         if (strequal(dom->name, "*")) {
554         } else {
555         }
556 #endif
557
558         ctx->rw_ops = talloc_zero(ctx, struct idmap_rw_ops);
559         if (ctx->rw_ops == NULL) {
560                 DEBUG(0, ("Out of memory!\n"));
561                 ret = NT_STATUS_NO_MEMORY;
562                 goto failed;
563         }
564
565         ctx->rw_ops->get_new_id = idmap_tdb_get_new_id;
566         ctx->rw_ops->set_mapping = idmap_tdb_set_mapping;
567
568         dom->private_data = ctx;
569
570         ret = idmap_tdb_open_db(dom);
571         if ( ! NT_STATUS_IS_OK(ret)) {
572                 goto failed;
573         }
574
575         return NT_STATUS_OK;
576
577 failed:
578         talloc_free(ctx);
579         return ret;
580 }
581
582
583 /**
584  * store a mapping in the database
585  */
586
587 struct idmap_tdb_set_mapping_context {
588         const char *ksidstr;
589         const char *kidstr;
590 };
591
592 static NTSTATUS idmap_tdb_set_mapping_action(struct db_context *db,
593                                              void *private_data)
594 {
595         NTSTATUS ret;
596         struct idmap_tdb_set_mapping_context *state;
597
598         state = (struct idmap_tdb_set_mapping_context *)private_data;
599
600         DEBUG(10, ("Storing %s <-> %s map\n", state->ksidstr, state->kidstr));
601
602         ret = dbwrap_store_bystring(db, state->ksidstr,
603                                     string_term_tdb_data(state->kidstr),
604                                     TDB_REPLACE);
605         if (!NT_STATUS_IS_OK(ret)) {
606                 DEBUG(0, ("Error storing SID -> ID (%s -> %s): %s\n",
607                           state->ksidstr, state->kidstr, nt_errstr(ret)));
608                 goto done;
609         }
610
611         ret = dbwrap_store_bystring(db, state->kidstr,
612                                     string_term_tdb_data(state->ksidstr),
613                                     TDB_REPLACE);
614         if (!NT_STATUS_IS_OK(ret)) {
615                 DEBUG(0, ("Error storing ID -> SID (%s -> %s): %s\n",
616                           state->kidstr, state->ksidstr, nt_errstr(ret)));
617                 goto done;
618         }
619
620         DEBUG(10,("Stored %s <-> %s\n", state->ksidstr, state->kidstr));
621         ret = NT_STATUS_OK;
622
623 done:
624         return ret;
625 }
626
627 static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom,
628                                       const struct id_map *map)
629 {
630         struct idmap_tdb_context *ctx;
631         NTSTATUS ret;
632         char *ksidstr, *kidstr;
633         struct idmap_tdb_set_mapping_context state;
634
635         if (!map || !map->sid) {
636                 return NT_STATUS_INVALID_PARAMETER;
637         }
638
639         ksidstr = kidstr = NULL;
640
641         /* TODO: should we filter a set_mapping using low/high filters ? */
642
643         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
644
645         switch (map->xid.type) {
646
647         case ID_TYPE_UID:
648                 kidstr = talloc_asprintf(ctx, "UID %lu",
649                                          (unsigned long)map->xid.id);
650                 break;
651
652         case ID_TYPE_GID:
653                 kidstr = talloc_asprintf(ctx, "GID %lu",
654                                          (unsigned long)map->xid.id);
655                 break;
656
657         default:
658                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
659                 return NT_STATUS_INVALID_PARAMETER;
660         }
661
662         if (kidstr == NULL) {
663                 DEBUG(0, ("ERROR: Out of memory!\n"));
664                 ret = NT_STATUS_NO_MEMORY;
665                 goto done;
666         }
667
668         ksidstr = sid_string_talloc(ctx, map->sid);
669         if (ksidstr == NULL) {
670                 DEBUG(0, ("Out of memory!\n"));
671                 ret = NT_STATUS_NO_MEMORY;
672                 goto done;
673         }
674
675         state.ksidstr = ksidstr;
676         state.kidstr = kidstr;
677
678         ret = dbwrap_trans_do(ctx->db, idmap_tdb_set_mapping_action, &state);
679
680 done:
681         talloc_free(ksidstr);
682         talloc_free(kidstr);
683         return ret;
684 }
685
686 /**
687  * Create a new mapping for an unmapped SID, also allocating a new ID.
688  * This should be run inside a transaction.
689  *
690  * TODO:
691  * Properly integrate this with multi domain idmap config:
692  * Currently, the allocator is default-config only.
693  */
694 static NTSTATUS idmap_tdb_new_mapping(struct idmap_domain *dom, struct id_map *map)
695 {
696         NTSTATUS ret;
697         struct idmap_tdb_context *ctx;
698
699         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
700
701         ret = idmap_rw_new_mapping(dom, ctx->rw_ops, map);
702
703         return ret;
704 }
705
706
707 /**********************************
708  Single id to sid lookup function. 
709 **********************************/
710
711 static NTSTATUS idmap_tdb_id_to_sid(struct idmap_domain *dom, struct id_map *map)
712 {
713         NTSTATUS ret;
714         TDB_DATA data;
715         char *keystr;
716         struct idmap_tdb_context *ctx;
717
718         if (!dom || !map) {
719                 return NT_STATUS_INVALID_PARAMETER;
720         }
721
722         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
723
724         /* apply filters before checking */
725         if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
726                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
727                                 map->xid.id, dom->low_id, dom->high_id));
728                 return NT_STATUS_NONE_MAPPED;
729         }
730
731         switch (map->xid.type) {
732
733         case ID_TYPE_UID:
734                 keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
735                 break;
736
737         case ID_TYPE_GID:
738                 keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
739                 break;
740
741         default:
742                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
743                 return NT_STATUS_INVALID_PARAMETER;
744         }
745
746         /* final SAFE_FREE safe */
747         data.dptr = NULL;
748
749         if (keystr == NULL) {
750                 DEBUG(0, ("Out of memory!\n"));
751                 ret = NT_STATUS_NO_MEMORY;
752                 goto done;
753         }
754
755         DEBUG(10,("Fetching record %s\n", keystr));
756
757         /* Check if the mapping exists */
758         ret = dbwrap_fetch_bystring(ctx->db, NULL, keystr, &data);
759
760         if (!NT_STATUS_IS_OK(ret)) {
761                 DEBUG(10,("Record %s not found\n", keystr));
762                 ret = NT_STATUS_NONE_MAPPED;
763                 goto done;
764         }
765
766         if (!string_to_sid(map->sid, (const char *)data.dptr)) {
767                 DEBUG(10,("INVALID SID (%s) in record %s\n",
768                         (const char *)data.dptr, keystr));
769                 ret = NT_STATUS_INTERNAL_DB_ERROR;
770                 goto done;
771         }
772
773         DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr));
774         ret = NT_STATUS_OK;
775
776 done:
777         talloc_free(data.dptr);
778         talloc_free(keystr);
779         return ret;
780 }
781
782 /**********************************
783  Single sid to id lookup function. 
784 **********************************/
785
786 static NTSTATUS idmap_tdb_sid_to_id(struct idmap_domain *dom, struct id_map *map)
787 {
788         NTSTATUS ret;
789         TDB_DATA data;
790         char *keystr;
791         unsigned long rec_id = 0;
792         struct idmap_tdb_context *ctx;
793         TALLOC_CTX *tmp_ctx = talloc_stackframe();
794
795         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
796
797         keystr = sid_string_talloc(tmp_ctx, map->sid);
798         if (keystr == NULL) {
799                 DEBUG(0, ("Out of memory!\n"));
800                 ret = NT_STATUS_NO_MEMORY;
801                 goto done;
802         }
803
804         DEBUG(10,("Fetching record %s\n", keystr));
805
806         /* Check if sid is present in database */
807         ret = dbwrap_fetch_bystring(ctx->db, tmp_ctx, keystr, &data);
808         if (!NT_STATUS_IS_OK(ret)) {
809                 DEBUG(10,("Record %s not found\n", keystr));
810                 ret = NT_STATUS_NONE_MAPPED;
811                 goto done;
812         }
813
814         /* What type of record is this ? */
815         if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
816                 map->xid.id = rec_id;
817                 map->xid.type = ID_TYPE_UID;
818                 DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr ));
819                 ret = NT_STATUS_OK;
820
821         } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
822                 map->xid.id = rec_id;
823                 map->xid.type = ID_TYPE_GID;
824                 DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr ));
825                 ret = NT_STATUS_OK;
826
827         } else { /* Unknown record type ! */
828                 DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr));
829                 ret = NT_STATUS_INTERNAL_DB_ERROR;
830                 goto done;
831         }
832
833         /* apply filters before returning result */
834         if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
835                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
836                                 map->xid.id, dom->low_id, dom->high_id));
837                 ret = NT_STATUS_NONE_MAPPED;
838         }
839
840 done:
841         talloc_free(tmp_ctx);
842         return ret;
843 }
844
845 /**********************************
846  lookup a set of unix ids. 
847 **********************************/
848
849 static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
850 {
851         NTSTATUS ret;
852         int i;
853
854         /* initialize the status to avoid suprise */
855         for (i = 0; ids[i]; i++) {
856                 ids[i]->status = ID_UNKNOWN;
857         }
858
859         for (i = 0; ids[i]; i++) {
860                 ret = idmap_tdb_id_to_sid(dom, ids[i]);
861                 if ( ! NT_STATUS_IS_OK(ret)) {
862
863                         /* if it is just a failed mapping continue */
864                         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
865
866                                 /* make sure it is marked as unmapped */
867                                 ids[i]->status = ID_UNMAPPED;
868                                 continue;
869                         }
870
871                         /* some fatal error occurred, return immediately */
872                         goto done;
873                 }
874
875                 /* all ok, id is mapped */
876                 ids[i]->status = ID_MAPPED;
877         }
878
879         ret = NT_STATUS_OK;
880
881 done:
882         return ret;
883 }
884
885 /**********************************
886  lookup a set of sids. 
887 **********************************/
888
889 struct idmap_tdb_sids_to_unixids_context {
890         struct idmap_domain *dom;
891         struct id_map **ids;
892         bool allocate_unmapped;
893 };
894
895 static NTSTATUS idmap_tdb_sids_to_unixids_action(struct db_context *db,
896                                                  void *private_data)
897 {
898         struct idmap_tdb_sids_to_unixids_context *state;
899         int i;
900         NTSTATUS ret = NT_STATUS_OK;
901
902         state = (struct idmap_tdb_sids_to_unixids_context *)private_data;
903
904         DEBUG(10, ("idmap_tdb_sids_to_unixids_action: "
905                    " domain: [%s], allocate: %s\n",
906                    state->dom->name,
907                    state->allocate_unmapped ? "yes" : "no"));
908
909         for (i = 0; state->ids[i]; i++) {
910                 if ((state->ids[i]->status == ID_UNKNOWN) ||
911                     /* retry if we could not map in previous run: */
912                     (state->ids[i]->status == ID_UNMAPPED))
913                 {
914                         NTSTATUS ret2;
915
916                         ret2 = idmap_tdb_sid_to_id(state->dom, state->ids[i]);
917                         if (!NT_STATUS_IS_OK(ret2)) {
918
919                                 /* if it is just a failed mapping, continue */
920                                 if (NT_STATUS_EQUAL(ret2, NT_STATUS_NONE_MAPPED)) {
921
922                                         /* make sure it is marked as unmapped */
923                                         state->ids[i]->status = ID_UNMAPPED;
924                                         ret = STATUS_SOME_UNMAPPED;
925                                 } else {
926                                         /* some fatal error occurred, return immediately */
927                                         ret = ret2;
928                                         goto done;
929                                 }
930                         } else {
931                                 /* all ok, id is mapped */
932                                 state->ids[i]->status = ID_MAPPED;
933                         }
934                 }
935
936                 if ((state->ids[i]->status == ID_UNMAPPED) &&
937                     state->allocate_unmapped)
938                 {
939                         ret = idmap_tdb_new_mapping(state->dom, state->ids[i]);
940                         if (!NT_STATUS_IS_OK(ret)) {
941                                 goto done;
942                         }
943                 }
944         }
945
946 done:
947         return ret;
948 }
949
950 static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
951 {
952         struct idmap_tdb_context *ctx;
953         NTSTATUS ret;
954         int i;
955         struct idmap_tdb_sids_to_unixids_context state;
956
957         /* initialize the status to avoid suprise */
958         for (i = 0; ids[i]; i++) {
959                 ids[i]->status = ID_UNKNOWN;
960         }
961
962         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
963
964         state.dom = dom;
965         state.ids = ids;
966         state.allocate_unmapped = false;
967
968         ret = idmap_tdb_sids_to_unixids_action(ctx->db, &state);
969
970         if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED) && !dom->read_only) {
971                 state.allocate_unmapped = true;
972                 ret = dbwrap_trans_do(ctx->db,
973                                       idmap_tdb_sids_to_unixids_action,
974                                       &state);
975         }
976
977         return ret;
978 }
979
980
981 /**********************************
982  Close the idmap tdb instance
983 **********************************/
984
985 static struct idmap_methods db_methods = {
986         .init = idmap_tdb_db_init,
987         .unixids_to_sids = idmap_tdb_unixids_to_sids,
988         .sids_to_unixids = idmap_tdb_sids_to_unixids,
989         .allocate_id = idmap_tdb_get_new_id,
990 };
991
992 NTSTATUS idmap_tdb_init(void)
993 {
994         DEBUG(10, ("calling idmap_tdb_init\n"));
995
996         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
997 }