don't dereference null pointer
[Samba/gebeck_regimport.git] / source4 / nsswitch / winbindd_idmap_tdb.c
blob911b3b41d2145313006fea8b7f0c8c0dafa91c61
1 /*
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.
24 #include "winbindd.h"
26 #undef DBGC_CLASS
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
36 /* Globals */
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,
41 void *ignored)
43 struct winbindd_domain *domain;
44 char *p;
45 DOM_SID sid;
46 uint32 rid;
47 fstring keystr;
48 fstring dom_name;
49 TDB_DATA key2;
51 p = strchr(key.dptr, '/');
52 if (!p)
53 return 0;
55 *p = 0;
56 fstrcpy(dom_name, key.dptr);
57 *p++ = '/';
59 domain = find_domain_from_name(dom_name);
60 if (!domain) {
61 /* We must delete the old record. */
62 DEBUG(0,
63 ("winbindd: tdb_convert_fn : Unable to find domain %s\n",
64 dom_name));
65 DEBUG(0,
66 ("winbindd: tdb_convert_fn : deleting record %s\n",
67 key.dptr));
68 tdb_delete(idmap_tdb, key);
69 return 0;
72 rid = atoi(p);
74 sid_copy(&sid, &domain->sid);
75 sid_append_rid(&sid, rid);
77 sid_to_string(keystr, &sid);
78 key2.dptr = keystr;
79 key2.dsize = strlen(keystr) + 1;
81 if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) {
82 /* not good! */
83 DEBUG(0,
84 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
85 key2.dptr));
86 DEBUG(0,
87 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
88 return -1;
91 if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) {
92 /* not good! */
93 DEBUG(0,
94 ("winbindd: tdb_convert_fn : Unable to update record %s\n",
95 data.dptr));
96 DEBUG(0,
97 ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
98 return -1;
101 tdb_delete(idmap_tdb, key);
103 return 0;
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)
116 return True;
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.
126 int32 wm;
128 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
130 if (wm != -1) {
131 wm = IREV(wm);
132 } else
133 wm = server_state.uid_low;
135 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
136 DEBUG(0,
137 ("tdb_idmap_convert: Unable to byteswap user hwm in idmap database\n"));
138 return False;
141 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
142 if (wm != -1) {
143 wm = IREV(wm);
144 } else
145 wm = server_state.gid_low;
147 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
148 DEBUG(0,
149 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
150 return False;
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) ==
158 -1) {
159 DEBUG(0,
160 ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
161 return False;
164 return True;
167 /* Allocate either a user or group id from the pool */
168 static BOOL tdb_allocate_id(uid_t * id, BOOL isgroup)
170 int hwm;
172 /* Get current high water mark */
173 if ((hwm = tdb_fetch_int32(idmap_tdb,
174 isgroup ? HWM_GROUP : HWM_USER)) ==
175 -1) {
176 return False;
179 /* Return next available uid in list */
180 if ((isgroup && (hwm > server_state.gid_high)) ||
181 (!isgroup && (hwm > server_state.uid_high))) {
182 DEBUG(0,
183 ("winbind %sid range full!\n", isgroup ? "g" : "u"));
184 return False;
187 if (id) {
188 *id = hwm;
191 hwm++;
193 /* Store new high water mark */
194 tdb_store_int32(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm);
196 return True;
199 /* Get a sid from an id */
200 static BOOL tdb_get_sid_from_id(int id, DOM_SID * sid, BOOL isgroup)
202 TDB_DATA key, data;
203 fstring keystr;
204 BOOL result = False;
206 slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID",
207 id);
209 key.dptr = keystr;
210 key.dsize = strlen(keystr) + 1;
212 data = tdb_fetch(idmap_tdb, key);
214 if (data.dptr) {
215 result = string_to_sid(sid, data.dptr);
216 SAFE_FREE(data.dptr);
219 return result;
222 /* Get an id from a sid */
223 static BOOL tdb_get_id_from_sid(DOM_SID * sid, uid_t * id, BOOL isgroup)
225 TDB_DATA data, key;
226 fstring keystr;
227 BOOL result = False;
229 /* Check if sid is present in database */
230 sid_to_string(keystr, sid);
232 key.dptr = keystr;
233 key.dsize = strlen(keystr) + 1;
235 data = tdb_fetch(idmap_tdb, key);
237 if (data.dptr) {
238 fstring scanstr;
239 int the_id;
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) {
246 /* Store uid */
247 if (id) {
248 *id = the_id;
251 result = True;
254 SAFE_FREE(data.dptr);
255 } else {
257 /* Allocate a new id for this sid */
258 if (id && tdb_allocate_id(id, isgroup)) {
259 fstring keystr2;
261 /* Store new id */
262 slprintf(keystr2, sizeof(keystr2), "%s %d",
263 isgroup ? "GID" : "UID", *id);
265 data.dptr = keystr2;
266 data.dsize = strlen(keystr2) + 1;
268 tdb_store(idmap_tdb, key, data, TDB_REPLACE);
269 tdb_store(idmap_tdb, data, key, TDB_REPLACE);
271 result = True;
275 return result;
278 /*****************************************************************************
279 Initialise idmap database.
280 *****************************************************************************/
281 static BOOL tdb_idmap_init(void)
283 /* Open tdb cache */
284 if (!(idmap_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
285 TDB_DEFAULT, O_RDWR | O_CREAT,
286 0600))) {
287 DEBUG(0,
288 ("winbindd_idmap_init: Unable to open idmap database\n"));
289 return False;
292 /* possibly convert from an earlier version */
293 if (!tdb_idmap_convert(lock_path("winbindd_idmap.tdb"))) {
294 DEBUG(0,
295 ("winbindd_idmap_init: Unable to open idmap database\n"));
296 return False;
299 /* Create high water marks for group and user id */
300 if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
301 if (tdb_store_int32
302 (idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
303 DEBUG(0,
304 ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
305 return False;
309 if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
310 if (tdb_store_int32
311 (idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
312 DEBUG(0,
313 ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
314 return False;
318 return True;
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);
345 /* Close the tdb */
346 static BOOL tdb_idmap_close(void)
348 if (idmap_tdb)
349 return (tdb_close(idmap_tdb) == 0);
350 return True;
354 /* Dump status information to log file. Display different stuff based on
355 the debug level:
357 Debug Level Information Displayed
358 =================================================================
359 0 Percentage of [ug]id range allocated
360 0 High water marks (next allocated ids)
363 #define DUMP_INFO 0
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) {
374 DEBUG(DUMP_INFO,
375 ("\tCould not get userid high water mark!\n"));
378 if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
379 DEBUG(DUMP_INFO,
380 ("\tCould not get groupid high water mark!\n"));
383 /* Display next ids to allocate */
385 if (user_hwm != -1) {
386 DEBUG(DUMP_INFO,
387 ("\tNext userid to allocate is %d\n", user_hwm));
390 if (group_hwm != -1) {
391 DEBUG(DUMP_INFO,
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;
399 int total_users =
400 server_state.uid_high - server_state.uid_low;
402 DEBUG(DUMP_INFO,
403 ("\tUser id range is %d%% full (%d of %d)\n",
404 num_users * 100 / total_users, num_users,
405 total_users));
408 if (group_hwm != -1) {
409 int num_groups = group_hwm - server_state.gid_low;
410 int total_groups =
411 server_state.gid_high - server_state.gid_low;
413 DEBUG(DUMP_INFO,
414 ("\tGroup id range is %d%% full (%d of %d)\n",
415 num_groups * 100 / total_groups, num_groups,
416 total_groups));
419 /* Display complete mapping of users and groups to rids */
422 struct idmap_methods tdb_idmap_methods = {
423 tdb_idmap_init,
425 tdb_get_sid_from_uid,
426 tdb_get_sid_from_gid,
428 tdb_get_uid_from_sid,
429 tdb_get_gid_from_sid,
431 tdb_idmap_close,
433 tdb_idmap_status
436 BOOL winbind_idmap_reg_tdb(struct idmap_methods **meth)
438 *meth = &tdb_idmap_methods;
440 return True;