int vacm_in_view (struct packet_info *pi, oid *name, int namelen) { struct vacm_securityEntry *sp = securityFirst; struct vacm_accessEntry *ap; struct vacm_groupEntry *gp; struct vacm_viewEntry *vp; char *vn; char *sn; if (pi->sec_model == SNMP_SEC_MODEL_SNMPv1 || pi->sec_model == SNMP_SEC_MODEL_SNMPv2c) { DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: ver=%d, source=%.8x, community=%s\n", pi->version, pi->source.sin_addr.s_addr, pi->community)); /* allow running without snmpd.conf */ if (sp == NULL) { DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: accepted with no com2sec entries\n")); switch (pi->pdutype) { case SNMP_MSG_GET: case SNMP_MSG_GETNEXT: case SNMP_MSG_GETBULK: return 1; default: return 0; } } while (sp) { if ((pi->source.sin_addr.s_addr & sp->sourceMask.sin_addr.s_addr) == sp->sourceIp.sin_addr.s_addr && strcmp(sp->community, (char *)pi->community) == 0) break; sp = sp->next; } if (sp == NULL) return 0; sn = sp->securityName; } else { sn = NULL; } if (sn == NULL) return 0; DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: securityName == %s\n", sn)); gp = vacm_getGroupEntry(pi->sec_model, sn); if (gp == NULL) return 0; DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: groupName == %s\n", gp->groupName)); ap = vacm_getAccessEntry(gp->groupName, "", pi->sec_model, pi->sec_level); if (ap == NULL) return 0; switch (pi->pdutype) { case SNMP_MSG_GET: case SNMP_MSG_GETNEXT: case SNMP_MSG_GETBULK: vn = ap->readView; break; case SNMP_MSG_SET: vn = ap->writeView; break; case SNMP_MSG_TRAP: case SNMP_MSG_TRAP2: case SNMP_MSG_INFORM: vn = ap->notifyView; break; default: fprintf(stderr,"bad msg type in vacm_in_view: %d\n", pi->pdutype); vn = ap->readView; } DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: viewName == %s\n", vn)); vp = vacm_getViewEntry (vn, name, namelen); if (vp == NULL) return 0; DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: viewType == %d\n", vp->viewType)); if (vp->viewType == SNMP_VIEW_EXCLUDED) return 0; return 1; }
u_char *var_vacm_view(struct variable *vp, oid *name, int *length, int exact, int *var_len, WriteMethod **write_method) { struct vacm_viewEntry *gp; char viewName[32]; oid subtree[MAX_OID_LEN]; int subtreeLen = 0; oid *op, *op1; int len; char *cp; int cmp; write_method = NULL; if (memcmp(name, vp->name, sizeof(oid)*vp->namelen) != 0) { memcpy(name, vp->name, sizeof(oid)*vp->namelen); *length = vp->namelen; } if (exact) { if (*length < 15) return NULL; op = name+12; len = *op++; cp = viewName; while (len-- > 0) { *cp++ = *op++; } *cp = 0; len = *length - (op - name); op1 = subtree; while (len-- > 0) { *op1++ = *op++; subtreeLen++; } if (op != name + *length) { return NULL; } gp = vacm_getViewEntry(viewName, subtree, subtreeLen); } else { viewName[0] = 0; op = name+12; if (op >= name + *length) { } else { len = *op; cp = viewName; while (len-- >= 0) { *cp++ = *op++; } *cp = 0; } if (op >= name + *length) { } else { len = *length - (op - name); op1 = subtree; while (len-- >= 0) { *op1++ = *op++; subtreeLen++; } } vacm_scanViewInit(); while ((gp = vacm_scanViewNext()) != NULL) { cmp = strcmp(gp->viewName, viewName); if (cmp > 0) break; if (cmp < 0) continue; } if (gp) { *length = 12; cp = gp->viewName; do { name[(*length)++] = *cp++; } while (*cp); op1 = gp->viewSubtree; len = gp->viewSubtreeLen; do { name[(*length)++] = *op1++; } while (len-- > 0); } } if (!gp) return NULL; *var_len =sizeof(long_return); switch (vp->magic) { case VIEWNAME: *var_len = gp->viewName[0]; return (u_char *)&gp->viewName[1]; case VIEWSUBTREE: *var_len = gp->viewSubtreeLen*sizeof(oid); return (u_char *)gp->viewSubtree; case VIEWMASK: *var_len = (gp->viewSubtreeLen + 7) / 8; return (u_char *)gp->viewMask; case VIEWTYPE: long_return = gp->viewType; return (u_char *)&long_return; case VIEWSTORAGE: long_return = gp->viewStorageType; return (u_char *)&long_return; case VIEWSTATUS: long_return = gp->viewStatus; return (u_char *)&long_return; } return NULL; }
int vacm_check_view_contents(netsnmp_pdu *pdu, oid * name, size_t namelen, int check_subtree, int viewtype, int flags) { struct vacm_accessEntry *ap; struct vacm_groupEntry *gp; struct vacm_viewEntry *vp; char vacm_default_context[1] = ""; const char *contextName = vacm_default_context; const char *sn = NULL; char *vn; const char *pdu_community; /* * len defined by the vacmContextName object */ #define CONTEXTNAMEINDEXLEN 32 char contextNameIndex[CONTEXTNAMEINDEXLEN + 1]; #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) #if defined(NETSNMP_DISABLE_SNMPV1) if (pdu->version == SNMP_VERSION_2c) #else #if defined(NETSNMP_DISABLE_SNMPV2C) if (pdu->version == SNMP_VERSION_1) #else if (pdu->version == SNMP_VERSION_1 || pdu->version == SNMP_VERSION_2c) #endif #endif { pdu_community = (const char *) pdu->community; if (!pdu_community) pdu_community = ""; if (snmp_get_do_debugging()) { char *buf; if (pdu->community) { buf = (char *) malloc(1 + pdu->community_len); memcpy(buf, pdu->community, pdu->community_len); buf[pdu->community_len] = '\0'; } else { DEBUGMSGTL(("mibII/vacm_vars", "NULL community")); buf = strdup("NULL"); } DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: ver=%ld, community=%s\n", pdu->version, buf)); free(buf); } /* * Okay, if this PDU was received from a UDP or a TCP transport then * ask the transport abstraction layer to map its source address and * community string to a security name for us. */ if (0) { #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN } else if (pdu->tDomain == netsnmpUDPDomain #ifdef NETSNMP_TRANSPORT_TCP_DOMAIN || pdu->tDomain == netsnmp_snmpTCPDomain #endif ) { if (!netsnmp_udp_getSecName(pdu->transport_data, pdu->transport_data_length, pdu_community, pdu->community_len, &sn, &contextName)) { /* * There are no com2sec entries. */ sn = NULL; } /* force the community -> context name mapping here */ SNMP_FREE(pdu->contextName); pdu->contextName = strdup(contextName); pdu->contextNameLen = strlen(contextName); #endif #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN } else if (pdu->tDomain == netsnmp_UDPIPv6Domain #ifdef NETSNMP_TRANSPORT_TCPIPV6_DOMAIN || pdu->tDomain == netsnmp_TCPIPv6Domain #endif ) { if (!netsnmp_udp6_getSecName(pdu->transport_data, pdu->transport_data_length, pdu_community, pdu->community_len, &sn, &contextName)) { /* * There are no com2sec entries. */ sn = NULL; } /* force the community -> context name mapping here */ SNMP_FREE(pdu->contextName); pdu->contextName = strdup(contextName); pdu->contextNameLen = strlen(contextName); #endif #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN } else if (pdu->tDomain == netsnmp_UnixDomain){ if (!netsnmp_unix_getSecName(pdu->transport_data, pdu->transport_data_length, pdu_community, pdu->community_len, &sn, &contextName)) { sn = NULL; } /* force the community -> context name mapping here */ SNMP_FREE(pdu->contextName); pdu->contextName = strdup(contextName); pdu->contextNameLen = strlen(contextName); #endif } else { /* * Map other <community, transport-address> pairs to security names * here. For now just let non-IPv4 transport always succeed. * * WHAAAATTTT. No, we don't let non-IPv4 transports * succeed! You must fix this to make it usable, sorry. * From a security standpoint this is insane. -- Wes */ /** @todo alternate com2sec mappings for non v4 transports. Should be implemented via registration */ sn = NULL; } } else #endif /* support for community based SNMP */ if (find_sec_mod(pdu->securityModel)) { /* * any legal defined v3 security model */ DEBUGMSG(("mibII/vacm_vars", "vacm_in_view: ver=%ld, model=%d, secName=%s\n", pdu->version, pdu->securityModel, pdu->securityName)); sn = pdu->securityName; contextName = pdu->contextName; } else { sn = NULL; } if (sn == NULL) { #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) snmp_increment_statistic(STAT_SNMPINBADCOMMUNITYNAMES); #endif DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: No security name found\n")); return VACM_NOSECNAME; } if (pdu->contextNameLen > CONTEXTNAMEINDEXLEN) { DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: bad ctxt length %d\n", (int)pdu->contextNameLen)); return VACM_NOSUCHCONTEXT; } /* * NULL termination of the pdu field is ugly here. Do in PDU parsing? */ if (pdu->contextName) memcpy(contextNameIndex, pdu->contextName, pdu->contextNameLen); else contextNameIndex[0] = '\0'; contextNameIndex[pdu->contextNameLen] = '\0'; if (!(flags & VACM_CHECK_VIEW_CONTENTS_DNE_CONTEXT_OK) && !netsnmp_subtree_find_first(contextNameIndex)) { /* * rfc 3415 section 3.2, step 1 * no such context here; return no such context error */ DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: no such ctxt \"%s\"\n", contextNameIndex)); return VACM_NOSUCHCONTEXT; } DEBUGMSGTL(("mibII/vacm_vars", "vacm_in_view: sn=%s", sn)); gp = vacm_getGroupEntry(pdu->securityModel, sn); if (gp == NULL) { DEBUGMSG(("mibII/vacm_vars", "\n")); return VACM_NOGROUP; } DEBUGMSG(("mibII/vacm_vars", ", gn=%s", gp->groupName)); ap = vacm_getAccessEntry(gp->groupName, contextNameIndex, pdu->securityModel, pdu->securityLevel); if (ap == NULL) { DEBUGMSG(("mibII/vacm_vars", "\n")); return VACM_NOACCESS; } if (name == NULL) { /* only check the setup of the vacm for the request */ DEBUGMSG(("mibII/vacm_vars", ", Done checking setup\n")); return VACM_SUCCESS; } if (viewtype < 0 || viewtype >= VACM_MAX_VIEWS) { DEBUGMSG(("mibII/vacm_vars", " illegal view type\n")); return VACM_NOACCESS; } vn = ap->views[viewtype]; DEBUGMSG(("mibII/vacm_vars", ", vn=%s", vn)); if (check_subtree) { DEBUGMSG(("mibII/vacm_vars", "\n")); return vacm_checkSubtree(vn, name, namelen); } vp = vacm_getViewEntry(vn, name, namelen, VACM_MODE_FIND); if (vp == NULL) { DEBUGMSG(("mibII/vacm_vars", "\n")); return VACM_NOVIEW; } DEBUGMSG(("mibII/vacm_vars", ", vt=%d\n", vp->viewType)); if (vp->viewType == SNMP_VIEW_EXCLUDED) { #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) #if defined(NETSNMP_DISABLE_SNMPV1) if (pdu->version == SNMP_VERSION_2c) #else #if defined(NETSNMP_DISABLE_SNMPV2C) if (pdu->version == SNMP_VERSION_1) #else if (pdu->version == SNMP_VERSION_1 || pdu->version == SNMP_VERSION_2c) #endif #endif { snmp_increment_statistic(STAT_SNMPINBADCOMMUNITYUSES); } #endif return VACM_NOTINVIEW; } return VACM_SUCCESS; } /* end vacm_in_view() */