The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=777123969db5ee8eceee28d7df72b7fd7352cb85
commit 777123969db5ee8eceee28d7df72b7fd7352cb85 Author: Gleb Smirnoff <gleb...@freebsd.org> AuthorDate: 2025-07-25 20:10:17 +0000 Commit: Gleb Smirnoff <gleb...@freebsd.org> CommitDate: 2025-07-25 20:10:17 +0000 libbsnmp: make binding of client UNIX socket optional and configurable Before this change snmp_open(3) would always bind(2) client socket to a random "/tmp/snmpXXXXXXXXXXXXXX" name. However, this binding is not required for SOCK_STREAM transport. Also, any attempt to specify a different name would fail, as open_client_local() would blindly rewrite the name to the default. Make this binding optional. If application had initialized snmp_client.local_path, then try to bind to the specified pathname, otherwise perform the random name binding only if we are in the SOCK_DGRAM mode. While here change snmp_client.local_path size to SUNPATHLEN, so that any legitimate local socket name can be used. This requires library version bump. Note that this code has been broken by 81e0e7b9e36d for three years, thus it is known not to be widely used. Reviewed by: harti Differential Revision: https://reviews.freebsd.org/D51070 --- ObsoleteFiles.inc | 3 + contrib/bsnmp/lib/bsnmpclient.3 | 19 ++++-- contrib/bsnmp/lib/snmpclient.c | 74 ++++++++++++++---------- contrib/bsnmp/lib/snmpclient.h | 5 +- lib/libbsnmp/libbsnmp/Makefile | 2 +- tools/build/mk/OptionalObsoleteFiles.inc | 2 +- usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c | 5 +- 7 files changed, 69 insertions(+), 41 deletions(-) diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 808e7be828c5..385e891049e7 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -51,6 +51,9 @@ # xargs -n1 | sort | uniq -d; # done +# 20250725: libbsnmp bumped to version 7 +OLD_LIBS+=usr/lib/libbsnmp.so.6 + # 20250725: Files which were briefly installed by WITH_MITKRB5 in 15.0. OLD_FILES+=usr/include/kadm5/admin_internal.h OLD_FILES+=usr/include/kadm5/admin_xdr.h diff --git a/contrib/bsnmp/lib/bsnmpclient.3 b/contrib/bsnmp/lib/bsnmpclient.3 index 0a2286eb14c4..1a5aa2e5e3a6 100644 --- a/contrib/bsnmp/lib/bsnmpclient.3 +++ b/contrib/bsnmp/lib/bsnmpclient.3 @@ -31,7 +31,7 @@ .\" .\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $ .\" -.Dd March 31, 2020 +.Dd June 24, 2025 .Dt BSNMPCLIENT 3 .Os .Sh NAME @@ -155,7 +155,7 @@ struct snmp_client { snmp_timeout_start_f timeout_start; snmp_timeout_stop_f timeout_stop; - char local_path[sizeof(SNMP_LOCAL_PATH)]; + char local_path[SUNPATHLEN]; }; .Ed .Pp @@ -285,8 +285,19 @@ The function will be called with the return value of the corresponding .Fn timeout_start function. .It Va local_path -If in local socket mode, the name of the clients socket. -Not needed by the application. +In local socket mode, optional path name the client socket shall be bound to +before connecting to the server. +For +.Dv SOCK_STREAM +local socket the named path is optional, and library will skip +.Xr bind 2 +if path is not provided. +For +.Dv SOCK_DGRAM +local socket the named path is required, thus library will create a random +one in +.Pa /tmp +if path is not provided. .El .Pp In the current implementation there is a global variable diff --git a/contrib/bsnmp/lib/snmpclient.c b/contrib/bsnmp/lib/snmpclient.c index d5d4af998a0c..5fa7d4f5be2a 100644 --- a/contrib/bsnmp/lib/snmpclient.c +++ b/contrib/bsnmp/lib/snmpclient.c @@ -977,7 +977,10 @@ remove_local(void) static int open_client_local(const char *path) { - struct sockaddr_un sa; + struct sockaddr_un sa = { + .sun_family = AF_LOCAL, + .sun_len = sizeof(sa), + }; char *ptr; int stype; @@ -1003,43 +1006,56 @@ open_client_local(const char *path) return (-1); } - snprintf(snmp_client.local_path, sizeof(snmp_client.local_path), - "%s", SNMP_LOCAL_PATH); - - if (mktemp(snmp_client.local_path) == NULL) { - seterr(&snmp_client, "%s", strerror(errno)); - (void)close(snmp_client.fd); - snmp_client.fd = -1; - return (-1); + /* + * A datagram socket requires a name to receive replies back. Would + * be cool to have an extension to unix(4) sockets similar to ip(4) + * IP_RECVDSTADDR/IP_SENDSRCADDR, so that a one-to-many datagram + * UNIX socket can send replies to its anonymous peers. + */ + if (snmp_client.trans == SNMP_TRANS_LOC_DGRAM && + snmp_client.local_path[0] == '\0') { + (void)strlcpy(snmp_client.local_path, "/tmp/snmpXXXXXXXXXXXXXX", + sizeof(snmp_client.local_path)); + if (mktemp(snmp_client.local_path) == NULL) { + seterr(&snmp_client, "mktemp(3): %s", strerror(errno)); + goto fail; + } } - sa.sun_family = AF_LOCAL; - sa.sun_len = sizeof(sa); - strcpy(sa.sun_path, snmp_client.local_path); - - if (bind(snmp_client.fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { - seterr(&snmp_client, "%s", strerror(errno)); - (void)close(snmp_client.fd); - snmp_client.fd = -1; - (void)remove(snmp_client.local_path); - return (-1); + if (snmp_client.local_path[0] != '\0') { + if (strlcpy(sa.sun_path, snmp_client.local_path, + sizeof(sa.sun_path)) >= + sizeof(sa.sun_path)) { + seterr(&snmp_client, "%s", + "Local socket pathname too long"); + goto fail; + } + if (bind(snmp_client.fd, (struct sockaddr *)&sa, sizeof(sa)) == + -1) { + seterr(&snmp_client, "%s", strerror(errno)); + goto fail; + } + atexit(remove_local); } - atexit(remove_local); - sa.sun_family = AF_LOCAL; - sa.sun_len = offsetof(struct sockaddr_un, sun_path) + - strlen(snmp_client.chost); - strncpy(sa.sun_path, snmp_client.chost, sizeof(sa.sun_path) - 1); - sa.sun_path[sizeof(sa.sun_path) - 1] = '\0'; + if (strlcpy(sa.sun_path, snmp_client.chost, sizeof(sa.sun_path)) >= + sizeof(sa.sun_path)) { + seterr(&snmp_client, "%s", "Server socket pathname too long"); + goto fail; + } if (connect(snmp_client.fd, (struct sockaddr *)&sa, sa.sun_len) == -1) { seterr(&snmp_client, "%s", strerror(errno)); - (void)close(snmp_client.fd); - snmp_client.fd = -1; - (void)remove(snmp_client.local_path); - return (-1); + goto fail; } return (0); + +fail: + (void)close(snmp_client.fd); + snmp_client.fd = -1; + if (snmp_client.local_path[0] != '\0') + (void)remove(snmp_client.local_path); + return (-1); } /* diff --git a/contrib/bsnmp/lib/snmpclient.h b/contrib/bsnmp/lib/snmpclient.h index 662dc7c4a204..a8a79ff824bc 100644 --- a/contrib/bsnmp/lib/snmpclient.h +++ b/contrib/bsnmp/lib/snmpclient.h @@ -35,6 +35,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/un.h> #include <netinet/in.h> #include <stddef.h> @@ -42,8 +43,6 @@ #define SNMP_STRERROR_LEN 200 #define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock" -#define SNMP_LOCAL_PATH "/tmp/snmpXXXXXXXXXXXXXX" - /* * transport methods */ @@ -111,7 +110,7 @@ struct snmp_client { snmp_timeout_start_f timeout_start; snmp_timeout_stop_f timeout_stop; - char local_path[sizeof(SNMP_LOCAL_PATH)]; + char local_path[SUNPATHLEN]; }; /* the global context */ diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile index 6bdb4003fdf4..2e2770b56c4a 100644 --- a/lib/libbsnmp/libbsnmp/Makefile +++ b/lib/libbsnmp/libbsnmp/Makefile @@ -7,7 +7,7 @@ CONTRIB= ${SRCTOP}/contrib/bsnmp/lib .PATH: ${CONTRIB} LIB= bsnmp -SHLIB_MAJOR= 6 +SHLIB_MAJOR= 7 LD_FATAL_WARNINGS= no CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 4c127b392138..3183c5f0b45c 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -461,7 +461,7 @@ OLD_FILES+=usr/include/bsnmp/snmpclient.h OLD_FILES+=usr/include/bsnmp/snmpmod.h OLD_FILES+=usr/lib/libbsnmp.a OLD_FILES+=usr/lib/libbsnmp.so -OLD_LIBS+=usr/lib/libbsnmp.so.6 +OLD_LIBS+=usr/lib/libbsnmp.so.7 OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbsnmptools.a OLD_FILES+=usr/lib/libbsnmptools.so diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c index b4613763fff5..d8fbb55290a8 100644 --- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c +++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c @@ -881,12 +881,11 @@ parse_local_path(char *opt_arg) { assert(opt_arg != NULL); - if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) { + if (strlcpy(snmp_client.local_path, opt_arg, + sizeof(snmp_client.local_path)) >= sizeof(snmp_client.local_path)) { warnx("Filename too long - %s", opt_arg); return (-1); } - - strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH)); return (2); }