diff -Nurp net-snmp-5.7.3.orig/configure.d/config_os_functions net-snmp-5.7.3/configure.d/config_os_functions --- net-snmp-5.7.3.orig/configure.d/config_os_functions 2014-12-08 21:23:22.000000000 +0100 +++ net-snmp-5.7.3/configure.d/config_os_functions 2015-07-16 10:32:15.159643068 +0200 @@ -31,11 +31,12 @@ AC_CHECK_FUNCS([lrand48 rand [signal sigset ] ) # Library: -AC_CHECK_FUNCS([closedir fgetc_unlocked flockfile ] dnl - [fork funlockfile getipnodebyname ] dnl - [gettimeofday if_nametoindex mkstemp ] dnl - [opendir readdir regcomp ] dnl - [setenv setitimer setlocale ] dnl +AC_CHECK_FUNCS([closedir endnetgrent fgetc_unlocked ] dnl + [flockfile fork funlockfile ] dnl + [getipnodebyname getnetgrent gettimeofday ] dnl + [if_nametoindex mkstemp opendir ] dnl + [readdir regcomp setenv ] dnl + [setitimer setlocale setnetgrent ] dnl [setsid snprintf strcasestr ] dnl [strdup strerror strncasecmp ] dnl [sysconf times vsnprintf ] ) diff -Nurp net-snmp-5.7.3.orig/man/snmpd.conf.5.def net-snmp-5.7.3/man/snmpd.conf.5.def --- net-snmp-5.7.3.orig/man/snmpd.conf.5.def 2014-12-08 21:23:22.000000000 +0100 +++ net-snmp-5.7.3/man/snmpd.conf.5.def 2015-07-16 10:41:34.337850287 +0200 @@ -389,7 +389,14 @@ map an SNMPv1 or SNMPv2c community strin a particular range of source addresses, or globally (\fI"default"\fR). A restricted source can either be a specific hostname (or address), or a subnet - represented as IP/MASK (e.g. 10.10.10.0/255.255.255.0), or -IP/BITS (e.g. 10.10.10.0/24), or the IPv6 equivalents. +IP/BITS (e.g. 10.10.10.0/24), or the IPv6 equivalents. It is also possible +to reference a specific \fInetgroup\fR starting with an '@' character (e.g. +@adminhosts). The \fInetgroup\fR lookup is running through the NSS (Name +Services Switch) making it possible to define the group locally or via +NIS/LDAP. +.IP +Note: The hostname DNS lookup and \fInetgroup\fR resolution is done only +during snmpd start or reload. .IP The same community string can be specified in several separate directives (presumably with different source tokens), and the first source/community diff -Nurp net-snmp-5.7.3.orig/snmplib/transports/snmpUDPDomain.c net-snmp-5.7.3/snmplib/transports/snmpUDPDomain.c --- net-snmp-5.7.3.orig/snmplib/transports/snmpUDPDomain.c 2014-12-08 21:23:22.000000000 +0100 +++ net-snmp-5.7.3/snmplib/transports/snmpUDPDomain.c 2015-07-16 10:32:15.160643078 +0200 @@ -88,6 +88,11 @@ void _netsnmp_udp_sockopt_set(int fd, in int netsnmp_sockaddr_in2(struct sockaddr_in *addr, const char *inpeername, const char *default_target); +static void +netsnmp_udp_com2SecList_add(char *secName, size_t secNameLen, + char *contextName, size_t contextNameLen, + char *community, size_t communityLen, + struct in_addr network, struct in_addr mask); /* * Return a string representing the address in data, or else the "far end" @@ -100,6 +105,59 @@ netsnmp_udp_fmtaddr(netsnmp_transport *t return netsnmp_ipv4_fmtaddr("UDP", t, data, len); } +static int +netsnmp_udp_resolve_source(char *source, struct in_addr *network, + struct in_addr *mask) +{ + /* Split the source/netmask parts */ + char *strmask = strchr(source, '/'); + if (strmask != NULL) + /* Mask given. */ + *strmask++ = '\0'; + + /* Try interpreting as a dotted quad. */ + if (inet_pton(AF_INET, source, network) == 0) { + /* Nope, wasn't a dotted quad. Must be a hostname. */ + int ret = netsnmp_gethostbyname_v4(source, &(network->s_addr)); + if (ret < 0) { + config_perror("cannot resolve source hostname"); + return ret; + } + } + + /* Now work out the mask. */ + if (strmask == NULL || *strmask == '\0') { + /* No mask was given. Assume /32 */ + mask->s_addr = (in_addr_t)(~0UL); + } else { + /* Try to interpret mask as a "number of 1 bits". */ + char* cp; + long maskLen = strtol(strmask, &cp, 10); + if (*cp == '\0') { + if (0 < maskLen && maskLen <= 32) + mask->s_addr = htonl((in_addr_t)(~0UL << (32 - maskLen))); + else if (maskLen == 0) + mask->s_addr = 0; + else { + config_perror("bad mask length"); + return -1; + } + } + /* Try to interpret mask as a dotted quad. */ + else if (inet_pton(AF_INET, strmask, mask) == 0) { + config_perror("bad mask"); + return -1; + } + + /* Check that the network and mask are consistent. */ + if (network->s_addr & ~mask->s_addr) { + config_perror("source/mask mismatch"); + return -1; + } + } + return 0; +} + #if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR) @@ -259,102 +317,85 @@ netsnmp_udp_parse_security(const char *t if (strcmp(source, "default") == 0) { network.s_addr = 0; mask.s_addr = 0; + netsnmp_udp_com2SecList_add(secName, secNameLen, contextName, + contextNameLen, community, communityLen, network, mask); } else { - /* Split the source/netmask parts */ - char *strmask = strchr(source, '/'); - if (strmask != NULL) - /* Mask given. */ - *strmask++ = '\0'; - - /* Try interpreting as a dotted quad. */ - if (inet_pton(AF_INET, source, &network) == 0) { - /* Nope, wasn't a dotted quad. Must be a hostname. */ - int ret = netsnmp_gethostbyname_v4(source, &network.s_addr); - if (ret < 0) { - config_perror("cannot resolve source hostname"); - return; - } - } - - /* Now work out the mask. */ - if (strmask == NULL || *strmask == '\0') { - /* No mask was given. Assume /32 */ - mask.s_addr = (in_addr_t)(~0UL); - } else { - /* Try to interpret mask as a "number of 1 bits". */ - char* cp; - long maskLen = strtol(strmask, &cp, 10); - if (*cp == '\0') { - if (0 < maskLen && maskLen <= 32) - mask.s_addr = htonl((in_addr_t)(~0UL << (32 - maskLen))); - else if (maskLen == 0) - mask.s_addr = 0; - else { - config_perror("bad mask length"); - return; +#if HAVE_ENDNETGRENT && HAVE_GETNETGRENT && HAVE_SETNETGRENT + /* Interpret as netgroup */ + if (*source == '@') { + char *netgroup = source+1; + char *host, *user, *domain; + setnetgrent(netgroup); + while (getnetgrent(&host, &user, &domain)) { + if (netsnmp_udp_resolve_source(host, &network, &mask) == 0) { + netsnmp_udp_com2SecList_add(secName, secNameLen, contextName, + contextNameLen, community, communityLen, network, mask); } } - /* Try to interpret mask as a dotted quad. */ - else if (inet_pton(AF_INET, strmask, &mask) == 0) { - config_perror("bad mask"); - return; - } - - /* Check that the network and mask are consistent. */ - if (network.s_addr & ~mask.s_addr) { - config_perror("source/mask mismatch"); - return; + endnetgrent(); + } + /* Without '@' it has to be an address or hostname */ + else +#endif + { + if (netsnmp_udp_resolve_source(source, &network, &mask) == 0) { + netsnmp_udp_com2SecList_add(secName, secNameLen, contextName, + contextNameLen, community, communityLen, network, mask); } } } +} - { - void* v = malloc(offsetof(com2SecEntry, community) + communityLen + - secNameLen + contextNameLen); - - com2SecEntry* e = (com2SecEntry*)v; - char* last = ((char*)v) + offsetof(com2SecEntry, community); +static void +netsnmp_udp_com2SecList_add(char *secName, size_t secNameLen, char *contextName, + size_t contextNameLen, char *community, size_t communityLen, + struct in_addr network, struct in_addr mask) +{ + void *v = malloc(offsetof(com2SecEntry, community) + communityLen + + secNameLen + contextNameLen); - if (v == NULL) { - config_perror("memory error"); - return; - } + com2SecEntry* e = (com2SecEntry*)v; + char* last = ((char*)v) + offsetof(com2SecEntry, community); - /* - * Everything is okay. Copy the parameters to the structure allocated - * above and add it to END of the list. - */ + if (v == NULL) { + config_perror("memory error"); + return; + } - { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - DEBUGMSGTL(("netsnmp_udp_parse_security", - "<\"%s\", %s/%s> => \"%s\"\n", community, - inet_ntop(AF_INET, &network, buf1, sizeof(buf1)), - inet_ntop(AF_INET, &mask, buf2, sizeof(buf2)), - secName)); - } + /* + * Everything is okay. Copy the parameters to the structure allocated + * above and add it to END of the list. + */ - memcpy(last, community, communityLen); - last += communityLen; - memcpy(last, secName, secNameLen); - e->secName = last; - last += secNameLen; - if (contextNameLen) { - memcpy(last, contextName, contextNameLen); - e->contextName = last; - } else - e->contextName = last - 1; - e->network = network.s_addr; - e->mask = mask.s_addr; - e->next = NULL; - - if (com2SecListLast != NULL) { - com2SecListLast->next = e; - com2SecListLast = e; - } else { - com2SecListLast = com2SecList = e; - } + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + DEBUGMSGTL(("netsnmp_udp_parse_security", + "<\"%s\", %s/%s> => \"%s\"\n", community, + inet_ntop(AF_INET, &network, buf1, sizeof(buf1)), + inet_ntop(AF_INET, &mask, buf2, sizeof(buf2)), + secName)); + } + + memcpy(last, community, communityLen); + last += communityLen; + memcpy(last, secName, secNameLen); + e->secName = last; + last += secNameLen; + if (contextNameLen) { + memcpy(last, contextName, contextNameLen); + e->contextName = last; + } else + e->contextName = last - 1; + e->network = network.s_addr; + e->mask = mask.s_addr; + e->next = NULL; + + if (com2SecListLast != NULL) { + com2SecListLast->next = e; + com2SecListLast = e; + } else { + com2SecListLast = com2SecList = e; } }