2 Unix SMB/CIFS implementation.
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Anthony Liguori 2003
8 Copyright (C) Simo Sorce 2003
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.
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.
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.
29 #define DBGC_CLASS DBGC_IDMAP
31 /* High water mark keys */
32 #define HWM_GROUP "GROUP HWM"
33 #define HWM_USER "USER HWM"
35 /* idmap version determines auto-conversion */
36 #define IDMAP_VERSION 2
39 static TDB_CONTEXT
*idmap_tdb
;
41 /* FIXME: let handle conversions when all things work ok.
42 I think it is better to handle the conversion at
43 upgrade time and leave the old db intact.
44 That would also make easier to go back to 2.2 if needed
48 /* convert one record to the new format */
49 static int tdb_convert_fn(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA data
,
52 struct winbindd_domain
*domain
;
60 p
= strchr(key
.dptr
, '/');
65 fstrcpy(dom_name
, key
.dptr
);
68 domain
= find_domain_from_name(dom_name
);
70 /* We must delete the old record. */
72 ("winbindd: tdb_convert_fn : Unable to find domain %s\n",
75 ("winbindd: tdb_convert_fn : deleting record %s\n",
77 tdb_delete(idmap_tdb
, key
);
83 sid_copy(&sid
, &domain
->sid
);
84 sid_append_rid(&sid
, rid
);
86 sid_to_string(keystr
, &sid
);
88 key2
.dsize
= strlen(keystr
) + 1;
90 if (tdb_store(idmap_tdb
, key2
, data
, TDB_INSERT
) != 0) {
93 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
96 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
100 if (tdb_store(idmap_tdb
, data
, key2
, TDB_REPLACE
) != 0) {
103 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
106 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
110 tdb_delete(idmap_tdb
, key
);
115 /*****************************************************************************
116 Convert the idmap database from an older version.
117 *****************************************************************************/
118 static BOOL
tdb_idmap_convert(const char *idmap_name
)
120 int32 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
121 BOOL bigendianheader
=
122 (idmap_tdb
->flags
& TDB_BIGENDIAN
) ? True
: False
;
124 if (vers
== IDMAP_VERSION
)
127 if (((vers
== -1) && bigendianheader
)
128 || (IREV(vers
) == IDMAP_VERSION
)) {
129 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
131 * high and low records were created on a
132 * big endian machine and will need byte-reversing.
137 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
142 wm
= server_state
.uid_low
;
144 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
146 ("tdb_idmap_convert: Unable to byteswap user hwm in idmap database\n"));
150 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
154 wm
= server_state
.gid_low
;
156 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
158 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
163 /* the old format stored as DOMAIN/rid - now we store the SID direct */
164 tdb_traverse(idmap_tdb
, tdb_convert_fn
, NULL
);
166 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) ==
169 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
177 /* Allocate either a user or group id from the pool */
178 static NTSTATUS
tdb_allocate_id(id_t
*id
, int id_type
)
182 if (!id
) return NT_STATUS_INVALID_PARAMETER
;
184 /* Get current high water mark */
187 if ((hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
188 return NT_STATUS_INTERNAL_DB_ERROR
;
191 if (hwm
> server_state
.uid_high
) {
192 DEBUG(0, ("idmap Fatal Error: UID range full!!\n"));
193 return NT_STATUS_UNSUCCESSFUL
;
198 /* Store new high water mark */
199 tdb_store_int32(idmap_tdb
, HWM_USER
, hwm
);
202 if ((hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
203 return NT_STATUS_INTERNAL_DB_ERROR
;
206 if (hwm
> server_state
.gid_high
) {
207 DEBUG(0, ("idmap Fatal Error: GID range full!!\n"));
208 return NT_STATUS_UNSUCCESSFUL
;
213 /* Store new high water mark */
214 tdb_store_int32(idmap_tdb
, HWM_GROUP
, hwm
);
217 return NT_STATUS_INVALID_PARAMETER
;
223 /* Get a sid from an id */
224 static NTSTATUS
tdb_get_sid_from_id(DOM_SID
*sid
, id_t id
, int id_type
)
228 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
230 if (!sid
) return NT_STATUS_INVALID_PARAMETER
;
234 slprintf(keystr
, sizeof(keystr
), "UID %d", id
.uid
);
237 slprintf(keystr
, sizeof(keystr
), "GID %d", id
.gid
);
240 return NT_STATUS_UNSUCCESSFUL
;
244 key
.dsize
= strlen(keystr
) + 1;
246 data
= tdb_fetch(idmap_tdb
, key
);
249 if (string_to_sid(sid
, data
.dptr
)) {
252 SAFE_FREE(data
.dptr
);
258 /* Get an id from a sid */
259 static NTSTATUS
tdb_get_id_from_sid(id_t
*id
, int *id_type
, DOM_SID
*sid
)
263 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
265 if (!sid
|| !id
|| !id_type
) return NT_STATUS_INVALID_PARAMETER
;
267 /* Check if sid is present in database */
268 sid_to_string(keystr
, sid
);
271 key
.dsize
= strlen(keystr
) + 1;
273 data
= tdb_fetch(idmap_tdb
, key
);
278 if (*id_type
== ID_EMPTY
|| *id_type
== ID_USERID
) {
279 /* Parse and return existing uid */
280 fstrcpy(scanstr
, "UID %d");
282 if (sscanf(data
.dptr
, scanstr
, *id
.uid
) == 1) {
284 if (*id_type
== ID_EMPTY
) {
285 *id_type
= ID_USERID
;
292 if (*id_type
== ID_EMPTY
|| *id_type
== ID_GROUPID
) {
293 /* Parse and return existing gid */
294 fstrcpy(scanstr
, "GID %d");
296 if (sscanf(data
.dptr
, scanstr
, *id
.gid
) == 1) {
298 if (*id_type
== ID_EMPTY
) {
299 *id_type
= ID_GROUPID
;
305 SAFE_FREE(data
.dptr
);
307 } else if (*id_type
== ID_USERID
|| *id_type
== ID_GROUPID
) {
309 /* Allocate a new id for this sid */
310 ret
= tdb_allocate_id(id
, id_type
);
311 if (NT_STATUS_IS_OK(ret
)) {
315 slprintf(keystr2
, sizeof(keystr2
), "%s %d",
316 *id_type
? "GID" : "UID", *id
);
319 data
.dsize
= strlen(keystr2
) + 1;
321 if (tdb_store(idmap_tdb
, key
, data
, TDB_INSERT
) == -1)
322 return NT_STATUS_UNSUCCESSFUL
;
323 if (tdb_store(idmap_tdb
, data
, key
, TDB_INSERT
) == -1)
324 return NT_STATUS_UNSUCCESSFUL
;
333 /*****************************************************************************
334 Initialise idmap database.
335 *****************************************************************************/
336 static NTSTATUS
tdb_idmap_init(void)
339 if (!(idmap_tdb
= tdb_open_log(lock_path("idmap.tdb"), 0,
340 TDB_DEFAULT
, O_RDWR
| O_CREAT
,
342 DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
343 return NT_STATUS_UNSUCCESSFUL
;
347 /* possibly convert from an earlier version */
348 if (!tdb_idmap_convert(lock_path("winbind_idmap.tdb"))) {
350 ("idmap_init: Unable to open old idmap database\n"));
355 /* Create high water marks for group and user id */
356 if (tdb_fetch_int32(idmap_tdb
, HWM_USER
) == -1) {
357 if (tdb_store_int32(idmap_tdb
, HWM_USER
, server_state
.uid_low
) == -1) {
358 DEBUG(0, ("idmap_init: Unable to initialise user hwm in idmap database\n"));
359 return NT_STATUS_INTERNAL_DB_ERROR
;
363 if (tdb_fetch_int32(idmap_tdb
, HWM_GROUP
) == -1) {
364 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, server_state
.gid_low
) == -1) {
365 DEBUG(0, ("idmap_init: Unable to initialise group hwm in idmap database\n"));
366 return NT_STATUS_INTERNAL_DB_ERROR
;
374 static NTSTATUS
tdb_idmap_close(void)
377 if (tdb_close(idmap_tdb
) == 0)
380 retrun NT_STATUS_UNSUCCESSFUL
;
385 /* Dump status information to log file. Display different stuff based on
388 Debug Level Information Displayed
389 =================================================================
390 0 Percentage of [ug]id range allocated
391 0 High water marks (next allocated ids)
396 static void tdb_idmap_status(void)
398 int user_hwm
, group_hwm
;
400 DEBUG(0, ("winbindd idmap status:\n"));
402 /* Get current high water marks */
404 if ((user_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
406 ("\tCould not get userid high water mark!\n"));
409 if ((group_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
411 ("\tCould not get groupid high water mark!\n"));
414 /* Display next ids to allocate */
416 if (user_hwm
!= -1) {
418 ("\tNext userid to allocate is %d\n", user_hwm
));
421 if (group_hwm
!= -1) {
423 ("\tNext groupid to allocate is %d\n", group_hwm
));
426 /* Display percentage of id range already allocated. */
428 if (user_hwm
!= -1) {
429 int num_users
= user_hwm
- server_state
.uid_low
;
431 server_state
.uid_high
- server_state
.uid_low
;
434 ("\tUser id range is %d%% full (%d of %d)\n",
435 num_users
* 100 / total_users
, num_users
,
439 if (group_hwm
!= -1) {
440 int num_groups
= group_hwm
- server_state
.gid_low
;
442 server_state
.gid_high
- server_state
.gid_low
;
445 ("\tGroup id range is %d%% full (%d of %d)\n",
446 num_groups
* 100 / total_groups
, num_groups
,
450 /* Display complete mapping of users and groups to rids */
453 struct idmap_methods tdb_idmap_methods
= {
463 NTSTATUS
idmap_reg_tdb(struct idmap_methods
**meth
)
465 *meth
= &tdb_idmap_methods
;