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