GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../table_db.c Lines: 0 85 0.0 %
Date: 2017-11-13 Branches: 0 40 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: table_db.c,v 1.9 2015/11/24 07:40:26 gilles Exp $	*/
2
3
/*
4
 * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <sys/queue.h>
22
#include <sys/tree.h>
23
#include <sys/socket.h>
24
25
#include <netinet/in.h>
26
#include <arpa/inet.h>
27
28
#include <db.h>
29
#include <ctype.h>
30
#include <err.h>
31
#include <event.h>
32
#include <fcntl.h>
33
#include <imsg.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "smtpd.h"
39
#include "log.h"
40
41
42
/* db(3) backend */
43
static int table_db_config(struct table *);
44
static int table_db_update(struct table *);
45
static void *table_db_open(struct table *);
46
static int table_db_lookup(void *, struct dict *, const char *, enum table_service, union lookup *);
47
static int table_db_fetch(void *, struct dict *, enum table_service, union lookup *);
48
static void  table_db_close(void *);
49
50
static char *table_db_get_entry(void *, const char *, size_t *);
51
static char *table_db_get_entry_match(void *, const char *, size_t *,
52
    int(*)(const char *, const char *));
53
54
struct table_backend table_backend_db = {
55
	K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE|K_MAILADDR|K_ADDRNAME|K_MAILADDRMAP,
56
	table_db_config,
57
	table_db_open,
58
	table_db_update,
59
	table_db_close,
60
	table_db_lookup,
61
	table_db_fetch,
62
};
63
64
static struct keycmp {
65
	enum table_service	service;
66
	int		       (*func)(const char *, const char *);
67
} keycmp[] = {
68
	{ K_DOMAIN, table_domain_match },
69
	{ K_NETADDR, table_netaddr_match },
70
	{ K_MAILADDR, table_mailaddr_match }
71
};
72
73
struct dbhandle {
74
	DB		*db;
75
	char		 pathname[PATH_MAX];
76
	time_t		 mtime;
77
	struct table	*table;
78
};
79
80
static int
81
table_db_config(struct table *table)
82
{
83
	struct dbhandle	       *handle;
84
85
	handle = table_db_open(table);
86
	if (handle == NULL)
87
		return 0;
88
89
	table_db_close(handle);
90
	return 1;
91
}
92
93
static int
94
table_db_update(struct table *table)
95
{
96
	struct dbhandle	*handle;
97
98
	handle = table_db_open(table);
99
	if (handle == NULL)
100
		return 0;
101
102
	table_db_close(table->t_handle);
103
	table->t_handle = handle;
104
	return 1;
105
}
106
107
static void *
108
table_db_open(struct table *table)
109
{
110
	struct dbhandle	       *handle;
111
	struct stat		sb;
112
113
	handle = xcalloc(1, sizeof *handle, "table_db_open");
114
	if (strlcpy(handle->pathname, table->t_config, sizeof handle->pathname)
115
	    >= sizeof handle->pathname)
116
		goto error;
117
118
	if (stat(handle->pathname, &sb) < 0)
119
		goto error;
120
121
	handle->mtime = sb.st_mtime;
122
	handle->db = dbopen(table->t_config, O_RDONLY, 0600, DB_HASH, NULL);
123
	if (handle->db == NULL)
124
		goto error;
125
	handle->table = table;
126
127
	return handle;
128
129
error:
130
	if (handle->db)
131
		handle->db->close(handle->db);
132
	free(handle);
133
	return NULL;
134
}
135
136
static void
137
table_db_close(void *hdl)
138
{
139
	struct dbhandle	*handle = hdl;
140
	handle->db->close(handle->db);
141
	free(handle);
142
}
143
144
static int
145
table_db_lookup(void *hdl, struct dict *params, const char *key, enum table_service service,
146
    union lookup *lk)
147
{
148
	struct dbhandle	*handle = hdl;
149
	struct table	*table = NULL;
150
	char	       *line;
151
	size_t		len = 0;
152
	int		ret;
153
	int	       (*match)(const char *, const char *) = NULL;
154
	size_t		i;
155
	struct stat	sb;
156
157
	if (stat(handle->pathname, &sb) < 0)
158
		return -1;
159
160
	/* DB has changed, close and reopen */
161
	if (sb.st_mtime != handle->mtime) {
162
		table = handle->table;
163
		table_db_update(handle->table);
164
		handle = table->t_handle;
165
	}
166
167
	for (i = 0; i < nitems(keycmp); ++i)
168
		if (keycmp[i].service == service)
169
			match = keycmp[i].func;
170
171
	if (match == NULL)
172
		line = table_db_get_entry(handle, key, &len);
173
	else
174
		line = table_db_get_entry_match(handle, key, &len, match);
175
	if (line == NULL)
176
		return 0;
177
178
	ret = 1;
179
	if (lk)
180
		ret = table_parse_lookup(service, key, line, lk);
181
	free(line);
182
183
	return ret;
184
}
185
186
static int
187
table_db_fetch(void *hdl, struct dict *params, enum table_service service, union lookup *lk)
188
{
189
	struct dbhandle	*handle = hdl;
190
	struct table	*table  = handle->table;
191
	DBT dbk;
192
	DBT dbd;
193
	int r;
194
195
	if (table->t_iter == NULL)
196
		r = handle->db->seq(handle->db, &dbk, &dbd, R_FIRST);
197
	else
198
		r = handle->db->seq(handle->db, &dbk, &dbd, R_NEXT);
199
	table->t_iter = handle->db;
200
	if (!r) {
201
		r = handle->db->seq(handle->db, &dbk, &dbd, R_FIRST);
202
		if (!r)
203
			return 0;
204
	}
205
206
	return table_parse_lookup(service, NULL, dbk.data, lk);
207
}
208
209
210
static char *
211
table_db_get_entry_match(void *hdl, const char *key, size_t *len,
212
    int(*func)(const char *, const char *))
213
{
214
	struct dbhandle	*handle = hdl;
215
	DBT dbk;
216
	DBT dbd;
217
	int r;
218
	char *buf = NULL;
219
220
	for (r = handle->db->seq(handle->db, &dbk, &dbd, R_FIRST); !r;
221
	     r = handle->db->seq(handle->db, &dbk, &dbd, R_NEXT)) {
222
		buf = xmemdup(dbk.data, dbk.size, "table_db_get_entry_cmp");
223
		if (func(key, buf)) {
224
			*len = dbk.size;
225
			return buf;
226
		}
227
		free(buf);
228
	}
229
	return NULL;
230
}
231
232
static char *
233
table_db_get_entry(void *hdl, const char *key, size_t *len)
234
{
235
	struct dbhandle	*handle = hdl;
236
	int ret;
237
	DBT dbk;
238
	DBT dbv;
239
	char pkey[LINE_MAX];
240
241
	/* workaround the stupidity of the DB interface */
242
	if (strlcpy(pkey, key, sizeof pkey) >= sizeof pkey)
243
		errx(1, "table_db_get_entry: key too long");
244
	dbk.data = pkey;
245
	dbk.size = strlen(pkey) + 1;
246
247
	if ((ret = handle->db->get(handle->db, &dbk, &dbv, 0)) != 0)
248
		return NULL;
249
250
	*len = dbv.size;
251
252
	return xmemdup(dbv.data, dbv.size, "table_db_get_entry");
253
}