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;