1 /*
2 * ProFTPD - mod_snmp
3 * Copyright (c) 2008-2021 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 * -----DO NOT EDIT BELOW THIS LINE-----
25 * $Archive: mod_snmp.a $
26 */
27
28 #include "mod_snmp.h"
29 #include "asn1.h"
30 #include "db.h"
31 #include "mib.h"
32 #include "packet.h"
33 #include "pdu.h"
34 #include "msg.h"
35 #include "notify.h"
36
37 /* Defaults */
38 #define SNMP_DEFAULT_AGENT_PORT 161
39 #define SNMP_DEFAULT_TRAP_PORT 162
40
41 /* Agent type/role */
42 #define SNMP_AGENT_TYPE_MASTER 1
43 #define SNMP_AGENT_TYPE_AGENTX 2
44
45 extern xaset_t *server_list;
46
47 module snmp_module;
48
49 int snmp_logfd = -1;
50 pool *snmp_pool = NULL;
51 conn_t *snmp_conn = NULL;
52 struct timeval snmp_start_tv;
53 int snmp_proto_udp = IPPROTO_UDP;
54
55 /* mod_snmp option flags */
56 #define SNMP_OPT_RESTART_CLEARS_COUNTERS 0x0001
57
58 static pid_t snmp_agent_pid = 0;
59 static int snmp_enabled = TRUE;
60 static int snmp_engine = FALSE;
61 static const char *snmp_logname = NULL;
62 static unsigned long snmp_opts = 0UL;
63
64 static const char *snmp_community = NULL;
65
66 /* The list of SNMPNotify receivers/managers to which to send notifications. */
67 static array_header *snmp_notifys = NULL;
68
69 /* This number defined as the maximum 'max-bindings' value in RFC19105; it's
70 * good enough for the default maximum number of variables in a bindings list
71 * to process.
72 */
73 static unsigned int snmp_max_variables = SNMP_PDU_MAX_BINDINGS;
74
75 /* Number of seconds to wait for the SNMP agent process to stop before
76 * we terminate it with extreme prejudice.
77 *
78 * Currently this has a granularity of seconds; needs to be in millsecs
79 * (e.g. for 500 ms timeout).
80 */
81 static time_t snmp_agent_timeout = 1;
82
83 static off_t snmp_retr_bytes = 0, snmp_stor_bytes = 0;
84
85 static const char *trace_channel = "snmp";
86
snmp_check_class_access(xaset_t * set,const char * name,struct snmp_packet * pkt)87 static int snmp_check_class_access(xaset_t *set, const char *name,
88 struct snmp_packet *pkt) {
89 config_rec *c;
90 int ok = FALSE;
91
92 /* If no class was found for this session, short-circuit the check.
93 * Note: this is an optimization that can/should be applied to the
94 * core engine as well, e.g. in the proftpd-1.3.5 devel cycle.
95 */
96 if (pkt->remote_class == NULL) {
97 return ok;
98 }
99
100 /* XXX Note: the pr_expr_eval_class_* functions assume the use of the
101 * global session variable. They should be refactored to take the
102 * class as an argument.
103 */
104
105 #if PROFTPD_VERSION_NUMBER >= 0x0001030501
106 session.conn_class = pkt->remote_class;
107 #else
108 session.class = pkt->remote_class;
109 #endif /* ProFTPD-1.3.5rc1 and later */
110
111 c = find_config(set, CONF_PARAM, name, FALSE);
112 while (c) {
113 pr_signals_handle();
114
115 #ifdef PR_USE_REGEX
116 if (*((unsigned char *) c->argv[0]) == PR_EXPR_EVAL_REGEX) {
117 pr_regex_t *pre = (pr_regex_t *) c->argv[1];
118
119 if (pkt->remote_class != NULL &&
120 pr_regexp_exec(pre, pkt->remote_class->cls_name, 0, NULL,
121 0, 0, 0) == 0) {
122 ok = TRUE;
123 break;
124 }
125
126 } else
127 #endif /* regex support */
128
129 if (*((unsigned char *) c->argv[0]) == PR_EXPR_EVAL_OR) {
130 ok = pr_expr_eval_class_or((char **) &c->argv[1]);
131 if (ok == TRUE)
132 break;
133
134 } else if (*((unsigned char *) c->argv[0]) == PR_EXPR_EVAL_AND) {
135 ok = pr_expr_eval_class_and((char **) &c->argv[1]);
136 if (ok == TRUE)
137 break;
138 }
139
140 c = find_config_next(c, c->next, CONF_PARAM, name, FALSE);
141 }
142
143 #if PROFTPD_VERSION_NUMBER >= 0x0001030501
144 session.conn_class = NULL;
145 #else
146 session.class = NULL;
147 #endif /* ProFTPD-1.3.5rc1 and later */
148
149 return ok;
150 }
151
snmp_check_ip_positive(const config_rec * c,struct snmp_packet * pkt)152 static int snmp_check_ip_positive(const config_rec *c,
153 struct snmp_packet *pkt) {
154 int aclc;
155 pr_netacl_t **aclv;
156
157 for (aclc = c->argc, aclv = (pr_netacl_t **) c->argv; aclc; aclc--, aclv++) {
158 if (pr_netacl_get_negated(*aclv) == TRUE) {
159 continue;
160 }
161
162 switch (pr_netacl_match(*aclv, pkt->remote_addr)) {
163 case 1:
164 /* Found it! */
165 return TRUE;
166
167 case -1:
168 /* Special value "NONE", meaning nothing can match, so we can
169 * short-circuit on this as well.
170 */
171 return FALSE;
172
173 default:
174 /* No match, keep trying */
175 break;
176 }
177 }
178
179 return FALSE;
180 }
181
snmp_check_ip_negative(const config_rec * c,struct snmp_packet * pkt)182 static int snmp_check_ip_negative(const config_rec *c,
183 struct snmp_packet *pkt) {
184 int aclc;
185 pr_netacl_t **aclv;
186
187 for (aclc = c->argc, aclv = (pr_netacl_t **) c->argv; aclc; aclc--, aclv++) {
188 if (pr_netacl_get_negated(*aclv) == FALSE) {
189 continue;
190 }
191
192 switch (pr_netacl_match(*aclv, pkt->remote_addr)) {
193 case 1:
194 /* This actually means we DID NOT match, and it's ok to short circuit
195 * everything (negative).
196 */
197 return FALSE;
198
199 case -1:
200 /* -1 signifies a NONE match, which isn't valid for negative
201 * conditions.
202 */
203 pr_log_pri(PR_LOG_NOTICE, MOD_SNMP_VERSION
204 ": ooops, it looks like !NONE was used in an ACL somehow");
205 return FALSE;
206
207 default:
208 /* This means our match is actually true and we can continue */
209 break;
210 }
211 }
212
213 /* If we got this far either all conditions were TRUE or there were no
214 * conditions.
215 */
216
217 return TRUE;
218 }
219
snmp_check_ip_access(xaset_t * set,const char * name,struct snmp_packet * pkt)220 static int snmp_check_ip_access(xaset_t *set, const char *name,
221 struct snmp_packet *pkt) {
222 config_rec *c;
223 int ok = FALSE;
224
225 c = find_config(set, CONF_PARAM, name, FALSE);
226 while (c) {
227 pr_signals_handle();
228
229 if (snmp_check_ip_negative(c, pkt) != TRUE) {
230 ok = FALSE;
231 break;
232 }
233
234 if (snmp_check_ip_positive(c, pkt) == TRUE) {
235 ok = TRUE;
236 break;
237 }
238
239 c = find_config_next(c, c->next, CONF_PARAM, name, FALSE);
240 }
241
242 return ok;
243 }
244
snmp_check_allow_limit(config_rec * c,struct snmp_packet * pkt)245 static int snmp_check_allow_limit(config_rec *c, struct snmp_packet *pkt) {
246 unsigned char *allow_all = NULL;
247
248 if (pkt->remote_class != NULL) {
249 if (snmp_check_class_access(c->subset, "AllowClass", pkt)) {
250 return 1;
251 }
252 }
253
254 if (snmp_check_ip_access(c->subset, "Allow", pkt)) {
255 return 1;
256 }
257
258 allow_all = get_param_ptr(c->subset, "AllowAll", FALSE);
259 if (allow_all != NULL &&
260 *allow_all == TRUE) {
261 return 1;
262 }
263
264 return 0;
265 }
266
snmp_check_deny_limit(config_rec * c,struct snmp_packet * pkt)267 static int snmp_check_deny_limit(config_rec *c, struct snmp_packet *pkt) {
268 unsigned char *deny_all;
269
270 deny_all = get_param_ptr(c->subset, "DenyAll", FALSE);
271 if (deny_all != NULL &&
272 *deny_all == TRUE) {
273 return 1;
274 }
275
276 if (pkt->remote_class != NULL) {
277 if (snmp_check_class_access(c->subset, "DenyClass", pkt)) {
278 return 1;
279 }
280 }
281
282 if (snmp_check_ip_access(c->subset, "Deny", pkt)) {
283 return 1;
284 }
285
286 return 0;
287 }
288
snmp_check_limit(config_rec * c,struct snmp_packet * pkt)289 static int snmp_check_limit(config_rec *c, struct snmp_packet *pkt) {
290 int *ptr = get_param_ptr(c->subset, "Order", FALSE);
291 int order = ptr ? *ptr : ORDER_ALLOWDENY;
292
293 if (order == ORDER_DENYALLOW) {
294 /* Check deny first */
295
296 if (snmp_check_deny_limit(c, pkt)) {
297 /* Explicit deny */
298 errno = EPERM;
299 return -2;
300 }
301
302 if (snmp_check_allow_limit(c, pkt)) {
303 /* Explicit allow */
304 return 1;
305 }
306
307 /* Implicit deny */
308 errno = EPERM;
309 return -1;
310 }
311
312 /* Check allow first */
313 if (snmp_check_allow_limit(c, pkt)) {
314 /* Explicit allow */
315 return 1;
316 }
317
318 if (snmp_check_deny_limit(c, pkt)) {
319 /* Explicit deny */
320 errno = EPERM;
321 return -2;
322 }
323
324 /* Implicit allow */
325 return 0;
326 }
327
328 /* Similar to the login_check_limits() function from src/dirtree.c, except
329 * that we assume some of the argument values (and thus don't need them
330 * from callers), we don't handle the per-user/group ACLs, and we look
331 * for <Limit SNMP> sections.
332 */
snmp_limits_allow(xaset_t * set,struct snmp_packet * pkt)333 static int snmp_limits_allow(xaset_t *set, struct snmp_packet *pkt) {
334 config_rec *c = NULL;
335 int ok = FALSE;
336 int found = 0;
337
338 if (set == NULL ||
339 set->xas_list == NULL) {
340 /* Allow by default */
341 return TRUE;
342 }
343
344 for (c = (config_rec *) set->xas_list; c; c = c->next) {
345 int argc = -1;
346 char **argv = NULL;
347
348 if (c->config_type != CONF_LIMIT) {
349 continue;
350 }
351
352 argc = c->argc;
353 argv = (char **) c->argv;
354
355 for (; argc; argc--, argv++) {
356 if (strncasecmp(*argv, "SNMP", 5) == 0) {
357 break;
358 }
359 }
360
361 if (argc > 0) {
362 switch (snmp_check_limit(c, pkt)) {
363 case 1:
364 ok = TRUE;
365 found++;
366 break;
367
368 case -1:
369 case -2:
370 found++;
371 break;
372 }
373 }
374 }
375
376 if (found == 0) {
377 /* Allow by default. */
378 ok = TRUE;
379 }
380
381 return ok;
382 }
383
snmp_security_check(struct snmp_packet * pkt)384 static int snmp_security_check(struct snmp_packet *pkt) {
385 int res = 0;
386
387 switch (pkt->snmp_version) {
388 case SNMP_PROTOCOL_VERSION_1:
389 case SNMP_PROTOCOL_VERSION_2:
390 /* Check the community string against the configured SNMPCommunity. */
391 if (strncmp(snmp_community, pkt->community, pkt->community_len) != 0) {
392 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
393 "%s message community '%s' does not match configured community, "
394 "ignoring message", snmp_msg_get_versionstr(pkt->snmp_version),
395 pkt->community);
396
397 /* XXX Send authenticationFailure trap to SNMPNotify address */
398
399 res = snmp_db_incr_value(pkt->pool,
400 SNMP_DB_SNMP_F_PKTS_AUTH_ERR_TOTAL, 1);
401 if (res < 0) {
402 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
403 "error incrementing snmp.packetsAuthFailedTotal: %s",
404 strerror(errno));
405 }
406
407 errno = EACCES;
408 return -1;
409 }
410 break;
411
412 case SNMP_PROTOCOL_VERSION_3:
413 /* XXX Not supported yet */
414 errno = ENOSYS;
415 return -1;
416 }
417
418 return res;
419 }
420
snmp_mkdir(const char * dir,uid_t uid,gid_t gid,mode_t mode)421 static int snmp_mkdir(const char *dir, uid_t uid, gid_t gid, mode_t mode) {
422 mode_t prev_mask;
423 struct stat st;
424 int res = -1;
425
426 pr_fs_clear_cache2(dir);
427 res = pr_fsio_stat(dir, &st);
428
429 if (res == -1 &&
430 errno != ENOENT) {
431 return -1;
432 }
433
434 /* The directory already exists. */
435 if (res == 0) {
436 return 0;
437 }
438
439 /* The given mode is absolute, not subject to any Umask setting. */
440 prev_mask = umask(0);
441
442 if (pr_fsio_mkdir(dir, mode) < 0) {
443 int xerrno = errno;
444
445 (void) umask(prev_mask);
446 errno = xerrno;
447 return -1;
448 }
449
450 umask(prev_mask);
451
452 if (pr_fsio_chown(dir, uid, gid) < 0) {
453 return -1;
454 }
455
456 return 0;
457 }
458
snmp_mkpath(pool * p,const char * path,uid_t uid,gid_t gid,mode_t mode)459 static int snmp_mkpath(pool *p, const char *path, uid_t uid, gid_t gid,
460 mode_t mode) {
461 char *currpath = NULL, *tmppath = NULL;
462 struct stat st;
463
464 pr_fs_clear_cache2(path);
465 if (pr_fsio_stat(path, &st) == 0) {
466 /* Path already exists, nothing to be done. */
467 errno = EEXIST;
468 return -1;
469 }
470
471 tmppath = pstrdup(p, path);
472
473 currpath = "/";
474 while (tmppath && *tmppath) {
475 char *currdir = strsep(&tmppath, "/");
476 currpath = pdircat(p, currpath, currdir, NULL);
477
478 if (snmp_mkdir(currpath, uid, gid, mode) < 0) {
479 return -1;
480 }
481
482 pr_signals_handle();
483 }
484
485 return 0;
486 }
487
snmp_openlog(void)488 static int snmp_openlog(void) {
489 int res = 0;
490 config_rec *c;
491
492 c = find_config(main_server->conf, CONF_PARAM, "SNMPLog", FALSE);
493 if (c) {
494 snmp_logname = c->argv[0];
495
496 if (strncasecmp(snmp_logname, "none", 5) != 0) {
497 int xerrno;
498
499 pr_signals_block();
500 PRIVS_ROOT
501 res = pr_log_openfile(snmp_logname, &snmp_logfd, 0600);
502 xerrno = errno;
503 PRIVS_RELINQUISH
504 pr_signals_unblock();
505
506 if (res < 0) {
507 if (res == -1) {
508 pr_log_pri(PR_LOG_NOTICE, MOD_SNMP_VERSION
509 ": notice: unable to open SNMPLog '%s': %s", snmp_logname,
510 strerror(xerrno));
511
512 } else if (res == PR_LOG_WRITABLE_DIR) {
513 pr_log_pri(PR_LOG_WARNING, MOD_SNMP_VERSION
514 ": notice: unable to open SNMPLog '%s': parent directory is "
515 "world-writable", snmp_logname);
516
517 } else if (res == PR_LOG_SYMLINK) {
518 pr_log_pri(PR_LOG_WARNING, MOD_SNMP_VERSION
519 ": notice: unable to open SNMPLog '%s': cannot log to a symlink",
520 snmp_logname);
521 }
522 }
523 }
524 }
525
526 return res;
527 }
528
529 /* We don't want to do the full daemonize() as provided in main.c; we
530 * already forked.
531 */
snmp_daemonize(const char * daemon_dir)532 static void snmp_daemonize(const char *daemon_dir) {
533 #ifndef HAVE_SETSID
534 int tty_fd;
535 #endif
536
537 #ifdef HAVE_SETSID
538 /* setsid() is the preferred way to disassociate from the
539 * controlling terminal
540 */
541 setsid();
542 #else
543 /* Open /dev/tty to access our controlling tty (if any) */
544 tty_fd = open("/dev/tty", O_RDWR);
545 if (tty_fd != -1) {
546 if (ioctl(tty_fd, TIOCNOTTY, NULL) == -1) {
547 perror("ioctl");
548 exit(1);
549 }
550
551 close(tty_fd);
552 }
553 #endif /* HAVE_SETSID */
554
555 /* Close the three big boys. */
556 close(fileno(stdin));
557 close(fileno(stdout));
558 close(fileno(stderr));
559
560 /* Portable way to prevent re-acquiring a tty in the future */
561
562 #ifdef HAVE_SETPGID
563 setpgid(0, getpid());
564
565 #else
566 # ifdef SETPGRP_VOID
567 setpgrp();
568
569 # else
570 setpgrp(0, getpid());
571 # endif /* SETPGRP_VOID */
572 #endif /* HAVE_SETPGID */
573
574 pr_fsio_chdir(daemon_dir, 0);
575 }
576
snmp_agent_handle_get(struct snmp_packet * pkt)577 static int snmp_agent_handle_get(struct snmp_packet *pkt) {
578 struct snmp_var *iter_var = NULL, *head_var = NULL, *tail_var = NULL;
579 unsigned int var_count = 0;
580 int res;
581
582 if (pkt->req_pdu->varlist == NULL) {
583 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
584 "missing request PDU variable bindings list, rejecting invalid request");
585 errno = EINVAL;
586 return -1;
587 }
588
589 pkt->resp_pdu = snmp_pdu_dup(pkt->pool, pkt->req_pdu);
590 pkt->resp_pdu->request_type = SNMP_PDU_RESPONSE;
591
592 if (pkt->req_pdu->varlistlen > snmp_max_variables) {
593 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
594 "%s %s of too many OIDs (%u, max %u)",
595 snmp_msg_get_versionstr(pkt->snmp_version),
596 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
597 pkt->req_pdu->varlistlen, snmp_max_variables);
598
599 pkt->resp_pdu->err_code = SNMP_ERR_TOO_BIG;
600 pkt->resp_pdu->err_idx = 0;
601
602 return 0;
603 }
604
605 for (iter_var = pkt->req_pdu->varlist; iter_var; iter_var = iter_var->next) {
606 struct snmp_mib *mib = NULL;
607 struct snmp_var *resp_var = NULL;
608 int32_t mib_int = -1;
609 char *mib_str = NULL;
610 size_t mib_strlen = 0;
611 int lacks_instance_id = FALSE;
612
613 pr_signals_handle();
614
615 mib = snmp_mib_get_by_oid(iter_var->name, iter_var->namelen,
616 &lacks_instance_id);
617 if (mib == NULL) {
618 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
619 "%s %s of unknown OID %s (lacks instance ID = %s)",
620 snmp_msg_get_versionstr(pkt->snmp_version),
621 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
622 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
623 iter_var->namelen), lacks_instance_id ? "true" : "false");
624
625 /* If SNMPv1, then set the err_code/err_idx values, and duplicate the
626 * varlist.
627 *
628 * If SNMPv2, then leave err_code/err_idex values set to zero, but
629 * create a var of exception 'noSuchObject' or 'noSuchInstance' as
630 * appropriate.
631 */
632
633 switch (pkt->snmp_version) {
634 case SNMP_PROTOCOL_VERSION_1:
635 pkt->resp_pdu->err_code = SNMP_ERR_NO_SUCH_NAME;
636 pkt->resp_pdu->err_idx = var_count + 1;
637 pkt->resp_pdu->varlist = snmp_smi_dup_var(pkt->pool,
638 pkt->req_pdu->varlist);
639 pkt->resp_pdu->varlistlen = pkt->req_pdu->varlistlen;
640 break;
641
642 case SNMP_PROTOCOL_VERSION_2:
643 case SNMP_PROTOCOL_VERSION_3:
644 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
645 iter_var->namelen, lacks_instance_id ? SNMP_SMI_NO_SUCH_INSTANCE :
646 SNMP_SMI_NO_SUCH_OBJECT);
647 break;
648 }
649
650 if (resp_var == NULL) {
651 return 0;
652 }
653 }
654
655 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
656 "%s %s of OID %s (%s)", snmp_msg_get_versionstr(pkt->snmp_version),
657 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
658 snmp_asn1_get_oidstr(iter_var->pool, iter_var->name, iter_var->namelen),
659 mib ? mib->instance_name : "unknown");
660
661 /* A response variable may be have generated above, e.g. when the MIB
662 * not known/supported.
663 */
664 if (resp_var == NULL) {
665 res = snmp_db_get_value(pkt->pool, mib->db_field, &mib_int, &mib_str,
666 &mib_strlen);
667
668 /* XXX Response with genErr instead? */
669 if (res < 0) {
670 int xerrno = errno;
671
672 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
673 "error retrieving database value for field %s: %s",
674 snmp_db_get_fieldstr(pkt->pool, mib->db_field), strerror(xerrno));
675 errno = xerrno;
676 return -1;
677 }
678
679 resp_var = snmp_smi_create_var(pkt->pool, mib->mib_oid, mib->mib_oidlen,
680 mib->smi_type, mib_int, mib_str, mib_strlen);
681 }
682
683 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var, resp_var);
684 }
685
686 pkt->resp_pdu->varlist = head_var;
687 pkt->resp_pdu->varlistlen = var_count;
688
689 return 0;
690 }
691
snmp_agent_handle_getnext(struct snmp_packet * pkt)692 static int snmp_agent_handle_getnext(struct snmp_packet *pkt) {
693 struct snmp_var *iter_var = NULL, *head_var = NULL, *tail_var = NULL;
694 unsigned int var_count = 0;
695 int max_idx, res;
696
697 if (pkt->req_pdu->varlist == NULL) {
698 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
699 "missing request PDU variable bindings list, rejecting invalid request");
700 errno = EINVAL;
701 return -1;
702 }
703
704 pkt->resp_pdu = snmp_pdu_dup(pkt->pool, pkt->req_pdu);
705 pkt->resp_pdu->request_type = SNMP_PDU_RESPONSE;
706
707 if (pkt->req_pdu->varlistlen > snmp_max_variables) {
708 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
709 "%s %s of too many OIDs (%u, max %u)",
710 snmp_msg_get_versionstr(pkt->snmp_version),
711 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
712 pkt->req_pdu->varlistlen, snmp_max_variables);
713
714 pkt->resp_pdu->err_code = SNMP_ERR_TOO_BIG;
715 pkt->resp_pdu->err_idx = 0;
716
717 return 0;
718 }
719
720 max_idx = snmp_mib_get_max_idx();
721
722 for (iter_var = pkt->req_pdu->varlist; iter_var; iter_var = iter_var->next) {
723 struct snmp_mib *mib = NULL;
724 struct snmp_var *resp_var = NULL;
725 int mib_idx = -1, next_idx = -1, lacks_instance_id = FALSE;
726 int32_t mib_int = -1;
727 char *mib_str = NULL;
728 size_t mib_strlen = 0;
729
730 pr_signals_handle();
731
732 mib_idx = snmp_mib_get_idx(iter_var->name, iter_var->namelen,
733 &lacks_instance_id);
734 if (mib_idx < 0) {
735 int unknown_oid = FALSE;
736
737 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
738 "%s %s of unknown OID %s (lacks instance ID = %s)",
739 snmp_msg_get_versionstr(pkt->snmp_version),
740 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
741 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
742 iter_var->namelen), lacks_instance_id ? "true" : "false");
743
744 if (lacks_instance_id) {
745 oid_t *oid;
746 unsigned int oidlen;
747
748 /* For GetNextRequest-PDUs, a request for "A", without instance
749 * identifier, gets the response of "A.0", since "A" comes before
750 * "A.0". (This does not hold true for GetRequest-PDUs.)
751 */
752
753 oidlen = iter_var->namelen + 1;
754 oid = pcalloc(pkt->pool, oidlen * sizeof(oid_t));
755 memmove(oid, iter_var->name, iter_var->namelen * sizeof(oid_t));
756
757 mib_idx = snmp_mib_get_idx(oid, oidlen, NULL);
758 if (mib_idx < 0) {
759 lacks_instance_id = FALSE;
760 unknown_oid = TRUE;
761
762 } else {
763 mib_idx--;
764 }
765
766 } else {
767 /* Try to find the "nearest" OID. */
768 mib_idx = snmp_mib_get_nearest_idx(iter_var->name, iter_var->namelen);
769 if (mib_idx < 0) {
770 unknown_oid = TRUE;
771
772 } else {
773 mib_idx--;
774 }
775 }
776
777 if (unknown_oid) {
778 /* If SNMPv1, then set the err_code/err_idx values, and duplicate the
779 * varlist.
780 *
781 * If SNMPv2/SNMPv3, then leave err_code/err_idex values set to zero,
782 * but create a var of exception 'noSuchObject' or 'noSuchInstance' as
783 * appropriate.
784 */
785
786 switch (pkt->snmp_version) {
787 case SNMP_PROTOCOL_VERSION_1:
788 pkt->resp_pdu->err_code = SNMP_ERR_NO_SUCH_NAME;
789 pkt->resp_pdu->err_idx = var_count + 1;
790 pkt->resp_pdu->varlist = snmp_smi_dup_var(pkt->pool,
791 pkt->req_pdu->varlist);
792 pkt->resp_pdu->varlistlen = pkt->req_pdu->varlistlen;
793 break;
794
795 case SNMP_PROTOCOL_VERSION_2:
796 case SNMP_PROTOCOL_VERSION_3:
797 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
798 iter_var->namelen, SNMP_SMI_NO_SUCH_OBJECT);
799 break;
800 }
801
802 if (resp_var == NULL) {
803 return 0;
804 }
805 }
806 }
807
808 pr_trace_msg(trace_channel, 19,
809 "%s %s for OID %s at MIB index %d (max index %d)",
810 snmp_msg_get_versionstr(pkt->snmp_version),
811 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
812 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
813 iter_var->namelen), mib_idx, max_idx);
814
815 next_idx = mib_idx + 1;
816
817 if (next_idx < max_idx) {
818 /* Get the next MIB in the list. Note that we may need to continue
819 * looking for a short while, as some arcs are for notifications only.
820 */
821 mib = snmp_mib_get_by_idx(next_idx);
822 while (mib != NULL &&
823 (mib->mib_enabled == FALSE ||
824 mib->notify_only == TRUE)) {
825 pr_signals_handle();
826
827 if (next_idx > max_idx) {
828 break;
829 }
830
831 mib = snmp_mib_get_by_idx(++next_idx);
832 }
833 }
834
835 if (mib_idx >= max_idx ||
836 next_idx > max_idx) {
837 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
838 "%s %s of last OID %s",
839 snmp_msg_get_versionstr(pkt->snmp_version),
840 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
841 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
842 iter_var->namelen));
843
844 /* If SNMPv1, then set the err_code/err_idx values, and duplicate the
845 * varlist.
846 *
847 * If SNMPv2/SNMPv3, then leave err_code/err_idex values set to zero, but
848 * create a var of value 'endOfMibView'.
849 */
850
851 switch (pkt->snmp_version) {
852 case SNMP_PROTOCOL_VERSION_1:
853 pkt->resp_pdu->err_code = SNMP_ERR_NO_SUCH_NAME;
854 pkt->resp_pdu->err_idx = var_count + 1;
855 pkt->resp_pdu->varlist = snmp_smi_dup_var(pkt->pool,
856 pkt->req_pdu->varlist);
857 pkt->resp_pdu->varlistlen = pkt->req_pdu->varlistlen;
858 break;
859
860 case SNMP_PROTOCOL_VERSION_2:
861 case SNMP_PROTOCOL_VERSION_3:
862 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
863 iter_var->namelen, SNMP_SMI_END_OF_MIB_VIEW);
864 break;
865 }
866
867 if (resp_var == NULL) {
868 return 0;
869 }
870 }
871
872 if (resp_var == NULL) {
873 /* Get the next MIB in the list. */
874 mib = snmp_mib_get_by_idx(next_idx);
875
876 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
877 "%s %s of OID %s (%s)", snmp_msg_get_versionstr(pkt->snmp_version),
878 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
879 snmp_asn1_get_oidstr(iter_var->pool, mib->mib_oid, mib->mib_oidlen),
880 mib->mib_name);
881
882 res = snmp_db_get_value(pkt->pool, mib->db_field, &mib_int, &mib_str,
883 &mib_strlen);
884
885 /* XXX Response with genErr instead? */
886 if (res < 0) {
887 int xerrno = errno;
888
889 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
890 "error retrieving database value for field %s: %s",
891 snmp_db_get_fieldstr(pkt->pool, mib->db_field), strerror(xerrno));
892 errno = xerrno;
893 return -1;
894 }
895
896 resp_var = snmp_smi_create_var(pkt->pool, mib->mib_oid, mib->mib_oidlen,
897 mib->smi_type, mib_int, mib_str, mib_strlen);
898 }
899
900 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var, resp_var);
901 }
902
903 pkt->resp_pdu->varlist = head_var;
904 pkt->resp_pdu->varlistlen = var_count;
905
906 return 0;
907 }
908
snmp_agent_handle_getbulk(struct snmp_packet * pkt)909 static int snmp_agent_handle_getbulk(struct snmp_packet *pkt) {
910 register unsigned int i = 0;
911 struct snmp_var *iter_var = NULL, *head_var = NULL, *tail_var = NULL;
912 unsigned int var_count = 0;
913 int max_idx, res;
914
915 /* SNMPv1 does not support GetBulkRequest PDUs. */
916 if (pkt->snmp_version == SNMP_PROTOCOL_VERSION_1) {
917 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
918 "GetBulkRequest-PDU not supported for %s packets, rejecting "
919 "invalid request", snmp_msg_get_versionstr(pkt->snmp_version));
920 errno = EINVAL;
921 return -1;
922 }
923
924 if (pkt->req_pdu->varlist == NULL) {
925 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
926 "missing request PDU variable bindings list, rejecting invalid request");
927 errno = EINVAL;
928 return -1;
929 }
930
931 /* If non-repeaters is zero, and max-repetitions is zero, treat this as
932 * just another GetNextRequest PDU.
933 */
934 if (pkt->req_pdu->non_repeaters == 0 &&
935 pkt->req_pdu->max_repetitions == 0) {
936 return snmp_agent_handle_getnext(pkt);
937 }
938
939 pkt->resp_pdu = snmp_pdu_dup(pkt->pool, pkt->req_pdu);
940 pkt->resp_pdu->request_type = SNMP_PDU_RESPONSE;
941
942 if (pkt->req_pdu->varlistlen > snmp_max_variables) {
943 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
944 "%s %s of too many OIDs (%u, max %u)",
945 snmp_msg_get_versionstr(pkt->snmp_version),
946 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
947 pkt->req_pdu->varlistlen, snmp_max_variables);
948
949 pkt->resp_pdu->err_code = SNMP_ERR_TOO_BIG;
950 pkt->resp_pdu->err_idx = 0;
951
952 return 0;
953 }
954
955 max_idx = snmp_mib_get_max_idx();
956
957 /* First, deal with the non_repeaters count. This part is just like handling
958 * any other GetNextRequest PDU.
959 */
960 for (i = 0, iter_var = pkt->req_pdu->varlist;
961 i < pkt->req_pdu->non_repeaters && iter_var != NULL;
962 i++, iter_var = iter_var->next) {
963 struct snmp_mib *mib = NULL;
964 struct snmp_var *resp_var = NULL;
965 int mib_idx = -1, lacks_instance_id = FALSE;
966 int32_t mib_int = -1;
967 char *mib_str = NULL;
968 size_t mib_strlen = 0;
969
970 pr_signals_handle();
971
972 mib_idx = snmp_mib_get_idx(iter_var->name, iter_var->namelen,
973 &lacks_instance_id);
974 if (mib_idx < 0) {
975 int unknown_oid = FALSE;
976
977 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
978 "%s %s of unknown OID %s (lacks instance ID = %s)",
979 snmp_msg_get_versionstr(pkt->snmp_version),
980 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
981 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
982 iter_var->namelen), lacks_instance_id ? "true" : "false");
983
984 if (lacks_instance_id) {
985 oid_t *oid;
986 unsigned int oidlen;
987
988 /* For GetBulkRequest-PDUs, a request for "A", without instance
989 * identifier, gets the response of "A.0", since "A" comes before
990 * "A.0". (This does not hold true for GetRequest-PDUs.)
991 */
992
993 oidlen = iter_var->namelen + 1;
994 oid = pcalloc(pkt->pool, oidlen * sizeof(oid_t));
995 memmove(oid, iter_var->name, iter_var->namelen * sizeof(oid_t));
996
997 mib_idx = snmp_mib_get_idx(oid, oidlen, NULL);
998 if (mib_idx < 0) {
999 lacks_instance_id = FALSE;
1000 unknown_oid = TRUE;
1001
1002 } else {
1003 mib_idx--;
1004 }
1005
1006 } else {
1007 /* Try to find the "nearest" OID. */
1008 mib_idx = snmp_mib_get_nearest_idx(iter_var->name, iter_var->namelen);
1009 if (mib_idx < 0) {
1010 unknown_oid = TRUE;
1011
1012 } else {
1013 mib_idx--;
1014 }
1015 }
1016
1017 if (unknown_oid) {
1018 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
1019 iter_var->namelen, lacks_instance_id ? SNMP_SMI_NO_SUCH_INSTANCE :
1020 SNMP_SMI_NO_SUCH_OBJECT);
1021 }
1022 }
1023
1024 pr_trace_msg(trace_channel, 19,
1025 "%s %s for OID %s at MIB index %d (max index %d)",
1026 snmp_msg_get_versionstr(pkt->snmp_version),
1027 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1028 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
1029 iter_var->namelen), mib_idx, max_idx);
1030
1031 if (mib_idx >= max_idx) {
1032 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1033 "%s %s of last OID %s",
1034 snmp_msg_get_versionstr(pkt->snmp_version),
1035 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1036 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
1037 iter_var->namelen));
1038
1039 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
1040 iter_var->namelen, SNMP_SMI_END_OF_MIB_VIEW);
1041 }
1042
1043 if (resp_var == NULL) {
1044 /* Get the next MIB in the list. */
1045 mib = snmp_mib_get_by_idx(mib_idx + 1);
1046
1047 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1048 "%s %s of OID %s (%s)", snmp_msg_get_versionstr(pkt->snmp_version),
1049 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1050 snmp_asn1_get_oidstr(iter_var->pool, mib->mib_oid, mib->mib_oidlen),
1051 mib->mib_name);
1052
1053 res = snmp_db_get_value(pkt->pool, mib->db_field, &mib_int, &mib_str,
1054 &mib_strlen);
1055
1056 /* XXX Response with genErr instead? */
1057 if (res < 0) {
1058 int xerrno = errno;
1059
1060 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1061 "error retrieving database value for field %s: %s",
1062 snmp_db_get_fieldstr(pkt->pool, mib->db_field), strerror(xerrno));
1063 errno = xerrno;
1064 return -1;
1065 }
1066
1067 resp_var = snmp_smi_create_var(pkt->pool, mib->mib_oid, mib->mib_oidlen,
1068 mib->smi_type, mib_int, mib_str, mib_strlen);
1069 }
1070
1071 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var, resp_var);
1072 }
1073
1074 /* Now, deal with the max_repetitions count. Keep in mind the max_variables
1075 * limits.
1076 *
1077 * The iter_var variable should (after the above non_repeaters loop) be
1078 * pointing at the starting variable for us to process in the max_repetitions
1079 * loop.
1080 */
1081 for (; iter_var; iter_var = iter_var->next) {
1082 register unsigned int j;
1083 struct snmp_mib *mib = NULL;
1084 struct snmp_var *resp_var = NULL;
1085 int mib_idx = -1, lacks_instance_id = FALSE;
1086 int32_t mib_int = -1;
1087 char *mib_str = NULL;
1088 size_t mib_strlen = 0;
1089
1090 mib_idx = snmp_mib_get_idx(iter_var->name, iter_var->namelen,
1091 &lacks_instance_id);
1092 if (mib_idx < 0) {
1093 int unknown_oid = FALSE;
1094
1095 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1096 "%s %s of unknown OID %s (lacks instance ID = %s)",
1097 snmp_msg_get_versionstr(pkt->snmp_version),
1098 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1099 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
1100 iter_var->namelen), lacks_instance_id ? "true" : "false");
1101
1102 if (lacks_instance_id) {
1103 oid_t *oid;
1104 unsigned int oidlen;
1105
1106 /* For GetBulkRequest-PDUs, a request for "A", without instance
1107 * identifier, gets the response of "A.0", since "A" comes before
1108 * "A.0". (This does not hold true for GetRequest-PDUs.)
1109 */
1110
1111 oidlen = iter_var->namelen + 1;
1112 oid = pcalloc(pkt->pool, oidlen * sizeof(oid_t));
1113 memmove(oid, iter_var->name, iter_var->namelen * sizeof(oid_t));
1114
1115 mib_idx = snmp_mib_get_idx(oid, oidlen, NULL);
1116 if (mib_idx < 0) {
1117 lacks_instance_id = FALSE;
1118 unknown_oid = TRUE;
1119
1120 } else {
1121 mib_idx--;
1122 }
1123
1124 } else {
1125 /* Try to find the "nearest" OID. */
1126 mib_idx = snmp_mib_get_nearest_idx(iter_var->name, iter_var->namelen);
1127 if (mib_idx < 0) {
1128 unknown_oid = TRUE;
1129
1130 } else {
1131 mib_idx--;
1132 }
1133 }
1134
1135 if (unknown_oid) {
1136 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
1137 iter_var->namelen, lacks_instance_id ? SNMP_SMI_NO_SUCH_INSTANCE :
1138 SNMP_SMI_NO_SUCH_OBJECT);
1139 }
1140 }
1141
1142 if (resp_var == NULL) {
1143 pr_trace_msg(trace_channel, 19,
1144 "%s %s for OID %s at MIB index %d (max index %d)",
1145 snmp_msg_get_versionstr(pkt->snmp_version),
1146 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1147 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
1148 iter_var->namelen), mib_idx, max_idx);
1149
1150 if (mib_idx >= max_idx) {
1151 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1152 "%s %s of last OID %s",
1153 snmp_msg_get_versionstr(pkt->snmp_version),
1154 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1155 snmp_asn1_get_oidstr(pkt->req_pdu->pool, iter_var->name,
1156 iter_var->namelen));
1157
1158 resp_var = snmp_smi_create_exception(pkt->pool, iter_var->name,
1159 iter_var->namelen, SNMP_SMI_END_OF_MIB_VIEW);
1160 }
1161
1162 if (resp_var == NULL) {
1163 struct snmp_mib *prev_mib = NULL;
1164
1165 for (j = 1; j <= pkt->req_pdu->max_repetitions; j++) {
1166 int next_idx;
1167
1168 pr_signals_handle();
1169
1170 /* Get the next MIB in the list. */
1171 next_idx = mib_idx + j;
1172 if (next_idx < max_idx) {
1173 mib = snmp_mib_get_by_idx(next_idx);
1174 while (mib != NULL &&
1175 (mib->mib_enabled == FALSE ||
1176 mib->notify_only == TRUE)) {
1177 pr_signals_handle();
1178
1179 if (next_idx > max_idx) {
1180 break;
1181 }
1182
1183 mib = snmp_mib_get_by_idx(++next_idx);
1184 }
1185 }
1186
1187 mib = snmp_mib_get_by_idx(next_idx);
1188 if (mib != NULL) {
1189 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1190 "%s %s of OID %s (%s)",
1191 snmp_msg_get_versionstr(pkt->snmp_version),
1192 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type),
1193 snmp_asn1_get_oidstr(iter_var->pool, mib->mib_oid,
1194 mib->mib_oidlen), mib->mib_name);
1195
1196 res = snmp_db_get_value(pkt->pool, mib->db_field, &mib_int,
1197 &mib_str, &mib_strlen);
1198
1199 /* XXX Response with genErr instead? */
1200 if (res < 0) {
1201 int xerrno = errno;
1202
1203 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1204 "error retrieving database value for field %s: %s",
1205 snmp_db_get_fieldstr(pkt->pool, mib->db_field),
1206 strerror(xerrno));
1207 errno = xerrno;
1208 return -1;
1209 }
1210
1211 resp_var = snmp_smi_create_var(pkt->pool, mib->mib_oid,
1212 mib->mib_oidlen, mib->smi_type, mib_int, mib_str, mib_strlen);
1213 prev_mib = mib;
1214
1215 } else {
1216 oid_t *end_oid;
1217 unsigned int end_oidlen;
1218
1219 /* We want to use the OID of the last MIB we processed, or the
1220 * last OID in the request, whichever is present.
1221 */
1222 if (prev_mib != NULL) {
1223 end_oid = prev_mib->mib_oid;
1224 end_oidlen = prev_mib->mib_oidlen;
1225
1226 } else {
1227 end_oid = iter_var->name;
1228 end_oidlen = iter_var->namelen;
1229 }
1230
1231 resp_var = snmp_smi_create_exception(pkt->pool, end_oid,
1232 end_oidlen, SNMP_SMI_END_OF_MIB_VIEW);
1233 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var,
1234 resp_var);
1235 break;
1236 }
1237
1238 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var,
1239 resp_var);
1240 }
1241
1242 } else {
1243 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var, resp_var);
1244 }
1245
1246 } else {
1247 var_count = snmp_smi_util_add_list_var(&head_var, &tail_var, resp_var);
1248 }
1249 }
1250
1251 pkt->resp_pdu->varlist = head_var;
1252 pkt->resp_pdu->varlistlen = var_count;
1253
1254 return 0;
1255 }
1256
snmp_agent_handle_set(struct snmp_packet * pkt)1257 static int snmp_agent_handle_set(struct snmp_packet *pkt) {
1258
1259 /* We currently don't support any SET operations. */
1260
1261 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1262 "%s %s not supported", snmp_msg_get_versionstr(pkt->snmp_version),
1263 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type));
1264
1265 /* Set the err_code/err_idx values, and duplicate the varlist. The only
1266 * difference is that SNMPv1 gets NO_SUCH_NAME, and SNMPv2/SNMPv3 get
1267 * NO_ACCESS.
1268 */
1269
1270 pkt->resp_pdu = snmp_pdu_dup(pkt->pool, pkt->req_pdu);
1271 pkt->resp_pdu->request_type = SNMP_PDU_RESPONSE;
1272
1273 switch (pkt->snmp_version) {
1274 case SNMP_PROTOCOL_VERSION_1:
1275 pkt->resp_pdu->err_code = SNMP_ERR_NO_SUCH_NAME;
1276 pkt->resp_pdu->err_idx = 1;
1277 pkt->resp_pdu->varlist = snmp_smi_dup_var(pkt->pool,
1278 pkt->req_pdu->varlist);
1279 pkt->resp_pdu->varlistlen = pkt->req_pdu->varlistlen;
1280 break;
1281
1282 case SNMP_PROTOCOL_VERSION_2:
1283 case SNMP_PROTOCOL_VERSION_3:
1284 pkt->resp_pdu->err_code = SNMP_ERR_NO_ACCESS;
1285 pkt->resp_pdu->err_idx = 1;
1286 pkt->resp_pdu->varlist = snmp_smi_dup_var(pkt->pool,
1287 pkt->req_pdu->varlist);
1288 pkt->resp_pdu->varlistlen = pkt->req_pdu->varlistlen;
1289 break;
1290 }
1291
1292 return 0;
1293 }
1294
snmp_agent_handle_request(struct snmp_packet * pkt)1295 static int snmp_agent_handle_request(struct snmp_packet *pkt) {
1296 int res;
1297
1298 switch (pkt->req_pdu->request_type) {
1299 case SNMP_PDU_GET:
1300 res = snmp_agent_handle_get(pkt);
1301 break;
1302
1303 case SNMP_PDU_GETNEXT:
1304 res = snmp_agent_handle_getnext(pkt);
1305 break;
1306
1307 case SNMP_PDU_GETBULK:
1308 res = snmp_agent_handle_getbulk(pkt);
1309 break;
1310
1311 case SNMP_PDU_SET:
1312 res = snmp_agent_handle_set(pkt);
1313 break;
1314
1315 default:
1316 errno = EINVAL;
1317 res = -1;
1318 }
1319
1320 return res;
1321 }
1322
snmp_agent_handle_packet(int sockfd,pr_netaddr_t * agent_addr)1323 static int snmp_agent_handle_packet(int sockfd, pr_netaddr_t *agent_addr) {
1324 int nbytes, res;
1325 struct sockaddr_in from_sockaddr;
1326 socklen_t from_sockaddrlen;
1327 pr_netaddr_t from_addr;
1328 struct snmp_packet *pkt = NULL;
1329
1330 pkt = snmp_packet_create(snmp_pool);
1331
1332 from_sockaddrlen = sizeof(struct sockaddr_in);
1333 nbytes = recvfrom(sockfd, pkt->req_data, pkt->req_datalen, 0,
1334 (struct sockaddr *) &from_sockaddr, &from_sockaddrlen);
1335 if (nbytes < 0) {
1336 int xerrno = errno;
1337
1338 pr_trace_msg(trace_channel, 3,
1339 "error receiving data from socket %d: %s", sockfd, strerror(xerrno));
1340
1341 destroy_pool(pkt->pool);
1342 errno = xerrno;
1343 return -1;
1344 }
1345
1346 pkt->req_datalen = nbytes;
1347
1348 /* XXX Support UDP/IPv6 in the future */
1349
1350 pr_netaddr_clear(&from_addr);
1351 pr_netaddr_set_family(&from_addr, AF_INET);
1352 pr_netaddr_set_sockaddr(&from_addr, (struct sockaddr *) &from_sockaddr);
1353
1354 pkt->remote_addr = &from_addr;
1355
1356 pr_trace_msg(trace_channel, 3,
1357 "read %d UDP bytes from %s#%u", nbytes,
1358 pr_netaddr_get_ipstr(pkt->remote_addr),
1359 ntohs(pr_netaddr_get_port(pkt->remote_addr)));
1360
1361 res = snmp_db_incr_value(pkt->pool, SNMP_DB_SNMP_F_PKTS_RECVD_TOTAL, 1);
1362 if (res < 0) {
1363 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1364 "error incrementing SNMP database for "
1365 "snmp.packetsReceivedTotal: %s", strerror(errno));
1366 }
1367
1368 pkt->remote_class = pr_class_match_addr(&from_addr);
1369 if (pkt->remote_class != NULL) {
1370 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1371 "received %d UDP bytes from client in '%s' class", nbytes,
1372 pkt->remote_class->cls_name);
1373
1374 } else {
1375 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1376 "received %d UDP bytes from client in unknown class", nbytes);
1377 }
1378
1379 /* Check for malicious packets, which forge the from address/port to be
1380 * the same as our listening address/port, trying to induce us to talk
1381 * to ourselves.
1382 */
1383 if (pr_netaddr_cmp(&from_addr, agent_addr) == 0 &&
1384 pr_netaddr_get_port(&from_addr) == pr_netaddr_get_port(agent_addr)) {
1385 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1386 "rejecting forged UDP packet from %s#%u (appears to be from "
1387 "SNMPAgent %s#%u)",
1388 pr_netaddr_get_ipstr(&from_addr), ntohs(pr_netaddr_get_port(&from_addr)),
1389 pr_netaddr_get_ipstr(agent_addr), ntohs(pr_netaddr_get_port(agent_addr)));
1390
1391 destroy_pool(pkt->pool);
1392 errno = EACCES;
1393 return -1;
1394 }
1395
1396 /* Note: mod_ifsession does NOT affect mod_snmp ACLs; use <Limit SNMP> */
1397
1398 if (snmp_limits_allow(main_server->conf, pkt) == FALSE) {
1399 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1400 "UDP packet from %s#%u denied by <Limit SNMP> rules",
1401 pr_netaddr_get_ipstr(&from_addr), ntohs(pr_netaddr_get_port(&from_addr)));
1402
1403 destroy_pool(pkt->pool);
1404 errno = EACCES;
1405 return -1;
1406 }
1407
1408 res = snmp_msg_read(pkt->pool, &(pkt->req_data), &(pkt->req_datalen),
1409 &(pkt->community), &(pkt->community_len), &(pkt->snmp_version),
1410 &(pkt->req_pdu));
1411 if (res < 0) {
1412 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1413 "error reading SNMP message from UDP packet: %s", strerror(errno));
1414
1415 destroy_pool(pkt->pool);
1416 errno = EINVAL;
1417 return -1;
1418 }
1419
1420 /* Check ACLs (community, SNMPv3, etc) */
1421 res = snmp_security_check(pkt);
1422 if (res < 0) {
1423 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1424 "%s message does not contain correct authentication info, "
1425 "ignoring message", snmp_msg_get_versionstr(pkt->snmp_version));
1426
1427 destroy_pool(pkt->pool);
1428 errno = EINVAL;
1429 return -1;
1430 }
1431
1432 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1433 "read SNMP message for %s, community = '%s', request ID %ld, "
1434 "request type '%s'", snmp_msg_get_versionstr(pkt->snmp_version),
1435 pkt->community, pkt->req_pdu->request_id,
1436 snmp_pdu_get_request_type_desc(pkt->req_pdu->request_type));
1437
1438 res = snmp_agent_handle_request(pkt);
1439 if (res < 0) {
1440 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1441 "error handling SNMP message: %s", strerror(errno));
1442 destroy_pool(pkt->pool);
1443 errno = EINVAL;
1444 return -1;
1445 }
1446
1447 /* We're done with the request PDU here. */
1448 destroy_pool(pkt->req_pdu->pool);
1449 pkt->req_pdu = NULL;
1450
1451 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1452 "writing SNMP message for %s, community = '%s', request ID %ld, "
1453 "request type '%s'", snmp_msg_get_versionstr(pkt->snmp_version),
1454 pkt->community, pkt->resp_pdu->request_id,
1455 snmp_pdu_get_request_type_desc(pkt->resp_pdu->request_type));
1456
1457 res = snmp_msg_write(pkt->pool, &(pkt->resp_data), &(pkt->resp_datalen),
1458 pkt->community, pkt->community_len, pkt->snmp_version, pkt->resp_pdu);
1459 if (res < 0) {
1460 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1461 "error writing SNMP message to UDP packet: %s", strerror(errno));
1462
1463 destroy_pool(pkt->pool);
1464 errno = EINVAL;
1465 return -1;
1466 }
1467
1468 snmp_packet_write(snmp_pool, sockfd, pkt);
1469
1470 destroy_pool(pkt->pool);
1471 return 0;
1472 }
1473
snmp_agent_listen(pr_netaddr_t * agent_addr)1474 static int snmp_agent_listen(pr_netaddr_t *agent_addr) {
1475 int family, res, sockfd;
1476
1477 family = pr_netaddr_get_family(agent_addr);
1478 sockfd = socket(family, SOCK_DGRAM, snmp_proto_udp);
1479 if (sockfd < 0) {
1480 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1481 "unable to create %s UDP socket: %s",
1482 family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
1483 exit(1);
1484 }
1485
1486 res = bind(sockfd, pr_netaddr_get_sockaddr(agent_addr),
1487 pr_netaddr_get_sockaddr_len(agent_addr));
1488 if (res < 0) {
1489 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1490 "unable to bind %s UDP socket to %s#%u: %s",
1491 family == AF_INET ? "IPv4" : "IPv6",
1492 pr_netaddr_get_ipstr(agent_addr),
1493 ntohs(pr_netaddr_get_port(agent_addr)), strerror(errno));
1494 (void) close(sockfd);
1495 exit(1);
1496
1497 } else {
1498 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1499 "bound %s UDP socket to %s#%u", family == AF_INET ? "IPv4" : "IPv6",
1500 pr_netaddr_get_ipstr(agent_addr),
1501 ntohs(pr_netaddr_get_port(agent_addr)));
1502 }
1503
1504 return sockfd;
1505 }
1506
snmp_agent_loop(array_header * sockfds,array_header * addrs)1507 static void snmp_agent_loop(array_header *sockfds, array_header *addrs) {
1508 fd_set listen_fds;
1509 struct timeval tv;
1510 int fd, res;
1511
1512 while (TRUE) {
1513 register unsigned int i;
1514 int maxfd = -1, *fds;
1515 pr_netaddr_t **agent_addrs;
1516
1517 /* XXX Is it necessary to even have a timeout? We could simply block
1518 * in select(2) indefinitely, until either an event arrives or we are
1519 * interrupted by a signal.
1520 *
1521 * Yes, we DO need a timeout here, specifically to poll the trap table
1522 * for any trap-generating state. Rather than using a timer and using
1523 * SIGALRM handling, we can reuse this event loop.
1524 */
1525 tv.tv_sec = 60;
1526 tv.tv_usec = 0L;
1527
1528 /* To implement notification criteria/thresholds, we poll for the
1529 * necessary conditions here.
1530 */
1531 snmp_notify_poll_cond();
1532
1533 FD_ZERO(&listen_fds);
1534
1535 fds = sockfds->elts;
1536 agent_addrs = addrs->elts;
1537
1538 for (i = 0; i < sockfds->nelts; i++) {
1539 fd = fds[i];
1540 FD_SET(fd, &listen_fds);
1541
1542 if (fd > maxfd) {
1543 maxfd = fd;
1544 }
1545 }
1546
1547 res = select(maxfd + 1, &listen_fds, NULL, NULL, &tv);
1548 if (res == 0) {
1549 /* Select timeout reached. Just try again. */
1550 continue;
1551 }
1552
1553 if (res < 0) {
1554 if (errno == EINTR) {
1555 pr_signals_handle();
1556 continue;
1557 }
1558
1559 } else {
1560 for (i = 0; i < sockfds->nelts; i++) {
1561 pr_netaddr_t *agent_addr;
1562
1563 fd = fds[i];
1564 agent_addr = agent_addrs[i];
1565
1566 if (FD_ISSET(fd, &listen_fds)) {
1567 res = snmp_agent_handle_packet(fd, agent_addr);
1568 if (res < 0) {
1569 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1570 "error handling SNMP packet: %s", strerror(errno));
1571 }
1572 }
1573 }
1574 }
1575 }
1576 }
1577
snmp_agent_start(const char * tables_dir,int agent_type,array_header * agent_addrs)1578 static pid_t snmp_agent_start(const char *tables_dir, int agent_type,
1579 array_header *agent_addrs) {
1580 register unsigned int i;
1581 pid_t agent_pid;
1582 char *agent_chroot = NULL;
1583 rlim_t curr_nproc, max_nproc;
1584 array_header *agent_fds = NULL;
1585
1586 agent_pid = fork();
1587 switch (agent_pid) {
1588 case -1:
1589 pr_log_pri(PR_LOG_ALERT,
1590 MOD_SNMP_VERSION ": unable to fork: %s", strerror(errno));
1591 return 0;
1592
1593 case 0:
1594 /* We're the child. */
1595 break;
1596
1597 default:
1598 /* We're the parent. */
1599 return agent_pid;
1600 }
1601
1602 /* Reset the cached PID, so that it is correctly reflected in the logs. */
1603 session.pid = getpid();
1604
1605 pr_trace_msg("snmp", 3, "forked SNMP agent PID %lu",
1606 (unsigned long) session.pid);
1607
1608 snmp_daemonize(tables_dir);
1609
1610 /* Install our own signal handlers (mostly to ignore signals) */
1611 (void) signal(SIGALRM, SIG_IGN);
1612 (void) signal(SIGHUP, SIG_IGN);
1613 (void) signal(SIGUSR1, SIG_IGN);
1614 (void) signal(SIGUSR2, SIG_IGN);
1615
1616 /* Remove our event listeners. */
1617 pr_event_unregister(&snmp_module, NULL, NULL);
1618
1619 /* XXX Check the agent_type variable, to see if we are a master agent or
1620 * an AgentX sub-agent.
1621 */
1622
1623 for (i = 0; i < agent_addrs->nelts; i++) {
1624 pr_netaddr_t *agent_addr, **addrs;
1625 int agent_fd;
1626
1627 addrs = agent_addrs->elts;
1628 agent_addr = addrs[i];
1629
1630 agent_fd = snmp_agent_listen(agent_addr);
1631 if (agent_fd < 0) {
1632 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1633 "unable to create listening socket for SNMP agent process: %s",
1634 strerror(errno));
1635 exit(0);
1636 }
1637
1638 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1639 "SNMP agent process listening on %s UDP %s#%u",
1640 pr_netaddr_get_family(agent_addr) == AF_INET ? "IPv4" : "IPv6",
1641 pr_netaddr_get_ipstr(agent_addr), ntohs(pr_netaddr_get_port(agent_addr)));
1642
1643 if (agent_fds == NULL) {
1644 agent_fds = make_array(snmp_pool, 1, sizeof(int));
1645 }
1646
1647 *((int *) push_array(agent_fds)) = agent_fd;
1648 }
1649
1650 PRIVS_ROOT
1651
1652 if (getuid() == PR_ROOT_UID) {
1653 int res;
1654
1655 /* Chroot to the SNMPTables/empty/ directory before dropping root privs. */
1656
1657 agent_chroot = pdircat(snmp_pool, tables_dir, "empty", NULL);
1658 res = chroot(agent_chroot);
1659 if (res < 0) {
1660 int xerrno = errno;
1661
1662 PRIVS_RELINQUISH
1663
1664 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1665 "unable to chroot to SNMPTables/empty/ directory '%s': %s",
1666 agent_chroot, strerror(xerrno));
1667 exit(0);
1668 }
1669
1670 if (chdir("/") < 0) {
1671 int xerrno = errno;
1672
1673 PRIVS_RELINQUISH
1674
1675 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1676 "unable to chdir to root directory within chroot: %s",
1677 strerror(xerrno));
1678 exit(0);
1679 }
1680 }
1681
1682 pr_proctitle_set("(listening for SNMP packets)");
1683
1684 /* Make the SNMP process have the identity of the configured daemon
1685 * User/Group.
1686 */
1687 session.uid = geteuid();
1688 session.gid = getegid();
1689 PRIVS_REVOKE
1690
1691 if (agent_chroot != NULL) {
1692 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1693 "SNMP agent process running with UID %s, GID %s, restricted to '%s'",
1694 pr_uid2str(snmp_pool, getuid()), pr_gid2str(snmp_pool, getgid()),
1695 agent_chroot);
1696
1697 } else {
1698 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1699 "SNMP agent process running with UID %s, GID %s, located in '%s'",
1700 pr_uid2str(snmp_pool, getuid()), pr_gid2str(snmp_pool, getgid()),
1701 getcwd(NULL, 0));
1702 }
1703
1704 /* Once we have chrooted, and dropped root privs completely, we can now
1705 * lower our nproc resource limit, so that we cannot fork any new
1706 * processed. We should not be doing so, and we want to mitigate any
1707 * possible exploitation.
1708 */
1709 if (pr_rlimit_get_nproc(&curr_nproc, NULL) == 0) {
1710 /* Override whatever the configured nproc is; we only want 1. */
1711 curr_nproc = 1;
1712
1713 max_nproc = curr_nproc;
1714
1715 if (pr_rlimit_set_nproc(curr_nproc, max_nproc) < 0) {
1716 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1717 "error setting nproc resource limits to %lu: %s",
1718 (unsigned long) max_nproc, strerror(errno));
1719
1720 } else {
1721 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1722 "set nproc resource limits to %lu", (unsigned long) max_nproc);
1723 }
1724
1725 } else {
1726 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1727 "error getting nproc limits: %s", strerror(errno));
1728 }
1729
1730 snmp_agent_loop(agent_fds, agent_addrs);
1731
1732 /* When we are done, we simply exit. */;
1733 pr_trace_msg("snmp", 3, "SNMP agent PID %lu exiting",
1734 (unsigned long) session.pid);
1735 exit(0);
1736 }
1737
snmp_agent_stop(pid_t agent_pid)1738 static void snmp_agent_stop(pid_t agent_pid) {
1739 int res, status;
1740 time_t start_time = time(NULL);
1741
1742 if (agent_pid == 0) {
1743 /* Nothing to do. */
1744 return;
1745 }
1746
1747 pr_trace_msg("snmp", 3, "stopping agent PID %lu", (unsigned long) agent_pid);
1748
1749 /* Litmus test: is the SNMP agent process still around? If not, there's
1750 * nothing for us to do.
1751 */
1752 res = kill(agent_pid, 0);
1753 if (res < 0 &&
1754 errno == ESRCH) {
1755 return;
1756 }
1757
1758 res = kill(agent_pid, SIGTERM);
1759 if (res < 0) {
1760 int xerrno = errno;
1761
1762 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1763 "error sending SIGTERM (signal %d) to SNMP agent process ID %lu: %s",
1764 SIGTERM, (unsigned long) agent_pid, strerror(xerrno));
1765 }
1766
1767 /* Poll every 500 millsecs. */
1768 pr_timer_usleep(500 * 1000);
1769
1770 res = waitpid(agent_pid, &status, WNOHANG);
1771 while (res <= 0) {
1772 if (res < 0) {
1773 if (errno == EINTR) {
1774 pr_signals_handle();
1775 continue;
1776 }
1777
1778 if (errno == ECHILD) {
1779 /* XXX Maybe we shouldn't be using waitpid(2) here, since the
1780 * main SIGCHLD handler may handle the termination of the SNMP
1781 * agent process?
1782 */
1783
1784 return;
1785 }
1786
1787 if (errno != EINTR) {
1788 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1789 "error waiting for SNMP agent process ID %lu: %s",
1790 (unsigned long) agent_pid, strerror(errno));
1791 status = -1;
1792 break;
1793 }
1794 }
1795
1796 /* Check the time elapsed since we started. */
1797 if ((time(NULL) - start_time) > snmp_agent_timeout) {
1798 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1799 "SNMP agent process ID %lu took longer than timeout (%lu secs) to "
1800 "stop, sending SIGKILL (signal %d)", (unsigned long) agent_pid,
1801 snmp_agent_timeout, SIGKILL);
1802 res = kill(agent_pid, SIGKILL);
1803 if (res < 0) {
1804 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1805 "error sending SIGKILL (signal %d) to SNMP agent process ID %lu: %s",
1806 SIGKILL, (unsigned long) agent_pid, strerror(errno));
1807 }
1808
1809 break;
1810 }
1811
1812 /* Poll every 500 millsecs. */
1813 pr_timer_usleep(500 * 1000);
1814 }
1815
1816 if (WIFEXITED(status)) {
1817 int exit_status;
1818
1819 exit_status = WEXITSTATUS(status);
1820 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1821 "SNMP agent process ID %lu terminated normally, with exit status %d",
1822 (unsigned long) agent_pid, exit_status);
1823 }
1824
1825 if (WIFSIGNALED(status)) {
1826 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1827 "SNMP agent process ID %lu died from signal %d",
1828 (unsigned long) agent_pid, WTERMSIG(status));
1829
1830 if (WCOREDUMP(status)) {
1831 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
1832 "SNMP agent process ID %lu created a coredump",
1833 (unsigned long) agent_pid);
1834 }
1835 }
1836
1837 snmp_agent_pid = 0;
1838 return;
1839 }
1840
1841 /* Configuration handlers
1842 */
1843
1844 /* usage: SNMPAgent "master"|"agentx" address[:port] [...] */
set_snmpagent(cmd_rec * cmd)1845 MODRET set_snmpagent(cmd_rec *cmd) {
1846 register unsigned int i;
1847 config_rec *c;
1848 array_header *agent_addrs;
1849 int agent_type;
1850
1851 if (cmd->argc < 2) {
1852 CONF_ERROR(cmd, "wrong number of parameters");
1853 }
1854 CHECK_CONF(cmd, CONF_ROOT);
1855
1856 if (strncasecmp(cmd->argv[1], "master", 7) == 0) {
1857 agent_type = SNMP_AGENT_TYPE_MASTER;
1858
1859 } else if (strncasecmp(cmd->argv[1], "agentx", 7) == 0) {
1860 agent_type = SNMP_AGENT_TYPE_AGENTX;
1861
1862 } else {
1863 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unsupported SNMP agent type '",
1864 cmd->argv[1], "'", NULL));
1865 }
1866
1867 agent_addrs = make_array(snmp_pool, 1, sizeof(pr_netaddr_t *));
1868
1869 for (i = 2; i < cmd->argc; i++) {
1870 const pr_netaddr_t *agent_addr;
1871 int agent_port = SNMP_DEFAULT_AGENT_PORT;
1872 char *addr = NULL, *ptr;
1873 size_t addrlen;
1874
1875 /* Separate the port out from the address, if present. */
1876 ptr = strrchr(cmd->argv[i], ':');
1877
1878 if (ptr != NULL) {
1879 char *ptr2;
1880
1881 /* We need to handle the following possibilities:
1882 *
1883 * ipv4-addr
1884 * ipv4-addr:port
1885 * [ipv6-addr]
1886 * [ipv6-addr]:port
1887 *
1888 * Thus we check to see if the last ':' occurs before, or after,
1889 * a ']' for an IPv6 address.
1890 */
1891
1892 ptr2 = strrchr(cmd->argv[i], ']');
1893 if (ptr2 != NULL) {
1894 if (ptr2 > ptr) {
1895 /* The found ':' is part of an IPv6 address, not a port delimiter. */
1896 ptr = NULL;
1897 }
1898 }
1899
1900 if (ptr != NULL) {
1901 *ptr = '\0';
1902
1903 agent_port = atoi(ptr + 1);
1904 if (agent_port < 1 ||
1905 agent_port > 65535) {
1906 CONF_ERROR(cmd, "port must be between 1-65535");
1907 }
1908 }
1909 }
1910
1911 addr = cmd->argv[i];
1912 addrlen = strlen(addr);
1913
1914 /* Make sure we can handle an IPv6 address here, e.g.:
1915 *
1916 * [::1]:162
1917 */
1918 if (addrlen > 0 &&
1919 (addr[0] == '[' && addr[addrlen-1] == ']')) {
1920 addr = pstrndup(cmd->pool, addr + 1, addrlen - 2);
1921 }
1922
1923 agent_addr = pr_netaddr_get_addr(snmp_pool, addr, NULL);
1924 if (agent_addr == NULL) {
1925 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to resolve \"", addr, "\"",
1926 NULL));
1927 }
1928
1929 pr_netaddr_set_port((pr_netaddr_t *) agent_addr, htons(agent_port));
1930 *((pr_netaddr_t **) push_array(agent_addrs)) = (pr_netaddr_t *) agent_addr;
1931 }
1932
1933 c = add_config_param(cmd->argv[0], 2, NULL, NULL);
1934 c->argv[0] = palloc(c->pool, sizeof(int));
1935 *((int *) c->argv[0]) = agent_type;
1936 c->argv[1] = agent_addrs;
1937
1938 return PR_HANDLED(cmd);
1939 }
1940
1941 /* usage: SNMPCommunity community */
set_snmpcommunity(cmd_rec * cmd)1942 MODRET set_snmpcommunity(cmd_rec *cmd) {
1943 CHECK_ARGS(cmd, 1);
1944 CHECK_CONF(cmd, CONF_ROOT);
1945
1946 (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
1947 return PR_HANDLED(cmd);
1948 }
1949
1950 /* usage: SNMPEnable on|off */
set_snmpenable(cmd_rec * cmd)1951 MODRET set_snmpenable(cmd_rec *cmd) {
1952 int enabled = -1;
1953 config_rec *c;
1954
1955 CHECK_ARGS(cmd, 1);
1956 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1957
1958 enabled = get_boolean(cmd, 1);
1959 if (enabled == -1) {
1960 CONF_ERROR(cmd, "expected Boolean parameter");
1961 }
1962
1963 c = add_config_param(cmd->argv[0], 1, NULL);
1964 c->argv[0] = palloc(c->pool, sizeof(int));
1965 *((int *) c->argv[0]) = enabled;
1966
1967 return PR_HANDLED(cmd);
1968 }
1969
1970 /* usage: SNMPEngine on|off */
set_snmpengine(cmd_rec * cmd)1971 MODRET set_snmpengine(cmd_rec *cmd) {
1972 int bool = 1;
1973 config_rec *c;
1974
1975 CHECK_ARGS(cmd, 1);
1976 CHECK_CONF(cmd, CONF_ROOT);
1977
1978 bool = get_boolean(cmd, 1);
1979 if (bool == -1)
1980 CONF_ERROR(cmd, "expected Boolean parameter");
1981
1982 c = add_config_param(cmd->argv[0], 1, NULL);
1983 c->argv[0] = pcalloc(c->pool, sizeof(int));
1984 *((int *) c->argv[0]) = bool;
1985
1986 return PR_HANDLED(cmd);
1987 }
1988
1989 /* usage: SNMPLog path|"none" */
set_snmplog(cmd_rec * cmd)1990 MODRET set_snmplog(cmd_rec *cmd) {
1991 CHECK_ARGS(cmd, 1);
1992 CHECK_CONF(cmd, CONF_ROOT);
1993
1994 (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
1995 return PR_HANDLED(cmd);
1996 }
1997
1998 /* usage: SNMPMaxVariables count */
set_snmpmaxvariables(cmd_rec * cmd)1999 MODRET set_snmpmaxvariables(cmd_rec *cmd) {
2000 int count = 0;
2001 config_rec *c;
2002
2003 CHECK_ARGS(cmd, 1);
2004 CHECK_CONF(cmd, CONF_ROOT);
2005
2006 count = atoi(cmd->argv[1]);
2007 if (count < 0) {
2008 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "count '", cmd->argv[1],
2009 "' must be greater than zero", NULL));
2010 }
2011
2012 c = add_config_param(cmd->argv[0], 1, NULL);
2013 c->argv[0] = palloc(c->pool, sizeof(unsigned int));
2014 *((unsigned int *) c->argv[0]) = count;
2015
2016 return PR_HANDLED(cmd);
2017 }
2018
2019 /* usage: SNMPNotify address[:port]
2020 *
2021 * XXX In the future, allow specifying of notification types/thresholds
2022 */
set_snmpnotify(cmd_rec * cmd)2023 MODRET set_snmpnotify(cmd_rec *cmd) {
2024 config_rec *c;
2025 const pr_netaddr_t *notify_addr;
2026 int notify_port = SNMP_DEFAULT_TRAP_PORT;
2027 char *ptr;
2028
2029 if (cmd->argc != 2) {
2030 CONF_ERROR(cmd, "wrong number of parameters");
2031 }
2032
2033 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2034
2035 /* Separate the port out from the address, if present.
2036 *
2037 * XXX Make sure we can handle an IPv6 address here, e.g.:
2038 *
2039 * [::1]:162
2040 */
2041 ptr = strrchr(cmd->argv[1], ':');
2042 if (ptr != NULL) {
2043 *ptr = '\0';
2044
2045 notify_port = atoi(ptr + 1);
2046 if (notify_port < 1 ||
2047 notify_port > 65535) {
2048 CONF_ERROR(cmd, "port must be between 1-65535");
2049 }
2050 }
2051
2052 c = add_config_param(cmd->argv[0], 1, NULL);
2053
2054 notify_addr = pr_netaddr_get_addr(c->pool, cmd->argv[1], NULL);
2055 if (notify_addr == NULL) {
2056 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to resolve '", cmd->argv[1],
2057 "': ", strerror(errno), NULL));
2058 }
2059
2060 pr_netaddr_set_port((pr_netaddr_t *) notify_addr, htons(notify_port));
2061 c->argv[0] = (void *) notify_addr;
2062
2063 return PR_HANDLED(cmd);
2064 }
2065
2066 /* usage: SNMPOptions opt1 ... optN */
set_snmpoptions(cmd_rec * cmd)2067 MODRET set_snmpoptions(cmd_rec *cmd) {
2068 config_rec *c = NULL;
2069 register unsigned int i;
2070 unsigned long opts = 0UL;
2071
2072 if (cmd->argc-1 == 0) {
2073 CONF_ERROR(cmd, "wrong number of parameters");
2074 }
2075
2076 CHECK_CONF(cmd, CONF_ROOT);
2077
2078 /* XXX Implement;
2079 *
2080 * NoSNMPv1
2081 * NoSNMPv2
2082 * NoSMPv3
2083 *
2084 * Describe how these relate to SNMPProtocol; or should these be folded
2085 * into SNMPProtocol, e.g.:
2086 *
2087 * SNMPProtocol 2-3
2088 *
2089 * Default SNMPProtocol would then be "1-3".
2090 */
2091
2092 c = add_config_param(cmd->argv[0], 1, NULL);
2093
2094 for (i = 1; i < cmd->argc; i++) {
2095 if (strcmp(cmd->argv[i], "RestartClearsCounters") == 0) {
2096 opts |= SNMP_OPT_RESTART_CLEARS_COUNTERS;
2097
2098 } else {
2099 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SNMPOption '",
2100 cmd->argv[i], "'", NULL));
2101 }
2102 }
2103
2104 c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
2105 *((unsigned long *) c->argv[0]) = opts;
2106
2107 return PR_HANDLED(cmd);
2108 }
2109
2110 /* usage: SNMPTables path */
set_snmptables(cmd_rec * cmd)2111 MODRET set_snmptables(cmd_rec *cmd) {
2112 int res;
2113 struct stat st;
2114 char *path;
2115
2116 CHECK_ARGS(cmd, 1);
2117 CHECK_CONF(cmd, CONF_ROOT);
2118
2119 path = cmd->argv[1];
2120 if (*path != '/') {
2121 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "must be a full path: '", path, "'",
2122 NULL));
2123 }
2124
2125 res = stat(path, &st);
2126 if (res < 0) {
2127 char *agent_chroot;
2128
2129 if (errno != ENOENT) {
2130 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to stat '", path, "': ",
2131 strerror(errno), NULL));
2132 }
2133
2134 pr_log_debug(DEBUG0, MOD_SNMP_VERSION
2135 ": SNMPTables directory '%s' does not exist, creating it", path);
2136
2137 /* Create the directory. */
2138 res = snmp_mkpath(cmd->tmp_pool, path, geteuid(), getegid(), 0755);
2139 if (res < 0) {
2140 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to create directory '",
2141 path, "': ", strerror(errno), NULL));
2142 }
2143
2144 /* Also create the empty/ directory underneath, for the chroot. */
2145 agent_chroot = pdircat(cmd->tmp_pool, path, "empty", NULL);
2146
2147 res = snmp_mkpath(cmd->tmp_pool, agent_chroot, geteuid(), getegid(), 0111);
2148 if (res < 0) {
2149 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to create directory '",
2150 agent_chroot, "': ", strerror(errno), NULL));
2151 }
2152
2153 pr_log_debug(DEBUG2, MOD_SNMP_VERSION
2154 ": created SNMPTables directory '%s'", path);
2155
2156 } else {
2157 char *agent_chroot;
2158
2159 if (!S_ISDIR(st.st_mode)) {
2160 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to use '", path,
2161 ": Not a directory", NULL));
2162 }
2163
2164 /* See if the chroot directory empty/ already exists as well. And enforce
2165 * the permissions on that directory.
2166 */
2167 agent_chroot = pdircat(cmd->tmp_pool, path, "empty", NULL);
2168
2169 res = stat(agent_chroot, &st);
2170 if (res < 0) {
2171 if (errno != ENOENT) {
2172 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to stat '", agent_chroot,
2173 "': ", strerror(errno), NULL));
2174 }
2175
2176 res = snmp_mkpath(cmd->tmp_pool, agent_chroot, geteuid(), getegid(),
2177 0111);
2178 if (res < 0) {
2179 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to create directory '",
2180 agent_chroot, "': ", strerror(errno), NULL));
2181 }
2182
2183 } else {
2184 mode_t dir_mode, expected_mode;
2185
2186 dir_mode = st.st_mode;
2187 dir_mode &= ~S_IFMT;
2188 expected_mode = (S_IXUSR|S_IXGRP|S_IXOTH);
2189
2190 if (dir_mode != expected_mode) {
2191 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "directory '", agent_chroot,
2192 "' has incorrect permissions (not 0111 as required)", NULL));
2193 }
2194 }
2195 }
2196
2197 (void) add_config_param_str(cmd->argv[0], 1, path);
2198 return PR_HANDLED(cmd);
2199 }
2200
2201 /* Command handlers
2202 */
2203
snmp_pre_list(cmd_rec * cmd)2204 MODRET snmp_pre_list(cmd_rec *cmd) {
2205 const char *proto;
2206 int res;
2207
2208 if (snmp_engine == FALSE) {
2209 return PR_DECLINED(cmd);
2210 }
2211
2212 proto = pr_session_get_protocol(0);
2213 if (strcmp(proto, "ftp") == 0) {
2214 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_XFERS_F_DIR_LIST_COUNT,
2215 1);
2216 if (res < 0) {
2217 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2218 "error incrementing SNMP database for "
2219 "ftp.dataTransfers.dirListCount: %s", strerror(errno));
2220 }
2221
2222 } else if (strcmp(proto, "ftps") == 0) {
2223 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_XFERS_F_DIR_LIST_COUNT,
2224 1);
2225 if (res < 0) {
2226 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2227 "error incrementing SNMP database for "
2228 "ftps.tlsDataTransfers.dirListCount: %s", strerror(errno));
2229 }
2230
2231 } else if (strcmp(proto, "sftp") == 0) {
2232 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_SFTP_XFERS_F_DIR_LIST_COUNT,
2233 1);
2234 if (res < 0) {
2235 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2236 "error incrementing SNMP database for "
2237 "sftp.sftpDataTransfers.dirListCount: %s", strerror(errno));
2238 }
2239 }
2240
2241 return PR_DECLINED(cmd);
2242 }
2243
snmp_log_list(cmd_rec * cmd)2244 MODRET snmp_log_list(cmd_rec *cmd) {
2245 const char *proto;
2246 int res;
2247
2248 if (snmp_engine == FALSE) {
2249 return PR_DECLINED(cmd);
2250 }
2251
2252 proto = pr_session_get_protocol(0);
2253 if (strcmp(proto, "ftp") == 0) {
2254 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_XFERS_F_DIR_LIST_COUNT,
2255 -1);
2256 if (res < 0) {
2257 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2258 "error decrementing SNMP database for "
2259 "ftp.dataTransfers.dirListCount: %s", strerror(errno));
2260 }
2261
2262 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_XFERS_F_DIR_LIST_TOTAL,
2263 1);
2264 if (res < 0) {
2265 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2266 "error incrementing SNMP database for "
2267 "ftp.dataTransfers.dirListTotal: %s", strerror(errno));
2268 }
2269
2270 } else if (strcmp(proto, "ftps") == 0) {
2271 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_XFERS_F_DIR_LIST_COUNT,
2272 -1);
2273 if (res < 0) {
2274 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2275 "error decrementing SNMP database for "
2276 "ftps.tlsDataTransfers.dirListCount: %s", strerror(errno));
2277 }
2278
2279 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_XFERS_F_DIR_LIST_TOTAL,
2280 1);
2281 if (res < 0) {
2282 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2283 "error incrementing SNMP database for "
2284 "ftps.tlsDataTransfers.dirListTotal: %s", strerror(errno));
2285 }
2286
2287 } else if (strcmp(proto, "sftp") == 0) {
2288 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_SFTP_XFERS_F_DIR_LIST_COUNT,
2289 -1);
2290 if (res < 0) {
2291 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2292 "error decrementing SNMP database for "
2293 "sftp.sftpDataTransfers.dirListCount: %s", strerror(errno));
2294 }
2295
2296 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_SFTP_XFERS_F_DIR_LIST_TOTAL,
2297 1);
2298 if (res < 0) {
2299 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2300 "error incrementing SNMP database for "
2301 "sftp.sftpDataTransfers.dirListTotal: %s", strerror(errno));
2302 }
2303 }
2304
2305 return PR_DECLINED(cmd);
2306 }
2307
snmp_err_list(cmd_rec * cmd)2308 MODRET snmp_err_list(cmd_rec *cmd) {
2309 const char *proto;
2310 int res;
2311
2312 if (snmp_engine == FALSE) {
2313 return PR_DECLINED(cmd);
2314 }
2315
2316 proto = pr_session_get_protocol(0);
2317
2318 if (strcmp(proto, "ftp") == 0) {
2319 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_XFERS_F_DIR_LIST_COUNT,
2320 -1);
2321 if (res < 0) {
2322 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2323 "error decrementing SNMP database for "
2324 "ftp.dataTransfers.dirListCount: %s", strerror(errno));
2325 }
2326
2327 res = snmp_db_incr_value(cmd->tmp_pool,
2328 SNMP_DB_FTP_XFERS_F_DIR_LIST_ERR_TOTAL, 1);
2329 if (res < 0) {
2330 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2331 "error incrementing SNMP database for "
2332 "ftp.dataTranfers.dirListFailedTotal: %s", strerror(errno));
2333 }
2334
2335 } else if (strcmp(proto, "ftps") == 0) {
2336 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_XFERS_F_DIR_LIST_COUNT,
2337 -1);
2338 if (res < 0) {
2339 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2340 "error decrementing SNMP database for "
2341 "ftps.tlsDataTransfers.dirListCount: %s", strerror(errno));
2342 }
2343
2344 res = snmp_db_incr_value(cmd->tmp_pool,
2345 SNMP_DB_FTPS_XFERS_F_DIR_LIST_ERR_TOTAL, 1);
2346 if (res < 0) {
2347 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2348 "error incrementing SNMP database for "
2349 "ftps.tlsDataTranfers.dirListFailedTotal: %s", strerror(errno));
2350 }
2351
2352 } else if (strcmp(proto, "sftp") == 0) {
2353 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_SFTP_XFERS_F_DIR_LIST_COUNT,
2354 -1);
2355 if (res < 0) {
2356 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2357 "error decrementing SNMP database for "
2358 "sftp.sftpDataTransfers.dirListCount: %s", strerror(errno));
2359 }
2360
2361 res = snmp_db_incr_value(cmd->tmp_pool,
2362 SNMP_DB_SFTP_XFERS_F_DIR_LIST_ERR_TOTAL, 1);
2363 if (res < 0) {
2364 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2365 "error incrementing SNMP database for "
2366 "sftp.sftpDataTranfers.dirListFailedTotal: %s", strerror(errno));
2367 }
2368 }
2369
2370 return PR_DECLINED(cmd);
2371 }
2372
snmp_log_pass(cmd_rec * cmd)2373 MODRET snmp_log_pass(cmd_rec *cmd) {
2374 const char *proto;
2375 int res;
2376
2377 if (snmp_engine == FALSE) {
2378 return PR_DECLINED(cmd);
2379 }
2380
2381 proto = pr_session_get_protocol(0);
2382
2383 if (strcmp(proto, "ftp") == 0) {
2384 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_SESS_F_SESS_COUNT, 1);
2385 if (res < 0) {
2386 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2387 "error incrementing SNMP database for ftp.sessions.sessionCount: %s",
2388 strerror(errno));
2389 }
2390
2391 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_SESS_F_SESS_TOTAL, 1);
2392 if (res < 0) {
2393 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2394 "error incrementing SNMP database for ftp.sessions.sessionTotal: %s",
2395 strerror(errno));
2396 }
2397
2398 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_LOGINS_F_TOTAL, 1);
2399 if (res < 0) {
2400 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2401 "error incrementing SNMP database for ftp.logins.loginsTotal: %s",
2402 strerror(errno));
2403 }
2404
2405 if (session.anon_config != NULL) {
2406 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_LOGINS_F_ANON_COUNT,
2407 1);
2408 if (res < 0) {
2409 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2410 "error incrementing SNMP database for ftp.logins.anonLoginCount: %s",
2411 strerror(errno));
2412 }
2413
2414 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_LOGINS_F_ANON_TOTAL,
2415 1);
2416 if (res < 0) {
2417 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2418 "error incrementing SNMP database for ftp.logins.anonLoginTotal: %s",
2419 strerror(errno));
2420 }
2421 }
2422
2423 } else if (strcmp(proto, "ftps") == 0) {
2424 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_LOGINS_F_TOTAL, 1);
2425 if (res < 0) {
2426 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2427 "error incrementing SNMP database for ftps.tlsLogins.loginsTotal: %s",
2428 strerror(errno));
2429 }
2430
2431 } else {
2432 /* SSH2 password logins are handled elsewhere. */
2433 }
2434
2435 return PR_DECLINED(cmd);
2436 }
2437
snmp_err_pass(cmd_rec * cmd)2438 MODRET snmp_err_pass(cmd_rec *cmd) {
2439 const char *proto;
2440 int res;
2441
2442 if (snmp_engine == FALSE) {
2443 return PR_DECLINED(cmd);
2444 }
2445
2446 proto = pr_session_get_protocol(0);
2447
2448 if (strcmp(proto, "ftp") == 0) {
2449 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTP_LOGINS_F_ERR_TOTAL, 1);
2450 if (res < 0) {
2451 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2452 "error incrementing SNMP database for ftp.logins.loginFailedTotal: %s",
2453 strerror(errno));
2454 }
2455
2456 } else if (strcmp(proto, "ftps") == 0) {
2457 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_LOGINS_F_ERR_TOTAL, 1);
2458 if (res < 0) {
2459 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2460 "error incrementing SNMP database for "
2461 "ftps.tlsLogins.loginFailedTotal: %s", strerror(errno));
2462 }
2463
2464 } else {
2465 /* SSH2 password logins are handled elsewhere. */
2466 }
2467
2468 return PR_DECLINED(cmd);
2469 }
2470
snmp_pre_retr(cmd_rec * cmd)2471 MODRET snmp_pre_retr(cmd_rec *cmd) {
2472 const char *proto;
2473 int res;
2474
2475 if (snmp_engine == FALSE) {
2476 return PR_DECLINED(cmd);
2477 }
2478
2479 proto = pr_session_get_protocol(0);
2480 if (strcmp(proto, "ftp") == 0) {
2481 res = snmp_db_incr_value(cmd->tmp_pool,
2482 SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_COUNT, 1);
2483 if (res < 0) {
2484 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2485 "error incrementing SNMP database for "
2486 "ftp.dataTransfers.fileDownloadCount: %s", strerror(errno));
2487 }
2488
2489 } else if (strcmp(proto, "ftps") == 0) {
2490 res = snmp_db_incr_value(cmd->tmp_pool,
2491 SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_COUNT, 1);
2492 if (res < 0) {
2493 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2494 "error incrementing SNMP database for "
2495 "ftps.tlsDataTransfers.fileDownloadCount: %s", strerror(errno));
2496 }
2497
2498 } else if (strcmp(proto, "sftp") == 0) {
2499 res = snmp_db_incr_value(cmd->tmp_pool,
2500 SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_COUNT, 1);
2501 if (res < 0) {
2502 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2503 "error incrementing SNMP database for "
2504 "sftp.sftpDataTransfers.fileDownloadCount: %s", strerror(errno));
2505 }
2506
2507 } else if (strcmp(proto, "scp") == 0) {
2508 res = snmp_db_incr_value(cmd->tmp_pool,
2509 SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_COUNT, 1);
2510 if (res < 0) {
2511 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2512 "error incrementing SNMP database for "
2513 "scp.scpDataTransfers.fileDownloadCount: %s", strerror(errno));
2514 }
2515 }
2516
2517 return PR_DECLINED(cmd);
2518 }
2519
snmp_log_retr(cmd_rec * cmd)2520 MODRET snmp_log_retr(cmd_rec *cmd) {
2521 const char *proto;
2522 uint32_t retr_kb;
2523 off_t rem_bytes;
2524 int res;
2525
2526 if (snmp_engine == FALSE) {
2527 return PR_DECLINED(cmd);
2528 }
2529
2530 proto = pr_session_get_protocol(0);
2531
2532 if (strcmp(proto, "ftp") == 0) {
2533 res = snmp_db_incr_value(cmd->tmp_pool,
2534 SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2535 if (res < 0) {
2536 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2537 "error decrementing SNMP database for "
2538 "ftp.dataTransfers.fileDownloadCount: %s", strerror(errno));
2539 }
2540
2541 res = snmp_db_incr_value(cmd->tmp_pool,
2542 SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_TOTAL, 1);
2543 if (res < 0) {
2544 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2545 "error incrementing SNMP database for "
2546 "ftp.dataTransfers.fileDownloadTotal: %s", strerror(errno));
2547 }
2548
2549 /* We also need to increment the KB download count. We know the number
2550 * of bytes downloaded as an off_t here, but we only store the number of KB
2551 * in the mod_snmp db tables.
2552 *
2553 * We could just increment by xfer_bytes / 1024, but that would mean that
2554 * several small files of say 999 bytes could be downloaded, and the KB
2555 * count would not be incremented.
2556 *
2557 * To deal with this situation, we use the snmp_retr_bytes static variable
2558 * as a "holding bucket" of bytes, from which we get the KB to add to the
2559 * db tables.
2560 */
2561 snmp_retr_bytes += session.xfer.total_bytes;
2562
2563 retr_kb = (snmp_retr_bytes / 1024);
2564 rem_bytes = (snmp_retr_bytes % 1024);
2565
2566 res = snmp_db_incr_value(cmd->tmp_pool,
2567 SNMP_DB_FTP_XFERS_F_KB_DOWNLOAD_TOTAL, retr_kb);
2568 if (res < 0) {
2569 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2570 "error incrementing SNMP database for "
2571 "ftp.dataTransfers.kbDownloadTotal: %s", strerror(errno));
2572 }
2573
2574 snmp_retr_bytes = rem_bytes;
2575
2576 } else if (strcmp(proto, "ftps") == 0) {
2577 res = snmp_db_incr_value(cmd->tmp_pool,
2578 SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2579 if (res < 0) {
2580 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2581 "error decrementing SNMP database for "
2582 "ftps.tlsDataTransfers.fileDownloadCount: %s", strerror(errno));
2583 }
2584
2585 res = snmp_db_incr_value(cmd->tmp_pool,
2586 SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_TOTAL, 1);
2587 if (res < 0) {
2588 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2589 "error incrementing SNMP database for "
2590 "ftps.tlsDataTransfers.fileDownloadTotal: %s", strerror(errno));
2591 }
2592
2593 /* We also need to increment the KB download count. We know the number
2594 * of bytes downloaded as an off_t here, but we only store the number of KB
2595 * in the mod_snmp db tables.
2596 *
2597 * We could just increment by xfer_bytes / 1024, but that would mean that
2598 * several small files of say 999 bytes could be downloaded, and the KB
2599 * count would not be incremented.
2600 *
2601 * To deal with this situation, we use the snmp_retr_bytes static variable
2602 * as a "holding bucket" of bytes, from which we get the KB to add to the
2603 * db tables.
2604 */
2605 snmp_retr_bytes += session.xfer.total_bytes;
2606
2607 retr_kb = (snmp_retr_bytes / 1024);
2608 rem_bytes = (snmp_retr_bytes % 1024);
2609
2610 res = snmp_db_incr_value(cmd->tmp_pool,
2611 SNMP_DB_FTPS_XFERS_F_KB_DOWNLOAD_TOTAL, retr_kb);
2612 if (res < 0) {
2613 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2614 "error incrementing SNMP database for "
2615 "ftps.tlsDataTransfers.kbDownloadTotal: %s", strerror(errno));
2616 }
2617
2618 snmp_retr_bytes = rem_bytes;
2619
2620 } else if (strcmp(proto, "sftp") == 0) {
2621 res = snmp_db_incr_value(cmd->tmp_pool,
2622 SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2623 if (res < 0) {
2624 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2625 "error decrementing SNMP database for "
2626 "sftp.sftpDataTransfers.fileDownloadCount: %s", strerror(errno));
2627 }
2628
2629 res = snmp_db_incr_value(cmd->tmp_pool,
2630 SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_TOTAL, 1);
2631 if (res < 0) {
2632 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2633 "error incrementing SNMP database for "
2634 "sftp.sftpDataTransfers.fileDownloadTotal: %s", strerror(errno));
2635 }
2636
2637 /* We also need to increment the KB download count. We know the number
2638 * of bytes downloaded as an off_t here, but we only store the number of KB
2639 * in the mod_snmp db tables.
2640 *
2641 * We could just increment by xfer_bytes / 1024, but that would mean that
2642 * several small files of say 999 bytes could be downloaded, and the KB
2643 * count would not be incremented.
2644 *
2645 * To deal with this situation, we use the snmp_retr_bytes static variable
2646 * as a "holding bucket" of bytes, from which we get the KB to add to the
2647 * db tables.
2648 */
2649 snmp_retr_bytes += session.xfer.total_bytes;
2650
2651 retr_kb = (snmp_retr_bytes / 1024);
2652 rem_bytes = (snmp_retr_bytes % 1024);
2653
2654 res = snmp_db_incr_value(cmd->tmp_pool,
2655 SNMP_DB_SFTP_XFERS_F_KB_DOWNLOAD_TOTAL, retr_kb);
2656 if (res < 0) {
2657 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2658 "error incrementing SNMP database for "
2659 "sftp.sftpDataTransfers.kbDownloadTotal: %s", strerror(errno));
2660 }
2661
2662 snmp_retr_bytes = rem_bytes;
2663
2664 } else if (strcmp(proto, "scp") == 0) {
2665 res = snmp_db_incr_value(cmd->tmp_pool,
2666 SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2667 if (res < 0) {
2668 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2669 "error decrementing SNMP database for "
2670 "scp.scpDataTransfers.fileDownloadCount: %s", strerror(errno));
2671 }
2672
2673 res = snmp_db_incr_value(cmd->tmp_pool,
2674 SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_TOTAL, 1);
2675 if (res < 0) {
2676 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2677 "error incrementing SNMP database for "
2678 "scp.scpDataTransfers.fileDownloadTotal: %s", strerror(errno));
2679 }
2680
2681 /* We also need to increment the KB download count. We know the number
2682 * of bytes downloaded as an off_t here, but we only store the number of KB
2683 * in the mod_snmp db tables.
2684 *
2685 * We could just increment by xfer_bytes / 1024, but that would mean that
2686 * several small files of say 999 bytes could be downloaded, and the KB
2687 * count would not be incremented.
2688 *
2689 * To deal with this situation, we use the snmp_retr_bytes static variable
2690 * as a "holding bucket" of bytes, from which we get the KB to add to the
2691 * db tables.
2692 */
2693 snmp_retr_bytes += session.xfer.total_bytes;
2694
2695 retr_kb = (snmp_retr_bytes / 1024);
2696 rem_bytes = (snmp_retr_bytes % 1024);
2697
2698 res = snmp_db_incr_value(cmd->tmp_pool,
2699 SNMP_DB_SCP_XFERS_F_KB_DOWNLOAD_TOTAL, retr_kb);
2700 if (res < 0) {
2701 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2702 "error incrementing SNMP database for "
2703 "scp.scpDataTransfers.kbDownloadTotal: %s", strerror(errno));
2704 }
2705
2706 snmp_retr_bytes = rem_bytes;
2707 }
2708
2709 return PR_DECLINED(cmd);
2710 }
2711
snmp_err_retr(cmd_rec * cmd)2712 MODRET snmp_err_retr(cmd_rec *cmd) {
2713 const char *proto;
2714 int res;
2715
2716 if (snmp_engine == FALSE) {
2717 return PR_DECLINED(cmd);
2718 }
2719
2720 proto = pr_session_get_protocol(0);
2721
2722 if (strcmp(proto, "ftp") == 0) {
2723 res = snmp_db_incr_value(cmd->tmp_pool,
2724 SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2725 if (res < 0) {
2726 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2727 "error decrementing SNMP database for "
2728 "ftp.dataTransfers.fileDownloadCount: %s", strerror(errno));
2729 }
2730
2731 res = snmp_db_incr_value(cmd->tmp_pool,
2732 SNMP_DB_FTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, 1);
2733 if (res < 0) {
2734 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2735 "error incrementing SNMP database for "
2736 "ftp.dataTransfers.fileDownloadFailedTotal: %s", strerror(errno));
2737 }
2738
2739 } else if (strcmp(proto, "ftps") == 0) {
2740 res = snmp_db_incr_value(cmd->tmp_pool,
2741 SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2742 if (res < 0) {
2743 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2744 "error decrementing SNMP database for "
2745 "ftps.tlsDataTransfers.fileDownloadCount: %s", strerror(errno));
2746 }
2747
2748 res = snmp_db_incr_value(cmd->tmp_pool,
2749 SNMP_DB_FTPS_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, 1);
2750 if (res < 0) {
2751 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2752 "error incrementing SNMP database for "
2753 "ftps.tlsDataTransfers.fileDownloadFailedTotal: %s", strerror(errno));
2754 }
2755
2756 } else if (strcmp(proto, "sftp") == 0) {
2757 res = snmp_db_incr_value(cmd->tmp_pool,
2758 SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2759 if (res < 0) {
2760 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2761 "error decrementing SNMP database for "
2762 "sftp.sftpDataTransfers.fileDownloadCount: %s", strerror(errno));
2763 }
2764
2765 res = snmp_db_incr_value(cmd->tmp_pool,
2766 SNMP_DB_SFTP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, 1);
2767 if (res < 0) {
2768 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2769 "error incrementing SNMP database for "
2770 "sftp.sftpDataTransfers.fileDownloadFailedTotal: %s", strerror(errno));
2771 }
2772
2773 } else if (strcmp(proto, "scp") == 0) {
2774 res = snmp_db_incr_value(cmd->tmp_pool,
2775 SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_COUNT, -1);
2776 if (res < 0) {
2777 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2778 "error decrementing SNMP database for "
2779 "scp.scpDataTransfers.fileDownloadCount: %s", strerror(errno));
2780 }
2781
2782 res = snmp_db_incr_value(cmd->tmp_pool,
2783 SNMP_DB_SCP_XFERS_F_FILE_DOWNLOAD_ERR_TOTAL, 1);
2784 if (res < 0) {
2785 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2786 "error incrementing SNMP database for "
2787 "scp.scpDataTransfers.fileDownloadFailedTotal: %s", strerror(errno));
2788 }
2789 }
2790
2791 return PR_DECLINED(cmd);
2792 }
2793
snmp_pre_stor(cmd_rec * cmd)2794 MODRET snmp_pre_stor(cmd_rec *cmd) {
2795 const char *proto;
2796 int res;
2797
2798 if (snmp_engine == FALSE) {
2799 return PR_DECLINED(cmd);
2800 }
2801
2802 proto = pr_session_get_protocol(0);
2803 if (strcmp(proto, "ftp") == 0) {
2804 res = snmp_db_incr_value(cmd->tmp_pool,
2805 SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_COUNT, 1);
2806 if (res < 0) {
2807 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2808 "error incrementing SNMP database for "
2809 "ftp.dataTransfers.fileUploadCount: %s", strerror(errno));
2810 }
2811
2812 } else if (strcmp(proto, "ftps") == 0) {
2813 res = snmp_db_incr_value(cmd->tmp_pool,
2814 SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_COUNT, 1);
2815 if (res < 0) {
2816 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2817 "error incrementing SNMP database for "
2818 "ftps.tlsDataTransfers.fileUploadCount: %s", strerror(errno));
2819 }
2820
2821 } else if (strcmp(proto, "sftp") == 0) {
2822 res = snmp_db_incr_value(cmd->tmp_pool,
2823 SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_COUNT, 1);
2824 if (res < 0) {
2825 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2826 "error incrementing SNMP database for "
2827 "sftp.sftpDataTransfers.fileUploadCount: %s", strerror(errno));
2828 }
2829
2830 } else if (strcmp(proto, "scp") == 0) {
2831 res = snmp_db_incr_value(cmd->tmp_pool,
2832 SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_COUNT, 1);
2833 if (res < 0) {
2834 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2835 "error incrementing SNMP database for "
2836 "scp.scpDataTransfers.fileUploadCount: %s", strerror(errno));
2837 }
2838 }
2839
2840 return PR_DECLINED(cmd);
2841 }
2842
snmp_log_stor(cmd_rec * cmd)2843 MODRET snmp_log_stor(cmd_rec *cmd) {
2844 const char *proto;
2845 uint32_t stor_kb;
2846 off_t rem_bytes;
2847 int res;
2848
2849 if (snmp_engine == FALSE) {
2850 return PR_DECLINED(cmd);
2851 }
2852
2853 proto = pr_session_get_protocol(0);
2854
2855 if (strcmp(proto, "ftp") == 0) {
2856 res = snmp_db_incr_value(cmd->tmp_pool,
2857 SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_COUNT, -1);
2858 if (res < 0) {
2859 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2860 "error decrementing SNMP database for "
2861 "ftp.dataTransfers.fileUploadCount: %s", strerror(errno));
2862 }
2863
2864 res = snmp_db_incr_value(cmd->tmp_pool,
2865 SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_TOTAL, 1);
2866 if (res < 0) {
2867 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2868 "error incrementing SNMP database for "
2869 "ftp.dataTransfers.fileUploadTotal: %s", strerror(errno));
2870 }
2871
2872 /* We also need to increment the KB upload count. We know the number
2873 * of bytes downloaded as an off_t here, but we only store the number of KB
2874 * in the mod_snmp db tables.
2875 *
2876 * We could just increment by xfer_bytes / 1024, but that would mean that
2877 * several small files of say 999 bytes could be uploaded, and the KB
2878 * count would not be incremented.
2879 *
2880 * To deal with this situation, we use the snmp_stor_bytes static variable
2881 * as a "holding bucket" of bytes, from which we get the KB to add to the
2882 * db tables.
2883 */
2884 snmp_stor_bytes += session.xfer.total_bytes;
2885
2886 stor_kb = (snmp_stor_bytes / 1024);
2887 rem_bytes = (snmp_stor_bytes % 1024);
2888
2889 res = snmp_db_incr_value(cmd->tmp_pool,
2890 SNMP_DB_FTP_XFERS_F_KB_UPLOAD_TOTAL, stor_kb);
2891 if (res < 0) {
2892 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2893 "error incrementing SNMP database for "
2894 "ftp.dataTransfers.kbUploadTotal: %s", strerror(errno));
2895 }
2896
2897 snmp_stor_bytes = rem_bytes;
2898
2899 } else if (strcmp(proto, "ftps") == 0) {
2900 res = snmp_db_incr_value(cmd->tmp_pool,
2901 SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_COUNT, -1);
2902 if (res < 0) {
2903 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2904 "error decrementing SNMP database for "
2905 "ftps.tlsDataTransfers.fileUploadCount: %s", strerror(errno));
2906 }
2907
2908 res = snmp_db_incr_value(cmd->tmp_pool,
2909 SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_TOTAL, 1);
2910 if (res < 0) {
2911 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2912 "error incrementing SNMP database for "
2913 "ftps.tlsDataTransfers.fileUploadTotal: %s", strerror(errno));
2914 }
2915
2916 /* We also need to increment the KB upload count. We know the number
2917 * of bytes downloaded as an off_t here, but we only store the number of KB
2918 * in the mod_snmp db tables.
2919 *
2920 * We could just increment by xfer_bytes / 1024, but that would mean that
2921 * several small files of say 999 bytes could be uploaded, and the KB
2922 * count would not be incremented.
2923 *
2924 * To deal with this situation, we use the snmp_stor_bytes static variable
2925 * as a "holding bucket" of bytes, from which we get the KB to add to the
2926 * db tables.
2927 */
2928 snmp_stor_bytes += session.xfer.total_bytes;
2929
2930 stor_kb = (snmp_stor_bytes / 1024);
2931 rem_bytes = (snmp_stor_bytes % 1024);
2932
2933 res = snmp_db_incr_value(cmd->tmp_pool,
2934 SNMP_DB_FTPS_XFERS_F_KB_UPLOAD_TOTAL, stor_kb);
2935 if (res < 0) {
2936 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2937 "error incrementing SNMP database for "
2938 "ftps.tlsDataTransfers.kbUploadTotal: %s", strerror(errno));
2939 }
2940
2941 snmp_stor_bytes = rem_bytes;
2942
2943 } else if (strcmp(proto, "sftp") == 0) {
2944 res = snmp_db_incr_value(cmd->tmp_pool,
2945 SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_COUNT, -1);
2946 if (res < 0) {
2947 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2948 "error decrementing SNMP database for "
2949 "sftp.sftpDataTransfers.fileUploadCount: %s", strerror(errno));
2950 }
2951
2952 res = snmp_db_incr_value(cmd->tmp_pool,
2953 SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_TOTAL, 1);
2954 if (res < 0) {
2955 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2956 "error incrementing SNMP database for "
2957 "sftp.sftpDataTransfers.fileUploadTotal: %s", strerror(errno));
2958 }
2959
2960 /* We also need to increment the KB upload count. We know the number
2961 * of bytes downloaded as an off_t here, but we only store the number of KB
2962 * in the mod_snmp db tables.
2963 *
2964 * We could just increment by xfer_bytes / 1024, but that would mean that
2965 * several small files of say 999 bytes could be uploaded, and the KB
2966 * count would not be incremented.
2967 *
2968 * To deal with this situation, we use the snmp_stor_bytes static variable
2969 * as a "holding bucket" of bytes, from which we get the KB to add to the
2970 * db tables.
2971 */
2972 snmp_stor_bytes += session.xfer.total_bytes;
2973
2974 stor_kb = (snmp_stor_bytes / 1024);
2975 rem_bytes = (snmp_stor_bytes % 1024);
2976
2977 res = snmp_db_incr_value(cmd->tmp_pool,
2978 SNMP_DB_SFTP_XFERS_F_KB_UPLOAD_TOTAL, stor_kb);
2979 if (res < 0) {
2980 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2981 "error incrementing SNMP database for "
2982 "sftp.sftpDataTransfers.kbUploadTotal: %s", strerror(errno));
2983 }
2984
2985 snmp_stor_bytes = rem_bytes;
2986
2987 } else if (strcmp(proto, "scp") == 0) {
2988 res = snmp_db_incr_value(cmd->tmp_pool,
2989 SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_COUNT, -1);
2990 if (res < 0) {
2991 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
2992 "error decrementing SNMP database for "
2993 "scp.scpDataTransfers.fileUploadCount: %s", strerror(errno));
2994 }
2995
2996 res = snmp_db_incr_value(cmd->tmp_pool,
2997 SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_TOTAL, 1);
2998 if (res < 0) {
2999 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3000 "error incrementing SNMP database for "
3001 "scp.scpDataTransfers.fileUploadTotal: %s", strerror(errno));
3002 }
3003
3004 /* We also need to increment the KB upload count. We know the number
3005 * of bytes downloaded as an off_t here, but we only store the number of KB
3006 * in the mod_snmp db tables.
3007 *
3008 * We could just increment by xfer_bytes / 1024, but that would mean that
3009 * several small files of say 999 bytes could be uploaded, and the KB
3010 * count would not be incremented.
3011 *
3012 * To deal with this situation, we use the snmp_stor_bytes static variable
3013 * as a "holding bucket" of bytes, from which we get the KB to add to the
3014 * db tables.
3015 */
3016 snmp_stor_bytes += session.xfer.total_bytes;
3017
3018 stor_kb = (snmp_stor_bytes / 1024);
3019 rem_bytes = (snmp_stor_bytes % 1024);
3020
3021 res = snmp_db_incr_value(cmd->tmp_pool,
3022 SNMP_DB_SCP_XFERS_F_KB_UPLOAD_TOTAL, stor_kb);
3023 if (res < 0) {
3024 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3025 "error incrementing SNMP database for "
3026 "scp.scpDataTransfers.kbUploadTotal: %s", strerror(errno));
3027 }
3028
3029 snmp_stor_bytes = rem_bytes;
3030 }
3031
3032 return PR_DECLINED(cmd);
3033 }
3034
snmp_err_stor(cmd_rec * cmd)3035 MODRET snmp_err_stor(cmd_rec *cmd) {
3036 const char *proto;
3037 int res;
3038
3039 if (snmp_engine == FALSE) {
3040 return PR_DECLINED(cmd);
3041 }
3042
3043 proto = pr_session_get_protocol(0);
3044
3045 if (strcmp(proto, "ftp") == 0) {
3046 res = snmp_db_incr_value(cmd->tmp_pool,
3047 SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_COUNT, -1);
3048 if (res < 0) {
3049 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3050 "error decrementing SNMP database for "
3051 "ftp.dataTransfers.fileUploadCount: %s", strerror(errno));
3052 }
3053
3054 res = snmp_db_incr_value(cmd->tmp_pool,
3055 SNMP_DB_FTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, 1);
3056 if (res < 0) {
3057 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3058 "error incrementing SNMP database for "
3059 "ftp.dataTransfers.fileUploadFailedTotal: %s", strerror(errno));
3060 }
3061
3062 } else if (strcmp(proto, "ftps") == 0) {
3063 res = snmp_db_incr_value(cmd->tmp_pool,
3064 SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_COUNT, -1);
3065 if (res < 0) {
3066 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3067 "error decrementing SNMP database for "
3068 "ftps.tlsDataTransfers.fileUploadCount: %s", strerror(errno));
3069 }
3070
3071 res = snmp_db_incr_value(cmd->tmp_pool,
3072 SNMP_DB_FTPS_XFERS_F_FILE_UPLOAD_ERR_TOTAL, 1);
3073 if (res < 0) {
3074 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3075 "error incrementing SNMP database for "
3076 "ftps.tlsDataTransfers.fileUploadFailedTotal: %s", strerror(errno));
3077 }
3078
3079 } else if (strcmp(proto, "sftp") == 0) {
3080 res = snmp_db_incr_value(cmd->tmp_pool,
3081 SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_COUNT, -1);
3082 if (res < 0) {
3083 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3084 "error decrementing SNMP database for "
3085 "sftp.sftpDataTransfers.fileUploadCount: %s", strerror(errno));
3086 }
3087
3088 res = snmp_db_incr_value(cmd->tmp_pool,
3089 SNMP_DB_SFTP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, 1);
3090 if (res < 0) {
3091 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3092 "error incrementing SNMP database for "
3093 "sftp.sftpDataTransfers.fileUploadFailedTotal: %s", strerror(errno));
3094 }
3095
3096 } else if (strcmp(proto, "scp") == 0) {
3097 res = snmp_db_incr_value(cmd->tmp_pool,
3098 SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_COUNT, -1);
3099 if (res < 0) {
3100 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3101 "error decrementing SNMP database for "
3102 "scp.scpDataTransfers.fileUploadCount: %s", strerror(errno));
3103 }
3104
3105 res = snmp_db_incr_value(cmd->tmp_pool,
3106 SNMP_DB_SCP_XFERS_F_FILE_UPLOAD_ERR_TOTAL, 1);
3107 if (res < 0) {
3108 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3109 "error incrementing SNMP database for "
3110 "scp.scpDataTransfers.fileUploadFailedTotal: %s", strerror(errno));
3111 }
3112 }
3113
3114 return PR_DECLINED(cmd);
3115 }
3116
snmp_log_auth(cmd_rec * cmd)3117 MODRET snmp_log_auth(cmd_rec *cmd) {
3118 const char *proto;
3119 int res;
3120
3121 if (snmp_engine == FALSE) {
3122 return PR_DECLINED(cmd);
3123 }
3124
3125 /* Note: we are not currently properly incrementing
3126 * SNMP_DB_FTPS_SESS_F_SESS_COUNT and SNMP_DB_FTPS_SESS_F_SESS_TOTAL
3127 * for FTPS connections accepted using the UseImplicitSSL TLSOption.
3128 *
3129 * The issue is that for those connections, the protocol will be set to
3130 * "ftps" in mod_tls' sess_init callback. But here in mod_snmp, we
3131 * are not guaranteed to being called AFTER mod_tls, due to module load
3132 * ordering. Thus we do not have a good way of determining when to
3133 * increment those counts for implicit FTPS connections.
3134 */
3135
3136 proto = pr_session_get_protocol(0);
3137 if (strcmp(proto, "ftps") == 0) {
3138 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_SESS_F_SESS_COUNT, 1);
3139 if (res < 0) {
3140 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3141 "error incrementing SNMP database for "
3142 "ftps.tlsSessions.sessionCount: %s", strerror(errno));
3143 }
3144
3145 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_SESS_F_SESS_TOTAL,
3146 1);
3147 if (res < 0) {
3148 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3149 "error incrementing SNMP database for "
3150 "ftps.tlsSessions.sessionTotal: %s", strerror(errno));
3151 }
3152
3153 } else {
3154 /* XXX Some other RFC2228 mechanism (e.g. mod_gss) */
3155 }
3156
3157 return PR_DECLINED(cmd);
3158 }
3159
snmp_log_ccc(cmd_rec * cmd)3160 MODRET snmp_log_ccc(cmd_rec *cmd) {
3161 const char *proto;
3162 int res;
3163
3164 if (snmp_engine == FALSE) {
3165 return PR_DECLINED(cmd);
3166 }
3167
3168 proto = pr_session_get_protocol(0);
3169 if (strcmp(proto, "ftps") == 0) {
3170 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_SESS_F_CCC_TOTAL, 1);
3171 if (res < 0) {
3172 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3173 "error incrementing SNMP database for "
3174 "ftps.tlsSessions.clearCommandChannelTotal: %s", strerror(errno));
3175 }
3176 }
3177
3178 return PR_DECLINED(cmd);
3179 }
3180
snmp_err_ccc(cmd_rec * cmd)3181 MODRET snmp_err_ccc(cmd_rec *cmd) {
3182 const char *proto;
3183 int res;
3184
3185 if (snmp_engine == FALSE) {
3186 return PR_DECLINED(cmd);
3187 }
3188
3189 proto = pr_session_get_protocol(0);
3190 if (strcmp(proto, "ftps") == 0) {
3191 res = snmp_db_incr_value(cmd->tmp_pool, SNMP_DB_FTPS_SESS_F_CCC_ERR_TOTAL,
3192 1);
3193 if (res < 0) {
3194 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3195 "error incrementing SNMP database for "
3196 "ftps.tlsSessions.clearCommandChannelFailedTotal: %s", strerror(errno));
3197 }
3198 }
3199
3200 return PR_DECLINED(cmd);
3201 }
3202
3203 /* Event handlers
3204 */
3205
ev_incr_value(unsigned int field_id,const char * field_str,int32_t incr)3206 static void ev_incr_value(unsigned int field_id, const char *field_str,
3207 int32_t incr) {
3208 int res;
3209 pool *p;
3210
3211 p = session.pool;
3212 if (p == NULL) {
3213 p = snmp_pool;
3214 }
3215
3216 res = snmp_db_incr_value(p, field_id, incr);
3217 if (res < 0) {
3218 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3219 "error %s SNMP database for %s: %s",
3220 incr < 0 ? "decrementing" : "incrementing", field_str, strerror(errno));
3221 }
3222 }
3223
snmp_auth_code_ev(const void * event_data,void * user_data)3224 static void snmp_auth_code_ev(const void *event_data, void *user_data) {
3225 int auth_code, res;
3226 unsigned int field_id = SNMP_DB_ID_UNKNOWN, is_ftps = FALSE, notify_id = 0;
3227 const char *notify_str = NULL, *proto;
3228
3229 if (snmp_engine == FALSE) {
3230 return;
3231 }
3232
3233 auth_code = *((int *) event_data);
3234
3235 /* Any notifications we generate here may depend on the protocol in use. */
3236 proto = pr_session_get_protocol(0);
3237
3238 if (strcmp(proto, "ftps") == 0) {
3239 is_ftps = TRUE;
3240 }
3241
3242 switch (auth_code) {
3243 case PR_AUTH_RFC2228_OK:
3244 if (is_ftps == TRUE) {
3245 field_id = SNMP_DB_FTPS_LOGINS_F_CERT_TOTAL;
3246 }
3247 break;
3248
3249 case PR_AUTH_NOPWD:
3250 if (is_ftps == FALSE) {
3251 field_id = SNMP_DB_FTP_LOGINS_F_ERR_BAD_USER_TOTAL;
3252
3253 } else {
3254 field_id = SNMP_DB_FTPS_LOGINS_F_ERR_BAD_USER_TOTAL;
3255 }
3256
3257 notify_id = SNMP_NOTIFY_FTP_BAD_USER;
3258 notify_str = "loginFailedBadUser";
3259 break;
3260
3261 case PR_AUTH_BADPWD:
3262 if (is_ftps == FALSE) {
3263 field_id = SNMP_DB_FTP_LOGINS_F_ERR_BAD_PASSWD_TOTAL;
3264
3265 } else {
3266 field_id = SNMP_DB_FTPS_LOGINS_F_ERR_BAD_PASSWD_TOTAL;
3267 }
3268
3269 notify_id = SNMP_NOTIFY_FTP_BAD_PASSWD;
3270 notify_str = "loginFailedBadPassword";
3271 break;
3272
3273 default:
3274 if (is_ftps == FALSE) {
3275 field_id = SNMP_DB_FTP_LOGINS_F_ERR_GENERAL_TOTAL;
3276
3277 } else {
3278 field_id = SNMP_DB_FTPS_LOGINS_F_ERR_GENERAL_TOTAL;
3279 }
3280
3281 break;
3282 }
3283
3284 if (auth_code >= 0) {
3285 ev_incr_value(field_id, "login total", 1);
3286
3287 /* We only send notifications for failed authentications. */
3288 return;
3289
3290 } else {
3291 ev_incr_value(field_id, "login failure total", 1);
3292 }
3293
3294 if (notify_id > 0 &&
3295 snmp_notifys != NULL) {
3296 register unsigned int i;
3297 pr_netaddr_t **dst_addrs;
3298
3299 dst_addrs = snmp_notifys->elts;
3300 for (i = 0; i < snmp_notifys->nelts; i++) {
3301 res = snmp_notify_generate(snmp_pool, -1, snmp_community,
3302 session.c->local_addr, dst_addrs[i], notify_id);
3303 if (res < 0) {
3304 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3305 "unable to send %s notification to SNMPNotify %s:%d: %s", notify_str,
3306 pr_netaddr_get_ipstr(dst_addrs[i]),
3307 ntohs(pr_netaddr_get_port(dst_addrs[i])), strerror(errno));
3308 }
3309 }
3310 }
3311 }
3312
snmp_cmd_invalid_ev(const void * event_data,void * user_data)3313 static void snmp_cmd_invalid_ev(const void *event_data, void *user_data) {
3314 if (snmp_engine == FALSE) {
3315 return;
3316 }
3317
3318 ev_incr_value(SNMP_DB_FTP_SESS_F_CMD_INVALID_TOTAL,
3319 "ftp.connections.commandInvalidTotal", 1);
3320 }
3321
snmp_exit_ev(const void * event_data,void * user_data)3322 static void snmp_exit_ev(const void *event_data, void *user_data) {
3323 if (snmp_engine == FALSE) {
3324 return;
3325 }
3326
3327 ev_incr_value(SNMP_DB_DAEMON_F_CONN_COUNT, "daemon.connectionCount", -1);
3328
3329 switch (session.disconnect_reason) {
3330 case PR_SESS_DISCONNECT_BANNED:
3331 case PR_SESS_DISCONNECT_CONFIG_ACL:
3332 case PR_SESS_DISCONNECT_MODULE_ACL:
3333 case PR_SESS_DISCONNECT_SESSION_INIT_FAILED:
3334 ev_incr_value(SNMP_DB_DAEMON_F_CONN_REFUSED_TOTAL,
3335 "daemon.connectionRefusedTotal", 1);
3336 break;
3337
3338 case PR_SESS_DISCONNECT_SEGFAULT:
3339 ev_incr_value(SNMP_DB_DAEMON_F_SEGFAULT_COUNT,
3340 "daemon.segfaultCount", 1);
3341 break;
3342
3343 default: {
3344 const char *proto;
3345
3346 proto = pr_session_get_protocol(0);
3347
3348 if (strcmp(proto, "ftp") == 0) {
3349 ev_incr_value(SNMP_DB_FTP_SESS_F_SESS_COUNT,
3350 "ftp.sessions.sessionCount", -1);
3351
3352 if (session.anon_config != NULL) {
3353 ev_incr_value(SNMP_DB_FTP_LOGINS_F_ANON_COUNT,
3354 "ftp.logins.anonLoginCount", -1);
3355 }
3356
3357 } else if (strcmp(proto, "ftps") == 0) {
3358 ev_incr_value(SNMP_DB_FTPS_SESS_F_SESS_COUNT,
3359 "ftps.tlsSessions.sessionCount", -1);
3360
3361 } else {
3362 /* XXX ssh2/sftp/scp session end */
3363 }
3364
3365 break;
3366 }
3367 }
3368
3369 if (snmp_logfd >= 0) {
3370 (void) close(snmp_logfd);
3371 snmp_logfd = -1;
3372 }
3373 }
3374
snmp_max_inst_ev(const void * event_data,void * user_data)3375 static void snmp_max_inst_ev(const void *event_data, void *user_data) {
3376 if (snmp_engine == FALSE) {
3377 return;
3378 }
3379
3380 ev_incr_value(SNMP_DB_DAEMON_F_MAXINST_TOTAL,
3381 "daemon.maxInstancesLimitTotal", 1);
3382
3383 if (snmp_notifys != NULL) {
3384 register unsigned int i;
3385 pr_netaddr_t **dst_addrs;
3386 unsigned int notify_id = SNMP_NOTIFY_DAEMON_MAX_INSTANCES;
3387
3388 dst_addrs = snmp_notifys->elts;
3389 for (i = 0; i < snmp_notifys->nelts; i++) {
3390 int res;
3391
3392 res = snmp_notify_generate(snmp_pool, -1, snmp_community,
3393 session.c->local_addr, dst_addrs[i], notify_id);
3394 if (res < 0) {
3395 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3396 "unable to send daemonMaxInstancesExceeded notification to "
3397 "SNMPNotify %s:%d: %s", pr_netaddr_get_ipstr(dst_addrs[i]),
3398 ntohs(pr_netaddr_get_port(dst_addrs[i])), strerror(errno));
3399 }
3400 }
3401 }
3402 }
3403
3404 #if defined(PR_SHARED_MODULE)
snmp_mod_unload_ev(const void * event_data,void * user_data)3405 static void snmp_mod_unload_ev(const void *event_data, void *user_data) {
3406 if (strcmp((const char *) event_data, "mod_snmp.c") == 0) {
3407 register unsigned int i;
3408
3409 /* Unregister ourselves from all events. */
3410 pr_event_unregister(&snmp_module, NULL, NULL);
3411
3412 for (i = 0; snmp_table_ids[i] > 0; i++) {
3413 snmp_db_close(snmp_pool, snmp_table_ids[i]);
3414 }
3415
3416 destroy_pool(snmp_pool);
3417 snmp_pool = NULL;
3418
3419 (void) close(snmp_logfd);
3420 snmp_logfd = -1;
3421 }
3422 }
3423 #endif
3424
snmp_postparse_ev(const void * event_data,void * user_data)3425 static void snmp_postparse_ev(const void *event_data, void *user_data) {
3426 register unsigned int i;
3427 config_rec *c;
3428 server_rec *s;
3429 unsigned int nvhosts = 0;
3430 const char *tables_dir;
3431 int agent_type, res;
3432 array_header *agent_addrs;
3433 unsigned char ban_loaded = FALSE, sftp_loaded = FALSE, tls_loaded = FALSE;
3434
3435 c = find_config(main_server->conf, CONF_PARAM, "SNMPEngine", FALSE);
3436 if (c) {
3437 snmp_engine = *((int *) c->argv[0]);
3438 }
3439
3440 if (snmp_engine == FALSE) {
3441 return;
3442 }
3443
3444 snmp_openlog();
3445
3446 c = find_config(main_server->conf, CONF_PARAM, "SNMPOptions", FALSE);
3447 while (c != NULL) {
3448 unsigned long opts = 0;
3449
3450 pr_signals_handle();
3451
3452 opts = *((unsigned long *) c->argv[0]);
3453 snmp_opts |= opts;
3454
3455 c = find_config_next(c, c->next, CONF_PARAM, "SNMPOptions", FALSE);
3456 }
3457
3458 c = find_config(main_server->conf, CONF_PARAM, "SNMPCommunity", FALSE);
3459 if (c == NULL) {
3460 /* No SNMPCommunity configured, mod_snmp cannot authenticate messages
3461 * properly.
3462 */
3463 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3464 "no SNMPCommunity configured, disabling module");
3465
3466 snmp_engine = FALSE;
3467 return;
3468 }
3469
3470 snmp_community = c->argv[0];
3471
3472 c = find_config(main_server->conf, CONF_PARAM, "SNMPMaxVariables", FALSE);
3473 if (c != NULL) {
3474 snmp_max_variables = *((unsigned int *) c->argv[0]);
3475 }
3476
3477 c = find_config(main_server->conf, CONF_PARAM, "SNMPTables", FALSE);
3478 if (c == NULL) {
3479 /* No SNMPTables configured, mod_snmp cannot run. */
3480 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3481 "no SNMPTables configured, disabling module");
3482
3483 snmp_engine = FALSE;
3484 return;
3485 }
3486
3487 tables_dir = c->argv[0];
3488
3489 if (snmp_db_set_root(tables_dir) < 0) {
3490 /* Unable to configure the SNMPTables root for some reason... */
3491
3492 snmp_engine = FALSE;
3493 return;
3494 }
3495
3496 /* Create the variable database table files, based on the configured
3497 * SNMPTables path.
3498 */
3499 tls_loaded = pr_module_exists("mod_tls.c");
3500 sftp_loaded = pr_module_exists("mod_sftp.c");
3501 ban_loaded = pr_module_exists("mod_ban.c");
3502
3503 for (i = 0; snmp_table_ids[i] > 0; i++) {
3504 int skip_table = FALSE;
3505
3506 switch (snmp_table_ids[i]) {
3507 case SNMP_DB_ID_TLS:
3508 if (tls_loaded == FALSE) {
3509 skip_table = TRUE;
3510 }
3511 break;
3512
3513 case SNMP_DB_ID_SSH:
3514 case SNMP_DB_ID_SFTP:
3515 case SNMP_DB_ID_SCP:
3516 if (sftp_loaded == FALSE) {
3517 skip_table = TRUE;
3518 }
3519 break;
3520
3521 case SNMP_DB_ID_BAN:
3522 if (ban_loaded == FALSE) {
3523 skip_table = TRUE;
3524 }
3525 break;
3526
3527 default:
3528 break;
3529 }
3530
3531 if (skip_table) {
3532 continue;
3533 }
3534
3535 res = snmp_db_open(snmp_pool, snmp_table_ids[i]);
3536 if (res < 0) {
3537 register unsigned int j;
3538
3539 /* If we fail to open this table, BUT have succeeded in opening previous
3540 * tables, AND we are just going to return here, then we need to make
3541 * sure to close the previously opened tables.
3542 */
3543 for (j = 0; snmp_table_ids[j] > 0 && j < i; j++) {
3544 (void) snmp_db_close(snmp_pool, snmp_table_ids[j]);
3545 }
3546
3547 snmp_engine = FALSE;
3548 return;
3549 }
3550 }
3551
3552 /* Initial the MIBs. */
3553 snmp_mib_init();
3554
3555 /* Iterate through the server_list, and count up the number of vhosts. */
3556 for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
3557 nvhosts++;
3558 }
3559
3560 ev_incr_value(SNMP_DB_DAEMON_F_VHOST_COUNT, "daemon.vhostCount", nvhosts);
3561
3562 c = find_config(main_server->conf, CONF_PARAM, "SNMPAgent", FALSE);
3563 if (c == NULL) {
3564 snmp_engine = FALSE;
3565 pr_log_debug(DEBUG0, MOD_SNMP_VERSION
3566 ": missing required SNMPAgent directive, disabling module");
3567
3568 /* Need to close database tables here. */
3569 for (i = 0; snmp_table_ids[i] > 0; i++) {
3570 (void) snmp_db_close(snmp_pool, snmp_table_ids[i]);
3571 }
3572
3573 return;
3574 }
3575
3576 agent_type = *((int *) c->argv[0]);
3577 agent_addrs = c->argv[1];
3578
3579 snmp_agent_pid = snmp_agent_start(tables_dir, agent_type, agent_addrs);
3580 if (snmp_agent_pid == 0) {
3581 snmp_engine = FALSE;
3582 pr_log_debug(DEBUG0, MOD_SNMP_VERSION
3583 ": failed to start agent listening process, disabling module");
3584
3585 /* Need to close database tables here. */
3586 for (i = 0; snmp_table_ids[i] > 0; i++) {
3587 (void) snmp_db_close(snmp_pool, snmp_table_ids[i]);
3588 }
3589 }
3590
3591 return;
3592 }
3593
snmp_restart_ev(const void * event_data,void * user_data)3594 static void snmp_restart_ev(const void *event_data, void *user_data) {
3595 if (snmp_engine == FALSE) {
3596 return;
3597 }
3598
3599 ev_incr_value(SNMP_DB_DAEMON_F_RESTART_COUNT, "daemon.restartCount", 1);
3600
3601 if (snmp_opts & SNMP_OPT_RESTART_CLEARS_COUNTERS) {
3602 int res;
3603
3604 pr_trace_msg(trace_channel, 17,
3605 "restart event received, resetting counters");
3606 res = snmp_mib_reset_counters();
3607 if (res < 0) {
3608 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3609 "error resetting SNMP database counters: %s", strerror(errno));
3610 }
3611 }
3612
3613 snmp_agent_stop(snmp_agent_pid);
3614
3615 /* Close the SNMPLog file descriptor; it will be reopened in the
3616 * postparse event listener.
3617 */
3618 (void) close(snmp_logfd);
3619 snmp_logfd = -1;
3620 }
3621
snmp_shutdown_ev(const void * event_data,void * user_data)3622 static void snmp_shutdown_ev(const void *event_data, void *user_data) {
3623 register unsigned int i;
3624
3625 snmp_agent_stop(snmp_agent_pid);
3626
3627 for (i = 0; snmp_table_ids[i] > 0; i++) {
3628 snmp_db_close(snmp_pool, snmp_table_ids[i]);
3629 }
3630
3631 destroy_pool(snmp_pool);
3632 snmp_pool = NULL;
3633
3634 (void) close(snmp_logfd);
3635 snmp_logfd = -1;
3636 }
3637
snmp_startup_ev(const void * event_data,void * user_data)3638 static void snmp_startup_ev(const void *event_data, void *user_data) {
3639 if (snmp_engine == FALSE) {
3640 return;
3641 }
3642
3643 if (ServerType == SERVER_INETD) {
3644 snmp_engine = FALSE;
3645 pr_log_debug(DEBUG0, MOD_SNMP_VERSION
3646 ": cannot support SNMP for ServerType inetd, disabling module");
3647 return;
3648 }
3649
3650 gettimeofday(&snmp_start_tv, NULL);
3651 return;
3652 }
3653
snmp_timeout_idle_ev(const void * event_data,void * user_data)3654 static void snmp_timeout_idle_ev(const void *event_data, void *user_data) {
3655 if (snmp_engine == FALSE) {
3656 return;
3657 }
3658
3659 ev_incr_value(SNMP_DB_TIMEOUTS_F_IDLE_TOTAL,
3660 "timeouts.idleTimeoutTotal", 1);
3661 }
3662
snmp_timeout_login_ev(const void * event_data,void * user_data)3663 static void snmp_timeout_login_ev(const void *event_data, void *user_data) {
3664 if (snmp_engine == FALSE) {
3665 return;
3666 }
3667
3668 ev_incr_value(SNMP_DB_TIMEOUTS_F_LOGIN_TOTAL,
3669 "timeouts.loginTimeoutTotal", 1);
3670 }
3671
snmp_timeout_noxfer_ev(const void * event_data,void * user_data)3672 static void snmp_timeout_noxfer_ev(const void *event_data, void *user_data) {
3673 if (snmp_engine == FALSE) {
3674 return;
3675 }
3676
3677 ev_incr_value(SNMP_DB_TIMEOUTS_F_NOXFER_TOTAL,
3678 "timeouts.noTransferTimeoutTotal", 1);
3679 }
3680
snmp_timeout_stalled_ev(const void * event_data,void * user_data)3681 static void snmp_timeout_stalled_ev(const void *event_data, void *user_data) {
3682 if (snmp_engine == FALSE) {
3683 return;
3684 }
3685
3686 ev_incr_value(SNMP_DB_TIMEOUTS_F_STALLED_TOTAL,
3687 "timeouts.stalledTimeoutTotal", 1);
3688 }
3689
3690 /* mod_tls-generated events */
snmp_tls_ctrl_handshake_err_ev(const void * event_data,void * user_data)3691 static void snmp_tls_ctrl_handshake_err_ev(const void *event_data,
3692 void *user_data) {
3693 if (snmp_engine == FALSE) {
3694 return;
3695 }
3696
3697 ev_incr_value(SNMP_DB_FTPS_SESS_F_CTRL_HANDSHAKE_ERR_TOTAL,
3698 "ftps.tlsSessions.ctrlHandshakeFailedTotal", 1);
3699 }
3700
snmp_tls_data_handshake_err_ev(const void * event_data,void * user_data)3701 static void snmp_tls_data_handshake_err_ev(const void *event_data,
3702 void *user_data) {
3703 if (snmp_engine == FALSE) {
3704 return;
3705 }
3706
3707 ev_incr_value(SNMP_DB_FTPS_SESS_F_DATA_HANDSHAKE_ERR_TOTAL,
3708 "ftps.tlsSessions.dataHandshakeFailedTotal", 1);
3709 }
3710
snmp_tls_verify_client_ev(const void * event_data,void * user_data)3711 static void snmp_tls_verify_client_ev(const void *event_data, void *user_data) {
3712 if (snmp_engine == FALSE) {
3713 return;
3714 }
3715
3716 ev_incr_value(SNMP_DB_FTPS_SESS_F_VERIFY_CLIENT_TOTAL,
3717 "ftps.tlsSessions.verifyClientTotal", 1);
3718 }
3719
snmp_tls_verify_client_err_ev(const void * event_data,void * user_data)3720 static void snmp_tls_verify_client_err_ev(const void *event_data,
3721 void *user_data) {
3722 if (snmp_engine == FALSE) {
3723 return;
3724 }
3725
3726 ev_incr_value(SNMP_DB_FTPS_SESS_F_VERIFY_CLIENT_ERR_TOTAL,
3727 "ftps.tlsSessions.verifyClientFailedTotal", 1);
3728 }
3729
3730 /* mod_sftp-generated events */
snmp_ssh2_kex_err_ev(const void * event_data,void * user_data)3731 static void snmp_ssh2_kex_err_ev(const void *event_data, void *user_data) {
3732 if (snmp_engine == FALSE) {
3733 return;
3734 }
3735
3736 ev_incr_value(SNMP_DB_SSH_SESS_F_KEX_ERR_TOTAL,
3737 "ssh.sshSessions.keyExchangeFailedTotal", 1);
3738 }
3739
snmp_ssh2_c2s_compress_ev(const void * event_data,void * user_data)3740 static void snmp_ssh2_c2s_compress_ev(const void *event_data, void *user_data) {
3741 if (snmp_engine == FALSE) {
3742 return;
3743 }
3744
3745 ev_incr_value(SNMP_DB_SSH_SESS_F_C2S_COMPRESS_TOTAL,
3746 "ssh.sshSessions.clientCompressionTotal", 1);
3747 }
3748
snmp_ssh2_s2c_compress_ev(const void * event_data,void * user_data)3749 static void snmp_ssh2_s2c_compress_ev(const void *event_data, void *user_data) {
3750 if (snmp_engine == FALSE) {
3751 return;
3752 }
3753
3754 ev_incr_value(SNMP_DB_SSH_SESS_F_S2C_COMPRESS_TOTAL,
3755 "ssh.sshSessions.serverCompressionTotal", 1);
3756 }
3757
snmp_ssh2_auth_hostbased_ev(const void * event_data,void * user_data)3758 static void snmp_ssh2_auth_hostbased_ev(const void *event_data,
3759 void *user_data) {
3760 if (snmp_engine == FALSE) {
3761 return;
3762 }
3763
3764 ev_incr_value(SNMP_DB_SSH_LOGINS_F_HOSTBASED_TOTAL,
3765 "ssh.sshLogins.hostbasedAuthTotal", 1);
3766 }
3767
snmp_ssh2_auth_hostbased_err_ev(const void * event_data,void * user_data)3768 static void snmp_ssh2_auth_hostbased_err_ev(const void *event_data,
3769 void *user_data) {
3770 if (snmp_engine == FALSE) {
3771 return;
3772 }
3773
3774 ev_incr_value(SNMP_DB_SSH_LOGINS_F_HOSTBASED_ERR_TOTAL,
3775 "ssh.sshLogins.hostbasedAuthFailedTotal", 1);
3776 }
3777
snmp_ssh2_auth_kbdint_ev(const void * event_data,void * user_data)3778 static void snmp_ssh2_auth_kbdint_ev(const void *event_data,
3779 void *user_data) {
3780 if (snmp_engine == FALSE) {
3781 return;
3782 }
3783
3784 ev_incr_value(SNMP_DB_SSH_LOGINS_F_KBDINT_TOTAL,
3785 "ssh.sshLogins.keyboardInteractiveAuthTotal", 1);
3786 }
3787
snmp_ssh2_auth_kbdint_err_ev(const void * event_data,void * user_data)3788 static void snmp_ssh2_auth_kbdint_err_ev(const void *event_data,
3789 void *user_data) {
3790 if (snmp_engine == FALSE) {
3791 return;
3792 }
3793
3794 ev_incr_value(SNMP_DB_SSH_LOGINS_F_KBDINT_ERR_TOTAL,
3795 "ssh.sshLogins.keyboardInteractiveAuthFailedTotal", 1);
3796 }
3797
snmp_ssh2_auth_passwd_ev(const void * event_data,void * user_data)3798 static void snmp_ssh2_auth_passwd_ev(const void *event_data,
3799 void *user_data) {
3800 if (snmp_engine == FALSE) {
3801 return;
3802 }
3803
3804 ev_incr_value(SNMP_DB_SSH_LOGINS_F_PASSWD_TOTAL,
3805 "ssh.sshLogins.passwordAuthTotal", 1);
3806 }
3807
snmp_ssh2_auth_passwd_err_ev(const void * event_data,void * user_data)3808 static void snmp_ssh2_auth_passwd_err_ev(const void *event_data,
3809 void *user_data) {
3810 if (snmp_engine == FALSE) {
3811 return;
3812 }
3813
3814 ev_incr_value(SNMP_DB_SSH_LOGINS_F_PASSWD_ERR_TOTAL,
3815 "ssh.sshLogins.passwordAuthFailedTotal", 1);
3816 }
3817
snmp_ssh2_auth_publickey_ev(const void * event_data,void * user_data)3818 static void snmp_ssh2_auth_publickey_ev(const void *event_data,
3819 void *user_data) {
3820 if (snmp_engine == FALSE) {
3821 return;
3822 }
3823
3824 ev_incr_value(SNMP_DB_SSH_LOGINS_F_PUBLICKEY_TOTAL,
3825 "ssh.sshLogins.publickeyAuthTotal", 1);
3826 }
3827
snmp_ssh2_auth_publickey_err_ev(const void * event_data,void * user_data)3828 static void snmp_ssh2_auth_publickey_err_ev(const void *event_data,
3829 void *user_data) {
3830 if (snmp_engine == FALSE) {
3831 return;
3832 }
3833
3834 ev_incr_value(SNMP_DB_SSH_LOGINS_F_PUBLICKEY_ERR_TOTAL,
3835 "ssh.sshLogins.publickeyAuthFailedTotal", 1);
3836 }
3837
snmp_ssh2_sftp_proto_version_ev(const void * event_data,void * user_data)3838 static void snmp_ssh2_sftp_proto_version_ev(const void *event_data,
3839 void *user_data) {
3840 unsigned long protocol_version;
3841 unsigned int field_id;
3842 const char *field_str;
3843
3844 if (snmp_engine == FALSE) {
3845 return;
3846 }
3847
3848 if (event_data == NULL) {
3849 /* Missing required data. */
3850 return;
3851 }
3852
3853 protocol_version = *((unsigned long *) event_data);
3854
3855 switch (protocol_version) {
3856 case 3:
3857 field_id = SNMP_DB_SFTP_SESS_F_SFTP_V3_TOTAL;
3858 field_str = "sftp.sftpSessions.protocolVersion3Total";
3859 break;
3860
3861 case 4:
3862 field_id = SNMP_DB_SFTP_SESS_F_SFTP_V4_TOTAL;
3863 field_str = "sftp.sftpSessions.protocolVersion4Total";
3864 break;
3865
3866 case 5:
3867 field_id = SNMP_DB_SFTP_SESS_F_SFTP_V5_TOTAL;
3868 field_str = "sftp.sftpSessions.protocolVersion5Total";
3869 break;
3870
3871 case 6:
3872 field_id = SNMP_DB_SFTP_SESS_F_SFTP_V6_TOTAL;
3873 field_str = "sftp.sftpSessions.protocolVersion6Total";
3874 break;
3875
3876 default:
3877 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
3878 "unknown SFTP protocol version %lu, ignoring", protocol_version);
3879 return;
3880 }
3881
3882 ev_incr_value(field_id, field_str, 1);
3883 }
3884
snmp_ssh2_sftp_sess_opened_ev(const void * event_data,void * user_data)3885 static void snmp_ssh2_sftp_sess_opened_ev(const void *event_data,
3886 void *user_data) {
3887 if (snmp_engine == FALSE) {
3888 return;
3889 }
3890
3891 ev_incr_value(SNMP_DB_SFTP_SESS_F_SESS_COUNT,
3892 "sftp.sftpSessions.sessionCount", 1);
3893 ev_incr_value(SNMP_DB_SFTP_SESS_F_SESS_TOTAL,
3894 "sftp.sftpSessions.sessionTotal", 1);
3895 }
3896
snmp_ssh2_sftp_sess_closed_ev(const void * event_data,void * user_data)3897 static void snmp_ssh2_sftp_sess_closed_ev(const void *event_data,
3898 void *user_data) {
3899 if (snmp_engine == FALSE) {
3900 return;
3901 }
3902
3903 ev_incr_value(SNMP_DB_SFTP_SESS_F_SESS_COUNT,
3904 "sftp.sftpSessions.sessionCount", -1);
3905 }
3906
snmp_ssh2_scp_sess_opened_ev(const void * event_data,void * user_data)3907 static void snmp_ssh2_scp_sess_opened_ev(const void *event_data,
3908 void *user_data) {
3909 if (snmp_engine == FALSE) {
3910 return;
3911 }
3912
3913 ev_incr_value(SNMP_DB_SCP_SESS_F_SESS_COUNT,
3914 "scp.scpSessions.sessionCount", 1);
3915 ev_incr_value(SNMP_DB_SCP_SESS_F_SESS_TOTAL,
3916 "scp.scpSessions.sessionTotal", 1);
3917 }
3918
snmp_ssh2_scp_sess_closed_ev(const void * event_data,void * user_data)3919 static void snmp_ssh2_scp_sess_closed_ev(const void *event_data,
3920 void *user_data) {
3921 if (snmp_engine == FALSE) {
3922 return;
3923 }
3924
3925 ev_incr_value(SNMP_DB_SCP_SESS_F_SESS_COUNT,
3926 "scp.scpSessions.sessionCount", -1);
3927 }
3928
3929 /* mod_ban-generated events */
snmp_ban_ban_user_ev(const void * event_data,void * user_data)3930 static void snmp_ban_ban_user_ev(const void *event_data, void *user_data) {
3931 ev_incr_value(SNMP_DB_BAN_BANS_F_USER_BAN_COUNT, "ban.bans.userBanCount", 1);
3932 ev_incr_value(SNMP_DB_BAN_BANS_F_USER_BAN_TOTAL, "ban.bans.userBanTotal", 1);
3933
3934 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_COUNT, "ban.bans.banCount", 1);
3935 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_TOTAL, "ban.bans.banTotal", 1);
3936 }
3937
snmp_ban_ban_host_ev(const void * event_data,void * user_data)3938 static void snmp_ban_ban_host_ev(const void *event_data, void *user_data) {
3939 ev_incr_value(SNMP_DB_BAN_BANS_F_HOST_BAN_COUNT, "ban.bans.hostBanCount", 1);
3940 ev_incr_value(SNMP_DB_BAN_BANS_F_HOST_BAN_TOTAL, "ban.bans.hostBanTotal", 1);
3941
3942 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_COUNT, "ban.bans.banCount", 1);
3943 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_TOTAL, "ban.bans.banTotal", 1);
3944 }
3945
snmp_ban_ban_class_ev(const void * event_data,void * user_data)3946 static void snmp_ban_ban_class_ev(const void *event_data, void *user_data) {
3947 ev_incr_value(SNMP_DB_BAN_BANS_F_CLASS_BAN_COUNT,
3948 "ban.bans.classBanCount", 1);
3949 ev_incr_value(SNMP_DB_BAN_BANS_F_CLASS_BAN_TOTAL,
3950 "ban.bans.classBanTotal", 1);
3951
3952 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_COUNT, "ban.bans.banCount", 1);
3953 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_TOTAL, "ban.bans.banTotal", 1);
3954 }
3955
snmp_ban_expired_ban_ev(const void * event_data,void * user_data)3956 static void snmp_ban_expired_ban_ev(const void *event_data, void *user_data) {
3957 const char *ban_desc = NULL;
3958
3959 if (event_data != NULL) {
3960 char *ptr = NULL;
3961
3962 ban_desc = (const char *) event_data;
3963
3964 ptr = strchr(ban_desc, ':');
3965 if (ptr != NULL) {
3966 /* To get the specific ban criteria/name later, use ptr + 1. */
3967
3968 if (strncmp(ban_desc, "USER", 4) == 0) {
3969 ev_incr_value(SNMP_DB_BAN_BANS_F_USER_BAN_COUNT,
3970 "ban.bans.userBanCount", -1);
3971
3972 } else if (strncmp(ban_desc, "HOST", 4) == 0) {
3973 ev_incr_value(SNMP_DB_BAN_BANS_F_HOST_BAN_COUNT,
3974 "ban.bans.hostBanCount", -1);
3975
3976 } else if (strncmp(ban_desc, "CLASS", 5) == 0) {
3977 ev_incr_value(SNMP_DB_BAN_BANS_F_CLASS_BAN_COUNT,
3978 "ban.bans.classBanCount", -1);
3979 }
3980
3981 ev_incr_value(SNMP_DB_BAN_BANS_F_BAN_COUNT, "ban.bans.banCount", -1);
3982 }
3983 }
3984 }
3985
snmp_ban_client_disconn_ev(const void * event_data,void * user_data)3986 static void snmp_ban_client_disconn_ev(const void *event_data,
3987 void *user_data) {
3988 const char *ban_desc = NULL;
3989
3990 if (event_data != NULL) {
3991 char *ptr = NULL;
3992
3993 ban_desc = (const char *) event_data;
3994
3995 ptr = strchr(ban_desc, ':');
3996 if (ptr != NULL) {
3997 /* To get the specific ban criteria/name later, use ptr + 1. */
3998
3999 if (strncmp(ban_desc, "USER", 4) == 0) {
4000 ev_incr_value(SNMP_DB_BAN_CONNS_F_USER_BAN_TOTAL,
4001 "ban.connections.userBannedTotal", 1);
4002
4003 } else if (strncmp(ban_desc, "HOST", 4) == 0) {
4004 ev_incr_value(SNMP_DB_BAN_CONNS_F_HOST_BAN_TOTAL,
4005 "ban.connections.hostBannedTotal", 1);
4006
4007 } else if (strncmp(ban_desc, "CLASS", 5) == 0) {
4008 ev_incr_value(SNMP_DB_BAN_CONNS_F_CLASS_BAN_TOTAL,
4009 "ban.connections.classBannedTotal", 1);
4010 }
4011
4012 ev_incr_value(SNMP_DB_BAN_CONNS_F_CONN_BAN_TOTAL,
4013 "ban.connections.connectionBannedTotal", 1);
4014 }
4015 }
4016 }
4017
4018 /* XXX Do we want to support any Controls/ftpctl actions? */
4019
4020 /* Initialization routines
4021 */
4022
snmp_init(void)4023 static int snmp_init(void) {
4024 struct protoent *pre = NULL;
4025
4026 snmp_pool = make_sub_pool(permanent_pool);
4027 pr_pool_tag(snmp_pool, MOD_SNMP_VERSION);
4028
4029 pr_event_register(&snmp_module, "core.max-instances",
4030 snmp_max_inst_ev, NULL);
4031 #if defined(PR_SHARED_MODULE)
4032 pr_event_register(&snmp_module, "core.module-unload", snmp_mod_unload_ev,
4033 NULL);
4034 #endif
4035 pr_event_register(&snmp_module, "core.postparse", snmp_postparse_ev, NULL);
4036 pr_event_register(&snmp_module, "core.restart", snmp_restart_ev, NULL);
4037 pr_event_register(&snmp_module, "core.shutdown", snmp_shutdown_ev, NULL);
4038 pr_event_register(&snmp_module, "core.startup", snmp_startup_ev, NULL);
4039
4040 /* Normally we should register the 'core.exit' event listener in the
4041 * sess_init callback. However, we use this listener to listen for
4042 * refused connections, e.g. connections refused by other modules'
4043 * sess_init callbacks. And depending on the module load order, another
4044 * module might refuse the connection before mod_snmp's sess_init callback
4045 * is invoked, which would prevent mod_snmp from registering its 'core.exit'
4046 * event listener.
4047 *
4048 * Thus to work around this timing issue, we register our 'core.exit' event
4049 * listener here, in the daemon process. It should not hurt anything.
4050 */
4051 pr_event_register(&snmp_module, "core.exit", snmp_exit_ev, NULL);
4052
4053 #ifdef HAVE_SETPROTOENT
4054 setprotoent(FALSE);
4055 #endif
4056
4057 pre = getprotobyname("udp");
4058 if (pre != NULL) {
4059 snmp_proto_udp = pre->p_proto;
4060 }
4061
4062 #ifdef HAVE_ENDPROTOENT
4063 endprotoent();
4064 #endif
4065
4066 #ifdef HAVE_RANDOM
4067 /* Seed the random(3) generator. */
4068 srandom((unsigned int) (time(NULL) * getpid()));
4069 #endif /* HAVE_RANDOM */
4070
4071 return 0;
4072 }
4073
snmp_sess_init(void)4074 static int snmp_sess_init(void) {
4075 config_rec *c;
4076 int res;
4077
4078 c = find_config(main_server->conf, CONF_PARAM, "SNMPEnable", FALSE);
4079 if (c != NULL) {
4080 snmp_enabled = *((int *) c->argv[0]);
4081 }
4082
4083 if (snmp_enabled == FALSE) {
4084 snmp_engine = FALSE;
4085 return 0;
4086 }
4087
4088 pr_event_register(&snmp_module, "core.invalid-command",
4089 snmp_cmd_invalid_ev, NULL);
4090 pr_event_register(&snmp_module, "core.timeout-idle",
4091 snmp_timeout_idle_ev, NULL);
4092 pr_event_register(&snmp_module, "core.timeout-login",
4093 snmp_timeout_login_ev, NULL);
4094 pr_event_register(&snmp_module, "core.timeout-no-transfer",
4095 snmp_timeout_noxfer_ev, NULL);
4096 pr_event_register(&snmp_module, "core.timeout-stalled",
4097 snmp_timeout_stalled_ev, NULL);
4098 pr_event_register(&snmp_module, "core.unhandled-command",
4099 snmp_cmd_invalid_ev, NULL);
4100
4101 pr_event_register(&snmp_module, "mod_auth.authentication-code",
4102 snmp_auth_code_ev, NULL);
4103
4104 if (pr_module_exists("mod_tls.c") == TRUE) {
4105 /* mod_tls events */
4106 pr_event_register(&snmp_module, "mod_tls.ctrl-handshake-failed",
4107 snmp_tls_ctrl_handshake_err_ev, NULL);
4108 pr_event_register(&snmp_module, "mod_tls.data-handshake-failed",
4109 snmp_tls_data_handshake_err_ev, NULL);
4110
4111 pr_event_register(&snmp_module, "mod_tls.verify-client",
4112 snmp_tls_verify_client_ev, NULL);
4113 pr_event_register(&snmp_module, "mod_tls.verify-client-failed",
4114 snmp_tls_verify_client_err_ev, NULL);
4115 }
4116
4117 if (pr_module_exists("mod_sftp.c") == TRUE) {
4118 /* mod_sftp events */
4119
4120 pr_event_register(&snmp_module, "mod_sftp.ssh2.kex.failed",
4121 snmp_ssh2_kex_err_ev, NULL);
4122 pr_event_register(&snmp_module, "mod_sftp.ssh2.client-compression",
4123 snmp_ssh2_c2s_compress_ev, NULL);
4124 pr_event_register(&snmp_module, "mod_sftp.ssh2.server-compression",
4125 snmp_ssh2_s2c_compress_ev, NULL);
4126
4127 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-hostbased",
4128 snmp_ssh2_auth_hostbased_ev, NULL);
4129 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-hostbased.failed",
4130 snmp_ssh2_auth_hostbased_err_ev, NULL);
4131
4132 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-kbdint",
4133 snmp_ssh2_auth_kbdint_ev, NULL);
4134 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-kbdint.failed",
4135 snmp_ssh2_auth_kbdint_err_ev, NULL);
4136
4137 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-password",
4138 snmp_ssh2_auth_passwd_ev, NULL);
4139 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-password.failed",
4140 snmp_ssh2_auth_passwd_err_ev, NULL);
4141
4142 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-publickey",
4143 snmp_ssh2_auth_publickey_ev, NULL);
4144 pr_event_register(&snmp_module, "mod_sftp.ssh2.auth-publickey.failed",
4145 snmp_ssh2_auth_publickey_err_ev, NULL);
4146
4147 pr_event_register(&snmp_module, "mod_sftp.sftp.session-opened",
4148 snmp_ssh2_sftp_sess_opened_ev, NULL);
4149 pr_event_register(&snmp_module, "mod_sftp.sftp.session-closed",
4150 snmp_ssh2_sftp_sess_closed_ev, NULL);
4151 pr_event_register(&snmp_module, "mod_sftp.sftp.protocol-version",
4152 snmp_ssh2_sftp_proto_version_ev, NULL);
4153
4154 pr_event_register(&snmp_module, "mod_sftp.scp.session-opened",
4155 snmp_ssh2_scp_sess_opened_ev, NULL);
4156 pr_event_register(&snmp_module, "mod_sftp.scp.session-closed",
4157 snmp_ssh2_scp_sess_closed_ev, NULL);
4158 }
4159
4160 if (pr_module_exists("mod_ban.c") == TRUE) {
4161 /* mod_ban events */
4162
4163 pr_event_register(&snmp_module, "mod_ban.ban-user", snmp_ban_ban_user_ev,
4164 NULL);
4165 pr_event_register(&snmp_module, "mod_ban.ban-host", snmp_ban_ban_host_ev,
4166 NULL);
4167 pr_event_register(&snmp_module, "mod_ban.ban-class", snmp_ban_ban_class_ev,
4168 NULL);
4169
4170 /* Note: For these event listeners to work as expected, the mod_snmp
4171 * module needs to be loaded AFTER mod_ban, i.e.:
4172 *
4173 * --with-modules=....:mod_ban:mod_snmp:...
4174 *
4175 * or:
4176 *
4177 * LoadModule mod_ban.c
4178 * ...
4179 * LoadModule mod_snmp.c
4180 *
4181 * That we, we can have our event listeners registered by the time that
4182 * mod_ban's sess_init callback causes events to be generated for an
4183 * incoming connection (including ban expiration).
4184 */
4185 pr_event_register(&snmp_module, "mod_ban.ban.expired",
4186 snmp_ban_expired_ban_ev, NULL);
4187 pr_event_register(&snmp_module, "mod_ban.ban.client-disconnected",
4188 snmp_ban_client_disconn_ev, NULL);
4189 }
4190
4191 res = snmp_db_incr_value(session.pool, SNMP_DB_DAEMON_F_CONN_COUNT, 1);
4192 if (res < 0) {
4193 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
4194 "error incrementing daemon.connectionCount: %s",
4195 strerror(errno));
4196 }
4197
4198 res = snmp_db_incr_value(session.pool, SNMP_DB_DAEMON_F_CONN_TOTAL, 1);
4199 if (res < 0) {
4200 (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
4201 "error incrementing daemon.connectionTotal: %s",
4202 strerror(errno));
4203 }
4204
4205 #ifdef HAVE_RANDOM
4206 /* Reseed the random(3) generator. */
4207 srandom((unsigned int) (time(NULL) * getpid()));
4208 #endif /* HAVE_RANDOM */
4209
4210 c = find_config(main_server->conf, CONF_PARAM, "SNMPNotify", FALSE);
4211 while (c != NULL) {
4212 pr_signals_handle();
4213
4214 if (snmp_notifys == NULL) {
4215 snmp_notifys = make_array(session.pool, 1, sizeof(pr_netaddr_t *));
4216 }
4217
4218 *((pr_netaddr_t **) push_array(snmp_notifys)) = c->argv[0];
4219
4220 c = find_config_next(c, c->next, CONF_PARAM, "SNMPNotify", FALSE);
4221 }
4222
4223 return 0;
4224 }
4225
4226 /* Module API tables
4227 */
4228
4229 static conftable snmp_conftab[] = {
4230 { "SNMPAgent", set_snmpagent, NULL },
4231 { "SNMPCommunity", set_snmpcommunity, NULL },
4232 { "SNMPEnable", set_snmpenable, NULL },
4233 { "SNMPEngine", set_snmpengine, NULL },
4234 { "SNMPLog", set_snmplog, NULL },
4235 { "SNMPMaxVariables", set_snmpmaxvariables, NULL },
4236 { "SNMPNotify", set_snmpnotify, NULL },
4237 { "SNMPOptions", set_snmpoptions, NULL },
4238 { "SNMPTables", set_snmptables, NULL },
4239 { NULL }
4240 };
4241
4242 static cmdtable snmp_cmdtab[] = {
4243 { PRE_CMD, C_LIST, G_NONE, snmp_pre_list, FALSE, FALSE },
4244 { LOG_CMD, C_LIST, G_NONE, snmp_log_list, FALSE, FALSE },
4245 { LOG_CMD_ERR, C_LIST, G_NONE, snmp_err_list, FALSE, FALSE },
4246
4247 { PRE_CMD, C_MLSD, G_NONE, snmp_pre_list, FALSE, FALSE },
4248 { LOG_CMD, C_MLSD, G_NONE, snmp_log_list, FALSE, FALSE },
4249 { LOG_CMD_ERR, C_MLSD, G_NONE, snmp_err_list, FALSE, FALSE },
4250
4251 { PRE_CMD, C_NLST, G_NONE, snmp_pre_list, FALSE, FALSE },
4252 { LOG_CMD, C_NLST, G_NONE, snmp_log_list, FALSE, FALSE },
4253 { LOG_CMD_ERR, C_NLST, G_NONE, snmp_err_list, FALSE, FALSE },
4254
4255 { LOG_CMD, C_PASS, G_NONE, snmp_log_pass, FALSE, FALSE },
4256 { LOG_CMD_ERR, C_PASS, G_NONE, snmp_err_pass, FALSE, FALSE },
4257
4258 { PRE_CMD, C_RETR, G_NONE, snmp_pre_retr, FALSE, FALSE },
4259 { LOG_CMD, C_RETR, G_NONE, snmp_log_retr, FALSE, FALSE },
4260 { LOG_CMD_ERR, C_RETR, G_NONE, snmp_err_retr, FALSE, FALSE },
4261
4262 { PRE_CMD, C_STOR, G_NONE, snmp_pre_stor, FALSE, FALSE },
4263 { LOG_CMD, C_STOR, G_NONE, snmp_log_stor, FALSE, FALSE },
4264 { LOG_CMD_ERR, C_STOR, G_NONE, snmp_err_stor, FALSE, FALSE },
4265
4266 /* For mod_tls */
4267 { LOG_CMD, C_AUTH, G_NONE, snmp_log_auth, FALSE, FALSE },
4268 { LOG_CMD, C_CCC, G_NONE, snmp_log_ccc, FALSE, FALSE },
4269 { LOG_CMD_ERR, C_CCC, G_NONE, snmp_err_ccc, FALSE, FALSE },
4270
4271 { 0, NULL }
4272 };
4273
4274 module snmp_module = {
4275 /* Always NULL */
4276 NULL, NULL,
4277
4278 /* Module API version */
4279 0x20,
4280
4281 /* Module name */
4282 "snmp",
4283
4284 /* Module configuration handler table */
4285 snmp_conftab,
4286
4287 /* Module command handler table */
4288 snmp_cmdtab,
4289
4290 /* Module authentication handler table */
4291 NULL,
4292
4293 /* Module initialization */
4294 snmp_init,
4295
4296 /* Session initialization */
4297 snmp_sess_init,
4298
4299 /* Module version */
4300 MOD_SNMP_VERSION
4301 };
4302