2 Unix SMB/CIFS implementation.
4 Winbind daemon - user related function
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Anthony Liguori 2003
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_WINBIND
29 /* High water mark keys */
30 #define HWM_GROUP "GROUP HWM"
31 #define HWM_USER "USER HWM"
33 /* idmap version determines auto-conversion */
34 #define IDMAP_VERSION 2
37 static TDB_CONTEXT
*idmap_tdb
;
39 /* convert one record to the new format */
40 static int tdb_convert_fn(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA data
,
43 struct winbindd_domain
*domain
;
51 p
= strchr(key
.dptr
, '/');
56 fstrcpy(dom_name
, key
.dptr
);
59 domain
= find_domain_from_name(dom_name
);
61 /* We must delete the old record. */
63 ("winbindd: tdb_convert_fn : Unable to find domain %s\n",
66 ("winbindd: tdb_convert_fn : deleting record %s\n",
68 tdb_delete(idmap_tdb
, key
);
74 sid_copy(&sid
, &domain
->sid
);
75 sid_append_rid(&sid
, rid
);
77 sid_to_string(keystr
, &sid
);
79 key2
.dsize
= strlen(keystr
) + 1;
81 if (tdb_store(idmap_tdb
, key2
, data
, TDB_INSERT
) != 0) {
84 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
87 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
91 if (tdb_store(idmap_tdb
, data
, key2
, TDB_REPLACE
) != 0) {
94 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
97 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
101 tdb_delete(idmap_tdb
, key
);
106 /*****************************************************************************
107 Convert the idmap database from an older version.
108 *****************************************************************************/
109 static BOOL
tdb_idmap_convert(const char *idmap_name
)
111 int32 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
112 BOOL bigendianheader
=
113 (idmap_tdb
->flags
& TDB_BIGENDIAN
) ? True
: False
;
115 if (vers
== IDMAP_VERSION
)
118 if (((vers
== -1) && bigendianheader
)
119 || (IREV(vers
) == IDMAP_VERSION
)) {
120 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
122 * high and low records were created on a
123 * big endian machine and will need byte-reversing.
128 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
133 wm
= server_state
.uid_low
;
135 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
137 ("tdb_idmap_convert: Unable to byteswap user hwm in idmap database\n"));
141 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
145 wm
= server_state
.gid_low
;
147 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
149 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
154 /* the old format stored as DOMAIN/rid - now we store the SID direct */
155 tdb_traverse(idmap_tdb
, tdb_convert_fn
, NULL
);
157 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) ==
160 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
167 /* Allocate either a user or group id from the pool */
168 static BOOL
tdb_allocate_id(uid_t
* id
, BOOL isgroup
)
172 /* Get current high water mark */
173 if ((hwm
= tdb_fetch_int32(idmap_tdb
,
174 isgroup
? HWM_GROUP
: HWM_USER
)) ==
179 /* Return next available uid in list */
180 if ((isgroup
&& (hwm
> server_state
.gid_high
)) ||
181 (!isgroup
&& (hwm
> server_state
.uid_high
))) {
183 ("winbind %sid range full!\n", isgroup
? "g" : "u"));
193 /* Store new high water mark */
194 tdb_store_int32(idmap_tdb
, isgroup
? HWM_GROUP
: HWM_USER
, hwm
);
199 /* Get a sid from an id */
200 static BOOL
tdb_get_sid_from_id(int id
, DOM_SID
* sid
, BOOL isgroup
)
206 slprintf(keystr
, sizeof(keystr
), "%s %d", isgroup
? "GID" : "UID",
210 key
.dsize
= strlen(keystr
) + 1;
212 data
= tdb_fetch(idmap_tdb
, key
);
215 result
= string_to_sid(sid
, data
.dptr
);
216 SAFE_FREE(data
.dptr
);
222 /* Get an id from a sid */
223 static BOOL
tdb_get_id_from_sid(DOM_SID
* sid
, uid_t
* id
, BOOL isgroup
)
229 /* Check if sid is present in database */
230 sid_to_string(keystr
, sid
);
233 key
.dsize
= strlen(keystr
) + 1;
235 data
= tdb_fetch(idmap_tdb
, key
);
241 /* Parse and return existing uid */
242 fstrcpy(scanstr
, isgroup
? "GID" : "UID");
243 fstrcat(scanstr
, " %d");
245 if (sscanf(data
.dptr
, scanstr
, &the_id
) == 1) {
254 SAFE_FREE(data
.dptr
);
257 /* Allocate a new id for this sid */
258 if (id
&& tdb_allocate_id(id
, isgroup
)) {
262 slprintf(keystr2
, sizeof(keystr2
), "%s %d",
263 isgroup
? "GID" : "UID", *id
);
266 data
.dsize
= strlen(keystr2
) + 1;
268 tdb_store(idmap_tdb
, key
, data
, TDB_REPLACE
);
269 tdb_store(idmap_tdb
, data
, key
, TDB_REPLACE
);
278 /*****************************************************************************
279 Initialise idmap database.
280 *****************************************************************************/
281 static BOOL
tdb_idmap_init(void)
284 if (!(idmap_tdb
= tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
285 TDB_DEFAULT
, O_RDWR
| O_CREAT
,
288 ("winbindd_idmap_init: Unable to open idmap database\n"));
292 /* possibly convert from an earlier version */
293 if (!tdb_idmap_convert(lock_path("winbindd_idmap.tdb"))) {
295 ("winbindd_idmap_init: Unable to open idmap database\n"));
299 /* Create high water marks for group and user id */
300 if (tdb_fetch_int32(idmap_tdb
, HWM_USER
) == -1) {
302 (idmap_tdb
, HWM_USER
, server_state
.uid_low
) == -1) {
304 ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
309 if (tdb_fetch_int32(idmap_tdb
, HWM_GROUP
) == -1) {
311 (idmap_tdb
, HWM_GROUP
, server_state
.gid_low
) == -1) {
313 ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
321 /* Get a sid from a uid */
322 static BOOL
tdb_get_sid_from_uid(uid_t uid
, DOM_SID
* sid
)
324 return tdb_get_sid_from_id((int) uid
, sid
, False
);
327 /* Get a sid from a gid */
328 static BOOL
tdb_get_sid_from_gid(gid_t gid
, DOM_SID
* sid
)
330 return tdb_get_sid_from_id((int) gid
, sid
, True
);
333 /* Get a uid from a sid */
334 static BOOL
tdb_get_uid_from_sid(DOM_SID
* sid
, uid_t
* uid
)
336 return tdb_get_id_from_sid(sid
, uid
, False
);
339 /* Get a gid from a group sid */
340 static BOOL
tdb_get_gid_from_sid(DOM_SID
* sid
, gid_t
* gid
)
342 return tdb_get_id_from_sid(sid
, gid
, True
);
346 static BOOL
tdb_idmap_close(void)
349 return (tdb_close(idmap_tdb
) == 0);
354 /* Dump status information to log file. Display different stuff based on
357 Debug Level Information Displayed
358 =================================================================
359 0 Percentage of [ug]id range allocated
360 0 High water marks (next allocated ids)
365 static void tdb_idmap_status(void)
367 int user_hwm
, group_hwm
;
369 DEBUG(0, ("winbindd idmap status:\n"));
371 /* Get current high water marks */
373 if ((user_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
)) == -1) {
375 ("\tCould not get userid high water mark!\n"));
378 if ((group_hwm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
)) == -1) {
380 ("\tCould not get groupid high water mark!\n"));
383 /* Display next ids to allocate */
385 if (user_hwm
!= -1) {
387 ("\tNext userid to allocate is %d\n", user_hwm
));
390 if (group_hwm
!= -1) {
392 ("\tNext groupid to allocate is %d\n", group_hwm
));
395 /* Display percentage of id range already allocated. */
397 if (user_hwm
!= -1) {
398 int num_users
= user_hwm
- server_state
.uid_low
;
400 server_state
.uid_high
- server_state
.uid_low
;
403 ("\tUser id range is %d%% full (%d of %d)\n",
404 num_users
* 100 / total_users
, num_users
,
408 if (group_hwm
!= -1) {
409 int num_groups
= group_hwm
- server_state
.gid_low
;
411 server_state
.gid_high
- server_state
.gid_low
;
414 ("\tGroup id range is %d%% full (%d of %d)\n",
415 num_groups
* 100 / total_groups
, num_groups
,
419 /* Display complete mapping of users and groups to rids */
422 struct idmap_methods tdb_idmap_methods
= {
425 tdb_get_sid_from_uid
,
426 tdb_get_sid_from_gid
,
428 tdb_get_uid_from_sid
,
429 tdb_get_gid_from_sid
,
436 BOOL
winbind_idmap_reg_tdb(struct idmap_methods
**meth
)
438 *meth
= &tdb_idmap_methods
;