665c56d2f679523f7d76dbb249f287d5e256908c
[samba.git] / source3 / sam / 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) Simo Sorce 2003
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_IDMAP
29
30 /* High water mark keys */
31 #define HWM_GROUP  "GROUP HWM"
32 #define HWM_USER   "USER HWM"
33
34 /* Globals */
35 static TDB_CONTEXT *idmap_tdb;
36
37 static struct idmap_state {
38
39         /* User and group id pool */
40
41         uid_t uid_low, uid_high;               /* Range of uids to allocate */
42         gid_t gid_low, gid_high;               /* Range of gids to allocate */
43 } idmap_state;
44
45 /**********************************************************************
46  Allocate either a user or group id from the pool 
47 **********************************************************************/
48  
49 static NTSTATUS db_allocate_id(unid_t *id, int id_type)
50 {
51         BOOL ret;
52         int hwm;
53
54         if (!id)
55                 return NT_STATUS_INVALID_PARAMETER;
56
57         /* Get current high water mark */
58         switch (id_type & ID_TYPEMASK) {
59                 case ID_USERID:
60
61                         if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
62                                 return NT_STATUS_INTERNAL_DB_ERROR;
63                         }
64
65                         /* check it is in the range */
66                         if (hwm > idmap_state.uid_high) {
67                                 DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %lu)\n", 
68                                           (unsigned long)idmap_state.uid_high));
69                                 return NT_STATUS_UNSUCCESSFUL;
70                         }
71
72                         /* fetch a new id and increment it */
73                         ret = tdb_change_uint32_atomic(idmap_tdb, HWM_USER, (unsigned int *)&hwm, 1);
74                         if (!ret) {
75                                 DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
76                                 return NT_STATUS_UNSUCCESSFUL;
77                         }
78
79                         /* recheck it is in the range */
80                         if (hwm > idmap_state.uid_high) {
81                                 DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %lu)\n", 
82                                           (unsigned long)idmap_state.uid_high));
83                                 return NT_STATUS_UNSUCCESSFUL;
84                         }
85                         
86                         (*id).uid = hwm;
87                         DEBUG(10,("db_allocate_id: ID_USERID (*id).uid = %d\n", (unsigned int)hwm));
88
89                         break;
90                 case ID_GROUPID:
91                         if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
92                                 return NT_STATUS_INTERNAL_DB_ERROR;
93                         }
94
95                         /* check it is in the range */
96                         if (hwm > idmap_state.gid_high) {
97                                 DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %lu)\n", 
98                                           (unsigned long)idmap_state.gid_high));
99                                 return NT_STATUS_UNSUCCESSFUL;
100                         }
101
102                         /* fetch a new id and increment it */
103                         ret = tdb_change_uint32_atomic(idmap_tdb, HWM_GROUP, (unsigned int *)&hwm, 1);
104
105                         if (!ret) {
106                                 DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
107                                 return NT_STATUS_UNSUCCESSFUL;
108                         }
109
110                         /* recheck it is in the range */
111                         if (hwm > idmap_state.gid_high) {
112                                 DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %lu)\n", 
113                                           (unsigned long)idmap_state.gid_high));
114                                 return NT_STATUS_UNSUCCESSFUL;
115                         }
116                         
117                         (*id).gid = hwm;
118                         DEBUG(10,("db_allocate_id: ID_GROUPID (*id).gid = %d\n", (unsigned int)hwm));
119                         
120                         break;
121                 default:
122                         return NT_STATUS_INVALID_PARAMETER;
123         }
124
125         return NT_STATUS_OK;
126 }
127
128 /* Get a sid from an id */
129 static NTSTATUS internal_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
130 {
131         TDB_DATA key, data;
132         fstring keystr;
133         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
134
135         if (!sid)
136                 return NT_STATUS_INVALID_PARAMETER;
137
138         switch (id_type & ID_TYPEMASK) {
139                 case ID_USERID:
140                         slprintf(keystr, sizeof(keystr), "UID %lu", (unsigned long)id.uid);
141                         break;
142                 case ID_GROUPID:
143                         slprintf(keystr, sizeof(keystr), "GID %lu", (unsigned long)id.gid);
144                         break;
145                 default:
146                         return NT_STATUS_UNSUCCESSFUL;
147         }
148
149         key.dptr = keystr;
150         key.dsize = strlen(keystr) + 1;
151
152         DEBUG(10,("internal_get_sid_from_id: fetching record %s\n", keystr ));
153
154         data = tdb_fetch(idmap_tdb, key);
155
156         if (data.dptr) {
157                 if (string_to_sid(sid, data.dptr)) {
158                         DEBUG(10,("internal_get_sid_from_id: fetching record %s -> %s\n", keystr, data.dptr ));
159                         ret = NT_STATUS_OK;
160                 }
161                 SAFE_FREE(data.dptr);
162         }
163
164         return ret;
165 }
166
167 /* Error codes for get_id_from_sid */
168 enum getidfromsiderr { GET_ID_FROM_SID_OK = 0, GET_ID_FROM_SID_NOTFOUND, GET_ID_FROM_SID_WRONG_TYPE, GET_ID_FROM_SID_ERR };
169
170 static enum getidfromsiderr internal_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid) 
171 {
172         enum getidfromsiderr ret = GET_ID_FROM_SID_ERR;
173         fstring keystr;
174         TDB_DATA key, data;
175         int type = *id_type & ID_TYPEMASK;
176
177         /* Check if sid is present in database */
178         sid_to_string(keystr, sid);
179
180         key.dptr = keystr;
181         key.dsize = strlen(keystr) + 1;
182
183         DEBUG(10,("internal_get_id_from_sid: fetching record %s of type 0x%x\n", keystr, type ));
184
185         data = tdb_fetch(idmap_tdb, key);
186         if (!data.dptr) {
187                 DEBUG(10,("internal_get_id_from_sid: record %s not found\n", keystr ));
188                 return GET_ID_FROM_SID_NOTFOUND;
189         } else {
190                 DEBUG(10,("internal_get_id_from_sid: record %s -> %s\n", keystr, data.dptr ));
191         }
192
193         if (type == ID_EMPTY || type == ID_USERID) {
194                 fstring scanstr;
195                 /* Parse and return existing uid */
196                 fstrcpy(scanstr, "UID %d");
197                 
198                 if (sscanf(data.dptr, scanstr, &((*id).uid)) == 1) {
199                         /* uid ok? */
200                         if (type == ID_EMPTY) {
201                                 *id_type = ID_USERID;
202                         }
203                         DEBUG(10,("internal_get_id_from_sid: %s fetching record %s -> %s \n",
204                                                 (type == ID_EMPTY) ? "ID_EMPTY" : "ID_USERID",
205                                                 keystr, data.dptr ));
206                         ret = GET_ID_FROM_SID_OK;
207                 } else {
208                         ret = GET_ID_FROM_SID_WRONG_TYPE;
209                 }
210         }
211         
212         if ((ret != GET_ID_FROM_SID_OK) && (type == ID_EMPTY || type == ID_GROUPID)) {
213                 fstring scanstr;
214                 /* Parse and return existing gid */
215                 fstrcpy(scanstr, "GID %d");
216                 
217                 if (sscanf(data.dptr, scanstr, &((*id).gid)) == 1) {
218                         /* gid ok? */
219                         if (type == ID_EMPTY) {
220                                 *id_type = ID_GROUPID;
221                         }
222                         DEBUG(10,("internal_get_id_from_sid: %s fetching record %s -> %s \n",
223                                                 (type == ID_EMPTY) ? "ID_EMPTY" : "ID_GROUPID",
224                                                 keystr, data.dptr ));
225                         ret = GET_ID_FROM_SID_OK;
226                 } else {
227                         ret = GET_ID_FROM_SID_WRONG_TYPE;
228                 }
229         }
230         
231         SAFE_FREE(data.dptr);
232
233         return ret;
234 }
235
236 /* Get a sid from an id */
237 static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type_in)
238 {
239         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
240         enum getidfromsiderr iderr;
241         int id_type = id_type_in & ID_TYPEMASK;
242         unid_t id_tmp = id;
243         int id_type_tmp = id_type;
244
245         DEBUG(10,("db_get_sid_from_id: id_type_in = 0x%x\n", id_type_in));
246
247         ret = internal_get_sid_from_id(sid, id, id_type);
248         if (!NT_STATUS_IS_OK(ret)) {
249                 return ret;
250         }
251         
252         iderr = internal_get_id_from_sid(&id_tmp, &id_type_tmp, sid);
253         if (iderr != GET_ID_FROM_SID_OK) {
254                 return NT_STATUS_UNSUCCESSFUL;
255         }
256         if (id_type_tmp != id_type) {
257                 return NT_STATUS_UNSUCCESSFUL;
258         } else if (id_type == ID_USERID) { 
259                 if (id_tmp.uid != id.uid) {
260                         return NT_STATUS_UNSUCCESSFUL;
261                 }
262         } else if (id_type == ID_GROUPID) {
263                 if (id_tmp.gid != id.gid) {
264                         return NT_STATUS_UNSUCCESSFUL;
265                 }
266         } else {
267                 return NT_STATUS_UNSUCCESSFUL;
268         }
269         return ret;
270 }
271 /* Get an id from a sid */
272 static NTSTATUS db_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
273 {
274         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
275         enum getidfromsiderr iderr;
276
277         DEBUG(10,("db_get_id_from_sid\n"));
278
279         if (!sid || !id || !id_type)
280                 return NT_STATUS_INVALID_PARAMETER;
281
282         iderr = internal_get_id_from_sid(id, id_type, sid);
283         if (iderr == GET_ID_FROM_SID_OK) {
284                 DOM_SID sid_tmp;
285                 ret = internal_get_sid_from_id(&sid_tmp, *id, *id_type);
286                 if (NT_STATUS_IS_OK(ret)) {
287                         if (!sid_equal(&sid_tmp, sid)) {
288                                 return NT_STATUS_UNSUCCESSFUL;
289                         }
290                 }
291         } else if (iderr == GET_ID_FROM_SID_WRONG_TYPE) {
292                 /* We found a record but not the type we wanted.
293                  * This is an error, not an opportunity to overwrite...
294                  * JRA.
295                  */
296                 return NT_STATUS_UNSUCCESSFUL;
297         }
298
299         if (!(*id_type & ID_QUERY_ONLY) && (iderr != GET_ID_FROM_SID_OK) &&
300                    (((*id_type & ID_TYPEMASK) == ID_USERID)
301                     || (*id_type & ID_TYPEMASK) == ID_GROUPID)) {
302                 TDB_DATA sid_data;
303                 TDB_DATA ugid_data;
304                 fstring sid_string;
305                 
306                 sid_to_string(sid_string, sid);
307                 
308                 sid_data.dptr = sid_string;
309                 sid_data.dsize = strlen(sid_string)+1;
310
311                 /* Lock the record for this SID. */
312                 if (tdb_chainlock(idmap_tdb, sid_data) != 0) {
313                         DEBUG(10,("db_get_id_from_sid: failed to lock record %s. Error %s\n",
314                                         sid_string, tdb_errorstr(idmap_tdb) ));
315                         return NT_STATUS_UNSUCCESSFUL;
316                 }
317
318                 do {
319                         fstring ugid_str;
320
321                         /* Allocate a new id for this sid */
322                         ret = db_allocate_id(id, *id_type);
323                         if (!NT_STATUS_IS_OK(ret))
324                                 break;
325                         
326                         /* Store the UID side */
327                         /* Store new id */
328                         if (*id_type & ID_USERID) {
329                                 slprintf(ugid_str, sizeof(ugid_str), "UID %lu", 
330                                          (unsigned long)((*id).uid));
331                         } else {
332                                 slprintf(ugid_str, sizeof(ugid_str), "GID %lu", 
333                                          (unsigned long)((*id).gid));
334                         }
335                         
336                         ugid_data.dptr = ugid_str;
337                         ugid_data.dsize = strlen(ugid_str) + 1;
338
339                         DEBUG(10,("db_get_id_from_sid: storing %s -> %s\n",
340                                         ugid_data.dptr, sid_data.dptr ));
341
342                         if (tdb_store(idmap_tdb, ugid_data, sid_data, TDB_INSERT) != -1) {
343                                 ret = NT_STATUS_OK;
344                                 break;
345                         }
346                         if (tdb_error(idmap_tdb) != TDB_ERR_EXISTS)
347                                 DEBUG(10,("db_get_id_from_sid: error %s\n", tdb_errorstr(idmap_tdb) ));
348                         ret = NT_STATUS_UNSUCCESSFUL;
349                 } while (tdb_error(idmap_tdb) == TDB_ERR_EXISTS);
350
351                 if (NT_STATUS_IS_OK(ret)) {
352
353                         DEBUG(10,("db_get_id_from_sid: storing %s -> %s\n",
354                                 sid_data.dptr, ugid_data.dptr ));
355
356                         if (tdb_store(idmap_tdb, sid_data, ugid_data, TDB_REPLACE) == -1) {
357                                 DEBUG(10,("db_get_id_from_sid: error %s\n", tdb_errorstr(idmap_tdb) ));
358                                 /* TODO: print tdb error !! */
359                                 tdb_chainunlock(idmap_tdb, sid_data);
360                                 return NT_STATUS_UNSUCCESSFUL;
361                         }
362                 }
363
364                 tdb_chainunlock(idmap_tdb, sid_data);
365         }
366         
367         return ret;
368 }
369
370 static NTSTATUS db_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
371 {
372         TDB_DATA ksid, kid, data;
373         fstring ksidstr;
374         fstring kidstr;
375
376         DEBUG(10,("db_set_mapping: id_type = 0x%x\n", id_type));
377
378         if (!sid)
379                 return NT_STATUS_INVALID_PARAMETER;
380
381         sid_to_string(ksidstr, sid);
382
383         ksid.dptr = ksidstr;
384         ksid.dsize = strlen(ksidstr) + 1;
385
386         if (id_type & ID_USERID) {
387                 slprintf(kidstr, sizeof(kidstr), "UID %lu", (unsigned long)id.uid);
388         } else if (id_type & ID_GROUPID) {
389                 slprintf(kidstr, sizeof(kidstr), "GID %lu", (unsigned long)id.gid);
390         } else {
391                 return NT_STATUS_INVALID_PARAMETER;
392         }
393
394         kid.dptr = kidstr;
395         kid.dsize = strlen(kidstr) + 1;
396
397         /* *DELETE* prevoius mappings if any.
398          * This is done both SID and [U|G]ID passed in */
399         
400         /* Lock the record for this SID. */
401         if (tdb_chainlock(idmap_tdb, ksid) != 0) {
402                 DEBUG(10,("db_set_mapping: failed to lock record %s. Error %s\n",
403                                 ksidstr, tdb_errorstr(idmap_tdb) ));
404                 return NT_STATUS_UNSUCCESSFUL;
405         }
406
407         DEBUG(10,("db_set_mapping: fetching %s\n", ksid.dptr));
408
409         data = tdb_fetch(idmap_tdb, ksid);
410         if (data.dptr) {
411                 DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, ksid.dptr ));
412                 tdb_delete(idmap_tdb, data);
413                 tdb_delete(idmap_tdb, ksid);
414                 SAFE_FREE(data.dptr);
415         }
416         data = tdb_fetch(idmap_tdb, kid);
417         if (data.dptr) {
418                 DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, kid.dptr ));
419                 tdb_delete(idmap_tdb, data);
420                 tdb_delete(idmap_tdb, kid);
421                 SAFE_FREE(data.dptr);
422         }
423
424         if (tdb_store(idmap_tdb, ksid, kid, TDB_INSERT) == -1) {
425                 DEBUG(0, ("idb_set_mapping: tdb_store 1 error: %s\n", tdb_errorstr(idmap_tdb)));
426                 tdb_chainunlock(idmap_tdb, ksid);
427                 return NT_STATUS_UNSUCCESSFUL;
428         }
429         if (tdb_store(idmap_tdb, kid, ksid, TDB_INSERT) == -1) {
430                 DEBUG(0, ("idb_set_mapping: tdb_store 2 error: %s\n", tdb_errorstr(idmap_tdb)));
431                 tdb_chainunlock(idmap_tdb, ksid);
432                 return NT_STATUS_UNSUCCESSFUL;
433         }
434
435         tdb_chainunlock(idmap_tdb, ksid);
436         DEBUG(10,("db_set_mapping: stored %s -> %s and %s -> %s\n", ksid.dptr, kid.dptr, kid.dptr, ksid.dptr ));
437         return NT_STATUS_OK;
438 }
439
440 /*****************************************************************************
441  Initialise idmap database. 
442 *****************************************************************************/
443
444 static NTSTATUS db_idmap_init( char *params )
445 {
446         SMB_STRUCT_STAT stbuf;
447         char *tdbfile = NULL;
448         int32 version;
449         BOOL tdb_is_new = False;
450
451         /* use the old database if present */
452         tdbfile = SMB_STRDUP(lock_path("winbindd_idmap.tdb"));
453         if (!tdbfile) {
454                 DEBUG(0, ("idmap_init: out of memory!\n"));
455                 return NT_STATUS_NO_MEMORY;
456         }
457
458         if (!file_exist(tdbfile, &stbuf)) {
459                 tdb_is_new = True;
460         }
461
462         DEBUG(10,("db_idmap_init: Opening tdbfile %s\n", tdbfile ));
463
464         /* Open idmap repository */
465         if (!(idmap_tdb = tdb_open_log(tdbfile, 0,
466                                        TDB_DEFAULT, O_RDWR | O_CREAT,
467                                        0644))) {
468                 DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
469                 SAFE_FREE(tdbfile);
470                 return NT_STATUS_UNSUCCESSFUL;
471         }
472
473         SAFE_FREE(tdbfile);
474
475         if (tdb_is_new) {
476                 /* the file didn't existed before opening it, let's
477                  * store idmap version as nobody else yet opened and
478                  * stored it. I do not like this method but didn't
479                  * found a way to understand if an opened tdb have
480                  * been just created or not --- SSS */
481                 tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION);
482         }
483
484         /* check against earlier versions */
485         version = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
486         if (version != IDMAP_VERSION) {
487                 DEBUG(0, ("idmap_init: Unable to open idmap database, it's in an old format!\n"));
488                 return NT_STATUS_INTERNAL_DB_ERROR;
489         }
490
491         /* Create high water marks for group and user id */
492         if (!lp_idmap_uid(&idmap_state.uid_low, &idmap_state.uid_high)) {
493                 DEBUG(1, ("idmap uid range missing or invalid\n"));
494                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
495         } else {
496                 if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
497                         if (tdb_store_int32(idmap_tdb, HWM_USER, idmap_state.uid_low) == -1) {
498                                 DEBUG(0, ("idmap_init: Unable to initialise user hwm in idmap database\n"));
499                                 return NT_STATUS_INTERNAL_DB_ERROR;
500                         }
501                 }
502         }
503
504         if (!lp_idmap_gid(&idmap_state.gid_low, &idmap_state.gid_high)) {
505                 DEBUG(1, ("idmap gid range missing or invalid\n"));
506                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
507         } else {
508                 if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
509                         if (tdb_store_int32(idmap_tdb, HWM_GROUP, idmap_state.gid_low) == -1) {
510                                 DEBUG(0, ("idmap_init: Unable to initialise group hwm in idmap database\n"));
511                                 return NT_STATUS_INTERNAL_DB_ERROR;
512                         }
513                 }
514         }
515
516         return NT_STATUS_OK;
517 }
518
519 /* Close the tdb */
520 static NTSTATUS db_idmap_close(void)
521 {
522         if (idmap_tdb) {
523                 if (tdb_close(idmap_tdb) == 0) {
524                         return NT_STATUS_OK;
525                 } else {
526                         return NT_STATUS_UNSUCCESSFUL;
527                 }
528         }
529         return NT_STATUS_OK;
530 }
531
532
533 /* Dump status information to log file.  Display different stuff based on
534    the debug level:
535
536    Debug Level        Information Displayed
537    =================================================================
538    0                  Percentage of [ug]id range allocated
539    0                  High water marks (next allocated ids)
540 */
541
542 #define DUMP_INFO 0
543
544 static void db_idmap_status(void)
545 {
546         int user_hwm, group_hwm;
547
548         DEBUG(0, ("winbindd idmap status:\n"));
549
550         /* Get current high water marks */
551
552         if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
553                 DEBUG(DUMP_INFO,
554                       ("\tCould not get userid high water mark!\n"));
555         }
556
557         if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
558                 DEBUG(DUMP_INFO,
559                       ("\tCould not get groupid high water mark!\n"));
560         }
561
562         /* Display next ids to allocate */
563
564         if (user_hwm != -1) {
565                 DEBUG(DUMP_INFO,
566                       ("\tNext userid to allocate is %d\n", user_hwm));
567         }
568
569         if (group_hwm != -1) {
570                 DEBUG(DUMP_INFO,
571                       ("\tNext groupid to allocate is %d\n", group_hwm));
572         }
573
574         /* Display percentage of id range already allocated. */
575
576         if (user_hwm != -1) {
577                 int num_users = user_hwm - idmap_state.uid_low;
578                 int total_users =
579                     idmap_state.uid_high - idmap_state.uid_low;
580
581                 DEBUG(DUMP_INFO,
582                       ("\tUser id range is %d%% full (%d of %d)\n",
583                        num_users * 100 / total_users, num_users,
584                        total_users));
585         }
586
587         if (group_hwm != -1) {
588                 int num_groups = group_hwm - idmap_state.gid_low;
589                 int total_groups =
590                     idmap_state.gid_high - idmap_state.gid_low;
591
592                 DEBUG(DUMP_INFO,
593                       ("\tGroup id range is %d%% full (%d of %d)\n",
594                        num_groups * 100 / total_groups, num_groups,
595                        total_groups));
596         }
597
598         /* Display complete mapping of users and groups to rids */
599 }
600
601 /**********************************************************************
602  Return the TDB_CONTEXT* for winbindd_idmap.  I **really** feel
603  dirty doing this, but not so dirty that I want to create another 
604  tdb
605 ***********************************************************************/
606
607 TDB_CONTEXT *idmap_tdb_handle( void )
608 {
609         if ( idmap_tdb )
610                 return idmap_tdb;
611                 
612         /* go ahead an open it;  db_idmap_init() doesn't use any params 
613            right now */
614            
615         db_idmap_init( NULL );
616         if ( idmap_tdb )
617                 return idmap_tdb;
618                 
619         return NULL;
620 }
621
622 static struct idmap_methods db_methods = {
623
624         db_idmap_init,
625         db_allocate_id,
626         db_get_sid_from_id,
627         db_get_id_from_sid,
628         db_set_mapping,
629         db_idmap_close,
630         db_idmap_status
631
632 };
633
634 NTSTATUS idmap_tdb_init(void)
635 {
636         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
637 }