View | Details | Raw Unified | Return to bug 23367 | Differences between
and this patch

Collapse All | Expand All

(-)a/management/univention-directory-listener/debian/control (+2 lines)
 Lines 7-12   Build-Depends: debhelper (>= 9), Link Here 
7
 ucslint-univention,
7
 ucslint-univention,
8
 libssl-dev,
8
 libssl-dev,
9
 libldap2-dev,
9
 libldap2-dev,
10
 liblmdb-dev,
10
 libdb3-dev,
11
 libdb3-dev,
11
 python-all-dev,
12
 python-all-dev,
12
 libunivention-debug-dev (>= 0.8),
13
 libunivention-debug-dev (>= 0.8),
 Lines 27-32   Depends: ${misc:Depends}, ${shlibs:Depends}, Link Here 
27
 python2.7-univention,
28
 python2.7-univention,
28
 python2.7-univention-debug,
29
 python2.7-univention-debug,
29
 python-univention-lib (>= 1.0.25-1)
30
 python-univention-lib (>= 1.0.25-1)
31
Suggests: lmdb-utils
30
Conflicts: univention-ldap-listener (<< 2.2.2)
32
Conflicts: univention-ldap-listener (<< 2.2.2)
31
Description: UCS - Directory Listener
33
Description: UCS - Directory Listener
32
 UCS Directory Listener is a client for the UCS
34
 UCS Directory Listener is a client for the UCS
(-)a/management/univention-directory-listener/debian/rules (+1 lines)
 Lines 50-55   override_dh_install: Link Here 
50
	mv debian/univention-directory-listener/usr/sbin/listener debian/univention-directory-listener/usr/sbin/univention-directory-listener
50
	mv debian/univention-directory-listener/usr/sbin/listener debian/univention-directory-listener/usr/sbin/univention-directory-listener
51
	mv debian/univention-directory-listener/usr/sbin/dump debian/univention-directory-listener/usr/sbin/univention-directory-listener-dump
51
	mv debian/univention-directory-listener/usr/sbin/dump debian/univention-directory-listener/usr/sbin/univention-directory-listener-dump
52
	mv debian/univention-directory-listener/usr/sbin/verify debian/univention-directory-listener/usr/sbin/univention-directory-listener-verify
52
	mv debian/univention-directory-listener/usr/sbin/verify debian/univention-directory-listener/usr/sbin/univention-directory-listener-verify
53
	mv debian/univention-directory-listener/usr/sbin/convert debian/univention-directory-listener/usr/sbin/univention-directory-listener-convert
53
	mv debian/univention-directory-listener/usr/sbin/listener-ctrl debian/univention-directory-listener/usr/sbin/univention-directory-listener-ctrl
54
	mv debian/univention-directory-listener/usr/sbin/listener-ctrl debian/univention-directory-listener/usr/sbin/univention-directory-listener-ctrl
54
55
55
override_dh_installinit:
56
override_dh_installinit:
(-)a/management/univention-directory-listener/debian/univention-directory-listener.install (+1 lines)
 Lines 1-6    Link Here 
1
src/listener usr/sbin/
1
src/listener usr/sbin/
2
src/dump usr/sbin/
2
src/dump usr/sbin/
3
src/verify usr/sbin/
3
src/verify usr/sbin/
4
src/convert usr/sbin/
4
src/listener-ctrl usr/sbin/
5
src/listener-ctrl usr/sbin/
5
python/get_notifier_id.py usr/share/univention-directory-listener/
6
python/get_notifier_id.py usr/share/univention-directory-listener/
6
python/ldap_server.py usr/lib/univention-directory-listener/system/
7
python/ldap_server.py usr/lib/univention-directory-listener/system/
(-)a/management/univention-directory-listener/debian/univention-directory-listener.postinst (+31 lines)
 Lines 67-72   fi Link Here 
67
67
68
call_joinscript 03univention-directory-listener.inst
68
call_joinscript 03univention-directory-listener.inst
69
69
70
convert_to_lmdb() {
71
	if [ ! -f /var/lib/univention-directory-listener/cache/data.mdb ]; then
72
		if [ ! -d /var/lib/univention-directory-listener/cache ]; then
73
			mkdir /var/lib/univention-directory-listener/cache
74
		fi
75
		if [ -f /var/lib/univention-directory-listener/cache.db ]; then
76
			running=1
77
			/etc/init.d/univention-directory-listener status >/dev/null \
78
				&& running=1 || running=0
79
80
			if [ "$running" -eq 1 ]; then
81
				/etc/init.d/univention-directory-listener stop
82
			fi
83
84
			univention-directory-listener-convert \
85
				/var/lib/univention-directory-listener/cache.db
86
87
			chown -R listener.nogroup \
88
				/var/lib/univention-directory-listener/cache
89
90
			if [ "$running" -eq 1 ]; then
91
				/etc/init.d/univention-directory-listener start
92
			fi
93
		fi
94
	fi
95
}
70
96
71
if [ "$1" = "configure" -a -n "$2" ]; then
97
if [ "$1" = "configure" -a -n "$2" ]; then
72
	if dpkg --compare-versions "$2" lt 6.0.7 && dpkg --compare-versions "$2" gt 6.0.0; then
98
	if dpkg --compare-versions "$2" lt 6.0.7 && dpkg --compare-versions "$2" gt 6.0.0; then
 Lines 76-81   if [ "$1" = "configure" -a -n "$2" ]; then Link Here 
76
		mv /var/lib/univention-directory-listener/__* /var/univention-backup/listener-cache-ucs_3.0-ms1/
102
		mv /var/lib/univention-directory-listener/__* /var/univention-backup/listener-cache-ucs_3.0-ms1/
77
		mv /var/lib/univention-directory-listener/log.* /var/univention-backup/listener-cache-ucs_3.0-ms1/
103
		mv /var/lib/univention-directory-listener/log.* /var/univention-backup/listener-cache-ucs_3.0-ms1/
78
	fi
104
	fi
105
106
	if dpkg --compare-versions "$2" lt 11.0.0-7; then
107
		convert_to_lmdb
108
	fi
109
79
	/etc/init.d/univention-directory-listener crestart
110
	/etc/init.d/univention-directory-listener crestart
80
fi
111
fi
81
112
(-)a/management/univention-directory-listener/src/Makefile (-6 / +13 lines)
 Lines 31-43    Link Here 
31
#
31
#
32
CC ?= gcc
32
CC ?= gcc
33
33
34
DB_LDLIBS := -ldb3
34
DB_LDLIBS := -llmdb
35
DB_CFLAGS := -I/usr/include/db3 -DWITH_DB3
35
DB_OBJS := cache.o cache_dn.o cache_entry.o cache_lowlevel.o base64.o filter.o
36
DB_OBJS := cache.o cache_entry.o cache_lowlevel.o base64.o filter.o
37
36
38
LDAP_LDLIBS := -lldap -llber
37
LDAP_LDLIBS := -lldap -llber
39
38
40
CFLAGS += -Wall -Werror -D_FILE_OFFSET_BITS=64 $(DB_CFLAGS)
39
CFLAGS += -Wall -Werror -D_FILE_OFFSET_BITS=64
41
LDLIBS := -luniventiondebug -luniventionconfig -licuuc
40
LDLIBS := -luniventiondebug -luniventionconfig -licuuc
42
LISTENER_LDLIBS := -luniventionpolicy $(LDAP_LDLIBS) -lpython2.7 $(DB_LDLIBS)
41
LISTENER_LDLIBS := -luniventionpolicy $(LDAP_LDLIBS) -lpython2.7 $(DB_LDLIBS)
43
LISTENER_OBJS := main.o notifier.o transfile.o handlers.o change.o network.o signals.o select_server.o utils.o $(DB_OBJS)
42
LISTENER_OBJS := main.o notifier.o transfile.o handlers.o change.o network.o signals.o select_server.o utils.o $(DB_OBJS)
 Lines 46-54   DUMP_OBJS := dump.o dump_signals.o utils.o $(DB_OBJS) Link Here 
46
DEMO_OBJS := demo.o network.o utils.o
45
DEMO_OBJS := demo.o network.o utils.o
47
VERIFY_LDLIBS := $(LDAP_LDLIBS) $(DB_LDLIBS)
46
VERIFY_LDLIBS := $(LDAP_LDLIBS) $(DB_LDLIBS)
48
VERIFY_OBJS := verify.o dump_signals.o utils.o $(DB_OBJS)
47
VERIFY_OBJS := verify.o dump_signals.o utils.o $(DB_OBJS)
48
CONVERT_LDLIBS := $(LDAP_LDLIBS) $(DB_LDLIBS) -ldb3
49
CONVERT_OBJS := convert.o cache_bdb.o dump_signals.o utils.o $(DB_OBJS)
49
50
50
.PHONY: all
51
.PHONY: all
51
all: listener dump verify
52
all: listener dump verify convert
52
53
53
listener: $(LISTENER_OBJS)
54
listener: $(LISTENER_OBJS)
54
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(LISTENER_LDLIBS)
55
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(LISTENER_LDLIBS)
 Lines 62-67   demo: $(DEMO_OBJS) Link Here 
62
verify: $(VERIFY_OBJS)
63
verify: $(VERIFY_OBJS)
63
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(VERIFY_LDLIBS)
64
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(VERIFY_LDLIBS)
64
65
66
convert: $(CONVERT_OBJS)
67
	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CONVERT_LDLIBS)
68
69
cache_bdb.o: cache_bdb.c
70
	$(CC) $(CFLAGS) -I/usr/include/db3 -DWITH_DB3 -c $^
71
65
.PHONY: clean
72
.PHONY: clean
66
clean:
73
clean:
67
	$(RM) *.o listener dump demo verify *.db3 *.db42
74
	$(RM) *.o listener dump demo verify convert *.db3 *.db42
(-)a/management/univention-directory-listener/src/README (+9 lines)
 Lines 24-32   References Link Here 
24
    +-- network.c
24
    +-- network.c
25
25
26
+-- verify.o
26
+-- verify.o
27
    +-- cache_bdb.c
28
        +-- cache_lowlevel.c
29
	+-- cache_entry.c
30
31
+-- convert.o
27
    +-- cache.c
32
    +-- cache.c
28
        +-- cache_lowlevel.c
33
        +-- cache_lowlevel.c
29
	+-- cache_entry.c
34
	+-- cache_entry.c
35
    +-- cache_bdb.c
36
        +-- cache_lowlevel.c
37
	+-- cache_entry.c
30
38
31
Files
39
Files
32
-----
40
-----
 Lines 49-54   notifier.c The name notifier might be misleading. The main function Link Here 
49
	    "notifier_listener" uses the listener network API (network.c) to
57
	    "notifier_listener" uses the listener network API (network.c) to
50
	    receive updates from a notifier and calls the "change" functions.
58
	    receive updates from a notifier and calls the "change" functions.
51
signals.c   Signal handlers are initialized and defined here.
59
signals.c   Signal handlers are initialized and defined here.
60
cache_bdb.c legacy bdb version of cache.c, required for convert.
52
61
53
main.c      The listener daemon
62
main.c      The listener daemon
54
demo.c      Demo program for the notifier client API.
63
demo.c      Demo program for the notifier client API.
(-)a/management/univention-directory-listener/src/cache.c (-253 / +548 lines)
 Lines 67-81    Link Here 
67
#include <sys/types.h>
67
#include <sys/types.h>
68
#include <sys/file.h>
68
#include <sys/file.h>
69
#include <sys/stat.h>
69
#include <sys/stat.h>
70
#include <db.h>
70
#include <lmdb.h>
71
#include <stdbool.h>
71
#include <stdbool.h>
72
#include <assert.h>
72
#include <assert.h>
73
#include <stdint.h>
73
74
74
#include <univention/debug.h>
75
#include <univention/debug.h>
75
#include <univention/config.h>
76
#include <univention/config.h>
76
77
77
#include "common.h"
78
#include "common.h"
78
#include "cache.h"
79
#include "cache.h"
80
#include "cache_dn.h"
79
#include "cache_lowlevel.h"
81
#include "cache_lowlevel.h"
80
#include "cache_entry.h"
82
#include "cache_entry.h"
81
#include "network.h"
83
#include "network.h"
 Lines 83-100    Link Here 
83
#include "filter.h"
85
#include "filter.h"
84
#include "utils.h"
86
#include "utils.h"
85
87
86
#define MASTER_KEY "__master__"
88
// #define MASTER_KEY "__master__"
87
#define MASTER_KEY_SIZE (sizeof MASTER_KEY)
89
static size_t MASTER_KEY=0;
90
#define MASTER_KEY_SIZE (sizeof(DNID))
88
91
89
char *cache_dir = "/var/lib/univention-directory-listener";
92
char *cache_dir = "/var/lib/univention-directory-listener";
90
char *ldap_dir = "/var/lib/univention-ldap";
93
char *ldap_dir = "/var/lib/univention-ldap";
91
94
92
CacheMasterEntry cache_master_entry;
95
CacheMasterEntry cache_master_entry;
93
96
94
DB *dbp;
97
MDB_env	*env;
95
#ifdef WITH_DB42
98
MDB_dbi	id2dn;
96
DB_ENV *dbenvp;
99
MDB_dbi	id2entry;
97
#endif
100
int	mdb_readonly = 0;
98
static FILE *lock_fp=NULL;
101
static FILE *lock_fp=NULL;
99
102
100
static struct filter cache_filter;
103
static struct filter cache_filter;
 Lines 110-126   static void setup_cache_filter(void) { Link Here 
110
	}
113
	}
111
}
114
}
112
115
113
#ifdef WITH_DB42
116
/*
114
static void cache_panic_call(DB_ENV *dbenvp, int errval)
117
int mdb_message_func(const char *msg, void *ctx) {
115
{
118
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
116
	exit(1);
119
			"%s\n", msg);
120
	return MDB_SUCCESS;
117
}
121
}
118
#endif
122
*/
119
123
120
static void cache_error_message(const char *errpfx, char *msg)
124
void cache_error_message(int rv, char *msg)
121
{
125
{
122
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
126
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
123
			"database error: %s", msg);
127
		"%s: failed: %s (%d)\n",
128
		msg, mdb_strerror(rv), rv);
124
}
129
}
125
130
126
int cache_lock(void)
131
int cache_lock(void)
 Lines 130-136   int cache_lock(void) Link Here 
130
135
131
	assert(!lock_fp);
136
	assert(!lock_fp);
132
137
133
	rv = snprintf(lock_file, PATH_MAX, "%s/cache.db.lock", cache_dir);
138
	rv = snprintf(lock_file, PATH_MAX, "%s/cache.lock", cache_dir);
134
	if (rv < 0 || rv >= PATH_MAX)
139
	if (rv < 0 || rv >= PATH_MAX)
135
		abort();
140
		abort();
136
141
 Lines 152-217   int cache_lock(void) Link Here 
152
	return fd;
157
	return fd;
153
}
158
}
154
159
155
int cache_init(void)
160
int cache_init(int mdb_flags)
156
{
161
{
157
	int rv;
162
	int rv;
158
	char file[PATH_MAX];
163
	char mdb_dir[PATH_MAX];
164
	MDB_txn *cache_init_txn;
165
	int mdb_dbi_flags = MDB_INTEGERKEY;
166
167
	if ((mdb_flags & MDB_RDONLY) != 0) {
168
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
169
				"cache_init: MDB_RDONLY");
170
		mdb_readonly = MDB_RDONLY;
171
	} else {
172
		mdb_dbi_flags |= MDB_CREATE;
173
	}
159
174
160
	snprintf(file, PATH_MAX, "%s/cache.db", cache_dir);
175
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
176
			"cache_init: start");
161
177
162
#ifdef WITH_DB42
178
	snprintf(mdb_dir, PATH_MAX, "%s/cache", cache_dir);
163
	if ((rv = db_env_create(&dbenvp, 0)) != 0) {
179
180
	rv = mdb_env_create(&env);
181
	if (rv != MDB_SUCCESS) {
164
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
182
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
165
				"creating database environment failed");
183
				"cache_init: creating environment handle failed");
184
		cache_error_message(rv, "cache_init: mdb_env_create");
166
		return rv;
185
		return rv;
167
	}
186
	}
168
	dbenvp->set_errcall(dbenvp, cache_error_message);
187
169
	dbenvp->set_paniccall(dbenvp, cache_panic_call);
188
	rv = mdb_env_set_mapsize(env, 1992294400);
170
	if ((rv = dbenvp->open(dbenvp, cache_dir, DB_CREATE | DB_INIT_MPOOL |
189
	if (rv != MDB_SUCCESS) {
171
				/*DB_INIT_LOCK | */DB_INIT_LOG | DB_INIT_TXN |
172
				DB_RECOVER, 0600)) != 0) {
173
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
190
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
174
				"opening database environment failed");
191
				"cache_init: setting mdb mapsize failed");
175
		dbenvp->err(dbenvp, rv, "%s", "environment");
192
		cache_error_message(rv, "cache_init: mdb_env_set_mapsize");
176
		return rv;
193
		return rv;
177
	}
194
	}
178
	if ((rv = db_create(&dbp, dbenvp, 0)) != 0) {
195
196
	rv = mdb_env_set_maxdbs(env, 2);
197
	if (rv != MDB_SUCCESS) {
179
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
198
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
180
				"creating database handle failed");
199
				"cache_init: setting mdb maxdbs failed");
200
		cache_error_message(rv, "cache_init: mdb_env_set_maxdbs");
181
		return rv;
201
		return rv;
182
	}
202
	}
183
	if ((rv = dbp->open(dbp, NULL, "cache.db", NULL, DB_BTREE,
203
184
				DB_CREATE | DB_CHKSUM | DB_AUTO_COMMIT,
204
	rv = mdb_env_open(env, mdb_dir, 0, 0600);
185
				0600)) != 0) {
205
	if (rv != MDB_SUCCESS) {
186
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
206
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
187
				"opening database failed");
207
				"cache_init: opening database failed");
188
		dbp->err(dbp, rv, "open");
208
		cache_error_message(rv, "cache_init: mdb_env_open");
189
		// FIXME: free dbp
190
		return rv;
209
		return rv;
191
	}
210
	}
192
#else
211
193
	if ((rv = db_create(&dbp, NULL, 0)) != 0) {
212
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
194
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
213
			"cache_init: Transaction begin");
195
				"creating database handle failed");
214
215
	rv = mdb_txn_begin(env, NULL, mdb_readonly, &cache_init_txn);
216
	if (rv != MDB_SUCCESS) {
217
		cache_error_message(rv, "cache_init: mdb_txn_begin");
218
		mdb_env_close(env);
196
		return rv;
219
		return rv;
197
	}
220
	}
198
	if ((rv = dbp->open(dbp, file, NULL, DB_BTREE, DB_CREATE, 0600)) != 0) {
221
199
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
222
	rv = dntree_init(&id2dn, cache_init_txn, mdb_flags);
200
				"opening database failed");
223
	if (rv != MDB_SUCCESS) {
201
		dbp->err(dbp, rv, "open");
224
		cache_error_message(rv, "dntree_init: mdb_open");
202
		// FIXME: free dbp
225
		mdb_txn_abort(cache_init_txn);
226
		mdb_env_close(env);
203
		return rv;
227
		return rv;
204
	}
228
	}
205
	dbp->set_errcall(dbp, cache_error_message);
206
#endif
207
	setup_cache_filter();
208
	return 0;
209
}
210
229
211
void cache_sync(void) {
230
	rv = mdb_dbi_open(cache_init_txn, "id2entry", mdb_dbi_flags, &id2entry);
212
	if (!INIT_ONLY && dbp) {
231
	if (rv != MDB_SUCCESS) {
213
		dbp->sync(dbp, 0);
232
		cache_error_message(rv, "cache_init: mdb_open");
233
		mdb_txn_abort(cache_init_txn);
234
		mdb_dbi_close(env, id2dn);
235
		mdb_env_close(env);
236
		return rv;
214
	}
237
	}
238
239
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
240
			"cache_init: Transaction commit");
241
242
	rv = mdb_txn_commit(cache_init_txn);
243
	if (rv != MDB_SUCCESS) {
244
		cache_error_message(rv, "cache_init: mdb_txn_commit");
245
		mdb_dbi_close(env, id2dn);
246
		mdb_dbi_close(env, id2entry);
247
		mdb_env_close(env);
248
		return rv;
249
	}
250
251
	setup_cache_filter();
252
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
253
			"cache_init: end");
254
	return 0;
215
}
255
}
216
256
217
int cache_set_schema_id(const NotifierID value)
257
int cache_set_schema_id(const NotifierID value)
 Lines 219-225   int cache_set_schema_id(const NotifierID value) Link Here 
219
	int rv, fd, len;
259
	int rv, fd, len;
220
	char file[PATH_MAX], buf[15];
260
	char file[PATH_MAX], buf[15];
221
261
222
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "Set Schema ID to %ld", value);
262
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN,
263
			"Set Schema ID to %ld", value);
223
	len = snprintf(buf, sizeof buf, "%ld", value);
264
	len = snprintf(buf, sizeof buf, "%ld", value);
224
	if (len < 0 || len >= sizeof buf)
265
	if (len < 0 || len >= sizeof buf)
225
		return len;
266
		return len;
 Lines 299-381   int cache_get_int(char *key, NotifierID *value, const long def) Link Here 
299
340
300
int cache_get_master_entry(CacheMasterEntry *master_entry)
341
int cache_get_master_entry(CacheMasterEntry *master_entry)
301
{
342
{
302
	DBT key, data;
343
	int		rv;
303
	int rv;
344
	MDB_txn		*read_txn;
345
	MDB_val		key, data;
346
347
	memset(&key, 0, sizeof(MDB_val));
348
	memset(&data, 0, sizeof(MDB_val));
304
349
305
	memset(&key, 0, sizeof(DBT));
350
	key.mv_data=&MASTER_KEY;
306
	memset(&data, 0, sizeof(DBT));
351
	key.mv_size=MASTER_KEY_SIZE;
307
352
308
	key.data=MASTER_KEY;
353
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
309
	key.size=MASTER_KEY_SIZE;
354
			"cache_get_master_entry: Transaction begin");
310
	data.flags = DB_DBT_REALLOC;
311
355
312
	if ((rv=dbp->get(dbp, NULL, &key, &data, 0)) == DB_NOTFOUND)
356
	rv = mdb_txn_begin(env, NULL, MDB_RDONLY, &read_txn);
357
	if (rv != MDB_SUCCESS) {
358
		cache_error_message(rv, "cache_get_master_entry: mdb_txn_begin");
313
		return rv;
359
		return rv;
314
	else if (rv != 0) {
360
	}
361
362
	rv = mdb_get(read_txn, id2entry, &key, &data);
363
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
364
			"cache_get_master_entry: got data");
365
	if (rv == MDB_NOTFOUND) {
366
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
367
				"cache_get_master_entry: Transaction abort");
368
		mdb_txn_abort(read_txn);
369
		return rv;
370
	} else if (rv != MDB_SUCCESS) {
315
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
371
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
316
				"reading master entry from database failed");
372
				"cache_get_master_entry: reading master entry from database failed");
317
		dbp->err(dbp, rv, "get");
373
		cache_error_message(rv, "cache_get_master_entry: mdb_get");
374
		mdb_txn_abort(read_txn);
318
		return rv;
375
		return rv;
319
	}
376
	}
320
377
321
	if (data.size != sizeof(CacheMasterEntry)) {
378
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
379
		"cache_get_master_entry: Transaction abort");
380
	mdb_txn_abort(read_txn);
381
382
	if (data.mv_size != sizeof(CacheMasterEntry)) {
322
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
383
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
323
				"master entry has unexpected length");
384
				"cache_get_master_entry: master entry has unexpected length");
324
		return 1;
385
		return 1;
325
	}
386
	}
326
387
327
	memcpy(master_entry, data.data, sizeof(CacheMasterEntry));
388
	memcpy(master_entry, data.mv_data, sizeof(CacheMasterEntry));
328
	free(data.data);
329
389
330
	return 0;
390
	return MDB_SUCCESS;
331
}
391
}
332
392
333
int cache_update_master_entry(CacheMasterEntry *master_entry, DB_TXN *dbtxnp)
393
/* The dbtxnp argument is only used when WITH_DB42 is defined - useless? */
394
int cache_update_master_entry(CacheMasterEntry *master_entry, MDB_txn *dbtxnp)
334
{
395
{
335
	DBT key, data;
396
	int		rv;
336
	int rv;
397
	MDB_txn		*write_txn = dbtxnp;
337
	int flags;
398
	MDB_val		key, data;
338
339
	memset(&key, 0, sizeof(DBT));
340
	memset(&data, 0, sizeof(DBT));
341
399
342
	key.data=MASTER_KEY;
400
	memset(&key, 0, sizeof(MDB_val));
343
	key.size=MASTER_KEY_SIZE;
401
	memset(&data, 0, sizeof(MDB_val));
344
402
345
	data.data=(void*)master_entry;
403
	key.mv_data=&MASTER_KEY;
346
	data.size=sizeof(CacheMasterEntry);
404
	key.mv_size=MASTER_KEY_SIZE;
347
405
348
#ifdef WITH_DB42
406
	data.mv_data=(void*)master_entry;
349
	if (dbtxnp == NULL)
407
	data.mv_size=sizeof(CacheMasterEntry);
350
		flags = DB_AUTO_COMMIT;
351
	else
352
#endif
353
		flags = 0;
354
408
355
	if ((rv=dbp->put(dbp, dbtxnp, &key, &data, flags)) != 0) {
409
	if (!dbtxnp) {
410
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
411
				"cache_update_master_entry: Transaction begin");
412
	}
413
	if (!dbtxnp
414
	    && (rv = mdb_txn_begin(env, NULL, 0, &write_txn)) != MDB_SUCCESS) {
415
		cache_error_message(rv, "cache_update_master_entry: mdb_txn_begin");
416
		return rv;
417
	}
418
	rv = mdb_put(write_txn, id2entry, &key, &data, 0);
419
	if (rv != MDB_SUCCESS) {
356
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
420
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
357
				"storing master entry in database failed");
421
				"cache_update_master_entry: storing master entry in database failed");
358
		dbp->err(dbp, rv, "put");
422
		cache_error_message(rv, "cache_update_master_entry: mdb_put");
423
		mdb_txn_abort(write_txn);
424
		return rv;
425
	}
426
	if (!dbtxnp) {
427
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
428
				"cache_update_master_entry: Transaction commit");
429
	}
430
	if (!dbtxnp
431
	    && (rv = mdb_txn_commit(write_txn)) != MDB_SUCCESS) {
432
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
433
				"cache_update_master_entry: storing master entry in database failed");
434
		cache_error_message(rv, "cache_update_master_entry: mdb_txn_commit");
359
		return rv;
435
		return rv;
360
	}
436
	}
361
437
362
	cache_sync();
438
	return MDB_SUCCESS;
363
364
	return 0;
365
}
439
}
366
440
367
DB_TXN* cache_new_transaction(NotifierID id, char *dn)
441
MDB_txn *cache_new_transaction(NotifierID id, char *dn)
368
{
442
{
369
#ifdef WITH_DB42
443
#ifdef WITH_DB42
370
	DB_TXN			*dbtxnp;
444
	int			rv;
445
	MDB_txn			*write_txn;
371
	CacheMasterEntry	 master_entry;
446
	CacheMasterEntry	 master_entry;
372
	NotifierID		*old_id;
447
	NotifierID		*old_id;
373
448
374
	dbenvp->txn_begin(dbenvp, NULL, &dbtxnp, 0);
449
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
450
			"cache_new_transaction: Transaction begin");
451
	rv = mdb_txn_begin(env, NULL, 0, &write_txn);
452
	if (rv != MDB_SUCCESS) {
453
		cache_error_message(rv, "cache_new_transaction: mdb_txn_begin");
454
		return NULL;
455
	}
375
456
376
	if (id != 0) {
457
	if (id != 0) {
377
		if (cache_get_master_entry(&master_entry) != 0) {
458
		rv = cache_get_master_entry(&master_entry);
378
			dbtxnp->abort(dbtxnp);
459
		if (rv != MDB_SUCCESS) {
460
			mdb_txn_abort(write_txn);
379
			return NULL;
461
			return NULL;
380
		}
462
		}
381
463
 Lines 386-467   DB_TXN* cache_new_transaction(NotifierID id, char *dn) Link Here 
386
468
387
		if (*old_id >= id) {
469
		if (*old_id >= id) {
388
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
470
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
389
					"New ID (%ld) is not greater than old"
471
				"New ID (%ld) is not greater than old"
390
					" ID (%ld): %s", id, *old_id, dn);
472
				" ID (%ld): %s", id, *old_id, dn);
391
			dbtxnp->abort(dbtxnp);
473
			mdb_txn_abort(write_txn);
392
			return NULL;
474
			return NULL;
393
		} else
475
		} else
394
			*old_id = id;
476
			*old_id = id;
395
477
396
		if (cache_update_master_entry(&master_entry, dbtxnp) != 0) {
478
		rv = cache_update_master_entry(&master_entry, write_txn);
397
			dbtxnp->abort(dbtxnp);
479
		if (rv != MDB_SUCCESS) {
480
			mdb_txn_abort(write_txn);
398
			return NULL;
481
			return NULL;
399
		}
482
		}
400
	}
483
	}
401
484
402
	return dbtxnp;
485
	return write_txn;
403
#else
486
#else
404
	return NULL;
487
	return NULL;
405
#endif
488
#endif
406
}
489
}
407
490
408
409
/* XXX: The NotifierID is passed for future use. Once the journal is
491
/* XXX: The NotifierID is passed for future use. Once the journal is
410
   implemented, entries other than the most recent one can be returned.
492
   implemented, entries other than the most recent one can be returned.
411
   At the moment, the id parameters for cache_update_entry, and
493
   At the moment, the id parameters for cache_update_entry, and
412
   cache_delete_entry do nothing (at least if WITH_DB42 is undefined) */
494
   cache_delete_entry do nothing (at least if WITH_DB42 is undefined) */
413
inline int cache_update_entry(NotifierID id, char *dn, CacheEntry *entry)
495
static inline int cache_update_entry_in_transaction(NotifierID id, char *dn, CacheEntry *entry, MDB_cursor **id2dn_cursor_pp)
414
{
496
{
415
	DBT key, data;
497
	int		rv;
416
	DB_TXN *dbtxnp;
498
	DNID		dnid;
417
	int rv = 0;
499
	MDB_txn		*write_txn;
500
	MDB_val		key, data;
501
	u_int32_t	tmp_size = 0;
502
503
	memset(&data, 0, sizeof(MDB_val));
504
	rv = unparse_entry(&data.mv_data, &tmp_size, entry);
505
	data.mv_size = tmp_size;
506
	if (rv != 0) {
507
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
508
				"cache_update_entry: unparsing entry failed");
509
		return rv;
510
	}
418
511
419
	memset(&key, 0, sizeof(DBT));
512
	signals_block();
420
	memset(&data, 0, sizeof(DBT));
513
514
	rv = dntree_get_id4dn(*id2dn_cursor_pp, dn, &dnid, true);
515
	if (rv != MDB_SUCCESS) {
516
		signals_unblock();
517
		return rv;
518
	}
519
520
	key.mv_data = &dnid;
521
	key.mv_size = sizeof(DNID);
421
522
422
	if ((rv=unparse_entry(&data.data, &data.size, entry)) != 0) {
523
	write_txn = mdb_cursor_txn(*id2dn_cursor_pp);
524
	rv = mdb_put(write_txn, id2entry, &key, &data, 0);
525
	if (rv != MDB_SUCCESS) {
423
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
526
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
424
				"unparsing entry failed");
527
				"cache_update_entry: storing entry in database failed: %s", dn);
528
		cache_error_message(rv, "cache_update_entry: mdb_put");
529
		signals_unblock();
425
		return rv;
530
		return rv;
426
	}
531
	}
532
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
533
			"put %zu bytes for %s", data.mv_size, dn);
427
534
535
	signals_unblock();
536
537
	return rv;
538
}
539
540
inline int cache_update_entry(NotifierID id, char *dn, CacheEntry *entry)
541
{
542
	int		rv;
543
	MDB_txn		*write_txn;
544
	MDB_cursor	*id2dn_write_cursor_p;
428
545
429
	signals_block();
430
#ifdef WITH_DB42
546
#ifdef WITH_DB42
431
	dbtxnp = cache_new_transaction(id, dn);
547
	write_txn = cache_new_transaction(id, dn);
432
	if (dbtxnp == NULL) {
548
	if (write_txn == NULL) {
433
		signals_unblock();
434
		free(data.data);
435
		return 1;
549
		return 1;
436
	}
550
	}
437
#else
551
#else
438
	dbtxnp = NULL;
552
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
553
			"cache_update_entry: Transaction begin");
554
	rv = mdb_txn_begin(env, NULL, 0, &write_txn);
555
	if (rv != MDB_SUCCESS) {
556
		cache_error_message(rv, "cache_update_entry: mdb_txn_begin");
557
		return rv;
558
	}
439
#endif
559
#endif
440
560
441
	key.data=dn;
561
	rv = mdb_cursor_open(write_txn, id2dn, &id2dn_write_cursor_p);
442
	key.size=strlen(dn)+1;
562
	if (rv != MDB_SUCCESS) {
443
563
		cache_error_message(rv, "cache_update_entry: mdb_cursor_open");
444
	if ((rv=dbp->put(dbp, dbtxnp, &key, &data, 0)) != 0) {
445
		signals_unblock();
446
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
447
				"storing entry in database failed: %s", dn);
448
		dbp->err(dbp, rv, "put");
449
#ifdef WITH_DB42
450
		dbtxnp->abort(dbtxnp);
451
#endif
452
		free(data.data);
453
		return rv;
564
		return rv;
454
	}
565
	}
455
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "put %d bytes for %s", data.size, dn);
456
566
567
	rv = cache_update_entry_in_transaction(id, dn, entry, &id2dn_write_cursor_p);
457
568
458
#ifdef WITH_DB42
569
	mdb_cursor_close(id2dn_write_cursor_p);
459
	dbtxnp->commit(dbtxnp, 0);
570
460
#endif
571
	if (rv != MDB_SUCCESS) {
461
	cache_sync();
572
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
462
	signals_unblock();
573
				"cache_update_entry: Transaction abort");
574
		mdb_txn_abort(write_txn);
575
		return rv;
576
	}
577
578
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
579
			"cache_update_entry: Transaction commit");
580
	rv = mdb_txn_commit(write_txn);
581
	if (rv != MDB_SUCCESS) {
582
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
583
				"cache_update_entry: storing updated entry in database failed");
584
		cache_error_message(rv, "cache_update_entry: mdb_txn_commit");
585
		return rv;
586
	}
463
587
464
	free(data.data);
465
	return rv;
588
	return rv;
466
}
589
}
467
590
 Lines 482-521   int cache_update_entry_lower(NotifierID id, char *dn, CacheEntry *entry) Link Here 
482
	return rv;
605
	return rv;
483
}
606
}
484
607
485
int cache_delete_entry(NotifierID id, char *dn)
608
static inline int cache_delete_entry_in_transaction(NotifierID id, char *dn, MDB_cursor **id2dn_cursor_pp)
486
{
609
{
487
	DB_TXN	*dbtxnp;
610
	int		rv;
488
	DBT	 key;
611
	DNID		dnid;
489
	int	 rv;
612
	MDB_txn		*write_txn;
613
	MDB_val		key;
614
615
	signals_block();
490
616
491
	memset(&key, 0, sizeof(DBT));
617
	rv = dntree_get_id4dn(*id2dn_cursor_pp, dn, &dnid, false);
618
	if (rv != MDB_SUCCESS) {
619
		signals_unblock();
620
		return rv;
621
	}
492
622
493
	key.data=dn;
623
	key.mv_data = &dnid;
494
	key.size=strlen(dn)+1;
624
	key.mv_size = sizeof(DNID);
495
625
496
	signals_block();
626
	write_txn = mdb_cursor_txn(*id2dn_cursor_pp);
497
#ifdef WITH_DB42
627
	rv = mdb_del(write_txn, id2entry, &key, 0);
498
	dbtxnp = cache_new_transaction(id, dn);
628
	if (rv != MDB_SUCCESS && rv != MDB_NOTFOUND) {
499
	if (dbtxnp == NULL) {
629
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
630
				"cache_delete_entry: removing from database failed: %s", dn);
631
		cache_error_message(rv, "cache_delete_entry: mdb_del");
500
		signals_unblock();
632
		signals_unblock();
501
		return 1;
633
		return rv;
502
	}
634
	}
503
#else
504
	dbtxnp = NULL;
505
#endif
506
635
507
	if ((rv=dbp->del(dbp, dbtxnp, &key, 0)) != 0 && rv != DB_NOTFOUND) {
636
	rv = dntree_del_id(*id2dn_cursor_pp, dnid);
637
	if (rv != MDB_SUCCESS) {
508
		signals_unblock();
638
		signals_unblock();
509
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
639
		return rv;
510
				"removing from database failed: %s", dn);
511
		dbp->err(dbp, rv, "del");
512
	}
640
	}
513
641
642
	signals_unblock();
643
644
	return rv;
645
}
646
647
int cache_delete_entry(NotifierID id, char *dn)
648
{
649
	int		rv;
650
	MDB_txn		*write_txn;
651
	MDB_cursor	*id2dn_write_cursor_p;
652
514
#ifdef WITH_DB42
653
#ifdef WITH_DB42
515
	dbtxnp->commit(dbtxnp, 0);
654
	write_txn = cache_new_transaction(id, dn);
655
	if (write_txn == NULL) {
656
		return 1;
657
	}
658
#else
659
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
660
			"cache_delete_entry: Transaction begin");
661
	rv = mdb_txn_begin(env, NULL, 0, &write_txn);
662
	if (rv != MDB_SUCCESS) {
663
		cache_error_message(rv, "cache_delete_entry: mdb_txn_begin");
664
		return rv;
665
	}
516
#endif
666
#endif
517
	cache_sync();
667
518
	signals_unblock();
668
	rv = mdb_cursor_open(write_txn, id2dn, &id2dn_write_cursor_p);
669
	if (rv != MDB_SUCCESS) {
670
		cache_error_message(rv, "cache_delete_entry: mdb_cursor_open");
671
		return rv;
672
	}
673
674
	rv = cache_delete_entry_in_transaction(id, dn, &id2dn_write_cursor_p);
675
676
	mdb_cursor_close(id2dn_write_cursor_p);
677
678
	if (rv != MDB_SUCCESS) {
679
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
680
				"cache_update_entry: Transaction abort");
681
		mdb_txn_abort(write_txn);
682
		return rv;
683
	}
684
685
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
686
			"cache_delete_entry: Transaction commit");
687
	rv = mdb_txn_commit(write_txn);
688
	if (rv != MDB_SUCCESS) {
689
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
690
				"cache_delete_entry: storing entry removal from database failed");
691
		cache_error_message(rv, "cache_delete_entry: mdb_txn_commit");
692
	}
519
693
520
	return rv;
694
	return rv;
521
}
695
}
 Lines 528-534   int cache_delete_entry_lower_upper(NotifierID id, char *dn) Link Here 
528
702
529
	// convert to a lowercase dn
703
	// convert to a lowercase dn
530
	lower_dn = lower_utf8(dn);
704
	lower_dn = lower_utf8(dn);
531
	rv=cache_delete_entry(id, lower_dn);
705
	rv = cache_delete_entry(id, lower_dn);
532
	if (strcmp(dn, lower_dn) != 0) {
706
	if (strcmp(dn, lower_dn) != 0) {
533
		mixedcase = true;
707
		mixedcase = true;
534
		// try again with original dn
708
		// try again with original dn
 Lines 536-595   int cache_delete_entry_lower_upper(NotifierID id, char *dn) Link Here 
536
	}
710
	}
537
711
538
	free(lower_dn);
712
	free(lower_dn);
539
	if ( mixedcase ) {
713
	if (mixedcase) {
540
		return rv?rv2:rv;	// if rv was bad (!=0) return rv2, otherwise return rv
714
		return rv?rv2:rv;	// if rv was bad (!=0) return rv2, otherwise return rv
541
	} else {
715
	} else {
542
		return rv;
716
		return rv;
543
	}
717
	}
544
}
718
}
545
719
546
int cache_update_or_deleteifunused_entry(NotifierID id, char *dn, CacheEntry *entry)
720
int cache_update_or_deleteifunused_entry(NotifierID id, char *dn, CacheEntry *entry, MDB_cursor **id2dn_cursor_pp)
547
{
721
{
548
	if (entry->module_count == 0)
722
	if (entry->module_count == 0)
549
		return cache_delete_entry(id, dn);
723
		return cache_delete_entry_in_transaction(id, dn, id2dn_cursor_pp);
550
	else
724
	else
551
		return cache_update_entry(id, dn, entry);
725
		return cache_update_entry_in_transaction(id, dn, entry, id2dn_cursor_pp);
552
}
726
}
553
727
554
int cache_get_entry(char *dn, CacheEntry *entry)
728
int cache_get_entry(char *dn, CacheEntry *entry)
555
{
729
{
556
	DBT key, data;
730
	int		rv;
557
	int rv = 0;
731
	DNID		dnid;
558
732
	MDB_txn		*read_txn;
559
	memset(&key, 0, sizeof(DBT));
733
	MDB_cursor	*id2dn_read_cursor_p;
560
	memset(&data, 0, sizeof(DBT));
734
	MDB_val		key, data;
735
736
	memset(&key, 0, sizeof(MDB_val));
737
	memset(&data, 0, sizeof(MDB_val));
561
	memset(entry, 0, sizeof(CacheEntry));
738
	memset(entry, 0, sizeof(CacheEntry));
562
739
563
	key.data=dn;
740
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
564
	key.size=strlen(dn)+1;
741
			"cache_get_entry: Transaction begin");
565
	data.flags = DB_DBT_REALLOC;
566
742
567
	signals_block();
743
	rv = mdb_txn_begin(env, NULL, MDB_RDONLY, &read_txn);
568
	rv=dbp->get(dbp, NULL, &key, &data, 0);
744
	if (rv != MDB_SUCCESS) {
569
	signals_unblock();
745
		cache_error_message(rv, "cache_get_entry: mdb_txn_begin");
746
		return rv;
747
	}
570
748
571
	if (rv != 0 && rv != DB_NOTFOUND) {
749
	rv = mdb_cursor_open(read_txn, id2dn, &id2dn_read_cursor_p);
572
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
750
	if (rv != MDB_SUCCESS) {
573
				"reading %s from database failed", dn);
751
		cache_error_message(rv, "cache_get_entry: mdb_cursor_open");
574
		dbp->err(dbp, rv, "get");
752
		mdb_txn_abort(read_txn);
575
		return rv;
753
		return rv;
576
	} else if (rv == DB_NOTFOUND) {
754
	}
577
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "no cache entry found for %s",
755
578
				dn);
756
	rv = dntree_get_id4dn(id2dn_read_cursor_p, dn, &dnid, false);
757
	mdb_cursor_close(id2dn_read_cursor_p);
758
	if (rv == MDB_NOTFOUND) {
759
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
760
				"cache_get_entry: Transaction abort");
761
		mdb_txn_abort(read_txn);
579
		return rv;
762
		return rv;
580
	}
763
	}
581
764
582
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "got %d bytes for %s",
765
	key.mv_data = &dnid;
583
			data.size, dn);
766
	key.mv_size = sizeof(DNID);
767
768
	// signals_block();	// TODO: Is this really required?
769
	rv = mdb_get(read_txn, id2entry, &key, &data);
770
	// signals_unblock();
771
772
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
773
			"cache_get_entry: Transaction abort");
774
	mdb_txn_abort(read_txn);
584
775
585
	if ((rv=parse_entry(data.data, data.size, entry)) != 0) {
776
	if (rv == MDB_SUCCESS) {
777
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
778
				"got %zu bytes for %s", data.mv_size, dn);
779
	} else if (rv == MDB_NOTFOUND) {
780
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
781
				"cache_get_entry: no cache entry found for %s", dn);
782
		return rv;
783
	} else {
784
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
785
				"reading %s from database failed", dn);
786
		cache_error_message(rv, "cache_get_entry: mdb_get");
787
		return rv;
788
	}
789
790
	assert(data.mv_size <= UINT32_MAX);
791
	rv = parse_entry(data.mv_data, data.mv_size, entry);
792
	if (rv != 0) {
586
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
793
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
587
				"parsing entry failed");
794
				"cache_get_entry: parsing entry failed");
588
		free(data.data);
589
		exit(1);
795
		exit(1);
590
	}
796
	}
591
797
592
	free(data.data);
593
	return rv;
798
	return rv;
594
}
799
}
595
800
 Lines 606-612   int cache_get_entry_lower_upper(char *dn, CacheEntry *entry) Link Here 
606
	}
811
	}
607
812
608
	rv = cache_get_entry(lower_dn, entry);
813
	rv = cache_get_entry(lower_dn, entry);
609
	if (rv == DB_NOTFOUND && mixedcase ) {
814
	if (rv == MDB_NOTFOUND && mixedcase ) {
610
		// try again with original dn
815
		// try again with original dn
611
		rv = cache_get_entry(dn, entry);
816
		rv = cache_get_entry(dn, entry);
612
	}
817
	}
 Lines 615-722   int cache_get_entry_lower_upper(char *dn, CacheEntry *entry) Link Here 
615
	return rv;
820
	return rv;
616
}
821
}
617
822
618
int cache_first_entry(DBC **cur, char **dn, CacheEntry *entry)
823
int cache_first_entry(MDB_cursor **id2entry_read_cursor_pp, MDB_cursor **id2dn_read_cursor_pp, char **dn, CacheEntry *entry)
619
{
824
{
825
	MDB_txn *read_txn;
620
	int rv;
826
	int rv;
621
827
622
	if ((rv=dbp->cursor(dbp, NULL, cur, 0)) != 0) {
828
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
623
		dbp->err(dbp, rv, "cursor");
829
			"cache_first_entry: Transaction begin");
830
831
	rv = mdb_txn_begin(env, NULL, mdb_readonly, &read_txn);
832
	if (rv != MDB_SUCCESS) {
833
		cache_error_message(rv, "cache_first_entry: mdb_txn_begin");
834
		return rv;
835
	}
836
837
	rv = mdb_cursor_open(read_txn, id2entry, id2entry_read_cursor_pp);
838
	if (rv != MDB_SUCCESS) {
839
		cache_error_message(rv, "cache_first_entry: mdb_cursor_open");
840
		mdb_txn_abort(read_txn);
624
		return rv;
841
		return rv;
625
	}
842
	}
626
843
627
	return cache_next_entry(cur, dn, entry);
844
	rv = mdb_cursor_open(read_txn, id2dn, id2dn_read_cursor_pp);
845
	if (rv != MDB_SUCCESS) {
846
		cache_error_message(rv, "cache_first_entry: mdb_cursor_open");
847
		mdb_txn_abort(read_txn);
848
		return rv;
849
	}
850
851
	/*
852
	// mdb_reader_list(env, &mdb_message_func, NULL);
853
	MDB_envinfo stat;
854
	MDB_env *env = mdb_txn_env(read_txn);
855
	mdb_env_info(env, &stat);
856
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "LAST COMMITTED TXN: %zu", stat.me_last_txnid);
857
	*/
858
859
	return cache_next_entry(id2entry_read_cursor_pp, id2dn_read_cursor_pp, dn, entry);
628
}
860
}
629
861
630
int cache_print_entries(char *dn)
862
int cache_print_entries(char *dn)
631
{
863
{
632
	DBT key, data;
864
	int		rv;
633
	DBC *cur;
865
	DNID		dnid;
634
	memset(&key, 0, sizeof(DBT));
866
	MDB_txn		*read_txn;
635
	memset(&data, 0, sizeof(DBT));
867
	MDB_cursor	*id2dn_read_cursor_p;
636
	key.data = strdup(dn);
868
	MDB_cursor	*id2entry_read_cursor_p;
637
	key.size = strlen(dn)+1;
869
	MDB_val		key, data;
638
	key.flags = DB_DBT_REALLOC;
870
639
	data.flags = DB_DBT_REALLOC;
871
	memset(&key, 0, sizeof(MDB_val));
640
872
	memset(&data, 0, sizeof(MDB_val));
641
	dbp->cursor(dbp, NULL, &cur, 0);
873
642
	cur->c_get(cur, &key, &data, DB_FIRST);
874
	rv = mdb_txn_begin(env, NULL, MDB_RDONLY, &read_txn);
643
	do {
875
	if (rv != MDB_SUCCESS) {
644
		printf("%s\n", (char*)key.data);
876
		cache_error_message(rv, "cache_print_entries: mdb_txn_begin");
645
	} while (cur->c_get(cur, &key, &data, DB_NEXT) == 0);
877
		return rv;
878
	}
646
879
647
	cur->c_close(cur);
880
	rv = mdb_cursor_open(read_txn, id2dn, &id2dn_read_cursor_p);
648
	free(key.data);
881
	if (rv != MDB_SUCCESS) {
649
	free(data.data);
882
		cache_error_message(rv, "cache_print_entries: mdb_cursor_open");
650
	return 0;
883
		mdb_txn_abort(read_txn);
884
		return rv;
885
	}
886
887
	// rv = cache_dntree_get_id(id2dn_read_cursor_p, dn, &dnid, false);
888
	rv = dntree_get_id4dn(id2dn_read_cursor_p, dn, &dnid, false);
889
	mdb_cursor_close(id2dn_read_cursor_p);
890
	if (rv == MDB_NOTFOUND) {
891
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
892
				"cache_print_entries: Transaction abort");
893
		mdb_txn_abort(read_txn);
894
		return rv;
895
	}
896
897
	key.mv_data = &dnid;
898
	key.mv_size = sizeof(DNID);
899
900
	rv = mdb_cursor_open(read_txn, id2entry, &id2entry_read_cursor_p);
901
	if (rv != MDB_SUCCESS) {
902
		cache_error_message(rv, "cache_print_entries: mdb_cursor_open");
903
		mdb_txn_abort(read_txn);
904
		return rv;
905
	}
906
	rv = mdb_cursor_get(id2entry_read_cursor_p, &key, &data, MDB_FIRST);
907
	do {
908
		if (rv != MDB_SUCCESS) {
909
			cache_error_message(rv, "cache_print_entries: mdb_cursor_get");
910
			mdb_txn_abort(read_txn);
911
			return rv;
912
		}
913
		printf("%s\n", dn);
914
		printf("%s\n", (char*)data.mv_data); //TODO: Is that what we want?
915
	} while ((rv = mdb_cursor_get(id2entry_read_cursor_p, &key, &data, MDB_NEXT)));
916
917
	mdb_cursor_close(id2entry_read_cursor_p);
918
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
919
			"cache_print_entries: Transaction abort");
920
	mdb_txn_abort(read_txn);
921
	return MDB_SUCCESS;
651
}
922
}
652
923
653
int cache_next_entry(DBC **cur, char **dn, CacheEntry *entry)
924
int cache_next_entry(MDB_cursor **id2entry_read_cursor_pp, MDB_cursor **id2dn_read_cursor_pp, char **dn, CacheEntry *entry)
654
{
925
{
655
	DBT key, data;
926
	MDB_val key, data;
927
	DNID dnid;
656
	int rv;
928
	int rv;
657
929
658
	memset(&key, 0, sizeof(DBT));
930
	memset(&key, 0, sizeof(MDB_val));
659
	key.flags = DB_DBT_REALLOC;
931
	memset(&data, 0, sizeof(MDB_val));
660
	memset(&data, 0, sizeof(DBT));
661
	data.flags = DB_DBT_REALLOC;
662
932
663
	if ((rv=(*cur)->c_get(*cur, &key, &data, DB_NEXT)) == DB_NOTFOUND) {
933
	/* Get the next entry data */
934
	rv = mdb_cursor_get(*id2entry_read_cursor_pp, &key, &data, MDB_NEXT);
935
	if (rv == MDB_NOTFOUND) {
664
		return rv;
936
		return rv;
665
	} else if (rv != 0) {
937
	} else if (rv != MDB_SUCCESS) {
666
		dbp->err(dbp, rv, "c_get");
938
		cache_error_message(rv, "cache_next_entry: mdb_cursor_get");
667
		return rv;
939
		return rv;
668
	}
940
	}
669
941
670
	/* skip master entry */
942
	// skip root node
671
	if (strcmp(key.data, MASTER_KEY) == 0) {
943
	dnid = * (DNID *) key.mv_data;
672
		free(key.data);
944
	if (dnid == MASTER_KEY) {
673
		free(data.data);
945
		return cache_next_entry(id2entry_read_cursor_pp, id2dn_read_cursor_pp, dn, entry);
674
		return cache_next_entry(cur, dn, entry);
675
	}
946
	}
676
947
677
	if (*dn)
948
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
678
		free(*dn);
949
			"got %zu bytes", data.mv_size);
679
	*dn = strdup(key.data);
680
681
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "got %d bytes", data.size);
682
950
683
	if ((rv=parse_entry(data.data, data.size, entry)) != 0) {
951
	assert(data.mv_size <= UINT32_MAX);
952
	rv = parse_entry(data.mv_data, (u_int32_t) data.mv_size, entry);
953
	if (rv != 0) {
684
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
954
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
685
				"parsing entry failed: %s", *dn);
955
				"cache_next_entry: parsing entry failed: %s", *dn);
686
		printf("%d\n", data.size);
956
		printf("%zu\n", data.mv_size);
687
		free(key.data);
688
		free(data.data);
689
		return rv;
957
		return rv;
690
	}
958
	}
691
959
692
	free(key.data);
960
	/* Get the corresponding dn */
693
	free(data.data);
961
	if (*dn) {
962
		free(*dn);
963
		*dn = NULL;
964
	}
965
		
966
	rv = dntree_lookup_dn4id(*id2dn_read_cursor_pp, dnid, dn);
967
968
	if (rv != MDB_SUCCESS) {
969
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
970
				"cache_next_entry: DB corruption, DN entry for id %d not found",
971
				*(int*)key.mv_data);
972
		cache_error_message(rv, "cache_next_entry: mdb_get");
973
		return rv;
974
	}
694
975
695
	return 0;
976
	return 0;
696
}
977
}
697
978
698
int cache_free_cursor(DBC *cur)
979
int cache_free_cursor(MDB_cursor *id2entry_read_cursor_pp, MDB_cursor *id2dn_read_cursor_pp)
699
{
980
{
700
	return cur->c_close(cur);
981
	int rv = 0;
982
	MDB_txn *read_txn;
983
984
	/*
985
	// mdb_reader_list(env, &mdb_message_func, NULL);
986
	MDB_envinfo stat;
987
	MDB_env *env = mdb_txn_env(read_txn);
988
	mdb_env_info(env, &stat);
989
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "LAST COMMITTED TXN: %zu", stat.me_last_txnid);
990
	*/
991
992
	read_txn = mdb_cursor_txn(id2entry_read_cursor_pp);
993
	mdb_cursor_close(id2entry_read_cursor_pp);
994
	mdb_cursor_close(id2dn_read_cursor_pp);
995
996
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL,
997
			"cache_free_cursor: Transaction commit");
998
	rv = mdb_txn_commit(read_txn);
999
	if (rv != MDB_SUCCESS) {
1000
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
1001
				"cache_free_cursor: Transation commit failed");
1002
		cache_error_message(rv, "cache_free_cursor: mdb_txn_commit");
1003
	}
1004
	return rv;
701
}
1005
}
702
1006
703
int cache_close(void)
1007
void cache_close(void)
704
{
1008
{
705
	int rv = 0;
1009
	mdb_close(env, id2dn);
1010
	mdb_close(env, id2entry);
1011
	mdb_env_close(env);
706
1012
707
	if (dbp && (rv = dbp->close(dbp, 0)) != 0) {
708
		dbp->err(dbp, rv, "close");
709
	}
710
	dbp = NULL;
711
#ifdef WITH_DB42
712
	if ((rv = dbenvp->close(dbenvp, 0)) != 0) {
713
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
714
				"closing database environment failed");
715
	}
716
#endif
717
	if (lock_fp != NULL) {
1013
	if (lock_fp != NULL) {
718
		fclose(lock_fp);
1014
		fclose(lock_fp);
719
		lock_fp = NULL;
1015
		lock_fp = NULL;
720
	}
1016
	}
721
	return rv;
722
}
1017
}
(-)a/management/univention-directory-listener/src/cache.h (-8 / +12 lines)
 Lines 33-39    Link Here 
33
#ifndef _CACHE_H_
33
#ifndef _CACHE_H_
34
#define _CACHE_H_
34
#define _CACHE_H_
35
35
36
#include <db.h>
36
#include <lmdb.h>
37
37
38
#include "network.h"
38
#include "network.h"
39
#include "cache_entry.h"
39
#include "cache_entry.h"
 Lines 49-59   typedef struct _CacheMasterEntry { Link Here 
49
extern CacheMasterEntry cache_master_entry;
49
extern CacheMasterEntry cache_master_entry;
50
50
51
int	cache_lock(void);
51
int	cache_lock(void);
52
int	cache_init				(void);
52
int	cache_init				(int mdb_flags);
53
void	cache_sync(void);
53
void	cache_sync(void);
54
int	cache_get_master_entry			(CacheMasterEntry	 *master_entry);
54
int	cache_get_master_entry			(CacheMasterEntry	 *master_entry);
55
int	cache_update_master_entry		(CacheMasterEntry	 *master_entry,
55
int	cache_update_master_entry		(CacheMasterEntry	 *master_entry,
56
						 DB_TXN			 *dptxnp);
56
						 MDB_txn		 *dptxnp);
57
int	cache_update_entry			(NotifierID		  id,
57
int	cache_update_entry			(NotifierID		  id,
58
						 char			 *dn,
58
						 char			 *dn,
59
						 CacheEntry		 *entry);
59
						 CacheEntry		 *entry);
 Lines 66-86   int cache_delete_entry_lower_upper (NotifierID id, Link Here 
66
						 char			 *dn);
66
						 char			 *dn);
67
int	cache_update_or_deleteifunused_entry	(NotifierID		  id,
67
int	cache_update_or_deleteifunused_entry	(NotifierID		  id,
68
						 char			 *dn,
68
						 char			 *dn,
69
						 CacheEntry		 *entry);
69
						 CacheEntry		 *entry,
70
						 MDB_cursor		**cur);
70
int	cache_get_entry(
71
int	cache_get_entry(
71
						 char			 *dn,
72
						 char			 *dn,
72
						 CacheEntry		 *entry);
73
						 CacheEntry		 *entry);
73
int	cache_get_entry_lower_upper(
74
int	cache_get_entry_lower_upper(
74
						 char			 *dn,
75
						 char			 *dn,
75
						 CacheEntry		 *entry);
76
						 CacheEntry		 *entry);
76
int	cache_first_entry			(DBC			**cur,
77
int	cache_first_entry			(MDB_cursor		**cur,
78
						 MDB_cursor		**cur_dn,
77
						 char			**dn,
79
						 char			**dn,
78
						 CacheEntry		 *entry);
80
						 CacheEntry		 *entry);
79
int	cache_next_entry			(DBC			**cur,
81
int	cache_next_entry			(MDB_cursor		**cur,
82
						 MDB_cursor		**cur_dn,
80
						 char			**dn,
83
						 char			**dn,
81
						 CacheEntry		 *entry);
84
						 CacheEntry		 *entry);
82
int	cache_free_cursor			(DBC			 *cur);
85
int	cache_free_cursor			(MDB_cursor		 *cur,
83
int	cache_close				(void);
86
						 MDB_cursor		 *cur_dn);
87
void	cache_close				(void);
84
88
85
/* deprecated with DB42*/
89
/* deprecated with DB42*/
86
int	cache_set_int				(char		 *key,
90
int	cache_set_int				(char		 *key,
(-)a/management/univention-directory-listener/src/cache_bdb.c (+722 lines)
Line 0    Link Here 
1
/*
2
 * Univention Directory Listener
3
 *  ldap listener caching system
4
 *
5
 * Copyright 2004-2017 Univention GmbH
6
 *
7
 * http://www.univention.de/
8
 *
9
 * All rights reserved.
10
 *
11
 * The source code of this program is made available
12
 * under the terms of the GNU Affero General Public License version 3
13
 * (GNU AGPL V3) as published by the Free Software Foundation.
14
 *
15
 * Binary versions of this program provided by Univention to you as
16
 * well as other copyrighted, protected or trademarked materials like
17
 * Logos, graphics, fonts, specific documentations and configurations,
18
 * cryptographic keys etc. are subject to a license agreement between
19
 * you and Univention and not subject to the GNU AGPL V3.
20
 *
21
 * In the case you use this program under the terms of the GNU AGPL V3,
22
 * the program is provided in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public
28
 * License with the Debian GNU/Linux or Univention distribution in file
29
 * /usr/share/common-licenses/AGPL-3; if not, see
30
 * <http://www.gnu.org/licenses/>.
31
 */
32
33
/* How it works:
34
35
   LDAP entries are cached here. If a modification takes place,
36
   the new LDAP entry is compared with the cache entry, and both,
37
   old and new entries, are passed to the handler modules.
38
39
   Berkeley DB provides a way to store and receive a chunk of data
40
   with a given key. However, we're not working with cache entries
41
   as chunks of data later, but use C structures. So we'll need to
42
   convert the C structure we can work with to chunks of data we
43
   can store in BDB, and the other way around.
44
45
   We have decided on a pretty low level, but straightforward
46
   binary format for the chunk of data. For manual error recovery, a
47
   text-based format like LDIF might have been easier.
48
49
   The function unparse_entry converts a C structure entry to a data
50
   chunk, parse_entry does the opposite.
51
52
   To convert the entry, unparse_entry walks through all values of
53
   all attributes, as well as through the list of modules registered
54
   with it, and write a block for each (attribute, value) pair or
55
   (, module) [write_header]. Each block starts with an entry_header
56
   structure that specified the lengths of the following data.
57
*/
58
59
60
#define _GNU_SOURCE /* for strndup */
61
62
#include <stdlib.h>
63
#include <string.h>
64
#include <limits.h>
65
#include <unistd.h>
66
#include <ctype.h>
67
#include <sys/types.h>
68
#include <sys/file.h>
69
#include <sys/stat.h>
70
#include <db.h>
71
#include <stdbool.h>
72
#include <assert.h>
73
74
#include <univention/debug.h>
75
#include <univention/config.h>
76
77
#include "common.h"
78
#include "cache_bdb.h"
79
#include "cache_lowlevel.h"
80
#include "cache_entry.h"
81
#include "network.h"
82
#include "signals.h"
83
#include "filter.h"
84
#include "utils.h"
85
86
#define MASTER_KEY "__master__"
87
#define MASTER_KEY_SIZE (sizeof MASTER_KEY)
88
89
char *bdb_cache_dir = "/var/lib/univention-directory-listener";
90
char *bdb_ldap_dir = "/var/lib/univention-ldap";
91
92
BdbCacheMasterEntry bdb_cache_master_entry;
93
94
DB *dbp;
95
#ifdef WITH_DB42
96
DB_ENV *dbenvp;
97
#endif
98
static FILE *lock_fp=NULL;
99
100
static struct filter cache_filter;
101
static struct filter *cache_filters[] = {&cache_filter, NULL};
102
103
static void setup_cache_filter(void) {
104
	FREE(cache_filter.filter);
105
	FREE(cache_filter.base);
106
	cache_filter.filter = univention_config_get_string("listener/cache/filter");
107
	if (cache_filter.filter && cache_filter.filter[0]) {
108
		cache_filter.base = univention_config_get_string("ldap/base");
109
		cache_filter.scope = LDAP_SCOPE_SUBTREE;
110
	}
111
}
112
113
#ifdef WITH_DB42
114
static void bdb_cache_panic_call(DB_ENV *dbenvp, int errval)
115
{
116
	exit(1);
117
}
118
#endif
119
120
static void bdb_cache_error_message(const char *errpfx, char *msg)
121
{
122
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
123
			"database error: %s", msg);
124
}
125
126
int bdb_cache_lock(void)
127
{
128
	int rv, fd;
129
	char lock_file[PATH_MAX];
130
131
	assert(!lock_fp);
132
133
	rv = snprintf(lock_file, PATH_MAX, "%s/cache.db.lock", bdb_cache_dir);
134
	if (rv < 0 || rv >= PATH_MAX)
135
		abort();
136
137
	if ((lock_fp = fopen(lock_file, "a+e")) == NULL) {
138
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
139
				"Could not open lock file [%s]", lock_file);
140
		exit(EXIT_FAILURE);
141
	}
142
	fd = fileno(lock_fp);
143
144
	if (lockf(fd, F_TLOCK, 0) != 0) {
145
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
146
				"Could not get lock for database [%s]; "
147
				"Is another listener processs running?\n",
148
				lock_file);
149
		exit(EXIT_FAILURE);
150
	}
151
152
	return fd;
153
}
154
155
int bdb_cache_init(void)
156
{
157
	int rv;
158
	char file[PATH_MAX];
159
160
	snprintf(file, PATH_MAX, "%s/cache.db", bdb_cache_dir);
161
162
#ifdef WITH_DB42
163
	if ((rv = db_env_create(&dbenvp, 0)) != 0) {
164
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
165
				"creating database environment failed");
166
		return rv;
167
	}
168
	dbenvp->set_errcall(dbenvp, bdb_cache_error_message);
169
	dbenvp->set_paniccall(dbenvp, bdb_cache_panic_call);
170
	if ((rv = dbenvp->open(dbenvp, bdb_cache_dir, DB_CREATE | DB_INIT_MPOOL |
171
				/*DB_INIT_LOCK | */DB_INIT_LOG | DB_INIT_TXN |
172
				DB_RECOVER, 0600)) != 0) {
173
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
174
				"opening database environment failed");
175
		dbenvp->err(dbenvp, rv, "%s", "environment");
176
		return rv;
177
	}
178
	if ((rv = db_create(&dbp, dbenvp, 0)) != 0) {
179
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
180
				"creating database handle failed");
181
		return rv;
182
	}
183
	if ((rv = dbp->open(dbp, NULL, "cache.db", NULL, DB_BTREE,
184
				DB_CREATE | DB_CHKSUM | DB_AUTO_COMMIT,
185
				0600)) != 0) {
186
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
187
				"opening database failed");
188
		dbp->err(dbp, rv, "open");
189
		// FIXME: free dbp
190
		return rv;
191
	}
192
#else
193
	if ((rv = db_create(&dbp, NULL, 0)) != 0) {
194
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
195
				"creating database handle failed");
196
		return rv;
197
	}
198
	if ((rv = dbp->open(dbp, file, NULL, DB_BTREE, DB_CREATE, 0600)) != 0) {
199
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
200
				"opening database failed");
201
		dbp->err(dbp, rv, "open");
202
		// FIXME: free dbp
203
		return rv;
204
	}
205
	dbp->set_errcall(dbp, bdb_cache_error_message);
206
#endif
207
	setup_cache_filter();
208
	return 0;
209
}
210
211
void bdb_cache_sync(void) {
212
	if (dbp) {
213
		dbp->sync(dbp, 0);
214
	}
215
}
216
217
int bdb_cache_set_schema_id(const NotifierID value)
218
{
219
	int rv, fd, len;
220
	char file[PATH_MAX], buf[15];
221
222
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "Set Schema ID to %ld", value);
223
	len = snprintf(buf, sizeof buf, "%ld", value);
224
	if (len < 0 || len >= sizeof buf)
225
		return len;
226
227
	rv = snprintf(file, PATH_MAX, "%s/schema/id/id", bdb_ldap_dir);
228
	if (rv < 0 || rv >= PATH_MAX)
229
		return rv;
230
	fd = open(file, O_WRONLY | O_CREAT, 0644);
231
	if (fd < 0)
232
		return fd;
233
	rv = write(fd, buf, len);
234
	if (rv != len) {
235
		close(fd);
236
		return 1;
237
	}
238
	rv = ftruncate(fd, len);
239
	if (rv != 0)
240
		return rv;
241
	rv = close(fd);
242
	if (rv != 0)
243
		return rv;
244
	return 0;
245
}
246
247
int bdb_cache_get_schema_id(NotifierID *value, const long def)
248
{
249
	FILE *fp;
250
	char file[PATH_MAX];
251
	int rv;
252
253
	*value = def;
254
255
	snprintf(file, PATH_MAX, "%s/schema/id/id", bdb_ldap_dir);
256
	if ((fp = fopen(file, "r")) == NULL)
257
		return 1;
258
	rv = fscanf(fp, "%ld", value);
259
	return fclose(fp) || (rv != 1);
260
}
261
262
int bdb_cache_set_int(char *key, const NotifierID value)
263
{
264
	int rv;
265
	FILE *fp;
266
	char file[PATH_MAX], tmpfile[PATH_MAX];
267
268
	rv = snprintf(tmpfile, PATH_MAX, "%s/%s.tmp", bdb_cache_dir, key);
269
	if (rv < 0 || rv >= PATH_MAX)
270
		return rv;
271
	if ((fp = fopen(tmpfile, "w")) == NULL)
272
		abort_io("open", tmpfile);
273
	fprintf(fp, "%ld", value);
274
	rv = fclose(fp);
275
	if (rv != 0)
276
		abort_io("close", tmpfile);
277
278
	rv = snprintf(file, PATH_MAX, "%s/%s", bdb_cache_dir, key);
279
	if (rv < 0 || rv >= PATH_MAX)
280
		return rv;
281
	rv = rename(tmpfile, file);
282
	return rv;
283
}
284
285
int bdb_cache_get_int(char *key, NotifierID *value, const long def)
286
{
287
	FILE *fp;
288
	char file[PATH_MAX];
289
	int rv;
290
291
	*value = def;
292
293
	snprintf(file, PATH_MAX, "%s/%s", bdb_cache_dir, key);
294
	if ((fp = fopen(file, "r")) == NULL)
295
		return 1;
296
	rv = fscanf(fp, "%ld", value);
297
	return fclose(fp) || (rv != 1);
298
}
299
300
int bdb_cache_get_master_entry(BdbCacheMasterEntry *master_entry)
301
{
302
	DBT key, data;
303
	int rv;
304
305
	memset(&key, 0, sizeof(DBT));
306
	memset(&data, 0, sizeof(DBT));
307
308
	key.data=MASTER_KEY;
309
	key.size=MASTER_KEY_SIZE;
310
	data.flags = DB_DBT_REALLOC;
311
312
	if ((rv=dbp->get(dbp, NULL, &key, &data, 0)) == DB_NOTFOUND)
313
		return rv;
314
	else if (rv != 0) {
315
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
316
				"reading master entry from database failed");
317
		dbp->err(dbp, rv, "get");
318
		return rv;
319
	}
320
321
	if (data.size != sizeof(BdbCacheMasterEntry)) {
322
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
323
				"master entry has unexpected length");
324
		return 1;
325
	}
326
327
	memcpy(master_entry, data.data, sizeof(BdbCacheMasterEntry));
328
	free(data.data);
329
330
	return 0;
331
}
332
333
int bdb_cache_update_master_entry(BdbCacheMasterEntry *master_entry, DB_TXN *dbtxnp)
334
{
335
	DBT key, data;
336
	int rv;
337
	int flags;
338
339
	memset(&key, 0, sizeof(DBT));
340
	memset(&data, 0, sizeof(DBT));
341
342
	key.data=MASTER_KEY;
343
	key.size=MASTER_KEY_SIZE;
344
345
	data.data=(void*)master_entry;
346
	data.size=sizeof(BdbCacheMasterEntry);
347
348
#ifdef WITH_DB42
349
	if (dbtxnp == NULL)
350
		flags = DB_AUTO_COMMIT;
351
	else
352
#endif
353
		flags = 0;
354
355
	if ((rv=dbp->put(dbp, dbtxnp, &key, &data, flags)) != 0) {
356
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
357
				"storing master entry in database failed");
358
		dbp->err(dbp, rv, "put");
359
		return rv;
360
	}
361
362
	bdb_cache_sync();
363
364
	return 0;
365
}
366
367
DB_TXN* bdb_cache_new_transaction(NotifierID id, char *dn)
368
{
369
#ifdef WITH_DB42
370
	DB_TXN			*dbtxnp;
371
	BdbCacheMasterEntry	 master_entry;
372
	NotifierID		*old_id;
373
374
	dbenvp->txn_begin(dbenvp, NULL, &dbtxnp, 0);
375
376
	if (id != 0) {
377
		if (bdb_cache_get_master_entry(&master_entry) != 0) {
378
			dbtxnp->abort(dbtxnp);
379
			return NULL;
380
		}
381
382
		if (strcmp(dn, "cn=Subschema") == 0)
383
			old_id = &master_entry.schema_id;
384
		else
385
			old_id = &master_entry.id;
386
387
		if (*old_id >= id) {
388
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
389
					"New ID (%ld) is not greater than old"
390
					" ID (%ld): %s", id, *old_id, dn);
391
			dbtxnp->abort(dbtxnp);
392
			return NULL;
393
		} else
394
			*old_id = id;
395
396
		if (bdb_cache_update_master_entry(&master_entry, dbtxnp) != 0) {
397
			dbtxnp->abort(dbtxnp);
398
			return NULL;
399
		}
400
	}
401
402
	return dbtxnp;
403
#else
404
	return NULL;
405
#endif
406
}
407
408
409
/* XXX: The NotifierID is passed for future use. Once the journal is
410
   implemented, entries other than the most recent one can be returned.
411
   At the moment, the id parameters for bdb_cache_update_entry, and
412
   bdb_cache_delete_entry do nothing (at least if WITH_DB42 is undefined) */
413
inline int bdb_cache_update_entry(NotifierID id, char *dn, CacheEntry *entry)
414
{
415
	DBT key, data;
416
	DB_TXN *dbtxnp;
417
	int rv = 0;
418
419
	memset(&key, 0, sizeof(DBT));
420
	memset(&data, 0, sizeof(DBT));
421
422
	if ((rv=unparse_entry(&data.data, &data.size, entry)) != 0) {
423
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
424
				"unparsing entry failed");
425
		return rv;
426
	}
427
428
429
	signals_block();
430
#ifdef WITH_DB42
431
	dbtxnp = bdb_cache_new_transaction(id, dn);
432
	if (dbtxnp == NULL) {
433
		signals_unblock();
434
		free(data.data);
435
		return 1;
436
	}
437
#else
438
	dbtxnp = NULL;
439
#endif
440
441
	key.data=dn;
442
	key.size=strlen(dn)+1;
443
444
	if ((rv=dbp->put(dbp, dbtxnp, &key, &data, 0)) != 0) {
445
		signals_unblock();
446
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
447
				"storing entry in database failed: %s", dn);
448
		dbp->err(dbp, rv, "put");
449
#ifdef WITH_DB42
450
		dbtxnp->abort(dbtxnp);
451
#endif
452
		free(data.data);
453
		return rv;
454
	}
455
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "put %d bytes for %s", data.size, dn);
456
457
458
#ifdef WITH_DB42
459
	dbtxnp->commit(dbtxnp, 0);
460
#endif
461
	bdb_cache_sync();
462
	signals_unblock();
463
464
	free(data.data);
465
	return rv;
466
}
467
468
int bdb_cache_update_entry_lower(NotifierID id, char *dn, CacheEntry *entry)
469
{
470
	char *lower_dn;
471
	int rv = 0;
472
473
	if (cache_filter.filter && cache_entry_ldap_filter_match(cache_filters, dn, entry)) {
474
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "Not caching %s, filtered out.", dn);
475
		return rv;
476
	}
477
478
	lower_dn = lower_utf8(dn);
479
	rv = bdb_cache_update_entry(id, lower_dn, entry);
480
481
	free(lower_dn);
482
	return rv;
483
}
484
485
int bdb_cache_delete_entry(NotifierID id, char *dn)
486
{
487
	DB_TXN	*dbtxnp;
488
	DBT	 key;
489
	int	 rv;
490
491
	memset(&key, 0, sizeof(DBT));
492
493
	key.data=dn;
494
	key.size=strlen(dn)+1;
495
496
	signals_block();
497
#ifdef WITH_DB42
498
	dbtxnp = bdb_cache_new_transaction(id, dn);
499
	if (dbtxnp == NULL) {
500
		signals_unblock();
501
		return 1;
502
	}
503
#else
504
	dbtxnp = NULL;
505
#endif
506
507
	if ((rv=dbp->del(dbp, dbtxnp, &key, 0)) != 0 && rv != DB_NOTFOUND) {
508
		signals_unblock();
509
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
510
				"removing from database failed: %s", dn);
511
		dbp->err(dbp, rv, "del");
512
	}
513
514
#ifdef WITH_DB42
515
	dbtxnp->commit(dbtxnp, 0);
516
#endif
517
	bdb_cache_sync();
518
	signals_unblock();
519
520
	return rv;
521
}
522
523
int bdb_cache_delete_entry_lower_upper(NotifierID id, char *dn)
524
{
525
	char *lower_dn;
526
	bool mixedcase = false;
527
	int	 rv, rv2;
528
529
	// convert to a lowercase dn
530
	lower_dn = lower_utf8(dn);
531
	rv=bdb_cache_delete_entry(id, lower_dn);
532
	if (strcmp(dn, lower_dn) != 0) {
533
		mixedcase = true;
534
		// try again with original dn
535
		rv2=bdb_cache_delete_entry(id, dn);
536
	}
537
538
	free(lower_dn);
539
	if ( mixedcase ) {
540
		return rv?rv2:rv;	// if rv was bad (!=0) return rv2, otherwise return rv
541
	} else {
542
		return rv;
543
	}
544
}
545
546
int bdb_cache_update_or_deleteifunused_entry(NotifierID id, char *dn, CacheEntry *entry)
547
{
548
	if (entry->module_count == 0)
549
		return bdb_cache_delete_entry(id, dn);
550
	else
551
		return bdb_cache_update_entry(id, dn, entry);
552
}
553
554
int bdb_cache_get_entry(char *dn, CacheEntry *entry)
555
{
556
	DBT key, data;
557
	int rv = 0;
558
559
	memset(&key, 0, sizeof(DBT));
560
	memset(&data, 0, sizeof(DBT));
561
	memset(entry, 0, sizeof(CacheEntry));
562
563
	key.data=dn;
564
	key.size=strlen(dn)+1;
565
	data.flags = DB_DBT_REALLOC;
566
567
	signals_block();
568
	rv=dbp->get(dbp, NULL, &key, &data, 0);
569
	signals_unblock();
570
571
	if (rv != 0 && rv != DB_NOTFOUND) {
572
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
573
				"reading %s from database failed", dn);
574
		dbp->err(dbp, rv, "get");
575
		return rv;
576
	} else if (rv == DB_NOTFOUND) {
577
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "no cache entry found for %s",
578
				dn);
579
		return rv;
580
	}
581
582
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "got %d bytes for %s",
583
			data.size, dn);
584
585
	if ((rv=parse_entry(data.data, data.size, entry)) != 0) {
586
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
587
				"parsing entry failed");
588
		free(data.data);
589
		exit(1);
590
	}
591
592
	free(data.data);
593
	return rv;
594
}
595
596
int bdb_cache_get_entry_lower_upper(char *dn, CacheEntry *entry)
597
{
598
	char *lower_dn;
599
	bool mixedcase = false;
600
	int	 rv;
601
602
	// convert to a lowercase dn
603
	lower_dn = lower_utf8(dn);
604
	if (strcmp(dn, lower_dn) != 0) {
605
		mixedcase = true;
606
	}
607
608
	rv = bdb_cache_get_entry(lower_dn, entry);
609
	if (rv == DB_NOTFOUND && mixedcase ) {
610
		// try again with original dn
611
		rv = bdb_cache_get_entry(dn, entry);
612
	}
613
614
	free(lower_dn);
615
	return rv;
616
}
617
618
int bdb_cache_first_entry(DBC **cur, char **dn, CacheEntry *entry)
619
{
620
	int rv;
621
622
	if ((rv=dbp->cursor(dbp, NULL, cur, 0)) != 0) {
623
		dbp->err(dbp, rv, "cursor");
624
		return rv;
625
	}
626
627
	return bdb_cache_next_entry(cur, dn, entry);
628
}
629
630
int bdb_cache_print_entries(char *dn)
631
{
632
	DBT key, data;
633
	DBC *cur;
634
	memset(&key, 0, sizeof(DBT));
635
	memset(&data, 0, sizeof(DBT));
636
	key.data = strdup(dn);
637
	key.size = strlen(dn)+1;
638
	key.flags = DB_DBT_REALLOC;
639
	data.flags = DB_DBT_REALLOC;
640
641
	dbp->cursor(dbp, NULL, &cur, 0);
642
	cur->c_get(cur, &key, &data, DB_FIRST);
643
	do {
644
		printf("%s\n", (char*)key.data);
645
	} while (cur->c_get(cur, &key, &data, DB_NEXT) == 0);
646
647
	cur->c_close(cur);
648
	free(key.data);
649
	free(data.data);
650
	return 0;
651
}
652
653
int bdb_cache_next_entry(DBC **cur, char **dn, CacheEntry *entry)
654
{
655
	DBT key, data;
656
	int rv;
657
658
	memset(&key, 0, sizeof(DBT));
659
	key.flags = DB_DBT_REALLOC;
660
	memset(&data, 0, sizeof(DBT));
661
	data.flags = DB_DBT_REALLOC;
662
663
	if ((rv=(*cur)->c_get(*cur, &key, &data, DB_NEXT)) == DB_NOTFOUND) {
664
		return rv;
665
	} else if (rv != 0) {
666
		dbp->err(dbp, rv, "c_get");
667
		return rv;
668
	}
669
670
	/* skip master entry */
671
	if (strcmp(key.data, MASTER_KEY) == 0) {
672
		free(key.data);
673
		free(data.data);
674
		return bdb_cache_next_entry(cur, dn, entry);
675
	}
676
677
	if (*dn)
678
		free(*dn);
679
	*dn = strdup(key.data);
680
681
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "got %d bytes", data.size);
682
683
	if ((rv=parse_entry(data.data, data.size, entry)) != 0) {
684
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
685
				"parsing entry failed: %s", *dn);
686
		printf("%d\n", data.size);
687
		free(key.data);
688
		free(data.data);
689
		return rv;
690
	}
691
692
	free(key.data);
693
	free(data.data);
694
695
	return 0;
696
}
697
698
int bdb_cache_free_cursor(DBC *cur)
699
{
700
	return cur->c_close(cur);
701
}
702
703
int bdb_cache_close(void)
704
{
705
	int rv = 0;
706
707
	if (dbp && (rv = dbp->close(dbp, 0)) != 0) {
708
		dbp->err(dbp, rv, "close");
709
	}
710
	dbp = NULL;
711
#ifdef WITH_DB42
712
	if ((rv = dbenvp->close(dbenvp, 0)) != 0) {
713
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
714
				"closing database environment failed");
715
	}
716
#endif
717
	if (lock_fp != NULL) {
718
		fclose(lock_fp);
719
		lock_fp = NULL;
720
	}
721
	return rv;
722
}
(-)a/management/univention-directory-listener/src/cache_bdb.h (+94 lines)
Line 0    Link Here 
1
/*
2
 * Univention Directory Listener
3
 *  header information for cache.c
4
 *
5
 * Copyright 2004-2017 Univention GmbH
6
 *
7
 * http://www.univention.de/
8
 *
9
 * All rights reserved.
10
 *
11
 * The source code of this program is made available
12
 * under the terms of the GNU Affero General Public License version 3
13
 * (GNU AGPL V3) as published by the Free Software Foundation.
14
 *
15
 * Binary versions of this program provided by Univention to you as
16
 * well as other copyrighted, protected or trademarked materials like
17
 * Logos, graphics, fonts, specific documentations and configurations,
18
 * cryptographic keys etc. are subject to a license agreement between
19
 * you and Univention and not subject to the GNU AGPL V3.
20
 *
21
 * In the case you use this program under the terms of the GNU AGPL V3,
22
 * the program is provided in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public
28
 * License with the Debian GNU/Linux or Univention distribution in file
29
 * /usr/share/common-licenses/AGPL-3; if not, see
30
 * <http://www.gnu.org/licenses/>.
31
 */
32
33
#ifndef _CACHE_BDB_H_
34
#define _CACHE_BDB_H_
35
36
#include <db.h>
37
38
#include "network.h"
39
#include "cache_entry.h"
40
41
extern char *bdb_cache_dir;
42
extern char *bdb_ldap_dir;
43
44
typedef struct _BdbCacheMasterEntry {
45
	NotifierID id;
46
	NotifierID schema_id;
47
} BdbCacheMasterEntry;
48
extern BdbCacheMasterEntry bdb_cache_master_entry;
49
50
int	bdb_cache_lock(void);
51
int	bdb_cache_init				(void);
52
void	bdb_cache_sync(void);
53
int	bdb_cache_get_master_entry			(BdbCacheMasterEntry	 *master_entry);
54
int	bdb_cache_update_master_entry		(BdbCacheMasterEntry	 *master_entry,
55
						 DB_TXN			 *dptxnp);
56
int	bdb_cache_update_entry			(NotifierID		  id,
57
						 char			 *dn,
58
						 CacheEntry		 *entry);
59
inline int	bdb_cache_update_entry_lower			(NotifierID		  id,
60
						 char			 *dn,
61
						 CacheEntry		 *entry);
62
int	bdb_cache_delete_entry			(NotifierID		  id,
63
						 char			 *dn);
64
int	bdb_cache_delete_entry_lower_upper			(NotifierID		  id,
65
						 char			 *dn);
66
int	bdb_cache_update_or_deleteifunused_entry	(NotifierID		  id,
67
						 char			 *dn,
68
						 CacheEntry		 *entry);
69
int	bdb_cache_get_entry(
70
						 char			 *dn,
71
						 CacheEntry		 *entry);
72
int	bdb_cache_get_entry_lower_upper(
73
						 char			 *dn,
74
						 CacheEntry		 *entry);
75
int	bdb_cache_first_entry			(DBC			**cur,
76
						 char			**dn,
77
						 CacheEntry		 *entry);
78
int	bdb_cache_next_entry			(DBC			**cur,
79
						 char			**dn,
80
						 CacheEntry		 *entry);
81
int	bdb_cache_free_cursor			(DBC			 *cur);
82
int	bdb_cache_close				(void);
83
84
/* deprecated with DB42*/
85
int	bdb_cache_set_int				(char		 *key,
86
						 const NotifierID		  value);
87
int	bdb_cache_get_int				(char		 *key,
88
						 NotifierID			 *value,
89
						 const long		  def);
90
91
int bdb_cache_get_schema_id(NotifierID *value, const long def);
92
int bdb_cache_set_schema_id(const NotifierID value);
93
94
#endif /* _CACHE_BDB_H_ */
(-)a/management/univention-directory-listener/src/cache_dn.c (+569 lines)
Line 0    Link Here 
1
/*
2
 *  example implementation for mdb dntree adjecency list
3
 *
4
 * Copyright 2016 Univention GmbH
5
 * Copyright 2016 Arvid Requate
6
 *
7
 * http://www.univention.de/
8
 *
9
 * All rights reserved.
10
 *
11
 * The source code of this program is made available
12
 * under the terms of the GNU Affero General Public License version 3
13
 * (GNU AGPL V3) as published by the Free Software Foundation.
14
 *
15
 * Binary versions of this program provided by Univention to you as
16
 * well as other copyrighted, protected or trademarked materials like
17
 * Logos, graphics, fonts, specific documentations and configurations,
18
 * cryptographic keys etc. are subject to a license agreement between
19
 * you and Univention and not subject to the GNU AGPL V3.
20
 *
21
 * In the case you use this program under the terms of the GNU AGPL V3,
22
 * the program is provided in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public
28
 * License with the Debian GNU/Linux or Univention distribution in file
29
 * /usr/share/common-licenses/AGPL-3; if not, see
30
 * <http://www.gnu.org/licenses/>.
31
 */
32
33
/*
34
 * Derived From: This code is derived from dn2id.c written by Howard Chu.
35
 * The code of dn2id.c has been published under OpenLDAP Public License.
36
 *
37
 * A copy of this license is available in the file LICENSE in the
38
 * top-level directory of the distribution or, alternatively, at
39
 * <http://www.OpenLDAP.org/license.html>.
40
 */
41
42
#include <stdio.h>
43
#include <unistd.h>
44
#include <malloc.h>
45
#include <stdlib.h>
46
#include <sys/types.h>
47
#include <sys/stat.h>
48
#include <unistd.h>
49
#include <assert.h>
50
#include "cache_dn.h"
51
#include <univention/debug.h>
52
53
int mdb_dupsort(const MDB_val *a, const MDB_val *b)
54
{
55
	int		diff;
56
	subDN		*sdn_a, *sdn_b;
57
58
	sdn_a = (subDN *)a->mv_data;
59
	sdn_b = (subDN *)b->mv_data;
60
61
	diff = sdn_a->type - sdn_b->type;
62
	if (diff) {
63
		return diff;
64
	}
65
	if (sdn_a->type == SUBDN_TYPE_LINK) {
66
		return strcmp(sdn_a->data, sdn_b->data);
67
	} else {
68
		return 0;
69
	}
70
}
71
72
unsigned int num_rdns(LDAPDN dn) {
73
	unsigned int	iRDN;
74
75
	for (iRDN=0; dn[iRDN]; iRDN++);
76
77
	return iRDN;
78
}
79
80
/* climb the dntree */
81
static int dntree_lookup_id4ldapdn(MDB_cursor *cur, LDAPDN dn, DNID *dnid_out, int *found_out)
82
{
83
	int		rv, iRDN, found;
84
	MDB_val		key, data;
85
	DNID		parent, id = 0;
86
	char		*rdn;
87
	subDN		*subdn;
88
89
	key.mv_size = sizeof(DNID);
90
91
	found = 0;
92
	iRDN = num_rdns(dn);
93
	for (iRDN--; iRDN>=0; iRDN--) {
94
		rv = ldap_rdn2str(dn[iRDN], &rdn, LDAP_DN_FORMAT_LDAPV3);
95
		if (rv != LDAP_SUCCESS) {
96
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
97
				"%s: ldap_rdn2str failed: %s (%d)",
98
				__func__, ldap_err2string(rv), rv);
99
			return rv;
100
		}
101
102
		key.mv_data = &parent;
103
		parent = id;
104
105
		data.mv_size = sizeof(subDN) + strlen(rdn);
106
		subdn = malloc(data.mv_size);
107
		memset(subdn, 0, data.mv_size);
108
		if (subdn == NULL) {
109
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
110
				"%s: Malloc failed", __func__);
111
			ldap_memfree(rdn);
112
			abort();
113
		}
114
		subdn->type = SUBDN_TYPE_LINK;
115
		strcpy(subdn->data, rdn);
116
		ldap_memfree(rdn);
117
		data.mv_data = subdn;
118
119
		rv = mdb_cursor_get(cur, &key, &data, MDB_GET_BOTH);
120
		free(subdn);
121
122
		if (rv == MDB_NOTFOUND) {
123
			break;
124
		}
125
		if (rv != MDB_SUCCESS) {
126
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
127
				"%s: mdb_cursor_get failed: %s (%d)",
128
			           __func__, ldap_err2string(rv), rv);
129
			return rv;
130
		};
131
132
		subdn = (subDN *) data.mv_data;
133
		id = subdn->id;
134
		found++;
135
	}
136
137
	if (rv == MDB_SUCCESS) {
138
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
139
			"%s: found id=%lu",
140
		        __func__, id);
141
	} else if (rv != MDB_NOTFOUND) {
142
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
143
			"%s: failed: %s (%d)",
144
		        __func__, mdb_strerror(rv), rv);
145
	}
146
147
	*dnid_out = id; 
148
	if (found_out) {
149
		*found_out = found;
150
	};
151
152
	return rv;
153
}
154
155
int dntree_lookup_dn4id(MDB_cursor *cur, DNID dnid, char **dn)
156
{
157
	int		rv;
158
	MDB_val		key, data;
159
	subDN		*subdn;
160
	DNID		id = dnid;
161
162
	key.mv_size = sizeof(DNID);
163
	key.mv_data = &id;
164
165
	data.mv_size = sizeof(subDN);
166
	subdn = malloc(data.mv_size);
167
	memset(subdn, 0, data.mv_size);
168
	if (subdn == NULL) {
169
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
170
			"%s: Malloc failed", __func__);
171
		abort();
172
	}
173
	subdn->type = SUBDN_TYPE_NODE;
174
	data.mv_data = subdn;
175
176
	rv = mdb_cursor_get(cur, &key, &data, MDB_GET_BOTH);
177
	free(subdn);
178
	data.mv_data = NULL;
179
	data.mv_size = 0;
180
181
	if (rv != MDB_SUCCESS) {
182
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
183
			"%s: mdb_cursor_get (MDB_GET_BOTH): %s (%d)",
184
		        __func__, mdb_strerror(rv), rv);
185
		return rv;
186
	};
187
188
	// Workaround for (ITS#8393) LMDB - MDB_GET_BOTH broken on non-dup value
189
	rv = mdb_cursor_get(cur, &key, &data, MDB_GET_CURRENT);
190
	if (rv != MDB_SUCCESS) {
191
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
192
			"%s: mdb_cursor_get: %s (%d)",
193
		        __func__, mdb_strerror(rv), rv);
194
		return rv;
195
	};
196
197
	/*
198
	 * or simply use this instead of MDB_GET_BOTH + MDB_GET_CURRENT:
199
	MDB_txn		*txn;
200
	MDB_dbi		dbi;
201
	txn = mdb_cursor_txn(cur);
202
	dbi = mdb_cursor_dbi(cur);
203
	rv = mdb_get(txn, dbi, &key, &data);
204
	if (rv != MDB_SUCCESS) {
205
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
206
			"%s: mdb_get: %s (%d)",
207
		        __func__, mdb_strerror(rv), rv);
208
		return rv;
209
	};
210
	*/
211
212
	subdn = (subDN *) data.mv_data;
213
214
	*dn = malloc(strlen(subdn->data) + 1);
215
	if (*dn == NULL) {
216
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
217
			"%s: Malloc failed", __func__);
218
		abort();
219
	}
220
	strcpy(*dn, subdn->data);
221
222
	return rv;
223
}
224
225
static int next_free_dnid(MDB_cursor *cur, DNID *dnid_out)
226
{
227
	int		rv;
228
	MDB_val		key;
229
230
	rv = mdb_cursor_get(cur, &key, NULL, MDB_LAST);
231
	if (rv == MDB_SUCCESS) {
232
		*dnid_out = (*(DNID *) key.mv_data) + 1;
233
		return rv;
234
	} else if (rv == MDB_NOTFOUND) {
235
		*dnid_out = 1;
236
		return MDB_SUCCESS;
237
	} else {
238
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
239
			"%s: mdb_cursor_get: %s (%d)",
240
		        __func__, mdb_strerror(rv), rv);
241
		return rv;
242
	}
243
}
244
245
static int dntree_add_id(MDB_cursor *write_cursor_p, DNID child, LDAPDN dn, DNID parent)
246
{
247
	int		rv;
248
	MDB_val		key, data;
249
	DNID		id;
250
	char		*rdn_str;
251
	char		*dn_str;
252
	size_t		dn_len;
253
	size_t		rdn_len;
254
	subDN		*subdn;
255
256
	key.mv_size = sizeof(DNID);
257
	key.mv_data = &id;
258
	id = parent;
259
260
	rv = ldap_dn2str(dn, &dn_str, LDAP_DN_FORMAT_LDAPV3);
261
	if (rv != LDAP_SUCCESS) {
262
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
263
			"%s: ldap_dn2str failed: %s (%d)",
264
		        __func__, ldap_err2string(rv), rv);
265
		return rv;
266
	}
267
268
	rv = ldap_rdn2str(dn[0], &rdn_str, LDAP_DN_FORMAT_LDAPV3);
269
	if (rv != LDAP_SUCCESS) {
270
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
271
			"%s: ldap_rdn2str failed: %s (%d)",
272
		        __func__, ldap_err2string(rv), rv);
273
		ldap_memfree(dn_str);
274
		return rv;
275
	}
276
277
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
278
		"%s: child=%lu, parent=%lu: \"%s\"",
279
	        __func__, child, parent, rdn_str);
280
281
	dn_len = strlen(dn_str);
282
	subdn = malloc(sizeof(subDN) + dn_len);
283
	memset(subdn, 0, sizeof(subDN) + dn_len);
284
	rdn_len = strlen(rdn_str);
285
	assert(dn_len >= rdn_len);
286
	data.mv_size = sizeof(subDN) + rdn_len;
287
	if (subdn == NULL) {
288
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
289
			"%s: Malloc failed", __func__);
290
		ldap_memfree(dn_str);
291
		ldap_memfree(rdn_str);
292
		abort();
293
	}
294
	subdn->type = SUBDN_TYPE_LINK;
295
	subdn->id = child;
296
	strcpy(subdn->data, rdn_str);
297
	ldap_memfree(rdn_str);
298
	data.mv_data = subdn;
299
300
	// Store subdn link
301
	rv = mdb_cursor_put(write_cursor_p, &key, &data, MDB_NODUPDATA);
302
303
	// Store subdn node
304
	if (rv == MDB_SUCCESS) {
305
		id = child;
306
307
		data.mv_size = sizeof(subDN) + dn_len;
308
		subdn->type = SUBDN_TYPE_NODE;
309
		subdn->id = parent;	// backlink
310
		strcpy(subdn->data, dn_str);
311
312
		rv = mdb_cursor_put(write_cursor_p, &key, &data, MDB_NODUPDATA);
313
		if (rv != MDB_SUCCESS) {
314
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
315
				"%s: mdb_cursor_put failed for child %lu: %s (%d)",
316
			        __func__, id, mdb_strerror(rv), rv);
317
		}
318
	} else {
319
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
320
			"%s: mdb_cursor_put failed for parent %lu: %s (%d)",
321
		        __func__, id, mdb_strerror(rv), rv);
322
	}
323
	ldap_memfree(dn_str);
324
	free(subdn);
325
326
	return rv;
327
}
328
329
static int dntree_has_children(MDB_cursor *local_cursor, DNID dnid)
330
{
331
	int		rv;
332
	size_t		values;
333
	MDB_val		key, data;
334
335
	key.mv_size = sizeof(DNID);
336
	key.mv_data = &dnid;
337
338
	rv = mdb_cursor_get(local_cursor, &key, &data, MDB_SET);
339
	if (rv != MDB_SUCCESS) {
340
		return rv;
341
	}
342
343
	rv = mdb_cursor_count(local_cursor, &values);
344
	if (rv == MDB_SUCCESS && values < 2) {
345
		rv = MDB_NOTFOUND;
346
	}
347
	return rv;
348
}
349
350
int dntree_del_id(MDB_cursor *write_cursor_p, DNID dnid)
351
{
352
	int		rv;
353
	MDB_val		key, data;
354
	MDB_cursor	*local_read_cursor_p;
355
	MDB_txn		*txn;
356
	MDB_dbi		dbi;
357
358
	txn = mdb_cursor_txn(write_cursor_p);
359
	dbi = mdb_cursor_dbi(write_cursor_p);
360
	rv = mdb_cursor_open(txn, dbi, &local_read_cursor_p);
361
	if (rv != MDB_SUCCESS) {
362
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
363
			"%s: mdb_cursor_open: %s (%d)",
364
		        __func__, ldap_err2string(rv), rv);
365
		return rv;
366
	}
367
368
	rv = dntree_has_children(local_read_cursor_p, dnid);
369
	if (rv == MDB_SUCCESS) {
370
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
371
			"%s: delete failed:"
372
		        " subordinate objects must be deleted first",
373
		        __func__);
374
		return -1;
375
	} else if (rv != MDB_NOTFOUND) {
376
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
377
			"%s: dntree_has_children failed: %s (%d)",
378
		        __func__, mdb_strerror(rv), rv);
379
		return -1;
380
	}
381
	mdb_cursor_close(local_read_cursor_p);
382
383
	// dntree_lookup_id4ldapdn positioned cursor on SUBDN_TYPE_LINK node below parent's key
384
	rv = mdb_cursor_del(write_cursor_p, 0);
385
386
	if (rv == MDB_SUCCESS) {
387
		key.mv_size = sizeof(DNID);
388
		key.mv_data = &dnid;
389
		rv = mdb_cursor_get(write_cursor_p, &key, &data, MDB_SET);
390
		if (rv == MDB_SUCCESS) {
391
			rv = mdb_cursor_del(write_cursor_p, 0);
392
		}
393
	}
394
395
	return rv;
396
}
397
398
int dntree_del_ldapdn(MDB_cursor *write_cursor_p, LDAPDN dn)
399
{
400
	int		rv;
401
	DNID		id;
402
403
	rv = dntree_lookup_id4ldapdn(write_cursor_p, dn, &id, NULL);
404
	if (rv != MDB_SUCCESS) {
405
		return rv;
406
	}
407
408
	return dntree_del_id(write_cursor_p, id);
409
}
410
411
412
static int dntree_get_id4ldapdn(MDB_cursor *write_cursor_p, LDAPDN dn, DNID *dnid_out)
413
{
414
	int		rv, found;
415
	DNID		id, parent = 0;
416
	LDAPDN		pdn;
417
418
	if (dn == NULL) {
419
		*dnid_out = 0;
420
		return MDB_SUCCESS;
421
	}
422
423
	rv = dntree_lookup_id4ldapdn(write_cursor_p, dn, &id, &found);
424
	if (rv == MDB_NOTFOUND) {
425
		pdn = &dn[1];
426
		if (num_rdns(pdn) != found) {
427
			rv = dntree_get_id4ldapdn(write_cursor_p, pdn, &parent); 
428
			if (rv != MDB_SUCCESS) {
429
				univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
430
					"%s: failed: %s (%d)",
431
				        __func__, mdb_strerror(rv), rv);
432
				return rv;
433
			}
434
		} else {
435
			parent = id;
436
		}
437
		rv = next_free_dnid(write_cursor_p, &id);
438
		if (rv != MDB_SUCCESS) {
439
			return rv;
440
		}
441
		rv = dntree_add_id(write_cursor_p, id, dn, parent);
442
	}
443
444
	*dnid_out = id;
445
446
	return rv;
447
}
448
449
int dntree_get_id4dn(MDB_cursor *id2dn_cursor_p, char *dn, DNID *dnid, bool create)
450
{
451
	int		rv;
452
	LDAPDN		ldapdn;
453
454
	rv = ldap_str2dn(dn, &ldapdn, LDAP_DN_FORMAT_LDAP);
455
	if (rv != LDAP_SUCCESS) {
456
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
457
			"%s: ldap_str2dn failed: %s (%d)",
458
		        __func__, ldap_err2string(rv), rv);
459
		return rv;
460
	}
461
462
	if (ldapdn == NULL) {
463
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
464
			"%s: ldap_str2dn NULL: %s (%d): %s",
465
		        __func__, ldap_err2string(rv), rv, dn);
466
		return 1;
467
	}
468
469
	if (create == true) {
470
		rv = dntree_get_id4ldapdn(id2dn_cursor_p, ldapdn, dnid); 
471
		if (rv != MDB_SUCCESS) {
472
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
473
				"%s: failed for: %s",
474
			        __func__, dn);
475
		}
476
		
477
	} else {
478
		rv = dntree_lookup_id4ldapdn(id2dn_cursor_p, ldapdn, dnid, NULL);
479
		if (rv == MDB_NOTFOUND) {
480
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
481
				"%s: DN %s not in id2dn",
482
			        __func__, dn);
483
		}
484
	}
485
486
	ldap_dnfree(ldapdn);
487
	return rv;
488
}
489
490
int dntree_del_dn(MDB_cursor *write_cursor_p, char *dn)
491
{
492
	int		rv;
493
	LDAPDN		ldapdn;
494
495
	rv = ldap_str2dn(dn, &ldapdn, LDAP_DN_FORMAT_LDAP);
496
	if (rv != LDAP_SUCCESS) {
497
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
498
			"%s: ldap_str2dn failed: %s (%d)",
499
		        __func__, ldap_err2string(rv), rv);
500
		return rv;
501
	}
502
503
	if (ldapdn == NULL) {
504
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
505
			"%s: ldap_str2dn NULL: %s (%d): %s",
506
		        __func__, ldap_err2string(rv), rv, dn);
507
		return 1;
508
	}
509
510
	rv = dntree_del_ldapdn(write_cursor_p, ldapdn); 
511
512
	ldap_dnfree(ldapdn);
513
	return rv;
514
}
515
516
517
int dntree_init(MDB_dbi *dbi_p, MDB_txn *cache_init_txn_p, int mdb_flags)
518
{
519
	int		rv;
520
	MDB_val		key, data;
521
	MDB_cursor	*cur;
522
	int		mdb_dbi_flags = MDB_INTEGERKEY|MDB_DUPSORT;
523
	bool		readonly = (mdb_flags & MDB_RDONLY) != 0;
524
525
	if (!readonly) {
526
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
527
				"dntree_init: MDB_RDONLY");
528
		mdb_dbi_flags |= MDB_CREATE;
529
	}
530
531
	rv = mdb_dbi_open(cache_init_txn_p, "id2dn", mdb_dbi_flags, dbi_p);
532
	if (rv != MDB_SUCCESS) {
533
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
534
			"%s: mdb_dbi_open: %s (%d)",
535
			__func__, mdb_strerror(rv), rv);
536
		return rv;
537
	};
538
	rv = mdb_set_dupsort(cache_init_txn_p, *dbi_p, mdb_dupsort);
539
	if (rv != MDB_SUCCESS) {
540
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
541
			"%s: mdb_set_dupsort: %s (%d)",
542
			__func__, mdb_strerror(rv), rv);
543
		return rv;
544
	};
545
546
	if (readonly) {
547
		return MDB_SUCCESS;
548
	}
549
550
	rv = mdb_cursor_open(cache_init_txn_p, *dbi_p, &cur);
551
	if (rv != MDB_SUCCESS) {
552
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
553
			"%s: mdb_cursor_open: %s (%d)",
554
			__func__, mdb_strerror(rv), rv);
555
		return rv;
556
	};
557
558
	// create root node
559
	key.mv_size = sizeof(DNID);
560
	key.mv_data = &(DNID) {0};
561
	data.mv_size = sizeof(subDN);
562
	data.mv_data = &(subDN) {0, SUBDN_TYPE_NODE, {0}};
563
	// ignore exists
564
	mdb_cursor_put(cur, &key, &data, MDB_NODUPDATA);
565
	// not strictly required, mdb_txn_commit does it for write txn
566
	mdb_cursor_close(cur);
567
568
	return MDB_SUCCESS;
569
}
(-)a/management/univention-directory-listener/src/cache_dn.h (+64 lines)
Line 0    Link Here 
1
/*
2
 *  header information for dntree.c
3
 *
4
 * Copyright 2016 Univention GmbH
5
 * Copyright 2016 Arvid Requate
6
 *
7
 * http://www.univention.de/
8
 *
9
 * All rights reserved.
10
 *
11
 * The source code of this program is made available
12
 * under the terms of the GNU Affero General Public License version 3
13
 * (GNU AGPL V3) as published by the Free Software Foundation.
14
 *
15
 * Binary versions of this program provided by Univention to you as
16
 * well as other copyrighted, protected or trademarked materials like
17
 * Logos, graphics, fonts, specific documentations and configurations,
18
 * cryptographic keys etc. are subject to a license agreement between
19
 * you and Univention and not subject to the GNU AGPL V3.
20
 *
21
 * In the case you use this program under the terms of the GNU AGPL V3,
22
 * the program is provided in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public
28
 * License with the Debian GNU/Linux or Univention distribution in file
29
 * /usr/share/common-licenses/AGPL-3; if not, see
30
 * <http://www.gnu.org/licenses/>.
31
 */
32
33
#ifndef _DNTREE_H_
34
#define _DNTREE_H_
35
36
#include <stdbool.h>
37
#include <lmdb.h>
38
#include <ldap.h>
39
40
typedef struct mdb_ctx {
41
	MDB_env		*env;
42
	MDB_dbi		dbi;
43
	MDB_txn		*txn;
44
	MDB_cursor	*cur;
45
} mdb_ctx;
46
47
#define	SUBDN_TYPE_NODE 0
48
#define	SUBDN_TYPE_LINK 1
49
50
typedef unsigned char SUBDNTYPE;
51
typedef unsigned long DNID;
52
typedef struct subDN {
53
	DNID id;
54
	SUBDNTYPE type;
55
	char data[1];
56
} subDN;
57
58
int dntree_init(MDB_dbi *dbi_ptr, MDB_txn *write_txn_p, int mdb_flags);
59
int dntree_get_id4dn(MDB_cursor *cursor, char *dn, DNID *dnid, bool create);
60
int dntree_lookup_dn4id(MDB_cursor *cur, DNID dnid, char **dn);
61
int dntree_del_id(MDB_cursor *cursor, DNID dnid);
62
int dntree_del_ldapdn(MDB_cursor *cursor, LDAPDN dn);
63
64
#endif /* _DNTREE_H_ */
(-)a/management/univention-directory-listener/src/change.c (-11 / +11 lines)
 Lines 40-46    Link Here 
40
#include <stdlib.h>
40
#include <stdlib.h>
41
#include <stdbool.h>
41
#include <stdbool.h>
42
#include <string.h>
42
#include <string.h>
43
#include <db.h>
43
#include <lmdb.h>
44
44
45
#include <univention/debug.h>
45
#include <univention/debug.h>
46
#include <univention/config.h>
46
#include <univention/config.h>
 Lines 74-80   static int change_init_module(univention_ldap_parameters_t *lp, Handler *handler Link Here 
74
	struct filter **f;
74
	struct filter **f;
75
	int rv;
75
	int rv;
76
	CacheEntry cache_entry, old_cache_entry;
76
	CacheEntry cache_entry, old_cache_entry;
77
	DBC *dbc_cur;
77
	MDB_cursor *id2entry_cursor_p = NULL;
78
	MDB_cursor *id2dn_cursor_p = NULL;
78
	char *dn = NULL;
79
	char *dn = NULL;
79
	int i;
80
	int i;
80
	bool abort_init = false;
81
	bool abort_init = false;
 Lines 93-118   static int change_init_module(univention_ldap_parameters_t *lp, Handler *handler Link Here 
93
	/* remove old entries for module */
94
	/* remove old entries for module */
94
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
95
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
95
			"remove old entries for module %s", handler->name);
96
			"remove old entries for module %s", handler->name);
96
	for (rv=cache_first_entry(&dbc_cur, &dn, &cache_entry); rv != DB_NOTFOUND;
97
	for (rv=cache_first_entry(&id2entry_cursor_p, &id2dn_cursor_p, &dn, &cache_entry); rv != MDB_NOTFOUND;
97
			rv=cache_next_entry(&dbc_cur, &dn, &cache_entry)) {
98
			rv=cache_next_entry(&id2entry_cursor_p, &id2dn_cursor_p, &dn, &cache_entry)) {
98
		if (rv == -1) continue;
99
		if (rv == -1) continue;
99
		if (rv < 0) break;
100
		if (rv < 0) break;
100
101
101
		cache_entry_module_remove(&cache_entry, handler->name);
102
		cache_entry_module_remove(&cache_entry, handler->name);
102
		cache_update_or_deleteifunused_entry(0, dn, &cache_entry);
103
		cache_update_or_deleteifunused_entry(0, dn, &cache_entry, &id2dn_cursor_p);
103
		cache_free_entry(&dn, &cache_entry);
104
		cache_free_entry(&dn, &cache_entry);
104
	}
105
	}
105
106
106
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
107
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
107
			"call cache_free_cursor for module %s", handler->name);
108
			"call cache_free_cursor for module %s", handler->name);
108
	cache_free_cursor(dbc_cur);
109
	cache_free_cursor(id2entry_cursor_p, id2dn_cursor_p);
109
110
110
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
111
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_INFO,
111
			"initialize schema for module %s", handler->name);
112
			"initialize schema for module %s", handler->name);
112
	/* initialize schema; if it's not in cache yet (it really should be), it'll
113
	/* initialize schema; if it's not in cache yet (it really should be), it'll
113
	   be initialized on the regular schema check after ldapsearches */
114
	   be initialized on the regular schema check after ldapsearches */
114
	if ((rv = cache_get_entry_lower_upper("cn=Subschema", &cache_entry)) != 0 &&
115
	if ((rv = cache_get_entry_lower_upper("cn=Subschema", &cache_entry)) != 0 &&
115
			rv != DB_NOTFOUND) {
116
			rv != MDB_NOTFOUND) {
116
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN,
117
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN,
117
				"error while reading from database");
118
				"error while reading from database");
118
		return LDAP_OTHER;
119
		return LDAP_OTHER;
 Lines 184-190   static int change_init_module(univention_ldap_parameters_t *lp, Handler *handler Link Here 
184
		for (i=0; i<dn_count; i++) {
185
		for (i=0; i<dn_count; i++) {
185
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "DN: %s", dns[i].dn);
186
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ALL, "DN: %s", dns[i].dn);
186
187
187
			if ((rv = cache_get_entry_lower_upper(dns[i].dn, &cache_entry)) == DB_NOTFOUND) { /* XXX */
188
			if ((rv = cache_get_entry_lower_upper(dns[i].dn, &cache_entry)) == MDB_NOTFOUND) { /* XXX */
188
				LDAPMessage *res2, *first;
189
				LDAPMessage *res2, *first;
189
				int attrsonly0 = 0;
190
				int attrsonly0 = 0;
190
				rv = LDAP_RETRY(lp, ldap_search_ext_s(lp->ld, dns[i].dn, LDAP_SCOPE_BASE, "(objectClass=*)", attrs, attrsonly0, serverctrls, clientctrls, &timeout, sizelimit0, &res2));
191
				rv = LDAP_RETRY(lp, ldap_search_ext_s(lp->ld, dns[i].dn, LDAP_SCOPE_BASE, "(objectClass=*)", attrs, attrsonly0, serverctrls, clientctrls, &timeout, sizelimit0, &res2));
 Lines 246-252   int change_new_modules(univention_ldap_parameters_t *lp) Link Here 
246
		}
247
		}
247
	}
248
	}
248
	INIT_ONLY = old_init_only;
249
	INIT_ONLY = old_init_only;
249
	cache_sync();
250
250
251
	return 0;
251
	return 0;
252
}
252
}
 Lines 267-273   int change_update_entry(univention_ldap_parameters_t *lp, NotifierID id, LDAPMes Link Here 
267
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error while converting LDAP entry to cache entry");
267
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error while converting LDAP entry to cache entry");
268
		goto result;
268
		goto result;
269
	}
269
	}
270
	if ((rv = cache_get_entry_lower_upper(dn, &old_cache_entry)) != 0 && rv != DB_NOTFOUND) {
270
	if ((rv = cache_get_entry_lower_upper(dn, &old_cache_entry)) != 0 && rv != MDB_NOTFOUND) {
271
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error while reading from database");
271
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error while reading from database");
272
		rv = LDAP_OTHER;
272
		rv = LDAP_OTHER;
273
	} else {
273
	} else {
 Lines 694-700   int change_update_dn(struct transaction *trans) { Link Here 
694
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_PROCESS, "updating '%s' command %c", trans->cur.notify.dn, trans->cur.notify.command);
694
	univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_PROCESS, "updating '%s' command %c", trans->cur.notify.dn, trans->cur.notify.command);
695
695
696
	rv = cache_get_entry_lower_upper(trans->cur.notify.dn, &trans->cur.cache);
696
	rv = cache_get_entry_lower_upper(trans->cur.notify.dn, &trans->cur.cache);
697
	if (rv != 0 && rv != DB_NOTFOUND) {
697
	if (rv != 0 && rv != MDB_NOTFOUND) {
698
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error reading database for %s", trans->cur.notify.dn);
698
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_WARN, "error reading database for %s", trans->cur.notify.dn);
699
		return LDAP_OTHER;
699
		return LDAP_OTHER;
700
	}
700
	}
(-)a/management/univention-directory-listener/src/convert.c (+151 lines)
Line 0    Link Here 
1
/*
2
 * Univention Directory Listener
3
 *  tool to convert the cache.
4
 *
5
 * Copyright 2016-2017 Univention GmbH
6
 *
7
 * http://www.univention.de/
8
 *
9
 * All rights reserved.
10
 *
11
 * The source code of this program is made available
12
 * under the terms of the GNU Affero General Public License version 3
13
 * (GNU AGPL V3) as published by the Free Software Foundation.
14
 *
15
 * Binary versions of this program provided by Univention to you as
16
 * well as other copyrighted, protected or trademarked materials like
17
 * Logos, graphics, fonts, specific documentations and configurations,
18
 * cryptographic keys etc. are subject to a license agreement between
19
 * you and Univention and not subject to the GNU AGPL V3.
20
 *
21
 * In the case you use this program under the terms of the GNU AGPL V3,
22
 * the program is provided in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public
28
 * License with the Debian GNU/Linux or Univention distribution in file
29
 * /usr/share/common-licenses/AGPL-3; if not, see
30
 * <http://www.gnu.org/licenses/>.
31
 */
32
33
#include <stdio.h>
34
#include <unistd.h>
35
#include <string.h>
36
#include <stdlib.h>
37
#include <fcntl.h>
38
#include <dirent.h>
39
#include <pwd.h>
40
#include <sys/types.h>
41
42
#include <univention/debug.h>
43
44
#include "cache_bdb.h"
45
#include "cache.h"
46
#include "common.h"
47
48
static void exit_if_cache_mdb_exists(void)
49
{
50
	int rv;
51
	char cache_mdb_filename[PATH_MAX];
52
53
	rv = snprintf(cache_mdb_filename, PATH_MAX, "%s/cache/data.mdb", cache_dir);
54
	if (rv < 0 || rv >= PATH_MAX)
55
		abort();
56
57
	if( access( cache_mdb_filename, F_OK ) != -1 ) {
58
		univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
59
				"%s already exists", cache_mdb_filename);
60
		exit(EXIT_FAILURE);
61
	}
62
}
63
64
static void usage(void)
65
{
66
	fprintf(stderr, "Usage: univention-directory-listener-convert [options]\n");
67
	fprintf(stderr, "Options:\n");
68
	fprintf(stderr, "   -d   debugging\n");
69
	fprintf(stderr, "   -c   Listener cache path\n");
70
}
71
72
73
int main(int argc, char* argv[])
74
{
75
	int debugging = 0;
76
	int rv;
77
	DBC *cur;
78
	char *dn = NULL;
79
	CacheEntry entry;
80
81
	univention_debug_init("stderr", 1, 1);
82
83
	/* parse arguments */
84
	for (;;) {
85
		int c;
86
87
		c = getopt(argc, argv, "d:c:");
88
		if (c < 0)
89
			break;
90
		switch (c) {
91
		case 'd':
92
			debugging=atoi(optarg);
93
			break;
94
		case 'c':
95
			cache_dir=strdup(optarg);
96
			bdb_cache_dir=strdup(optarg);
97
			break;
98
		default:
99
			usage();
100
			exit(1);
101
		}
102
	}
103
104
	if (debugging > 1) {
105
		univention_debug_set_level(UV_DEBUG_LISTENER, UV_DEBUG_ALL);
106
		univention_debug_set_level(UV_DEBUG_LDAP, UV_DEBUG_ALL);
107
		univention_debug_set_level(UV_DEBUG_KERBEROS, UV_DEBUG_ALL);
108
	} else if ( debugging > 0 ) {
109
		univention_debug_set_level(UV_DEBUG_LISTENER, UV_DEBUG_INFO);
110
		univention_debug_set_level(UV_DEBUG_LDAP, UV_DEBUG_INFO);
111
		univention_debug_set_level(UV_DEBUG_KERBEROS, UV_DEBUG_INFO);
112
	} else {
113
		univention_debug_set_level(UV_DEBUG_LISTENER, UV_DEBUG_ERROR);
114
		univention_debug_set_level(UV_DEBUG_LDAP, UV_DEBUG_ERROR);
115
		univention_debug_set_level(UV_DEBUG_KERBEROS, UV_DEBUG_ERROR);
116
	}
117
118
	exit_if_cache_mdb_exists();
119
120
	rv = bdb_cache_lock();
121
	rv = cache_lock();
122
123
	if (bdb_cache_init() != 0)
124
		exit(1);
125
126
	if (cache_init(0) != 0)
127
		exit(1);
128
129
	bdb_cache_get_master_entry(&bdb_cache_master_entry);
130
	rv = cache_update_master_entry(&cache_master_entry, NULL);
131
132
	for (rv=bdb_cache_first_entry(&cur, &dn, &entry); rv != DB_NOTFOUND;
133
			rv=bdb_cache_next_entry(&cur, &dn, &entry)) {
134
		if (rv != 0) {
135
			univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
136
			                 "error while reading database");
137
		} else if ((rv=cache_update_entry_lower(0, dn, &entry)) != MDB_SUCCESS) {
138
				univention_debug(UV_DEBUG_LISTENER, UV_DEBUG_ERROR,
139
				                 "error while writing to database");
140
		}
141
		cache_free_entry(&dn, &entry);
142
		if (rv < -1) break;
143
	}
144
145
	bdb_cache_free_cursor(cur);
146
147
	bdb_cache_close();
148
	cache_close();
149
150
	return 0;
151
}
(-)a/management/univention-directory-listener/src/dump.c (-5 / +6 lines)
 Lines 67-73   int main(int argc, char* argv[]) Link Here 
67
	char *output_file = NULL;
67
	char *output_file = NULL;
68
	FILE *fp;
68
	FILE *fp;
69
	int rv;
69
	int rv;
70
	DBC *cur;
70
	MDB_cursor *id2entry_read_cursor_p = NULL;
71
	MDB_cursor *id2dn_read_cursor_p = NULL;
71
	char *dn = NULL;
72
	char *dn = NULL;
72
	CacheEntry entry;
73
	CacheEntry entry;
73
74
 Lines 124-130   int main(int argc, char* argv[]) Link Here 
124
			"Couldn't open dump file");
125
			"Couldn't open dump file");
125
		exit(1);
126
		exit(1);
126
	}
127
	}
127
	if (cache_init() != 0)
128
	if (cache_init(MDB_RDONLY) != 0)
128
		exit(1);
129
		exit(1);
129
130
130
	if (id_only) {
131
	if (id_only) {
 Lines 133-140   int main(int argc, char* argv[]) Link Here 
133
		printf("%ld %ld\n", cache_master_entry.id, cache_master_entry.schema_id);
134
		printf("%ld %ld\n", cache_master_entry.id, cache_master_entry.schema_id);
134
	} else {
135
	} else {
135
136
136
	for (rv=cache_first_entry(&cur, &dn, &entry); rv != DB_NOTFOUND;
137
	for (rv=cache_first_entry(&id2entry_read_cursor_p, &id2dn_read_cursor_p, &dn, &entry); rv != MDB_NOTFOUND;
137
			rv=cache_next_entry(&cur, &dn, &entry)) {
138
			rv=cache_next_entry(&id2entry_read_cursor_p, &id2dn_read_cursor_p, &dn, &entry)) {
138
		if ((rv == 0 && !broken_only) || (rv == -1 && broken_only)) {
139
		if ((rv == 0 && !broken_only) || (rv == -1 && broken_only)) {
139
			cache_dump_entry(dn, &entry, fp);
140
			cache_dump_entry(dn, &entry, fp);
140
			fprintf(fp, "\n");
141
			fprintf(fp, "\n");
 Lines 142-148   int main(int argc, char* argv[]) Link Here 
142
		cache_free_entry(&dn, &entry);
143
		cache_free_entry(&dn, &entry);
143
		if (rv < -1) break;
144
		if (rv < -1) break;
144
	}
145
	}
145
	cache_free_cursor(cur);
146
	cache_free_cursor(id2entry_read_cursor_p, id2dn_read_cursor_p);
146
147
147
	}
148
	}
148
149
(-)a/management/univention-directory-listener/src/main.c (-2 / +3 lines)
 Lines 536-542   int main(int argc, char* argv[]) Link Here 
536
536
537
	/* XXX: we shouldn't block all signals for so long */
537
	/* XXX: we shouldn't block all signals for so long */
538
	signals_block();
538
	signals_block();
539
	cache_init();
539
	if (cache_init(0) != 0)
540
		exit(1);
540
	handlers_init();
541
	handlers_init();
541
542
542
	/* pass data to handlers */
543
	/* pass data to handlers */
 Lines 560-566   int main(int argc, char* argv[]) Link Here 
560
561
561
	/* if no ID is set, assume the database has just been initialized */
562
	/* if no ID is set, assume the database has just been initialized */
562
	rv = cache_get_master_entry(&cache_master_entry);
563
	rv = cache_get_master_entry(&cache_master_entry);
563
	if (rv == DB_NOTFOUND) {
564
	if (rv == MDB_NOTFOUND) {
564
		cache_get_int("notifier_id", &cache_master_entry.id, -1);
565
		cache_get_int("notifier_id", &cache_master_entry.id, -1);
565
		if (cache_master_entry.id == -1) {
566
		if (cache_master_entry.id == -1) {
566
			rv = notifier_get_id_s(NULL, &cache_master_entry.id);
567
			rv = notifier_get_id_s(NULL, &cache_master_entry.id);
(-)a/management/univention-directory-listener/src/verify.c (-6 / +7 lines)
 Lines 140-146   int main(int argc, char* argv[]) Link Here 
140
	char		*bindpw = NULL;
140
	char		*bindpw = NULL;
141
	char		*basedn = NULL;
141
	char		*basedn = NULL;
142
	int		 rv;
142
	int		 rv;
143
	DBC		*cur;
143
	MDB_cursor	*id2entry_read_cursor_p = NULL;
144
	MDB_cursor	*id2dn_read_cursor_p = NULL;
144
	char		*dn;
145
	char		*dn;
145
	CacheEntry	 entry;
146
	CacheEntry	 entry;
146
	LDAP		*ld;
147
	LDAP		*ld;
 Lines 221-231   int main(int argc, char* argv[]) Link Here 
221
	}
222
	}
222
223
223
224
224
	if (cache_init() != 0)
225
	if (cache_init(MDB_RDONLY) != 0)
225
		exit(1);
226
		exit(1);
226
227
227
	for (rv=cache_first_entry(&cur, &dn, &entry); rv != DB_NOTFOUND;
228
	for (rv=cache_first_entry(&id2entry_read_cursor_p, &id2dn_read_cursor_p, &dn, &entry); rv != MDB_NOTFOUND;
228
			rv=cache_next_entry(&cur, &dn, &entry)) {
229
			rv=cache_next_entry(&id2entry_read_cursor_p, &id2dn_read_cursor_p, &dn, &entry)) {
229
		if (rv < -1) break;
230
		if (rv < -1) break;
230
231
231
		if (has_dn(dn)) {
232
		if (has_dn(dn)) {
 Lines 245-251   int main(int argc, char* argv[]) Link Here 
245
		}
246
		}
246
		add_dn(dn);
247
		add_dn(dn);
247
	}
248
	}
248
	cache_free_cursor(cur);
249
	cache_free_cursor(id2entry_read_cursor_p, id2dn_read_cursor_p);
249
250
250
	if ((rv=ldap_search_ext_s(ld, basedn, LDAP_SCOPE_SUBTREE, "(objectClass=*)",
251
	if ((rv=ldap_search_ext_s(ld, basedn, LDAP_SCOPE_SUBTREE, "(objectClass=*)",
251
			attrs, attrsonly0, serverctrls, clientctrls, &timeout, sizelimit0, &res)) != LDAP_SUCCESS) {
252
			attrs, attrsonly0, serverctrls, clientctrls, &timeout, sizelimit0, &res)) != LDAP_SUCCESS) {
 Lines 258-264   int main(int argc, char* argv[]) Link Here 
258
			char *dn = ldap_get_dn(ld, cur);
259
			char *dn = ldap_get_dn(ld, cur);
259
			if (has_dn(dn)) continue;
260
			if (has_dn(dn)) continue;
260
261
261
			if ((rv = cache_get_entry(dn, &entry)) == DB_NOTFOUND) {
262
			if ((rv = cache_get_entry(dn, &entry)) == MDB_NOTFOUND) {
262
				printf("E: %s only in LDAP\n", dn);
263
				printf("E: %s only in LDAP\n", dn);
263
			} else if (rv != 0) {
264
			} else if (rv != 0) {
264
				printf("E: error reading %s from cache", dn);
265
				printf("E: error reading %s from cache", dn);

Return to bug 23367