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.
28 #define DBGC_CLASS DBGC_IDMAP
30 /* High water mark keys */
31 #define HWM_GROUP "GROUP HWM"
32 #define HWM_USER "USER HWM"
34 /* idmap version determines auto-conversion */
35 #define IDMAP_VERSION 2
38 static TDB_CONTEXT
*idmap_tdb
;
40 static struct idmap_state
{
42 /* User and group id pool */
44 uid_t uid_low
, uid_high
; /* Range of uids to allocate */
45 gid_t gid_low
, gid_high
; /* Range of gids to allocate */
48 /* Allocate either a user or group id from the pool */
49 static NTSTATUS
db_allocate_id(unid_t
*id
, int id_type
)
53 if (!id
) return NT_STATUS_INVALID_PARAMETER
;
55 /* Get current high water mark */
56 switch (id_type
& ID_TYPEMASK
) {
58 if ((hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
59 return NT_STATUS_INTERNAL_DB_ERROR
;
62 if (hwm
> idmap_state
.uid_high
) {
63 DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state
.uid_high
));
64 return NT_STATUS_UNSUCCESSFUL
;
69 /* Store new high water mark */
70 tdb_store_int32(idmap_tdb
, HWM_USER
, hwm
);
73 if ((hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
74 return NT_STATUS_INTERNAL_DB_ERROR
;
77 if (hwm
> idmap_state
.gid_high
) {
78 DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %u)\n", idmap_state
.gid_high
));
79 return NT_STATUS_UNSUCCESSFUL
;
84 /* Store new high water mark */
85 tdb_store_int32(idmap_tdb
, HWM_GROUP
, hwm
);
88 return NT_STATUS_INVALID_PARAMETER
;
94 /* Get a sid from an id */
95 static NTSTATUS
db_get_sid_from_id(DOM_SID
*sid
, unid_t id
, int id_type
)
99 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
101 if (!sid
) return NT_STATUS_INVALID_PARAMETER
;
103 switch (id_type
& ID_TYPEMASK
) {
105 slprintf(keystr
, sizeof(keystr
), "UID %d", id
.uid
);
108 slprintf(keystr
, sizeof(keystr
), "GID %d", id
.gid
);
111 return NT_STATUS_UNSUCCESSFUL
;
115 key
.dsize
= strlen(keystr
) + 1;
117 data
= tdb_fetch(idmap_tdb
, key
);
120 if (string_to_sid(sid
, data
.dptr
)) {
123 SAFE_FREE(data
.dptr
);
129 /* Get an id from a sid */
130 static NTSTATUS
db_get_id_from_sid(unid_t
*id
, int *id_type
, const DOM_SID
*sid
)
134 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
136 if (!sid
|| !id
|| !id_type
) return NT_STATUS_INVALID_PARAMETER
;
138 /* Check if sid is present in database */
139 sid_to_string(keystr
, sid
);
142 key
.dsize
= strlen(keystr
) + 1;
144 data
= tdb_fetch(idmap_tdb
, key
);
147 int type
= *id_type
& ID_TYPEMASK
;
150 if (type
== ID_EMPTY
|| type
== ID_USERID
) {
151 /* Parse and return existing uid */
152 fstrcpy(scanstr
, "UID %d");
154 if (sscanf(data
.dptr
, scanstr
, &((*id
).uid
)) == 1) {
156 if (type
== ID_EMPTY
) {
157 *id_type
= ID_USERID
;
164 if (type
== ID_EMPTY
|| type
== ID_GROUPID
) {
165 /* Parse and return existing gid */
166 fstrcpy(scanstr
, "GID %d");
168 if (sscanf(data
.dptr
, scanstr
, &((*id
).gid
)) == 1) {
170 if (type
== ID_EMPTY
) {
171 *id_type
= ID_GROUPID
;
177 SAFE_FREE(data
.dptr
);
179 } else if (!(*id_type
& ID_NOMAP
) &&
180 (((*id_type
& ID_TYPEMASK
) == ID_USERID
)
181 || (*id_type
& ID_TYPEMASK
) == ID_GROUPID
)) {
183 /* Allocate a new id for this sid */
184 ret
= db_allocate_id(id
, *id_type
);
185 if (NT_STATUS_IS_OK(ret
)) {
189 if (*id_type
& ID_USERID
) {
190 slprintf(keystr2
, sizeof(keystr2
), "UID %d", (*id
).uid
);
192 slprintf(keystr2
, sizeof(keystr2
), "GID %d", (*id
).gid
);
196 data
.dsize
= strlen(keystr2
) + 1;
198 if (tdb_store(idmap_tdb
, key
, data
, TDB_REPLACE
) == -1) {
199 /* TODO: print tdb error !! */
200 return NT_STATUS_UNSUCCESSFUL
;
202 if (tdb_store(idmap_tdb
, data
, key
, TDB_REPLACE
) == -1) {
203 /* TODO: print tdb error !! */
204 return NT_STATUS_UNSUCCESSFUL
;
214 static NTSTATUS
db_set_mapping(const DOM_SID
*sid
, unid_t id
, int id_type
)
220 if (!sid
) return NT_STATUS_INVALID_PARAMETER
;
222 sid_to_string(ksidstr
, sid
);
225 ksid
.dsize
= strlen(ksidstr
) + 1;
227 if (id_type
& ID_USERID
) {
228 slprintf(kidstr
, sizeof(kidstr
), "UID %d", id
.uid
);
229 } else if (id_type
& ID_GROUPID
) {
230 slprintf(kidstr
, sizeof(kidstr
), "GID %d", id
.gid
);
232 return NT_STATUS_INVALID_PARAMETER
;
236 kid
.dsize
= strlen(kidstr
) + 1;
238 if (tdb_store(idmap_tdb
, ksid
, kid
, TDB_INSERT
) == -1) {
239 DEBUG(0, ("idb_set_mapping: tdb_store 1 error: %s\n", tdb_errorstr(idmap_tdb
)));
240 return NT_STATUS_UNSUCCESSFUL
;
242 if (tdb_store(idmap_tdb
, kid
, ksid
, TDB_INSERT
) == -1) {
243 DEBUG(0, ("idb_set_mapping: tdb_store 2 error: %s\n", tdb_errorstr(idmap_tdb
)));
244 return NT_STATUS_UNSUCCESSFUL
;
249 /*****************************************************************************
250 Initialise idmap database.
251 *****************************************************************************/
252 static NTSTATUS
db_idmap_init(void)
254 SMB_STRUCT_STAT stbuf
;
258 /* use the old database if present */
259 if (!file_exist(lock_path("idmap.tdb"), &stbuf
)) {
260 if (file_exist(lock_path("winbindd_idmap.tdb"), &stbuf
)) {
261 DEBUG(0, ("idmap_init: using winbindd_idmap.tdb file!\n"));
262 tdbfile
= strdup(lock_path("winbindd_idmap.tdb"));
264 DEBUG(0, ("idmap_init: out of memory!\n"));
265 return NT_STATUS_NO_MEMORY
;
269 tdbfile
= strdup(lock_path("idmap.tdb"));
271 DEBUG(0, ("idmap_init: out of memory!\n"));
272 return NT_STATUS_NO_MEMORY
;
277 if (!(idmap_tdb
= tdb_open_log(tdbfile
, 0,
278 TDB_DEFAULT
, O_RDWR
| O_CREAT
,
280 DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
282 return NT_STATUS_UNSUCCESSFUL
;
287 /* check against earlier versions */
288 version
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
289 if (version
!= IDMAP_VERSION
) {
290 DEBUG(0, ("idmap_init: Unable to open idmap database, it's in an old format!\n"));
291 return NT_STATUS_INTERNAL_DB_ERROR
;
294 /* Create high water marks for group and user id */
295 if (tdb_fetch_int32(idmap_tdb
, HWM_USER
) == -1) {
296 if (tdb_store_int32(idmap_tdb
, HWM_USER
, idmap_state
.uid_low
) == -1) {
297 DEBUG(0, ("idmap_init: Unable to initialise user hwm in idmap database\n"));
298 return NT_STATUS_INTERNAL_DB_ERROR
;
302 if (tdb_fetch_int32(idmap_tdb
, HWM_GROUP
) == -1) {
303 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, idmap_state
.gid_low
) == -1) {
304 DEBUG(0, ("idmap_init: Unable to initialise group hwm in idmap database\n"));
305 return NT_STATUS_INTERNAL_DB_ERROR
;
309 if (!lp_idmap_uid(&idmap_state
.uid_low
, &idmap_state
.uid_high
)) {
310 DEBUG(0, ("idmap uid range missing or invalid\n"));
311 DEBUGADD(0, ("idmap will be unable to map foreign SIDs\n"));
314 if (!lp_idmap_gid(&idmap_state
.gid_low
, &idmap_state
.gid_high
)) {
315 DEBUG(0, ("idmap gid range missing or invalid\n"));
316 DEBUGADD(0, ("idmap will be unable to map foreign SIDs\n"));
323 static NTSTATUS
db_idmap_close(void)
326 if (tdb_close(idmap_tdb
) == 0) {
329 return NT_STATUS_UNSUCCESSFUL
;
336 /* Dump status information to log file. Display different stuff based on
339 Debug Level Information Displayed
340 =================================================================
341 0 Percentage of [ug]id range allocated
342 0 High water marks (next allocated ids)
347 static void db_idmap_status(void)
349 int user_hwm
, group_hwm
;
351 DEBUG(0, ("winbindd idmap status:\n"));
353 /* Get current high water marks */
355 if ((user_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
357 ("\tCould not get userid high water mark!\n"));
360 if ((group_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
362 ("\tCould not get groupid high water mark!\n"));
365 /* Display next ids to allocate */
367 if (user_hwm
!= -1) {
369 ("\tNext userid to allocate is %d\n", user_hwm
));
372 if (group_hwm
!= -1) {
374 ("\tNext groupid to allocate is %d\n", group_hwm
));
377 /* Display percentage of id range already allocated. */
379 if (user_hwm
!= -1) {
380 int num_users
= user_hwm
- idmap_state
.uid_low
;
382 idmap_state
.uid_high
- idmap_state
.uid_low
;
385 ("\tUser id range is %d%% full (%d of %d)\n",
386 num_users
* 100 / total_users
, num_users
,
390 if (group_hwm
!= -1) {
391 int num_groups
= group_hwm
- idmap_state
.gid_low
;
393 idmap_state
.gid_high
- idmap_state
.gid_low
;
396 ("\tGroup id range is %d%% full (%d of %d)\n",
397 num_groups
* 100 / total_groups
, num_groups
,
401 /* Display complete mapping of users and groups to rids */
404 struct idmap_methods db_methods
= {
415 NTSTATUS
idmap_reg_tdb(struct idmap_methods
**meth
)