GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapctl/ldapctl.c Lines: 0 200 0.0 %
Date: 2017-11-13 Branches: 0 131 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ldapctl.c,v 1.10 2017/01/20 11:55:08 benno Exp $	*/
2
3
/*
4
 * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
5
 * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
6
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
8
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
9
 *
10
 * Permission to use, copy, modify, and distribute this software for any
11
 * purpose with or without fee is hereby granted, provided that the above
12
 * copyright notice and this permission notice appear in all copies.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
 */
22
23
#include <sys/types.h>
24
#include <sys/socket.h>
25
#include <sys/stat.h>
26
#include <sys/queue.h>
27
#include <sys/un.h>
28
#include <sys/tree.h>
29
30
#include <netinet/in.h>
31
#include <arpa/inet.h>
32
#include <net/if.h>
33
#include <net/if_media.h>
34
#include <net/if_types.h>
35
36
#include <err.h>
37
#include <errno.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
#include <event.h>
43
44
#include "ldapd.h"
45
#include "log.h"
46
47
enum action {
48
	NONE,
49
	SHOW_STATS,
50
	LOG_VERBOSE,
51
	LOG_BRIEF,
52
	COMPACT_DB,
53
	INDEX_DB
54
};
55
56
__dead void	 usage(void);
57
void		 show_stats(struct imsg *imsg);
58
void		 show_dbstats(const char *prefix, struct btree_stat *st);
59
void		 show_nsstats(struct imsg *imsg);
60
int		 compact_db(const char *path);
61
int		 compact_namespace(struct namespace *ns, const char *datadir);
62
int		 compact_namespaces(const char *datadir);
63
int		 index_namespace(struct namespace *ns, const char *datadir);
64
int		 index_namespaces(const char *datadir);
65
int		 ssl_load_certfile(struct ldapd_config *, const char *, u_int8_t);
66
67
__dead void
68
usage(void)
69
{
70
	extern char *__progname;
71
72
	fprintf(stderr,
73
	    "usage: %s [-v] [-f file] [-r directory] [-s socket] "
74
	    "command [argument ...]\n",
75
	    __progname);
76
	exit(1);
77
}
78
79
int
80
compact_db(const char *path)
81
{
82
	struct btree	*bt;
83
	int		 rc;
84
85
	log_info("compacting database %s", path);
86
	bt = btree_open(path, BT_NOSYNC | BT_REVERSEKEY, 0644);
87
	if (bt == NULL)
88
		return -1;
89
90
	do {
91
		if ((rc = btree_compact(bt)) == -1 && errno == EBUSY)
92
			usleep(100000);
93
	} while (rc == -1 && errno == EBUSY);
94
95
	btree_close(bt);
96
	return rc;
97
}
98
99
int
100
compact_namespace(struct namespace *ns, const char *datadir)
101
{
102
	char		*path;
103
104
	if (asprintf(&path, "%s/%s_data.db", datadir, ns->suffix) < 0)
105
		return -1;
106
	if (compact_db(path) != 0) {
107
		log_warn("%s", path);
108
		free(path);
109
		return -1;
110
	}
111
	free(path);
112
113
	if (asprintf(&path, "%s/%s_indx.db", datadir, ns->suffix) < 0)
114
		return -1;
115
	if (compact_db(path) != 0) {
116
		log_warn("%s", path);
117
		free(path);
118
		return -1;
119
	}
120
	free(path);
121
122
	return 0;
123
}
124
125
int
126
compact_namespaces(const char *datadir)
127
{
128
	struct namespace	*ns;
129
130
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
131
		if (SLIST_EMPTY(&ns->referrals))
132
		    continue;
133
		if (compact_namespace(ns, datadir) != 0)
134
			return -1;
135
	}
136
137
	return 0;
138
}
139
140
int
141
index_namespace(struct namespace *ns, const char *datadir)
142
{
143
	struct btval		 key, val;
144
	struct btree		*data_db, *indx_db;
145
	struct cursor		*cursor;
146
	struct ber_element	*elm;
147
	char			*path;
148
	long long int		 ncomplete = 0;
149
	int			 i, rc;
150
151
	log_info("indexing namespace %s", ns->suffix);
152
153
	if (asprintf(&path, "%s/%s_data.db", DATADIR, ns->suffix) < 0)
154
		return -1;
155
	data_db = btree_open(path, BT_NOSYNC | BT_REVERSEKEY, 0644);
156
	free(path);
157
	if (data_db == NULL)
158
		return -1;
159
160
	if (asprintf(&path, "%s/%s_indx.db", datadir, ns->suffix) < 0)
161
		return -1;
162
	indx_db = btree_open(path, BT_NOSYNC, 0644);
163
	free(path);
164
	if (indx_db == NULL) {
165
		btree_close(data_db);
166
		return -1;
167
	}
168
169
	if ((cursor = btree_cursor_open(data_db)) == NULL) {
170
		btree_close(data_db);
171
		btree_close(indx_db);
172
		return -1;
173
	}
174
175
	bzero(&key, sizeof(key));
176
	bzero(&val, sizeof(val));
177
178
	for (;;) {
179
		for (;;) {
180
			ns->indx_txn = btree_txn_begin(indx_db, 0);
181
			if (ns->indx_txn == NULL && errno == EBUSY)
182
				usleep(100000);
183
			else
184
				break;
185
		}
186
187
		if (ns->indx_txn == NULL) {
188
			log_warn("failed to start transaction");
189
			break;
190
		}
191
192
		for (i = 0; i < 100; i++) {
193
			rc = btree_cursor_get(cursor, &key, &val, BT_NEXT);
194
			if (rc != BT_SUCCESS)
195
				break;
196
			if ((elm = db2ber(&val, ns->compression_level)) == NULL)
197
				continue;
198
			rc = index_entry(ns, &key, elm);
199
			ber_free_elements(elm);
200
			btval_reset(&key);
201
			btval_reset(&val);
202
			if (rc != 0)
203
				break;
204
			++ncomplete;
205
		}
206
207
		if (btree_txn_commit(ns->indx_txn) != BT_SUCCESS)
208
			break;
209
210
		if (i != 100)
211
			break;
212
	}
213
214
	btree_cursor_close(cursor);
215
	btree_close(data_db);
216
	btree_close(indx_db);
217
218
	return 0;
219
}
220
221
int
222
index_namespaces(const char *datadir)
223
{
224
	struct namespace	*ns;
225
226
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
227
		if (SLIST_EMPTY(&ns->referrals))
228
			continue;
229
		if (index_namespace(ns, datadir) != 0)
230
			return -1;
231
	}
232
233
	return 0;
234
}
235
236
int
237
ssl_load_certfile(struct ldapd_config *env, const char *name, u_int8_t flags)
238
{
239
	return 0;
240
}
241
242
int
243
main(int argc, char *argv[])
244
{
245
	int			 ctl_sock;
246
	int			 done = 0, verbose = 0;
247
	ssize_t			 n;
248
	int			 ch;
249
	enum action		 action = NONE;
250
	const char		*datadir = DATADIR;
251
	struct stat		 sb;
252
	const char		*sock = LDAPD_SOCKET;
253
	char			*conffile = CONFFILE;
254
	struct sockaddr_un	 sun;
255
	struct imsg		 imsg;
256
	struct imsgbuf		 ibuf;
257
258
	log_init(1);
259
260
	while ((ch = getopt(argc, argv, "f:r:s:v")) != -1) {
261
		switch (ch) {
262
		case 'f':
263
			conffile = optarg;
264
			break;
265
		case 'r':
266
			datadir = optarg;
267
			break;
268
		case 's':
269
			sock = optarg;
270
			break;
271
		case 'v':
272
			verbose = 1;
273
			break;
274
		default:
275
			usage();
276
			/* NOTREACHED */
277
		}
278
	}
279
	argc -= optind;
280
	argv += optind;
281
282
	if (argc == 0)
283
		usage();
284
285
	if (stat(datadir, &sb) == -1)
286
		err(1, "%s", datadir);
287
	if (!S_ISDIR(sb.st_mode))
288
		errx(1, "%s is not a directory", datadir);
289
290
	log_verbose(verbose);
291
292
	if (strcmp(argv[0], "stats") == 0)
293
		action = SHOW_STATS;
294
	else if (strcmp(argv[0], "compact") == 0)
295
		action = COMPACT_DB;
296
	else if (strcmp(argv[0], "index") == 0)
297
		action = INDEX_DB;
298
	else if (strcmp(argv[0], "log") == 0) {
299
		if (argc != 2)
300
			usage();
301
		if (strcmp(argv[1], "verbose") == 0)
302
			action = LOG_VERBOSE;
303
		else if (strcmp(argv[1], "brief") == 0)
304
			action = LOG_BRIEF;
305
		else
306
			usage();
307
	} else
308
		usage();
309
310
	if (action == COMPACT_DB || action == INDEX_DB) {
311
		if (parse_config(conffile) != 0)
312
			exit(2);
313
314
		if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
315
			err(1, "pledge");
316
317
		if (action == COMPACT_DB)
318
			return compact_namespaces(datadir);
319
		else
320
			return index_namespaces(datadir);
321
	}
322
323
	/* connect to ldapd control socket */
324
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
325
		err(1, "socket");
326
327
	bzero(&sun, sizeof(sun));
328
	sun.sun_family = AF_UNIX;
329
	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
330
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
331
		err(1, "connect: %s", sock);
332
333
	imsg_init(&ibuf, ctl_sock);
334
	done = 0;
335
336
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
337
		err(1, "pledge");
338
339
	/* process user request */
340
	switch (action) {
341
	case SHOW_STATS:
342
		imsg_compose(&ibuf, IMSG_CTL_STATS, 0, 0, -1, NULL, 0);
343
		break;
344
	case LOG_VERBOSE:
345
		verbose = 1;
346
		/* FALLTHROUGH */
347
	case LOG_BRIEF:
348
		imsg_compose(&ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
349
		    &verbose, sizeof(verbose));
350
		printf("logging request sent.\n");
351
		done = 1;
352
		break;
353
	case NONE:
354
		break;
355
	case COMPACT_DB:
356
	case INDEX_DB:
357
		fatal("internal error");
358
	}
359
360
	while (ibuf.w.queued)
361
		if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN)
362
			err(1, "write error");
363
364
	while (!done) {
365
		if ((n = imsg_read(&ibuf)) == -1 && errno != EAGAIN)
366
			errx(1, "imsg_read error");
367
		if (n == 0)
368
			errx(1, "pipe closed");
369
370
		while (!done) {
371
			if ((n = imsg_get(&ibuf, &imsg)) == -1)
372
				errx(1, "imsg_get error");
373
			if (n == 0)
374
				break;
375
			switch (imsg.hdr.type) {
376
			case IMSG_CTL_STATS:
377
				show_stats(&imsg);
378
				break;
379
			case IMSG_CTL_NSSTATS:
380
				show_nsstats(&imsg);
381
				break;
382
			case IMSG_CTL_END:
383
				done = 1;
384
				break;
385
			case NONE:
386
				break;
387
			}
388
			imsg_free(&imsg);
389
		}
390
	}
391
	close(ctl_sock);
392
393
	return (0);
394
}
395
396
void
397
show_stats(struct imsg *imsg)
398
{
399
	struct ldapd_stats	*st;
400
401
	st = imsg->data;
402
403
	printf("start time: %s", ctime(&st->started_at));
404
	printf("requests: %llu\n", st->requests);
405
	printf("search requests: %llu\n", st->req_search);
406
	printf("bind requests: %llu\n", st->req_bind);
407
	printf("modify requests: %llu\n", st->req_mod);
408
	printf("timeouts: %llu\n", st->timeouts);
409
	printf("unindexed searches: %llu\n", st->unindexed);
410
	printf("active connections: %u\n", st->conns);
411
	printf("active searches: %u\n", st->searches);
412
}
413
414
#define ZDIV(t,n)	((n) == 0 ? 0 : (float)(t) / (n))
415
416
void
417
show_dbstats(const char *prefix, struct btree_stat *st)
418
{
419
	printf("%s timestamp: %s", prefix, ctime(&st->created_at));
420
	printf("%s page size: %u\n", prefix, st->psize);
421
	printf("%s depth: %u\n", prefix, st->depth);
422
	printf("%s revisions: %u\n", prefix, st->revisions);
423
	printf("%s entries: %llu\n", prefix, st->entries);
424
	printf("%s branch/leaf/overflow pages: %u/%u/%u\n",
425
	    prefix, st->branch_pages, st->leaf_pages, st->overflow_pages);
426
427
	printf("%s cache size: %u of %u (%.1f%% full)\n", prefix,
428
	    st->cache_size, st->max_cache,
429
	    100 * ZDIV(st->cache_size, st->max_cache));
430
	printf("%s page reads: %llu\n", prefix, st->reads);
431
	printf("%s cache hits: %llu (%.1f%%)\n", prefix, st->hits,
432
	    100 * ZDIV(st->hits, (st->hits + st->reads)));
433
}
434
435
void
436
show_nsstats(struct imsg *imsg)
437
{
438
	struct ns_stat		*nss;
439
440
	nss = imsg->data;
441
442
	printf("\nsuffix: %s\n", nss->suffix);
443
	show_dbstats("data", &nss->data_stat);
444
	show_dbstats("indx", &nss->indx_stat);
445
}
446