snmpd(8): don't traverse back in tree

2022-07-22 Thread Martijn van Duren
When we have 2 overlapping regions within the same backend the current
code takes the OID of the parent region after the child region returned
an EOMV. This is of course wrong and creates an infinite loop.

OK?

martijn@

Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.6
diff -u -p -r1.6 application.c
--- application.c   30 Jun 2022 11:28:36 -  1.6
+++ application.c   22 Jul 2022 15:07:53 -
@@ -1260,6 +1260,7 @@ appl_varbind_backend(struct appl_varbind
struct appl_request_upstream *ureq = ivb->avi_request_upstream;
struct appl_region search, *region, *pregion;
struct appl_varbind *vb = &(ivb->avi_varbind);
+   struct ber_oid oid;
int next, cmp;
 
next = ureq->aru_pdu->be_type == SNMP_C_GETNEXTREQ ||
@@ -1310,10 +1311,15 @@ appl_varbind_backend(struct appl_varbind
}
ivb->avi_region = region;
if (next) {
+   oid = region->ar_oid;
do {
pregion = region;
-   region = appl_region_next(ureq->aru_ctx,
-   &(region->ar_oid), pregion);
+   region = appl_region_next(ureq->aru_ctx, , pregion);
+   if (region != NULL &&
+   appl_region_cmp(region, pregion) > 0)
+   oid = region->ar_oid;
+   else
+   ober_oid_nextsibling();
} while (region != NULL &&
region->ar_backend == pregion->ar_backend);
if (region == NULL) {



snmpd(8): restart requests where backend disappeared.

2022-07-22 Thread Martijn van Duren
appl_request_downstream_free gets called from 3 locations:
- appl_request_upstream_free: called from appl_request_upstream_reply
  and cleans up after a request has been answered, whether all the
  downstream requests have been completed or not (when timed out)
- appl_response: When a downstream reqeuest has been completed
- appl_close: When a downstream backend has been closed.

appl_request_upstream_free is already done with the upstream request
and appl_response already automatically starts the next iteration of
missing varbinds.

The problem arrises when appl_close is called (e.g. a backend
disappears unexpected) while there are still pending downstream
requests. In that case all references to the upstream request are
lost and we have a memory leak.

Diff below resets the pending varbinds to new and restarts the
parsing procedure.

OK?

martijn@

Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.6
diff -u -p -r1.6 application.c
--- application.c   30 Jun 2022 11:28:36 -  1.6
+++ application.c   22 Jul 2022 14:59:00 -
@@ -716,6 +716,7 @@ void
 appl_request_downstream_free(struct appl_request_downstream *dreq)
 {
struct appl_varbind_internal *vb;
+   int retry = 0;
 
if (dreq == NULL)
return;
@@ -723,9 +724,16 @@ appl_request_downstream_free(struct appl
RB_REMOVE(appl_requests, &(dreq->ard_backend->ab_requests), dreq);
evtimer_del(&(dreq->ard_timer));
 
-   for (vb = dreq->ard_vblist; vb != NULL; vb = vb->avi_next)
+   for (vb = dreq->ard_vblist; vb != NULL; vb = vb->avi_next) { 
vb->avi_request_downstream = NULL;
+   if (vb->avi_state == APPL_VBSTATE_PENDING) {
+   vb->avi_state = APPL_VBSTATE_NEW;
+   retry = 1;
+   }
+   }
 
+   if (retry)
+   appl_request_upstream_resolve(dreq->ard_request);
free(dreq);
 }
 



snmpd(8): honour searchrange end

2022-07-22 Thread Martijn van Duren
This is the snmpd(8) part of searchrange end issue mentioned in my
libagentx diff from yesterday.[0]

Since searchranges are an agentx specific thing I implemented two
cases:
1) Backends that support searchranges set ab_range to 1
   (application_agentx.c) and check the av_oid_end in
   appl_varbind_valid. If it fails here we generate a GENERR
   and disconnect the backend.
2) Backends that don't support searchranges set ab_range to 0 and
   are not checked for overflow in appl_varbind_valid, but instead
   treat the response as ENDOFMIBVIEW and continue searching at
   av_oid_end.

Since this is already the 3rd EOMV case added I decided to move to
a simple variable and do the reset-logic in a single place.

While here, also fix an indent in appl_close.

OK?

martijn@

[0] https://marc.info/?l=openbsd-tech=165843466721371=2

Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.6
diff -u -p -r1.6 application.c
--- application.c   30 Jun 2022 11:28:36 -  1.6
+++ application.c   22 Jul 2022 13:13:43 -
@@ -126,7 +126,7 @@ void appl_request_downstream_send(struct
 void appl_request_downstream_timeout(int, short, void *);
 void appl_request_upstream_reply(struct appl_request_upstream *);
 int appl_varbind_valid(struct appl_varbind *, struct appl_varbind *, int, int,
-const char **);
+int, const char **);
 int appl_varbind_backend(struct appl_varbind_internal *);
 void appl_varbind_error(struct appl_varbind_internal *, enum appl_error);
 void appl_report(struct snmp_message *, int32_t, struct ber_oid *,
@@ -541,7 +541,7 @@ appl_close(struct appl_backend *backend)
 
RB_FOREACH_SAFE(request, appl_requests,
&(backend->ab_requests), trequest)
-   appl_request_downstream_free(request);
+   appl_request_downstream_free(request);
 }
 
 struct appl_region *
@@ -1025,14 +1025,13 @@ appl_response(struct appl_backend *backe
 {
struct appl_request_downstream *dreq, search;
struct appl_request_upstream *ureq = NULL;
-   struct appl_region *nregion;
const char *errstr;
char oidbuf[1024];
enum snmp_pdutype pdutype;
struct appl_varbind *vb;
struct appl_varbind_internal *origvb = NULL;
int invalid = 0;
-   int next = 0;
+   int next = 0, eomv;
int32_t i;
 
appl_pdu_log(backend, SNMP_C_RESPONSE, requestid, error, index, vblist);
@@ -1055,7 +1054,7 @@ appl_response(struct appl_backend *backe
for (i = 1; vb != NULL; vb = vb->av_next, i++) {
 if (!appl_varbind_valid(vb, origvb == NULL ?
NULL : &(origvb->avi_varbind), next,
-error != APPL_ERROR_NOERROR, )) {
+error != APPL_ERROR_NOERROR, backend->ab_range, )) {
smi_oid2string(&(vb->av_oid), oidbuf,
sizeof(oidbuf), 0);
log_warnx("%s: %"PRIu32" %s: %s",
@@ -1068,35 +1067,36 @@ appl_response(struct appl_backend *backe
appl_varbind_error(origvb, error);
origvb->avi_state = APPL_VBSTATE_DONE;
origvb->avi_varbind.av_oid = vb->av_oid;
-   if (vb->av_value != NULL &&
+
+   eomv = vb->av_value != NULL &&
vb->av_value->be_class == BER_CLASS_CONTEXT &&
-   vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW) {
-   nregion = appl_region_next(ureq->aru_ctx,
-   &(vb->av_oid), origvb->avi_region);
-   if (nregion != NULL) {
-   ober_free_elements(vb->av_value);
-   origvb->avi_varbind.av_oid =
-   nregion->ar_oid;
-   origvb->avi_varbind.av_include = 1;
-   vb->av_value = NULL;
-   origvb->avi_state = APPL_VBSTATE_NEW;
-   }
-   }
+   vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW;
+   /*
+* Treat results past av_oid_end for backends that
+* don't support searchranges as EOMV
+*/
+   eomv |= !backend->ab_range && next &&
+   ober_oid_cmp(&(vb->av_oid),
+   &(origvb->avi_varbind.av_oid_end)) > 0;
/* RFC 3584 section 4.2.2.1 */
if (ureq->aru_pduversion == SNMP_V1 &&
vb->av_value != NULL &&
vb->av_value->be_class == BER_CLASS_APPLICATION &&
vb->av_value->be_type 

libagentx: honour searchrange end

2022-07-21 Thread Martijn van Duren
When doing a getnext/getbulk request, agentx diverges from snmp that it
sends a searchrange, instead of a simple next. The end oid is currently
not correctly handled by both snmpd(8) and libagentx. If a backend has
two ranges with one or more other backends having a region claimed
in between snmpd(8) can skip over that other region.

To make it concrete. Moving most of mib.c into an libagentx based
application make it claim ipfRouteEntStatus and dot1dBaseNumPorts.
But the snmp tree (which resides in between) remains part of snmpd(8).
Doing a getnext on ipfRouteEntStatus.9 would make snmpd(8) skip to
dot1dBaseNumPorts.0, instead of snmpInPkts.0.

This diff should fix the libagentx side of things.

OK?

martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.15
diff -u -p -r1.15 agentx.c
--- agentx.c19 Jul 2022 19:25:42 -  1.15
+++ agentx.c21 Jul 2022 20:14:04 -
@@ -2722,7 +2722,8 @@ agentx_varbind_start(struct agentx_varbi
 getnext:
while (axo != NULL && axo->axo_cstate != AX_CSTATE_OPEN)
axo = RB_NEXT(axc_objects, &(axc->axc_objects), axo);
-   if (axo == NULL) {
+   if (axo == NULL ||
+   ax_oid_cmp(&(axo->axo_oid), &(axv->axv_end)) > 0) {
agentx_varbind_endofmibview(axv);
return;
}



libagentx: enable objects on dynamic index enabling

2022-07-17 Thread Martijn van Duren
Diff below is needed for migrating snmpd's mib.c to a libagentx based
environment. Specifically the OPENBSD-MEM-MIB:memIfTable, which relies
on IF-MIB:ifIndex.

The issue bubbles forth from the following behaviour:
In libagentx both an object and an index are enabled (started) based
when their respective region is started. The order in which these
regions are started is undetermined.
For agentx_object the agentx_object_start function is halted when not
all indices are in AX_CSTATE_OPEN.

The problem arises from the fact that agentx_index_finalize (the
function called when we know that the request to be opened can be
answered) is combined with a dynamic index (an index not registered
at the snmpd server, but determined by the libagentx based application):
The index is placed in the AX_CSTATE_OPEN state, but it returns
immediately, ignoring any objects that rely on it being opened.

The diff below replaces the return statement to a jump statement
to the final part of the function trying to open the functions.

OK?

martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.14
diff -u -p -r1.14 agentx.c
--- agentx.c24 Oct 2021 18:03:27 -  1.14
+++ agentx.c17 Jul 2022 12:03:55 -
@@ -1660,7 +1660,7 @@ agentx_index_finalize(struct ax_pdu *pdu
 #endif
if (axi->axi_type == AXI_TYPE_DYNAMIC) {
axi->axi_cstate = AX_CSTATE_OPEN;
-   return 0;
+   goto objects_start;
}
 
resp = &(pdu->ap_payload.ap_response);
@@ -1717,6 +1717,7 @@ agentx_index_finalize(struct ax_pdu *pdu
if (axi->axi_dstate == AX_DSTATE_CLOSE)
return agentx_index_close(axi);
 
+ objects_start:
/* TODO Make use of range_subid register */
for (i = 0; i < axi->axi_objectlen; i++) {
if (axi->axi_object[i]->axo_dstate == AX_DSTATE_OPEN) {



Re: snmpd(8): clean up variable printing

2022-06-29 Thread Martijn van Duren
On Wed, 2022-01-19 at 16:23 +0100, Martijn van Duren wrote:
> The new code uses smi_print_element when debugging is enabled to trace
> calls. Unfortunately the current smi_print_element lacks in quite a few
> departments. This diff rewrites smi_print_element to be more concise
> than what we currently have, without moving into the more complex
> territory that snmp(1) has.
> 
> Unknown types are printed in a similar fashion to what tcpdump(8)'s
> snmp output does.
> 
> This change helps mostly with exceptions (NOSUCH{OBJECT,INSTANCE} and
> ENDOFMIBVIEW) and distinguishing between different integer types.
> 
> I kept the current implementation under smi_print_element_legacy, so
> that we don't change the output of trap handlers. We should probably
> revisit that one at some point, but I don't think to go into that
> territory right now.
> 
> OK?
> 
> martijn@
> 
> p.s. I'm not particularly thrilled about the type hinting, but it's
> the cleanest that I could come up with without being too much of an
> eyesore or filling the screen up even further.
> 
ping

Index: smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.30
diff -u -p -r1.30 smi.c
--- smi.c   21 Oct 2021 15:08:15 -  1.30
+++ smi.c   29 Jun 2022 11:44:26 -
@@ -46,6 +46,7 @@
 
 #include "snmpd.h"
 #include "mib.h"
+#include "application.h"
 
 #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
 
@@ -461,8 +462,9 @@ smi_debug_elements(struct ber_element *r
 }
 #endif
 
+/* Keep around so trap handle scripts don't break */
 char *
-smi_print_element(struct ber_element *root)
+smi_print_element_legacy(struct ber_element *root)
 {
char*str = NULL, *buf, *p;
size_t   len, i;
@@ -520,6 +522,140 @@ smi_print_element(struct ber_element *ro
case BER_TYPE_SET:
default:
str = strdup("");
+   break;
+   }
+
+   return (str);
+
+ fail:
+   free(str);
+   return (NULL);
+}
+
+char *
+smi_print_element(struct ber_element *root)
+{
+   char*str = NULL, *buf, *p;
+   long longv;
+   struct ber_oid   o;
+   char strbuf[BUFSIZ];
+
+   switch (root->be_class) {
+   case BER_CLASS_UNIVERSAL:
+   switch (root->be_type) {
+   case BER_TYPE_INTEGER:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld", v) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OBJECT:
+   if (ober_get_oid(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s", smi_oid2string(, strbuf,
+   sizeof(strbuf), 0)) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OCTETSTRING:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   p = reallocarray(NULL, 4, root->be_len + 1);
+   if (p == NULL)
+   goto fail;
+   strvisx(p, buf, root->be_len, VIS_NL);
+   if (asprintf(, "\"%s\"", p) == -1) {
+   free(p);
+   goto fail;
+   }
+   free(p);
+   break;
+   case BER_TYPE_NULL:
+   if (asprintf(, "null") == -1)
+   goto fail;
+   break;
+   default:
+   /* Should not happen in a valid SNMP packet */
+   if (asprintf(, "[U/%u]", root->be_type) == -1)
+   goto fail;
+   break;
+   }
+   break;
+   case BER_CLASS_APPLICATION:
+   switch (root->be_type) {
+   case SNMP_T_IPADDR:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s",
+   inet_ntoa(*(struct in_addr *)buf)) == -1)
+   goto fail;
+   break;
+   case SNMP_T_COUNTER32:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld(c32)", v) == -1)
+   goto fail;
+   break;
+   case SNMP_T_GAUGE32:
+   if (ober_get_intege

Re: snmpd(8): Add blocklist feature

2022-06-29 Thread Martijn van Duren
On Tue, 2022-06-28 at 12:33 +0200, Martijn van Duren wrote:
> On Tue, 2022-06-28 at 12:21 +0200, Martijn van Duren wrote:
> > On Tue, 2022-06-28 at 10:21 +0200, Martijn van Duren wrote:
> > > Back in 2020 florian@ added the filter-pf-addresses keyword.
> > > Although useful, I always felt it was a bit too case-specific. The diff
> > > below adds a new blocklist feature/backend, which takes hold of an
> > > entire subtree, effectively removing it from the tree.
> > > 
> > > With this I've deprecated the filter-pf-address case and should
> > > probably be removed somewhere after 7.4. The filter-routes case can't
> > > be removed unfortunately, since its behaviour is not identical, and
> > > instead adds filters to the routing socket, preventing updates being
> > > pushed to snmpd(8).
> > > 
> > > Feedback/OK?
> > > 
> > > martijn@
> > > 
> > Also clean up after ourselves if appl_exception fails.
> > 
> *sigh* Missed a return.
> 
And also some cleanup during shutdown.

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- Makefile19 Jan 2022 11:00:56 -  1.18
+++ Makefile29 Jun 2022 11:35:23 -
@@ -3,6 +3,7 @@
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
 SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
+   application_blocklist.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.5
diff -u -p -r1.5 application.c
--- application.c   27 Jun 2022 10:31:17 -  1.5
+++ application.c   29 Jun 2022 11:35:23 -
@@ -148,6 +148,7 @@ RB_PROTOTYPE_STATIC(appl_requests, appl_
 void
 appl_init(void)
 {
+   appl_blocklist_init();
appl_legacy_init();
 }
 
@@ -156,6 +157,7 @@ appl_shutdown(void)
 {
struct appl_context *ctx, *tctx;
 
+   appl_blocklist_shutdown();
appl_legacy_shutdown();
 
TAILQ_FOREACH_SAFE(ctx, , ac_entries, tctx) {
Index: application.h
===
RCS file: /cvs/src/usr.sbin/snmpd/application.h,v
retrieving revision 1.1
diff -u -p -r1.1 application.h
--- application.h   19 Jan 2022 10:59:35 -  1.1
+++ application.h   29 Jun 2022 11:35:23 -
@@ -133,3 +133,7 @@ struct ber_element *appl_exception(enum 
 /* application_legacy.c */
 voidappl_legacy_init(void);
 voidappl_legacy_shutdown(void);
+
+/* application_blocklist.c */
+voidappl_blocklist_init(void);
+voidappl_blocklist_shutdown(void);
Index: application_blocklist.c
===
RCS file: application_blocklist.c
diff -N application_blocklist.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application_blocklist.c     29 Jun 2022 11:35:23 -
@@ -0,0 +1,141 @@
+/* $OpenBSD: application.c,v 1.5 2022/06/27 10:31:17 martijn Exp $ */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include "application.h"
+#include "snmpd.h"
+
+struct appl_varbind *appl_blocklist_response(size_t);
+void appl_blocklist_get(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_blocklist_getnext(struct appl_backend *, int32_t, int32_t,
+const char *, struct appl_varbind *);
+
+struct appl_backend_functions appl_blocklist_functions = {
+   .ab_get = appl_blocklist_get,
+   .ab_getnext = appl_blocklist_getnext,
+   .ab_getbulk = NULL,
+};
+
+struct appl_backend appl_blocklist = {
+   .ab_name = "blocklist",
+   .ab_cookie = NULL,
+   .ab_retries = 0,
+   .ab_fn = _blocklist_functions
+};
+
+static struct appl_varbind *response = NULL;
+static size_t responsesz = 0;
+
+struct appl_varbind *
+appl

Re: snmpd(8): Add blocklist feature

2022-06-28 Thread Martijn van Duren
On Tue, 2022-06-28 at 12:21 +0200, Martijn van Duren wrote:
> On Tue, 2022-06-28 at 10:21 +0200, Martijn van Duren wrote:
> > Back in 2020 florian@ added the filter-pf-addresses keyword.
> > Although useful, I always felt it was a bit too case-specific. The diff
> > below adds a new blocklist feature/backend, which takes hold of an
> > entire subtree, effectively removing it from the tree.
> > 
> > With this I've deprecated the filter-pf-address case and should
> > probably be removed somewhere after 7.4. The filter-routes case can't
> > be removed unfortunately, since its behaviour is not identical, and
> > instead adds filters to the routing socket, preventing updates being
> > pushed to snmpd(8).
> > 
> > Feedback/OK?
> > 
> > martijn@
> > 
> Also clean up after ourselves if appl_exception fails.
> 
*sigh* Missed a return.

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- Makefile19 Jan 2022 11:00:56 -  1.18
+++ Makefile28 Jun 2022 10:32:40 -
@@ -3,6 +3,7 @@
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
 SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
+   application_blocklist.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.5
diff -u -p -r1.5 application.c
--- application.c   27 Jun 2022 10:31:17 -  1.5
+++ application.c   28 Jun 2022 10:32:40 -
@@ -148,6 +148,7 @@ RB_PROTOTYPE_STATIC(appl_requests, appl_
 void
 appl_init(void)
 {
+   appl_blocklist_init();
appl_legacy_init();
 }
 
Index: application.h
===
RCS file: /cvs/src/usr.sbin/snmpd/application.h,v
retrieving revision 1.1
diff -u -p -r1.1 application.h
--- application.h   19 Jan 2022 10:59:35 -  1.1
+++ application.h   28 Jun 2022 10:32:40 -
@@ -133,3 +133,6 @@ struct ber_element *appl_exception(enum 
 /* application_legacy.c */
 voidappl_legacy_init(void);
 voidappl_legacy_shutdown(void);
+
+/* application_blocklist.c */
+voidappl_blocklist_init(void);
Index: application_blocklist.c
===
RCS file: application_blocklist.c
diff -N application_blocklist.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application_blocklist.c 28 Jun 2022 10:32:40 -
@@ -0,0 +1,134 @@
+/*     $OpenBSD: application.c,v 1.5 2022/06/27 10:31:17 martijn Exp $ */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include "application.h"
+#include "snmpd.h"
+
+struct appl_varbind *appl_blocklist_response(size_t);
+void appl_blocklist_get(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_blocklist_getnext(struct appl_backend *, int32_t, int32_t,
+const char *, struct appl_varbind *);
+
+struct appl_backend_functions appl_blocklist_functions = {
+   .ab_get = appl_blocklist_get,
+   .ab_getnext = appl_blocklist_getnext,
+   .ab_getbulk = NULL,
+};
+
+struct appl_backend appl_blocklist = {
+   .ab_name = "blocklist",
+   .ab_cookie = NULL,
+   .ab_retries = 0,
+   .ab_fn = _blocklist_functions
+};
+
+static struct appl_varbind *response = NULL;
+static size_t responsesz = 0;
+
+struct appl_varbind *
+appl_blocklist_response(size_t nvarbind)
+{
+   struct appl_varbind *tmp;
+   size_t i;
+
+   if (responsesz < nvarbind) {
+   if ((tmp = recallocarray(response, responsesz, nvarbind,
+   sizeof(*response))) == NULL) {
+   log_warn(NULL);
+   return NULL;
+   }
+   responsesz = nvarbind;
+   response = tmp;
+   }
+   for (i = 0; i <

Re: snmpd(8): Add blocklist feature

2022-06-28 Thread Martijn van Duren
On Tue, 2022-06-28 at 10:21 +0200, Martijn van Duren wrote:
> Back in 2020 florian@ added the filter-pf-addresses keyword.
> Although useful, I always felt it was a bit too case-specific. The diff
> below adds a new blocklist feature/backend, which takes hold of an
> entire subtree, effectively removing it from the tree.
> 
> With this I've deprecated the filter-pf-address case and should
> probably be removed somewhere after 7.4. The filter-routes case can't
> be removed unfortunately, since its behaviour is not identical, and
> instead adds filters to the routing socket, preventing updates being
> pushed to snmpd(8).
> 
> Feedback/OK?
> 
> martijn@
> 
Also clean up after ourselves if appl_exception fails.

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- Makefile19 Jan 2022 11:00:56 -  1.18
+++ Makefile28 Jun 2022 10:20:23 -
@@ -3,6 +3,7 @@
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
 SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
+   application_blocklist.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.5
diff -u -p -r1.5 application.c
--- application.c   27 Jun 2022 10:31:17 -  1.5
+++ application.c   28 Jun 2022 10:20:23 -
@@ -148,6 +148,7 @@ RB_PROTOTYPE_STATIC(appl_requests, appl_
 void
 appl_init(void)
 {
+   appl_blocklist_init();
appl_legacy_init();
 }
 
Index: application.h
===
RCS file: /cvs/src/usr.sbin/snmpd/application.h,v
retrieving revision 1.1
diff -u -p -r1.1 application.h
--- application.h   19 Jan 2022 10:59:35 -  1.1
+++ application.h   28 Jun 2022 10:20:23 -
@@ -133,3 +133,6 @@ struct ber_element *appl_exception(enum 
 /* application_legacy.c */
 voidappl_legacy_init(void);
 voidappl_legacy_shutdown(void);
+
+/* application_blocklist.c */
+voidappl_blocklist_init(void);
Index: application_blocklist.c
===
RCS file: application_blocklist.c
diff -N application_blocklist.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application_blocklist.c 28 Jun 2022 10:20:23 -
@@ -0,0 +1,132 @@
+/* $OpenBSD: application.c,v 1.5 2022/06/27 10:31:17 martijn Exp $ */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include "application.h"
+#include "snmpd.h"
+
+struct appl_varbind *appl_blocklist_response(size_t);
+void appl_blocklist_get(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_blocklist_getnext(struct appl_backend *, int32_t, int32_t,
+const char *, struct appl_varbind *);
+
+struct appl_backend_functions appl_blocklist_functions = {
+   .ab_get = appl_blocklist_get,
+   .ab_getnext = appl_blocklist_getnext,
+   .ab_getbulk = NULL,
+};
+
+struct appl_backend appl_blocklist = {
+   .ab_name = "blocklist",
+   .ab_cookie = NULL,
+   .ab_retries = 0,
+   .ab_fn = _blocklist_functions
+};
+
+static struct appl_varbind *response = NULL;
+static size_t responsesz = 0;
+
+struct appl_varbind *
+appl_blocklist_response(size_t nvarbind)
+{
+   struct appl_varbind *tmp;
+   size_t i;
+
+   if (responsesz < nvarbind) {
+   if ((tmp = recallocarray(response, responsesz, nvarbind,
+   sizeof(*response))) == NULL) {
+   log_warn(NULL);
+   return NULL;
+   }
+   responsesz = nvarbind;
+   response = tmp;
+   }
+   for (i = 0; i < nvarbind; i++)
+   response[i].av_next = i + 1 == nvarbind ?
+   NULL : &(response[i + 1]);
+   return response;
+}
+
+void
+appl_blocklist_

snmpd(8): Allow for symbolic OID names in snmpd.conf

2022-06-28 Thread Martijn van Duren
When playing with the blocklist I noticed that the oid directive only
supports numeric OIDs. So if florian wants to use filter-pf-table in the
future he'd have to set:
blocklist 1.3.6.1.4.1.30155.1.9.129
which is pure insanity, if:
blocklist pfTblAddrTable
could be an option.

Diff below changes the "oid" parse.y definition from ober_string2oid to
smi_string2oid, which allows for the locally known symbolic names.
This also helps out with existing statements ("system oid",
"trap handle oid", and "trap receiver", and "oid").

While here, rename sysoid to oid, since it's not used by the system
oid anymore and do a little KNF.

OK?

martijn@

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.73
diff -u -p -r1.73 parse.y
--- parse.y 21 Nov 2021 13:33:53 -  1.73
+++ parse.y 28 Jun 2022 09:02:36 -
@@ -666,21 +666,20 @@ optwrite  : READONLY  { $$ = 
0; }
;
 
 oid: STRING{
-   struct ber_oid  *sysoid;
-   if ((sysoid =
-   calloc(1, sizeof(*sysoid))) == NULL) {
+   struct ber_oid  *oid;
+   if ((oid = calloc(1, sizeof(*oid))) == NULL) {
yyerror("calloc");
free($1);
YYERROR;
}
-   if (ober_string2oid($1, sysoid) == -1) {
+   if (smi_string2oid($1, oid) == -1) {
yyerror("invalid OID: %s", $1);
-   free(sysoid);
+   free(oid);
free($1);
YYERROR;
}
free($1);
-   $$ = sysoid;
+   $$ = oid;
}
;
 



snmpd(8): Add blocklist feature

2022-06-28 Thread Martijn van Duren
Back in 2020 florian@ added the filter-pf-addresses keyword.
Although useful, I always felt it was a bit too case-specific. The diff
below adds a new blocklist feature/backend, which takes hold of an
entire subtree, effectively removing it from the tree.

With this I've deprecated the filter-pf-address case and should
probably be removed somewhere after 7.4. The filter-routes case can't
be removed unfortunately, since its behaviour is not identical, and
instead adds filters to the routing socket, preventing updates being
pushed to snmpd(8).

Feedback/OK?

martijn@

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- Makefile19 Jan 2022 11:00:56 -  1.18
+++ Makefile28 Jun 2022 08:18:17 -
@@ -3,6 +3,7 @@
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
 SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
+   application_blocklist.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.5
diff -u -p -r1.5 application.c
--- application.c   27 Jun 2022 10:31:17 -  1.5
+++ application.c   28 Jun 2022 08:18:17 -
@@ -148,6 +148,7 @@ RB_PROTOTYPE_STATIC(appl_requests, appl_
 void
 appl_init(void)
 {
+   appl_blocklist_init();
appl_legacy_init();
 }
 
Index: application.h
===
RCS file: /cvs/src/usr.sbin/snmpd/application.h,v
retrieving revision 1.1
diff -u -p -r1.1 application.h
--- application.h   19 Jan 2022 10:59:35 -  1.1
+++ application.h   28 Jun 2022 08:18:17 -
@@ -133,3 +133,6 @@ struct ber_element *appl_exception(enum 
 /* application_legacy.c */
 voidappl_legacy_init(void);
 voidappl_legacy_shutdown(void);
+
+/* application_blocklist.c */
+voidappl_blocklist_init(void);
Index: application_blocklist.c
===
RCS file: application_blocklist.c
diff -N application_blocklist.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application_blocklist.c 28 Jun 2022 08:18:17 -
@@ -0,0 +1,122 @@
+/* $OpenBSD: application.c,v 1.5 2022/06/27 10:31:17 martijn Exp $ */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include "application.h"
+#include "snmpd.h"
+
+struct appl_varbind *appl_blocklist_response(size_t);
+void appl_blocklist_get(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_blocklist_getnext(struct appl_backend *, int32_t, int32_t,
+const char *, struct appl_varbind *);
+
+struct appl_backend_functions appl_blocklist_functions = {
+   .ab_get = appl_blocklist_get,
+   .ab_getnext = appl_blocklist_getnext,
+   .ab_getbulk = NULL,
+};
+
+struct appl_backend appl_blocklist = {
+   .ab_name = "blocklist",
+   .ab_cookie = NULL,
+   .ab_retries = 0,
+   .ab_fn = _blocklist_functions
+};
+
+static struct appl_varbind *response = NULL;
+static size_t responsesz = 0;
+
+struct appl_varbind *
+appl_blocklist_response(size_t nvarbind)
+{
+   struct appl_varbind *tmp;
+   size_t i;
+
+   if (responsesz < nvarbind) {
+   if ((tmp = recallocarray(response, responsesz, nvarbind,
+   sizeof(*response))) == NULL) {
+   log_warn(NULL);
+   return NULL;
+   }
+   responsesz = nvarbind;
+   response = tmp;
+   }
+   for (i = 0; i < nvarbind; i++)
+   response[i].av_next = i + 1 == nvarbind ?
+   NULL : &(response[i + 1]);
+   return response;
+}
+
+void
+appl_blocklist_init(void)
+{
+   extern struct snmpd *snmpd_env;
+   size_t i;
+
+   for (i = 0; i < snmpd_env->sc_nblocklist; i++)
+   appl_register(NULL, 150, 1, &

snmpd(8): Add rudimentary AgentX support

2022-06-27 Thread Martijn van Duren
quot;Invalid error index");
invalid = 1;
}
+/* amavisd-snmp-subagent sets index to 1, no reason to crash over it. */
+#if PEDANTIC
if (error == APPL_ERROR_NOERROR && index != 0) {
log_warnx("error index with no error");
invalid = 1;
}
+#endif
if (vb == NULL && origvb != NULL) {
log_warnx("%s: Request %"PRIu32" returned less varbinds then "
"requested", backend->ab_name, requestid);
Index: usr.sbin/snmpd.application.agentx/application.h
===
RCS file: /cvs/src/usr.sbin/snmpd/application.h,v
retrieving revision 1.1
diff -u -p -r1.1 application.h
--- usr.sbin/snmpd.application.agentx/application.h 19 Jan 2022 10:59:35 
-  1.1
+++ usr.sbin/snmpd.application.agentx/application.h 27 Jun 2022 11:29:36 
-
@@ -117,6 +117,7 @@ struct appl_backend {
RB_HEAD(appl_requests, appl_request_downstream) ab_requests;
 };
 
+void appl(void);
 void appl_init(void);
 void appl_shutdown(void);
 enum appl_error appl_register(const char *, uint32_t, uint8_t, struct ber_oid 
*,
@@ -133,3 +134,8 @@ struct ber_element *appl_exception(enum 
 /* application_legacy.c */
 voidappl_legacy_init(void);
 voidappl_legacy_shutdown(void);
+
+/* application_agentx.c */
+voidappl_agentx(void);
+voidappl_agentx_init(void);
+voidappl_agentx_shutdown(void);
Index: usr.sbin/snmpd.application.agentx/application_agentx.c
===
RCS file: usr.sbin/snmpd.application.agentx/application_agentx.c
diff -N usr.sbin/snmpd.application.agentx/application_agentx.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ usr.sbin/snmpd.application.agentx/application_agentx.c  27 Jun 2022 
11:29:36 -0000
@@ -0,0 +1,842 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2021 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "application.h"
+#include "ax.h"
+#include "log.h"
+#include "smi.h"
+#include "snmp.h"
+#include "snmpd.h"
+
+#define AGENTX_DEFAULTTIMEOUT 5
+
+struct appl_agentx {
+   uint32_t ax_id;
+   struct ax *ax_ax;
+   struct event ax_ev;
+
+   struct appl_agentx_session *ax_session; /* List of sessions */
+   RB_ENTRY(appl_agentx) ax_entry;
+};
+
+struct appl_agentx_session {
+   struct appl_agentx *axs_ax;
+   uint32_t axs_id;
+   enum ax_byte_order axs_byteorder;
+   uint8_t axs_timeout;
+   struct ax_oid axs_oid;
+   struct ax_ostring axs_descr;
+   struct appl_backend axs_backend;
+
+   RB_ENTRY(appl_agentx_session) axs_entry;
+   struct appl_agentx_session *axs_next;
+};
+
+void appl_agentx_listen(struct agentx_master *);
+void appl_agentx_accept(int, short, void *);
+void appl_agentx_free(struct appl_agentx *);
+void appl_agentx_read(int, short, void *);
+void appl_agentx_open(struct appl_agentx *, struct ax_pdu *);
+void appl_agentx_close(struct appl_agentx_session *, struct ax_pdu *);
+void appl_agentx_forceclose(struct appl_backend *, enum appl_close_reason);
+void appl_agentx_session_free(struct appl_agentx_session *);
+void appl_agentx_register(struct appl_agentx_session *, struct ax_pdu *);
+void appl_agentx_unregister(struct appl_agentx_session *, struct ax_pdu *);
+void appl_agentx_get(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_agentx_getnext(struct appl_backend *, int32_t, int32_t, const char *,
+struct appl_varbind *);
+void appl_agentx_response(struct appl_agentx_session *, struct ax_pdu *);
+ssize_t appl_agentx_send(struct appl_agentx_session *);
+struct ber_oid *appl_agentx_oid2ber_oid(struct ax_oid *, struct ber_oid *);
+struct ber_element *appl_agentx_value2ber_element(struct ax_varbind *);
+struct ax_ostring *appl_agentx_string2ostring(const char *,
+struct ax_ostring *);
+int appl_agentx_cmp(struct appl_agentx *, struct appl_agentx *);
+int appl_agentx_sess

snmpd(8): Application.c properly initialize oidbuf for appl_region

2022-06-27 Thread Martijn van Duren
When registering a region in appl_region (through appl_register) we
fill oidbuf with strlcat, but we don't start from a clean state and
might have garbage prepended.

This oidbuf is only used on error-conditions, so it's unlikely to
trigger with the current code. Diff below properly initializes it.

OK?

martijn@

Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.3
diff -u -p -r1.3 application.c
--- application.c   22 Feb 2022 15:59:13 -  1.3
+++ application.c   27 Jun 2022 10:10:37 -
@@ -224,6 +224,7 @@ appl_region(struct appl_context *ctx, ui
goto overlap;
 
/* Don't use smi_oid2string, because appl_register can't use it */
+   oidbuf[0] = '\0';
for (i = 0; i < oid->bo_n; i++) {
if (i != 0)
strlcat(oidbuf, ".", sizeof(oidbuf));



Re: syslogd(8): Add hostname parsing support

2022-01-30 Thread Martijn van Duren
On Wed, 2022-01-26 at 09:18 -0700, Theo de Raadt wrote:
> > However, as things stand interpretation can be broken with the base
> > tools. I can't fix garbage input.
> 
> Your proposal builds a mechanism which encourages making decisions based
> upon parsing garbage input.

So let's just focus on my original diff and let that one stand on its
own.

Say I have a sender with the following line:
sender$ tail -2 /etc/syslog.conf
!doas
*.* @100.64.2.2

and a receiver with:
receiver$ tail -6 /etc/syslog.conf 
+100.64.2.3
!doas
*.* /tmp/prog_doas

!sender
*.* /tmp/prog_sender

receiver runs syslogd with -U100.64.2.2

When running syslogd on sender without any flags and doing a simple
`doas ls`:
receiver$ tail /tmp/prog_*
==> /tmp/prog_doas <==
Jan 30 15:03:51 100.64.2.3 doas: martijn ran command ls as root from 
/home/martijn

==> /tmp/prog_sender <==
receiver$ 

When running syslogd on sender with -h and doing a simple `doas ls`:
receiver$ tail /tmp/prog_*
==> /tmp/prog_doas <==

==> /tmp/prog_sender <==
Jan 30 15:08:08 100.64.2.3 sender doas: martijn ran command ls as root from 
/home/martijn
receiver$ 

With my diff applied and without -h:
receiver$ tail /tmp/prog_*
==> /tmp/prog_doas <==
Jan 30 15:11:55 100.64.2.3 doas: martijn ran command ls as root from 
/home/martijn

==> /tmp/prog_sender <==
receiver$ 

With my diff applied and with -h:
receiver$ tail /tmp/prog_*
==> /tmp/prog_doas <==
Jan 30 15:12:47 100.64.2.3 doas: martijn ran command ls as root from 
/home/martijn

==> /tmp/prog_sender <==
receiver$ 

So no new mechanism is introduced, but I am trying to make sure that
existing mechanisms work more consistent with what we already offer
out of the box in base.

martijn@

Index: parsemsg.c
===
RCS file: /cvs/src/usr.sbin/syslogd/parsemsg.c,v
retrieving revision 1.1
diff -u -p -r1.1 parsemsg.c
--- parsemsg.c  13 Jan 2022 10:34:07 -  1.1
+++ parsemsg.c  30 Jan 2022 14:20:36 -
@@ -17,8 +17,14 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include 
+
+#include 
+#include 
+
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,27 +35,42 @@
 
 size_t parsemsg_timestamp_bsd(const char *, char *);
 size_t parsemsg_timestamp_v1(const char *, char *);
+size_t parsemsg_hostname(const char *, char *);
 size_t parsemsg_prog(const char *, char *);
 
 struct msg *
 parsemsg(const char *msgstr, struct msg *msg)
 {
-   size_t n;
+   size_t timelen, proglen;
+   const char *hostname;
 
msg->m_pri = -1;
msgstr += parsemsg_priority(msgstr, >m_pri);
if (msg->m_pri &~ (LOG_FACMASK|LOG_PRIMASK))
msg->m_pri = -1;
 
-   if ((n = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0)
-   n = parsemsg_timestamp_v1(msgstr, msg->m_timestamp);
-   msgstr += n;
+   if ((timelen = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0)
+   timelen = parsemsg_timestamp_v1(msgstr, msg->m_timestamp);
+   msgstr += timelen;
 
-   while (isspace(msgstr[0]))
+   while (isspace((unsigned char)msgstr[0]))
msgstr++;
 
-   parsemsg_prog(msgstr, msg->m_prog);
+   hostname = msgstr;
+   msgstr += parsemsg_hostname(msgstr, msg->m_hostname);
+ 
+   while (isspace((unsigned char)msgstr[0]))
+   msgstr++;
 
+   proglen = parsemsg_prog(msgstr, msg->m_prog);
+
+   /*
+* Without timestamp and tag, assume hostname as part of message.
+*/
+   if (!timelen && !proglen) {
+   msg->m_hostname[0] = '\0';
+   msgstr = hostname;
+   }
strlcpy(msg->m_msg, msgstr, sizeof(msg->m_msg));
 
return msg;
@@ -169,6 +190,47 @@ parsemsg_timestamp_v1(const char *msgstr
return msg - msgstr;
 }
 
+/*
+ * Parse the ip address or hostname according to inet_pton and res_hnok and
+ * return the length of the hostname including the trailing space if available.
+ */
+size_t
+parsemsg_hostname(const char *msgstr, char *hostname)
+{
+   size_t len;
+   struct in_addr buf4;
+   struct in6_addr buf6;
+
+   if (msgstr[0] == '-' && (msgstr[1] == ' ' || msgstr[1] == '\0')) {
+   hostname[0] = '\0';
+   if (msgstr[1] == '\0')
+   return 1;
+   return 2;
+   }
+
+   if ((len = strcspn(msgstr, " ")) > HOST_NAME_MAX)
+   return 0;
+   strlcpy(hostname, msgstr, len + 1);
+   if (msgstr[len] == ' ')
+   len++;
+
+   if (inet_pton(AF_INET, hostname, ) == 1 ||
+   inet_pton(AF_INET6, hostname, ) == 1) {
+   return len;
+   }
+
+   if (res_hnok(hostname) == 0) {
+   hostname[0] = '\0';
+   return 0;
+   }
+   return len;
+}

Re: snmpd(8): clean up variable printing

2022-01-28 Thread Martijn van Duren
On Wed, 2022-01-19 at 16:23 +0100, Martijn van Duren wrote:
> The new code uses smi_print_element when debugging is enabled to trace
> calls. Unfortunately the current smi_print_element lacks in quite a few
> departments. This diff rewrites smi_print_element to be more concise
> than what we currently have, without moving into the more complex
> territory that snmp(1) has.
> 
> Unknown types are printed in a similar fashion to what tcpdump(8)'s
> snmp output does.
> 
> This change helps mostly with exceptions (NOSUCH{OBJECT,INSTANCE} and
> ENDOFMIBVIEW) and distinguishing between different integer types.
> 
> I kept the current implementation under smi_print_element_legacy, so
> that we don't change the output of trap handlers. We should probably
> revisit that one at some point, but I don't think to go into that
> territory right now.
> 
> OK?
> 
> martijn@
> 
> p.s. I'm not particularly thrilled about the type hinting, but it's
> the cleanest that I could come up with without being too much of an
> eyesore or filling the screen up even further.

Found a missing break after the BER_TYPE_NULL case.

OK?

martijn@

Index: smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.30
diff -u -p -r1.30 smi.c
--- smi.c   21 Oct 2021 15:08:15 -  1.30
+++ smi.c   29 Jan 2022 07:28:15 -
@@ -46,6 +46,7 @@
 
 #include "snmpd.h"
 #include "mib.h"
+#include "application.h"
 
 #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
 
@@ -461,8 +462,9 @@ smi_debug_elements(struct ber_element *r
 }
 #endif
 
+/* Keep around so trap handle scripts don't break */
 char *
-smi_print_element(struct ber_element *root)
+smi_print_element_legacy(struct ber_element *root)
 {
char*str = NULL, *buf, *p;
size_t   len, i;
@@ -520,6 +522,140 @@ smi_print_element(struct ber_element *ro
case BER_TYPE_SET:
default:
str = strdup("");
+   break;
+   }
+
+   return (str);
+
+ fail:
+   free(str);
+   return (NULL);
+}
+
+char *
+smi_print_element(struct ber_element *root)
+{
+   char*str = NULL, *buf, *p;
+   long longv;
+   struct ber_oid   o;
+   char strbuf[BUFSIZ];
+
+   switch (root->be_class) {
+   case BER_CLASS_UNIVERSAL:
+   switch (root->be_type) {
+   case BER_TYPE_INTEGER:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld", v) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OBJECT:
+   if (ober_get_oid(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s", smi_oid2string(, strbuf,
+   sizeof(strbuf), 0)) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OCTETSTRING:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   p = reallocarray(NULL, 4, root->be_len + 1);
+   if (p == NULL)
+   goto fail;
+   strvisx(p, buf, root->be_len, VIS_NL);
+   if (asprintf(, "\"%s\"", p) == -1) {
+   free(p);
+   goto fail;
+   }
+   free(p);
+   break;
+   case BER_TYPE_NULL:
+   if (asprintf(, "null") == -1)
+   goto fail;
+   break;
+   default:
+   /* Should not happen in a valid SNMP packet */
+   if (asprintf(, "[U/%u]", root->be_type) == -1)
+   goto fail;
+   break;
+   }
+   break;
+   case BER_CLASS_APPLICATION:
+   switch (root->be_type) {
+   case SNMP_T_IPADDR:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s",
+   inet_ntoa(*(struct in_addr *)buf)) == -1)
+   goto fail;
+   break;
+   case SNMP_T_COUNTER32:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld(c32)", v) == -1)
+   goto fail;
+   break;
+   case SNMP

Re: syslogd(8): Add hostname parsing support

2022-01-25 Thread Martijn van Duren
Thanks for looking into this.

On Sat, 2022-01-22 at 10:05 -0700, Theo de Raadt wrote:
> > Note that this only adds the parsing, the rest of the current behaviour
> > of stays the same. I have another diff in the pipeline for allowing the
> > hostname in the message.
> 
> I object to this process.
> 
> You want to add parsing code as a fait accompli. With no justification.
> Then later on, spring on us the code that uses it.

Sorry if my phrasing was off, but I do think the diff stands on its own
and I thought I made that case in the first paragraph. Even though I
include the mentioned follow up diffs below, let me try to rephrase my
case for it as a stand alone diff.

Right now we have 3 elements where syslog.conf can filter on: priority,
hostname, and progname. hostname currently always comes from the input
source:
- sendsyslog(2), /dev/klog, unix socket, vlogmsg(), and markit() use
  LocalHostName
- UDP/TCP/TLS print reverse lookup or numerical if -n is specified

My previous parsemsg() diff didn't change any behaviour, but makes it
more clear what's going on. When a message is handled through
printline() it goes through parsemsg(). Here we first check for an
optional priority and timestamp. parsemsg_priority() is the original
priority parsing code and parsemsg_timestamp_{bsd,v1} are the original
code lifted from logmsg. After that we continue to parsemsg_prog, which
is also lifted from logmsg(). In other words, at no point do we look
for a hostname in a message.
So if someone were to set -h in syslogd or use any other syslog server
that includes a hostname in the message and would relay it to a
syslogd(8) it would first parse priority/timestamp (if available) and
then continue to interpret the "first word" as progname. So a message
like: "<13>Jan 25 20:35:44 myhost myprog: mymsg" send over localhost
would have myhost as progname and localhost (or 127.0.0.1 if -n is
used) as hostname. So if someone would have "!myprog" in their
syslog.conf it would not match (while it should) and someone who
would have "!myhost" in their syslog.conf would match, while it
shouldn't.

What my diff does is based mainly on syslog(3) (and happens to match
what I've mostly seen in the wild) by saying that a progname should end
in a ':' or a '['. This is also what NetBSD does. By this minor change
we can reliably determine what the progname is and by that merit
determine what the hostname is.

The hostname in the original diff is stored in struct msg and not looked
at again, effectively replacing the hostname with the address found by
the input source. This behaviour should be identical to FreeBSD, which
has the -H flag to preserve the hostname in the message. To make this
explicit, the example message previously would be written out as:
"<13>Jan 25 20:35:44 localhost myprog: mymsg" instead of the current
"<13>Jan 25 20:35:44 localhost myhost myprog: mymsg"
and "+localhost" would continue to keep working as always.

>   What if we disagree
> with the code that uses it?  Will you delete this parsing code which
> nothing uses?

Fixing the "!progname" case should be sufficient reason on its own and
no other.
> 
> > - Timestamp: is easy to interpret, since it's a strict format.
> >   No changes here.
> 
> I believe "timestamp missing" is not strictly permitted.  But this was
> common for a while, and in OpenBSD it is the default message format.
> This is a due to the desire to make syslog_r(3) be signal/re-entrant
> safe on top of sendsyslog(2).  Then there is no good way of creating a
> timestamp string in the sender libc context.  A timestamp is easily
> re-inserted by the receiving syslogd.
> 
> > +   for (i = 0; i < HOST_NAME_MAX; i++) {
> 
> Unlike MAXHOSTNAMELEN/NI_MAXHOST, HOST_NAME_MAX storage does not include
> a NUL.  You might have the loop right.  Be careful.

I've defined it as "char m_hostname[HOST_NAME_MAX + 1];", so we have room
for the NUL.
> 
> > +* fqdn: [[:alnum:]-.]
> 
> That is not totally correct.
> 
> hostnames very often also contain '_' in the middle positions, early
> RFCs said no, but around 1990-ish Vixie in particular had to face
> reality..  I was involved in that conversation, it seems so long ago.
> 
> Your pattern is also incorrect in other ways, such as ".." is not legal,
> hostnames cannot start or end with '-' or '-', etc.  The current accepted
> rules are encoded in the undocumented libc function __res_hnok in
> lib/libc/net/res_comp.c

I wasn't aware of res_hnok. I see that it's used in other applications as
well. I changed it to use strcspn to look for the terminating space and
try inet_pton and res_hnok to check if it's valid. This makes the code a
lot cleaner. Thanks.
> 
> I don't know if false-identification of broken hostnames is bad or not
> I guess it depends what will happen with this information later on [ie.
> the part of your proposal that is being kept a secret].

The same thing that already happens. Writing it out to log-files and
using it to match on 

syslogd(8): Add hostname parsing support

2022-01-22 Thread Martijn van Duren
Currently syslogd(8) doesn't support hostname parsing for incoming
messages. This means that if a sender adds a hostname to a message it
will be interpreted as progname. Additionally, when a message is being
relayed, or there's some form of NATting taking place the originator of
the message will be completely lost.

The diff below adds hostname parsing and is already OK bluhm@, but since
I wanted to give other people a chance to yell at me before committing.
If nobody objects I'll commit it next weekend.
Note that this only adds the parsing, the rest of the current behaviour
of stays the same. I have another diff in the pipeline for allowing the
hostname in the message.

The definitions below are mostly in line with what {Net,Free}BSD do.

The BSD syslog protocol is rather loose and in quite a few locations
open for interpretation, so some definitions need to be hammered out:
- Timestamp: is easy to interpret, since it's a strict format.
  No changes here.
- Hostname: ip{,6} address, RFC1034 label, fqdn and is max
  HOST_NAME_MAX long.
- progname: alphanumeric, '-', '.', '_', ending in a ':' or '[' and is
  max 255 characters long.
  This changes in that a progname must end with ':' or '['.

I left the program name parsing as similar as I could, but make it
always distinguishable from the hostname. The ending in ':' or '[' is
part of syslog(3) and what I've always seen in the wild (ymmv). The only
exception to this rule is when progname (or ident as syslog(3) calls it)
fills up the message and ':' can't be placed. However, in that case it
won't fit in syslogd(8)'s progname definition of 255 characters.

According to syslog(3)'s guts, progname can be omitted if both ident
and LOG_PID have been omitted during openlog(3), and __progname
isn't set (no clue how that could happen op OpenBSD).
If this somehow miraculously happens the whole message is just the
"message" parameter of the syslog(3) call.

Because progname is now always identifiable, we know if we have a
hostname if progname is set and found on the first or second position
after timestamp/priority.

If progname is completely omitted we're a bit in no-mans-land. So here
we have to make a best effort. Currently we never set the hostname when
forwarding a message, unless syslogd is specified with '-h'. However,
this is not a sane default since it hinders relaying messages and bluhm@
and I already agree that we should make -h default and make -h a noop.

Going from syslog(3), if no timestamp is given we have just the message
plus (not quite) optional progname/ident. So my proposal is that
hostname should be parsed if either timestamp or progname is found.

Finally, the syslogd regress with rsyslog now fails, because we send
a message from the guts of the perl framework without timestamp or
progname, but rsyslog adds a timestamp when forwarding, but no other
changes are made. This test can be re-enabled when we allow using the
hostname from the message, or someone is brave enough to go into these
perl guts.

Additional OK? Comment?

martijn@

Index: usr.sbin/syslogd/parsemsg.c
===
RCS file: /cvs/src/usr.sbin/syslogd/parsemsg.c,v
retrieving revision 1.1
diff -u -p -r1.1 parsemsg.c
--- usr.sbin/syslogd/parsemsg.c 13 Jan 2022 10:34:07 -  1.1
+++ usr.sbin/syslogd/parsemsg.c 22 Jan 2022 14:52:04 -
@@ -17,6 +17,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include 
+
+#include 
+#include 
+
 #include 
 #include 
 #include 
@@ -29,27 +34,42 @@
 
 size_t parsemsg_timestamp_bsd(const char *, char *);
 size_t parsemsg_timestamp_v1(const char *, char *);
+size_t parsemsg_hostname(const char *, char *);
 size_t parsemsg_prog(const char *, char *);
 
 struct msg *
 parsemsg(const char *msgstr, struct msg *msg)
 {
-   size_t n;
+   size_t timelen, proglen;
+   const char *hostname;
 
msg->m_pri = -1;
msgstr += parsemsg_priority(msgstr, >m_pri);
if (msg->m_pri &~ (LOG_FACMASK|LOG_PRIMASK))
msg->m_pri = -1;
 
-   if ((n = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0)
-   n = parsemsg_timestamp_v1(msgstr, msg->m_timestamp);
-   msgstr += n;
+   if ((timelen = parsemsg_timestamp_bsd(msgstr, msg->m_timestamp)) == 0)
+   timelen = parsemsg_timestamp_v1(msgstr, msg->m_timestamp);
+   msgstr += timelen;
+
+   while (isspace((unsigned char)msgstr[0]))
+   msgstr++;
 
-   while (isspace(msgstr[0]))
+   hostname = msgstr;
+   msgstr += parsemsg_hostname(msgstr, msg->m_hostname);
+ 
+   while (isspace((unsigned char)msgstr[0]))
msgstr++;
 
-   parsemsg_prog(msgstr, msg->m_prog);
+   proglen = parsemsg_prog(msgstr, msg->m_prog);
 
+   /*
+* Without timestamp and tag, assume hostname as part of message.
+*/
+   if (!timelen && !proglen) {
+   msg->m_hostname[0] = '\0';
+

Re: snmpd(8): fix exceptions in mps.c

2022-01-20 Thread Martijn van Duren
Disregard this one for now. If o_get returns -1 it indicates an error,
so it should indicate this to the upper layers. However, the old code
can't handle this and I kept this code as is so that we can have some
time to let the dust settle around the new code (and easily switch back
if needed). Changing it to something more in line with the intended
behaviour of the current code, but still incorrect is not really an
improvement.

I'll revisit this one once more people have been exposed to the new
code.

On Thu, 2022-01-20 at 22:08 +0100, Martijn van Duren wrote:
> When hitting an error case in mps_get{,next}req, mps assumes that no OID
> has been linked to the root element. However, in both the get as well as
> the getnext case it's already set when entering the mib.c code, so going
> the fail goto path will result in the intended OID/exception pair being
> appended to the prior attached OID, instead of directly to the sequence
> (OID,OID,EXCEPTION).
> 
> This behaviour could already be triggered in the original codepath, so
> it's not a new issue introduced with the new application.c. And even
> though I would like to get rid of this code, I think it's worth fixing
> while we still have it around.
> 
> Easiest way to reproduce is to just return -1 in mib_getsys and do
> get syscontact.0 or getnext syscontact.
> 
> OK?
> 
> martijn@
> 
> Index: mps.c
> ===
> RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 mps.c
> --- mps.c 30 Jun 2020 17:11:49 -  1.29
> +++ mps.c 20 Jan 2022 21:03:17 -
> @@ -150,7 +150,9 @@ fail:
>   return (-1);
>  
>   /* Set SNMPv2 extended error response. */
> - elm = ober_add_oid(elm, o);
> + if (root->be_sub != NULL)
> + ober_free_elements(ober_unlink_elements(root));
> + elm = ober_add_oid(root, o);
>   elm = ober_add_null(elm);
>   ober_set_header(elm, BER_CLASS_CONTEXT, error_type);
>   return (0);
> @@ -178,15 +180,16 @@ mps_setreq(struct snmp_message *msg, str
>  
>  int
>  mps_getnextreq(struct snmp_message *msg, struct ber_element *root,
> -struct ber_oid *o)
> +struct ber_oid *o0)
>  {
>   struct oid  *next = NULL;
>   struct ber_element  *ber = root;
>   struct oid   key, *value;
>   int  ret;
> - struct ber_oid   no;
> - unsigned longerror_type = 0;/* noSuchObject */
> + struct ber_oid   no, so, *o = 
> + unsigned longerror_type = 2;/* EndOfMibView */
>  
> + so = *o0;
>   if (o->bo_n > BER_MAX_OID_LEN)
>   return (-1);
>   bzero(, sizeof(key));
> @@ -259,7 +262,9 @@ fail:
>   return (-1);
>  
>   /* Set SNMPv2 extended error response. */
> - ber = ober_add_oid(ber, o);
> + if (root->be_sub != NULL)
> + ober_free_elements(ober_unlink_elements(root));
> + ber = ober_add_oid(root, o0);
>   ber = ober_add_null(ber);
>   ober_set_header(ber, BER_CLASS_CONTEXT, error_type);
>   return (0);
> 



application.c be more paranoid for misbehaving backends

2022-01-20 Thread Martijn van Duren
There's a missing NULL check in appl_response(). This should only happenwhen a 
backend is misbehaving, so I only managed to find this because
I'm actively bashing it right now. This should make us a little more
future-proof. Code further down the path already has similar NULL checks
against this variable.

OK?

martijn@

Index: application.c
===
RCS file: /cvs/src/usr.sbin/snmpd/application.c,v
retrieving revision 1.1
diff -u -p -r1.1 application.c
--- application.c   19 Jan 2022 10:59:35 -  1.1
+++ application.c   20 Jan 2022 21:52:41 -
@@ -1056,7 +1056,8 @@ appl_response(struct appl_backend *backe
appl_varbind_error(origvb, error);
origvb->avi_state = APPL_VBSTATE_DONE;
origvb->avi_varbind.av_oid = vb->av_oid;
-   if (vb->av_value->be_class == BER_CLASS_CONTEXT &&
+   if (vb->av_value != NULL &&
+   vb->av_value->be_class == BER_CLASS_CONTEXT &&
vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW) {
nregion = appl_region_next(ureq->aru_ctx,
&(vb->av_oid), origvb->avi_region);



snmpd(8): fix exceptions in mps.c

2022-01-20 Thread Martijn van Duren
When hitting an error case in mps_get{,next}req, mps assumes that no OID
has been linked to the root element. However, in both the get as well as
the getnext case it's already set when entering the mib.c code, so going
the fail goto path will result in the intended OID/exception pair being
appended to the prior attached OID, instead of directly to the sequence
(OID,OID,EXCEPTION).

This behaviour could already be triggered in the original codepath, so
it's not a new issue introduced with the new application.c. And even
though I would like to get rid of this code, I think it's worth fixing
while we still have it around.

Easiest way to reproduce is to just return -1 in mib_getsys and do
get syscontact.0 or getnext syscontact.

OK?

martijn@

Index: mps.c
===
RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v
retrieving revision 1.29
diff -u -p -r1.29 mps.c
--- mps.c   30 Jun 2020 17:11:49 -  1.29
+++ mps.c   20 Jan 2022 21:03:17 -
@@ -150,7 +150,9 @@ fail:
return (-1);
 
/* Set SNMPv2 extended error response. */
-   elm = ober_add_oid(elm, o);
+   if (root->be_sub != NULL)
+   ober_free_elements(ober_unlink_elements(root));
+   elm = ober_add_oid(root, o);
elm = ober_add_null(elm);
ober_set_header(elm, BER_CLASS_CONTEXT, error_type);
return (0);
@@ -178,15 +180,16 @@ mps_setreq(struct snmp_message *msg, str
 
 int
 mps_getnextreq(struct snmp_message *msg, struct ber_element *root,
-struct ber_oid *o)
+struct ber_oid *o0)
 {
struct oid  *next = NULL;
struct ber_element  *ber = root;
struct oid   key, *value;
int  ret;
-   struct ber_oid   no;
-   unsigned longerror_type = 0;/* noSuchObject */
+   struct ber_oid   no, so, *o = 
+   unsigned longerror_type = 2;/* EndOfMibView */
 
+   so = *o0;
if (o->bo_n > BER_MAX_OID_LEN)
return (-1);
bzero(, sizeof(key));
@@ -259,7 +262,9 @@ fail:
return (-1);
 
/* Set SNMPv2 extended error response. */
-   ber = ober_add_oid(ber, o);
+   if (root->be_sub != NULL)
+   ober_free_elements(ober_unlink_elements(root));
+   ber = ober_add_oid(root, o0);
ber = ober_add_null(ber);
ober_set_header(ber, BER_CLASS_CONTEXT, error_type);
return (0);



Re: ober_get_writebuf return correct length

2022-01-20 Thread Martijn van Duren
Forgot to mention, I checked all the instances of ober_get_writebuf I
could find and they either don't use it for the actual length, or ber
has been freshly initialised just before. So there's no problem here in
the known consumers.

On Thu, 2022-01-20 at 18:50 +0100, Martijn van Duren wrote:
> While reading through ber.c I noticed that ober_get_writebuf can return
> the wrong length when called multiple times on the same ber instance.
> 
> This is because ober_get_writebuf uses br_wend to calculate the length,
> while ober_write_elements uses that to determine the size of the buffer.
> ober_write_elements uses br_wptr to determine how much has been written.
> So use that pointer instead.
> 
> $ cat test.c
> #include 
> #include 
> #include 
> 
> int
> main(int argc, char *argv[])
> {
> struct ber_element *root;
> struct ber ber;
> void *buf;
> 
> bzero(, sizeof(ber));
> 
> root = ober_printf_elements(NULL, "{}");
> printf("%zd\n", ober_write_elements(, root));
> printf("%zd\n", ober_get_writebuf(, ));
> 
> ober_free_elements(root);
> root = ober_printf_elements(NULL, "{d}", (int)1);
> printf("%zd\n", ober_write_elements(, root));
> printf("%zd\n", ober_get_writebuf(, ));
> 
> ober_free_elements(root);
> root = ober_printf_elements(NULL, "{}");
> printf("%zd\n", ober_write_elements(, root));
> printf("%zd\n", ober_get_writebuf(, ));
> }
> $ CFLAGS='-lutil' make test && ./test
> cc -lutil   -o test test.c 
> 2
> 2
> 5
> 5
> 2
> 5
> 
> OK?
> 
> martijn@
> 
> Index: ber.c
> ===
> RCS file: /cvs/src/lib/libutil/ber.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 ber.c
> --- ber.c 21 Oct 2021 08:17:33 -  1.23
> +++ ber.c 20 Jan 2022 17:48:27 -
> @@ -831,7 +831,7 @@ ober_get_writebuf(struct ber *b, void **
>   if (b->br_wbuf == NULL)
>   return -1;
>   *buf = b->br_wbuf;
> - return (b->br_wend - b->br_wbuf);
> + return (b->br_wptr - b->br_wbuf);
>  }
>  
>  /*
> 



ober_get_writebuf return correct length

2022-01-20 Thread Martijn van Duren
While reading through ber.c I noticed that ober_get_writebuf can return
the wrong length when called multiple times on the same ber instance.

This is because ober_get_writebuf uses br_wend to calculate the length,
while ober_write_elements uses that to determine the size of the buffer.
ober_write_elements uses br_wptr to determine how much has been written.
So use that pointer instead.

$ cat test.c
#include 
#include 
#include 

int
main(int argc, char *argv[])
{
struct ber_element *root;
struct ber ber;
void *buf;

bzero(, sizeof(ber));

root = ober_printf_elements(NULL, "{}");
printf("%zd\n", ober_write_elements(, root));
printf("%zd\n", ober_get_writebuf(, ));

ober_free_elements(root);
root = ober_printf_elements(NULL, "{d}", (int)1);
printf("%zd\n", ober_write_elements(, root));
printf("%zd\n", ober_get_writebuf(, ));

ober_free_elements(root);
root = ober_printf_elements(NULL, "{}");
printf("%zd\n", ober_write_elements(, root));
printf("%zd\n", ober_get_writebuf(, ));
}
$ CFLAGS='-lutil' make test && ./test
cc -lutil   -o test test.c 
2
2
5
5
2
5

OK?

martijn@

Index: ber.c
===
RCS file: /cvs/src/lib/libutil/ber.c,v
retrieving revision 1.23
diff -u -p -r1.23 ber.c
--- ber.c   21 Oct 2021 08:17:33 -  1.23
+++ ber.c   20 Jan 2022 17:48:27 -
@@ -831,7 +831,7 @@ ober_get_writebuf(struct ber *b, void **
if (b->br_wbuf == NULL)
return -1;
*buf = b->br_wbuf;
-   return (b->br_wend - b->br_wbuf);
+   return (b->br_wptr - b->br_wbuf);
 }
 
 /*



remove snmpe.c transactionid

2022-01-20 Thread Martijn van Duren
This was from a sequence of early attempts to work towards a new
application layer. I can give more reasoning behind it, but the bottom
line is that it's currently dead weight.

OK to remove this code again?

martijn@

Index: snmpd.h
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.102
diff -u -p -r1.102 snmpd.h
--- snmpd.h 19 Jan 2022 10:25:04 -  1.102
+++ snmpd.h 20 Jan 2022 13:38:28 -
@@ -403,8 +403,6 @@ struct snmp_message {
u_int8_t sm_data[READ_BUF_SIZE];
size_t   sm_datalen;
 
-   uint32_t sm_transactionid;
-
u_intsm_version;
 
/* V1, V2c */
@@ -441,11 +439,7 @@ struct snmp_message {
 
struct ber_element  *sm_varbind;
struct ber_element  *sm_varbindresp;
-
-   RB_ENTRY(snmp_message)   sm_entry;
 };
-RB_HEAD(snmp_messages, snmp_message);
-extern struct snmp_messages snmp_messages;
 
 /* Defined in SNMPv2-MIB.txt (RFC 3418) */
 struct snmp_stats {
@@ -644,8 +638,6 @@ void snmpe(struct privsep *, struct pr
 voidsnmpe_shutdown(void);
 voidsnmpe_dispatchmsg(struct snmp_message *);
 voidsnmpe_response(struct snmp_message *);
-int snmp_messagecmp(struct snmp_message *, struct snmp_message *);
-RB_PROTOTYPE(snmp_messages, snmp_message, sm_entry, snmp_messagecmp)
 
 /* trap.c */
 voidtrap_init(void);
Index: snmpe.c
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.82
diff -u -p -r1.82 snmpe.c
--- snmpe.c 19 Jan 2022 11:00:56 -  1.82
+++ snmpe.c 20 Jan 2022 13:38:28 -
@@ -58,8 +58,6 @@ intsnmpe_encode(struct snmp_message *)
 struct imsgev  *iev_parent;
 static const struct timevalsnmpe_tcp_timeout = { 10, 0 }; /* 10s */
 
-struct snmp_messages snmp_messages = RB_INITIALIZER(_messages);
-
 static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT }
 };
@@ -246,11 +244,6 @@ snmpe_parse(struct snmp_message *msg)
 
msg->sm_errstr = "invalid message";
 
-   do {
-   msg->sm_transactionid = arc4random();
-   } while (msg->sm_transactionid == 0 ||
-   RB_INSERT(snmp_messages, _messages, msg) != NULL);
-
if (ober_scanf_elements(root, "{ie", , ) != 0)
goto parsefail;
 
@@ -910,8 +903,6 @@ snmpe_response(struct snmp_message *msg)
 void
 snmp_msgfree(struct snmp_message *msg)
 {
-   if (msg->sm_transactionid != 0)
-   RB_REMOVE(snmp_messages, _messages, msg);
event_del(>sm_sockev);
ober_free(>sm_ber);
if (msg->sm_req != NULL)
@@ -974,12 +965,3 @@ snmpe_encode(struct snmp_message *msg)
 #endif
return 0;
 }
-
-int
-snmp_messagecmp(struct snmp_message *m1, struct snmp_message *m2)
-{
-   return (m1->sm_transactionid < m2->sm_transactionid ? -1 :
-   m1->sm_transactionid > m2->sm_transactionid);
-}
-
-RB_GENERATE(snmp_messages, snmp_message, sm_entry, snmp_messagecmp)



snmpd(8): clean up variable printing

2022-01-19 Thread Martijn van Duren
The new code uses smi_print_element when debugging is enabled to trace
calls. Unfortunately the current smi_print_element lacks in quite a few
departments. This diff rewrites smi_print_element to be more concise
than what we currently have, without moving into the more complex
territory that snmp(1) has.

Unknown types are printed in a similar fashion to what tcpdump(8)'s
snmp output does.

This change helps mostly with exceptions (NOSUCH{OBJECT,INSTANCE} and
ENDOFMIBVIEW) and distinguishing between different integer types.

I kept the current implementation under smi_print_element_legacy, so
that we don't change the output of trap handlers. We should probably
revisit that one at some point, but I don't think to go into that
territory right now.

OK?

martijn@

p.s. I'm not particularly thrilled about the type hinting, but it's
the cleanest that I could come up with without being too much of an
eyesore or filling the screen up even further.

Index: smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.30
diff -u -p -r1.30 smi.c
--- smi.c   21 Oct 2021 15:08:15 -  1.30
+++ smi.c   19 Jan 2022 15:21:20 -
@@ -46,6 +46,7 @@
 
 #include "snmpd.h"
 #include "mib.h"
+#include "application.h"
 
 #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
 
@@ -461,8 +462,9 @@ smi_debug_elements(struct ber_element *r
 }
 #endif
 
+/* Keep around so trap handle scripts don't break */
 char *
-smi_print_element(struct ber_element *root)
+smi_print_element_legacy(struct ber_element *root)
 {
char*str = NULL, *buf, *p;
size_t   len, i;
@@ -520,6 +522,139 @@ smi_print_element(struct ber_element *ro
case BER_TYPE_SET:
default:
str = strdup("");
+   break;
+   }
+
+   return (str);
+
+ fail:
+   free(str);
+   return (NULL);
+}
+
+char *
+smi_print_element(struct ber_element *root)
+{
+   char*str = NULL, *buf, *p;
+   long longv;
+   struct ber_oid   o;
+   char strbuf[BUFSIZ];
+
+   switch (root->be_class) {
+   case BER_CLASS_UNIVERSAL:
+   switch (root->be_type) {
+   case BER_TYPE_INTEGER:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld", v) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OBJECT:
+   if (ober_get_oid(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s", smi_oid2string(, strbuf,
+   sizeof(strbuf), 0)) == -1)
+   goto fail;
+   break;
+   case BER_TYPE_OCTETSTRING:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   p = reallocarray(NULL, 4, root->be_len + 1);
+   if (p == NULL)
+   goto fail;
+   strvisx(p, buf, root->be_len, VIS_NL);
+   if (asprintf(, "\"%s\"", p) == -1) {
+   free(p);
+   goto fail;
+   }
+   free(p);
+   break;
+   case BER_TYPE_NULL:
+   if (asprintf(, "null") == -1)
+   goto fail;
+   default:
+   /* Should not happen in a valid SNMP packet */
+   if (asprintf(, "[U/%u]", root->be_type) == -1)
+   goto fail;
+   break;
+   }
+   break;
+   case BER_CLASS_APPLICATION:
+   switch (root->be_type) {
+   case SNMP_T_IPADDR:
+   if (ober_get_string(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%s",
+   inet_ntoa(*(struct in_addr *)buf)) == -1)
+   goto fail;
+   break;
+   case SNMP_T_COUNTER32:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld(c32)", v) == -1)
+   goto fail;
+   break;
+   case SNMP_T_GAUGE32:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if (asprintf(, "%lld(g32)", v) == -1)
+   goto fail;
+   break;
+   case SNMP_T_TIMETICKS:
+   if (ober_get_integer(root, ) == -1)
+   goto fail;
+   if 

Re: sed(1): enable regression tests and correct pattern space assumptions

2022-01-10 Thread Martijn van Duren
On Mon, 2022-01-10 at 08:21 -0700, Todd C. Miller wrote:
> On Mon, 10 Jan 2022 15:23:42 +0100, Martijn van Duren wrote:
> 
> > The lputs case is fairly straight forward and I'd like to get an OK
> > for that part.
> 
> I agree that fixing lputs() to honor psl is the best approach.
> Wouldn't the diff be simpler if you left the handling of 's' as-is
> but make the loop invariant l > 0 and decrement l accordingly?
> Using len instead of l is probably a little easier to read.
> 
>  - todd

sure

Index: process.c
===
RCS file: /cvs/src/usr.bin/sed/process.c,v
retrieving revision 1.34
diff -u -p -r1.34 process.c
--- process.c   14 Nov 2018 10:59:33 -  1.34
+++ process.c   10 Jan 2022 15:52:26 -
@@ -60,7 +60,7 @@ static SPACE HS, PS, SS;
 
 static inline int   applies(struct s_command *);
 static void flush_appends(void);
-static void lputs(char *);
+static void lputs(char *, size_t);
 static inline int   regexec_e(regex_t *, const char *, int, int, size_t,
 size_t);
 static void regsub(SPACE *, char *, char *);
@@ -158,7 +158,7 @@ redirect:
(void)fprintf(outfile, "%s", cp->t);
break;
case 'l':
-   lputs(ps);
+   lputs(ps, psl);
break;
case 'n':
if (!nflag && !pd)
@@ -478,14 +478,14 @@ flush_appends(void)
 }
 
 static void
-lputs(char *s)
+lputs(char *s, size_t len)
 {
int count;
extern int termwidth;
const char *escapes;
char *p;
 
-   for (count = 0; *s; ++s) {
+   for (count = 0; len > 0; len--, s++) {
if (count >= termwidth) {
(void)fprintf(outfile, "\\\n");
count = 0;
@@ -501,7 +501,7 @@ lputs(char *s)
} else {
escapes = "\\\a\b\f\r\t\v";
(void)fputc('\\', outfile);
-   if ((p = strchr(escapes, *s))) {
+   if ((p = strchr(escapes, *s)) && *s != '\0') {
(void)fputc("\\abfrtv"[p - escapes], outfile);
count += 2;
} else {



Re: sed(1): enable regression tests and correct pattern space assumptions

2022-01-10 Thread Martijn van Duren
On Mon, 2022-01-10 at 00:25 -0600, user wrote:
> The commandD1 regression test can be enabled without modifying sed's source 
> code, it is no longer failing. The commandl1, commandl2, and commandc1 tests 
> fail because the 'c' and 'D' commands assume that setting the correct length 
> of the pattern space is sufficient and do not correct the pattern space. 
> 
> The pattern space is cleared in the 'c' command by setting ps to a null byte 
> and a null byte is copied to the pattern space in the 'D' command to prevent 
> stray bytes from being printed by other commands. Specifically, the 
> substitute function in pattern.c:408 calls cspace(, s++, 1, APPEND) if s 
> doesn't point to a null byte. If the pattern space isn't cleared by the 'c' 
> command this will be executed and cause the substitute space to be advanced 
> by 1 byte and causes an incorrect output (commandc1 test). If the pattern 
> space isn't cleared in the 'c' command lputs (called by the l command) will 
> also print the pattern space without checking the pattern space length 
> (commandl2 test), giving an incorrect output. In the 'D' command, the 
> original memmove did not copy the null byte at the end of the bytes that were 
> moved, causing a lputs call following the command to give an incorrect output 
> (commandl1 test).
> 
> Not sure if the diff is correct since it was generated using got diff.

Thanks for the detailed analysis. However, I think we should fix the
cases where SPACE.len is not honoured...

The lputs case is fairly straight forward and I'd like to get an OK
for that part.

The substitute case I haven't convinced myself just yet that it's
correct. But (all) regress passes and I want to put it out here in
case someone with more spare brain cycles than me wants to dive into it.

martijn@

Index: process.c
===
RCS file: /cvs/src/usr.bin/sed/process.c,v
retrieving revision 1.34
diff -u -p -r1.34 process.c
--- process.c   14 Nov 2018 10:59:33 -  1.34
+++ process.c   10 Jan 2022 14:20:56 -
@@ -60,7 +60,7 @@ static SPACE HS, PS, SS;
 
 static inline int   applies(struct s_command *);
 static void flush_appends(void);
-static void lputs(char *);
+static void lputs(char *, size_t);
 static inline int   regexec_e(regex_t *, const char *, int, int, size_t,
 size_t);
 static void regsub(SPACE *, char *, char *);
@@ -158,7 +158,7 @@ redirect:
(void)fprintf(outfile, "%s", cp->t);
break;
case 'l':
-   lputs(ps);
+   lputs(ps, psl);
break;
case 'n':
if (!nflag && !pd)
@@ -390,11 +390,11 @@ substitute(struct s_command *cp)
 * and at the end of the line, terminate.
 */
if (match[0].rm_so == match[0].rm_eo) {
-   if (*s == '\0' || *s == '\n')
+   if (slen == 0 || *s == '\0' || *s == '\n')
slen = -1;
else
slen--;
-   if (*s != '\0') {
+   if (slen >= 0 && *s != '\0') {
cspace(, s++, 1, APPEND);
le++;
}
@@ -478,34 +478,35 @@ flush_appends(void)
 }
 
 static void
-lputs(char *s)
+lputs(char *s, size_t l)
 {
int count;
extern int termwidth;
const char *escapes;
+   size_t i;
char *p;
 
-   for (count = 0; *s; ++s) {
+   for (i = 0, count = 0; i < l; i++) {
if (count >= termwidth) {
(void)fprintf(outfile, "\\\n");
count = 0;
}
-   if (isascii((unsigned char)*s) && isprint((unsigned char)*s)
-   && *s != '\\') {
-   (void)fputc(*s, outfile);
+   if (isascii((unsigned char)s[i]) && isprint((unsigned char)s[i])
+   && s[i] != '\\') {
+   (void)fputc(s[i], outfile);
count++;
-   } else if (*s == '\n') {
+   } else if (s[i] == '\n') {
(void)fputc('$', outfile);
(void)fputc('\n', outfile);
count = 0;
} else {
escapes = "\\\a\b\f\r\t\v";
(void)fputc('\\', outfile);
-   if ((p = strchr(escapes, *s))) {
+   if ((p = strchr(escapes, s[i])) && s[i] != '\0') {
(void)fputc("\\abfrtv"[p - escapes], outfile);
count += 2;
} else {
-   

Re: rev(1): pull MB_CUR_MAX out of the hot loop

2022-01-08 Thread Martijn van Duren
I fully agree with your reasoning and also prefer this one over the
previous two diff.

OK martijn@

On Sun, 2022-01-09 at 00:45 +0100, Ingo Schwarze wrote:
> Hi,
> 
> Martijn van Duren wrote on Sat, Jan 08, 2022 at 08:30:20AM +0100:
> 
> > Why not go for the following diff?
> > It has a comparable speed increase, but without the added complexity
> > of a second inner loop.
> 
> Actually, i like the idea of not duplicating the loop, in cases where
> that is possible without a noticeable performance cost.
> 
> I admit i OK'ed the original UTF-8 diff almost six years ago,
> but looking at the code again, i now dislike how it is testing
> every byte twice for no apparent reason.  Even worse, i regard
> the lack of I/O error checking on write operations as a bug.
> Note that it does make sense to proceed to the next file on *read*
> errors, whereas a *write* error should better be fatal.
> 
> For those reason, and because i prefer versions of isu8cont()
> that do not inspect the locale, i propose the following patch
> instead.
> 
> As an aside, i tried using fwrite(3) instead of the manual
> putchar(*u) loop, but that is almost exactly as slow as repeatedly
> calling MB_CUR_MAX, probably due to either locking or orientation
> setting or some aspect of iov handling or buffering or more than
> one of those; i refrained from profiling it.
> 
>  - 8< - schnipp - >8 - 8< - schnapp - >8 -
> 
> Index: rev.c
> ===
> RCS file: /cvs/src/usr.bin/rev/rev.c,v
> retrieving revision 1.13
> diff -u -p -r1.13 rev.c
> --- rev.c 10 Apr 2016 17:06:52 -  1.13
> +++ rev.c 8 Jan 2022 23:19:46 -
> @@ -46,13 +46,14 @@ void usage(void);
>  int
>  main(int argc, char *argv[])
>  {
> - char *filename, *p = NULL, *t, *u;
> + char *filename, *p = NULL, *t, *te, *u;
>   FILE *fp;
>   ssize_t len;
>   size_t ps = 0;
> - int ch, rval;
> + int ch, multibyte, rval;
>  
>   setlocale(LC_CTYPE, "");
> + multibyte = MB_CUR_MAX > 1;
>  
>   if (pledge("stdio rpath", NULL) == -1)
>   err(1, "pledge");
> @@ -83,14 +84,16 @@ main(int argc, char *argv[])
>   if (p[len - 1] == '\n')
>   --len;
>   for (t = p + len - 1; t >= p; --t) {
> - if (isu8cont(*t))
> - continue;
> - u = t;
> - do {
> - putchar(*u);
> - } while (isu8cont(*(++u)));
> + te = t;
> + if (multibyte)
> + while (t > p && isu8cont(*t))
> + --t;
> + for (u = t; u <= te; ++u)
> + if (putchar(*u) == EOF)
> + err(1, "stdout");
>   }
> - putchar('\n');
> + if (putchar('\n') == EOF)
> + err(1, "stdout");
>   }
>   if (ferror(fp)) {
>   warn("%s", filename);
> @@ -104,7 +107,7 @@ main(int argc, char *argv[])
>  int
>  isu8cont(unsigned char c)
>  {
> - return MB_CUR_MAX > 1 && (c & (0x80 | 0x40)) == 0x80;
> + return (c & (0x80 | 0x40)) == 0x80;
>  }
>  
>  void
> 
>  - 8< - schnipp - >8 - 8< - schnapp - >8 -
> 
> The rest of this mail contains test reports.
> These test reports use two test programs:
> 
>  - 8< - schnipp - >8 - 8< - schnapp - >8 -
> 
> /* makeutf8.c */
> 
> #include 
> #include 
> #include 
> #include 
> #include 
> 
> int
> main(void)
> {
>   FILE*in, *out;
>   char*line = NULL;
>   size_t   linesize = 0;
>   unsigned int wc, wcl = 0;
> 
>   if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL)
>   err(1, "setlocale");
> 
>   if ((in = fopen("/usr/src/gnu/usr.bin/perl/lib/unicore/"
>   "UnicodeData.txt", "r")) == NULL)
>   err(1, "in");
>   if ((out = fopen("utf8.txt", "w")) == NULL)
>   err(1, "out");
> 
>   while (getline(, , in) != -1

Re: rev(1): pull MB_CUR_MAX out of the hot loop

2022-01-07 Thread Martijn van Duren
On Fri, 2022-01-07 at 15:00 -0600, Scott Cheloha wrote:
> On Fri, Jan 07, 2022 at 01:43:24PM -0600, Scott Cheloha wrote:
> > 
> > [...]
> > 
> > Like this?
> > 
> > [...]
> 
> Updated: make the for-loop update expressions match.
> 
Why not go for the following diff?
It has a comparable speed increase, but without the added complexity of
a second inner loop.

Either diff is fine by me though, so if you want to go ahead with your
diff: OK martijn@

$ export LC_ALL=C
$ for i in $(jot 10); do time rev /usr/share/dict/words > /dev/null; done
0m00.17s real 0m00.16s user 0m00.02s system
0m00.17s real 0m00.17s user 0m00.01s system
0m00.17s real 0m00.17s user 0m00.01s system
0m00.17s real 0m00.18s user 0m00.00s system
0m00.17s real 0m00.17s user 0m00.01s system
0m00.20s real 0m00.16s user 0m00.03s system
0m00.23s real 0m00.16s user 0m00.01s system
0m00.17s real 0m00.18s user 0m00.00s system
0m00.17s real 0m00.21s user 0m00.00s system
0m00.17s real 0m00.16s user 0m00.01s system
$ for i in $(jot 10); do time ./obj/rev.scott /usr/share/dict/words > 
/dev/null; done
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.02s system
0m00.06s real 0m00.04s user 0m00.02s system
0m00.05s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.05s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.03s user 0m00.01s system
0m00.04s real 0m00.05s user 0m00.00s system
$ for i in $(jot 10); do time ./obj/rev.martijn /usr/share/dict/words > 
/dev/null; done
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.03s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.06s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.05s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.01s system
$ export LC_ALL=en_US.UTF-8
$ for i in $(jot 10); do time rev /usr/share/dict/words > /dev/null; done
0m00.17s real 0m00.17s user 0m00.00s system
0m00.17s real 0m00.18s user 0m00.00s system
0m00.17s real 0m00.17s user 0m00.00s system
0m00.17s real 0m00.18s user 0m00.01s system
0m00.17s real 0m00.17s user 0m00.01s system
0m00.17s real 0m00.18s user 0m00.00s system
0m00.17s real 0m00.17s user 0m00.00s system
0m00.17s real 0m00.17s user 0m00.02s system
0m00.17s real 0m00.17s user 0m00.01s system
0m00.17s real 0m00.18s user 0m00.00s system
$ for i in $(jot 10); do time ./obj/rev.scott /usr/share/dict/words > 
/dev/null; done
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.05s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.00s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.01s system
0m00.04s real 0m00.04s user 0m00.00s system
$ for i in $(jot 10); do time ./obj/rev.martijn /usr/share/dict/words > 
/dev/null; done
0m00.04s real 0m00.04s user 0m00.01s system
0m00.05s real 0m00.04s user 0m00.00s system
0m00.05s real 0m00.05s user 0m00.00s system
0m00.05s real 0m00.03s user 0m00.02s system
0m00.05s real 0m00.05s user 0m00.00s system
0m00.05s real 0m00.05s user 0m00.00s system
0m00.05s real 0m00.05s user 0m00.00s system
0m00.05s real 0m00.04s user 0m00.01s system
0m00.05s real 0m00.04s user 0m00.01s system
0m00.05s real 0m00.05s user 0m00.00s system

martijn@

ps. I don't have your fancy nanotime. Where can I find that?

Index: rev.c
===
RCS file: /cvs/src/usr.bin/rev/rev.c,v
retrieving revision 1.13
diff -u -p -r1.13 rev.c
--- rev.c   10 Apr 2016 17:06:52 -  1.13
+++ rev.c   8 Jan 2022 07:09:19 -
@@ -43,6 +43,8 @@
 int isu8cont(unsigned char);
 void usage(void);
 
+int multibyte;
+
 int
 main(int argc, char *argv[])
 {
@@ -53,6 +55,7 @@ main(int argc, char *argv[])
int ch, rval;
 
setlocale(LC_CTYPE, "");
+   multibyte = MB_CUR_MAX > 1;
 
if (pledge("stdio rpath", 

Re: snmpd(8): New application layer - step towards agentx support

2022-01-05 Thread Martijn van Duren
Problem found: The code was compiled on -stable, which I apparently
misread. There's changes in libutil in current that this diff needs.

Pending Joel's results: Anyone else wanting to chime in?

On Mon, 2022-01-03 at 15:09 +0100, Joel Carnat wrote:
> Hello,
> 
> I have just patched my snmpd from -current ; everything else is 
> 7.0-stable. I'm not sure what happens but I use the same snmpd.conf and 
> connects to snmpd from another machine using
> 
> # snmpwalk -v 3 -a SHA -A "changeme" -l authPriv -u telegraf \
> -x AES -X "changeme" server
> 
> But using the patched snmpd, I get the following error:
> mib_2 = No Such Object available on this agent at this OID. Using the 
> 7.0 version, it works perfectly.
> 
> I can send full snmpd logs if you think it's usefull.
> 
> Regards,
> Joel C.
> 
> On 1/3/22 13:57, Martijn van Duren wrote:
> > On Sun, 2021-11-21 at 14:58 +0100, Martijn van Duren wrote:
> > > On Sun, 2021-11-14 at 14:35 +, Stuart Henderson wrote:
> > > > On 2021/11/14 11:49, Martijn van Duren wrote:
> > > > > sthen@ found an issue when using this diff with netsnmp tools.
> > > > > 
> > > > > The problem was that I put the requestID in the msgID, resulting
> > > > > in a mismatch upon receiving the reply. The reason that snmp(1)
> > > > > works is because msgID and requestID are the same.
> > > > > Diff below fixes things.
> > > > 
> > > > This version works for me, and the runtime increase with librenms
> > > > fetches and polls (which use a mixture of get/bulkwalk) is acceptable
> > > > (10% or so).
> > > > 
> > > Anyone else put this through a test? I want to move forward with this.
> > > 
> > > martijn@
> > > 
> > 2 month ping.
> > So far I only have gotten test results from sthen@.
> > Should I just put this in or is someone planning to actually look into
> > the code?
> > 
> > martijn@



Re: snmpd(8): New application layer - step towards agentx support

2022-01-03 Thread Martijn van Duren
On Mon, 2022-01-03 at 15:09 +0100, Joel Carnat wrote:
> Hello,
> 
> I have just patched my snmpd from -current ; everything else is 
> 7.0-stable. I'm not sure what happens but I use the same snmpd.conf and 
> connects to snmpd from another machine using
> 
> # snmpwalk -v 3 -a SHA -A "changeme" -l authPriv -u telegraf \
> -x AES -X "changeme" server
> 
> But using the patched snmpd, I get the following error:
> mib_2 = No Such Object available on this agent at this OID. Using the 
> 7.0 version, it works perfectly.
> 
> I can send full snmpd logs if you think it's usefull.

Thanks for testing, unfortunately I can't reproduce your error:
martijn$ snmpwalk -v3 -a SHA -A test1234 -l authpriv -u testsha1 -x AES -X 
test1234 127.0.0.1 | head
SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD martijn.office.cloudvps.nl 7.0 
GENERIC.MP#213 amd64
SNMPv2-MIB::sysObjectID.0 = OID: OPENBSD-BASE-MIB::openBSDDefaultObjectID
SNMPv2-MIB::sysUpTime.0 = Timeticks: (344136) 0:57:21.36
SNMPv2-MIB::sysContact.0 = STRING: Martijn van Duren
SNMPv2-MIB::sysName.0 = STRING: martijn
SNMPv2-MIB::sysLocation.0 = STRING: 
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (0) 0:00:00.00
SNMPv2-MIB::sysORIndex.1 = INTEGER: 1
SNMPv2-MIB::sysORIndex.2 = INTEGER: 2
SNMPv2-MIB::sysORIndex.3 = INTEGER: 3

Also, your report doesn't make sense to me: snmpwalk is from net-snmp,
while the name mib_2 is used (incorrectly) by snmp(1). And "No Such
Object" should not happen on getnext requests (which is what a walk
does): Something must have gone really weird to end up in such an
error path.

Could you please provide a minimal proof of concept snmpd.conf with
full client command and output to allow me to reproduce this?

> 
> Regards,
> Joel C.
> 
> On 1/3/22 13:57, Martijn van Duren wrote:
> > On Sun, 2021-11-21 at 14:58 +0100, Martijn van Duren wrote:
> > > On Sun, 2021-11-14 at 14:35 +, Stuart Henderson wrote:
> > > > On 2021/11/14 11:49, Martijn van Duren wrote:
> > > > > sthen@ found an issue when using this diff with netsnmp tools.
> > > > > 
> > > > > The problem was that I put the requestID in the msgID, resulting
> > > > > in a mismatch upon receiving the reply. The reason that snmp(1)
> > > > > works is because msgID and requestID are the same.
> > > > > Diff below fixes things.
> > > > 
> > > > This version works for me, and the runtime increase with librenms
> > > > fetches and polls (which use a mixture of get/bulkwalk) is acceptable
> > > > (10% or so).
> > > > 
> > > Anyone else put this through a test? I want to move forward with this.
> > > 
> > > martijn@
> > > 
> > 2 month ping.
> > So far I only have gotten test results from sthen@.
> > Should I just put this in or is someone planning to actually look into
> > the code?
> > 
> > martijn@



Re: ldap search vs ldapsearch

2022-01-03 Thread Martijn van Duren
On Mon, 2021-11-08 at 09:51 +0100, Martijn van Duren wrote:
> On Sat, 2021-11-06 at 03:11 -0400, Allan Streib wrote:
> > On OpenBSD 7.0-release, comparing the output of OpenLDAP's
> > ldapsearch(1) to ldap(1) search, the ldap(1) search output is
> > missing the last attribute of each directory entry.
> > 
> > e.g. from a directory I am working on at work:
> > 
> > $ ldapsearch -LLL -x -H ldapi://%2fvar%2frun%2fldapi -b 
> > dc=ise,dc=luddy,dc=indiana,dc=edu '(objectClass=organizationalUnit)'
> > dn: ou=people,dc=ise,dc=luddy,dc=indiana,dc=edu
> > objectClass: organizationalUnit
> > ou: people
> > description: ISE Systems Users
> > 
> > dn: ou=groups,dc=ise,dc=luddy,dc=indiana,dc=edu
> > objectClass: organizationalUnit
> > ou: groups
> > description: ISE Systems Groups
> > 
> > 
> > Note that these are missing the "description" attribute:
> > 
> > $ ldap search -H ldapi://%2fvar%2frun%2fldapi -b 
> > dc=ise,dc=luddy,dc=indiana,dc=edu '(objectClass=organizationalUnit)'
> > dn: ou=people,dc=ise,dc=luddy,dc=indiana,dc=edu
> > objectClass: organizationalUnit
> > ou: people
> > 
> > dn: ou=groups,dc=ise,dc=luddy,dc=indiana,dc=edu
> > objectClass: organizationalUnit
> > ou: groups
> > 
> > Allan
> > 
> Thanks for the detailed report.
> This edgecase got overlooked when moving to a stricter ASN.1 parsing for
> ober_scanf_elements, which resulted in a premature exit of the loop.
> Diff below should fix it.
> 
> This diff also applies to libexec/login_ldap and usr.sbin/ypldap.
> 
> OK?
> 
> martijn@

Almost forgot about this one.

Index: aldap.c
===
RCS file: /cvs/src/usr.bin/ldap/aldap.c,v
retrieving revision 1.9
diff -u -p -r1.9 aldap.c
--- aldap.c 24 Oct 2019 12:39:26 -  1.9
+++ aldap.c 8 Nov 2021 08:50:12 -
@@ -580,15 +580,15 @@ int
 aldap_first_attr(struct aldap_message *msg, char **outkey,
 struct aldap_stringset **outvalues)
 {
-   struct ber_element *b, *c;
+   struct ber_element *b;
char *key;
struct aldap_stringset *ret;
 
if (msg->body.search.attrs == NULL)
goto fail;
 
-   if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}e",
-   , , ) != 0)
+   if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}",
+   , ) != 0)
goto fail;
 
msg->body.search.iter = msg->body.search.attrs->be_next;
@@ -610,7 +610,7 @@ int
 aldap_next_attr(struct aldap_message *msg, char **outkey,
 struct aldap_stringset **outvalues)
 {
-   struct ber_element *a, *b;
+   struct ber_element *a;
char *key;
struct aldap_stringset *ret;
 
@@ -622,8 +622,7 @@ aldap_next_attr(struct aldap_message *ms
if (ober_get_eoc(msg->body.search.iter) == 0)
goto notfound;
 
-   if (ober_scanf_elements(msg->body.search.iter, "{s(e)}e", , , )
-   != 0)
+   if (ober_scanf_elements(msg->body.search.iter, "{s(e)}", , ) != 0)
goto fail;
 
msg->body.search.iter = msg->body.search.iter->be_next;



Re: snmpd(8): New application layer - step towards agentx support

2022-01-03 Thread Martijn van Duren
On Sun, 2021-11-21 at 14:58 +0100, Martijn van Duren wrote:
> On Sun, 2021-11-14 at 14:35 +, Stuart Henderson wrote:
> > On 2021/11/14 11:49, Martijn van Duren wrote:
> > > sthen@ found an issue when using this diff with netsnmp tools.
> > > 
> > > The problem was that I put the requestID in the msgID, resulting
> > > in a mismatch upon receiving the reply. The reason that snmp(1)
> > > works is because msgID and requestID are the same.
> > > Diff below fixes things.
> > 
> > This version works for me, and the runtime increase with librenms
> > fetches and polls (which use a mixture of get/bulkwalk) is acceptable
> > (10% or so).
> > 
> Anyone else put this through a test? I want to move forward with this.
> 
> martijn@
> 
2 month ping.
So far I only have gotten test results from sthen@.
Should I just put this in or is someone planning to actually look into
the code?

martijn@

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.17
diff -u -p -r1.17 Makefile
--- Makefile30 Jun 2020 17:11:49 -  1.17
+++ Makefile1 Dec 2021 06:45:57 -
@@ -2,7 +2,7 @@
 
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
-SRCS=  parse.y log.c snmpe.c \
+SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: application.c
diff -N application.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application.c   1 Dec 2021 06:45:57 -
@@ -0,0 +1,1451 @@
+/* $OpenBSD$   */
+
+/*
+ * Copyright (c) 2021 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "application.h"
+#include "log.h"
+#include "smi.h"
+#include "snmp.h"
+#include "snmpe.h"
+#include "mib.h"
+
+TAILQ_HEAD(, appl_context) contexts = TAILQ_HEAD_INITIALIZER(contexts);
+
+struct appl_context {
+   char ac_name[APPL_CONTEXTNAME_MAX + 1];
+
+   RB_HEAD(appl_regions, appl_region) ac_regions;
+
+   TAILQ_ENTRY(appl_context) ac_entries;
+};
+
+struct appl_region {
+   struct ber_oid ar_oid;
+   uint8_t ar_priority;
+   int32_t ar_timeout;
+   int ar_instance;
+   int ar_subtree; /* Claim entire subtree */
+   struct appl_backend *ar_backend;
+   struct appl_region *ar_next; /* Sorted by priority */
+
+   RB_ENTRY(appl_region) ar_entry;
+};
+
+struct appl_request_upstream {
+   struct appl_context *aru_ctx;
+   struct snmp_message *aru_statereference;
+   int32_t aru_requestid; /* upstream requestid */
+   int32_t aru_transactionid; /* RFC 2741 section 6.1 */
+   int16_t aru_nonrepeaters;
+   int16_t aru_maxrepetitions;
+   struct appl_varbind_internal *aru_vblist;
+   size_t aru_varbindlen;
+   enum appl_error aru_error;
+   int16_t aru_index;
+   int aru_locked; /* Prevent recursion through appl_request_send */
+
+   enum snmp_version aru_pduversion;
+   struct ber_element *aru_pdu; /* Original requested pdu */
+};
+
+struct appl_request_downstream {
+   struct appl_request_upstream *ard_request;
+   struct appl_backend *ard_backend;
+   enum snmp_pdutype ard_requesttype;
+   int16_t ard_nonrepeaters;
+   int16_t ard_maxrepetitions;
+   int32_t ard_requestid;
+   uint8_t ard_retries;
+
+   struct appl_varbind_internal *ard_vblist;
+   struct event ard_timer;
+
+   RB_ENTRY(appl_request_downstream) ard_entry;
+};
+
+enum appl_varbind_state {
+   APPL_VBSTATE_MUSTFILL,
+   APPL_VBSTATE_NEW,
+   APPL_VBSTATE_PENDING,
+   APPL_VBSTATE_DONE
+};
+
+struct appl_varbind_internal {
+   enum appl_varbind_state avi_state;
+   struct appl_varbind avi_varbind;
+   struct appl_region *avi_region;
+   int16_t avi_index;
+   str

Re: Do not send SIGHUP to syslogd on wtmp rotation

2021-12-08 Thread Martijn van Duren
Comitted, thanks.
Although your patch was mangled, so I needed to apply it by hand.
Please make sure that you mail is properly formatted.

martijn@

On Wed, 2021-12-08 at 13:03 +0300, Антон Касимов wrote:
> Hi,
> I've noticed that newsyslog sends SIGHUP to syslogd on /var/log/wtmp
> rotation.
> But syslogd does not deal with the wtmp log file so there is no need for
> SIGHUP.
> 
> I propose to make slightly changes to default newsyslog.conf file:
> 
> --- /etc/newsyslog.conf Thu Oct 11 22:18:27 2018
> +++ /tmp/newsyslog.conf Wed Dec  8 02:05:10 2021
> @@ -10,7 +10,7 @@
>  /var/log/maillog 640  7 *24Z
>  /var/log/messages 644  5 300  * Z
>  /var/log/secure 600  7 *168   Z
> -/var/log/wtmp 644  7 *$W6D4 B
> +/var/log/wtmp 644  7 *$W6D4 B ""
>  /var/log/xferlog 640  7 250  * Z
>  /var/log/pflog 600  3 250  * ZB "pkill -HUP -u root -U root -t -
> -x pflogd"
>  /var/www/logs/access.log 644  4 *$W0   Z "pkill -USR1 -u root -U
> root -x httpd"
> 
> 
> -- Forwarded message -
> От: Martijn van Duren 
> Date: ср, 8 дек. 2021 г. в 09:50
> Subject: Re: Proposal for improvement of newsyslog.conf
> To: Антон Касимов , 
> 
> 
> On Wed, 2021-12-08 at 02:12 +0300, Антон Касимов wrote:
> > Hi,
> > I've noticed that newsyslog sends SIGHUP to syslogd on /var/log/wtmp
> > rotation.
> > But syslogd does not deal with the wtmp log file so there is no need for
> > SIGHUP.
> > 
> > I propose to make slightly changes to default newsyslog.conf file:
> > 13c13
> > < /var/log/wtmp 644  7 *$W6D4 B
> > ---
> > > /var/log/wtmp 644  7 *$W6D4 B ""
> > 
> > Is misc a proper mailing list, or shall I send this message to bugs?
> > 
> tech@ is usually the best place for this kind of suggestions.
> Also make sure that you make your diff unified (diff -u).
> 
> martijn@
> 
> 



Re: snmpd(8): New application layer - step towards agentx support

2021-11-30 Thread Martijn van Duren
On Sun, 2021-11-21 at 14:58 +0100, Martijn van Duren wrote:
> On Sun, 2021-11-14 at 14:35 +, Stuart Henderson wrote:
> > On 2021/11/14 11:49, Martijn van Duren wrote:
> > > sthen@ found an issue when using this diff with netsnmp tools.
> > > 
> > > The problem was that I put the requestID in the msgID, resulting
> > > in a mismatch upon receiving the reply. The reason that snmp(1)
> > > works is because msgID and requestID are the same.
> > > Diff below fixes things.
> > 
> > This version works for me, and the runtime increase with librenms
> > fetches and polls (which use a mixture of get/bulkwalk) is acceptable
> > (10% or so).
> > 
> Anyone else put this through a test? I want to move forward with this.
> 
> martijn@
> 
ping

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/snmpd/Makefile,v
retrieving revision 1.17
diff -u -p -r1.17 Makefile
--- Makefile30 Jun 2020 17:11:49 -  1.17
+++ Makefile1 Dec 2021 06:45:57 -
@@ -2,7 +2,7 @@
 
 PROG=  snmpd
 MAN=   snmpd.8 snmpd.conf.5
-SRCS=  parse.y log.c snmpe.c \
+SRCS=  parse.y log.c snmpe.c application.c application_legacy.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
pf.c proc.c usm.c traphandler.c util.c
 
Index: application.c
===
RCS file: application.c
diff -N application.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ application.c   1 Dec 2021 06:45:57 -
@@ -0,0 +1,1451 @@
+/* $OpenBSD$   */
+
+/*
+ * Copyright (c) 2021 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "application.h"
+#include "log.h"
+#include "smi.h"
+#include "snmp.h"
+#include "snmpe.h"
+#include "mib.h"
+
+TAILQ_HEAD(, appl_context) contexts = TAILQ_HEAD_INITIALIZER(contexts);
+
+struct appl_context {
+   char ac_name[APPL_CONTEXTNAME_MAX + 1];
+
+   RB_HEAD(appl_regions, appl_region) ac_regions;
+
+   TAILQ_ENTRY(appl_context) ac_entries;
+};
+
+struct appl_region {
+   struct ber_oid ar_oid;
+   uint8_t ar_priority;
+   int32_t ar_timeout;
+   int ar_instance;
+   int ar_subtree; /* Claim entire subtree */
+   struct appl_backend *ar_backend;
+   struct appl_region *ar_next; /* Sorted by priority */
+
+   RB_ENTRY(appl_region) ar_entry;
+};
+
+struct appl_request_upstream {
+   struct appl_context *aru_ctx;
+   struct snmp_message *aru_statereference;
+   int32_t aru_requestid; /* upstream requestid */
+   int32_t aru_transactionid; /* RFC 2741 section 6.1 */
+   int16_t aru_nonrepeaters;
+   int16_t aru_maxrepetitions;
+   struct appl_varbind_internal *aru_vblist;
+   size_t aru_varbindlen;
+   enum appl_error aru_error;
+   int16_t aru_index;
+   int aru_locked; /* Prevent recursion through appl_request_send */
+
+   enum snmp_version aru_pduversion;
+   struct ber_element *aru_pdu; /* Original requested pdu */
+};
+
+struct appl_request_downstream {
+   struct appl_request_upstream *ard_request;
+   struct appl_backend *ard_backend;
+   enum snmp_pdutype ard_requesttype;
+   int16_t ard_nonrepeaters;
+   int16_t ard_maxrepetitions;
+   int32_t ard_requestid;
+   uint8_t ard_retries;
+
+   struct appl_varbind_internal *ard_vblist;
+   struct event ard_timer;
+
+   RB_ENTRY(appl_request_downstream) ard_entry;
+};
+
+enum appl_varbind_state {
+   APPL_VBSTATE_MUSTFILL,
+   APPL_VBSTATE_NEW,
+   APPL_VBSTATE_PENDING,
+   APPL_VBSTATE_DONE
+};
+
+struct appl_varbind_internal {
+   enum appl_varbind_state avi_state;
+   struct appl_varbind avi_varbind;
+   struct appl_region *avi_region;
+   int16_t avi_index;
+   struct appl_request_upstream *avi_request_upstream;
+   struct appl_request_downstream *avi_request_downstream;
+   struct appl_varbind_internal *avi_

Re: snmpd(8): New application layer - step towards agentx support

2021-11-21 Thread Martijn van Duren
On Sun, 2021-11-14 at 14:35 +, Stuart Henderson wrote:
> On 2021/11/14 11:49, Martijn van Duren wrote:
> > sthen@ found an issue when using this diff with netsnmp tools.
> > 
> > The problem was that I put the requestID in the msgID, resulting
> > in a mismatch upon receiving the reply. The reason that snmp(1)
> > works is because msgID and requestID are the same.
> > Diff below fixes things.
> 
> This version works for me, and the runtime increase with librenms
> fetches and polls (which use a mixture of get/bulkwalk) is acceptable
> (10% or so).
> 
Anyone else put this through a test? I want to move forward with this.

martijn@



Re: snmpd: tweak listen on

2021-11-21 Thread Martijn van Duren
On Sat, 2021-11-20 at 14:17 +, Stuart Henderson wrote:
> On 2021/11/20 10:20, Martijn van Duren wrote:
> > On Sun, 2021-11-14 at 22:30 +0100, Sebastian Benoit wrote:
> > > If there is no obvious reason (i.e. be different because you need it for a
> > > specific feature) why not to use the same host*() function as other 
> > > parse.y?
> > > it would be better to stay in sync with otehrr daemons. That way if there 
> > > is
> > > an issue in one daemon, we can fix it in all of them.
> > > 
> > > Or, to turn the argument around: if you have found a way to improve those
> > > functions in parse.y, you could push for your changes to be applied to all
> > > parse.y that use the same function.
> > > 
> > > This applies to other parse.y functions too. The more they deviate, the
> > > harder maintanance becomes.
> > 
> > This is the original message[0] (code committed had some tweaks not in this
> > mail).
> > In there I mention reyk's commit message saying that host_* could be merged.
> > This commit tried to implement that (but apparently doesn't hold true any
> > more, or maybe it never did). Moving away from struct address in host() also
> > has the benefit that having different implementations of struct address to
> > be more forgiving and it's less code overall.
> > 
> > Since it took over a year to find this particular edge case I think it could
> > be a good idea to push this code to the other daemons as well, but I'm short
> > on time at the moment.
> > 
> > Diff below should fix this particular issue and is easy enough to revert if
> > we decide to go for the behaviour change of getaddrinfo proposed in my
> > previous mail.
> 
> ok

committed, thanks.
> 
> > I'm not afraid of moving the other way in getaddrinfo (that AI_NUMERICHOST
> > is also subject to the family statement in resolv.conf), because that would
> 
> I don't like that at all. And I don't think it matches resolv.conf's
> definition of "family":
> 
>  family  Specify which type of Internet protocol family to prefer, if
>  a host is reachable using different address families. 
> 
> the "if a host is reachable using different address families"
> means that this doesn't apply for numeric addresses. (OK there could be
> a side-case with CLAT on OS that don't force IPV6_V6ONLY but not on
> OpenBSD).
> 
I fully agree and that was the line of thought in my original diff.
However, I still think the behaviour should be made consistent between
AI_NUMERICHOST and !AI_NUMERICHOST. Iff someone were to make a solid
argument for the behaviour of !AI_NUMERICHOST in AI_NUMERICHOST my code
is not any more dangerous than the current host_v6 cases in the other
daemons. That was my only point I wanted to make.
> 
> 
> > also break all current host_v6 implementations in parse.y, so that would
> > be an overhaul in all parse.y files anyway.
> > 
> > martijn@
> > > 
> > > Martijn van Duren(openbsd+t...@list.imperialat.at) on 2021.11.14 00:23:59 
> > > +0100:
> > > > On Sat, 2021-11-13 at 13:23 +, Stuart Henderson wrote:
> > > > > On 2021/08/09 20:55, Martijn van Duren wrote:
> > > > > > On Mon, 2021-08-09 at 11:57 +0200, Martijn van Duren wrote:
> > > > > > > 
> > > > > > > This diff fixes all of the above:
> > > > > > > - Allow any to be used resolving to 0.0.0.0 and ::
> > > > > > > - Set SO_REUSEADDR on sockets, so we can listen on both any and
> > > > > > > ?? localhost
> > > > > > > - Document that we listen on any by default
> > > > > 
> > > > > I've discovered a problem with this, if you have "family inet4" or
> > > > > "family inet6" in resolv.conf then startup fails, either with the
> > > > > implicit listen:
> > > > > 
> > > > > snmpd: Unexpected resolving of ::
> > > > > 
> > > > > or with explicit e.g. "listen on any snmpv3":
> > > > > 
> > > > > /etc/snmpd.conf:3: invalid address: any
> > > > > 
> > > > > Config-based workaround is e.g. "listen on 0.0.0.0 snmpv3"
> > > > > 
> > > > > Should host() use a specific ai_family instead of PF_UNSPEC where we
> > > > > already know that it's a v4 or v6 address? Or just do like 
> > > > > httpd/parse.y
> > > > > where host() tries v4, then v6 if that fails, then dns?
>

Re: snmpd: tweak listen on

2021-11-20 Thread Martijn van Duren
On Sun, 2021-11-14 at 22:30 +0100, Sebastian Benoit wrote:
> If there is no obvious reason (i.e. be different because you need it for a
> specific feature) why not to use the same host*() function as other parse.y?
> it would be better to stay in sync with otehrr daemons. That way if there is
> an issue in one daemon, we can fix it in all of them.
> 
> Or, to turn the argument around: if you have found a way to improve those
> functions in parse.y, you could push for your changes to be applied to all
> parse.y that use the same function.
> 
> This applies to other parse.y functions too. The more they deviate, the
> harder maintanance becomes.

This is the original message[0] (code committed had some tweaks not in this
mail).
In there I mention reyk's commit message saying that host_* could be merged.
This commit tried to implement that (but apparently doesn't hold true any
more, or maybe it never did). Moving away from struct address in host() also
has the benefit that having different implementations of struct address to
be more forgiving and it's less code overall.

Since it took over a year to find this particular edge case I think it could
be a good idea to push this code to the other daemons as well, but I'm short
on time at the moment.

Diff below should fix this particular issue and is easy enough to revert if
we decide to go for the behaviour change of getaddrinfo proposed in my
previous mail.

I'm not afraid of moving the other way in getaddrinfo (that AI_NUMERICHOST
is also subject to the family statement in resolv.conf), because that would
also break all current host_v6 implementations in parse.y, so that would
be an overhaul in all parse.y files anyway.

martijn@
> 
> Martijn van Duren(openbsd+t...@list.imperialat.at) on 2021.11.14 00:23:59 
> +0100:
> > On Sat, 2021-11-13 at 13:23 +, Stuart Henderson wrote:
> > > On 2021/08/09 20:55, Martijn van Duren wrote:
> > > > On Mon, 2021-08-09 at 11:57 +0200, Martijn van Duren wrote:
> > > > > 
> > > > > This diff fixes all of the above:
> > > > > - Allow any to be used resolving to 0.0.0.0 and ::
> > > > > - Set SO_REUSEADDR on sockets, so we can listen on both any and
> > > > > ?? localhost
> > > > > - Document that we listen on any by default
> > > 
> > > I've discovered a problem with this, if you have "family inet4" or
> > > "family inet6" in resolv.conf then startup fails, either with the
> > > implicit listen:
> > > 
> > > snmpd: Unexpected resolving of ::
> > > 
> > > or with explicit e.g. "listen on any snmpv3":
> > > 
> > > /etc/snmpd.conf:3: invalid address: any
> > > 
> > > Config-based workaround is e.g. "listen on 0.0.0.0 snmpv3"
> > > 
> > > Should host() use a specific ai_family instead of PF_UNSPEC where we
> > > already know that it's a v4 or v6 address? Or just do like httpd/parse.y
> > > where host() tries v4, then v6 if that fails, then dns?
> > > 

[0] https://marc.info/?l=openbsd-tech=159838549814986=2

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.72
diff -u -p -r1.72 parse.y
--- parse.y 25 Oct 2021 11:21:32 -  1.72
+++ parse.y 20 Nov 2021 09:19:00 -
@@ -1600,7 +1600,16 @@ host(const char *s, const char *port, in
bzero(, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = type;
+   /*
+* Without AI_NUMERICHOST getaddrinfo might not resolve ip addresses
+* for families not specified in the "family" statement in resolv.conf.
+*/
+   hints.ai_flags = AI_NUMERICHOST;
error = getaddrinfo(s, port, , );
+   if (error == EAI_NONAME) {
+   hints.ai_flags = 0;
+   error = getaddrinfo(s, port, , );
+   }
if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
return 0;
if (error) {



Re: [PATCH] usr.sbin/ldapd: Match bind DN by suffix instead of complete DN.

2021-11-14 Thread Martijn van Duren
On Sun, 2021-11-14 at 14:08 +0100, vifino wrote:
> On Wed Nov 10, 2021 at 9:46 AM CET, Martijn van Duren wrote:
> > On Fri, 2021-10-15 at 06:13 +, Klemens Nanni wrote:
> > > On Sun, Oct 03, 2021 at 10:05:56AM +, Klemens Nanni wrote:
> > > > On Sat, Oct 02, 2021 at 07:03:21PM +0200, vifino wrote:
> > > > > On Sat Oct 2, 2021 at 6:36 PM CEST, Raf Czlonka wrote:
> > > > > > On Sat, Oct 02, 2021 at 02:15:53PM BST, vifino wrote:
> > > > > > > Index: ldapd.conf.5
> > > > > > > ===
> > > > > > > RCS file: /cvs/src/usr.sbin/ldapd/ldapd.conf.5,v
> > > > > > > retrieving revision 1.27
> > > > > > > diff -u -p -u -p -r1.27 ldapd.conf.5
> > > > > > > --- ldapd.conf.5  24 Jun 2020 07:20:47 -  1.27
> > > > > > > +++ ldapd.conf.5  2 Oct 2021 12:43:29 -
> > > > > > > @@ -270,7 +270,7 @@ Finally, the filter rule can match a bin
> > > > > > >  The filter rule matches by any bind dn, including anonymous 
> > > > > > > binds.
> > > > > > >  .It by Ar DN
> > > > > > >  The filter rule matches only if the requestor has previously 
> > > > > > > performed
> > > > > > > -a bind as the specified distinguished name.
> > > > > > > +a bind as the specified distinguished name or a decendant.
> > > > > >^
> > > > > > A spellchecker[0] would have caught that ;^)
> > > > > Ah, yes, of course. The one thing I spent zero effort on.
> > > > > I haven't quite grokked the workflow, first submitted patch and all.
> > > > > I'll certainly run `spell` next time.
> > > > > 
> > > > > I'll keep this in mind for the next one. ;)
> > > > > > 
> > > > > > [0] https://manpages.bsd.lv/part3-3-2.html
> > > > > > 
> > > > > > Regards,
> > > > > > 
> > > > > > Raf
> > > > > 
> > > > > Revised patch below, not that it's necessary.
> > > > > - vifino
> > > > 
> > > > The patch doesn't apply (for me) as your mail is quoted, here's your
> > > > diff in 7bit.
> > > > 
> > > > Makes sense and works as expected.
> > > > OK kn if some other LDAP hacker wants to commit, otherwise I'd make sure
> > > > that this lands unless there are objections.
> > > 
> > > Any takers?  I plan to commit this by the end of the weekend.
> > 
> > Sorry for the delay.
> > 
> > The code looks good to me, however there is one edge case I think
> > doesn't occur too often in the wild, but could bite people in the
> > rear if they deploy this construct:
> > 
> > Things like an organization or organizationalUnit MAY contain
> > userPassword, which implies that people might login as that particular
> > DN, which in turn might have something like posixAccount entries below
> > it. The problem now becomes that the posixAccounts get the same
> > permissions the organizationalUnit.
> Hey.
> On my first thoughts, I considered that a quite weird use of LDAP.
> After all, having seperate user accounts seems - to me - to be the point.
> Why would you bind as that?
> 
> I could only think of one usecase: To allow creation of new sub-DN accounts
> from an organizational admin, limited in it's power.
> However, this could probably be solved more cleanly by a seperate rule,
> which would allow more than one admin. (Without sharing passwords.. yuck!)
> 
> In my opinion, any organization which is large enough to have seperate
> admins for sub-DNs is also large enough to potentially need more than
> one account for it.

*shrugs* I don't know. But it's more than possible within the LDAP data
structures and so we should assume that people are using these features
or might be using them in the future.

It's unlikely that I would set up a setup like that, but I've been
surprised by people's setups too often that my "best practice"
understanding has been completely thrown out the window.
> 
> I would love hear of a situation where this edge case gets triggered!

But if I were to let my imagination go wild: maybe it's the binddn
used by login_ldap to search for accounts.
> 
> Plus, there is a simple enough workaround:
> Have more than one rule, one with a comma before the filter DN.
> It'll only matc

Re: snmpd(8): New application layer - step towards agentx support

2021-11-14 Thread Martijn van Duren
sthen@ found an issue when using this diff with netsnmp tools.

The problem was that I put the requestID in the msgID, resulting
in a mismatch upon receiving the reply. The reason that snmp(1)
works is because msgID and requestID are the same.
Diff below fixes things.

On Mon, 2021-11-01 at 18:59 +0100, Martijn van Duren wrote:
> So here's (part of) my work from h2k21.
> 
> The end-goal is to re-introduce agentx support in snmpd.
> 
> Currently snmpd(8) has its varbind logic divided over 4 files:
> - snmpe.c:loop over the varbinds inside the pdu/snmp-package.
> - smi.c:  Register all the objects and act as a lookup for the
>   requested varbinds (as well as some other things that
>   are irrelevant to this story)
> - mib.c:  The object implementation: This is where the actual
>   objects live and are being registered inside smi.c
> - mps.c:  The glue between snmpe.c, smi.c and mib.c. snmpe.c
>   calls the mps.c functions for the appropriate request-
>   type and calls out to smi.c to find the correct backend
>   which in turns calls out the callback functions which
>   live in mib.c to get the actual data.
> 
> So what is wrong with this approach/the current implementation?
> - The current implementation is fully synchronous, meaning that if a
>   backend decides to waits a long time (snmp(1)'s default timeout is
>   1 second, the snmpTargetAddrTimeout is 1500 centiseconds) and multiple
>   varbinds are requested it would be really easy to go over the
>   timeout.
> - Because varbinds are requested in a loop it's currently not possible
>   to lookup the backend for each requested varbind and cluster these
>   varbinds in their subqueries. This could delay things even further.
> - mps, according to snmpd.h, stands for message processing subsystem.
>   However, mps according to RFC3412 means the {,un}packing of the snmp
>   package, not the handling of the varbinds. According to RFC3413 that
>   name should be application.
> - When a variable is not found in smi.c/mps.c it returns -1 for SNMPv1
>   packages. This in turn gets converted into a noSuchName by snmpe.c.
>   However, mib.c can return -1 on error, which simply bubbles up from
>   mps.c into snmpe.c, which still gets converted into noSuchName,
>   instead of the expected genErr.
> - snmpe.c calls mps_getbulkreq on each varbind, resulting in all the
>   maxrepetitions being placed subsequently one after another for each
>   requested varbind. However, according to RFC3416 section 4.2.3, these
>   results should be interleaved. To phrase it in a different way: If
>   the requested varbinds are the column names of a table, the response-
>   pdu should return the results row by row, while we currently return
>   the results column by column.
> - While mps.c tries to take into account the NoSuchName case to properly
>   support SNMPv1, it completely ignores the Counter64 case, which does
>   not exist in SNMPv1. According to RFC3584 these should return
>   NoSuchName for get requests and move to the next object for
>   get{next,bulk}-requests and return NoSuchName on EOMV.
> - The current implementation (in the current local-only constraints;
>   safely) assumes that all objects are registered on a boundary and no
>   overlapping regions are registered. This assumption however breaks
>   when moving to agentx-space where regions can be allocated overlapping
>   and with different priority. So before moving to the next object on
>   the edge of the registered regions we must first look back up to see
>   if there's a region that also needs to be asked to stay in
>   lexicographical order.
> - The current implementation completely ignores trailing sub-
>   identifiers that are deemed unnecessary for the request. E.g.
>   requesting sysContact.0.1 returns the value of sysContact.0 on the
>   instanstance syscontact.0.1. This must be a noSuchInstance exception
>   (or NoSuchName error in case of SNMPv1)
> 
> Considering all the issues mentioned above and the fact that the entire
> application namespace was free it was easier to just reimplement things
> from scratch. I tried to keep as much of the existing code in place as
> I could, so that in the case of problems moving back to the old codepath
> wouldn't mean reverting the entire diff, as well as keep the mental
> gymnastics around the current code to a minimum.
> 
> Apart from the fixes mentioned above, this code has two downsides that I
> think are worth accepting:
> - I haven't implemented write support. It doesn't really make sense for
>   our current support level. We don't have atomic support, which is
>   expected for proper SNMP implementations. And the values are volatile
>   a

Re: snmpd: tweak listen on

2021-11-13 Thread Martijn van Duren
On Sat, 2021-11-13 at 13:23 +, Stuart Henderson wrote:
> On 2021/08/09 20:55, Martijn van Duren wrote:
> > On Mon, 2021-08-09 at 11:57 +0200, Martijn van Duren wrote:
> > > 
> > > This diff fixes all of the above:
> > > - Allow any to be used resolving to 0.0.0.0 and ::
> > > - Set SO_REUSEADDR on sockets, so we can listen on both any and
> > >   localhost
> > > - Document that we listen on any by default
> 
> I've discovered a problem with this, if you have "family inet4" or
> "family inet6" in resolv.conf then startup fails, either with the
> implicit listen:
> 
> snmpd: Unexpected resolving of ::
> 
> or with explicit e.g. "listen on any snmpv3":
> 
> /etc/snmpd.conf:3: invalid address: any
> 
> Config-based workaround is e.g. "listen on 0.0.0.0 snmpv3"
> 
> Should host() use a specific ai_family instead of PF_UNSPEC where we
> already know that it's a v4 or v6 address? Or just do like httpd/parse.y
> where host() tries v4, then v6 if that fails, then dns?
> 
Actually, this diff isn't the cause of the regression, it's r1.60 of
parse.y. Prior to that snmpd also used the v4->v6->dns method, similar
to httpd. I removed these steps to simplify the code and because
getaddrinfo(3) is supposed to do the same thing as host_v4 and host_v6
do/did. To be more precise: host_v6 uses getaddrinfo(3), but with the
AI_NUMERICHOST flag.

So this brings to light a discrepancy's between calling getaddrinfo(3)
with and without AI_NUMERICHOST:
When called without AI_NUMERICHOST the family keyword in resolv.conf(5)
is "honoured", but when called with AI_NUMERICHOST the family keyword is
ignored.

When looking at POSIX[0] it states:
If the nodename argument is not null, it can be a descriptive name or
can be an address string. If the specified address family is AF_INET,
[IP6] [Option Start]  AF_INET6, [Option End] or AF_UNSPEC, valid
descriptive names include host names. If the specified address family is
AF_INET or AF_UNSPEC, address strings using Internet standard dot
notation as specified in inet_addr are valid.

[IP6] [Option Start] If the specified address family is AF_INET6 or
AF_UNSPEC, standard IPv6 text forms described in inet_ntop are valid.
[Option End]

The way I read this text is that we should always test for numeric
hostnames (within the requested family of ai_family) regardless of what
is in resolv.conf and would make us consistent with the AI_NUMERICHOST
case. This is also consistent with the phrasing in resolv.conf(5), which
states "inet4 IPv4 queries.", since I don't consider calling
inet_pton(3) (which is what is called internally) a query.
Diff below does this and fixes the bug in snmpd(8).

As for the risks: I think these are nil: It only affects the few
installs that have set family to a single value. For the people that
do have it, it will change an IPv{4,6} literal to always be "resolved",
but if you enter e.g. a v6 numeric address on a v4 only machines it will
almost always error out on the next step (most probably EHOSTUNREACH or
EADDRNOTAVAIL).

regress/lib/libc/asr is currently broken, but with some minimal tweaking
all test-cases pass.

martijn@

[0] https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html

Index: asr/getaddrinfo_async.c
===
RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v
retrieving revision 1.57
diff -u -p -r1.57 getaddrinfo_async.c
--- asr/getaddrinfo_async.c 26 Jan 2021 12:27:28 -  1.57
+++ asr/getaddrinfo_async.c 13 Nov 2021 23:17:43 -
@@ -492,8 +492,8 @@ get_port(const char *servname, const cha
 }
 
 /*
- * Iterate over the address families that are to be queried. Use the
- * list on the async context, unless a specific family was given in hints.
+ * Iterate over PF_INET and PF_INET6 unless a specific family was given in
+ * hints. Only to be used when resolving numeric address.
  */
 static int
 iter_family(struct asr_query *as, int first)
@@ -502,7 +502,7 @@ iter_family(struct asr_query *as, int fi
as->as_family_idx = 0;
if (as->as.ai.hints.ai_family != PF_UNSPEC)
return as->as.ai.hints.ai_family;
-   return AS_FAMILY(as);
+   return PF_INET;
}
 
if (as->as.ai.hints.ai_family != PF_UNSPEC)
@@ -510,7 +510,7 @@ iter_family(struct asr_query *as, int fi
 
as->as_family_idx++;
 
-   return AS_FAMILY(as);
+   return as->as_family_idx == 1 ? PF_INET6 : -1;
 }
 
 /*



Re: locale in who(1)

2021-11-10 Thread Martijn van Duren
I see no reason to keep it.

OK martijn@ if anyone wants to commit this.

On Wed, 2021-11-10 at 13:37 +0100, Jan Stary wrote:
> Why does who(1) need to setlocale()?
> 
>   Jan
> 
> 
> Index: who.c
> ===
> RCS file: /cvs/src/usr.bin/who/who.c,v
> retrieving revision 1.30
> diff -u -p -r1.30 who.c
> --- who.c 12 Jul 2021 15:09:20 -  1.30
> +++ who.c 10 Nov 2021 12:37:05 -
> @@ -44,7 +44,6 @@
>  #include 
>  #include 
>  #include 
> -#include 
>  
>  void  output(struct utmp *);
>  void  output_labels(void);
> @@ -71,8 +70,6 @@ main(int argc, char *argv[])
>   FILE *ufp;
>   char *t;
>   int c;
> -
> - setlocale(LC_ALL, "");
>  
>   if (pledge("stdio unveil rpath getpw", NULL) == -1)
>   err(1, "pledge");
> 



Re: [PATCH] usr.sbin/ldapd: Match bind DN by suffix instead of complete DN.

2021-11-10 Thread Martijn van Duren
On Fri, 2021-10-15 at 06:13 +, Klemens Nanni wrote:
> On Sun, Oct 03, 2021 at 10:05:56AM +, Klemens Nanni wrote:
> > On Sat, Oct 02, 2021 at 07:03:21PM +0200, vifino wrote:
> > > On Sat Oct 2, 2021 at 6:36 PM CEST, Raf Czlonka wrote:
> > > > On Sat, Oct 02, 2021 at 02:15:53PM BST, vifino wrote:
> > > > > Index: ldapd.conf.5
> > > > > ===
> > > > > RCS file: /cvs/src/usr.sbin/ldapd/ldapd.conf.5,v
> > > > > retrieving revision 1.27
> > > > > diff -u -p -u -p -r1.27 ldapd.conf.5
> > > > > --- ldapd.conf.5  24 Jun 2020 07:20:47 -  1.27
> > > > > +++ ldapd.conf.5  2 Oct 2021 12:43:29 -
> > > > > @@ -270,7 +270,7 @@ Finally, the filter rule can match a bin
> > > > >  The filter rule matches by any bind dn, including anonymous binds.
> > > > >  .It by Ar DN
> > > > >  The filter rule matches only if the requestor has previously 
> > > > > performed
> > > > > -a bind as the specified distinguished name.
> > > > > +a bind as the specified distinguished name or a decendant.
> > > >^
> > > > A spellchecker[0] would have caught that ;^)
> > > Ah, yes, of course. The one thing I spent zero effort on.
> > > I haven't quite grokked the workflow, first submitted patch and all.
> > > I'll certainly run `spell` next time.
> > > 
> > > I'll keep this in mind for the next one. ;)
> > > > 
> > > > [0] https://manpages.bsd.lv/part3-3-2.html
> > > > 
> > > > Regards,
> > > > 
> > > > Raf
> > > 
> > > Revised patch below, not that it's necessary.
> > > - vifino
> > 
> > The patch doesn't apply (for me) as your mail is quoted, here's your
> > diff in 7bit.
> > 
> > Makes sense and works as expected.
> > OK kn if some other LDAP hacker wants to commit, otherwise I'd make sure
> > that this lands unless there are objections.
> 
> Any takers?  I plan to commit this by the end of the weekend.

Sorry for the delay.

The code looks good to me, however there is one edge case I think
doesn't occur too often in the wild, but could bite people in the
rear if they deploy this construct:

Things like an organization or organizationalUnit MAY contain
userPassword, which implies that people might login as that particular
DN, which in turn might have something like posixAccount entries below
it. The problem now becomes that the posixAccounts get the same
permissions the organizationalUnit.

Maybe something like "by filter" would be a better fit, since it would
allow for an even wider functionality.

martijn@
> 
> 
> Index: auth.c
> ===
> RCS file: /cvs/src/usr.sbin/ldapd/auth.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 auth.c
> --- auth.c24 Oct 2019 12:39:26 -  1.14
> +++ auth.c3 Oct 2021 09:25:10 -
> @@ -94,8 +94,13 @@ aci_matches(struct aci *aci, struct conn
>   if (strcmp(aci->subject, "@") == 0) {
>   if (strcmp(dn, conn->binddn) != 0)
>   return 0;
> - } else if (strcmp(aci->subject, conn->binddn) != 0)
> - return 0;
> + } else {
> + key.size = strlen(conn->binddn);
> + key.data = conn->binddn;
> +
> + if (!has_suffix(, aci->subject))
> + return 0;
> + }
>   }
>  
>   if (aci->attribute != NULL) {
> Index: ldapd.conf.5
> ===
> RCS file: /cvs/src/usr.sbin/ldapd/ldapd.conf.5,v
> retrieving revision 1.27
> diff -u -p -r1.27 ldapd.conf.5
> --- ldapd.conf.5  24 Jun 2020 07:20:47 -  1.27
> +++ ldapd.conf.5  3 Oct 2021 09:22:34 -
> @@ -270,7 +270,7 @@ Finally, the filter rule can match a bin
>  The filter rule matches by any bind dn, including anonymous binds.
>  .It by Ar DN
>  The filter rule matches only if the requestor has previously performed
> -a bind as the specified distinguished name.
> +a bind as the specified distinguished name or a descendant.
>  .It by self
>  The filter rule matches only if the requestor has previously performed
>  a bind as the distinguished name that is being requested.
> 



Re: ldap search vs ldapsearch

2021-11-08 Thread Martijn van Duren
Moving to tech@

On Sat, 2021-11-06 at 03:11 -0400, Allan Streib wrote:
> On OpenBSD 7.0-release, comparing the output of OpenLDAP's
> ldapsearch(1) to ldap(1) search, the ldap(1) search output is
> missing the last attribute of each directory entry.
> 
> e.g. from a directory I am working on at work:
> 
> $ ldapsearch -LLL -x -H ldapi://%2fvar%2frun%2fldapi -b 
> dc=ise,dc=luddy,dc=indiana,dc=edu '(objectClass=organizationalUnit)'
> dn: ou=people,dc=ise,dc=luddy,dc=indiana,dc=edu
> objectClass: organizationalUnit
> ou: people
> description: ISE Systems Users
> 
> dn: ou=groups,dc=ise,dc=luddy,dc=indiana,dc=edu
> objectClass: organizationalUnit
> ou: groups
> description: ISE Systems Groups
> 
> 
> Note that these are missing the "description" attribute:
> 
> $ ldap search -H ldapi://%2fvar%2frun%2fldapi -b 
> dc=ise,dc=luddy,dc=indiana,dc=edu '(objectClass=organizationalUnit)'
> dn: ou=people,dc=ise,dc=luddy,dc=indiana,dc=edu
> objectClass: organizationalUnit
> ou: people
> 
> dn: ou=groups,dc=ise,dc=luddy,dc=indiana,dc=edu
> objectClass: organizationalUnit
> ou: groups
> 
> Allan
> 
Thanks for the detailed report.
This edgecase got overlooked when moving to a stricter ASN.1 parsing for
ober_scanf_elements, which resulted in a premature exit of the loop.
Diff below should fix it.

This diff also applies to libexec/login_ldap and usr.sbin/ypldap.

OK?

martijn@

Index: aldap.c
===
RCS file: /cvs/src/usr.bin/ldap/aldap.c,v
retrieving revision 1.9
diff -u -p -r1.9 aldap.c
--- aldap.c 24 Oct 2019 12:39:26 -  1.9
+++ aldap.c 8 Nov 2021 08:50:12 -
@@ -580,15 +580,15 @@ int
 aldap_first_attr(struct aldap_message *msg, char **outkey,
 struct aldap_stringset **outvalues)
 {
-   struct ber_element *b, *c;
+   struct ber_element *b;
char *key;
struct aldap_stringset *ret;
 
if (msg->body.search.attrs == NULL)
goto fail;
 
-   if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}e",
-   , , ) != 0)
+   if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}",
+   , ) != 0)
goto fail;
 
msg->body.search.iter = msg->body.search.attrs->be_next;
@@ -610,7 +610,7 @@ int
 aldap_next_attr(struct aldap_message *msg, char **outkey,
 struct aldap_stringset **outvalues)
 {
-   struct ber_element *a, *b;
+   struct ber_element *a;
char *key;
struct aldap_stringset *ret;
 
@@ -622,8 +622,7 @@ aldap_next_attr(struct aldap_message *ms
if (ober_get_eoc(msg->body.search.iter) == 0)
goto notfound;
 
-   if (ober_scanf_elements(msg->body.search.iter, "{s(e)}e", , , )
-   != 0)
+   if (ober_scanf_elements(msg->body.search.iter, "{s(e)}", , ) != 0)
goto fail;
 
msg->body.search.iter = msg->body.search.iter->be_next;



Re: snmpd(8): New application layer - step towards agentx support

2021-11-01 Thread Martijn van Duren
On Mon, 2021-11-01 at 18:59 +0100, Martijn van Duren wrote:
> So here's (part of) my work from h2k21.
> 
And here's the diff to make regress pass again.

Index: usr.bin/snmp/Makefile
===
RCS file: /cvs/src/regress/usr.bin/snmp/Makefile,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile
--- usr.bin/snmp/Makefile   20 Jun 2021 20:08:19 -  1.2
+++ usr.bin/snmp/Makefile   1 Nov 2021 18:05:10 -
@@ -838,8 +838,7 @@ bulkget_simple:
 REGRESS_TARGETS+=  bulkget_multi
 CLEANFILES+=   bulkget_multi.res bulkget_multi.exp
 bulkget_multi:
-   IDX=1; while [ $$IDX -le 10 ]; do ${SNMPGET} -v2c -cpublic 127.0.0.1 
sysORDescr.$$IDX; IDX=$$((IDX+1)); done > $@.exp
-   IDX=1; while [ $$IDX -le 10 ]; do ${SNMPGET} -v2c -cpublic 127.0.0.1 
sysORID.$$IDX; IDX=$$((IDX+1)); done >> $@.exp
+   IDX=1; while [ $$IDX -le 10 ]; do ${SNMPGET} -v2c -cpublic 127.0.0.1 
sysORDescr.$$IDX sysORID.$$IDX; IDX=$$((IDX+1)); done > $@.exp
${SNMPBULKGET} -v2c -cpublic 127.0.0.1 sysORDescr sysORID > $@.res
diff -up $@.exp $@.res
 
@@ -938,6 +937,7 @@ bulkwalk_skip:
 
 ### SNMP SET
 
+REGRESS_EXPECTED_FAILURES+= set_string
 REGRESS_TARGETS+=  set_string
 CLEANFILES+=   set_string.res set_string.exp
 set_string:
@@ -945,6 +945,7 @@ set_string:
${SNMPSET} -v2c -cprivate -Oqv 127.0.0.1 1.3.6.1.4.1.30155.42.3.3.0 s 
$$(cat $@.exp) > $@.res
diff -up $@.exp $@.res
 
+REGRESS_EXPECTED_FAILURES+= set_integer
 REGRESS_TARGETS+=  set_integer
 CLEANFILES+=   set_integer.res set_integer.exp
 set_integer:
@@ -952,6 +953,7 @@ set_integer:
${SNMPSET} -v2c -cprivate -Oqv 127.0.0.1 1.3.6.1.4.1.30155.42.3.4.0 i 
$$(cat $@.exp) > $@.res
diff -up $@.exp $@.res
 
+REGRESS_EXPECTED_FAILURES+= set_string_integer
 REGRESS_TARGETS+=  set_string_integer
 CLEANFILES+=   set_string_integer.res set_string_integer.exp
 set_string_integer:
Index: usr.sbin/snmpd/snmpd.sh
===
RCS file: /cvs/src/regress/usr.sbin/snmpd/snmpd.sh,v
retrieving revision 1.15
diff -u -p -r1.15 snmpd.sh
--- usr.sbin/snmpd/snmpd.sh 7 Sep 2021 10:09:28 -   1.15
+++ usr.sbin/snmpd/snmpd.sh 1 Nov 2021 18:05:10 -
@@ -151,19 +151,19 @@ fi
 
 # system.sysContact set with default rw community string
 
-puffy="pu...@openbsd.org"
-snmp_command="snmp set -c private -v 1 localhost system.sysContact.0 s $puffy"
-echo === $snmp_command
-eval $snmp_command > /dev/null 2>&1
-snmp_command="snmp get -v2c -cpublic localhost 1.3.6.1.2.1.1.4.0"
-echo === $snmp_command
-contact="$(eval $snmp_command)"
-contact="${contact##sysContact.0 = STRING: }"
-if [ "$contact" !=  "$puffy" ]
-then
-   echo "Setting with default rw community string failed."
-   FAILED=1
-fi
+#puffy="pu...@openbsd.org"
+#snmp_command="snmp set -c private -v 1 localhost system.sysContact.0 s $puffy"
+#echo === $snmp_command
+#eval $snmp_command > /dev/null 2>&1
+#snmp_command="snmp get -v2c -cpublic localhost 1.3.6.1.2.1.1.4.0"
+#echo === $snmp_command
+#contact="$(eval $snmp_command)"
+#contact="${contact##sysContact.0 = STRING: }"
+#if [ "$contact" !=  "$puffy" ]
+#then
+#  echo "Setting with default rw community string failed."
+#  FAILED=1
+#fi
 
 kill $(pgrep snmpd) >/dev/null 2>&1
 wait
@@ -296,19 +296,19 @@ fi
 
 # system.sysContact set with non-default rw/ro community strings
 
-puffy="pu...@openbsd.org"
-snmp_command="snmp set -c non-default-rw -v 1 localhost system.sysContact.0 \
-   s $puffy"
-echo === $snmp_command
-eval $snmp_command > /dev/null 2>&1
-snmp_command="snmp get -Oqv -v2c -cnon-default-ro localhost 1.3.6.1.2.1.1.4.0"
-echo === $snmp_command
-contact="$(eval $snmp_command)"
-if [ "$contact" !=  "$puffy" ]
-then
-   echo "Setting with default rw community string failed."
-   FAILED=1
-fi
+#puffy="pu...@openbsd.org"
+#snmp_command="snmp set -c non-default-rw -v 1 localhost system.sysContact.0 \
+#   s $puffy"
+#echo === $snmp_command
+#eval $snmp_command > /dev/null 2>&1
+#snmp_command="snmp get -Oqv -v2c -cnon-default-ro localhost 1.3.6.1.2.1.1.4.0"
+#echo === $snmp_command
+#contact="$(eval $snmp_command)"
+#if [ "$contact" !=  "$puffy" ]
+#then
+#  echo "Setting with default rw community string failed."
+#  FAILED=1
+#fi
 
 # custom oids, with a ro that we should not be able to set
 
@@ -332,15 +332,15 @@ then
FAILED=1
 fi
 
-snmp_command="snmp set -c non-default-rw -v 1 localhost \
-   1.3.6.1.4.1.30155.42

snmpd(8): New application layer - step towards agentx support

2021-11-01 Thread Martijn van Duren
   smi_init(void);
-u_long  smi_getticks(void);
 voidsmi_mibtree(struct oid *);
 struct oid *smi_find(struct oid *);
 struct oid *smi_nfind(struct oid *);
@@ -728,7 +707,6 @@ struct oid  *smi_next(struct oid *);
 struct oid *smi_foreach(struct oid *, u_int);
 voidsmi_oidlen(struct ber_oid *);
 voidsmi_scalar_oidlen(struct ber_oid *);
-char   *smi_oid2string(struct ber_oid *, char *, size_t, size_t);
 int smi_string2oid(const char *, struct ber_oid *);
 voidsmi_delete(struct oid *);
 int smi_insert(struct oid *);
@@ -736,7 +714,6 @@ int  smi_oid_cmp(struct oid *, struct o
 int smi_key_cmp(struct oid *, struct oid *);
 unsigned intsmi_application(struct ber_element *);
 voidsmi_debug_elements(struct ber_element *);
-char   *smi_print_element(struct ber_element *);
 
 /* timer.c */
 voidtimer_init(void);
Index: snmpe.c
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.78
diff -u -p -r1.78 snmpe.c
--- snmpe.c 21 Oct 2021 14:33:13 -  1.78
+++ snmpe.c 1 Nov 2021 17:47:16 -
@@ -37,11 +37,12 @@
 #include 
 #include 
 
+#include "application.h"
 #include "snmpd.h"
+#include "snmpe.h"
 #include "mib.h"
 
 voidsnmpe_init(struct privsep *, struct privsep_proc *, void *);
-const char *snmpe_pdutype2string(enum snmp_pdutype);
 int snmpe_parse(struct snmp_message *);
 voidsnmpe_tryparse(int, struct snmp_message *);
 int snmpe_parsevarbinds(struct snmp_message *);
@@ -53,7 +54,6 @@ void   snmpe_writecb(int fd, short, void 
 voidsnmpe_acceptcb(int fd, short, void *);
 voidsnmpe_prepare_read(struct snmp_message *, int);
 int snmpe_encode(struct snmp_message *);
-voidsnmp_msgfree(struct snmp_message *);
 
 struct imsgev  *iev_parent;
 static const struct timevalsnmpe_tcp_timeout = { 10, 0 }; /* 10s */
@@ -99,6 +99,7 @@ snmpe_init(struct privsep *ps, struct pr
kr_init();
timer_init();
usm_generate_keys();
+   appl_init();
 
/* listen for incoming SNMP UDP/TCP messages */
TAILQ_FOREACH(h, >sc_addresses, entry) {
@@ -137,6 +138,7 @@ snmpe_shutdown(void)
close(h->fd);
}
kr_shutdown();
+   appl_shutdown();
 }
 
 int
@@ -427,6 +429,11 @@ badversion:
goto fail;
}
 
+   for (a = msg->sm_varbind; a != NULL; a = a->be_next) {
+   if (ober_scanf_elements(a, "{oS$}", NULL) == -1)
+   goto parsefail;
+   }
+
msg->sm_request = req;
msg->sm_error = errval;
msg->sm_errorindex = erridx;
@@ -467,6 +474,13 @@ snmpe_parsevarbinds(struct snmp_message 
struct ber_oid   o;
int  i;
 
+   appl_processpdu(msg, msg->sm_ctxname, msg->sm_version, msg->sm_pdu);
+   return 0;
+   /*
+* Leave code here for now so it's easier to switch back in case of
+* issues.
+*/
+
msg->sm_errstr = "invalid varbind element";
 
varbind = msg->sm_varbind;
@@ -811,7 +825,26 @@ snmpe_dispatchmsg(struct snmp_message *m
/* XXX Do proper error handling */
(void) snmpe_parsevarbinds(msg);
 
+   return;
+   /*
+* Leave code here for now so it's easier to switch back in case of
+* issues.
+*/
/* respond directly */
+   msg->sm_pdutype = SNMP_C_RESPONSE;
+   snmpe_response(msg);
+}
+
+void
+snmpe_send(struct snmp_message *msg, enum snmp_pdutype type, int32_t requestid,
+int32_t error, uint32_t index, struct ber_element *varbindlist)
+{
+   msg->sm_msgid = requestid;
+   msg->sm_pdutype = type;
+   msg->sm_error = error;
+   msg->sm_errorindex = index;
+   msg->sm_varbindresp = varbindlist;
+
msg->sm_pdutype = SNMP_C_RESPONSE;
snmpe_response(msg);
 }
Index: snmpe.h
===
RCS file: snmpe.h
diff -N snmpe.h
--- /dev/null   1 Jan 1970 00:00:00 -
+++ snmpe.h 1 Nov 2021 17:47:16 -
@@ -0,0 +1,25 @@
+/* $OpenBSD$   */
+
+/*
+ * Copyright (c) 2021 Martijn van Duren 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS

Re: snmpd(8): don't allocate memory for system mib

2021-10-30 Thread Martijn van Duren
On Fri, 2021-10-29 at 04:52 -0600, Theo de Raadt wrote:
> Stuart Henderson  wrote:
> 
> > > Diff below calls uname(3) only a single time and if the variables
> > > aren't snmpd.conf I simply rebuild it every time.
> > 
> > I'm in two minds about this. While it's not something that will happen
> > very often, hostnames do get changed sometimes, and it would be nice to
> > have snmpd reflect the current name of the system rather than what it
> > was named when snmpd started.
> 
> I also disagree with this caching.  Someone should not need to restart
> the daemon if they change the hostname, that is crazy, so the daemon
> should get it continually (or at least poll once in a while to look for
> a change).
> 
> snmpd's job is to export current & correct information, not cache.

That would be the diff below. Keep in mind that there are two edge-cases
here, which will not use current information:
1) snmpd.conf(5)'s "system description" and "system name"
2) snmpd(8) allows these values to be set via a set-request. In this
   case the information doesn't change any kernel values, but does set a
   cache string.

Index: mib.c
===
RCS file: /cvs/src/usr.sbin/snmpd/mib.c,v
retrieving revision 1.102
diff -u -p -r1.102 mib.c
--- mib.c   1 Sep 2021 15:54:40 -   1.102
+++ mib.c   30 Oct 2021 16:06:59 -
@@ -126,22 +126,21 @@ mib_getsys(struct oid *oid, struct ber_o
 {
struct ber_oid   sysoid = OID(MIB_SYSOID_DEFAULT);
char*s = oid->o_data;
+   char buf[256];
struct ber_oid  *so = oid->o_data;
-   struct utsname   u;
+   struct utsname   u;
long longticks;
 
-   if (uname() == -1)
-   return (-1);
 
switch (oid->o_oid[OIDIDX_system]) {
case 1:
if (s == NULL) {
-   if (asprintf(, "%s %s %s %s %s",
-   u.sysname, u.nodename, u.release,
-   u.version, u.machine) == -1)
+   if (uname() == -1)
return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
+   snprintf(buf, sizeof(buf), "%s %s %s %s %s",
+   u.sysname, u.nodename, u.release,
+   u.version, u.machine);
+   s = buf;
}
*elm = ober_add_string(*elm, s);
break;
@@ -157,20 +156,15 @@ mib_getsys(struct oid *oid, struct ber_o
ober_set_header(*elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
break;
case 4:
-   if (s == NULL) {
-   if (asprintf(, "root@%s", u.nodename) == -1)
-   return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
-   }
+   if (s == NULL)
+   s = "";
*elm = ober_add_string(*elm, s);
break;
case 5:
if (s == NULL) {
-   if ((s = strdup(u.nodename)) == NULL)
-   return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
+   if (gethostname(buf, sizeof(buf)) == -1)
+   return -1;
+   s = buf;
}
*elm = ober_add_string(*elm, s);
break;
Index: snmpd.conf.5
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
retrieving revision 1.58
diff -u -p -r1.58 snmpd.conf.5
--- snmpd.conf.52 Sep 2021 05:41:02 -   1.58
+++ snmpd.conf.530 Oct 2021 16:06:59 -
@@ -244,9 +244,6 @@ This is the default value.
 .It Ic system contact Ar string
 Specify the name or description of the system contact, typically a
 name or an email address.
-The default value is
-.Ar root@hostname
-using the hostname of the local machine.
 .It Ic system description Ar string
 Specify a description of the local system.
 The default value is the operating system identification as printed by the




Re: snmpd(8): don't allocate memory for system mib

2021-10-27 Thread Martijn van Duren
On Wed, 2021-10-27 at 14:14 -0600, Todd C. Miller wrote:
> On Wed, 27 Oct 2021 17:14:28 +0100, Martijn van Duren wrote:
> 
> > Trying to search for memory leaks in my new snmpd code I found some
> > harmless, but annoying ones in system from SNMPv2-MIB.
> > 
> > We call uname(3) every time (even if we don't even need info from
> > that call) and ones set we save it until forever.
> > 
> > Diff below calls uname(3) only a single time and if the variables
> > aren't snmpd.conf I simply rebuild it every time.
> 
> It's possible that 256 bytes will not be sufficient.  I think you
> need to make the buffer sizeof(struct utsname) bytes.
> 
>  - todd

Maybe it's not sufficient, but:

sysDescr OBJECT-TYPE
SYNTAX  DisplayString (SIZE (0..255))
MAX-ACCESS  read-only
STATUS  current
DESCRIPTION
"A textual description of the entity.  This value should
include the full name and version identification of
the system's hardware type, software operating-system,
and networking software."
::= { system 1 }




Re: snmpd(8): don't allocate memory for system mib

2021-10-27 Thread Martijn van Duren
On Wed, 2021-10-27 at 17:37 +0100, Stuart Henderson wrote:
> On 2021/10/27 17:14, Martijn van Duren wrote:
> > Trying to search for memory leaks in my new snmpd code I found some
> > harmless, but annoying ones in system from SNMPv2-MIB.
> > 
> > We call uname(3) every time (even if we don't even need info from
> > that call) and ones set we save it until forever.
> > 
> > Diff below calls uname(3) only a single time and if the variables
> > aren't snmpd.conf I simply rebuild it every time.
> 
> I'm in two minds about this. While it's not something that will happen
> very often, hostnames do get changed sometimes, and it would be nice to
> have snmpd reflect the current name of the system rather than what it
> was named when snmpd started.

But that's the fun part, as soon as it has been requested ones it
continues to being cached anyway, so calling uname(3) every time
is completely useless.
Even better, it may result in inconsistency between objects:

test1$ snmp get -v2c -cpublic 127.0.0.1 sysdescr.0
sysDescr.0 = STRING: OpenBSD test1 7.0 GENERIC.MP#42 amd64
test1$ doas hostname test2
test2$ snmp get -v2c -cpublic 127.0.0.1 sysname.0 
sysName.0 = STRING: test2
test2$ snmp get -v2c -cpublic 127.0.0.1 sysdescr.0
sysDescr.0 = STRING: OpenBSD test1 7.0 GENERIC.MP#42 amd64

We can go for what you're describing, but I'm not sure it's
worth it. Whatever you think is best :-)

> 
> > I also changed the default "system contact" to an empty string,
> > since SNMPv2-MIB states:
> > "If no contact information is known, the value is the zero-length
> > string."
> > I've basically never came across a system where there was both
> > a smtp process accepting remote mail for the root-account and
> > where the hostname were correctly resolving. If people are really
> > attached to this value it's easy enough to set it, but I think
> > it would be better to not tell unfounded assertions.
> 
> I'm certainly OK with that part.
> 
> > OK?
> > 
> > martijn@
> > 
> > Index: mib.c
> > ===
> > RCS file: /cvs/src/usr.sbin/snmpd/mib.c,v
> > retrieving revision 1.102
> > diff -u -p -r1.102 mib.c
> > --- mib.c   1 Sep 2021 15:54:40 -   1.102
> > +++ mib.c   27 Oct 2021 16:14:15 -
> > @@ -126,22 +126,25 @@ mib_getsys(struct oid *oid, struct ber_o
> >  {
> > struct ber_oid   sysoid = OID(MIB_SYSOID_DEFAULT);
> > char*s = oid->o_data;
> > +   char buf[256];
> > struct ber_oid  *so = oid->o_data;
> > -   struct utsname   u;
> > +   static struct utsnameu;
> > +   int  init = 0;
> > long longticks;
> >  
> > -   if (uname() == -1)
> > -   return (-1);
> > +   if (!init) {
> > +   if (uname() == -1)
> > +   return (-1);
> > +   init = 1;
> > +   }
> >  
> > switch (oid->o_oid[OIDIDX_system]) {
> > case 1:
> > if (s == NULL) {
> > -   if (asprintf(, "%s %s %s %s %s",
> > +   snprintf(buf, sizeof(buf), "%s %s %s %s %s",
> > u.sysname, u.nodename, u.release,
> > -   u.version, u.machine) == -1)
> > -   return (-1);
> > -   oid->o_data = s;
> > -   oid->o_val = strlen(s);
> > +   u.version, u.machine);
> > +   s = buf;
> > }
> > *elm = ober_add_string(*elm, s);
> > break;
> > @@ -157,21 +160,13 @@ mib_getsys(struct oid *oid, struct ber_o
> > ober_set_header(*elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
> > break;
> > case 4:
> > -   if (s == NULL) {
> > -   if (asprintf(, "root@%s", u.nodename) == -1)
> > -   return (-1);
> > -   oid->o_data = s;
> > -   oid->o_val = strlen(s);
> > -   }
> > +   if (s == NULL)
> > +   s = "";
> > *elm = ober_add_string(*elm, s);
> > break;
> > case 5:
> > -   if (s == NULL) {
> > -   if ((s = strdup(u.nodename)) == NULL)
> > -   return (-1);
> > -   oid->o_data = s;
> > -   oid->o_val = strl

snmpd(8): don't allocate memory for system mib

2021-10-27 Thread Martijn van Duren
Trying to search for memory leaks in my new snmpd code I found some
harmless, but annoying ones in system from SNMPv2-MIB.

We call uname(3) every time (even if we don't even need info from
that call) and ones set we save it until forever.

Diff below calls uname(3) only a single time and if the variables
aren't snmpd.conf I simply rebuild it every time.

I also changed the default "system contact" to an empty string,
since SNMPv2-MIB states:
"If no contact information is known, the value is the zero-length
string."
I've basically never came across a system where there was both
a smtp process accepting remote mail for the root-account and
where the hostname were correctly resolving. If people are really
attached to this value it's easy enough to set it, but I think
it would be better to not tell unfounded assertions.

OK?

martijn@

Index: mib.c
===
RCS file: /cvs/src/usr.sbin/snmpd/mib.c,v
retrieving revision 1.102
diff -u -p -r1.102 mib.c
--- mib.c   1 Sep 2021 15:54:40 -   1.102
+++ mib.c   27 Oct 2021 16:14:15 -
@@ -126,22 +126,25 @@ mib_getsys(struct oid *oid, struct ber_o
 {
struct ber_oid   sysoid = OID(MIB_SYSOID_DEFAULT);
char*s = oid->o_data;
+   char buf[256];
struct ber_oid  *so = oid->o_data;
-   struct utsname   u;
+   static struct utsnameu;
+   int  init = 0;
long longticks;
 
-   if (uname() == -1)
-   return (-1);
+   if (!init) {
+   if (uname() == -1)
+   return (-1);
+   init = 1;
+   }
 
switch (oid->o_oid[OIDIDX_system]) {
case 1:
if (s == NULL) {
-   if (asprintf(, "%s %s %s %s %s",
+   snprintf(buf, sizeof(buf), "%s %s %s %s %s",
u.sysname, u.nodename, u.release,
-   u.version, u.machine) == -1)
-   return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
+   u.version, u.machine);
+   s = buf;
}
*elm = ober_add_string(*elm, s);
break;
@@ -157,21 +160,13 @@ mib_getsys(struct oid *oid, struct ber_o
ober_set_header(*elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
break;
case 4:
-   if (s == NULL) {
-   if (asprintf(, "root@%s", u.nodename) == -1)
-   return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
-   }
+   if (s == NULL)
+   s = "";
*elm = ober_add_string(*elm, s);
break;
case 5:
-   if (s == NULL) {
-   if ((s = strdup(u.nodename)) == NULL)
-   return (-1);
-   oid->o_data = s;
-   oid->o_val = strlen(s);
-   }
+   if (s == NULL)
+   s = u.nodename;
*elm = ober_add_string(*elm, s);
break;
case 6:
Index: snmpd.conf.5
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
retrieving revision 1.58
diff -u -p -r1.58 snmpd.conf.5
--- snmpd.conf.52 Sep 2021 05:41:02 -   1.58
+++ snmpd.conf.527 Oct 2021 16:14:15 -
@@ -244,9 +244,6 @@ This is the default value.
 .It Ic system contact Ar string
 Specify the name or description of the system contact, typically a
 name or an email address.
-The default value is
-.Ar root@hostname
-using the hostname of the local machine.
 .It Ic system description Ar string
 Specify a description of the local system.
 The default value is the operating system identification as printed by the




libutil/ber: Bump BER_MAX_OID_LEN one last time

2021-10-26 Thread Martijn van Duren
Last time when this value was bumped because I ran into SNMP problems
walking net-snmp because of string based indices in USM.
This time I want to bump them one more time because I found the
definition of the upper bound RFC 2578 section 7.1.3. This makes it
easier to parse agentx messages, which also have their upper bound
on 128.

I see no risk of fallout, since the previous bump only broke agentx
support in snmpd, which has since been removed. Nothing in ports is
using this code as far I know.

Memory footprint of snmpd only increases by a few 100KB, claudio@
only found on stack use of ber_oid in ldapd, so memory impact is
manageable.

Already discussed with claudio@
Iff OK tb@ promised to commit it at the same time as the libcrypto
bump to keep churn to a minimum.

OK?

martijn@

Index: ber.h
===
RCS file: /cvs/src/lib/libutil/ber.h,v
retrieving revision 1.4
diff -u -p -r1.4 ber.h
--- ber.h   29 Aug 2021 13:27:11 -  1.4
+++ ber.h   26 Oct 2021 10:14:26 -
@@ -80,8 +80,8 @@ struct ber {
 #define BER_CLASS_MASK 0x3
 
 /* common definitions */
-#define BER_MIN_OID_LEN2   /* OBJECT */
-#define BER_MAX_OID_LEN64  /* OBJECT */
+#define BER_MIN_OID_LEN2   /* X.690 section 8.19.5 
*/
+#define BER_MAX_OID_LEN128 /* RFC 2578 section 
7.1.3 */
 #define BER_MAX_SEQ_ELEMENTS   USHRT_MAX   /* 65535 */
 
 struct ber_oid {
Index: shlib_version
===
RCS file: /cvs/src/lib/libutil/shlib_version,v
retrieving revision 1.33
diff -u -p -r1.33 shlib_version
--- shlib_version   29 Aug 2021 13:27:11 -  1.33
+++ shlib_version   26 Oct 2021 10:14:26 -
@@ -1,2 +1,2 @@
-major=15
-minor=1
+major=16
+minor=0




Re: snmpd trap community problem

2021-10-25 Thread Martijn van Duren
Thanks for the detailed analysis.

diff below should fix it.

martijn@

On Sun, 2021-10-24 at 22:44 +0100, Stuart Henderson wrote:
> ooops, sorry not trondd, it was jhuldtgren who spotted it!
> 
> On 2021/10/24 22:26, Stuart Henderson wrote:
> > trondd noticed a startup problem with snmpd on mips64 but didn't see
> > them on amd64 and wondered if it was arch-specific, I had a go at
> > reproducing and see it very often on aarch64 and also sometimes on
> > amd64.
> > 
> > Any setting of "trap receiver $ip snmpv2c community $community"
> > triggers the problem:
> > 
> > # for i in `jot 20`; do snmpd -nvf /etc/snmpd.conf; done
> > trap receiver: missing community
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > trap receiver: missing community
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > configuration ok
> > trap receiver: missing community
> > 
> > Additionally even when configuration is accepted, the community is set
> > to junk
> > 
> >  822 tr->ta_oid = $2;
> >  823 tr->ta_version = $3.type;
> > 
> > with snmpv2c ta_version is set to 1
> > 
> >  824 if ($3.type == ADDRESS_FLAG_SNMPV2) {
> > 
> > so this branch isn't taken
> > 
> >  825 (void)strlcpy(tr->ta_community, 
> > $3.data,
> >  826 sizeof(tr->ta_community));
> >  827 free($3.data);
> >  828 } else {
> >  829 tr->ta_usmusername = $3.data;
> >  830 tr->ta_seclevel = $3.value;
> >  831 }
> > 
> > at this point ta_usmusername is set to the community and ta_community
> > is junk.
> > 
> > 810 if ($4 != NULL) {
> > (gdb) 
> > 823 tr->ta_version = $3.type;
> > (gdb) 
> > 824 if ($3.type == ADDRESS_FLAG_SNMPV2) {
> > (gdb) p *tr
> > $3 = {ta_ss = {ss_len = 16 '\020', ss_family = 2 '\002', __ss_pad1 = 
> > "\000\242\303_\273T", __ss_pad2 = 0, 
> > __ss_pad3 = "\002\000\000\000\001\000\000\000\001\000\000\000\a", 
> > '\000' }, ta_sslocal = {
> > ss_len = 0 '\000', ss_family = 0 '\000', __ss_pad1 = 
> > "\000\000\000\000\000", __ss_pad2 = 0, 
> > __ss_pad3 = '\000' }, ta_version = 1, {ta_community 
> > = '\000' , {
> >   ta_usmusername = 0x0, ta_usmuser = 0x0, ta_seclevel = 0}}, ta_oid = 
> > 0x0, entry = {tqe_next = 0x0, 
> > tqe_prev = 0x0}}
> > (gdb) n
> > 829 tr->ta_usmusername = $3.data;
> > (gdb) 
> > 830 tr->ta_seclevel = $3.value;
> > (gdb) 
> > 832 TAILQ_INSERT_TAIL(&(conf->sc_trapreceivers), 
> > tr, entry);
> > (gdb) p *tr
> > $4 = {ta_ss = {ss_len = 16 '\020', ss_family = 2 '\002', __ss_pad1 = 
> > "\000\242\303_\273T", __ss_pad2 = 0, 
> > __ss_pad3 = "\002\000\000\000\001\000\000\000\001\000\000\000\a", 
> > '\000' }, ta_sslocal = {
> > ss_len = 0 '\000', ss_family = 0 '\000', __ss_pad1 = 
> > "\000\000\000\000\000", __ss_pad2 = 0, 
> > __ss_pad3 = '\000' }, ta_version = 1, {
> > ta_community = "\340\035a\250O\005", '\000' , {
> >   ta_usmusername = 0x54fa8611de0 "zz", ta_usmuser = 
> > 0x0, ta_seclevel = 0}}, ta_oid = 0x0, 
> >   entry = {tqe_next = 0x0, tqe_prev = 0x0}}
> > 
> > 
> > 

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.71
diff -u -p -r1.71 parse.y
--- parse.y 20 Oct 2021 16:00:47 -  1.71
+++ parse.y 25 Oct 2021 09:09:14 -
@@ -821,7 +821,7 @@ hostdef : STRING hostoid hostauth srcad
}
tr->ta_oid = $2;
tr->ta_version = $3.type;
-   if ($3.type == ADDRESS_FLAG_SNMPV2) {
+   if ($3.type == SNMP_V2) {
(void)strlcpy(tr->ta_community, $3.data,
sizeof(tr->ta_community));
free($3.data);




libagentx: Don't allow OIDs < 2

2021-10-24 Thread Martijn van Duren
libagentx currently allows OIDs with a length of 0.
This isn't wrong from an agentx protocol point of view, but ber encoding
can't handle OIDs with less then 2 elements, which makes it unable to
map the values back to SNMP. netsnmp maps a null-oid to 0.0, but I don't
think we should do that.

This diff also adds the check to a couple of other places where there
was no active length checking prior. This is not an issue with current
code using it (relayd(8)), because all OIDs are static, so are not
susceptible for manipulation.

regress still passes.

OK?

Index: agentx.h
===
RCS file: /cvs/src/lib/libagentx/agentx.h,v
retrieving revision 1.5
diff -u -p -r1.5 agentx.h
--- agentx.h27 Oct 2020 18:24:01 -  1.5
+++ agentx.h24 Oct 2021 17:39:16 -
@@ -36,6 +36,7 @@ enum agentx_request_type {
 };
 
 #define AGENTX_MASTER_PATH "/var/agentx/master"
+#define AGENTX_OID_MIN_LEN 2
 #define AGENTX_OID_MAX_LEN 128
 #define AGENTX_OID_INDEX_MAX_LEN 10
 #define AGENTX_MIB2 1, 3, 6, 1, 2, 1
Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.13
diff -u -p -r1.13 agentx.c
--- agentx.c23 Oct 2021 17:13:50 -  1.13
+++ agentx.c24 Oct 2021 17:39:17 -
@@ -189,6 +189,8 @@ static int agentx_request(struct agentx 
 static int agentx_request_cmp(struct agentx_request *,
 struct agentx_request *);
 static int agentx_strcat(char **, const char *);
+static int agentx_oidfill(struct ax_oid *, const uint32_t[], size_t,
+const char **);
 
 RB_PROTOTYPE_STATIC(ax_requests, agentx_request, axr_ax_requests,
 agentx_request_cmp)
@@ -362,25 +364,26 @@ agentx_session(struct agentx *ax, uint32
 size_t oidlen, const char *descr, uint8_t timeout)
 {
struct agentx_session *axs;
-   size_t i;
+   const char *errstr;
 
-   if (oidlen > AGENTX_OID_MAX_LEN) {
-#ifdef AX_DEBUG
-   agentx_log_ax_fatalx(ax, "%s: oidlen > %d", __func__,
-   AGENTX_OID_MAX_LEN);
-#else
-   errno = EINVAL;
-   return NULL;
-#endif
-   }
if ((axs = calloc(1, sizeof(*axs))) == NULL)
return NULL;
 
axs->axs_ax = ax;
axs->axs_timeout = timeout;
-   for (i = 0; i < oidlen; i++)
-   axs->axs_oid.aoi_id[i] = oid[i];
-   axs->axs_oid.aoi_idlen = oidlen;
+   /* RFC 2741 section 6.2.1: may send a null Object Identifier */
+   if (oidlen == 0)
+   axs->axs_oid.aoi_idlen = oidlen;
+   else {
+   if (agentx_oidfill((>axs_oid), oid, oidlen,
+   ) == -1) {
+#ifdef AX_DEBUG
+   agentx_log_ax_fatalx(ax, "%s: %s", __func__, errstr);
+#else
+   return NULL;
+#endif
+   }
+   }
axs->axs_descr.aos_string = (unsigned char *)strdup(descr);
if (axs->axs_descr.aos_string == NULL) {
free(axs);
@@ -670,11 +673,21 @@ agentx_context_object_find(struct agentx
 const uint32_t oid[], size_t oidlen, int active, int instance)
 {
struct agentx_object *axo, axo_search;
-   size_t i;
+   const char *errstr;
 
-   for (i = 0; i < oidlen; i++)
-   axo_search.axo_oid.aoi_id[i] = oid[i];
-   axo_search.axo_oid.aoi_idlen = oidlen;
+   if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, ) == -1) {
+   if (oidlen > AGENTX_OID_MIN_LEN) {
+#ifdef AX_DEBUG
+   agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
+#else
+   agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
+   return NULL;
+   }
+#endif
+   if (oidlen == 1)
+   axo_search.axo_oid.aoi_id[0] = oid[0];
+   axo_search.axo_oid.aoi_idlen = oidlen;
+   }
 
axo = RB_FIND(axc_objects, &(axc->axc_objects), _search);
while (axo == NULL && !instance && axo_search.axo_oid.aoi_idlen > 0) {
@@ -691,11 +704,21 @@ agentx_context_object_nfind(struct agent
 const uint32_t oid[], size_t oidlen, int active, int inclusive)
 {
struct agentx_object *axo, axo_search;
-   size_t i;
+   const char *errstr;
 
-   for (i = 0; i < oidlen; i++)
-   axo_search.axo_oid.aoi_id[i] = oid[i];
-   axo_search.axo_oid.aoi_idlen = oidlen;
+   if (agentx_oidfill(&(axo_search.axo_oid), oid, oidlen, ) == -1) {
+   if (oidlen > AGENTX_OID_MIN_LEN) {
+#ifdef AX_DEBUG
+   agentx_log_axc_fatalx(axc, "%s: %s", __func__, errstr);
+#else
+   agentx_log_axc_warnx(axc, "%s: %s", __func__, errstr);
+   return NULL;
+#endif
+   }
+   if (oidlen == 1)
+   axo_search.axo_oid.aoi_id[0] = oid[0];
+   axo_search.axo_oid.aoi_idlen = oidlen;
+   }
 
axo 

libagentx: always initialize buf in ax_oidrange2string

2021-10-24 Thread Martijn van Duren
This diff should be superfluous with the next diff, but I don't think
this should be left as is anyway.

It's not a big problem, since it's a static buffer and it gets
initialized by previous calls, so it's always NUL-terminated, but
it's not accurate.

OK?

martijn@

Index: ax.c
===
RCS file: /cvs/src/lib/libagentx/ax.c,v
retrieving revision 1.7
diff -u -p -r1.7 ax.c
--- ax.c2 Jan 2021 01:06:31 -   1.7
+++ ax.c24 Oct 2021 17:31:03 -
@@ -764,6 +764,8 @@ ax_oidrange2string(struct ax_oid *oid, u
 
rest = sizeof(buf);
p = buf;
+   if (oid->aoi_idlen == 0)
+   (void)strlcpy(buf, "null", sizeof(buf));
for (i = 0; i < oid->aoi_idlen; i++) {
if (range_subid != 0 && range_subid - 1 == (uint8_t)i)
ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i],




snmp{,d}: Clean up non-SNMP encodings

2021-10-23 Thread Martijn van Duren
RFC2578 section 7.1.1:
   The INTEGER type (but not the Integer32 type) may also be used to
   represent integer-valued information as named-number enumerations.
RFC3416 section 2.5:
  A BITS value is encoded as an OCTET STRING

So these two can go.

There's still plenty opportunity for cleanup here, but that's for
another time.

OK?

martijn@

Index: usr.bin/snmp/smi.c
===
RCS file: /cvs/src/usr.bin/snmp/smi.c,v
retrieving revision 1.15
diff -u -p -r1.15 smi.c
--- usr.bin/snmp/smi.c  21 Oct 2021 08:17:34 -  1.15
+++ usr.bin/snmp/smi.c  23 Oct 2021 20:25:37 -
@@ -247,7 +247,7 @@ smi_print_element(struct ber_oid *oid, s
struct oid   okey;
struct oid  *object = NULL;
struct textconv  tckey;
-   size_t   len, i, slen;
+   size_t   len, i;
long longv, ticks;
int  is_hex = 0, ret;
struct ber_oid   o;
@@ -271,7 +271,6 @@ smi_print_element(struct ber_oid *oid, s
 
switch (root->be_encoding) {
case BER_TYPE_INTEGER:
-   case BER_TYPE_ENUMERATED:
if (ober_get_integer(root, ) == -1)
goto fail;
if (root->be_class == BER_CLASS_APPLICATION &&
@@ -344,22 +343,6 @@ smi_print_element(struct ber_oid *oid, s
}
if (asprintf(, "%s%lld", print_hint ? hint : "", v) == -1)
goto fail;
-   break;
-   case BER_TYPE_BITSTRING:
-   if (ober_get_bitstring(root, (void *), ) == -1)
-   goto fail;
-   slen = len * 2 + 1 + sizeof("BITS: ");
-   if ((str = calloc(1, slen)) == NULL)
-   goto fail;
-   p = str;
-   if (print_hint) {
-   strlcpy(str, "BITS: ", slen);
-   p += sizeof("BITS: ");
-   }
-   for (i = 0; i < len; i++) {
-   snprintf(p, 3, "%02x", buf[i]);
-   p += 2;
-   }
break;
case BER_TYPE_OBJECT:
if (ober_get_oid(root, ) == -1)
Index: usr.sbin/snmpd/smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.30
diff -u -p -r1.30 smi.c
--- usr.sbin/snmpd/smi.c21 Oct 2021 15:08:15 -  1.30
+++ usr.sbin/snmpd/smi.c23 Oct 2021 20:25:37 -
@@ -472,21 +472,10 @@ smi_print_element(struct ber_element *ro
 
switch (root->be_encoding) {
case BER_TYPE_INTEGER:
-   case BER_TYPE_ENUMERATED:
if (ober_get_integer(root, ) == -1)
goto fail;
if (asprintf(, "%lld", v) == -1)
goto fail;
-   break;
-   case BER_TYPE_BITSTRING:
-   if (ober_get_bitstring(root, (void *), ) == -1)
-   goto fail;
-   if ((str = calloc(1, len * 2 + 1)) == NULL)
-   goto fail;
-   for (p = str, i = 0; i < len; i++) {
-   snprintf(p, 3, "%02x", buf[i]);
-   p += 2;
-   }
break;
case BER_TYPE_OBJECT:
if (ober_get_oid(root, ) == -1)




tcpdump: print-snmp.c recognize notfound conditions

2021-10-23 Thread Martijn van Duren
Right now tcpdump prints noSuchObject/noSuchInstance/endOfMibView as
[P/x/GetRequest]/[P/x/GetNextRequest]/[P/x/GetResponse]. This is because
tcpdump doesn't treat CONTEXT for what it is: context dependent.

I'm not going to untangle this entire mess, but this diff at least gives
us a better output:
martijn$ doas tcpdump -s1500 -ilo0 port snmp  
tcpdump: listening on lo0, link-type LOOP
11:33:04.381363 localhost.40238 > localhost.snmp: GetRequest(27) 
system.sysContact
11:33:04.381476 localhost.snmp > localhost.40238: GetResponse(27) 
system.sysContact=[P/x/GetRequest]
11:33:06.564163 localhost.5317 > localhost.snmp: GetRequest(29) 
system.sysContact.0.1
11:33:06.564278 localhost.snmp > localhost.5317: GetResponse(29) 
system.sysContact.0.1=[P/x/GetNextRequest]
^C
4 packets received by filter
0 packets dropped by kernel
martijn$ make -j4 && doas ./obj/tcpdump -s1500 -ilo0 port snmp
tcpdump: listening on lo0, link-type LOOP
11:33:11.814521 localhost.19859 > localhost.snmp: GetRequest(27) 
system.sysContact
11:33:11.814655 localhost.snmp > localhost.19859: GetResponse(27) 
system.sysContact=noSuchObject
11:33:12.346477 localhost.2383 > localhost.snmp: GetRequest(29) 
system.sysContact.0.1
11:33:12.346584 localhost.snmp > localhost.2383: GetResponse(29) 
system.sysContact.0.1=noSuchInstance

OK?

martijn@

Index: print-snmp.c
===
RCS file: /cvs/src/usr.sbin/tcpdump/print-snmp.c,v
retrieving revision 1.26
diff -u -p -r1.26 print-snmp.c
--- print-snmp.c23 Oct 2021 09:42:14 -  1.26
+++ print-snmp.c23 Oct 2021 10:35:15 -
@@ -134,6 +134,15 @@ char *Context[] = {
 #define REPORT 8
 };
 
+char *ContextVarbind[] = {
+   "noSuchObject",
+#define NOSUCHOBJECT 0
+   "noSuchInstance",
+#define NOSUCHINSTANCE 1
+   "endOfMibView"
+#define ENDOFMIBVIEW 2
+};
+
 /*
  * Private ASN.1 types
  * The Internet SMI does not specify any
@@ -196,7 +205,7 @@ char *GenericTrap[] = {
 struct {
char*name;
char**Id;
-   int numIDs;
+   int numIDs;
 } Class[] = {
defineCLASS(Universal),
 #defineUNIVERSAL   0
@@ -315,6 +324,7 @@ struct be {
 #define BE_INETADDR8
 #define BE_PDU 9
 #define BE_UNS64   10
+#define BE_VB  11
 };
 
 
@@ -576,6 +586,22 @@ asn1_parse(const u_char *p, u_int len, s
}
break;
 
+   case CONTEXT:
+   switch (id) {
+   case NOSUCHOBJECT:
+   case NOSUCHINSTANCE:
+   case ENDOFMIBVIEW:
+   elem->type = BE_VB;
+   elem->data.raw = NULL;
+   break;
+   default:
+   elem->type = BE_OCTET;
+   elem->data.raw = (caddr_t)p;
+   printf("[P/C/%d]", id);
+   break;
+   }
+   break;
+
default:
elem->type = BE_OCTET;
elem->data.raw = (caddr_t)p;
@@ -723,6 +749,11 @@ asn1_print(struct be *elem)
case BE_PDU:
printf("%s(%u)",
Class[CONTEXT].Id[elem->id], elem->asnlen);
+   break;
+   case BE_VB:
+   if (elem->id > sizeof(ContextVarbind)/sizeof(ContextVarbind[0]))
+   break;
+   printf("%s", ContextVarbind[elem->id]);
break;
case BE_ANY:
printf("[BE_ANY!?]");




tcpdump: print-snmp.c don't treat "public" as default community

2021-10-23 Thread Martijn van Duren
We moved away from the idea of default community in all of our snmp
tools. Let's give tcpdump the same treatment so that people don't
get the wrong idea.

OK?

martijn@

Index: print-snmp.c
===
RCS file: /cvs/src/usr.sbin/tcpdump/print-snmp.c,v
retrieving revision 1.25
diff -u -p -r1.25 print-snmp.c
--- print-snmp.c24 Jan 2020 22:46:37 -  1.25
+++ print-snmp.c23 Oct 2021 09:54:05 -
@@ -342,11 +342,6 @@ struct snmp3_sm {
 };

 /*
- * Defaults for SNMP PDU components
- */
-#define DEF_COMMUNITY "public"
-
-/*
  * constants for ASN.1 decoding
  */
 #define OIDMUX 40
@@ -1059,11 +1054,7 @@ snmp12_print(const u_char *np, u_int len
asn1_print();
return;
}
-   /* default community */
-   if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
-   sizeof(DEF_COMMUNITY) - 1))
-   /* ! "public" */
-   printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
+   printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
length -= count;
np += count;
 




tcpdump: print-snmp.c document some ancient history

2021-10-23 Thread Martijn van Duren
Thanks to benno who found the original reference to this value.
Help out some poor soul who might wander in here in the future.

OK?

martijn@

Index: print-snmp.c
===
RCS file: /cvs/src/usr.sbin/tcpdump/print-snmp.c,v
retrieving revision 1.25
diff -u -p -r1.25 print-snmp.c
--- print-snmp.c24 Jan 2020 22:46:37 -  1.25
+++ print-snmp.c23 Oct 2021 09:26:44 -
@@ -106,6 +106,7 @@ char *Application[] = {
 #define NSAPADDR 5
"Counter64",
 #define COUNTER64 6
+/* Defined in RFC1442, removed since RFC1902 */
"UInteger32"
 #define UINTEGER32 7
 };




Re: snmpd: s/SNMP_C_GETRESP/SNMP_C_RESPONSE

2021-10-21 Thread Martijn van Duren
On Thu, 2021-10-21 at 15:22 +0100, Stuart Henderson wrote:
> On 2021/10/21 15:08, Martijn van Duren wrote:
> > This one has been bothering me for a while.
> > 
> > OK?
> > 
> > martijn@
> > 
> > Index: smi.c
> > ===
> > RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
> > retrieving revision 1.28
> > diff -u -p -r1.28 smi.c
> > --- smi.c   4 Jan 2021 07:59:54 -   1.28
> > +++ smi.c   21 Oct 2021 14:06:40 -
> > @@ -377,7 +377,7 @@ smi_debug_elements(struct ber_element *r
> > case SNMP_C_GETNEXTREQ:
> > fprintf(stderr, "nextreq");
> > break;
> > -   case SNMP_C_GETRESP:
> > +   case SNMP_C_RESPONSE:
> > fprintf(stderr, "getresp");
> 
> ok.
> 
> maybe s/getresp/response in the fprintf above too?
> 
Sure, but let's clean up nextreq while we're here.

> 
Index: smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.29
diff -u -p -r1.29 smi.c
--- smi.c   21 Oct 2021 14:33:13 -  1.29
+++ smi.c   21 Oct 2021 14:34:49 -
@@ -375,10 +375,10 @@ smi_debug_elements(struct ber_element *r
fprintf(stderr, "getreq");
break;
case SNMP_C_GETNEXTREQ:
-   fprintf(stderr, "nextreq");
+   fprintf(stderr, "getnextreq");
break;
case SNMP_C_RESPONSE:
-   fprintf(stderr, "getresp");
+   fprintf(stderr, "response");
break;
case SNMP_C_SETREQ:
fprintf(stderr, "setreq");




snmpd: s/SNMP_C_GETRESP/SNMP_C_RESPONSE

2021-10-21 Thread Martijn van Duren
This one has been bothering me for a while.

OK?

martijn@

Index: smi.c
===
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.28
diff -u -p -r1.28 smi.c
--- smi.c   4 Jan 2021 07:59:54 -   1.28
+++ smi.c   21 Oct 2021 14:06:40 -
@@ -377,7 +377,7 @@ smi_debug_elements(struct ber_element *r
case SNMP_C_GETNEXTREQ:
fprintf(stderr, "nextreq");
break;
-   case SNMP_C_GETRESP:
+   case SNMP_C_RESPONSE:
fprintf(stderr, "getresp");
break;
case SNMP_C_SETREQ:
Index: snmp.h
===
RCS file: /cvs/src/usr.sbin/snmpd/snmp.h,v
retrieving revision 1.17
diff -u -p -r1.17 snmp.h
--- snmp.h  20 May 2021 08:53:12 -  1.17
+++ snmp.h  21 Oct 2021 14:06:40 -
@@ -80,7 +80,7 @@ enum snmp_version {
 enum snmp_pdutype {
SNMP_C_GETREQ   = 0,
SNMP_C_GETNEXTREQ   = 1,
-   SNMP_C_GETRESP  = 2,
+   SNMP_C_RESPONSE = 2,
SNMP_C_SETREQ   = 3,
SNMP_C_TRAP = 4,
 
Index: snmpe.c
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.77
diff -u -p -r1.77 snmpe.c
--- snmpe.c 21 Oct 2021 08:21:43 -  1.77
+++ snmpe.c 21 Oct 2021 14:06:40 -
@@ -207,7 +207,7 @@ snmpe_pdutype2string(enum snmp_pdutype p
return "GetRequest";
case SNMP_C_GETNEXTREQ:
return "GetNextRequest";
-   case SNMP_C_GETRESP:
+   case SNMP_C_RESPONSE:
return "Response";
case SNMP_C_SETREQ:
return "SetRequest";
@@ -373,7 +373,7 @@ badversion:
}
break;
 
-   case SNMP_C_GETRESP:
+   case SNMP_C_RESPONSE:
stats->snmp_ingetresponses++;
msg->sm_errstr = "response without request";
goto parsefail;
@@ -812,7 +812,7 @@ snmpe_dispatchmsg(struct snmp_message *m
(void) snmpe_parsevarbinds(msg);
 
/* respond directly */
-   msg->sm_pdutype = SNMP_C_GETRESP;
+   msg->sm_pdutype = SNMP_C_RESPONSE;
snmpe_response(msg);
 }
 




Re: libagentx: Fix thumbling after free

2021-10-21 Thread Martijn van Duren
ping

On Wed, 2021-09-01 at 22:51 +0200, Martijn van Duren wrote:
> Bluhm asked me to rethink the freeing strategy.
> Here's the end result.
> 
> On Mon, 2021-08-30 at 12:03 +0200, Martijn van Duren wrote:
> > I missed this one before, since apparently it doesn't show up with
> > MALLOC_OPTIONS set to "S", but it does if it is empty.
> > 
> > This probably effects relayd if the admin has it enabled en then
> > disables it via a "relayctl reload". However, I'm not able to
> > reproduce it there and even if it can be triggered, chances of
> > that happening in real life are slim to none.
> > 
> > I think the comment should explain enough.
> > 
> > OK?
> > 
> > martijn@
> 
> Index: agentx.c
> ===
> RCS file: /cvs/src/lib/libagentx/agentx.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 agentx.c
> --- agentx.c  2 Jun 2021 08:40:09 -   1.10
> +++ agentx.c  1 Sep 2021 20:51:09 -
> @@ -270,10 +270,12 @@ agentx_reset(struct agentx *ax)
>   struct agentx_session *axs, *tsas;
>   struct agentx_request *axr;
>   struct agentx_get *axg;
> + int axfree = ax->ax_free;
>  
>   ax_free(ax->ax_ax);
>   ax->ax_ax = NULL;
>   ax->ax_fd = -1;
> + ax->ax_free = 1;
>  
>   ax->ax_cstate = AX_CSTATE_CLOSE;
>  
> @@ -289,52 +291,52 @@ agentx_reset(struct agentx *ax)
>   TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
>   }
>  
> - if (ax->ax_dstate == AX_DSTATE_CLOSE) {
> - agentx_free_finalize(ax);
> - return;
> - }
> + if (ax->ax_dstate == AX_DSTATE_OPEN)
> + agentx_start(ax);
>  
> - agentx_start(ax);
> + if (!axfree)
> + agentx_free_finalize(ax);
>  }
>  
>  void
>  agentx_free(struct agentx *ax)
>  {
>   struct agentx_session *axs, *tsas;
> + int axfree;
>  
>   if (ax == NULL)
>   return;
>  
> - if (ax->ax_dstate == AX_DSTATE_CLOSE) {
> -/* Malloc throws abort on invalid pointers as well */
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> + /* Malloc throws abort on invalid pointers as well */
> + if (ax->ax_dstate == AX_DSTATE_CLOSE)
>   agentx_log_ax_fatalx(ax, "%s: double free", __func__);
> - }
>   ax->ax_dstate = AX_DSTATE_CLOSE;
>  
> - if (!TAILQ_EMPTY(&(ax->ax_sessions))) {
> - TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions,
> - tsas) {
> - if (axs->axs_dstate != AX_DSTATE_CLOSE)
> - agentx_session_free(axs);
> - }
> - } else
> + TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, tsas) {
> + if (axs->axs_dstate != AX_DSTATE_CLOSE)
> + agentx_session_free(axs);
> + }
> + if (!axfree)
>   agentx_free_finalize(ax);
>  }
>  
>  static void
>  agentx_free_finalize(struct agentx *ax)
>  {
> -#ifdef AX_DEBUG
> - if (ax->ax_dstate != AX_DSTATE_CLOSE)
> - agentx_log_ax_fatalx(ax, "%s: agentx not closing",
> - __func__);
> - if (!TAILQ_EMPTY(&(ax->ax_sessions)))
> - agentx_log_ax_fatalx(ax, "%s: agentx still has sessions",
> - __func__);
> - if (!RB_EMPTY(&(ax->ax_requests)))
> - agentx_log_ax_fatalx(ax,
> - "%s: agentx still has pending requests", __func__);
> -#endif
> + struct agentx_session *axs, *taxs;
> +
> + ax->ax_free = 0;
> +
> + TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
> + agentx_session_free_finalize(axs);
> +
> + if (!TAILQ_EMPTY(&(ax->ax_sessions)) ||
> + !RB_EMPTY(&(ax->ax_requests)) ||
> + ax->ax_dstate != AX_DSTATE_CLOSE)
> + return;
>  
>   ax_free(ax->ax_ax);
>   ax->ax_nofd(ax, ax->ax_cookie, 1);
> @@ -477,6 +479,7 @@ agentx_session_close_finalize(struct ax_
>   struct agentx_session *axs = cookie;
>   struct agentx *ax = axs->axs_ax;
>   struct agentx_context *axc, *tsac;
> + int axfree = ax->ax_free;
>  
>  #ifdef AX_DEBUG
>   if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
> @@ -492,19 +495,19 @@ agentx_session_close_finalize(struct ax_
>   }
>  
>   axs->axs_cstate = AX_CSTATE_CLOSE;
> + ax->ax_free = 1;
>  
>   agentx_

Re: libagentx(3): Don't deallocate dynamic indices

2021-10-21 Thread Martijn van Duren
ping

On Thu, 2021-09-09 at 21:49 +0200, Martijn van Duren wrote:
> When calling agentx_index_start we short-circuit the call to the agentx
> master when the index is dynamic. This is in accordance with the RFC.
> At the moment we don't do the same thing when calling
> agentx_index_close. Diff below addresses this.
> 
> Largest part is a reindent of agentx_index_close_finalize.
> 
> OK?
> 
> martijn@
> 
> Index: agentx.c
> ===
> RCS file: /cvs/src/lib/libagentx/agentx.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 agentx.c
> --- agentx.c  2 Jun 2021 08:40:09 -   1.10
> +++ agentx.c  9 Sep 2021 19:47:52 -
> @@ -1818,6 +1818,9 @@ agentx_index_close(struct agentx_index *
>   if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
>   return 0;
>  
> + if (axi->axi_type == AXI_TYPE_DYNAMIC)
> + return agentx_index_close_finalize(NULL, axi);
> +
>   /* We might be able to bundle, but if we fail we'd have to reorganise */
>   packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
>   AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
> @@ -1849,55 +1852,58 @@ agentx_index_close_finalize(struct ax_pd
>   __func__);
>  #endif
>  
> - if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
> - agentx_log_axc_warnx(axc,
> - "index %s: couldn't deallocate: %s",
> - ax_oid2string(&(axi->axi_vb.avb_oid)),
> - ax_error2string(resp->ap_error));
> - agentx_reset(ax);
> - return -1;
> - }
> + if (pdu != NULL) {
> + if (pdu->ap_payload.ap_response.ap_error !=
> + AX_PDU_ERROR_NOERROR) {
> + agentx_log_axc_warnx(axc,
> + "index %s: couldn't deallocate: %s",
> + ax_oid2string(&(axi->axi_vb.avb_oid)),
> + ax_error2string(resp->ap_error));
> + agentx_reset(ax);
> + return -1;
> + }
>  
> - if (resp->ap_nvarbind != 1) {
> - agentx_log_axc_warnx(axc,
> - "index %s: unexpected number of indices",
> - ax_oid2string(&(axr->axr_oid)));
> - agentx_reset(ax);
> - return -1;
> - }
> - if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
> - agentx_log_axc_warnx(axc, "index %s: unexpected index type",
> - ax_oid2string(&(axr->axr_oid)));
> - agentx_reset(ax);
> - return -1;
> - }
> - if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
> - &(axi->axi_vb.avb_oid)) != 0) {
> - agentx_log_axc_warnx(axc, "index %s: unexpected oid",
> - ax_oid2string(&(axr->axr_oid)));
> - agentx_reset(ax);
> - return -1;
> - }
> - switch (axi->axi_vb.avb_type) {
> - case AX_DATA_TYPE_INTEGER:
> - if (axi->axi_vb.avb_data.avb_int32 !=
> - resp->ap_varbindlist[0].avb_data.avb_int32) {
> + if (resp->ap_nvarbind != 1) {
>   agentx_log_axc_warnx(axc,
> - "index %s: unexpected index value",
> + "index %s: unexpected number of indices",
>   ax_oid2string(&(axr->axr_oid)));
>   agentx_reset(ax);
>   return -1;
>   }
> - break;
> - default:
> - agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
> - __func__);
> + if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
> + agentx_log_axc_warnx(axc, "index %s: unexpected index "
> + "type", ax_oid2string(&(axr->axr_oid)));
> + agentx_reset(ax);
> + return -1;
> + }
> + if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
> + &(axi->axi_vb.avb_oid)) != 0) {
> + agentx_log_axc_warnx(axc, "index %s: unexpected oid",
> + ax_oid2string(&(axr->axr_oid)));
> + agentx_reset(ax);
> + return -1;
> + }
> + switch (axi->axi_vb.avb_type) {
> + case AX_DATA_TYPE_INTEGER:
>

Re: snmpd(8): Log correct engineid

2021-10-21 Thread Martijn van Duren
ping

On Sun, 2021-09-26 at 10:22 +0200, Martijn van Duren wrote:
> ober_get_nstring writes a pointer to buf and does not overwrite the
> content of buf itself. So pushing an array in there will result in it
> only writing the pointer address to the array, which is not exactly what
> we want to show.
> 
> I choose to go for sizeof, instead of using the define to be a little
> more on the safe side, but I didn't change SNMPD_MAXCONTEXNAMELEN to
> keep the diff small.
> 
> OK?
> 
> martijn@
> 
> Index: snmpe.c
> ===
> RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
> retrieving revision 1.76
> diff -u -p -r1.76 snmpe.c
> --- snmpe.c   6 Sep 2021 13:32:18 -   1.76
> +++ snmpe.c   26 Sep 2021 08:19:59 -
> @@ -237,7 +237,7 @@ snmpe_parse(struct snmp_message *msg)
>   long longerrval, erridx;
>   u_intclass;
>   char*comn;
> - char*flagstr, *ctxname;
> + char*flagstr, *ctxname, *engineid;
>   size_t   len;
>   struct sockaddr_storage *ss = >sm_ss;
>   struct ber_element  *root = msg->sm_req;
> @@ -300,9 +300,12 @@ snmpe_parse(struct snmp_message *msg)
>   }
>  
>   if (ober_scanf_elements(a, "{xxeS$}$",
> - >sm_ctxengineid, >sm_ctxengineid_len,
> - , , >sm_pdu) != 0)
> + , >sm_ctxengineid_len, , ,
> + >sm_pdu) != 0)
>   goto parsefail;
> + if (msg->sm_ctxengineid_len > sizeof(msg->sm_ctxengineid))
> + goto parsefail;
> + memcpy(msg->sm_ctxengineid, engineid, msg->sm_ctxengineid_len);
>   if (len > SNMPD_MAXCONTEXNAMELEN)
>   goto parsefail;
>   memcpy(msg->sm_ctxname, ctxname, len);
> 




Re: ober_oid_cmp: copy over ax_oid_cmp logic

2021-10-21 Thread Martijn van Duren
ping

On Fri, 2021-10-01 at 16:42 +0200, Martijn van Duren wrote:
> Right now ober_oid_cmp has inverted logic compared to other *cmp
> functions. Specifically values greater than 0 are returned when
> a is smaller than b.
> Additionally, the value of 2 is only used b is a child of a, but
> -1 is returned when a is a child of b.
> 
> This makes it harder than needed to use it with say the RB_*
> family of functions, as well as wanting to test between the
> parent-child relationship between two value.
> 
> Both these issues are not present in ax_oid_cmp and I would like
> to copy the logic over from there.
> 
> Manpage bits mostly taken from strcmp(3)
> 
> I did a full scan of our tree and I could only find this function in
> snmp(1) and snmpd(8) and patches for those are attaches as well.
> No known 3rd party software is using this code.
> 
> Regress for libagentx, snmp and snmp pass.
> 
> OK for the next cycle?
> 
> martijn@
> 
> Index: lib/libutil/ber.c
> ===
> RCS file: /cvs/src/lib/libutil/ber.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 ber.c
> --- lib/libutil/ber.c 29 Aug 2021 13:27:11 -  1.22
> +++ lib/libutil/ber.c 1 Oct 2021 14:36:34 -
> @@ -473,26 +473,21 @@ ober_string2oid(const char *oidstr, stru
>  int
>  ober_oid_cmp(struct ber_oid *a, struct ber_oid *b)
>  {
> - size_t   i;
> - for (i = 0; i < a->bo_n && i < b->bo_n; i++) {
> - if (a->bo_id[i] == b->bo_id[i])
> - continue;
> - else if (a->bo_id[i] < b->bo_id[i]) {
> - /* b is a successor of a */
> - return (1);
> - } else {
> - /* b is a predecessor of a */
> + size_t   i, min;
> +
> + min = a->bo_n < b->bo_n ? a->bo_n : b->bo_n;
> + for (i = 0; i < min; i++) {
> + if (a->bo_id[i] < b->bo_id[i])
>   return (-1);
> - }
> + if (a->bo_id[i] > b->bo_id[i])
> + return (1);
>   }
> - /* b is larger, but a child of a */
> + /* a is parent of b */
>   if (a->bo_n < b->bo_n)
> - return (2);
> - /* b is a predecessor of a */
> + return (-2);
> + /* a is child of b */
>   if (a->bo_n > b->bo_n)
> - return -1;
> -
> - /* b and a are identical */
> + return 2;
>   return (0);
>  }
>  
> Index: lib/libutil/ober_oid_cmp.3
> ===
> RCS file: /cvs/src/lib/libutil/ober_oid_cmp.3,v
> retrieving revision 1.4
> diff -u -p -r1.4 ober_oid_cmp.3
> --- lib/libutil/ober_oid_cmp.312 Mar 2021 07:24:49 -  1.4
> +++ lib/libutil/ober_oid_cmp.31 Oct 2021 14:36:34 -
> @@ -66,26 +66,17 @@ returns the number of bytes written or 0
>  returns 0 on success or -1 on failure.
>  .Pp
>  .Fn ober_oid_cmp
> -returns 0 when oids
> +returns an integer greater than, equal to, or less than 0, according to 
> whether
> +the oid
> +.Fa a
> +is greater than, equal to, or less than the oid
> +.Fa b .
> +If the shortest length from
>  .Fa a
>  and
>  .Fa b
> -are identical.
> -If
> -.Fa b
> -is a successor of
> -.Fa a ,
> -1 is returned.
> -If
> -.Fa b
> -is a predecessor of
> -.Fa a ,
> --1 is returned.
> -If
> -.Fa b
> -is larger, but a child of
> -.Fa a ,
> -2 is returned.
> +matches
> +the weight of the integer is 2, else it is 1.
>  .Sh SEE ALSO
>  .Xr ober_add_string 3 ,
>  .Xr ober_get_string 3 ,
> Index: usr.sbin/snmpd/traphandler.c
> ===
> RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v
> retrieving revision 1.21
> diff -u -p -r1.21 traphandler.c
> --- usr.sbin/snmpd/traphandler.c  22 Feb 2021 11:31:09 -  1.21
> +++ usr.sbin/snmpd/traphandler.c  1 Oct 2021 14:36:34 -
> @@ -440,7 +440,7 @@ trapcmd_cmp(struct trapcmd *cmd1, struct
>  {
>   int ret;
>  
> - ret = ober_oid_cmp(cmd2->cmd_oid, cmd1->cmd_oid);
> + ret = ober_oid_cmp(cmd1->cmd_oid, cmd2->cmd_oid);
>   switch (ret) {
>   case 2:
>   /* cmd1 is a child of cmd2 */
> Index: usr.bin/snmp/smi.c
> ===
> RCS file: /cvs/src/usr.bin/snmp/smi.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 smi.c
> --- usr.bin/snmp/smi.c4 Jan 2021 08:00:29 -   1.14
> +++ usr.bin/snmp/smi.c  

ober_oid_cmp: copy over ax_oid_cmp logic

2021-10-01 Thread Martijn van Duren
Right now ober_oid_cmp has inverted logic compared to other *cmp
functions. Specifically values greater than 0 are returned when
a is smaller than b.
Additionally, the value of 2 is only used b is a child of a, but
-1 is returned when a is a child of b.

This makes it harder than needed to use it with say the RB_*
family of functions, as well as wanting to test between the
parent-child relationship between two value.

Both these issues are not present in ax_oid_cmp and I would like
to copy the logic over from there.

Manpage bits mostly taken from strcmp(3)

I did a full scan of our tree and I could only find this function in
snmp(1) and snmpd(8) and patches for those are attaches as well.
No known 3rd party software is using this code.

Regress for libagentx, snmp and snmp pass.

OK for the next cycle?

martijn@

Index: lib/libutil/ber.c
===
RCS file: /cvs/src/lib/libutil/ber.c,v
retrieving revision 1.22
diff -u -p -r1.22 ber.c
--- lib/libutil/ber.c   29 Aug 2021 13:27:11 -  1.22
+++ lib/libutil/ber.c   1 Oct 2021 14:36:34 -
@@ -473,26 +473,21 @@ ober_string2oid(const char *oidstr, stru
 int
 ober_oid_cmp(struct ber_oid *a, struct ber_oid *b)
 {
-   size_t   i;
-   for (i = 0; i < a->bo_n && i < b->bo_n; i++) {
-   if (a->bo_id[i] == b->bo_id[i])
-   continue;
-   else if (a->bo_id[i] < b->bo_id[i]) {
-   /* b is a successor of a */
-   return (1);
-   } else {
-   /* b is a predecessor of a */
+   size_t   i, min;
+
+   min = a->bo_n < b->bo_n ? a->bo_n : b->bo_n;
+   for (i = 0; i < min; i++) {
+   if (a->bo_id[i] < b->bo_id[i])
return (-1);
-   }
+   if (a->bo_id[i] > b->bo_id[i])
+   return (1);
}
-   /* b is larger, but a child of a */
+   /* a is parent of b */
if (a->bo_n < b->bo_n)
-   return (2);
-   /* b is a predecessor of a */
+   return (-2);
+   /* a is child of b */
if (a->bo_n > b->bo_n)
-   return -1;
-
-   /* b and a are identical */
+   return 2;
return (0);
 }
 
Index: lib/libutil/ober_oid_cmp.3
===
RCS file: /cvs/src/lib/libutil/ober_oid_cmp.3,v
retrieving revision 1.4
diff -u -p -r1.4 ober_oid_cmp.3
--- lib/libutil/ober_oid_cmp.3  12 Mar 2021 07:24:49 -  1.4
+++ lib/libutil/ober_oid_cmp.3  1 Oct 2021 14:36:34 -
@@ -66,26 +66,17 @@ returns the number of bytes written or 0
 returns 0 on success or -1 on failure.
 .Pp
 .Fn ober_oid_cmp
-returns 0 when oids
+returns an integer greater than, equal to, or less than 0, according to whether
+the oid
+.Fa a
+is greater than, equal to, or less than the oid
+.Fa b .
+If the shortest length from
 .Fa a
 and
 .Fa b
-are identical.
-If
-.Fa b
-is a successor of
-.Fa a ,
-1 is returned.
-If
-.Fa b
-is a predecessor of
-.Fa a ,
--1 is returned.
-If
-.Fa b
-is larger, but a child of
-.Fa a ,
-2 is returned.
+matches
+the weight of the integer is 2, else it is 1.
 .Sh SEE ALSO
 .Xr ober_add_string 3 ,
 .Xr ober_get_string 3 ,
Index: usr.sbin/snmpd/traphandler.c
===
RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v
retrieving revision 1.21
diff -u -p -r1.21 traphandler.c
--- usr.sbin/snmpd/traphandler.c22 Feb 2021 11:31:09 -  1.21
+++ usr.sbin/snmpd/traphandler.c1 Oct 2021 14:36:34 -
@@ -440,7 +440,7 @@ trapcmd_cmp(struct trapcmd *cmd1, struct
 {
int ret;
 
-   ret = ober_oid_cmp(cmd2->cmd_oid, cmd1->cmd_oid);
+   ret = ober_oid_cmp(cmd1->cmd_oid, cmd2->cmd_oid);
switch (ret) {
case 2:
/* cmd1 is a child of cmd2 */
Index: usr.bin/snmp/smi.c
===
RCS file: /cvs/src/usr.bin/snmp/smi.c,v
retrieving revision 1.14
diff -u -p -r1.14 smi.c
--- usr.bin/snmp/smi.c  4 Jan 2021 08:00:29 -   1.14
+++ usr.bin/snmp/smi.c  1 Oct 2021 14:36:34 -
@@ -506,7 +506,7 @@ smi_string2oid(const char *oidstr, struc
*p++ = '\0';
if ((oid = smi_findkey(sp)) != NULL) {
bcopy(>o_id, , sizeof(ko));
-   if (o->bo_n && ober_oid_cmp(o, ) != 2)
+   if (o->bo_n && ober_oid_cmp(, o) != 2)
return (-1);
bcopy(, o, sizeof(*o));
errstr = NULL;
Index: usr.bin/snmp/snmpc.c
===
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.37
diff -u -p -r1.37 snmpc.c
--- usr.bin/snmp/snmpc.c11 Aug 2021 18:53:45 -  1.37
+++ usr.bin/snmp/snmpc.c1 Oct 2021 

snmpd(8): Log correct engineid

2021-09-26 Thread Martijn van Duren
ober_get_nstring writes a pointer to buf and does not overwrite the
content of buf itself. So pushing an array in there will result in it
only writing the pointer address to the array, which is not exactly what
we want to show.

I choose to go for sizeof, instead of using the define to be a little
more on the safe side, but I didn't change SNMPD_MAXCONTEXNAMELEN to
keep the diff small.

OK?

martijn@

Index: snmpe.c
===
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.76
diff -u -p -r1.76 snmpe.c
--- snmpe.c 6 Sep 2021 13:32:18 -   1.76
+++ snmpe.c 26 Sep 2021 08:19:59 -
@@ -237,7 +237,7 @@ snmpe_parse(struct snmp_message *msg)
long longerrval, erridx;
u_intclass;
char*comn;
-   char*flagstr, *ctxname;
+   char*flagstr, *ctxname, *engineid;
size_t   len;
struct sockaddr_storage *ss = >sm_ss;
struct ber_element  *root = msg->sm_req;
@@ -300,9 +300,12 @@ snmpe_parse(struct snmp_message *msg)
}
 
if (ober_scanf_elements(a, "{xxeS$}$",
-   >sm_ctxengineid, >sm_ctxengineid_len,
-   , , >sm_pdu) != 0)
+   , >sm_ctxengineid_len, , ,
+   >sm_pdu) != 0)
goto parsefail;
+   if (msg->sm_ctxengineid_len > sizeof(msg->sm_ctxengineid))
+   goto parsefail;
+   memcpy(msg->sm_ctxengineid, engineid, msg->sm_ctxengineid_len);
if (len > SNMPD_MAXCONTEXNAMELEN)
goto parsefail;
memcpy(msg->sm_ctxname, ctxname, len);




Re: syslogd sendmsg

2021-09-11 Thread Martijn van Duren
On Sat, 2021-09-11 at 04:05 +0300, Vitaliy Makkoveev wrote:
> On Fri, Sep 10, 2021 at 07:40:58PM +0200, Alexander Bluhm wrote:
> > Hi,
> > 
> > After converting syslogd messages to iov, UDP can use sendmsg(2)
> > instead of snprintf().
> > 
> > ok?
> > 
> 
> I have one question below, but the diff is ok by mvs@ if it is not
> significant.
> 
> It is expected we could drop iov[6].iov_len bytes more from `msg' but
> keep newline stuff when message size exceeds MAX_UDPMSG? The original
> code has the different behaviour.

Maybe I'm misreading, but the iov[6] is set in the final switch
statement, which lacks the F_FORWUDP case, so it drops to default,
which has an empty string, not a newline.

As I already mailed bluhm@ in private; I'm more curious about the
else case for if (iov[5].iov_len > l). In this case iov[0..4]
still overflow MAX_UDPMSG and we also drop the entire "msg"
itself, which leaves basically no useful information.
Since we only prepend pribuf (13 bytes), lasttime (33 bytes + 1 space),
and prevhost/localhostname (HOST_NAME_MAX=255 + 1 bytes + 1 space) we
can at most reach 304 bytes, which is a lot shorter than the current
MAX_UDPMSG of 1180 bytes.
If we trust that noone will be stupid enough to blindly change
MAX_UDPMSG to <304 bytes, or start bloating the preemble >876 bytes I
don't see a reason to add this case.
If it's a genuine concern then I think it would make more sense
to just drop the message altogether, since everything that could be
useful is already lost.
> 
> > bluhm
> > 
> > Index: usr.sbin/syslogd/syslogd.c
> > ===
> > RCS file: /cvs/src/usr.sbin/syslogd/syslogd.c,v
> > retrieving revision 1.269
> > diff -u -p -r1.269 syslogd.c
> > --- usr.sbin/syslogd/syslogd.c  10 Sep 2021 15:18:36 -  1.269
> > +++ usr.sbin/syslogd/syslogd.c  10 Sep 2021 17:36:45 -
> > @@ -1897,6 +1897,7 @@ void
> >  fprintlog(struct filed *f, int flags, char *msg)
> >  {
> > struct iovec iov[IOVCNT], *v;
> > +   struct msghdr msghdr;
> > int l, retryonce;
> > char line[LOG_MAXLINE + 1], pribuf[13], greetings[500], repbuf[80];
> > char ebuf[ERRBUFSIZE];
> > @@ -2037,20 +2038,22 @@ fprintlog(struct filed *f, int flags, ch
> >  
> > case F_FORWUDP:
> > log_debug(" %s", f->f_un.f_forw.f_loghost);
> > -   l = snprintf(line, MINIMUM(MAX_UDPMSG + 1, sizeof(line)),
> > -   "%s%s%s%s%s%s%s", (char *)iov[0].iov_base,
> > -   (char *)iov[1].iov_base, (char *)iov[2].iov_base,
> > -   (char *)iov[3].iov_base, (char *)iov[4].iov_base,
> > -   (char *)iov[5].iov_base, (char *)iov[6].iov_base);
> > -   if (l < 0)
> > -   l = strlcpy(line, iov[5].iov_base, sizeof(line));
> > -   if (l >= sizeof(line))
> > -   l = sizeof(line) - 1;
> > -   if (l >= MAX_UDPMSG + 1)
> > -   l = MAX_UDPMSG;
> > -   if (sendto(f->f_file, line, l, 0,
> > -   (struct sockaddr *)>f_un.f_forw.f_addr,
> > -   f->f_un.f_forw.f_addr.ss_len) != l) {
> > +   l = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len +
> > +   iov[3].iov_len + iov[4].iov_len + iov[5].iov_len +
> > +   iov[6].iov_len;
> > +   if (l > MAX_UDPMSG) {
> > +   l -= MAX_UDPMSG;
> > +   if (iov[5].iov_len > l)
> > +   iov[5].iov_len -= l;
> > +   else
> > +   iov[5].iov_len = 0;
> > +   }
> > +   memset(, 0, sizeof(msghdr));
> > +   msghdr.msg_name = >f_un.f_forw.f_addr;
> > +   msghdr.msg_namelen = f->f_un.f_forw.f_addr.ss_len;
> > +   msghdr.msg_iov = iov;
> > +   msghdr.msg_iovlen = IOVCNT;
> > +   if (sendmsg(f->f_file, , 0) == -1) {
> > switch (errno) {
> > case EADDRNOTAVAIL:
> > case EHOSTDOWN:
> > @@ -2063,7 +2066,7 @@ fprintlog(struct filed *f, int flags, ch
> > break;
> > default:
> > f->f_type = F_UNUSED;
> > -   log_warn("sendto \"%s\"",
> > +   log_warn("sendmsg to \"%s\"",
> > f->f_un.f_forw.f_loghost);
> > break;
> > }
> > 
> 




libagentx(3): Don't deallocate dynamic indices

2021-09-09 Thread Martijn van Duren
When calling agentx_index_start we short-circuit the call to the agentx
master when the index is dynamic. This is in accordance with the RFC.
At the moment we don't do the same thing when calling
agentx_index_close. Diff below addresses this.

Largest part is a reindent of agentx_index_close_finalize.

OK?

martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.10
diff -u -p -r1.10 agentx.c
--- agentx.c2 Jun 2021 08:40:09 -   1.10
+++ agentx.c9 Sep 2021 19:47:52 -
@@ -1818,6 +1818,9 @@ agentx_index_close(struct agentx_index *
if (axs->axs_cstate == AX_CSTATE_WAITCLOSE)
return 0;
 
+   if (axi->axi_type == AXI_TYPE_DYNAMIC)
+   return agentx_index_close_finalize(NULL, axi);
+
/* We might be able to bundle, but if we fail we'd have to reorganise */
packetid = ax_indexdeallocate(ax->ax_ax, axs->axs_id,
AGENTX_CONTEXT_CTX(axc), &(axi->axi_vb), 1);
@@ -1849,55 +1852,58 @@ agentx_index_close_finalize(struct ax_pd
__func__);
 #endif
 
-   if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) {
-   agentx_log_axc_warnx(axc,
-   "index %s: couldn't deallocate: %s",
-   ax_oid2string(&(axi->axi_vb.avb_oid)),
-   ax_error2string(resp->ap_error));
-   agentx_reset(ax);
-   return -1;
-   }
+   if (pdu != NULL) {
+   if (pdu->ap_payload.ap_response.ap_error !=
+   AX_PDU_ERROR_NOERROR) {
+   agentx_log_axc_warnx(axc,
+   "index %s: couldn't deallocate: %s",
+   ax_oid2string(&(axi->axi_vb.avb_oid)),
+   ax_error2string(resp->ap_error));
+   agentx_reset(ax);
+   return -1;
+   }
 
-   if (resp->ap_nvarbind != 1) {
-   agentx_log_axc_warnx(axc,
-   "index %s: unexpected number of indices",
-   ax_oid2string(&(axr->axr_oid)));
-   agentx_reset(ax);
-   return -1;
-   }
-   if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
-   agentx_log_axc_warnx(axc, "index %s: unexpected index type",
-   ax_oid2string(&(axr->axr_oid)));
-   agentx_reset(ax);
-   return -1;
-   }
-   if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
-   &(axi->axi_vb.avb_oid)) != 0) {
-   agentx_log_axc_warnx(axc, "index %s: unexpected oid",
-   ax_oid2string(&(axr->axr_oid)));
-   agentx_reset(ax);
-   return -1;
-   }
-   switch (axi->axi_vb.avb_type) {
-   case AX_DATA_TYPE_INTEGER:
-   if (axi->axi_vb.avb_data.avb_int32 !=
-   resp->ap_varbindlist[0].avb_data.avb_int32) {
+   if (resp->ap_nvarbind != 1) {
agentx_log_axc_warnx(axc,
-   "index %s: unexpected index value",
+   "index %s: unexpected number of indices",
ax_oid2string(&(axr->axr_oid)));
agentx_reset(ax);
return -1;
}
-   break;
-   default:
-   agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
-   __func__);
+   if (resp->ap_varbindlist[0].avb_type != axi->axi_vb.avb_type) {
+   agentx_log_axc_warnx(axc, "index %s: unexpected index "
+   "type", ax_oid2string(&(axr->axr_oid)));
+   agentx_reset(ax);
+   return -1;
+   }
+   if (ax_oid_cmp(&(resp->ap_varbindlist[0].avb_oid),
+   &(axi->axi_vb.avb_oid)) != 0) {
+   agentx_log_axc_warnx(axc, "index %s: unexpected oid",
+   ax_oid2string(&(axr->axr_oid)));
+   agentx_reset(ax);
+   return -1;
+   }
+   switch (axi->axi_vb.avb_type) {
+   case AX_DATA_TYPE_INTEGER:
+   if (axi->axi_vb.avb_data.avb_int32 !=
+   resp->ap_varbindlist[0].avb_data.avb_int32) {
+   agentx_log_axc_warnx(axc,
+   "index %s: unexpected index value",
+   ax_oid2string(&(axr->axr_oid)));
+   agentx_reset(ax);
+   return -1;
+   }
+   break;
+   default:
+   agentx_log_axc_fatalx(axc, "%s: Unsupported index type",
+   __func__);
+   }
+
+   

Re: OpenSSH: RSA/SHA1 disabled by default

2021-09-07 Thread Martijn van Duren
On Mon, 2021-08-30 at 10:08 +1000, Damien Miller wrote:
> Hi,
> 
> RSA/SHA1, a.k.a the "ssh-rsa" signature type is now disabled by default
> in OpenSSH.
> 
> While The SSH protocol confusingly uses overlapping names for key and
> signature algorithms, this does not stop the use of RSA keys and there
> is no need to regenerate "ssh-rsa" keys - most servers released in the
> last five years will automatically negotiate the use of RSA/SHA-256/512
> signatures.
> 
> This has been coming for a long time, but I do expect it will be
> distruptive for some people as there are likely to be some devices
> out there that cannot be upgraded to support the safer algorithms.
> 
> In these cases, it is possible to selectively re-enable RSA/SHA1
> support by specifying PubkeyAcceptedAlgorithms=+ssh-rsa in the
> ssh_config(5) or sshd_config(5) for the endpoint.
> 
> Please report any problems here, to bugs@ or to openssh@
> 
> Thanks,
> Damien
> 
Just did an update to the latest snapshot and this breaks connection
to one of the older hosts I still need to connect to from time to time.

Reverting this diff fixes the issue for me.

According to -G it should work:

$ ssh -G -oPubkeyAcceptedAlgorithms=ssh-rsa 10.255.3.242 | grep -i 
PubkeyAcceptedAlgorithms
pubkeyacceptedalgorithms ssh-rsa

But when trying it for real I get the following:
martijn$ ssh - -oPubkeyAcceptedAlgorithms=ssh-rsa x.x.x.x
OpenSSH_8.7, LibreSSL 3.4.0
debug1: Reading configuration data /etc/ssh/ssh_config
debug2: resolve_canonicalize: hostname x.x.x.x is address
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> 
'/home/martijn/.ssh/known_hosts'
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> 
'/home/martijn/.ssh/known_hosts2'
debug3: ssh_connect_direct: entering
debug1: Connecting to x.x.x.x [x.x.x.x] port 22.
debug3: set_sock_tos: set socket 3 IP_TOS 0x48
debug1: Connection established.
debug1: identity file /home/martijn/.ssh/id_rsa type 0
debug1: identity file /home/martijn/.ssh/id_rsa-cert type -1
debug1: identity file /home/martijn/.ssh/id_dsa type -1
debug1: identity file /home/martijn/.ssh/id_dsa-cert type -1
debug1: identity file /home/martijn/.ssh/id_ecdsa type -1
debug1: identity file /home/martijn/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/martijn/.ssh/id_ecdsa_sk type -1
debug1: identity file /home/martijn/.ssh/id_ecdsa_sk-cert type -1
debug1: identity file /home/martijn/.ssh/id_ed25519 type -1
debug1: identity file /home/martijn/.ssh/id_ed25519-cert type -1
debug1: identity file /home/martijn/.ssh/id_ed25519_sk type -1
debug1: identity file /home/martijn/.ssh/id_ed25519_sk-cert type -1
debug1: identity file /home/martijn/.ssh/id_xmss type -1
debug1: identity file /home/martijn/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.7
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.9p1 
Debian-5ubuntu1.9
debug1: compat_banner: match: OpenSSH_5.9p1 Debian-5ubuntu1.9 pat OpenSSH_5* 
compat 0x0c02
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to x.x.x.x:22 as 'martijn'
debug3: record_hostkey: found key type RSA in file 
/home/martijn/.ssh/known_hosts:4
debug3: load_hostkeys_file: loaded 1 keys from x.x.x.x
debug1: load_hostkeys: fopen /home/martijn/.ssh/known_hosts2: No such file or 
directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or 
directory
debug3: order_hostkeyalgs: prefer hostkeyalgs: 
rsa-sha2-512-cert-...@openssh.com,rsa-sha2-256-cert-...@openssh.com,rsa-sha2-512,rsa-sha2-256
debug3: send packet: type 20
debug1: SSH2_MSG_KEXINIT sent
debug3: receive packet: type 20
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
debug2: KEX algorithms: 
curve25519-sha256,curve25519-sha...@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-
sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,ext-info-c
debug2: host key algorithms: 
rsa-sha2-512-cert-...@openssh.com,rsa-sha2-256-cert-...@openssh.com,rsa-sha2-512,rsa-sha2-
256,ssh-ed25519-cert-...@openssh.com,ecdsa-sha2-nistp256-cert-...@openssh.com,ecdsa-sha2-nistp384-cert-...@openssh.com,ecdsa-sha2-nistp521-cert-...@openssh.com,sk-ssh-ed25519-cert-...@openssh.com,s
k-ecdsa-sha2-nistp256-cert-...@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25...@openssh.com,sk-ecdsa-sha2-nistp...@openssh.com
debug2: ciphers ctos: 
chacha20-poly1...@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-...@openssh.com,aes256-...@openssh.com
debug2: ciphers stoc: 
chacha20-poly1...@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-...@openssh.com,aes256-...@openssh.com
debug2: MACs ctos: 

Re: Atomic signal flags for vi(1)

2021-09-02 Thread Martijn van Duren
On Thu, 2021-09-02 at 13:25 +0200, Ingo Schwarze wrote:
> Hi Tim,
> 
> trondd wrote on Wed, Sep 01, 2021 at 08:46:28PM -0400:
> > Ingo Schwarze  wrote:
> > > Ingo Schwarze wrote on Wed, Sep 01, 2021 at 04:38:51PM +0200:
> 
> > > > Note that the h_hup() and h_term() signal handlers are still unsafe
> > > > after this commit because they also set the "killersig" (how fitting!)
> > > > field in a global struct.
> 
> > > I like it when fixing two bugs only amounts to minus: minus 14 LOC,
> > > 1 function, 1 global variable, 2 automatic variables, 1 struct member,
> > > 9 pointer dereferences, 1 #define, and minus 1 #undef.
> > > 
> > > The argument that only one single GS exists applies unchanged.
> 
> > Great.  This is the direction I was going to go in with it.  I hadn't
> > thought of collapsing h_hup an h_term, though.
> > 
> > This makes sense as I understand the signal/event handling and a quick
> > test through the signals shows no difference in behavior.
> 
> Thank you (and martijn@) for reviewing and testing.
> This is now committed.
> 
> > Should h_term() and cl_sigterm be named something more general to
> > indicate that they also handle SIGHUP?  Or is it good enough since it
> > includes all the signals that 'term'inate vi?  It's not hard to follow
> > as-is. 
> 
> That is what i was thinking: why re-paint a bike shed if the existing
> paint is already pretty and not yet falling off?

Luckily the paint is pretty. :-)
> 
> Yours,
>   Ingo
> 
> 
> > > Index: cl/cl.h
> > > ===
> > > RCS file: /cvs/src/usr.bin/vi/cl/cl.h,v
> > > retrieving revision 1.11
> > > diff -u -p -r1.11 cl.h
> > > --- cl/cl.h   1 Sep 2021 14:28:15 -   1.11
> > > +++ cl/cl.h   1 Sep 2021 17:15:34 -
> > > @@ -11,7 +11,6 @@
> > >   *   @(#)cl.h10.19 (Berkeley) 9/24/96
> > >   */
> > >  
> > > -extern   volatile sig_atomic_t cl_sighup;
> > >  extern   volatile sig_atomic_t cl_sigint;
> > >  extern   volatile sig_atomic_t cl_sigterm;
> > >  extern   volatile sig_atomic_t cl_sigwinch;
> > > @@ -31,7 +30,6 @@ typedef struct _cl_private {
> > >   char*rmso, *smso;   /* Inverse video terminal strings. */
> > >   char*smcup, *rmcup; /* Terminal start/stop strings. */
> > >  
> > > - int  killersig; /* Killer signal. */
> > >  #define  INDX_HUP0
> > >  #define  INDX_INT1
> > >  #define  INDX_TERM   2
> > > Index: cl/cl_funcs.c
> > > ===
> > > RCS file: /cvs/src/usr.bin/vi/cl/cl_funcs.c,v
> > > retrieving revision 1.21
> > > diff -u -p -r1.21 cl_funcs.c
> > > --- cl/cl_funcs.c 1 Sep 2021 14:28:15 -   1.21
> > > +++ cl/cl_funcs.c 1 Sep 2021 17:15:34 -
> > > @@ -437,7 +437,7 @@ cl_refresh(SCR *sp, int repaint)
> > >* If we received a killer signal, we're done, there's no point
> > >* in refreshing the screen.
> > >*/
> > > - if (clp->killersig)
> > > + if (cl_sigterm)
> > >   return (0);
> > >  
> > >   /*
> > > @@ -582,7 +582,7 @@ cl_suspend(SCR *sp, int *allowedp)
> > >* unchanged.  In addition, the terminal has already been reset
> > >* correctly, so leave it alone.
> > >*/
> > > - if (clp->killersig) {
> > > + if (cl_sigterm) {
> > >   F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
> > >   return (0);
> > >   }
> > > Index: cl/cl_main.c
> > > ===
> > > RCS file: /cvs/src/usr.bin/vi/cl/cl_main.c,v
> > > retrieving revision 1.34
> > > diff -u -p -r1.34 cl_main.c
> > > --- cl/cl_main.c  1 Sep 2021 14:28:15 -   1.34
> > > +++ cl/cl_main.c  1 Sep 2021 17:15:34 -
> > > @@ -33,7 +33,6 @@
> > >  
> > >  GS *__global_list;   /* GLOBAL: List of 
> > > screens. */
> > >  
> > > -volatile sig_atomic_t cl_sighup;
> > >  volatile sig_atomic_t cl_sigint;
> > >  volatile sig_atomic_t cl_sigterm;
> > >  volatile sig_atomic_t cl_sigwinch;
> > > @@ -120,9 +119,9 @@ main(int argc, char *argv[])
> > >   }
> > >  
> > >   /* If a killer signal arrived, pretend we just got it. */
> > > - if (clp->killersig) {
> > > - (void)signal(clp->killersig, SIG_DFL);
> > > - (void)kill(getpid(), clp->killersig);
> > > + if (cl_sigterm) {
> > > + (void)signal(cl_sigterm, SIG_DFL);
> > > + (void)kill(getpid(), cl_sigterm);
> > >   /* NOTREACHED */
> > >   }
> > >  
> > > @@ -215,17 +214,6 @@ term_init(char *ttype)
> > >   }
> > >  }
> > >  
> > > -#define  GLOBAL_CLP \
> > > - CL_PRIVATE *clp = GCLP(__global_list);
> > > -static void
> > > -h_hup(int signo)
> > > -{
> > > - GLOBAL_CLP;
> > > -
> > > - cl_sighup = 1;
> > > - clp->killersig = SIGHUP;
> > > -}
> > > -
> > >  static void
> > >  h_int(int signo)
> > >  {
> > > @@ -235,10 +223,7 @@ h_int(int signo)
> > >  static void
> > >  h_term(int signo)
> > >  {
> > > - GLOBAL_CLP;
> > > -
> > > - cl_sigterm = 1;
> > > - 

Re: timeout: Prettify man page and usage

2021-09-02 Thread Martijn van Duren
On Thu, 2021-09-02 at 08:56 +, Job Snijders wrote:
> On Thu, Sep 02, 2021 at 07:23:26AM +0100, Jason McIntyre wrote:
> > >  .Ar time
> > > -can be integer or decimal numbers.
> > > +are positive integer or real (decimal) numbers, with an optional
> > 
> > can you have a negative timeout?
> 
> Negative values are not permitted
> 
> $ timeout -- -1 /bin/ls
> timeout: invalid duration: Undefined error: 0
> 
> Kind regards,
> 
> Job
> 
There are a few cases where we don't set errno, but do use err(3).

Index: timeout.c
===
RCS file: /cvs/src/usr.bin/timeout/timeout.c,v
retrieving revision 1.13
diff -u -p -r1.13 timeout.c
--- timeout.c   2 Sep 2021 06:23:32 -   1.13
+++ timeout.c   2 Sep 2021 09:05:08 -
@@ -68,15 +68,15 @@ parse_duration(const char *duration)
 
ret = strtod(duration, );
if (ret == 0 && suffix == duration)
-   err(1, "invalid duration");
+   errx(1, "invalid duration");
if (ret < 0 || ret >= 1UL)
-   err(1, "invalid duration");
+   errx(1, "invalid duration");
 
if (suffix == NULL || *suffix == '\0')
return (ret);
 
if (suffix != NULL && *(suffix + 1) != '\0')
-   err(1, "invalid duration");
+   errx(1, "invalid duration");
 
switch (*suffix) {
case 's':
@@ -91,7 +91,7 @@ parse_duration(const char *duration)
ret *= 60 * 60 * 24;
break;
default:
-   err(1, "invalid duration");
+   errx(1, "invalid duration");
}
 
return (ret);
@@ -111,12 +111,12 @@ parse_signal(const char *str)
if (strcasecmp(str, sys_signame[i]) == 0)
return (i);
}
-   err(1, "invalid signal name");
+   errx(1, "invalid signal name");
}
 
sig = strtonum(str, 1, NSIG, );
if (errstr != NULL)
-   err(1, "signal %s %s", str, errstr);
+   errx(1, "signal %s %s", str, errstr);
 
return (int)sig;
 }




Re: libagentx: Fix thumbling after free

2021-09-01 Thread Martijn van Duren
Bluhm asked me to rethink the freeing strategy.
Here's the end result.

On Mon, 2021-08-30 at 12:03 +0200, Martijn van Duren wrote:
> I missed this one before, since apparently it doesn't show up with
> MALLOC_OPTIONS set to "S", but it does if it is empty.
> 
> This probably effects relayd if the admin has it enabled en then
> disables it via a "relayctl reload". However, I'm not able to
> reproduce it there and even if it can be triggered, chances of
> that happening in real life are slim to none.
> 
> I think the comment should explain enough.
> 
> OK?
> 
> martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.10
diff -u -p -r1.10 agentx.c
--- agentx.c2 Jun 2021 08:40:09 -   1.10
+++ agentx.c1 Sep 2021 20:51:09 -
@@ -270,10 +270,12 @@ agentx_reset(struct agentx *ax)
struct agentx_session *axs, *tsas;
struct agentx_request *axr;
struct agentx_get *axg;
+   int axfree = ax->ax_free;
 
ax_free(ax->ax_ax);
ax->ax_ax = NULL;
ax->ax_fd = -1;
+   ax->ax_free = 1;
 
ax->ax_cstate = AX_CSTATE_CLOSE;
 
@@ -289,52 +291,52 @@ agentx_reset(struct agentx *ax)
TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
}
 
-   if (ax->ax_dstate == AX_DSTATE_CLOSE) {
-   agentx_free_finalize(ax);
-   return;
-   }
+   if (ax->ax_dstate == AX_DSTATE_OPEN)
+   agentx_start(ax);
 
-   agentx_start(ax);
+   if (!axfree)
+   agentx_free_finalize(ax);
 }
 
 void
 agentx_free(struct agentx *ax)
 {
struct agentx_session *axs, *tsas;
+   int axfree;
 
if (ax == NULL)
return;
 
-   if (ax->ax_dstate == AX_DSTATE_CLOSE) {
-/* Malloc throws abort on invalid pointers as well */
+   axfree = ax->ax_free;
+   ax->ax_free = 1;
+
+   /* Malloc throws abort on invalid pointers as well */
+   if (ax->ax_dstate == AX_DSTATE_CLOSE)
agentx_log_ax_fatalx(ax, "%s: double free", __func__);
-   }
ax->ax_dstate = AX_DSTATE_CLOSE;
 
-   if (!TAILQ_EMPTY(&(ax->ax_sessions))) {
-   TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions,
-   tsas) {
-   if (axs->axs_dstate != AX_DSTATE_CLOSE)
-   agentx_session_free(axs);
-   }
-   } else
+   TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, tsas) {
+   if (axs->axs_dstate != AX_DSTATE_CLOSE)
+   agentx_session_free(axs);
+   }
+   if (!axfree)
agentx_free_finalize(ax);
 }
 
 static void
 agentx_free_finalize(struct agentx *ax)
 {
-#ifdef AX_DEBUG
-   if (ax->ax_dstate != AX_DSTATE_CLOSE)
-   agentx_log_ax_fatalx(ax, "%s: agentx not closing",
-   __func__);
-   if (!TAILQ_EMPTY(&(ax->ax_sessions)))
-   agentx_log_ax_fatalx(ax, "%s: agentx still has sessions",
-   __func__);
-   if (!RB_EMPTY(&(ax->ax_requests)))
-   agentx_log_ax_fatalx(ax,
-   "%s: agentx still has pending requests", __func__);
-#endif
+   struct agentx_session *axs, *taxs;
+
+   ax->ax_free = 0;
+
+   TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
+   agentx_session_free_finalize(axs);
+
+   if (!TAILQ_EMPTY(&(ax->ax_sessions)) ||
+   !RB_EMPTY(&(ax->ax_requests)) ||
+   ax->ax_dstate != AX_DSTATE_CLOSE)
+   return;
 
ax_free(ax->ax_ax);
ax->ax_nofd(ax, ax->ax_cookie, 1);
@@ -477,6 +479,7 @@ agentx_session_close_finalize(struct ax_
struct agentx_session *axs = cookie;
struct agentx *ax = axs->axs_ax;
struct agentx_context *axc, *tsac;
+   int axfree = ax->ax_free;
 
 #ifdef AX_DEBUG
if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
@@ -492,19 +495,19 @@ agentx_session_close_finalize(struct ax_
}
 
axs->axs_cstate = AX_CSTATE_CLOSE;
+   ax->ax_free = 1;
 
agentx_log_axs_info(axs, "closed");
 
TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac)
agentx_context_reset(axc);
 
-   if (axs->axs_dstate == AX_DSTATE_CLOSE)
-   agentx_session_free_finalize(axs);
-   else {
-   if (ax->ax_cstate == AX_CSTATE_OPEN)
-   if (agentx_session_start(axs) == -1)
-   return -1;
-   }
+   if (ax->ax_cstate == AX_CSTATE_OPEN &&
+   axs->axs_dstate == AX_DSTATE_OPEN)
+   

relayd(8): agentx allow re-enabling

2021-08-30 Thread Martijn van Duren
Via "relayctl reload" agentx can be enabled, disabled, but if it's
enabled->disabled->enabled the final enable won't work because we
never reset the sa.

Also add an extra guard so that we don't accidentally free it
twice.

OK?

martijn@

Index: agentx_control.c
===
RCS file: /cvs/src/usr.sbin/relayd/agentx_control.c,v
retrieving revision 1.4
diff -u -p -r1.4 agentx_control.c
--- agentx_control.c27 Oct 2020 18:48:07 -  1.4
+++ agentx_control.c30 Aug 2021 10:49:49 -
@@ -124,7 +124,7 @@ static struct snmp_oid  hosttrapoid = {
 #define RELAYDTABLENAMERELAYDTABLEENTRY, 2
 #define RELAYDTABLESTATUS  RELAYDTABLEENTRY, 3
 
-void agentx_needsock(struct agentx *, void *, int);
+void agentx_nofd(struct agentx *, void *, int);
 
 struct relayd *env;
 
@@ -202,6 +202,7 @@ agentx_init(struct relayd *nenv)
struct agentx_context *sac;
struct agentx_region *sar;
struct agentx_index *session_idxs[2];
+   static int freed;
 
agentx_log_fatal = fatalx;
agentx_log_warn = log_warnx;
@@ -211,14 +212,17 @@ agentx_init(struct relayd *nenv)
env = nenv;
 
if ((env->sc_conf.flags & F_AGENTX) == 0) {
-   if (sa != NULL)
+   if (sa != NULL && !freed) {
agentx_free(sa);
+   freed = 1;
+   }
return;
}
if (sa != NULL)
return;
 
-   if ((sa = agentx(agentx_needsock, NULL)) == NULL)
+   freed = 0;
+   if ((sa = agentx(agentx_nofd, NULL)) == NULL)
fatal("%s: agentx alloc", __func__);
if ((sas = agentx_session(sa, NULL, 0, "relayd", 0)) == NULL)
fatal("%s: agentx session alloc", __func__);
@@ -420,9 +424,15 @@ agentx_init(struct relayd *nenv)
 }
 
 void
-agentx_needsock(struct agentx *usa, void *cookie, int fd)
+agentx_nofd(struct agentx *usa, void *cookie, int close)
 {
-   proc_compose(env->sc_ps, PROC_PARENT, IMSG_AGENTXSOCK, NULL, 0);
+   if (!close)
+   proc_compose(env->sc_ps, PROC_PARENT, IMSG_AGENTXSOCK, NULL, 0);
+   else {
+   sa = NULL;
+   agentx_init(env);
+   event_del(&(env->sc_agentxev));
+   }
 }
 
 void




libagentx: Fix thumbling after free

2021-08-30 Thread Martijn van Duren
I missed this one before, since apparently it doesn't show up with
MALLOC_OPTIONS set to "S", but it does if it is empty.

This probably effects relayd if the admin has it enabled en then
disables it via a "relayctl reload". However, I'm not able to
reproduce it there and even if it can be triggered, chances of
that happening in real life are slim to none.

I think the comment should explain enough.

OK?

martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.10
diff -u -p -r1.10 agentx.c
--- agentx.c2 Jun 2021 08:40:09 -   1.10
+++ agentx.c30 Aug 2021 10:03:08 -
@@ -1262,16 +1262,29 @@ agentx_region_reset(struct agentx_region
 {
struct agentx_index *axi, *tsai;
struct agentx_object *axo, *tsao;
+   int dofree = 1;
 
axr->axr_cstate = AX_CSTATE_CLOSE;
axr->axr_priority = AX_PRIORITY_DEFAULT;
 
-   TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai)
+   TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai) {
agentx_index_reset(axi);
-   TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao)
+   dofree = 0;
+   }
+   TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao) {
agentx_object_reset(axo);
+   dofree = 0;
+   }
 
-   if (axr->axr_dstate == AX_DSTATE_CLOSE)
+   /*
+* If there were children they already freed axr for us via
+* agentx_index_finalize().
+* This construction is needed because agentx_region_free()
+* calls the *_close functions on itself and its children, but the close
+* confirmations might be received out of order and we can't free the
+* region if there's still children active.
+*/
+   if (dofree && axr->axr_dstate == AX_DSTATE_CLOSE)
agentx_region_free_finalize(axr);
 }
 




Re: Atomic signal flags for vi(1)

2021-08-29 Thread Martijn van Duren
I'll see if I can fit this one in in the next few days.
Feel free to remind me :-)

martijn@

On Sun, 2021-08-29 at 02:54 -0600, Theo de Raadt wrote:
> This does look better.
> 
> I appreciate that you are fixing this underlying problem first, before
> overlaying your timer diff.
> 
> Is this working for the vi crowd?
> 
> 
> trondd  wrote:
> 
> > "Theo de Raadt"  wrote:
> > 
> > > +h_alrm(int signo)
> > > +{
> > > +   GLOBAL_CLP;
> > > +
> > > +   F_SET(clp, CL_SIGALRM);
> > > 
> > > F_SET is |=, which is not atomic.
> > > 
> > > This is unsafe.  Safe signal handlers need to make single stores to
> > > atomic-sized variables, which tend to be int-sized, easier to declare
> > > as sig_atomic_t.  Most often these are global scope with the following
> > > type:
> > > 
> > >   volatile sig_atomic_t variable
> > > 
> > > I can see you copied an existing practice.  Sadly all the other
> > > signal handlers are also broken in the same way.
> > > 
> > > The flag bits should be replaced with seperate sig_atomic_t variables.
> > 
> > Ok.  Took a swing at converting the signal handling to sig_atomic_t flags.
> > No additional changes added other than removing a redundant check of the
> > flags in cl_read.c.  Seemed to be a pretty straight-forward conversion and
> > I haven't found any change in behavior.
> > 
> > Tim.
> > 
> > 
> > Index: cl/cl.h
> > ===
> > RCS file: /cvs/src/usr.bin/vi/cl/cl.h,v
> > retrieving revision 1.10
> > diff -u -p -r1.10 cl.h
> > --- cl/cl.h 27 May 2016 09:18:11 -  1.10
> > +++ cl/cl.h 24 Aug 2021 23:34:27 -
> > @@ -11,6 +11,11 @@
> >   * @(#)cl.h10.19 (Berkeley) 9/24/96
> >   */
> >  
> > +extern volatile sig_atomic_t cl_sighup;
> > +extern volatile sig_atomic_t cl_sigint;
> > +extern volatile sig_atomic_t cl_sigterm;
> > +extern volatile sig_atomic_t cl_sigwinch;
> > +
> >  typedef struct _cl_private {
> > CHAR_T   ibuf[256]; /* Input keys. */
> >  
> > @@ -45,11 +50,7 @@ typedef struct _cl_private {
> >  #defineCL_RENAME_OK0x0004  /* User wants the windows renamed. */
> >  #defineCL_SCR_EX_INIT  0x0008  /* Ex screen initialized. */
> >  #defineCL_SCR_VI_INIT  0x0010  /* Vi screen initialized. */
> > -#defineCL_SIGHUP   0x0020  /* SIGHUP arrived. */
> > -#defineCL_SIGINT   0x0040  /* SIGINT arrived. */
> > -#defineCL_SIGTERM  0x0080  /* SIGTERM arrived. */
> > -#defineCL_SIGWINCH 0x0100  /* SIGWINCH arrived. */
> > -#defineCL_STDIN_TTY0x0200  /* Talking to a terminal. */
> > +#defineCL_STDIN_TTY0x0020  /* Talking to a terminal. */
> > u_int32_t flags;
> >  } CL_PRIVATE;
> >  
> > Index: cl/cl_funcs.c
> > ===
> > RCS file: /cvs/src/usr.bin/vi/cl/cl_funcs.c,v
> > retrieving revision 1.20
> > diff -u -p -r1.20 cl_funcs.c
> > --- cl/cl_funcs.c   27 May 2016 09:18:11 -  1.20
> > +++ cl/cl_funcs.c   24 Aug 2021 23:34:27 -
> > @@ -601,7 +601,7 @@ cl_suspend(SCR *sp, int *allowedp)
> > if (cl_ssize(sp, 1, NULL, NULL, ))
> > return (1);
> > if (changed)
> > -   F_SET(CLP(sp), CL_SIGWINCH);
> > +   cl_sigwinch = 1;
> >  
> > return (0);
> >  }
> > Index: cl/cl_main.c
> > ===
> > RCS file: /cvs/src/usr.bin/vi/cl/cl_main.c,v
> > retrieving revision 1.33
> > diff -u -p -r1.33 cl_main.c
> > --- cl/cl_main.c5 May 2016 20:36:41 -   1.33
> > +++ cl/cl_main.c24 Aug 2021 23:34:27 -
> > @@ -33,6 +33,11 @@
> >  
> >  GS *__global_list; /* GLOBAL: List of screens. */
> >  
> > +volatile sig_atomic_t cl_sighup;
> > +volatile sig_atomic_t cl_sigint;
> > +volatile sig_atomic_t cl_sigterm;
> > +volatile sig_atomic_t cl_sigwinch;
> > +
> >  static void   cl_func_std(GS *);
> >  static CL_PRIVATE *cl_init(GS *);
> >  static GS*gs_init(void);
> > @@ -217,16 +222,14 @@ h_hup(int signo)
> >  {
> > GLOBAL_CLP;
> >  
> > -   F_SET(clp, CL_SIGHUP);
> > +   cl_sighup = 1;
> > clp->killersig = SIGHUP;
> >  }
> >  
> >  static void
> >  h_int(int signo)
> >  {
> > -   GLOBAL_CLP;
> > -
> > -   F_SET(clp, CL_SIGINT);
> > +   cl_sigint = 1;
> >  }
> >  
> >  static void
> > @@ -234,16 +237,14 @@ h_term(int signo)
> >  {
> > GLOBAL_CLP;
> >  
> > -   F_SET(clp, CL_SIGTERM);
> > +   cl_sigterm = 1;
> > clp->killersig = SIGTERM;
> >  }
> >  
> >  static void
> >  h_winch(int signo)
> >  {
> > -   GLOBAL_CLP;
> > -
> > -   F_SET(clp, CL_SIGWINCH);
> > +   cl_sigwinch = 1;
> >  }
> >  #undef GLOBAL_CLP
> >  
> > @@ -259,6 +260,11 @@ sig_init(GS *gp, SCR *sp)
> > CL_PRIVATE *clp;
> >  
> > clp = GCLP(gp);
> > +
> > +   cl_sighup = 0;
> > +   cl_sigint = 0;
> > +   cl_sigterm = 0;
> > +   cl_sigwinch = 0;
> >  
> > if (sp == NULL) {
> > if (setsig(SIGHUP, >oact[INDX_HUP], 

Re: cal(1): Clean up mutually exclusive options

2021-08-16 Thread Martijn van Duren
Ok, I'll drop the diff. I misunderstood our previous conversation.
Sorry for the stir it caused.

On Mon, 2021-08-16 at 12:31 +0200, Ingo Schwarze wrote:
> Hi Martijn,
> 
> Martijn van Duren wrote on Sun, Aug 15, 2021 at 11:40:49PM +0200:
> > To quote schwarze in the jot mutually exclusive thread:
> > On Fri, 2021-08-13 at 11:48 +0200, Ingo Schwarze wrote:
> 
> > > In this case, even though this is not a POSIX command, POSIX utility
> > > convention 12.2.11 is pertinent:
> > > 
> > >   The order of different options relative to one another should not
> > >   matter, unless the options are documented as mutually-exclusive
> > >   and such an option is documented to override any incompatible
> > >   options preceding it.  If an option that has option-arguments is
> > >   repeated, the option and option-argument combinations should be
> > >   interpreted in the order specified on the command line.
> 
> > This is also violated by cal(1)
> 
> You seem to misunderstand.
> 
> The cal(1) utility does *not* violate this syntax guideline.
> It neither has options where the order on the command line matters
> nor options that take arguments, so this guideline simply makes
> no recommendation whatsoever for cal(1).
> 
> > (and maybe others, but this one came
> > up first). Diff below should fix this.
> 
> I think the diff is not OK.
> 
> It changes established and documented behaviour of a program, and
> you provide no explanation why the new behaviour would be more
> useful than the old one.  Also, considering whether this might or
> might not cause compatibility issues would would be required.
> 
> Compatibility issues may be unlikely because it merely defines new
> behaviour for something that is now a syntax error.  That alone does
> not make the change useful, though.
> 
> The change itself seems illogical and confusing to me.  If a user
> says "i want days numbered consecutively from Jan 1 *and* week
> numbers displayed in addition", why should the first half of the
> request be ignored?  And worse, *silently* ignored?  Both halfs of
> the request are unrelated to each other, so both one overriding
> the other and their effect depending on their order would seem
> surprising and hardly useful.
> 
> Also, allowing additional syntax makes the user interface more
> complex, which should not be done without a very good reason.
> 
> Finally, even *if* we would decide to make the UI more complex and
> allow -jw and -wj (i see no pressing need because -j does not seem
> all that useful in the first place, and needing both at the same
> time would be an even less common task), then the logical behaviour
> would be to simply honour both at the the same time.  So your change
> not only makes the UI more complex without a good reason.  It also
> blocks syntax space that could, in the future, possibly be assigned
> to more useful functionality.
> 
> I admit there are no strong logical reasons why these two options
> have to mutually exclusive.  That's seems merely an implementation
> choice to keep the command and documentation simpler.  Nothing is
> wrong with having some (not usually needed) functionality unimplemented
> in a program.  In this case, this is even properly documented.
> 
> To summarize, i oppose the diff as a whole, and i see not parts in
> it that could be salvaged.
> 
> Yours,
>   Ingo
> 
> 
> > Index: cal.1
> > ===
> > RCS file: /cvs/src/usr.bin/cal/cal.1,v
> > retrieving revision 1.31
> > diff -u -p -r1.31 cal.1
> > --- cal.1   27 Nov 2016 10:37:22 -  1.31
> > +++ cal.1   15 Aug 2021 21:39:28 -
> > @@ -53,11 +53,8 @@ The options are as follows:
> >  .Bl -tag -width Ds
> >  .It Fl j
> >  Display Julian dates (days one-based, numbered from January 1).
> > -The options
> > -.Fl j
> > -and
> > -.Fl w
> > -are mutually exclusive.
> > +Overrides earlier
> > +.Fl w .
> >  .It Fl m
> >  Display weeks starting on Monday instead of Sunday.
> >  .It Fl w
> > @@ -65,11 +62,8 @@ Display week numbers in the month displa
> >  If
> >  .Fl m
> >  is specified the ISO week format is assumed.
> > -The options
> > -.Fl j
> > -and
> > -.Fl w
> > -are mutually exclusive.
> > +Overrides earlier
> > +.Fl j .
> >  .It Fl y
> >  Display a calendar for the current year.
> >  .El
> > Index: cal.c
> > ===
> > RCS file: /cvs/src/usr.bin/cal/cal.c,v
> > retrieving revision

Re: snmpd: allow sending traps with SNMPv3

2021-08-16 Thread Martijn van Duren
On Mon, 2021-08-16 at 22:45 +1000, Jonathan Matthew wrote:
> On Tue, Aug 10, 2021 at 12:58:05PM +0200, Martijn van Duren wrote:
> > On Mon, 2021-08-09 at 21:44 +0200, Martijn van Duren wrote:
> > > On Tue, 2021-07-27 at 21:28 +0200, Martijn van Duren wrote:
> > > > This diff allows sending traps in SNMPv3 messages.
> > > > It defaults to the global seclevel, but it can be specified on a per
> > > > rule basis.
> > > > 
> > > > Diff requires both previous setting engineid and ober_dup diff.
> > > > 
> > > > Tested with netsnmp's snmptrapd and my WIP diff.
> > > > 
> > > > The other 2 outstanding diffs are for receiving SNMPv3 traps.
> > > > 
> > > > OK?
> > > > 
> > > > martijn@
> > > > 
> > > Resending now that the engineid diff is in.
> > > 
> > > Still awaiting the commit of ober_dup diff[0].
> > > 
> > > OK once that one goes in?
> > > 
> > > Also, rereading the diff, splitting the trap receiver in two might be a
> > > bit clutch. Once again invoking the manpage gurus.
> > > 
> > > martijn@
> > > 
> > > [0] https://marc.info/?l=openbsd-tech=162698527126249=2
> > > 
> > The listen on diff committed this morning broke this patch.
> > Updated version
> 
> I think my only concern with this is that the config syntax changes
> incompatibly, since you now have to specify 'snmpv2c' for v2c trap
> receivers.  I can think of a few alternatives, but none of them are
> great.  What you've done here seems to be the cleanest option both in
> terms of what the config looks like and the code for processing it,
> so if we're prepared to change the config syntax, I'm happy with it.
> 
To make v3 the default is the logical conclusion of the reason moves
away from SNMPv2c in general for our SNMP stack. We've disabled SNMPv2c
for listen on in snmpd(8), including trap handle. We've removed default
communities (including "trap community"), so enabling snmpv2c on a
notify listener will not even make the receiver work without explicitly
setting that community. And similar for "trap receiver", without setting
either the global "trap community" or the "trap receiver" local
community it will not work.
It would be easy enough to enable keep snmpv2c the default for trap
receiver, but considering the general direction it just seems pointless.

In other words, this change is intentional and I assumed that people
interested in OKing this diff were aware enough of the recent changes
to understand this context of changing defaults. Sorry that that wasn't
clear.

If noone else objects I'll commit as soon as I get the green light for
the libutil bump. Thanks for checking.



Re: sed(1): line addresses and next cycle

2021-08-16 Thread Martijn van Duren
On Mon, 2021-08-16 at 08:25 -0600, Todd C. Miller wrote:
> On Sun, 15 Aug 2021 23:56:54 +0200, Andreas Kusalananda 
> =?utf-8?B?S8OkaMOkcmk=?
> = wrote:
> 
> > But note that this comes out of a discussion on how to do '0,/re/'
> > addressing with OpenBSD sed.  Your changes appears to remove one way of
> > actually handling a match of '/re/' on the first line without giving us
> > another.  It would be better to have a clean way of doing the equivalent
> > of '0,/re/' than to remove a way to do this.  Interestingly (?), the sed
> > in plan9port works the same as our native sed.
> 
> As does AT sed on Solaris.  Since our sed currently matches the
> behavior of the "canonical" sed, I don't see a reason to change it.
> 
>  - todd
Ack. Like I said, just putting some feelers out. I'll drop the idea.



cal(1): Clean up mutually exclusive options

2021-08-15 Thread Martijn van Duren
To quote schwarze in the jot mutually exclusive thread:
On Fri, 2021-08-13 at 11:48 +0200, Ingo Schwarze wrote:
> In this case, even though this is not a POSIX command, POSIX utility
> convention 12.2.11 is pertinent:
> 
>   The order of different options relative to one another should not
>   matter, unless the options are documented as mutually-exclusive
>   and such an option is documented to override any incompatible
>   options preceding it.  If an option that has option-arguments is
>   repeated, the option and option-argument combinations should be
>   interpreted in the order specified on the command line.

This is also violated by cal(1) (and maybe others, but this one came
up first). Diff below should fix this.

OK?

martijn@

Index: cal.1
===
RCS file: /cvs/src/usr.bin/cal/cal.1,v
retrieving revision 1.31
diff -u -p -r1.31 cal.1
--- cal.1   27 Nov 2016 10:37:22 -  1.31
+++ cal.1   15 Aug 2021 21:39:28 -
@@ -53,11 +53,8 @@ The options are as follows:
 .Bl -tag -width Ds
 .It Fl j
 Display Julian dates (days one-based, numbered from January 1).
-The options
-.Fl j
-and
-.Fl w
-are mutually exclusive.
+Overrides earlier
+.Fl w .
 .It Fl m
 Display weeks starting on Monday instead of Sunday.
 .It Fl w
@@ -65,11 +62,8 @@ Display week numbers in the month displa
 If
 .Fl m
 is specified the ISO week format is assumed.
-The options
-.Fl j
-and
-.Fl w
-are mutually exclusive.
+Overrides earlier
+.Fl j .
 .It Fl y
 Display a calendar for the current year.
 .El
Index: cal.c
===
RCS file: /cvs/src/usr.bin/cal/cal.c,v
retrieving revision 1.30
diff -u -p -r1.30 cal.c
--- cal.c   9 Oct 2015 01:37:06 -   1.30
+++ cal.c   15 Aug 2021 21:39:28 -
@@ -158,12 +158,14 @@ main(int argc, char *argv[])
switch(ch) {
case 'j':
julian = 1;
+   wflag = 0;
break;
case 'm':
mflag = 1;
break;
case 'w':
wflag = 1;
+   julian = 0;
break;
case 'y':
yflag = 1;
@@ -174,9 +176,6 @@ main(int argc, char *argv[])
}
argc -= optind;
argv += optind;
-
-   if (julian && wflag)
-   usage();
 
day_headings = DAY_HEADINGS_S;
sep1752 = sep1752s;




sed(1): line addresses and next cycle

2021-08-15 Thread Martijn van Duren
Andreas Kähäri gave a nice example on misc@ on how our sed addressing
implemenation differs from gsed[0][1]. While writing my reply I noticed
that POSIX doesn't state how "next cycle" should be interpreted when it
comes to address ranges. So I can't state that our implementation is
wrong per se. However, I do think that gsed's interpretation is more
intuitive, since a numeric address is not dependent on the context of
the pattern space and thus should register as "in range".

Diff below changes program parsing to more closely match gsed in this
regard:
$ printf 'test1\nbla1\ntest2\nbla2\n' | sed -e '1 { /^test/d; }' -e 
'1,/^test/d'  
bla1
test2
bla2
$ printf 'test1\nbla1\ntest2\nbla2\n' | ./obj/sed -e '1 { /^test/d; }' -e 
'1,/^test/d'  
bla2
$ printf 'bla0\ntest1\nbla1\ntest2\nbla2\n' | ./obj/sed -e '1 { /^test/d; }' -e 
'1,/^test/d'
bla1
test2
bla2
$ printf 'test1\nbla1\ntest2\nbla2\n' | gsed -e '1 { /^test/d; }' -e 
'1,/^test/d' 
bla2
$ printf 'bla0\ntest1\nbla1\ntest2\nbla2\n' | gsed -e '1 { /^test/d; }' -e 
'1,/^test/d'
bla1
test2
bla2

The diff passes regress, but hasn't had a lot of scrutiny. Just checking
for general interest in changing this functionality. As soon as I
know that it's something we might want I'll spend more braincycles on
it.

martijn@

[0] https://marc.info/?l=openbsd-misc=162896537001890=2
[1] https://marc.info/?l=openbsd-misc=162905748428954=2

Index: process.c
===
RCS file: /cvs/src/usr.bin/sed/process.c,v
retrieving revision 1.34
diff -u -p -r1.34 process.c
--- process.c   14 Nov 2018 10:59:33 -  1.34
+++ process.c   15 Aug 2021 21:30:22 -
@@ -89,14 +89,16 @@ process(void)
SPACE tspace;
size_t len, oldpsl;
char *p;
+   int nextcycle;
 
for (linenum = 0; mf_fgets(, REPLACE);) {
pd = 0;
+   nextcycle = 0;
 top:
cp = prog;
 redirect:
while (cp != NULL) {
-   if (!applies(cp)) {
+   if (!applies(cp) || nextcycle) {
cp = cp->next;
continue;
}
@@ -127,14 +129,16 @@ redirect:
break;
case 'd':
pd = 1;
-   goto new;
+   nextcycle = 1;
+   break;
case 'D':
if (pd)
goto new;
if (psl == 0 ||
(p = memchr(ps, '\n', psl)) == NULL) {
pd = 1;
-   goto new;
+   nextcycle = 1;
+   break;
} else {
psl -= (p + 1) - ps;
memmove(ps, p + 1, psl);
@@ -267,8 +271,9 @@ new:if (!nflag && !pd)
  * (lastline, linenumber, ps).
  */
 #defineMATCH(a)\
-   (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, 0, psl) :\
-   (a)->type == AT_LINE ? linenum == (a)->u.l : lastline()
+   (a)->type == AT_LINE ? linenum == (a)->u.l :\
+   (a)->type == AT_LAST ? lastline() : \
+   pd ? 0 : regexec_e((a)->u.r, ps, 0, 1, 0, psl)
 
 /*
  * Return TRUE if the command applies to the current line.  Sets the inrange




jot(1): putdata de Morgan's rule

2021-08-13 Thread Martijn van Duren
Similar to tb's de Morgan's rule send last night.

Shaves of 4 LoC of putdata and reads easier to me.

regress passes

OK?

martijn@

Index: jot.c
===
RCS file: /cvs/src/usr.bin/jot/jot.c,v
retrieving revision 1.51
diff -u -p -r1.51 jot.c
--- jot.c   30 Jul 2021 02:47:37 -  1.51
+++ jot.c   13 Aug 2021 07:09:41 -
@@ -304,25 +304,21 @@ putdata(double x, bool last)
if (boring)
printf("%s", format);
else if (longdata && nosign) {
-   if (x <= (double)ULONG_MAX && x >= 0.0)
-   printf(format, (unsigned long)x);
-   else
+   if (x < 0.0 || x > (double)ULONG_MAX)
return 1;
+   printf(format, (unsigned long)x);
} else if (longdata) {
-   if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
-   printf(format, (long)x);
-   else
+   if (x < (double)LONG_MIN || x > (double)LONG_MAX)
return 1;
+   printf(format, (long)x);
} else if (chardata || (intdata && !nosign)) {
-   if (x <= (double)INT_MAX && x >= (double)INT_MIN)
-   printf(format, (int)x);
-   else
+   if (x < (double)INT_MIN || x > (double)INT_MAX)
return 1;
+   printf(format, (int)x);
} else if (intdata) {
-   if (x <= (double)UINT_MAX && x >= 0.0)
-   printf(format, (unsigned int)x);
-   else
+   if (x < 0.0 || x > (double)UINT_MAX)
return 1;
+   printf(format, (unsigned int)x);
} else
printf(format, x);
if (!last)




jot(1): rename 's' to 'step'

2021-08-13 Thread Martijn van Duren
Historically 's' presumably stood both for step and seed, but since we
don't support seed anymore I think it's wise to make things a little
more readable and just rename 's' to 'step'.

tb@ already agrees with the concept.

OK?

martijn@

Index: jot.1
===
RCS file: /cvs/src/usr.bin/jot/jot.1,v
retrieving revision 1.23
diff -u -p -r1.23 jot.1
--- jot.1   12 Aug 2016 21:49:31 -  1.23
+++ jot.1   13 Aug 2021 06:57:56 -
@@ -45,7 +45,7 @@
 .Op Fl s Ar string
 .Op Fl w Ar word
 .Oo Ar reps Oo Ar begin Oo Ar end
-.Oo Ar s Oc Oc Oc Oc
+.Oo Ar step Oc Oc Oc Oc
 .Ek
 .Sh DESCRIPTION
 .Nm
@@ -115,7 +115,7 @@ The default values for
 .Ar begin ,
 .Ar end ,
 and
-.Ar s
+.Ar step
 are 100, 1, 100, and 1, respectively.
 Omitted values are computed if possible or assume the default.
 A special case arises if only
@@ -128,7 +128,7 @@ if
 is greater than
 .Ar end
 then
-.Ar s
+.Ar step
 is set to \(mi1, otherwise it is set to 1;
 afterwards
 .Ar reps
@@ -149,7 +149,7 @@ Random numbers are obtained through
 Historical versions of
 .Nm
 used
-.Ar s
+.Ar step
 to seed the random number generator.
 This is no longer supported.
 The name




jot(1): make -b -c and -w mutually exclusive

2021-08-13 Thread Martijn van Duren
Looking at tb's diff I fell in the trap of looking at other parts of the
code. Now he's conning me into writing diffs...

So here's the first one:
- When -b is set, but followed by -w it doesn't remove the boring flag
  and the -w is interpreted as a -b string
- -c is defined as "This is an abbreviation for -w %c.", but adding a
  -w option itself results in:
  $ jot -cw"bla " 5 97
  bla a
  bla b
  bla c
  bla d
  bla e

  instead of

  $ jot -w"bla " 5 97 
  bla 97
  bla 98
  bla 99
  bla 100
  bla 101
- -b always overwrites -c.

tb already agrees that these options should be mutually exlusive, so
here's the accompanying code. I choose to go for the last option wins
appraoch, similar to ls, df, du, ...

Regress seems to pass.

OK?

martijn@

Index: jot.1
===
RCS file: /cvs/src/usr.bin/jot/jot.1,v
retrieving revision 1.23
diff -u -p -r1.23 jot.1
--- jot.1   12 Aug 2016 21:49:31 -  1.23
+++ jot.1   13 Aug 2021 06:50:42 -
@@ -101,6 +101,15 @@ conversion specification inside
 in which case the data is inserted rather than appended.
 .El
 .Pp
+It is not an error to specify more than one of
+the mutually exclusive options
+.Fl b ,
+.Fl c
+and
+.Fl w .
+Where more than one of these options is specified,
+the last option given overrides the others.
+.Pp
 The last four arguments specify the length of the output sequence,
 its start and end points, and the step size.
 Any three of these arguments determine the fourth.
Index: jot.c
===
RCS file: /cvs/src/usr.bin/jot/jot.c,v
retrieving revision 1.51
diff -u -p -r1.51 jot.c
--- jot.c   30 Jul 2021 02:47:37 -  1.51
+++ jot.c   13 Aug 2021 06:50:42 -
@@ -86,6 +86,7 @@ main(int argc, char *argv[])
int n = 0;
int ch;
const char  *errstr;
+   boolword;
 
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
@@ -94,10 +95,13 @@ main(int argc, char *argv[])
switch (ch) {
case 'b':
boring = true;
+   chardata = word = false;
format = optarg;
break;
case 'c':
chardata = true;
+   boring = word = false;
+   format = "";
break;
case 'n':
finalnl = false;
@@ -115,6 +119,8 @@ main(int argc, char *argv[])
sepstring = optarg;
break;
case 'w':
+   word = true;
+   boring = chardata = false;
format = optarg;
break;
default:




Re: fresh prompt after Ctrl-C in cdio(1)

2021-08-12 Thread Martijn van Duren
On Thu, 2021-08-12 at 15:57 +0200, Ingo Schwarze wrote:
> Hi,
> 
> deraadt@ recently pointed out to me in private mail that it is good
> for usability if interactive programs providing line editing
> functionality are consistent what they do with Ctrl-C, ideally
> discard the current input line and provide a fresh prompt.
> At least that is what bc(1), ftp(1), sftp(1) and all shells do.
> 
> So i propose to do the same in cdio(1), which currently just exits
> on Ctrl-C.
> 
> Sending to tech@ because i'm not quite sure which developer owns cdio(1),
> or who might be interested.  According to the CVS logs, naddy@ was the
> last one to change user-visible functionality, and before that, there
> was nothing but bug fixes and cleanup since 2010.
> 
> OK?
>   Ingo
> 
> P.S.
> Note that the current "!siz" is fragile; el_gets(3) sets it to -1
> on error.  I'm polishing that while here.
> 
> P.P.S.
> buf = (char *)el_gets(...) is ugly and potentially dangerous, the
> manual page explicitly warns to not do that, but that's a job for
> another day.
> 
> P.P.P.S.
> Insects are the most successful class of animals on earth.
> Even in OpenBSD, it is rarely possible to look at code without
> finding something unrelated that could be improved, too.

Maybe I've used cdio once or twice and I don't have a cd-player at hand
(at least connected to my workstation) to test this. So purely from code
inspection: You set the signal handler before entering el_gets and you
ignore it right after.

Wouldn't this imply that if you do something like "cdplay" at the prompt
and while you wait for the cd to spin you hit ^C the application just
exits? If so, wouldn't it make more sense to install the signal handler
once and let open_cd() handle EINTR as well and just return to the prompt?

Something that springs to is
cdio> play
^C
cdio> cdplay

> 
> 
> Index: cdio.c
> ===
> RCS file: /cvs/src/usr.bin/cdio/cdio.c,v
> retrieving revision 1.80
> diff -u -p -r1.80 cdio.c
> --- cdio.c  18 Jan 2021 00:44:00 -  1.80
> +++ cdio.c  12 Aug 2021 13:36:38 -
> @@ -63,6 +63,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -158,6 +159,7 @@ int verbose = 1;
>  intmsf = 1;
>  const char *cddb_host;
>  char   **track_names;
> +volatile sig_atomic_t signo;
>  
>  EditLine   *el = NULL; /* line-editing structure */
>  History*hist = NULL;   /* line-editing history */
> @@ -179,6 +181,7 @@ int pstatus(char *arg);
>  intplay_next(char *arg);
>  intplay_prev(char *arg);
>  intplay_same(char *arg);
> +void   sigint_handler(int);
>  char   *input(int *);
>  char   *prompt(void);
>  void   prtrack(struct cd_toc_entry *e, int lastflag, char *name);
> @@ -1499,18 +1502,36 @@ status(int *trk, int *min, int *sec, int
> return s.data->header.audio_status;
>  }
>  
> +void
> +sigint_handler(int signo_arg)
> +{
> +   signo = signo_arg;
> +}
> +
>  char *
>  input(int *cmd)
>  {
> +   struct sigaction sa;
> char *buf;
> int siz = 0;
> char *p;
> HistEvent hev;
>  
> +   memset(, 0, sizeof(sa));
> do {
> -   if ((buf = (char *) el_gets(el, )) == NULL || !siz) {
> -   *cmd = CMD_QUIT;
> +   signo = 0;
> +   sa.sa_handler = sigint_handler;
> +   if (sigaction(SIGINT, , NULL) == -1)
> +   err(1, "sigaction");
> +   buf = (char *)el_gets(el, );
> +   sa.sa_handler = SIG_DFL;
> +   if (sigaction(SIGINT, , NULL) == -1)
> +   err(1, "sigaction");
> +   if (buf == NULL || siz <= 0) {
> fprintf(stderr, "\r\n");
> +   if (siz < 0 && errno == EINTR && signo == SIGINT)
> +   continue;
> +   *cmd = CMD_QUIT;
> return (0);
> }
> if (strlen(buf) > 1)
> 




Re: snmp(1): Fix unsafe defaults

2021-08-11 Thread Martijn van Duren
On Wed, 2021-08-11 at 18:59 +0100, Stuart Henderson wrote:
> On 2021/08/11 19:34, Martijn van Duren wrote:
> > On Wed, 2021-08-11 at 18:03 +0100, Stuart Henderson wrote:
> > > On 2021/08/11 16:35, Martijn van Duren wrote:
> > > > Following snmpd, remove the public default community and move to snmpv3
> > > > by default. This is also what net-snmp does. I originally chose this
> > > > default because that's what snmpctl did and it allowed for easier
> > > > interoperability with snmpd(8).
> > > 
> > > v3 by default makes sense to me.
> > > 
> > > I'm not sure how much it buys to remove the default community in snmp(1),
> > > though, there doesn't seem a lot of benefit to removing it?
> > 
> > My reasoning being that setting having public the default in snmp(1)
> > might encourage users to set public in snmpd(8) as well, which is what
> > we tried to discourage.
> 
> Hmm maybe. I won't object to that.
> 
> 
Forgot the manpage bits.

OK?

martijn@

Index: snmp.1
===
RCS file: /cvs/src/usr.bin/snmp/snmp.1,v
retrieving revision 1.19
diff -u -p -r1.19 snmp.1
--- snmp.1  8 Aug 2021 13:41:26 -   1.19
+++ snmp.1  11 Aug 2021 18:22:18 -
@@ -303,12 +303,11 @@ Show how long it took to walk the entire
 Set the
 .Ar community
 string.
-Defaults to
-.Cm public .
 This option is only used by
 .Fl v Cm 1
 and
-.Fl v Cm 2c .
+.Fl v Cm 2c
+and has no default.
 .It Fl e Ar secengineid
 The USM security engine id.
 Under normal circumstances this value is discovered via snmpv3 discovery and
@@ -425,7 +424,7 @@ to either
 or
 .Cm 3 .
 Currently defaults to
-.Cm 2c .
+.Cm 3 .
 .It Fl X Ar privpass
 The privacy password for the user.
 This will be tansformed to
Index: snmpc.c
===
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.35
diff -u -p -r1.35 snmpc.c
--- snmpc.c 8 Aug 2021 13:41:26 -   1.35
+++ snmpc.c 11 Aug 2021 18:22:18 -
@@ -84,12 +84,12 @@ struct snmp_app snmp_apps[] = {
 };
 struct snmp_app *snmp_app = NULL;
 
-char *community = "public";
+char *community = NULL;
 struct snmp_v3 *v3;
 char *mib = "mib_2";
 int retries = 5;
 int timeout = 1;
-enum snmp_version version = SNMP_V2C;
+enum snmp_version version = SNMP_V3;
 int print_equals = 1;
 int print_varbind_only = 0;
 int print_summary = 0;
@@ -468,7 +468,10 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
 
-   if (version == SNMP_V3) {
+   if (version == SNMP_V1 || version == SNMP_V2C) {
+   if (community == NULL || community[0] == '\0')
+   errx(1, "No community name specified.");
+   } else if (version == SNMP_V3) {
/* Setup USM */
if (user == NULL || user[0] == '\0')
errx(1, "No securityName specified");




Re: snmp(1): Fix unsafe defaults

2021-08-11 Thread Martijn van Duren
On Wed, 2021-08-11 at 18:59 +0100, Stuart Henderson wrote:
> On 2021/08/11 19:34, Martijn van Duren wrote:
> > On Wed, 2021-08-11 at 18:03 +0100, Stuart Henderson wrote:
> > > On 2021/08/11 16:35, Martijn van Duren wrote:
> > > > Following snmpd, remove the public default community and move to snmpv3
> > > > by default. This is also what net-snmp does. I originally chose this
> > > > default because that's what snmpctl did and it allowed for easier
> > > > interoperability with snmpd(8).
> > > 
> > > v3 by default makes sense to me.
> > > 
> > > I'm not sure how much it buys to remove the default community in snmp(1),
> > > though, there doesn't seem a lot of benefit to removing it?
> > 
> > My reasoning being that setting having public the default in snmp(1)
> > might encourage users to set public in snmpd(8) as well, which is what
> > we tried to discourage.
> 
> Hmm maybe. I won't object to that.
> 
> > And it's easy enough to do something like
> > alias snmp_get="snmp get -v2c -ccommunity"
> > in .profile for interactive use
> 
> and walk, bulkwalk, df, [...]
> 
> FWIW I have this for now.
> 
> -
> #!/bin/ksh
> if [[ -z $2 ]]; then
> /usr/bin/snmp 2>&1 | sed "s/snmp/`basename $0`/" >&2
> exit 1
> fi
> cmd=$1
> shift
> exec /usr/bin/snmp $cmd -v 3 -l authPriv -u xxx [etc] $*
> -
> 
> > and in scripts you always want to be
> > explicit with such parameters.
> 
> Maybe. I do quite like keeping the secrets out of ps/top though.
> 
> While I'm thinking about it, thoughts on this?

No objection from me.
OK martijn@
> 
> Index: snmpd.conf.5
> ===
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
> retrieving revision 1.56
> diff -u -p -r1.56 snmpd.conf.5
> --- snmpd.conf.510 Aug 2021 07:53:57 -  1.56
> +++ snmpd.conf.511 Aug 2021 17:57:53 -
> @@ -402,12 +402,13 @@ Example configuration file.
>  .Sh EXAMPLES
>  The following example will tell
>  .Xr snmpd 8
> -to listen on localhost for SNMPv2c messages only with the public community,
> -override the default system OID, set the magic services value and provides 
> some
> -custom OID values:
> +to listen on localhost for SNMPv2c messages only with the community
> +.Dq 8LHQtm1QLGzk ,
> +override the default system OID, set the magic services value,
> +and provide some custom OID values:
>  .Bd -literal -offset indent
>  listen on 127.0.0.1 snmpv2c
> -read-only community public
> +read-only community 8LHQtm1QLGzk
>  
>  system oid 1.3.6.1.4.1.30155.23.2
>  system services 74
> 




Re: libedit: stop playing hopeless games with FIONBIO

2021-08-11 Thread Martijn van Duren
On Wed, 2021-08-11 at 18:50 +0200, Ingo Schwarze wrote:
> Hi,
> 
> in its current state, the editline(3) library is completely unfit
> to work with non-blocking I/O.  Neither the API nor the implementation
> are even designed for that purpose.
> 
> I do have some candidate ideas to minimally extend the API - without
> adding any new functions - to also work with non-blocking I/O, but
> frankly, i don't see any sane use case for it yet.  Why would anyone
> desire to mix non-blocking I/O and interactive line editing with the
> editline(3) library on the same file descriptor?

I can't think of anything. If you want to combine with something that
also uses other resources you should probably put something like kqueue
in front of it anyway.
That being said and a completely different issue: if this construct is
the case and someone enters a single byte of a UTF-8 character your
whole event-based system grinds to a halt until the rest of the
character is read.
> 
> Consequently, i propose that we document the facts up front and
> simply delete some code that isn't going to do any good in practice.
> For programs not using non-blocking I/O on the editline input file
> descriptor, this patch makes no difference.  Programs that do set
> FIONBIO on a file descriptor and then call editline(3) on it anyway
> can't possibly work as intended as far as i can see.  Either setting
> FIONBIO is needless in the first place, or el_gets(3) clearing it
> will ruin the rest of the program's functionality.
> 
> Do any of you have any doubts, and if so, which ones?

Sounds reasonable, but I'm not aware enough of the libedit consumers
to make a definitive statement.
Patch reads mostly OK to me.
> 
> Or is anybody willing to OK this patch?
> 
> 
> If soembody comes up with a sane use case for mixing FIONBIO with
> editline(3) at a later point in time, we can still consider my plans
> to make that work.  In that case, deleting the junk deleted by this
> patch would be required as the first step anyway.
> 
> 
> I'm appending a simple test program at the end.
> 
> Before the patch:
> 
>   nbio is on
>   ?test
>   the user said: test
>   nbio is off    /* oops, what is this? */
> 
> After the patch:
> 
>   nbio is on
>   ?progname: el_gets: Resource temporarily unavailable
> 
> I think the latter makes more sense and is less surprising.
> 
> Yours,
>   Ingo
> 
> 
> Index: editline.3
> ===
> RCS file: /cvs/src/lib/libedit/editline.3,v
> retrieving revision 1.46
> diff -u -p -r1.46 editline.3
> --- editline.3  22 May 2016 22:08:42 -  1.46
> +++ editline.3  11 Aug 2021 16:20:00 -
> @@ -169,6 +169,20 @@ Programs should be linked with
>  .Pp
>  The
>  .Nm
> +library is designed to work with blocking I/O only.
> +If the
> +.Dv FIONBIO
> +.Xr ioctl 2

I'm not sure if FIONBIO should be mentioned here.
Else you would also have to mention O_NONBLOCK and O_NDELAY.

> +is set on
> +.Ar fin ,
> +.Fn el_gets
> +and
> +.Fn el_wgets
> +will almost certainly fail with
> +.Ar EAGAIN .
> +.Pp
> +The
> +.Nm
>  library respects the
>  .Ev LC_CTYPE
>  locale set by the application program and never uses
> Index: read.c
> ===
> RCS file: /cvs/src/lib/libedit/read.c,v
> retrieving revision 1.47
> diff -u -p -r1.47 read.c
> --- read.c  11 Aug 2021 15:13:46 -  1.47
> +++ read.c  11 Aug 2021 16:20:00 -
> @@ -66,7 +66,6 @@ struct el_read_t {
> int  read_errno;
>  };
>  
> -static int read__fixio(int, int);
>  static int read_char(EditLine *, wchar_t *);
>  static int read_getcmd(EditLine *, el_action_t *, wchar_t *);
>  static voidread_clearmacros(struct macros *);
> @@ -132,26 +131,6 @@ el_read_getfn(struct el_read_t *el_read)
>  }
>  
>  
> -/* read__fixio():
> - * Try to recover from a read error
> - */
> -static int
> -read__fixio(int fd, int e)
> -{
> -   int zero = 0;
> -
> -   switch (e) {
> -   case EAGAIN:
> -   if (ioctl(fd, FIONBIO, ) == -1)
> -   return -1;
> -   return 0;
> -
> -   default:
> -   return -1;
> -   }
> -}
> -
> -
>  /* el_push():
>   * Push a macro
>   */
> @@ -231,15 +210,12 @@ static int
>  read_char(EditLine *el, wchar_t *cp)
>  {
> ssize_t num_read;
> -   int tried = 0;
> char cbuf[MB_LEN_MAX];
> int cbp = 0;
> -   int save_errno = errno;
>  
>   again:
> el->el_signal->sig_no = 0;
> while ((num_read = read(el->el_infd, cbuf + cbp, 1)) == -1) {
> -   int e = errno;
> if (errno == EINTR) {
> switch (el->el_signal->sig_no) {
> case SIGCONT:
> @@ -252,14 +228,8 @@ read_char(EditLine *el, wchar_t *cp)
> break;
> }
> }
> -   if (!tried && 

Re: snmp(1): Fix unsafe defaults

2021-08-11 Thread Martijn van Duren
On Wed, 2021-08-11 at 18:03 +0100, Stuart Henderson wrote:
> On 2021/08/11 16:35, Martijn van Duren wrote:
> > Following snmpd, remove the public default community and move to snmpv3
> > by default. This is also what net-snmp does. I originally chose this
> > default because that's what snmpctl did and it allowed for easier
> > interoperability with snmpd(8).
> 
> v3 by default makes sense to me.
> 
> I'm not sure how much it buys to remove the default community in snmp(1),
> though, there doesn't seem a lot of benefit to removing it?

My reasoning being that setting having public the default in snmp(1)
might encourage users to set public in snmpd(8) as well, which is what
we tried to discourage.

And it's easy enough to do something like
alias snmp_get="snmp get -v2c -ccommunity"
in .profile for interactive use and in scripts you always want to be
explicit with such parameters.
> 
> (net-snmp tools do have that, but they also have /etc/snmp/snmp.conf or
> .snmp/snmp.conf so there's less to type on the command line).
> 
> > Now that snmpd(8) moved on, so should snmp(1).
> > 
> > OK?
> > 
> > martijn@
> > 
> > Index: snmpc.c
> > ===
> > RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
> > retrieving revision 1.35
> > diff -u -p -r1.35 snmpc.c
> > --- snmpc.c 8 Aug 2021 13:41:26 -   1.35
> > +++ snmpc.c 11 Aug 2021 14:34:08 -
> > @@ -84,12 +84,12 @@ struct snmp_app snmp_apps[] = {
> >  };
> >  struct snmp_app *snmp_app = NULL;
> >  
> > -char *community = "public";
> > +char *community = NULL;
> >  struct snmp_v3 *v3;
> >  char *mib = "mib_2";
> >  int retries = 5;
> >  int timeout = 1;
> > -enum snmp_version version = SNMP_V2C;
> > +enum snmp_version version = SNMP_V3;
> >  int print_equals = 1;
> >  int print_varbind_only = 0;
> >  int print_summary = 0;
> > @@ -468,7 +468,10 @@ main(int argc, char *argv[])
> > argc -= optind;
> > argv += optind;
> >  
> > -   if (version == SNMP_V3) {
> > +   if (version == SNMP_V1 || version == SNMP_V2C) {
> > +   if (community == NULL || community[0] == '\0')
> > +   errx(1, "No community name specified.");
> > +   } else if (version == SNMP_V3) {
> > /* Setup USM */
> > if (user == NULL || user[0] == '\0')
> > errx(1, "No securityName specified");
> > 
> > 




snmp(1): Fix mibree usage

2021-08-11 Thread Martijn van Duren
Probably not something many people will run into.

$ snmp mibtree -q
snmp: unknown option -- q
usage: snmp mibtree[-O fnS] [oid ...]
$ ./obj/snmp mibtree -q
snmp: unknown option -- q
usage: snmp mibtree [-O fnS] [oid ...]

mibtree is the only one not setting the usecommonopt.

OK?

martijn@

Index: snmpc.c
===
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.35
diff -u -p -r1.35 snmpc.c
--- snmpc.c 8 Aug 2021 13:41:26 -   1.35
+++ snmpc.c 11 Aug 2021 14:47:51 -
@@ -1572,7 +1572,7 @@ usage(void)
"[-E ctxengineid] [-K localpriv] [-k localauth] 
[-l seclevel]\n"
"[-n ctxname] [-O afnqvxSQ] [-r retries] [-t 
timeout] [-u user]\n"
"[-v version] [-X privpass] [-x cipher] [-Z 
boots,time]\n"
-   "" : "",
+   "" : " ",
snmp_app->usage == NULL ? "" : snmp_app->usage);
exit(1);
}




snmp(1): Fix unsafe defaults

2021-08-11 Thread Martijn van Duren
Following snmpd, remove the public default community and move to snmpv3
by default. This is also what net-snmp does. I originally chose this
default because that's what snmpctl did and it allowed for easier
interoperability with snmpd(8).
Now that snmpd(8) moved on, so should snmp(1).

OK?

martijn@

Index: snmpc.c
===
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.35
diff -u -p -r1.35 snmpc.c
--- snmpc.c 8 Aug 2021 13:41:26 -   1.35
+++ snmpc.c 11 Aug 2021 14:34:08 -
@@ -84,12 +84,12 @@ struct snmp_app snmp_apps[] = {
 };
 struct snmp_app *snmp_app = NULL;
 
-char *community = "public";
+char *community = NULL;
 struct snmp_v3 *v3;
 char *mib = "mib_2";
 int retries = 5;
 int timeout = 1;
-enum snmp_version version = SNMP_V2C;
+enum snmp_version version = SNMP_V3;
 int print_equals = 1;
 int print_varbind_only = 0;
 int print_summary = 0;
@@ -468,7 +468,10 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
 
-   if (version == SNMP_V3) {
+   if (version == SNMP_V1 || version == SNMP_V2C) {
+   if (community == NULL || community[0] == '\0')
+   errx(1, "No community name specified.");
+   } else if (version == SNMP_V3) {
/* Setup USM */
if (user == NULL || user[0] == '\0')
errx(1, "No securityName specified");




Re: snmpd: allow sending traps with SNMPv3

2021-08-10 Thread Martijn van Duren
On Mon, 2021-08-09 at 21:44 +0200, Martijn van Duren wrote:
> On Tue, 2021-07-27 at 21:28 +0200, Martijn van Duren wrote:
> > This diff allows sending traps in SNMPv3 messages.
> > It defaults to the global seclevel, but it can be specified on a per
> > rule basis.
> > 
> > Diff requires both previous setting engineid and ober_dup diff.
> > 
> > Tested with netsnmp's snmptrapd and my WIP diff.
> > 
> > The other 2 outstanding diffs are for receiving SNMPv3 traps.
> > 
> > OK?
> > 
> > martijn@
> > 
> Resending now that the engineid diff is in.
> 
> Still awaiting the commit of ober_dup diff[0].
> 
> OK once that one goes in?
> 
> Also, rereading the diff, splitting the trap receiver in two might be a
> bit clutch. Once again invoking the manpage gurus.
> 
> martijn@
> 
> [0] https://marc.info/?l=openbsd-tech=162698527126249=2
> 
The listen on diff committed this morning broke this patch.
Updated version

In case someone wants a quick example of how to test this:
$ cat snmpd.conf
trap receiver 127.0.0.1 user test
user test authkey test1234 auth hmac-sha256 enckey test1234 enc aes
$ doas ./snmpd -df snmpd.conf  
startup
snmpe: listening on udp 0.0.0.0:161
snmpe: listening on udp :::161
snmpe 800075cb81afa75034471524f4b8c3608f47d7f5dff8f28584e99f87d8854128: ready
^C
$ doas cat /etc/snmp/snmptrapd.conf
snmpTrapdAddr 127.0.0.1
createUser -e 
0x800075cb81afa75034471524f4b8c3608f47d7f5dff8f28584e99f87d8854128 test SHA256 
test1234 AES test1234
authUser log test
$ doas snmptrapd -fLe &
[1] 72884
trapd> NET-SNMP version 5.9
$ doas ./snmpd -df snmpd.conf
snmpd> startup
snmpd> snmpe: listening on udp 0.0.0.0:161
snmpd> snmpe: listening on udp :::161
snmpd> snmpe 800075cb81afa75034471524f4b8c3608f47d7f5dff8f28584e99f87d8854128: 
ready
trapd> 2021-08-10 12:50:21 localhost [UDP: [127.0.0.1]:42772->[0.0.0.0]:0]:
trapd> SNMPv2-MIB::sysUpTime.0 = Timeticks: (2) 0:00:00.02 
SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-MIB::coldStart.0

Don't forget to replace my engineid with your personal one in snmptrapd.conf.

martijn@

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.66
diff -u -p -r1.66 parse.y
--- parse.y 10 Aug 2021 06:49:33 -  1.66
+++ parse.y 10 Aug 2021 10:57:36 -
@@ -134,11 +134,11 @@ typedef struct {
 %token HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER PORT
 %token   STRING
 %token   NUMBER
-%typehostcmn
+%typeusmuser community optcommunity
 %typelistenproto listenflag listenflags
 %typesrcaddr port
 %typeoptwrite yesno seclevel
-%type  objtype cmd
+%type  objtype cmd hostauth hostauthv3 usmauthopts usmauthopt
 %type   oid hostoid trapoid
 %type  auth
 %type   enc
@@ -243,13 +243,13 @@ main  : LISTEN ON listen_udptcp
free($3);
}
| TRAP RECEIVER host
-   | TRAP HANDLE hostcmn trapoid cmd {
-   struct trapcmd *cmd = $5.data;
+   | TRAP HANDLE trapoid cmd {
+   struct trapcmd *cmd = $4.data;
 
-   cmd->cmd_oid = $4;
+   cmd->cmd_oid = $3;
 
if (trapcmd_add(cmd) != 0) {
-   free($4);
+   free($3);
free(cmd);
yyerror("duplicate oid");
YYERROR;
@@ -268,8 +268,8 @@ main: LISTEN ON listen_udptcp
| PFADDRFILTER yesno{
conf->sc_pfaddrfilter = $2;
}
-   | SECLEVEL seclevel {
-   conf->sc_min_seclevel = $2;
+   | seclevel {
+   conf->sc_min_seclevel = $1;
}
| USER STRING   {
const char *errstr;
@@ -701,15 +701,93 @@ hostoid   : /* empty */   
{ $$ = NULL; }
| OBJECTID oid  { $$ = $2; }
;
 
-hostcmn: /* empty */   { $$ = NULL; }
-   | COMMUNITY STRING  { $$ = $2; }
+usmuser: USER STRING   {
+   if (strlen($2) > SNMPD_MAXUSERNAMELEN) {
+   yyerror("User name too long: %s", $2);
+   free($2);
+   YYERROR;
+   }
+   $$ = $2;
+   }
+   ;
+
+community  : COMMUNITY STRING

Re: CVS: cvs.openbsd.org: src

2021-08-09 Thread Martijn van Duren
On Mon, 2021-08-09 at 21:58 +0100, Stuart Henderson wrote:
> On 2021/08/09 22:35, Martijn van Duren wrote:
> > Moving to tech@
> > 
> > On Mon, 2021-08-09 at 20:56 +0100, Stuart Henderson wrote:
> > > On 2021/08/09 12:14, Martijn van Duren wrote:
> > > > CVSROOT:/cvs
> > > > Module name:src
> > > > Changes by: mart...@cvs.openbsd.org2021/08/09 12:14:53
> > > > 
> > > > Modified files:
> > > > usr.sbin/snmpd : parse.y snmpd.c snmpd.conf.5 snmpd.h snmpe.c 
> > > >  util.c 
> > > > 
> > > > Log message:
> > > > Allow setting the engineid.
> > > > 
> > > > The previous engineid was based aronud the engine boottime and a random
> > > > value, which gives problems when sending/receiving unacknowledged PDUs
> > > > (trapv2) over SNMPv3 with authentication enabled, which need a 
> > > > consistent
> > > > engineid across restarts to determine the correct user from the sender.
> > > > 
> > > > The new default engineid takes a sha256 hash (chosen for its longer 
> > > > output)
> > > > of gethostname(3) and places the first 27 bytes after the new format 
> > > > number
> > > > 129. This should give us a very low probability of collisions, assuming
> > > > all machines have a unique name.
> > > 
> > > what happens if there's a collision? i'm not sure it's safe to assume
> > > unique names.
> > 
> > The engineid is used to load the engine context of the originator agent.
> > For unacknowledged pdu's this means at least loading the remote users
> > (unlike get requests the users, keys and engineid are from the
> > originator).
> > 
> > If there's a collision for trapv2 this means that if a user exists on
> > both remote agents but with different keys one of them will fail.
> > 
> > But if you want to enter a new user of a new system and you find that
> > that engineid already exist it should be a pretty big red flag that
> > there's a collision and the new system can explicitly set the engineid.
> > Similar if you ever want to set up something like "this engineid can
> > only send from this ip": If you see that a new systems engineid already
> > has such restriction it means you have to manually set the engineid.
> > 
> > For existing get requests we don't have any risk: For acknowledged PDUs
> > (get*/set) the engineid will be discovered (RFC3414 Section 4). And
> > people can't have any hefty restrictions in place as is, because
> > previously it was randomly generated at startup, so no persistent
> > engineid to check on.
> > 
> > I don't see any big risks here.
> > 
> > A minor risk would be that if a hostname ever changes traps won't be
> > received anymore, since the engineid changes. But changing a hostname
> > seems like something that doesn't happen very often and brings with it
> > a lot more migration research.
> > 
> > But considering the question if there was a better idea for generating
> > a consistent engineid by jmatthew@ on the 1st without any feedback I
> > went with this one.
> > If you still feel like there's a risk here after my previous reasoning
> > feel free to come up with an alternative. We still have time to change
> > it, and even then we have the range 130-255 to implement new formats
> > (although then we come back to the discussion about defaults without
> > negotiation)
> > > 
> > > > The other formats as specified in SNMP-FRAMEWORK-MIB (RFC3411) are also
> > > > supported as well as arbitrary formats in the range 128-255 for other
> > > > private enterprise numbers in hex format.
> > > > 
> > > > OK jmatthew@
> > > > 
> > > 
> > 
> > 
> 
> Thanks. I haven't looked closely at this before, I just know that it's
> common for agents to set it randomly at startup (net-snmp docs say "must
> be consistent through time and should not change or conflict with another
> agent's engineID.  Ever." which isn't exactly clear which is the stronger
> requirement - consistency or not conflicting).

I'd say the not changing. Because it determines how a password is
changed to an auth-/priv-key, which is needed to decipher an incoming
unacknowledged trap. However, users will always find some legitimate
reason to change it. But that should be their burden.
If during setup it's found that a conflict occurs it should be fine to
change the engineid, but if you change

Re: CVS: cvs.openbsd.org: src

2021-08-09 Thread Martijn van Duren
Moving to tech@

On Mon, 2021-08-09 at 20:56 +0100, Stuart Henderson wrote:
> On 2021/08/09 12:14, Martijn van Duren wrote:
> > CVSROOT:/cvs
> > Module name:src
> > Changes by: mart...@cvs.openbsd.org2021/08/09 12:14:53
> > 
> > Modified files:
> > usr.sbin/snmpd : parse.y snmpd.c snmpd.conf.5 snmpd.h snmpe.c 
> >  util.c 
> > 
> > Log message:
> > Allow setting the engineid.
> > 
> > The previous engineid was based aronud the engine boottime and a random
> > value, which gives problems when sending/receiving unacknowledged PDUs
> > (trapv2) over SNMPv3 with authentication enabled, which need a consistent
> > engineid across restarts to determine the correct user from the sender.
> > 
> > The new default engineid takes a sha256 hash (chosen for its longer output)
> > of gethostname(3) and places the first 27 bytes after the new format number
> > 129. This should give us a very low probability of collisions, assuming
> > all machines have a unique name.
> 
> what happens if there's a collision? i'm not sure it's safe to assume
> unique names.

The engineid is used to load the engine context of the originator agent.
For unacknowledged pdu's this means at least loading the remote users
(unlike get requests the users, keys and engineid are from the
originator).

If there's a collision for trapv2 this means that if a user exists on
both remote agents but with different keys one of them will fail.

But if you want to enter a new user of a new system and you find that
that engineid already exist it should be a pretty big red flag that
there's a collision and the new system can explicitly set the engineid.
Similar if you ever want to set up something like "this engineid can
only send from this ip": If you see that a new systems engineid already
has such restriction it means you have to manually set the engineid.

For existing get requests we don't have any risk: For acknowledged PDUs
(get*/set) the engineid will be discovered (RFC3414 Section 4). And
people can't have any hefty restrictions in place as is, because
previously it was randomly generated at startup, so no persistent
engineid to check on.

I don't see any big risks here.

A minor risk would be that if a hostname ever changes traps won't be
received anymore, since the engineid changes. But changing a hostname
seems like something that doesn't happen very often and brings with it
a lot more migration research.

But considering the question if there was a better idea for generating
a consistent engineid by jmatthew@ on the 1st without any feedback I
went with this one.
If you still feel like there's a risk here after my previous reasoning
feel free to come up with an alternative. We still have time to change
it, and even then we have the range 130-255 to implement new formats
(although then we come back to the discussion about defaults without
negotiation)
> 
> > The other formats as specified in SNMP-FRAMEWORK-MIB (RFC3411) are also
> > supported as well as arbitrary formats in the range 128-255 for other
> > private enterprise numbers in hex format.
> > 
> > OK jmatthew@
> > 
> 




Re: snmpd: allow sending traps with SNMPv3

2021-08-09 Thread Martijn van Duren
On Tue, 2021-07-27 at 21:28 +0200, Martijn van Duren wrote:
> This diff allows sending traps in SNMPv3 messages.
> It defaults to the global seclevel, but it can be specified on a per
> rule basis.
> 
> Diff requires both previous setting engineid and ober_dup diff.
> 
> Tested with netsnmp's snmptrapd and my WIP diff.
> 
> The other 2 outstanding diffs are for receiving SNMPv3 traps.
> 
> OK?
> 
> martijn@
> 
Resending now that the engineid diff is in.

Still awaiting the commit of ober_dup diff[0].

OK once that one goes in?

Also, rereading the diff, splitting the trap receiver in two might be a
bit clutch. Once again invoking the manpage gurus.

martijn@

[0] https://marc.info/?l=openbsd-tech=162698527126249=2

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.65
diff -u -p -r1.65 parse.y
--- parse.y 9 Aug 2021 18:14:53 -   1.65
+++ parse.y 9 Aug 2021 19:41:38 -
@@ -134,10 +134,10 @@ typedef struct {
 %token HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER PORT
 %token   STRING
 %token   NUMBER
-%typehostcmn
+%typeusmuser community optcommunity
 %typesrcaddr port
 %typeoptwrite yesno seclevel listenopt listenopts
-%type  objtype cmd
+%type  objtype cmd hostauth hostauthv3 usmauthopts usmauthopt
 %type   oid hostoid trapoid
 %type  auth
 %type   enc
@@ -242,13 +242,13 @@ main  : LISTEN ON listenproto
free($3);
}
| TRAP RECEIVER host
-   | TRAP HANDLE hostcmn trapoid cmd {
-   struct trapcmd *cmd = $5.data;
+   | TRAP HANDLE trapoid cmd {
+   struct trapcmd *cmd = $4.data;
 
-   cmd->cmd_oid = $4;
+   cmd->cmd_oid = $3;
 
if (trapcmd_add(cmd) != 0) {
-   free($4);
+   free($3);
free(cmd);
yyerror("duplicate oid");
YYERROR;
@@ -267,8 +267,8 @@ main: LISTEN ON listenproto
| PFADDRFILTER yesno{
conf->sc_pfaddrfilter = $2;
}
-   | SECLEVEL seclevel {
-   conf->sc_min_seclevel = $2;
+   | seclevel {
+   conf->sc_min_seclevel = $1;
}
| USER STRING   {
const char *errstr;
@@ -720,15 +720,93 @@ hostoid   : /* empty */   
{ $$ = NULL; }
| OBJECTID oid  { $$ = $2; }
;
 
-hostcmn: /* empty */   { $$ = NULL; }
-   | COMMUNITY STRING  { $$ = $2; }
+usmuser: USER STRING   {
+   if (strlen($2) > SNMPD_MAXUSERNAMELEN) {
+   yyerror("User name too long: %s", $2);
+   free($2);
+   YYERROR;
+   }
+   $$ = $2;
+   }
+   ;
+
+community  : COMMUNITY STRING  {
+   if (strlen($2) > SNMPD_MAXCOMMUNITYLEN) {
+   yyerror("Community too long: %s", $2);
+   free($2);
+   YYERROR;
+   }
+   $$ = $2;
+   }
+   ;
+
+optcommunity   : /* empty */   { $$ = NULL; }
+   | community { $$ = $1; }
+   ;
+
+usmauthopt : usmuser   {
+   $$.data = $1;
+   $$.value = -1;
+   }
+   | seclevel  {
+   $$.data = 0;
+   $$.value = $1;
+   }
+   ;
+
+usmauthopts: /* empty */   {
+   $$.data = NULL;
+   $$.value = -1;
+   }
+   | usmauthopts usmauthopt{
+   if ($2.data != NULL) {
+   if ($$.data != NULL) {
+   yyerror("user redefined");
+   free($2.data);
+   YYERROR;
+   }
+   $$.data = $2.data;
+   } else {
+ 

Re: snmpd: tweak listen on

2021-08-09 Thread Martijn van Duren
On Mon, 2021-08-09 at 11:57 +0200, Martijn van Duren wrote:
> On Sun, 2021-08-08 at 14:44 +0100, Stuart Henderson wrote:
> > > This is probably is a bad example.
> > > Reading it like this: you're correct that we listen on all interfaces
> > > by default, but that's not listed in snmpd.conf(5). So that should
> > > probably be fixed (including mentioning that setting one "listen on"
> > > disables the all interfaces default).
> > 
> > Let's handle that separately. (it would be convenient to support
> > "any" to mean any v4+v6 as well).
> > 
> > > Second, your examples enable snmpv2c on all interfaces, while you
> > > enable an implicit snmpv3 on 127.0.0.1. This should probably be the
> > 
> > I wasn't intending that they should all be uncommented at once,
> > just showing some common options. And actually it seems snmpd
> > doesn't allow listening to 0.0.0.0 as well as a specific v4 address
> > (and similarly for :: and v6) so while it's a convenient idea to
> > allow v2c on localhost for quick testing while using v3 for external
> > traffic, it doesn't actually work.
> 
> This diff fixes all of the above:
> - Allow any to be used resolving to 0.0.0.0 and ::
> - Set SO_REUSEADDR on sockets, so we can listen on both any and
>   localhost
> - Document that we listen on any by default
> 
> The listen on text is starting to get quite large, so I hope that one of
> our man guru's can either confirm that it's still readable enough or
> help me to polish it.
> 
> martijn@
> 
Updated diff after my engineid commit.
This also incorperates some manpage feedback from schwarze@.

OK?

martijn@

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.65
diff -u -p -r1.65 parse.y
--- parse.y 9 Aug 2021 18:14:53 -   1.65
+++ parse.y 9 Aug 2021 18:54:56 -
@@ -135,8 +135,9 @@ typedef struct {
 %token   STRING
 %token   NUMBER
 %typehostcmn
+%typelistenproto listenflag listenflags
 %typesrcaddr port
-%typeoptwrite yesno seclevel listenopt listenopts
+%typeoptwrite yesno seclevel
 %type  objtype cmd
 %type   oid hostoid trapoid
 %type  auth
@@ -202,7 +203,7 @@ yesno   :  STRING   {
}
;
 
-main   : LISTEN ON listenproto
+main   : LISTEN ON listen_udptcp
| engineid_local {
if (conf->sc_engineid_len != 0) {
yyerror("Redefinition of engineid");
@@ -288,15 +289,16 @@ main  : LISTEN ON listenproto
}
;
 
-listenproto: UDP listen_udp
-   | TCP listen_tcp
-   | listen_udp
+listenproto: /* empty */   { $$ = SOCK_DGRAM; }
+   | UDP   { $$ = SOCK_DGRAM; }
+   | TCP listen_tcp{ $$ = SOCK_STREAM; }
+   ;
 
-listenopts : /* empty */ { $$ = 0; }
-   | listenopts listenopt { $$ |= $2; }
+listenflags: /* empty */ { $$ = 0; }
+   | listenflags listenflag { $$ |= $2; }
;
 
-listenopt  : READ { $$ = ADDRESS_FLAG_READ; }
+listenflag : READ { $$ = ADDRESS_FLAG_READ; }
| WRITE { $$ = ADDRESS_FLAG_WRITE; }
| NOTIFY { $$ = ADDRESS_FLAG_NOTIFY; }
| SNMPV1 { $$ = ADDRESS_FLAG_SNMPV1; }
@@ -304,71 +306,50 @@ listenopt : READ { $$ = ADDRESS_FLAG_REA
| SNMPV3 { $$ = ADDRESS_FLAG_SNMPV3; }
;
 
-listen_udp : STRING port listenopts{
+listen_udptcp  : listenproto STRING port listenflags   {
struct sockaddr_storage ss[16];
-   int nhosts, i;
-   char *port = $2;
+   int nhosts, j;
+   char *address[2], *port = $3;
+   size_t addresslen = 1, i;
 
if (port == NULL) {
-   if (($3 & ADDRESS_FLAG_PERM) ==
+   if (($4 & ADDRESS_FLAG_PERM) ==
ADDRESS_FLAG_NOTIFY)
port = SNMPTRAP_PORT;
else
port = SNMP_PORT;
}
 
-   nhosts = host($1, port, SOCK_DGRAM, ss, nitems(ss));
-   if (nhosts < 1) {
-   yyerror("invalid address: %s", $1);
-   free($1);
-   free($2);
-   YYERROR;
+ 

Re: libedit: stop ignoring SIGINT

2021-08-09 Thread Martijn van Duren
On Mon, 2021-08-09 at 15:17 +0200, Ingo Schwarze wrote:
> Hi Martijn,
> 
> Martijn van Duren wrote on Mon, Aug 09, 2021 at 02:15:42PM +0200:
> 
> > If we're stripping down fixio to a single function, why not
> > inline the whole thing?
> 
> I deliberately tried to:
> 
>  1. Keep patches that change behaviour as small as possible to make
>     review as simple as possible for people who fear they might be
>     affected but are not specifically interested in editline(3).
> 
>  2. Make sure that reorg / cleanup patches do not change behaviour.
> 
> > Also, as far as my brain explains things to me, it could theoretically
> > be possible that the signal handler kicks in right after we return a -1
> > from read(2), making it possible to get something like an EIO and
> > entering the sig switch statement. Assuming that a signal handler
> > doesn't clobber our errno (which libedit doesn't do, but who knows what
> > bad code is out there) we should probably only check the signal type
> > when we know we have an EINTR.
> 
> Yes, that looks like a race condition bug that so far escaped my
> attention.  But it seems unrelated to what should happen with signals
> in general, so can we keep fixing that bug separate?
> 
> > Finally, I don't understand why we only have a single retry on EAGAIN?
> 
> Not having *any* retries inside read_char() would look like a worthy
> long-term goal to me, but i'm not yet completely sure that can be
> reached.  I would prefer to steer into the direction of fewer magic
> retries rather than more of them.  Either way, EAGAIN seems unrelated
> to SIGINT, so i'd prefer to keep topics separate.
> 
> > If the application keeps resetting the FIONBIO in such a furious way
> > that it happens more then once in a single call (no idea how that could
> > happen) it might be an uphill battle, but we just burn away cpu cycles.
> > It is not and should probably not be treated like something fatal.
> 
> Actually, if the application sets FIONBIO at all (even once), chances
> are quite low in the first place that stuff works as inteded by the
> author of the application.  So i certainly wouldn't worry about an
> application setting FIONBIO in a loop, we have significantly worse
> problems than that.  But again, that's a separate topic.
> 
> > Diff below does this. (minus 27 LoC)
> 
> I do not in general object to cleaning this code up, and getting rid
> of read__fixio() indeed seems to be a long-term goal.  But i hope
> we will be able to remove all the (mostly broken) functionality
> from read__fixio() in a step-by-step manner, and once the function
> is empty, it will fade away without having to disturb the code in
> read_char().  Either way - separate topic...
> 
> The most important short-term goal seems to fix sftp(1), including
> the steps required to get that done in a clean way.
> 
> > The following ports use libedit (there might be a better way of
> > finding them, but this works):
> 
> Hmm, thanks, that list feels useful.
> 
> > So if we decide which of our interpretations should take precedence
> > it might be a good idea to put it into snaps for a while.
> 
> I don't think so in this case.  Let's not over-use the feature of
> putting stuff in snaps.  I think that should be reserved for stuff
> that is quite important and somewhat urgent and can't easily be
> tested in a less disruptive way.  But here, testing a program is
> quite feasible once you know which program to test.
> 
> Besides, *if* this patch causes a change in behaviour of a port,
> the most likely change is that a program that now ignores SIGINT
> exits on SIGINT afterwards.  That may be worth investigating and
> making a decision on in each individual case, but it's not a
> super-critical change in behaviour that might require testing
> in snaps.
> 
> Yours,
>   Ingo
> 
Your reasoning makes sense to me.
Assuming you're confident enough with the applications linked to
libedit: OK martijn@



Re: libedit: stop ignoring SIGINT

2021-08-09 Thread Martijn van Duren
On Mon, 2021-08-09 at 14:15 +0200, Martijn van Duren wrote:
> On Mon, 2021-08-09 at 13:19 +0200, Ingo Schwarze wrote:
> > Hi,
> > 
> > as mentioned earlier, deraadt@ reported that sftp(1) ignores Ctrl-C.
> > Fixing that without longjmp(3) requires making editline(3) better
> > behaved.
> > 
> > Currently, when read(2) from the terminal gets interrupted by a
> > signal, editline(3) ignores the (first) signal and unconditionally
> > calls read(2) a second time.  That seems wrong: if the user hits
> > Ctrl-C, it is sane to assume that they meant it, not that they
> > want it ignored.
> > 
> > The following patch causes el_gets(3) and el_wgets(3) to return
> > failure when read(2)ing from the terminal is interrupted by a
> > signal other than SIGCONT or SIGWINCH.  That allows the calling
> > program to decide what to do, usually either exit the program or
> > provide a fresh prompt to the user.
> > 
> > If i know how to grep(1), the following programs in the base system
> > use -ledit:
> > 
> >  * bc(1)
> >    It behaves well with the patch: Ctrl-C discards the current
> >    input line and starts a new input line.
> >    The reason why this already works even without the patch
> >    is that bc(1) does very scary stuff inside the signal handler:
> >    pass a file-global EditLine pointer on the heap to el_line(3)
> >    and access fields inside the returned struct.  Needless to
> >    say that no signal handler should do such things...
> > 
> >  * cdio(1)
> >    Behaviour is acceptable and unchanged with the patch:
> >    Ctrl-C exits cdio(1).
> > 
> >  * ftp(1)
> >    It behaves well with the patch: Ctrl-C discards the current
> >    input line and provides a fresh prompt.
> >    The reason why it already works without the patch is that ftp(1)
> >    uses setjmp(3)/longjmp(3) to forcefully grab back control
> >    from el_gets(3) without waiting for it to return.
> > 
> >  * lldb(1)
> >    It misbehaves with or without the patch and ignores Ctrl-C.
> >    I freely admit that i don't feel too enthusiastic about
> >    debugging that beast.
> > 
> >  * sftp(1)
> >    Behaviour is improved with the patch: Ctrl-C now exits sftp(1).
> >    If desired, i can supply a very simple follow-up patch to sftp.c
> >    to instead behave like ftp(1) and bc(1), i.e. discard the
> >    current input line and provide a fresh prompt.
> >    Neither doing undue work in the signal handler nor longjmp(3)
> >    will be required for that (if this patch gets committed).
> > 
> >  * bgplgsh(8), fsdb(8)
> >    I have no idea how to test those.  Does anyone think that testing
> >    either of them would be required?
> > 
> > Regarding the patch below, note that differentiating EINTR behaviour
> > by signal number is not needed because the calling code in read_char()
> > already handles SIGCONT and SIGWINCH, so those two never arrive in
> > read__fixio() in the first place.
> > 
> > Also note that deraadt@ pointed out in private mail to me that the
> > fact that read__fixio() clears FIONBIO is probably a symptom of
> > botched editline(3) API design.  That might be worth fixing, too,
> > as far as that is feasible, but it is unrelated to the sftp(1)
> > Ctrl-C issue; let's address one topic at a time.
> > 
> > Any feedback is welcome.
> > 
> > Yours,
> >   Ingo
> > 
> > P.S.
> > I decided to Cc: tech@ again because this patch might affect
> > even people who are not specifically interested in editline(3),
> > and i have no intention to cause unpleasant surprises.
> > 
> If we're stripping down fixio to a single function, why not inline the
> whole thing?
> 
> Also, as far as my brain explains things to me, it could theoretically
> be possible that the signal handler kicks in right after we return a -1
> from read(2), making it possible to get something like an EIO and
> entering the sig switch statement. Assuming that a signal handler
> doesn't clobber our errno (which libedit doesn't do, but who knows what
> bad code is out there) we should probably only check the signal type
> when we know we have an EINTR.
> 
> Finally, I don't understand why we only have a single retry on EAGAIN?
> If the application keeps resetting the FIONBIO in such a furious way
> that it happens more then once in a single call (no idea how that could
> happen) it might be an uphill battle, but we just burn away cpu cycles.
> It is not and should probably not be treated like something fatal.
> 
> Diff below does this. (minus 27 LoC)
&

Re: libedit: stop ignoring SIGINT

2021-08-09 Thread Martijn van Duren
On Mon, 2021-08-09 at 13:19 +0200, Ingo Schwarze wrote:
> Hi,
> 
> as mentioned earlier, deraadt@ reported that sftp(1) ignores Ctrl-C.
> Fixing that without longjmp(3) requires making editline(3) better
> behaved.
> 
> Currently, when read(2) from the terminal gets interrupted by a
> signal, editline(3) ignores the (first) signal and unconditionally
> calls read(2) a second time.  That seems wrong: if the user hits
> Ctrl-C, it is sane to assume that they meant it, not that they
> want it ignored.
> 
> The following patch causes el_gets(3) and el_wgets(3) to return
> failure when read(2)ing from the terminal is interrupted by a
> signal other than SIGCONT or SIGWINCH.  That allows the calling
> program to decide what to do, usually either exit the program or
> provide a fresh prompt to the user.
> 
> If i know how to grep(1), the following programs in the base system
> use -ledit:
> 
>  * bc(1)
>    It behaves well with the patch: Ctrl-C discards the current
>    input line and starts a new input line.
>    The reason why this already works even without the patch
>    is that bc(1) does very scary stuff inside the signal handler:
>    pass a file-global EditLine pointer on the heap to el_line(3)
>    and access fields inside the returned struct.  Needless to
>    say that no signal handler should do such things...
> 
>  * cdio(1)
>    Behaviour is acceptable and unchanged with the patch:
>    Ctrl-C exits cdio(1).
> 
>  * ftp(1)
>    It behaves well with the patch: Ctrl-C discards the current
>    input line and provides a fresh prompt.
>    The reason why it already works without the patch is that ftp(1)
>    uses setjmp(3)/longjmp(3) to forcefully grab back control
>    from el_gets(3) without waiting for it to return.
> 
>  * lldb(1)
>    It misbehaves with or without the patch and ignores Ctrl-C.
>    I freely admit that i don't feel too enthusiastic about
>    debugging that beast.
> 
>  * sftp(1)
>    Behaviour is improved with the patch: Ctrl-C now exits sftp(1).
>    If desired, i can supply a very simple follow-up patch to sftp.c
>    to instead behave like ftp(1) and bc(1), i.e. discard the
>    current input line and provide a fresh prompt.
>    Neither doing undue work in the signal handler nor longjmp(3)
>    will be required for that (if this patch gets committed).
> 
>  * bgplgsh(8), fsdb(8)
>    I have no idea how to test those.  Does anyone think that testing
>    either of them would be required?
> 
> Regarding the patch below, note that differentiating EINTR behaviour
> by signal number is not needed because the calling code in read_char()
> already handles SIGCONT and SIGWINCH, so those two never arrive in
> read__fixio() in the first place.
> 
> Also note that deraadt@ pointed out in private mail to me that the
> fact that read__fixio() clears FIONBIO is probably a symptom of
> botched editline(3) API design.  That might be worth fixing, too,
> as far as that is feasible, but it is unrelated to the sftp(1)
> Ctrl-C issue; let's address one topic at a time.
> 
> Any feedback is welcome.
> 
> Yours,
>   Ingo
> 
> P.S.
> I decided to Cc: tech@ again because this patch might affect
> even people who are not specifically interested in editline(3),
> and i have no intention to cause unpleasant surprises.
> 
If we're stripping down fixio to a single function, why not inline the
whole thing?

Also, as far as my brain explains things to me, it could theoretically
be possible that the signal handler kicks in right after we return a -1
from read(2), making it possible to get something like an EIO and
entering the sig switch statement. Assuming that a signal handler
doesn't clobber our errno (which libedit doesn't do, but who knows what
bad code is out there) we should probably only check the signal type
when we know we have an EINTR.

Finally, I don't understand why we only have a single retry on EAGAIN?
If the application keeps resetting the FIONBIO in such a furious way
that it happens more then once in a single call (no idea how that could
happen) it might be an uphill battle, but we just burn away cpu cycles.
It is not and should probably not be treated like something fatal.

Diff below does this. (minus 27 LoC)

The following ports use libedit (there might be a better way of finding
them, but this works):
$ find . -name Makefile | xargs grep -F '.include ' | \
> cut -d: -f1 | while read file; do \
> (cd $(dirname $file); make show=WANTLIB | \
> grep -q '\' && echo $(dirname $file)); \>
> done 2> /dev/null 
./devel/clang-tools-extra
./devel/llvm
./mail/dcc
./mail/nmh
./emulators/gsplus
./emulators/nono
./lang/brainfuck
./lang/eltclsh
./lang/lua/5.1
./lang/lua/5.2
./lang/lua/5.3
./lang/swi-prolog
./math/gbc
./net/dnsdist
./net/honeyd
./net/icinga/core2
./net/knot
./net/ntp
./security/kc
./security/pivy
./shells/dash
./shells/nsh
./sysutils/ipmitool

So if we decide which of our interpretations should take precedence it
might be a good idea to put it into snaps for a while.

martijn@

Index: 

snmpd: tweak listen on

2021-08-09 Thread Martijn van Duren
On Sun, 2021-08-08 at 14:44 +0100, Stuart Henderson wrote:
> > This is probably is a bad example.
> > Reading it like this: you're correct that we listen on all interfaces
> > by default, but that's not listed in snmpd.conf(5). So that should
> > probably be fixed (including mentioning that setting one "listen on"
> > disables the all interfaces default).
> 
> Let's handle that separately. (it would be convenient to support
> "any" to mean any v4+v6 as well).
> 
> > Second, your examples enable snmpv2c on all interfaces, while you
> > enable an implicit snmpv3 on 127.0.0.1. This should probably be the
> 
> I wasn't intending that they should all be uncommented at once,
> just showing some common options. And actually it seems snmpd
> doesn't allow listening to 0.0.0.0 as well as a specific v4 address
> (and similarly for :: and v6) so while it's a convenient idea to
> allow v2c on localhost for quick testing while using v3 for external
> traffic, it doesn't actually work.

This diff fixes all of the above:
- Allow any to be used resolving to 0.0.0.0 and ::
- Set SO_REUSEADDR on sockets, so we can listen on both any and
  localhost
- Document that we listen on any by default

The listen on text is starting to get quite large, so I hope that one of
our man guru's can either confirm that it's still readable enough or
help me to polish it.

martijn@

Index: parse.y
===
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.64
diff -u -p -r1.64 parse.y
--- parse.y 20 Jun 2021 19:55:48 -  1.64
+++ parse.y 9 Aug 2021 09:53:08 -
@@ -128,8 +128,9 @@ typedef struct {
 %token   STRING
 %token   NUMBER
 %typehostcmn
+%typelistenproto listenflag listenflags
 %typesrcaddr port
-%typeoptwrite yesno seclevel listenopt listenopts
+%typeoptwrite yesno seclevel
 %type  objtype cmd
 %type   oid hostoid trapoid
 %type  auth
@@ -195,7 +196,7 @@ yesno   :  STRING   {
}
;
 
-main   : LISTEN ON listenproto
+main   : LISTEN ON listen_udptcp
| READONLY COMMUNITY STRING {
if (strlcpy(conf->sc_rdcommunity, $3,
sizeof(conf->sc_rdcommunity)) >=
@@ -273,15 +274,16 @@ main  : LISTEN ON listenproto
}
;
 
-listenproto: UDP listen_udp
-   | TCP listen_tcp
-   | listen_udp
+listenproto: /* empty */   { $$ = SOCK_DGRAM; }
+   | UDP   { $$ = SOCK_DGRAM; }
+   | TCP listen_tcp{ $$ = SOCK_STREAM; }
+   ;
 
-listenopts : /* empty */ { $$ = 0; }
-   | listenopts listenopt { $$ |= $2; }
+listenflags: /* empty */ { $$ = 0; }
+   | listenflags listenflag { $$ |= $2; }
;
 
-listenopt  : READ { $$ = ADDRESS_FLAG_READ; }
+listenflag : READ { $$ = ADDRESS_FLAG_READ; }
| WRITE { $$ = ADDRESS_FLAG_WRITE; }
| NOTIFY { $$ = ADDRESS_FLAG_NOTIFY; }
| SNMPV1 { $$ = ADDRESS_FLAG_SNMPV1; }
@@ -289,71 +291,50 @@ listenopt : READ { $$ = ADDRESS_FLAG_REA
| SNMPV3 { $$ = ADDRESS_FLAG_SNMPV3; }
;
 
-listen_udp : STRING port listenopts{
+listen_udptcp  : listenproto STRING port listenflags   {
struct sockaddr_storage ss[16];
-   int nhosts, i;
-   char *port = $2;
+   int nhosts, j;
+   char *address[2], *port = $3;
+   size_t addresslen = 1, i;
 
if (port == NULL) {
-   if (($3 & ADDRESS_FLAG_PERM) ==
+   if (($4 & ADDRESS_FLAG_PERM) ==
ADDRESS_FLAG_NOTIFY)
port = SNMPTRAP_PORT;
else
port = SNMP_PORT;
}
 
-   nhosts = host($1, port, SOCK_DGRAM, ss, nitems(ss));
-   if (nhosts < 1) {
-   yyerror("invalid address: %s", $1);
-   free($1);
-   free($2);
-   YYERROR;
+   if (strcmp($2, "any") == 0) {
+   addresslen = 2;
+   address[0] = "0.0.0.0";
+   address[1] = "::";
+   } else {
+   addresslen = 1;
+   address[0] = $2;
}
-   if (nhosts > (int)nitems(ss))
-   log_warn("%s:%s 

Re: libedit: read__fixio cleanup

2021-08-09 Thread Martijn van Duren
Btw, would there be any benefit to declare zero as const in this
context?

On Sun, 2021-08-08 at 13:42 +0200, Ingo Schwarze wrote:
> Hi,
> 
> deraadt@ recently reported to me that the editline(3) library, while
> line editing is active - for example inside el_gets(3) - ignores
> the first SIGINT it receives, for example the the first Ctrl-C the
> user presses.  I consider that a bug in the editline(3) library.
> Some programs, for example our old ftp(1) implementation, work
> around the bug in a horrible way by using setjmp(3)/longjmp(3).
> 
> The root cause of the problem is in libedit/read.c, in the interaction
> of the functions read_char() and read__fixio().  Before fixing the bug
> can reasonably be considered, the function read__fixio() direly needs
> cleanup.  As it stands, it is utterly unreadable.
> 
> So here is a patch to make it clear what the function does, with
> no functional change intended yet (-37 +5 LOC).
> 
> There will be one or more follow-up patches.  If you want to receive
> them, please reply to me, i won't necessarily send them all to
> tech@.
> 
> I see some value in avoiding gratuitious divergence from NetBSD,
> but getting rid of this horrible mess is not gratuitious.
> 
> Rationale:
>  * Do not mark an argument as unused that is actually used.
>  * errno cannot possibly be -1.  Even is it were, treating it as
>    EAGAIN makes no sense, treating it as the most severe error
>    imaginable makes more sense to me.
>  * We define EWOULDBLOCK to be the same as EAGAIN, so no need
>    to handle it separately.
>  * No need to #define TRY_AGAIN to use it just once.
>  * Don't do the same thing twice.  We do support the FIONBIO ioctl(2),
>    so the the indirection using the F_GETFL fcntl(2) can be deleted.
>  * No need to play confusing games with the "e" variable.
>    Just return -1 for error or 0 for success in a straightforward
>    manner.
> 
> OK?
>   Ingo
> 
> P.S.
> I also considered whether this FIONBIO dance should better be done
> at the initialization stage rather than after EAGAIN already happened.
> But maybe not.  This is a library.  The application program might
> set the fd to non-blocking mode at any time and then call el_gets(3)
> again, in which case the library needs to restore blocking I/O to
> do its work.
> 
> 
> Index: read.c
> ===
> RCS file: /cvs/src/lib/libedit/read.c,v
> retrieving revision 1.44
> diff -u -p -r1.44 read.c
> --- read.c  25 May 2016 09:36:21 -  1.44
> +++ read.c  8 Aug 2021 10:30:06 -
> @@ -39,9 +39,10 @@
>   * read.c: Clean this junk up! This is horrible code.
>   *    Terminal read functions
>   */
> +#include 
> +
>  #include 
>  #include 
> -#include 
>  #include 
>  #include 
>  #include 
> @@ -134,55 +135,16 @@ el_read_getfn(struct el_read_t *el_read)
>  /* read__fixio():
>   * Try to recover from a read error
>   */
> -/* ARGSUSED */
>  static int
> -read__fixio(int fd __attribute__((__unused__)), int e)
> +read__fixio(int fd, int e)
>  {
> +   int zero = 0;
>  
> switch (e) {
> -   case -1:/* Make sure that the code is reachable */
> -
> -#ifdef EWOULDBLOCK
> -   case EWOULDBLOCK:
> -#ifndef TRY_AGAIN
> -#define TRY_AGAIN
> -#endif
> -#endif /* EWOULDBLOCK */
> -
> -#if defined(POSIX) && defined(EAGAIN)
> -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
> case EAGAIN:
> -#ifndef TRY_AGAIN
> -#define TRY_AGAIN
> -#endif
> -#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
> -#endif /* POSIX && EAGAIN */
> -
> -   e = 0;
> -#ifdef TRY_AGAIN
> -#if defined(F_SETFL) && defined(O_NDELAY)
> -   if ((e = fcntl(fd, F_GETFL)) == -1)
> +   if (ioctl(fd, FIONBIO, ) == -1)
> return -1;
> -
> -   if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
> -   return -1;
> -   else
> -   e = 1;
> -#endif /* F_SETFL && O_NDELAY */
> -
> -#ifdef FIONBIO
> -   {
> -   int zero = 0;
> -
> -   if (ioctl(fd, FIONBIO, ) == -1)
> -   return -1;
> -   else
> -   e = 1;
> -   }
> -#endif /* FIONBIO */
> -
> -#endif /* TRY_AGAIN */
> -   return e ? 0 : -1;
> +   return 0;
>  
> case EINTR:
> return 0;
> 




Re: libedit: read__fixio cleanup

2021-08-08 Thread Martijn van Duren
On Sun, 2021-08-08 at 13:42 +0200, Ingo Schwarze wrote:
> Hi,
> 
> deraadt@ recently reported to me that the editline(3) library, while
> line editing is active - for example inside el_gets(3) - ignores
> the first SIGINT it receives, for example the the first Ctrl-C the
> user presses.  I consider that a bug in the editline(3) library.
> Some programs, for example our old ftp(1) implementation, work
> around the bug in a horrible way by using setjmp(3)/longjmp(3).
> 
> The root cause of the problem is in libedit/read.c, in the interaction
> of the functions read_char() and read__fixio().  Before fixing the bug
> can reasonably be considered, the function read__fixio() direly needs
> cleanup.  As it stands, it is utterly unreadable.
> 
> So here is a patch to make it clear what the function does, with
> no functional change intended yet (-37 +5 LOC).
> 
> There will be one or more follow-up patches.  If you want to receive
> them, please reply to me, i won't necessarily send them all to
> tech@.
> 
> I see some value in avoiding gratuitious divergence from NetBSD,
> but getting rid of this horrible mess is not gratuitious.
> 
> Rationale:
>  * Do not mark an argument as unused that is actually used.
>  * errno cannot possibly be -1.  Even is it were, treating it as
>    EAGAIN makes no sense, treating it as the most severe error
>    imaginable makes more sense to me.
>  * We define EWOULDBLOCK to be the same as EAGAIN, so no need
>    to handle it separately.
>  * No need to #define TRY_AGAIN to use it just once.
>  * Don't do the same thing twice.  We do support the FIONBIO ioctl(2),
>    so the the indirection using the F_GETFL fcntl(2) can be deleted.
>  * No need to play confusing games with the "e" variable.
>    Just return -1 for error or 0 for success in a straightforward
>    manner.
> 
> OK?
>   Ingo
> 
> P.S.
> I also considered whether this FIONBIO dance should better be done
> at the initialization stage rather than after EAGAIN already happened.
> But maybe not.  This is a library.  The application program might
> set the fd to non-blocking mode at any time and then call el_gets(3)
> again, in which case the library needs to restore blocking I/O to
> do its work.
> 
Hopefully without getting dragged too much into this one:
Your reasoning and diff look fine to me.

OK martijn@
> 
> Index: read.c
> ===
> RCS file: /cvs/src/lib/libedit/read.c,v
> retrieving revision 1.44
> diff -u -p -r1.44 read.c
> --- read.c  25 May 2016 09:36:21 -  1.44
> +++ read.c  8 Aug 2021 10:30:06 -
> @@ -39,9 +39,10 @@
>   * read.c: Clean this junk up! This is horrible code.
>   *    Terminal read functions
>   */
> +#include 
> +
>  #include 
>  #include 
> -#include 
>  #include 
>  #include 
>  #include 
> @@ -134,55 +135,16 @@ el_read_getfn(struct el_read_t *el_read)
>  /* read__fixio():
>   * Try to recover from a read error
>   */
> -/* ARGSUSED */
>  static int
> -read__fixio(int fd __attribute__((__unused__)), int e)
> +read__fixio(int fd, int e)
>  {
> +   int zero = 0;
>  
> switch (e) {
> -   case -1:/* Make sure that the code is reachable */
> -
> -#ifdef EWOULDBLOCK
> -   case EWOULDBLOCK:
> -#ifndef TRY_AGAIN
> -#define TRY_AGAIN
> -#endif
> -#endif /* EWOULDBLOCK */
> -
> -#if defined(POSIX) && defined(EAGAIN)
> -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
> case EAGAIN:
> -#ifndef TRY_AGAIN
> -#define TRY_AGAIN
> -#endif
> -#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
> -#endif /* POSIX && EAGAIN */
> -
> -   e = 0;
> -#ifdef TRY_AGAIN
> -#if defined(F_SETFL) && defined(O_NDELAY)
> -   if ((e = fcntl(fd, F_GETFL)) == -1)
> +   if (ioctl(fd, FIONBIO, ) == -1)
> return -1;
> -
> -   if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
> -   return -1;
> -   else
> -   e = 1;
> -#endif /* F_SETFL && O_NDELAY */
> -
> -#ifdef FIONBIO
> -   {
> -   int zero = 0;
> -
> -   if (ioctl(fd, FIONBIO, ) == -1)
> -   return -1;
> -   else
> -   e = 1;
> -   }
> -#endif /* FIONBIO */
> -
> -#endif /* TRY_AGAIN */
> -   return e ? 0 : -1;
> +   return 0;
>  
> case EINTR:
> return 0;
> 




  1   2   3   4   5   6   >