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