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(void)
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)
283 SMB_STRUCT_STAT stbuf;
285 /* move to the new database on first startup */
286 if (!file_exist(lock_path("idmap.tdb"), &stbuf)) {
287 if (file_exist(lock_path("winbindd_idmap.tdb"), &stbuf)) {
291 if (asprintf(&cmd, "cp -p %s/winbindd_idmap.tdb %s/idmap.tdb", lp_lockdir(), lp_lockdir()) != -1) {
295 if (!file_exist(lock_path("idmap.tdb"), &stbuf)) {
296 DEBUG(0, ("idmap_init: Unable to make a new database copy\n"));
303 if (!(idmap_tdb = tdb_open_log(lock_path("idmap.tdb"), 0,
304 TDB_DEFAULT, O_RDWR | O_CREAT,
307 ("winbindd_idmap_init: Unable to open idmap database\n"));
311 /* possibly convert from an earlier version */
312 if (!tdb_idmap_convert()) {
313 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
317 /* Create high water marks for group and user id */
318 if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
320 (idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
322 ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
327 if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
329 (idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
331 ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
339 /* Get a sid from a uid */
340 static BOOL tdb_get_sid_from_uid(uid_t uid, DOM_SID * sid)
342 return tdb_get_sid_from_id((int) uid, sid, False);
345 /* Get a sid from a gid */
346 static BOOL tdb_get_sid_from_gid(gid_t gid, DOM_SID * sid)
348 return tdb_get_sid_from_id((int) gid, sid, True);
351 /* Get a uid from a sid */
352 static BOOL tdb_get_uid_from_sid(DOM_SID * sid, uid_t * uid)
354 return tdb_get_id_from_sid(sid, uid, False);
357 /* Get a gid from a group sid */
358 static BOOL tdb_get_gid_from_sid(DOM_SID * sid, gid_t * gid)
360 return tdb_get_id_from_sid(sid, gid, True);
364 static BOOL tdb_idmap_close(void)
367 return (tdb_close(idmap_tdb) == 0);
372 /* Dump status information to log file. Display different stuff based on
375 Debug Level Information Displayed
376 =================================================================
377 0 Percentage of [ug]id range allocated
378 0 High water marks (next allocated ids)
383 static void tdb_idmap_status(void)
385 int user_hwm, group_hwm;
387 DEBUG(0, ("winbindd idmap status:\n"));
389 /* Get current high water marks */
391 if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
393 ("\tCould not get userid high water mark!\n"));
396 if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
398 ("\tCould not get groupid high water mark!\n"));
401 /* Display next ids to allocate */
403 if (user_hwm != -1) {
405 ("\tNext userid to allocate is %d\n", user_hwm));
408 if (group_hwm != -1) {
410 ("\tNext groupid to allocate is %d\n", group_hwm));
413 /* Display percentage of id range already allocated. */
415 if (user_hwm != -1) {
416 int num_users = user_hwm - server_state.uid_low;
418 server_state.uid_high - server_state.uid_low;
421 ("\tUser id range is %d%% full (%d of %d)\n",
422 num_users * 100 / total_users, num_users,
426 if (group_hwm != -1) {
427 int num_groups = group_hwm - server_state.gid_low;
429 server_state.gid_high - server_state.gid_low;
432 ("\tGroup id range is %d%% full (%d of %d)\n",
433 num_groups * 100 / total_groups, num_groups,
437 /* Display complete mapping of users and groups to rids */
440 struct winbindd_idmap_methods tdb_idmap_methods = {
443 tdb_get_sid_from_uid,
444 tdb_get_sid_from_gid,
446 tdb_get_uid_from_sid,
447 tdb_get_gid_from_sid,
454 BOOL winbind_idmap_reg_tdb(struct winbindd_idmap_methods **meth)
456 *meth = &tdb_idmap_methods;