1 /*
2 * ProFTPD - mod_snmp database storage
3 * Copyright (c) 2008-2017 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_snmp.h"
26 #include "db.h"
27 #include "uptime.h"
28
29 /* On some platforms, this may not be defined. On AIX, for example, this
30 * symbol is only defined when _NO_PROTO is defined, and _XOPEN_SOURCE is 500.
31 * How annoying.
32 */
33 #ifndef MAP_FAILED
34 # define MAP_FAILED ((void *) -1)
35 #endif
36
37 #define SNMP_MAX_LOCK_ATTEMPTS 10
38
39 /* Note: Not all database IDs are in this list; only those databases which
40 * have on-disk tables are here. Thus the NOTIFY and CONN database IDs are
41 * explicitly NOT here, as they are ephemeral/synthetic databases anyway.
42 */
43 int snmp_table_ids[] = {
44 SNMP_DB_ID_DAEMON,
45 SNMP_DB_ID_TIMEOUTS,
46 SNMP_DB_ID_FTP,
47 SNMP_DB_ID_SNMP,
48 SNMP_DB_ID_TLS,
49 SNMP_DB_ID_SSH,
50 SNMP_DB_ID_SFTP,
51 SNMP_DB_ID_SCP,
52 SNMP_DB_ID_BAN,
53
54 /* XXX Not supported just yet */
55 #if 0
56 SNMP_DB_ID_SQL,
57 SNMP_DB_ID_QUOTA,
58 SNMP_DB_ID_GEOIP,
59 #endif
60
61 SNMP_DB_ID_UNKNOWN
62 };
63
64 static const char *snmp_db_root = NULL;
65
66 static const char *trace_channel = "snmp.db";
67
68 struct snmp_field_info {
69 unsigned int field;
70 int db_id;
71 off_t field_start;
72 size_t field_len;
73 const char *field_name;
74 };
75
76 static struct snmp_field_info snmp_fields[] = {
77
78 /* Miscellaneous SNMP-related fields */
79 { SNMP_DB_NOTIFY_F_SYS_UPTIME, SNMP_DB_ID_NOTIFY, 0,
80 0, "NOTIFY_F_SYS_UPTIME" },
81
82 /* Connection fields */
83 { SNMP_DB_CONN_F_SERVER_NAME, SNMP_DB_ID_CONN, 0,
84 0, "CONN_F_SERVER_NAME" },
85 { SNMP_DB_CONN_F_SERVER_ADDR, SNMP_DB_ID_CONN, 0,
86 0, "CONN_F_SERVER_ADDR" },
87 { SNMP_DB_CONN_F_SERVER_PORT, SNMP_DB_ID_CONN, 0,
88 0, "CONN_F_SERVER_PORT" },
89 { SNMP_DB_CONN_F_CLIENT_ADDR, SNMP_DB_ID_CONN, 0,
90 0, "CONN_F_CLIENT_ADDR" },
91 { SNMP_DB_CONN_F_PID, SNMP_DB_ID_CONN, 0,
92 0, "CONN_F_PID" },
93 { SNMP_DB_CONN_F_USER_NAME, SNMP_DB_ID_CONN, 0,
94 0, "CONN_F_USER_NAME" },
95 { SNMP_DB_CONN_F_PROTOCOL, SNMP_DB_ID_CONN, 0,
96 0, "CONN_F_PROTOCOL" },
97
98 /* Daemon fields */
99 { SNMP_DB_DAEMON_F_SOFTWARE, SNMP_DB_ID_DAEMON, 0,
100 0, "DAEMON_F_SOFTWARE" },
101 { SNMP_DB_DAEMON_F_VERSION, SNMP_DB_ID_DAEMON, 0,
102 0, "DAEMON_F_VERSION" },
103 { SNMP_DB_DAEMON_F_ADMIN, SNMP_DB_ID_DAEMON, 0,
104 0, "DAEMON_F_ADMIN" },
105 { SNMP_DB_DAEMON_F_UPTIME, SNMP_DB_ID_DAEMON, 0,
106 0, "DAEMON_F_UPTIME" },
107 { SNMP_DB_DAEMON_F_VHOST_COUNT, SNMP_DB_ID_DAEMON, 0,
108 sizeof(uint32_t), "DAEMON_F_VHOST_COUNT" },
109 { SNMP_DB_DAEMON_F_CONN_COUNT, SNMP_DB_ID_DAEMON, 4,
110 sizeof(uint32_t), "DAEMON_F_CONN_COUNT" },
111 { SNMP_DB_DAEMON_F_CONN_TOTAL, SNMP_DB_ID_DAEMON, 8,
112 sizeof(uint32_t), "DAEMON_F_CONN_TOTAL" },
113 { SNMP_DB_DAEMON_F_CONN_REFUSED_TOTAL, SNMP_DB_ID_DAEMON, 12,
114 sizeof(uint32_t), "DAEMON_F_CONN_REFUSED_TOTAL" },
115 { SNMP_DB_DAEMON_F_RESTART_COUNT, SNMP_DB_ID_DAEMON, 16,
116 sizeof(uint32_t), "DAEMON_F_RESTART_COUNT" },
117 { SNMP_DB_DAEMON_F_SEGFAULT_COUNT, SNMP_DB_ID_DAEMON, 20,
118 sizeof(uint32_t), "DAEMON_F_SEGFAULT_COUNT" },
119 { SNMP_DB_DAEMON_F_MAXINST_TOTAL, SNMP_DB_ID_DAEMON, 24,
120 sizeof(uint32_t), "DAEMON_F_MAXINST_TOTAL" },
121 { SNMP_DB_DAEMON_F_MAXINST_CONF, SNMP_DB_ID_DAEMON, 28,
122 sizeof(uint32_t), "DAEMON_F_MAXINST_CONF" },
123
124 /* timeouts fields */
125 { SNMP_DB_TIMEOUTS_F_IDLE_TOTAL, SNMP_DB_ID_TIMEOUTS, 0,
126 sizeof(uint32_t), "TIMEOUTS_F_IDLE_TOTAL" },
127 { SNMP_DB_TIMEOUTS_F_LOGIN_TOTAL, SNMP_DB_ID_TIMEOUTS, 4,
128 sizeof(uint32_t), "TIMEOUTS_F_LOGIN_TOTAL" },
129 { SNMP_DB_TIMEOUTS_F_NOXFER_TOTAL, SNMP_DB_ID_TIMEOUTS, 8,
130 sizeof(uint32_t), "TIMEOUTS_F_NOXFER_TOTAL" },
131 { SNMP_DB_TIMEOUTS_F_STALLED_TOTAL, SNMP_DB_ID_TIMEOUTS, 12,
132 sizeof(uint32_t), "TIMEOUTS_F_STALLED_TOTAL" },
133
134 /* ftp.sessions fields */
135 { SNMP_DB_FTP_SESS_F_SESS_COUNT, SNMP_DB_ID_FTP, 0,
136 sizeof(uint32_t), "FTP_SESS_F_SESS_COUNT" },
137 { SNMP_DB_FTP_SESS_F_SESS_TOTAL, SNMP_DB_ID_FTP, 4,
138 sizeof(uint32_t), "FTP_SESS_F_SESS_TOTAL" },
139 { SNMP_DB_FTP_SESS_F_CMD_INVALID_TOTAL, SNMP_DB_ID_FTP, 8,
140 sizeof(uint32_t), "FTP_SESS_F_CMD_INVALID_TOTAL" },
141
142 /* ftp.logins fields */
143 { SNMP_DB_FTP_LOGINS_F_TOTAL, SNMP_DB_ID_FTP, 12,
144 sizeof(uint32_t), "FTP_LOGINS_F_TOTAL" },
145 { SNMP_DB_FTP_LOGINS_F_ERR_TOTAL, SNMP_DB_ID_FTP, 16,
146 sizeof(uint32_t), "FTP_LOGINS_F_ERR_TOTAL" },
147 { SNMP_DB_FTP_LOGINS_F_ERR_BAD_USER_TOTAL, SNMP_DB_ID_FTP, 20,
148 sizeof(uint32_t), "FTP_LOGINS_F_ERR_BAD_USER_TOTAL" },
149 { SNMP_DB_FTP_LOGINS_F_ERR_BAD_PASSWD_TOTAL, SNMP_DB_ID_FTP, 24,
150 sizeof(uint32_t), "FTP_LOGINS_F_ERR_BAD_PASSWD_TOTAL" },
151 { SNMP_DB_FTP_LOGINS_F_ERR_GENERAL_TOTAL, SNMP_DB_ID_FTP, 28,
152 sizeof(uint32_t), "FTP_LOGINS_F_ERR_GENERAL_TOTAL" },
153 { SNMP_DB_FTP_LOGINS_F_ANON_COUNT, SNMP_DB_ID_FTP, 32,
154 sizeof(uint32_t), "FTP_LOGINS_F_ANON_COUNT" },
155 { SNMP_DB_FTP_LOGINS_F_ANON_TOTAL, SNMP_DB_ID_FTP, 36,
156 sizeof(uint32_t), "FTP_LOGINS_F_ANON_TOTAL" },
157
158 /* ftp.dataTransfers fields */
159 { SNMP_DB_FTP_XFERS_F_DIR_LIST_COUNT, SNMP_DB_ID_FTP, 40,
160 sizeof(uint32_t), "FTP_XFERS_F_DIR_LIST_COUNT" },
161 { SNMP_DB_FTP_XFERS_F_DIR_LIST_TOTAL, SNMP_DB_ID_FTP, 44,
162 sizeof(uint32_t), "FTP_XFERS_F_DIR_LIST_TOTAL" },
163 { SNMP_DB_FTP_XFERS_F_DIR_LIST_ERR_TOTAL, SNMP_DB_ID_FTP, 48,
164 sizeof(uint32_t), "FTP_XFERS_F_DIR_LIST_ERR_TOTAL" },
165 { SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_COUNT, SNMP_DB_ID_FTP, 52,
166 sizeof(uint32_t), "FTP_XFERS_F_FILE_UPLOAD_COUNT" },
167 { SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_TOTAL, SNMP_DB_ID_FTP, 56,
168 sizeof(uint32_t), "FTP_XFERS_F_FILE_UPLOAD_TOTAL" },
169 { SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, SNMP_DB_ID_FTP, 60,
170 sizeof(uint32_t), "FTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL" },
171 { SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_COUNT, SNMP_DB_ID_FTP, 64,
172 sizeof(uint32_t), "FTP_XFERS_F_FILE_DOWNLOAD_COUNT" },
173 { SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_TOTAL, SNMP_DB_ID_FTP, 68,
174 sizeof(uint32_t), "FTP_XFERS_F_FILE_DOWNLOAD_TOTAL" },
175 { SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, SNMP_DB_ID_FTP, 72,
176 sizeof(uint32_t), "FTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL" },
177 { SNMP_DB_FTP_XFERS_F_KB_UPLOAD_TOTAL, SNMP_DB_ID_FTP, 76,
178 sizeof(uint32_t), "FTP_XFERS_F_KB_UPLOAD_TOTAL" },
179 { SNMP_DB_FTP_XFERS_F_KB_DOWNLOAD_TOTAL, SNMP_DB_ID_FTP, 80,
180 sizeof(uint32_t), "FTP_XFERS_F_KB_DOWNLOAD_TOTAL" },
181
182 /* snmp fields */
183 { SNMP_DB_SNMP_F_PKTS_RECVD_TOTAL, SNMP_DB_ID_SNMP, 0,
184 sizeof(uint32_t), "SNMP_F_PKTS_RECVD_TOTAL" },
185 { SNMP_DB_SNMP_F_PKTS_SENT_TOTAL, SNMP_DB_ID_SNMP, 4,
186 sizeof(uint32_t), "SNMP_F_PKTS_SENT_TOTAL" },
187 { SNMP_DB_SNMP_F_TRAPS_SENT_TOTAL, SNMP_DB_ID_SNMP, 8,
188 sizeof(uint32_t), "SNMP_F_TRAPS_SENT_TOTAL" },
189 { SNMP_DB_SNMP_F_PKTS_AUTH_ERR_TOTAL, SNMP_DB_ID_SNMP, 12,
190 sizeof(uint32_t), "SNMP_F_PKTS_AUTH_ERR_TOTAL" },
191 { SNMP_DB_SNMP_F_PKTS_DROPPED_TOTAL, SNMP_DB_ID_SNMP, 16,
192 sizeof(uint32_t), "SNMP_F_PKTS_DROPPED_TOTAL" },
193
194 /* ftps.tlsSessions fields */
195 { SNMP_DB_FTPS_SESS_F_SESS_COUNT, SNMP_DB_ID_TLS, 0,
196 sizeof(uint32_t), "FTPS_SESS_F_SESS_COUNT" },
197 { SNMP_DB_FTPS_SESS_F_SESS_TOTAL, SNMP_DB_ID_TLS, 4,
198 sizeof(uint32_t), "FTPS_SESS_F_SESS_TOTAL" },
199 { SNMP_DB_FTPS_SESS_F_CTRL_HANDSHAKE_ERR_TOTAL, SNMP_DB_ID_TLS, 8,
200 sizeof(uint32_t), "FTPS_SESS_F_CTRL_HANDSHAKE_ERR_TOTAL" },
201 { SNMP_DB_FTPS_SESS_F_DATA_HANDSHAKE_ERR_TOTAL, SNMP_DB_ID_TLS, 12,
202 sizeof(uint32_t), "FTPS_SESS_F_DATA_HANDSHAKE_ERR_TOTAL" },
203 { SNMP_DB_FTPS_SESS_F_CCC_TOTAL, SNMP_DB_ID_TLS, 16,
204 sizeof(uint32_t), "FTPS_SESS_F_CCC_TOTAL" },
205 { SNMP_DB_FTPS_SESS_F_CCC_ERR_TOTAL, SNMP_DB_ID_TLS, 20,
206 sizeof(uint32_t), "FTPS_SESS_F_CCC_ERR_TOTAL" },
207 { SNMP_DB_FTPS_SESS_F_VERIFY_CLIENT_TOTAL, SNMP_DB_ID_TLS, 24,
208 sizeof(uint32_t), "FTPS_SESS_F_VERIFY_CLIENT_TOTAL" },
209 { SNMP_DB_FTPS_SESS_F_VERIFY_CLIENT_ERR_TOTAL, SNMP_DB_ID_TLS, 28,
210 sizeof(uint32_t), "FTPS_SESS_F_VERIFY_CLIENT_ERR_TOTAL" },
211
212 /* ftps.tlsLogins fields */
213 { SNMP_DB_FTPS_LOGINS_F_TOTAL, SNMP_DB_ID_TLS, 32,
214 sizeof(uint32_t), "FTPS_LOGINS_F_TOTAL" },
215 { SNMP_DB_FTPS_LOGINS_F_ERR_TOTAL, SNMP_DB_ID_TLS, 36,
216 sizeof(uint32_t), "FTPS_LOGINS_F_ERR_TOTAL" },
217 { SNMP_DB_FTPS_LOGINS_F_ERR_BAD_USER_TOTAL, SNMP_DB_ID_TLS, 40,
218 sizeof(uint32_t), "FTPS_LOGINS_F_ERR_BAD_USER_TOTAL" },
219 { SNMP_DB_FTPS_LOGINS_F_ERR_BAD_PASSWD_TOTAL, SNMP_DB_ID_TLS, 44,
220 sizeof(uint32_t), "FTPS_LOGINS_F_ERR_BAD_PASSWD_TOTAL" },
221 { SNMP_DB_FTPS_LOGINS_F_ERR_GENERAL_TOTAL, SNMP_DB_ID_TLS, 48,
222 sizeof(uint32_t), "FTPS_LOGINS_F_ERR_GENERAL_TOTAL" },
223 { SNMP_DB_FTPS_LOGINS_F_CERT_TOTAL, SNMP_DB_ID_TLS, 52,
224 sizeof(uint32_t), "FTPS_LOGINS_F_CERT_TOTAL" },
225
226 /* ftps.tlsDataTransfers fields */
227 { SNMP_DB_FTPS_XFERS_F_DIR_LIST_COUNT, SNMP_DB_ID_TLS, 56,
228 sizeof(uint32_t), "FTPS_XFERS_F_DIR_LIST_COUNT" },
229 { SNMP_DB_FTPS_XFERS_F_DIR_LIST_TOTAL, SNMP_DB_ID_TLS, 60,
230 sizeof(uint32_t), "FTPS_XFERS_F_DIR_LIST_TOTAL" },
231 { SNMP_DB_FTPS_XFERS_F_DIR_LIST_ERR_TOTAL, SNMP_DB_ID_TLS, 64,
232 sizeof(uint32_t), "FTPS_XFERS_F_DIR_LIST_ERR_TOTAL" },
233 { SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_COUNT, SNMP_DB_ID_TLS, 68,
234 sizeof(uint32_t), "FTPS_XFERS_F_FILE_UPLOAD_COUNT" },
235 { SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_TOTAL, SNMP_DB_ID_TLS, 72,
236 sizeof(uint32_t), "FTPS_XFERS_F_FILE_UPLOAD_TOTAL" },
237 { SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_ERR_TOTAL, SNMP_DB_ID_TLS, 76,
238 sizeof(uint32_t), "FTPS_XFERS_F_FILE_UPLOAD_ERR_TOTAL" },
239 { SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_COUNT, SNMP_DB_ID_TLS, 80,
240 sizeof(uint32_t), "FTPS_XFERS_F_FILE_DOWNLOAD_COUNT" },
241 { SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_TOTAL, SNMP_DB_ID_TLS, 84,
242 sizeof(uint32_t), "FTPS_XFERS_F_FILE_DOWNLOAD_TOTAL" },
243 { SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, SNMP_DB_ID_TLS, 88,
244 sizeof(uint32_t), "FTPS_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL" },
245 { SNMP_DB_FTPS_XFERS_F_KB_UPLOAD_TOTAL, SNMP_DB_ID_TLS, 92,
246 sizeof(uint32_t), "FTPS_XFERS_F_KB_UPLOAD_TOTAL" },
247 { SNMP_DB_FTPS_XFERS_F_KB_DOWNLOAD_TOTAL, SNMP_DB_ID_TLS, 96,
248 sizeof(uint32_t), "FTPS_XFERS_F_KB_DOWNLOAD_TOTAL" },
249
250 /* ssh.sshSessions fields */
251 { SNMP_DB_SSH_SESS_F_KEX_ERR_TOTAL, SNMP_DB_ID_SSH, 0,
252 sizeof(uint32_t), "SSH_SESS_F_KEX_ERR_TOTAL" },
253 { SNMP_DB_SSH_SESS_F_C2S_COMPRESS_TOTAL, SNMP_DB_ID_SSH, 4,
254 sizeof(uint32_t), "SSH_SESS_F_C2S_COMPRESS_TOTAL" },
255 { SNMP_DB_SSH_SESS_F_S2C_COMPRESS_TOTAL, SNMP_DB_ID_SSH, 8,
256 sizeof(uint32_t), "SSH_SESS_F_S2C_COMPRESS_TOTAL" },
257
258 /* ssh.sshLogins fields */
259 { SNMP_DB_SSH_LOGINS_F_HOSTBASED_TOTAL, SNMP_DB_ID_SSH, 12,
260 sizeof(uint32_t), "SSH_LOGINS_F_HOSTBASED_TOTAL" },
261 { SNMP_DB_SSH_LOGINS_F_HOSTBASED_ERR_TOTAL, SNMP_DB_ID_SSH, 16,
262 sizeof(uint32_t), "SSH_LOGINS_F_HOSTBASED_ERR_TOTAL" },
263 { SNMP_DB_SSH_LOGINS_F_KBDINT_TOTAL, SNMP_DB_ID_SSH, 20,
264 sizeof(uint32_t), "SSH_LOGINS_F_KBDINT_TOTAL" },
265 { SNMP_DB_SSH_LOGINS_F_KBDINT_ERR_TOTAL, SNMP_DB_ID_SSH, 24,
266 sizeof(uint32_t), "SSH_LOGINS_F_KBDINT_ERR_TOTAL" },
267 { SNMP_DB_SSH_LOGINS_F_PASSWD_TOTAL, SNMP_DB_ID_SSH, 28,
268 sizeof(uint32_t), "SSH_LOGINS_F_PASSWD_TOTAL" },
269 { SNMP_DB_SSH_LOGINS_F_PASSWD_ERR_TOTAL, SNMP_DB_ID_SSH, 32,
270 sizeof(uint32_t), "SSH_LOGINS_F_PASSWD_ERR_TOTAL" },
271 { SNMP_DB_SSH_LOGINS_F_PUBLICKEY_TOTAL, SNMP_DB_ID_SSH, 36,
272 sizeof(uint32_t), "SSH_LOGINS_F_PUBLICKEY_TOTAL" },
273 { SNMP_DB_SSH_LOGINS_F_PUBLICKEY_ERR_TOTAL, SNMP_DB_ID_SSH, 40,
274 sizeof(uint32_t), "SSH_LOGINS_F_PUBLICKEY_ERR_TOTAL" },
275
276 /* sftp.sftpSessions fields */
277 { SNMP_DB_SFTP_SESS_F_SESS_COUNT, SNMP_DB_ID_SFTP, 0,
278 sizeof(uint32_t), "SFTP_SESS_F_SESS_COUNT" },
279 { SNMP_DB_SFTP_SESS_F_SESS_TOTAL, SNMP_DB_ID_SFTP, 4,
280 sizeof(uint32_t), "SFTP_SESS_F_SESS_TOTAL" },
281 { SNMP_DB_SFTP_SESS_F_SFTP_V3_TOTAL, SNMP_DB_ID_SFTP, 8,
282 sizeof(uint32_t), "SFTP_SESS_F_SFTP_V3_TOTAL" },
283 { SNMP_DB_SFTP_SESS_F_SFTP_V4_TOTAL, SNMP_DB_ID_SFTP, 12,
284 sizeof(uint32_t), "SFTP_SESS_F_SFTP_V4_TOTAL" },
285 { SNMP_DB_SFTP_SESS_F_SFTP_V5_TOTAL, SNMP_DB_ID_SFTP, 16,
286 sizeof(uint32_t), "SFTP_SESS_F_SFTP_V5_TOTAL" },
287 { SNMP_DB_SFTP_SESS_F_SFTP_V6_TOTAL, SNMP_DB_ID_SFTP, 20,
288 sizeof(uint32_t), "SFTP_SESS_F_SFTP_V6_TOTAL" },
289
290 /* sftp.sftpDataTransfers fields */
291 { SNMP_DB_SFTP_XFERS_F_DIR_LIST_COUNT, SNMP_DB_ID_SFTP, 24,
292 sizeof(uint32_t), "SFTP_XFERS_F_DIR_LIST_COUNT" },
293 { SNMP_DB_SFTP_XFERS_F_DIR_LIST_TOTAL, SNMP_DB_ID_SFTP, 28,
294 sizeof(uint32_t), "SFTP_XFERS_F_DIR_LIST_TOTAL" },
295 { SNMP_DB_SFTP_XFERS_F_DIR_LIST_ERR_TOTAL, SNMP_DB_ID_SFTP, 32,
296 sizeof(uint32_t), "SFTP_XFERS_F_DIR_LIST_ERR_TOTAL" },
297 { SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_COUNT, SNMP_DB_ID_SFTP, 36,
298 sizeof(uint32_t), "SFTP_XFERS_F_FILE_UPLOAD_COUNT" },
299 { SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_TOTAL, SNMP_DB_ID_SFTP, 40,
300 sizeof(uint32_t), "SFTP_XFERS_F_FILE_UPLOAD_TOTAL" },
301 { SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, SNMP_DB_ID_SFTP, 44,
302 sizeof(uint32_t), "SFTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL" },
303 { SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_COUNT, SNMP_DB_ID_SFTP, 48,
304 sizeof(uint32_t), "SFTP_XFERS_F_FILE_DOWNLOAD_COUNT" },
305 { SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_TOTAL, SNMP_DB_ID_SFTP, 52,
306 sizeof(uint32_t), "SFTP_XFERS_F_FILE_DOWNLOAD_TOTAL" },
307 { SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, SNMP_DB_ID_SFTP, 56,
308 sizeof(uint32_t), "SFTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL" },
309 { SNMP_DB_SFTP_XFERS_F_KB_UPLOAD_TOTAL, SNMP_DB_ID_SFTP, 60,
310 sizeof(uint32_t), "SFTP_XFERS_F_KB_UPLOAD_TOTAL" },
311 { SNMP_DB_SFTP_XFERS_F_KB_DOWNLOAD_TOTAL, SNMP_DB_ID_SFTP, 64,
312 sizeof(uint32_t), "SFTP_XFERS_F_KB_DOWNLOAD_TOTAL" },
313
314 /* scp.scpSessions fields */
315 { SNMP_DB_SCP_SESS_F_SESS_COUNT, SNMP_DB_ID_SCP, 0,
316 sizeof(uint32_t), "SCP_SESS_F_SESS_COUNT" },
317 { SNMP_DB_SCP_SESS_F_SESS_TOTAL, SNMP_DB_ID_SCP, 4,
318 sizeof(uint32_t), "SCP_SESS_F_SESS_TOTAL" },
319
320 /* scp.scpDataTransfers fields */
321 { SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_COUNT, SNMP_DB_ID_SCP, 8,
322 sizeof(uint32_t), "SCP_XFERS_F_FILE_UPLOAD_COUNT" },
323 { SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_TOTAL, SNMP_DB_ID_SCP, 12,
324 sizeof(uint32_t), "SCP_XFERS_F_FILE_UPLOAD_TOTAL" },
325 { SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, SNMP_DB_ID_SCP, 16,
326 sizeof(uint32_t), "SCP_XFERS_F_FILE_UPLOAD_ERR_TOTAL" },
327 { SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_COUNT, SNMP_DB_ID_SCP, 20,
328 sizeof(uint32_t), "SCP_XFERS_F_FILE_DOWNLOAD_COUNT" },
329 { SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_TOTAL, SNMP_DB_ID_SCP, 24,
330 sizeof(uint32_t), "SCP_XFERS_F_FILE_DOWNLOAD_TOTAL" },
331 { SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, SNMP_DB_ID_SCP, 28,
332 sizeof(uint32_t), "SCP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL" },
333 { SNMP_DB_SCP_XFERS_F_KB_UPLOAD_TOTAL, SNMP_DB_ID_SCP, 32,
334 sizeof(uint32_t), "SCP_XFERS_F_KB_UPLOAD_TOTAL" },
335 { SNMP_DB_SCP_XFERS_F_KB_DOWNLOAD_TOTAL, SNMP_DB_ID_SCP, 36,
336 sizeof(uint32_t), "SCP_XFERS_F_KB_DOWNLOAD_TOTAL" },
337
338 /* ban.connections fields */
339 { SNMP_DB_BAN_CONNS_F_CONN_BAN_TOTAL, SNMP_DB_ID_BAN, 0,
340 sizeof(uint32_t), "BAN_CONNS_F_CONN_BAN_TOTAL" },
341 { SNMP_DB_BAN_CONNS_F_USER_BAN_TOTAL, SNMP_DB_ID_BAN, 4,
342 sizeof(uint32_t), "BAN_CONNS_F_USER_BAN_TOTAL" },
343 { SNMP_DB_BAN_CONNS_F_HOST_BAN_TOTAL, SNMP_DB_ID_BAN, 8,
344 sizeof(uint32_t), "BAN_CONNS_F_HOST_BAN_TOTAL" },
345 { SNMP_DB_BAN_CONNS_F_CLASS_BAN_TOTAL, SNMP_DB_ID_BAN, 12,
346 sizeof(uint32_t), "BAN_CONNS_F_CLASS_BAN_TOTAL" },
347
348 /* ban.bans fields */
349 { SNMP_DB_BAN_BANS_F_BAN_COUNT, SNMP_DB_ID_BAN, 16,
350 sizeof(uint32_t), "BAN_BANS_F_BAN_COUNT" },
351 { SNMP_DB_BAN_BANS_F_BAN_TOTAL, SNMP_DB_ID_BAN, 20,
352 sizeof(uint32_t), "BAN_BANS_F_BAN_TOTAL" },
353 { SNMP_DB_BAN_BANS_F_USER_BAN_COUNT, SNMP_DB_ID_BAN, 24,
354 sizeof(uint32_t), "BAN_BANS_F_USER_BAN_COUNT" },
355 { SNMP_DB_BAN_BANS_F_USER_BAN_TOTAL, SNMP_DB_ID_BAN, 28,
356 sizeof(uint32_t), "BAN_BANS_F_USER_BAN_TOTAL" },
357 { SNMP_DB_BAN_BANS_F_HOST_BAN_COUNT, SNMP_DB_ID_BAN, 32,
358 sizeof(uint32_t), "BAN_BANS_F_HOST_BAN_COUNT" },
359 { SNMP_DB_BAN_BANS_F_HOST_BAN_TOTAL, SNMP_DB_ID_BAN, 36,
360 sizeof(uint32_t), "BAN_BANS_F_HOST_BAN_TOTAL" },
361 { SNMP_DB_BAN_BANS_F_CLASS_BAN_COUNT, SNMP_DB_ID_BAN, 40,
362 sizeof(uint32_t), "BAN_BANS_F_CLASS_BAN_COUNT" },
363 { SNMP_DB_BAN_BANS_F_CLASS_BAN_TOTAL, SNMP_DB_ID_BAN, 44,
364 sizeof(uint32_t), "BAN_BANS_F_CLASS_BAN_TOTAL" },
365
366 { 0, -1, 0, 0 }
367 };
368
369 struct snmp_db_info {
370 int db_id;
371 int db_fd;
372 const char *db_name;
373 char *db_path;
374 void *db_data;
375 size_t db_datasz;
376 };
377
378 static struct snmp_db_info snmp_dbs[] = {
379 { SNMP_DB_ID_UNKNOWN, -1, NULL, NULL, 0 },
380
381 /* This "table" is synthetic; nothing to be persisted to disk. */
382 { SNMP_DB_ID_NOTIFY, -1, "notify.dat", NULL, NULL, 0 },
383
384 /* This "table" is comprised purely of values in memory; nothing to be
385 * persisted to disk.
386 */
387 { SNMP_DB_ID_CONN, -1, "conn.dat", NULL, NULL, 0 },
388
389 /* Eight numeric fields only in this table: 8 x 4 bytes = 32 bytes */
390 { SNMP_DB_ID_DAEMON, -1, "daemon.dat", NULL, NULL, 32 },
391
392 /* The size of the timeouts table is calculated as:
393 *
394 * 4 timeout fields x 4 bytes = 16 bytes
395 *
396 * for a total of 16 bytes.
397 */
398 { SNMP_DB_ID_TIMEOUTS, -1, "timeouts.dat", NULL, NULL, 16 },
399
400 /* The size of the ftp table is calculated as:
401 *
402 * 3 session fields x 4 bytes = 12 bytes
403 * 7 login fields x 4 bytes = 28 bytes
404 * 11 data transfer fields x 4 bytes = 44 bytes
405 *
406 * for a total of 84 bytes.
407 */
408 { SNMP_DB_ID_FTP, -1, "ftp.dat", NULL, NULL, 84 },
409
410 /* The size of the snmp table is calculated as:
411 *
412 * 4 fields x 4 bytes = 20 bytes
413 */
414 { SNMP_DB_ID_SNMP, -1, "snmp.dat", NULL, NULL, 20 },
415
416 /* The size of the ftps table is calculated as:
417 *
418 * 8 session fields x 4 bytes = 32 bytes
419 * 6 login fields x 4 bytes = 24 bytes
420 * 11 data transfer fields x 4 bytes = 44 bytes
421 *
422 * for a total of 100 bytes.
423 */
424 { SNMP_DB_ID_TLS, -1, "tls.dat", NULL, NULL, 100 },
425
426 /* The size of the ssh table is calculated as:
427 *
428 * 3 session fields x 4 bytes = 12 bytes
429 * 8 auth fields x 4 bytes = 32 bytes
430 *
431 * for a total of 40 bytes.
432 */
433 { SNMP_DB_ID_SSH, -1, "ssh.dat", NULL, NULL, 44 },
434
435 /* The size of the sftp table is calculated as:
436 *
437 * 6 session fields x 4 bytes = 24 bytes
438 * 11 data transfer fields x 4 bytes = 44 bytes
439 *
440 * for a total of 68 bytes.
441 */
442 { SNMP_DB_ID_SFTP, -1, "sftp.dat", NULL, NULL, 68 },
443
444 /* The size of the scp table is calculated as:
445 *
446 * 2 session fields x 4 bytes = 8 bytes
447 * 8 data transfer fields x 4 bytes = 32 bytes
448 *
449 * for a total of 40 bytes.
450 */
451 { SNMP_DB_ID_SCP, -1, "scp.dat", NULL, NULL, 40 },
452
453 /* The size of the ban table is calculated as:
454 *
455 * 12 ban fields x 4 bytes = 48 bytes
456 *
457 * for a total of 48 bytes.
458 */
459 { SNMP_DB_ID_BAN, -1, "ban.dat", NULL, NULL, 48 },
460
461 #if 0
462 { SNMP_DB_ID_SQL, -1, "sql.dat", NULL, NULL, 0 },
463
464 { SNMP_DB_ID_QUOTA, -1, "quota.dat", NULL, NULL, 0 },
465
466 { SNMP_DB_ID_GEOIP, -1, "geoip.dat", NULL, NULL, 0 }
467 #endif
468
469 { -1, -1, NULL, NULL, 0 },
470 };
471
472 /* For the given field, provision the corresponding lock start and len
473 * values, for the byte-range locking.
474 */
get_field_range(unsigned int field,off_t * field_start,size_t * field_len)475 static int get_field_range(unsigned int field, off_t *field_start,
476 size_t *field_len) {
477 register unsigned int i;
478 int field_idx = -1;
479
480 if (field_start == NULL &&
481 field_len == NULL) {
482 /* Nothing to do here. */
483 return 0;
484 }
485
486 for (i = 0; snmp_fields[i].db_id > 0; i++) {
487 if (snmp_fields[i].field == field) {
488 field_idx = i;
489 break;
490 }
491 }
492
493 if (field_idx < 0) {
494 errno = ENOENT;
495 return -1;
496 }
497
498 if (field_start != NULL) {
499 *field_start = snmp_fields[field_idx].field_start;
500 }
501
502 if (field_len != NULL) {
503 *field_len = snmp_fields[field_idx].field_len;
504 }
505
506 return 0;
507 }
508
get_lock_type(struct flock * lock)509 static const char *get_lock_type(struct flock *lock) {
510 const char *lock_type;
511
512 switch (lock->l_type) {
513 case F_RDLCK:
514 lock_type = "read";
515 break;
516
517 case F_WRLCK:
518 lock_type = "write";
519 break;
520
521 case F_UNLCK:
522 lock_type = "unlock";
523 break;
524
525 default:
526 lock_type = "[unknown]";
527 }
528
529 return lock_type;
530 }
531
snmp_db_get_field_db_id(unsigned int field)532 int snmp_db_get_field_db_id(unsigned int field) {
533 register unsigned int i;
534 int db_id = -1;
535
536 for (i = 0; snmp_fields[i].db_id > 0; i++) {
537 if (snmp_fields[i].field == field) {
538 db_id = snmp_fields[i].db_id;
539 break;
540 }
541 }
542
543 if (db_id < 0) {
544 errno = ENOENT;
545 }
546
547 return db_id;
548 }
549
snmp_db_get_fieldstr(pool * p,unsigned int field)550 const char *snmp_db_get_fieldstr(pool *p, unsigned int field) {
551 register unsigned int i;
552 char fieldstr[256];
553 int db_id = -1;
554 const char *db_name = NULL, *field_name = NULL;
555
556 for (i = 0; snmp_fields[i].db_id > 0; i++) {
557 if (snmp_fields[i].field == field) {
558 db_id = snmp_fields[i].db_id;
559 field_name = snmp_fields[i].field_name;
560 break;
561 }
562 }
563
564 if (db_id < 0) {
565 return NULL;
566 }
567
568 db_name = snmp_dbs[db_id].db_name;
569
570 memset(fieldstr, '\0', sizeof(fieldstr));
571 pr_snprintf(fieldstr, sizeof(fieldstr)-1, "%s (%d) [%s (%d)]",
572 field_name, field, db_name, db_id);
573 return pstrdup(p, fieldstr);
574 }
575
snmp_db_rlock(unsigned int field)576 int snmp_db_rlock(unsigned int field) {
577 struct flock lock;
578 unsigned int nattempts = 1;
579 int db_id, db_fd;
580 size_t field_len;
581
582 lock.l_type = F_RDLCK;
583 lock.l_whence = SEEK_SET;
584
585 db_id = snmp_db_get_field_db_id(field);
586 if (db_id < 0) {
587 return -1;
588 }
589
590 db_fd = snmp_dbs[db_id].db_fd;
591 if (get_field_range(field, &(lock.l_start), &field_len) < 0) {
592 return -1;
593 }
594 lock.l_len = (off_t) field_len;
595
596 pr_trace_msg(trace_channel, 9,
597 "attempt #%u to read-lock field %u db ID %d table '%s' "
598 "(fd %d start %lu len %lu)", nattempts, field, db_id,
599 snmp_dbs[db_id].db_path, db_fd, (unsigned long) lock.l_start,
600 (unsigned long) lock.l_len);
601
602 while (fcntl(db_fd, F_SETLK, &lock) < 0) {
603 int xerrno = errno;
604
605 if (xerrno == EINTR) {
606 pr_signals_handle();
607 continue;
608 }
609
610 pr_trace_msg(trace_channel, 3, "read-lock of table fd %d failed: %s",
611 db_fd, strerror(xerrno));
612 if (xerrno == EACCES) {
613 struct flock locker;
614
615 /* Get the PID of the process blocking this lock. */
616 if (fcntl(db_fd, F_GETLK, &locker) == 0) {
617 pr_trace_msg(trace_channel, 3, "process ID %lu has blocking %s lock on "
618 "table fd %d, start %lu len %lu", (unsigned long) locker.l_pid,
619 get_lock_type(&locker), db_fd, (unsigned long) lock.l_start,
620 (unsigned long) lock.l_len);
621 }
622 }
623
624 if (xerrno == EAGAIN ||
625 xerrno == EACCES) {
626 /* Treat this as an interrupted call, call pr_signals_handle() (which
627 * will delay for a few msecs because of EINTR), and try again.
628 * After SNMP_MAX_LOCK_ATTEMPTS attempts, give up altogether.
629 */
630
631 nattempts++;
632 if (nattempts <= SNMP_MAX_LOCK_ATTEMPTS) {
633 errno = EINTR;
634
635 pr_signals_handle();
636
637 errno = 0;
638 pr_trace_msg(trace_channel, 9,
639 "attempt #%u to read-lock table fd %d", nattempts, db_fd);
640 continue;
641 }
642
643 pr_trace_msg(trace_channel, 3,
644 "unable to acquire read-lock on table fd %d: %s", db_fd,
645 strerror(xerrno));
646 }
647
648 errno = xerrno;
649 return -1;
650 }
651
652 pr_trace_msg(trace_channel, 9,
653 "read-lock of field %u table fd %d (start %lu len %lu) successful",
654 field, db_fd, (unsigned long) lock.l_start, (unsigned long) lock.l_len);
655 return 0;
656 }
657
snmp_db_wlock(unsigned int field)658 int snmp_db_wlock(unsigned int field) {
659 struct flock lock;
660 unsigned int nattempts = 1;
661 int db_id, db_fd;
662 size_t field_len;
663
664 lock.l_type = F_WRLCK;
665 lock.l_whence = SEEK_SET;
666
667 db_id = snmp_db_get_field_db_id(field);
668 if (db_id < 0) {
669 return -1;
670 }
671
672 db_fd = snmp_dbs[db_id].db_fd;
673 if (get_field_range(field, &(lock.l_start), &field_len) < 0) {
674 return -1;
675 }
676 lock.l_len = (off_t) field_len;
677
678 pr_trace_msg(trace_channel, 9,
679 "attempt #%u to write-lock field %u db ID %d table '%s' "
680 "(fd %d start %lu len %lu)", nattempts, field, db_id,
681 snmp_dbs[db_id].db_path, db_fd, (unsigned long) lock.l_start,
682 (unsigned long) lock.l_len);
683
684 while (fcntl(db_fd, F_SETLK, &lock) < 0) {
685 int xerrno = errno;
686
687 if (xerrno == EINTR) {
688 pr_signals_handle();
689 continue;
690 }
691
692 pr_trace_msg(trace_channel, 3, "write-lock of table fd %d failed: %s",
693 db_fd, strerror(xerrno));
694 if (xerrno == EACCES) {
695 struct flock locker;
696
697 /* Get the PID of the process blocking this lock. */
698 if (fcntl(db_fd, F_GETLK, &locker) == 0) {
699 pr_trace_msg(trace_channel, 3, "process ID %lu has blocking %s lock on "
700 "table fd %d, start %lu len %lu", (unsigned long) locker.l_pid,
701 get_lock_type(&locker), db_fd, (unsigned long) lock.l_start,
702 (unsigned long) lock.l_len);
703 }
704 }
705
706 if (xerrno == EAGAIN ||
707 xerrno == EACCES) {
708 /* Treat this as an interrupted call, call pr_signals_handle() (which
709 * will delay for a few msecs because of EINTR), and try again.
710 * After SNMP_MAX_LOCK_ATTEMPTS attempts, give up altogether.
711 */
712
713 nattempts++;
714 if (nattempts <= SNMP_MAX_LOCK_ATTEMPTS) {
715 errno = EINTR;
716
717 pr_signals_handle();
718
719 errno = 0;
720 pr_trace_msg(trace_channel, 9,
721 "attempt #%u to write-lock table fd %d", nattempts, db_fd);
722 continue;
723 }
724
725 pr_trace_msg(trace_channel, 3,
726 "unable to acquire write-lock on table fd %d: %s", db_fd,
727 strerror(xerrno));
728 }
729
730 errno = xerrno;
731 return -1;
732 }
733
734 pr_trace_msg(trace_channel, 9,
735 "write-lock of field %u table fd %d (start %lu len %lu) successful",
736 field, db_fd, (unsigned long) lock.l_start, (unsigned long) lock.l_len);
737 return 0;
738 }
739
snmp_db_unlock(unsigned int field)740 int snmp_db_unlock(unsigned int field) {
741 struct flock lock;
742 unsigned int nattempts = 1;
743 int db_id, db_fd;
744 size_t field_len;
745
746 lock.l_type = F_UNLCK;
747 lock.l_whence = SEEK_SET;
748
749 db_id = snmp_db_get_field_db_id(field);
750 if (db_id < 0) {
751 return -1;
752 }
753
754 db_fd = snmp_dbs[db_id].db_fd;
755 if (get_field_range(field, &(lock.l_start), &field_len) < 0) {
756 return -1;
757 }
758 lock.l_len = (off_t) field_len;
759
760 pr_trace_msg(trace_channel, 9,
761 "attempt #%u to unlock field %u table '%s' (fd %d start %lu len %lu)",
762 nattempts, field, snmp_dbs[db_id].db_path, db_fd,
763 (unsigned long) lock.l_start, (unsigned long) lock.l_len);
764
765 while (fcntl(db_fd, F_SETLK, &lock) < 0) {
766 int xerrno = errno;
767
768 if (xerrno == EINTR) {
769 pr_signals_handle();
770 continue;
771 }
772
773 pr_trace_msg(trace_channel, 3, "unlock of table fd %d failed: %s",
774 db_fd, strerror(xerrno));
775 if (xerrno == EACCES) {
776 struct flock locker;
777
778 /* Get the PID of the process blocking this lock. */
779 if (fcntl(db_fd, F_GETLK, &locker) == 0) {
780 pr_trace_msg(trace_channel, 3, "process ID %lu has blocking %s lock on "
781 "table fd %d, start %lu len %lu", (unsigned long) locker.l_pid,
782 get_lock_type(&locker), db_fd, (unsigned long) lock.l_start,
783 (unsigned long) lock.l_len);
784 }
785 }
786
787 if (xerrno == EAGAIN ||
788 xerrno == EACCES) {
789 /* Treat this as an interrupted call, call pr_signals_handle() (which
790 * will delay for a few msecs because of EINTR), and try again.
791 * After SNMP_MAX_LOCK_ATTEMPTS attempts, give up altogether.
792 */
793
794 nattempts++;
795 if (nattempts <= SNMP_MAX_LOCK_ATTEMPTS) {
796 errno = EINTR;
797
798 pr_signals_handle();
799
800 errno = 0;
801 pr_trace_msg(trace_channel, 9,
802 "attempt #%u to unlock table fd %d", nattempts, db_fd);
803 continue;
804 }
805
806 pr_trace_msg(trace_channel, 3,
807 "unable to acquire unlock on table fd %d: %s", db_fd,
808 strerror(xerrno));
809 }
810
811 errno = xerrno;
812 return -1;
813 }
814
815 pr_trace_msg(trace_channel, 9,
816 "unlock of field %u table fd %d (start %lu len %lu) successful",
817 field, db_fd, (unsigned long) lock.l_start, (unsigned long) lock.l_len);
818 return 0;
819 }
820
snmp_db_open(pool * p,int db_id)821 int snmp_db_open(pool *p, int db_id) {
822 int db_fd, mmap_flags, xerrno;
823 char *db_path;
824 size_t db_datasz;
825 void *db_data;
826
827 if (db_id < 0) {
828 errno = EINVAL;
829 return -1;
830 }
831
832 /* First, see if the database is already opened. */
833 if (snmp_dbs[db_id].db_path != NULL) {
834 return 0;
835 }
836
837 pr_trace_msg(trace_channel, 19,
838 "opening db ID %d (db root = %s, db name = %s)", db_id, snmp_db_root,
839 snmp_dbs[db_id].db_name);
840
841 db_path = pdircat(p, snmp_db_root, snmp_dbs[db_id].db_name, NULL);
842
843 PRIVS_ROOT
844 db_fd = open(db_path, O_RDWR|O_CREAT, 0600);
845 xerrno = errno;
846 PRIVS_RELINQUISH
847
848 if (db_fd < 0) {
849 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
850 "error opening SNMPTable '%s': %s", db_path, strerror(xerrno));
851 errno = xerrno;
852 return -1;
853 }
854
855 /* Make sure the fd isn't one of the big three. */
856 (void) pr_fs_get_usable_fd2(&db_fd);
857
858 pr_trace_msg(trace_channel, 19, "opened fd %d for SNMPTable '%s'", db_fd,
859 db_path);
860
861 snmp_dbs[db_id].db_fd = db_fd;
862 snmp_dbs[db_id].db_path = db_path;
863
864 db_datasz = snmp_dbs[db_id].db_datasz;
865
866 /* Truncate the table first; any existing data should be deleted. */
867 if (ftruncate(db_fd, 0) < 0) {
868 xerrno = errno;
869
870 pr_trace_msg(trace_channel, 1,
871 "error truncating SNMPTable '%s' to size 0: %s", db_path,
872 strerror(xerrno));
873
874 (void) snmp_db_close(p, db_id);
875 errno = xerrno;
876 return -1;
877 }
878
879 /* Seek to the desired table size (actually, one byte less than the desired
880 * size) and write a single byte, so that there's enough allocated backing
881 * store on the filesystem to support the ensuing mmap() call.
882 */
883 if (lseek(db_fd, db_datasz, SEEK_SET) < 0) {
884 xerrno = errno;
885
886 pr_trace_msg(trace_channel, 1,
887 "error seeking to %lu in table '%s': %s",
888 (unsigned long) db_datasz-1, db_path, strerror(xerrno));
889
890 (void) snmp_db_close(p, db_id);
891 errno = xerrno;
892 return -1;
893 }
894
895 if (write(db_fd, "", 1) != 1) {
896 xerrno = errno;
897
898 pr_trace_msg(trace_channel, 1,
899 "error writing single byte to table '%s': %s", db_path, strerror(xerrno));
900
901 (void) snmp_db_close(p, db_id);
902 errno = xerrno;
903 return -1;
904 }
905
906 mmap_flags = MAP_SHARED;
907
908 /* Make sure to set the fd to -1 if MAP_ANON(YMOUS) is used. By definition,
909 * anonymous mapped memory does not need (or want) a valid file backing
910 * store; some implementations will not do what is expected when anonymous
911 * memory is requested AND a valid fd is passed in.
912 *
913 * However, we want to keep a valid fd open anyway, for later use by
914 * fcntl(2) for byte range locking; we simply don't use the valid fd for
915 * the mmap(2) call.
916 */
917
918 #if defined(MAP_ANONYMOUS)
919 /* Linux */
920 mmap_flags |= MAP_ANONYMOUS;
921 db_fd = -1;
922
923 #elif defined(MAP_ANON)
924 /* FreeBSD, MacOSX, Solaris, others? */
925 mmap_flags |= MAP_ANON;
926 db_fd = -1;
927
928 #else
929 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
930 "mmap(2) MAP_ANONYMOUS and MAP_ANON flags not defined");
931 #endif
932
933 db_data = mmap(NULL, db_datasz, PROT_READ|PROT_WRITE, mmap_flags, db_fd, 0);
934 if (db_data == MAP_FAILED) {
935 xerrno = errno;
936
937 pr_trace_msg(trace_channel, 1,
938 "error mapping table '%s' fd %d size %lu into memory: %s", db_path,
939 db_fd, (unsigned long) db_datasz, strerror(xerrno));
940
941 (void) snmp_db_close(p, db_id);
942 errno = xerrno;
943 return -1;
944 }
945
946 snmp_dbs[db_id].db_data = db_data;
947
948 /* Make sure the data are zeroed. */
949 memset(db_data, 0, db_datasz);
950
951 return 0;
952 }
953
snmp_db_close(pool * p,int db_id)954 int snmp_db_close(pool *p, int db_id) {
955 int db_fd, res;
956 void *db_data;
957
958 if (db_id < 0) {
959 errno = EINVAL;
960 return -1;
961 }
962
963 db_data = snmp_dbs[db_id].db_data;
964
965 if (db_data != NULL) {
966 size_t db_datasz;
967
968 db_datasz = snmp_dbs[db_id].db_datasz;
969
970 if (munmap(db_data, db_datasz) < 0) {
971 int xerrno = errno;
972
973 pr_trace_msg(trace_channel, 1,
974 "error unmapping SNMPTable '%s' from memory: %s",
975 pdircat(p, snmp_db_root, snmp_dbs[db_id].db_path, NULL),
976 strerror(xerrno));
977
978 errno = xerrno;
979 return -1;
980 }
981 }
982
983 snmp_dbs[db_id].db_data = NULL;
984
985 db_fd = snmp_dbs[db_id].db_fd;
986 res = close(db_fd);
987 if (res < 0) {
988 return -1;
989 }
990
991 snmp_dbs[db_id].db_fd = -1;
992 return 0;
993 }
994
snmp_db_get_value(pool * p,unsigned int field,int32_t * int_value,char ** str_value,size_t * str_valuelen)995 int snmp_db_get_value(pool *p, unsigned int field, int32_t *int_value,
996 char **str_value, size_t *str_valuelen) {
997 void *db_data, *field_data;
998 int db_id, res;
999 off_t field_start;
1000 size_t field_len;
1001
1002 switch (field) {
1003 case SNMP_DB_NOTIFY_F_SYS_UPTIME: {
1004 struct timeval start_tv, now_tv;
1005
1006 /* TimeTicks are in hundredths of seconds since start time. */
1007 res = snmp_uptime_get(p, &start_tv);
1008 if (res < 0)
1009 return -1;
1010
1011 gettimeofday(&now_tv, NULL);
1012
1013 *int_value = (int32_t) (((now_tv.tv_sec - start_tv.tv_sec) * 100) +
1014 ((now_tv.tv_usec - start_tv.tv_usec) / 10000));
1015
1016 pr_trace_msg(trace_channel, 19,
1017 "read value %lu for field %s", (unsigned long) *int_value,
1018 snmp_db_get_fieldstr(p, field));
1019 return 0;
1020 }
1021
1022 case SNMP_DB_CONN_F_SERVER_NAME:
1023 if (main_server->ServerName == NULL) {
1024 errno = ENOENT;
1025 return -1;
1026 }
1027
1028 *str_value = (char *) main_server->ServerName;
1029 *str_valuelen = strlen(*str_value);
1030
1031 pr_trace_msg(trace_channel, 19,
1032 "read value '%s' for field %s", *str_value,
1033 snmp_db_get_fieldstr(p, field));
1034 return 0;
1035
1036 case SNMP_DB_CONN_F_SERVER_ADDR:
1037 if (session.c == NULL) {
1038 errno = ENOENT;
1039 return -1;
1040 }
1041
1042 *str_value = (char *) pr_netaddr_get_ipstr(session.c->local_addr);
1043 *str_valuelen = strlen(*str_value);
1044
1045 pr_trace_msg(trace_channel, 19,
1046 "read value '%s' for field %s", *str_value,
1047 snmp_db_get_fieldstr(p, field));
1048 return 0;
1049
1050 case SNMP_DB_CONN_F_SERVER_PORT:
1051 if (session.c == NULL) {
1052 errno = ENOENT;
1053 return -1;
1054 }
1055
1056 *int_value = ntohs(pr_netaddr_get_port(session.c->remote_addr));
1057 pr_trace_msg(trace_channel, 19,
1058 "read value %lu for field %s", (unsigned long) *int_value,
1059 snmp_db_get_fieldstr(p, field));
1060 return 0;
1061
1062 case SNMP_DB_CONN_F_CLIENT_ADDR:
1063 if (session.c == NULL) {
1064 errno = ENOENT;
1065 return -1;
1066 }
1067
1068 *str_value = (char *) pr_netaddr_get_ipstr(session.c->remote_addr);
1069 *str_valuelen = strlen(*str_value);
1070
1071 pr_trace_msg(trace_channel, 19,
1072 "read value '%s' for field %s", *str_value,
1073 snmp_db_get_fieldstr(p, field));
1074 return 0;
1075
1076 case SNMP_DB_CONN_F_PID:
1077 *int_value = session.pid;
1078 pr_trace_msg(trace_channel, 19,
1079 "read value %lu for field %s", (unsigned long) *int_value,
1080 snmp_db_get_fieldstr(p, field));
1081 return 0;
1082
1083 case SNMP_DB_CONN_F_USER_NAME: {
1084 const char *orig_user;
1085
1086 orig_user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
1087 if (orig_user == NULL) {
1088 errno = ENOENT;
1089 return -1;
1090 }
1091
1092 *str_value = (char *) orig_user;
1093 *str_valuelen = strlen(*str_value);
1094
1095 pr_trace_msg(trace_channel, 19,
1096 "read value '%s' for field %s", *str_value,
1097 snmp_db_get_fieldstr(p, field));
1098 return 0;
1099 }
1100
1101 case SNMP_DB_CONN_F_PROTOCOL: {
1102 const char *proto;
1103
1104 proto = pr_session_get_protocol(0);
1105
1106 *str_value = (char *) proto;
1107 *str_valuelen = strlen(*str_value);
1108
1109 pr_trace_msg(trace_channel, 19,
1110 "read value '%s' for field %s", *str_value,
1111 snmp_db_get_fieldstr(p, field));
1112 return 0;
1113 }
1114
1115 case SNMP_DB_DAEMON_F_SOFTWARE:
1116 *str_value = "proftpd";
1117 *str_valuelen = strlen(*str_value);
1118
1119 pr_trace_msg(trace_channel, 19,
1120 "read value '%s' for field %s", *str_value,
1121 snmp_db_get_fieldstr(p, field));
1122 return 0;
1123
1124 case SNMP_DB_DAEMON_F_VERSION:
1125 *str_value = "ProFTPD Version " PROFTPD_VERSION_TEXT " (built at " BUILD_STAMP ")";
1126 *str_valuelen = strlen(*str_value);
1127
1128 pr_trace_msg(trace_channel, 19,
1129 "read value '%s' for field %s", *str_value,
1130 snmp_db_get_fieldstr(p, field));
1131 return 0;
1132
1133 case SNMP_DB_DAEMON_F_ADMIN:
1134 *str_value = (char *) main_server->ServerAdmin;
1135 *str_valuelen = strlen(*str_value);
1136
1137 pr_trace_msg(trace_channel, 19,
1138 "read value '%s' for field %s", *str_value,
1139 snmp_db_get_fieldstr(p, field));
1140 return 0;
1141
1142 case SNMP_DB_DAEMON_F_UPTIME: {
1143 struct timeval now_tv;
1144
1145 /* TimeTicks are in hundredths of seconds since start time. */
1146 gettimeofday(&now_tv, NULL);
1147
1148 *int_value = (int32_t) (((now_tv.tv_sec - snmp_start_tv.tv_sec) * 100) +
1149 ((now_tv.tv_usec - snmp_start_tv.tv_usec) / 10000));
1150
1151 pr_trace_msg(trace_channel, 19,
1152 "read value %lu for field %s", (unsigned long) *int_value,
1153 snmp_db_get_fieldstr(p, field));
1154 return 0;
1155 }
1156
1157 case SNMP_DB_DAEMON_F_MAXINST_CONF:
1158 *int_value = ServerMaxInstances;
1159
1160 pr_trace_msg(trace_channel, 19,
1161 "read value %lu for field %s", (unsigned long) *int_value,
1162 snmp_db_get_fieldstr(p, field));
1163 return 0;
1164
1165 default:
1166 break;
1167 }
1168
1169 db_id = snmp_db_get_field_db_id(field);
1170 if (db_id < 0) {
1171 return -1;
1172 }
1173
1174 if (get_field_range(field, &field_start, &field_len) < 0) {
1175 return -1;
1176 }
1177
1178 res = snmp_db_rlock(field);
1179 if (res < 0) {
1180 return -1;
1181 }
1182
1183 db_data = snmp_dbs[db_id].db_data;
1184 field_data = &(((uint32_t *) db_data)[field_start]);
1185 memmove(int_value, field_data, field_len);
1186
1187 res = snmp_db_unlock(field);
1188 if (res < 0) {
1189 return -1;
1190 }
1191
1192 pr_trace_msg(trace_channel, 19,
1193 "read value %lu for field %s", (unsigned long) *int_value,
1194 snmp_db_get_fieldstr(p, field));
1195 return 0;
1196 }
1197
snmp_db_incr_value(pool * p,unsigned int field,int32_t incr)1198 int snmp_db_incr_value(pool *p, unsigned int field, int32_t incr) {
1199 uint32_t orig_val, new_val;
1200 int db_id, res;
1201 void *db_data, *field_data;
1202 off_t field_start;
1203 size_t field_len;
1204
1205 db_id = snmp_db_get_field_db_id(field);
1206 if (db_id < 0) {
1207 return -1;
1208 }
1209
1210 if (get_field_range(field, &field_start, &field_len) < 0) {
1211 return -1;
1212 }
1213
1214 res = snmp_db_wlock(field);
1215 if (res < 0) {
1216 return -1;
1217 }
1218
1219 db_data = snmp_dbs[db_id].db_data;
1220 field_data = &(((uint32_t *) db_data)[field_start]);
1221 memmove(&new_val, field_data, field_len);
1222 orig_val = new_val;
1223
1224 if (orig_val == 0 &&
1225 incr < 0) {
1226 /* If we are in fact decrementing a value, and that value is
1227 * already zero, then do nothing.
1228 */
1229
1230 res = snmp_db_unlock(field);
1231 if (res < 0) {
1232 return -1;
1233 }
1234
1235 pr_trace_msg(trace_channel, 19,
1236 "value already zero for field %s (%d), not decrementing by %ld",
1237 snmp_db_get_fieldstr(p, field), field, (long) incr);
1238 return 0;
1239 }
1240
1241 new_val += incr;
1242 memmove(field_data, &new_val, field_len);
1243
1244 #if 0
1245 res = msync(field_data, field_len, MS_SYNC);
1246 if (res < 0) {
1247 pr_trace_msg(trace_channel, 1, "msync(2) error for field %s (%d): %s",
1248 snmp_db_get_fieldstr(p, field), field, strerror(errno));
1249 }
1250 #endif
1251
1252 res = snmp_db_unlock(field);
1253 if (res < 0) {
1254 return -1;
1255 }
1256
1257 pr_trace_msg(trace_channel, 19,
1258 "wrote value %lu (was %lu) for field %s (%d)", (unsigned long) new_val,
1259 (unsigned long) orig_val, snmp_db_get_fieldstr(p, field), field);
1260 return 0;
1261 }
1262
snmp_db_reset_value(pool * p,unsigned int field)1263 int snmp_db_reset_value(pool *p, unsigned int field) {
1264 uint32_t val;
1265 int db_id, res;
1266 void *db_data, *field_data;
1267 off_t field_start;
1268 size_t field_len;
1269
1270 db_id = snmp_db_get_field_db_id(field);
1271 if (db_id < 0) {
1272 return -1;
1273 }
1274
1275 if (get_field_range(field, &field_start, &field_len) < 0) {
1276 return -1;
1277 }
1278
1279 res = snmp_db_wlock(field);
1280 if (res < 0) {
1281 return -1;
1282 }
1283
1284 db_data = snmp_dbs[db_id].db_data;
1285 field_data = &(((uint32_t *) db_data)[field_start]);
1286
1287 val = 0;
1288 memmove(field_data, &val, field_len);
1289
1290 res = snmp_db_unlock(field);
1291 if (res < 0) {
1292 return -1;
1293 }
1294
1295 pr_trace_msg(trace_channel, 19,
1296 "reset value to 0 for field %s", snmp_db_get_fieldstr(p, field));
1297 return 0;
1298 }
1299
snmp_db_set_root(const char * db_root)1300 int snmp_db_set_root(const char *db_root) {
1301 if (db_root == NULL) {
1302 errno = EINVAL;
1303 return -1;
1304 }
1305
1306 snmp_db_root = db_root;
1307 return 0;
1308 }
1309