Blame agent/mibgroup/ucd-snmp/proxy.c

Packit Service b38f0b
/* Portions of this file are subject to the following copyright(s).  See
Packit Service b38f0b
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit Service b38f0b
 * that may apply:
Packit Service b38f0b
 */
Packit Service b38f0b
/*
Packit Service b38f0b
 * Portions of this file are copyrighted by:
Packit Service b38f0b
 * Copyright @ 2009 Sun Microsystems, Inc. All rights reserved.
Packit Service b38f0b
 * Use is subject to license terms specified in the COPYING file
Packit Service b38f0b
 * distributed with the Net-SNMP package.
Packit Service b38f0b
 *
Packit Service b38f0b
 * Portions of this file are copyrighted by:
Packit Service b38f0b
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
Packit Service b38f0b
 * Use is subject to license terms specified in the COPYING file
Packit Service b38f0b
 * distributed with the Net-SNMP package.
Packit Service b38f0b
 */
Packit Service b38f0b
#include <net-snmp/net-snmp-config.h>
Packit Service b38f0b
#include <net-snmp/net-snmp-features.h>
Packit Service b38f0b
Packit Service b38f0b
#include <sys/types.h>
Packit Service b38f0b
#if HAVE_STRING_H
Packit Service b38f0b
#include <string.h>
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifdef HAVE_NETINET_IN_H
Packit Service b38f0b
#include <netinet/in.h>
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
#include <net-snmp/net-snmp-includes.h>
Packit Service b38f0b
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit Service b38f0b
Packit Service b38f0b
#include "proxy.h"
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_require(handler_mark_requests_as_delegated)
Packit Service b38f0b
netsnmp_feature_require(request_set_error_idx)
Packit Service b38f0b
Packit Service b38f0b
static struct simple_proxy *proxies = NULL;
Packit Service b38f0b
Packit Service b38f0b
/*
Packit Service b38f0b
 * this must be standardized somewhere, right? 
Packit Service b38f0b
 */
Packit Service b38f0b
#define MAX_ARGS 128
Packit Service b38f0b
Packit Service b38f0b
char           *context_string;
Packit Service b38f0b
Packit Service b38f0b
static void
Packit Service b38f0b
proxyOptProc(int argc, char *const *argv, int opt)
Packit Service b38f0b
{
Packit Service b38f0b
    switch (opt) {
Packit Service b38f0b
    case 'C':
Packit Service b38f0b
        while (*optarg) {
Packit Service b38f0b
            switch (*optarg++) {
Packit Service b38f0b
            case 'n':
Packit Service b38f0b
                optind++;
Packit Service b38f0b
                if (optind < argc) {
Packit Service b38f0b
                    context_string = argv[optind - 1];
Packit Service b38f0b
                } else {
Packit Service b38f0b
                    config_perror("No context name passed to -Cn");
Packit Service b38f0b
                }
Packit Service b38f0b
                break;
Packit Service b38f0b
            case 'c':
Packit Service b38f0b
                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
Packit Service b38f0b
                                       NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY, 1);
Packit Service b38f0b
                break;
Packit Service b38f0b
            default:
Packit Service b38f0b
                config_perror("unknown argument passed to -C");
Packit Service b38f0b
                break;
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
        break;
Packit Service b38f0b
    default:
Packit Service b38f0b
        break;
Packit Service b38f0b
        /*
Packit Service b38f0b
         * shouldn't get here 
Packit Service b38f0b
         */
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
proxy_parse_config(const char *token, char *line)
Packit Service b38f0b
{
Packit Service b38f0b
    /*
Packit Service b38f0b
     * proxy args [base-oid] [remap-to-remote-oid] 
Packit Service b38f0b
     */
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_session session, *ss;
Packit Service b38f0b
    struct simple_proxy *newp, **listpp;
Packit Service b38f0b
    char           *argv[MAX_ARGS];
Packit Service b38f0b
    int             argn, arg;
Packit Service b38f0b
    char           *cp;
Packit Service b38f0b
    char           *buff;
Packit Service b38f0b
    netsnmp_handler_registration *reg;
Packit Service b38f0b
Packit Service b38f0b
    context_string = NULL;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("proxy_config", "entering\n"));
Packit Service b38f0b
Packit Service b38f0b
    /* Put the first string into the array */
Packit Service b38f0b
    argv[0] = strdup("snmpd-proxy");
Packit Service b38f0b
    if (!argv[0]) {
Packit Service b38f0b
        config_perror("could not allocate memory for argv[0]");
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
    /*
Packit Service b38f0b
     * create the argv[] like array 
Packit Service b38f0b
     */
Packit Service b38f0b
    /* Allocates memory to store the parameters value */     
Packit Service b38f0b
    buff = (char *) malloc (strlen(line)+1);
Packit Service b38f0b
    if (!buff) {
Packit Service b38f0b
        config_perror("could not allocate memory for buff");
Packit Service b38f0b
         /* Free the memory allocated */
Packit Service b38f0b
        SNMP_FREE(argv[0]);
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    for (argn = 1, cp = line; cp && argn < MAX_ARGS;) {
Packit Service b38f0b
        /* Copy a parameter into the buff */
Packit Service b38f0b
        cp = copy_nword(cp, buff, strlen(cp)+1);
Packit Service b38f0b
        argv[argn] = strdup(buff);
Packit Service b38f0b
        if (!argv[argn]) {
Packit Service b38f0b
            config_perror("could not allocate memory for argv[n]");
Packit Service b38f0b
            while(argn--)
Packit Service b38f0b
                SNMP_FREE(argv[argn]);
Packit Service b38f0b
            SNMP_FREE(buff);
Packit Service b38f0b
            return;
Packit Service b38f0b
        }
Packit Service b38f0b
	argn++;
Packit Service b38f0b
    }
Packit Service b38f0b
    SNMP_FREE(buff);
Packit Service b38f0b
Packit Service b38f0b
    for (arg = 0; arg < argn; arg++) {
Packit Service b38f0b
        DEBUGMSGTL(("proxy_args", "final args: %d = %s\n", arg,
Packit Service b38f0b
                    argv[arg]));
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("proxy_config", "parsing args: %d\n", argn));
Packit Service b38f0b
    /* Call special parse_args that allows for no specified community string */
Packit Service b38f0b
    arg = netsnmp_parse_args(argn, argv, &session, "C:", proxyOptProc,
Packit Service b38f0b
                             NETSNMP_PARSE_ARGS_NOLOGGING |
Packit Service b38f0b
                             NETSNMP_PARSE_ARGS_NOZERO);
Packit Service b38f0b
Packit Service b38f0b
    /* reset this in case we modified it */
Packit Service b38f0b
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
Packit Service b38f0b
                           NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY, 0);
Packit Service b38f0b
    
Packit Service b38f0b
    if (arg < 0) {
Packit Service b38f0b
        config_perror("failed to parse proxy args");
Packit Service b38f0b
        /* Free the memory allocated */
Packit Service b38f0b
        while(argn--)
Packit Service b38f0b
            SNMP_FREE(argv[argn]);
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUGMSGTL(("proxy_config", "done parsing args\n"));
Packit Service b38f0b
Packit Service b38f0b
    if (arg >= argn) {
Packit Service b38f0b
        config_perror("missing base oid");
Packit Service b38f0b
        /* Free the memory allocated */
Packit Service b38f0b
        while(argn--)
Packit Service b38f0b
            SNMP_FREE(argv[argn]);   
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * usm_set_reportErrorOnUnknownID(0); 
Packit Service b38f0b
     *
Packit Service b38f0b
     * hack, stupid v3 ASIs. 
Packit Service b38f0b
     */
Packit Service b38f0b
    /*
Packit Service b38f0b
     * XXX: on a side note, we don't really need to be a reference
Packit Service b38f0b
     * platform any more so the proper thing to do would be to fix
Packit Service b38f0b
     * snmplib/snmpusm.c to pass in the pdu type to usm_process_incoming
Packit Service b38f0b
     * so this isn't needed. 
Packit Service b38f0b
     */
Packit Service b38f0b
    ss = snmp_open(&session);
Packit Service b38f0b
    /*
Packit Service b38f0b
     * usm_set_reportErrorOnUnknownID(1); 
Packit Service b38f0b
     */
Packit Service b38f0b
    if (ss == NULL) {
Packit Service b38f0b
        /*
Packit Service b38f0b
         * diagnose snmp_open errors with the input netsnmp_session pointer 
Packit Service b38f0b
         */
Packit Service b38f0b
        snmp_sess_perror("snmpget", &session);
Packit Service b38f0b
        /* Free the memory allocated */
Packit Service b38f0b
        while(argn--)
Packit Service b38f0b
            SNMP_FREE(argv[argn]);
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    newp = (struct simple_proxy *) calloc(1, sizeof(struct simple_proxy));
Packit Service b38f0b
Packit Service b38f0b
    newp->sess = ss;
Packit Service b38f0b
    DEBUGMSGTL(("proxy_init", "name = %s\n", argv[arg]));
Packit Service b38f0b
    newp->name_len = MAX_OID_LEN;
Packit Service b38f0b
    if (!snmp_parse_oid(argv[arg++], newp->name, &newp->name_len)) {
Packit Service b38f0b
        snmp_perror("proxy");
Packit Service b38f0b
        config_perror("illegal proxy oid specified\n");
Packit Service b38f0b
        /*deallocate the memory previously allocated*/
Packit Service b38f0b
        SNMP_FREE(newp);
Packit Service b38f0b
        while(argn--)
Packit Service b38f0b
            SNMP_FREE(argv[argn]);
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (arg < argn) {
Packit Service b38f0b
        DEBUGMSGTL(("proxy_init", "base = %s\n", argv[arg]));
Packit Service b38f0b
        newp->base_len = MAX_OID_LEN;
Packit Service b38f0b
        if (!snmp_parse_oid(argv[arg++], newp->base, &newp->base_len)) {
Packit Service b38f0b
            snmp_perror("proxy");
Packit Service b38f0b
            config_perror("illegal variable name specified (base oid)\n");
Packit Service b38f0b
            SNMP_FREE(newp);
Packit Service b38f0b
            /* Free the memory allocated */
Packit Service b38f0b
            while(argn--)
Packit Service b38f0b
                SNMP_FREE(argv[argn]);
Packit Service b38f0b
            return;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    if ( context_string )
Packit Service b38f0b
        newp->context = strdup(context_string);
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("proxy_init", "registering at: "));
Packit Service b38f0b
    DEBUGMSGOID(("proxy_init", newp->name, newp->name_len));
Packit Service b38f0b
    DEBUGMSG(("proxy_init", "\n"));
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * add to our chain 
Packit Service b38f0b
     */
Packit Service b38f0b
    /*
Packit Service b38f0b
     * must be sorted! 
Packit Service b38f0b
     */
Packit Service b38f0b
    listpp = &proxies;
Packit Service b38f0b
    while (*listpp &&
Packit Service b38f0b
           snmp_oid_compare(newp->name, newp->name_len,
Packit Service b38f0b
                            (*listpp)->name, (*listpp)->name_len) > 0) {
Packit Service b38f0b
        listpp = &((*listpp)->next);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * listpp should be next in line from us. 
Packit Service b38f0b
     */
Packit Service b38f0b
    if (*listpp) {
Packit Service b38f0b
        /*
Packit Service b38f0b
         * make our next in the link point to the current link 
Packit Service b38f0b
         */
Packit Service b38f0b
        newp->next = *listpp;
Packit Service b38f0b
    }
Packit Service b38f0b
    /*
Packit Service b38f0b
     * replace current link with us 
Packit Service b38f0b
     */
Packit Service b38f0b
    *listpp = newp;
Packit Service b38f0b
Packit Service b38f0b
    reg = netsnmp_create_handler_registration("proxy",
Packit Service b38f0b
                                              proxy_handler,
Packit Service b38f0b
                                              newp->name,
Packit Service b38f0b
                                              newp->name_len,
Packit Service b38f0b
                                              HANDLER_CAN_RWRITE);
Packit Service b38f0b
    reg->handler->myvoid = newp;
Packit Service b38f0b
    if (context_string)
Packit Service b38f0b
        reg->contextName = strdup(context_string);
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_register_handler(reg);
Packit Service b38f0b
    /* Free the memory allocated */
Packit Service b38f0b
    while(argn--)
Packit Service b38f0b
        SNMP_FREE(argv[argn]);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
proxy_free_config(void)
Packit Service b38f0b
{
Packit Service b38f0b
    struct simple_proxy *rm;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("proxy_free_config", "Free config\n"));
Packit Service b38f0b
    while (proxies) {
Packit Service b38f0b
        rm = proxies;
Packit Service b38f0b
        proxies = rm->next;
Packit Service b38f0b
Packit Service b38f0b
        DEBUGMSGTL(( "proxy_free_config", "freeing "));
Packit Service b38f0b
        DEBUGMSGOID(("proxy_free_config", rm->name, rm->name_len));
Packit Service b38f0b
        DEBUGMSG((   "proxy_free_config", " (%s)\n", rm->context));
Packit Service b38f0b
        unregister_mib_context(rm->name, rm->name_len,
Packit Service b38f0b
                               DEFAULT_MIB_PRIORITY, 0, 0,
Packit Service b38f0b
                               rm->context);
Packit Service b38f0b
        SNMP_FREE(rm->variables);
Packit Service b38f0b
        SNMP_FREE(rm->context);
Packit Service b38f0b
        snmp_close(rm->sess);
Packit Service b38f0b
        SNMP_FREE(rm);
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/*
Packit Service b38f0b
 * Configure special parameters on the session.
Packit Service b38f0b
 * Currently takes the parameter configured and changes it if something 
Packit Service b38f0b
 * was configured.  It becomes "-c" if the community string from the pdu
Packit Service b38f0b
 * is placed on the session.
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
proxy_fill_in_session(netsnmp_mib_handler *handler,
Packit Service b38f0b
                      netsnmp_agent_request_info *reqinfo,
Packit Service b38f0b
                      void **configured)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_session *session;
Packit Service b38f0b
    struct simple_proxy *sp;
Packit Service b38f0b
Packit Service b38f0b
    sp = (struct simple_proxy *) handler->myvoid;
Packit Service b38f0b
    if (!sp) {
Packit Service b38f0b
        return 0;
Packit Service b38f0b
    }
Packit Service b38f0b
    session = sp->sess;
Packit Service b38f0b
    if (!session) {
Packit Service b38f0b
        return 0;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
Packit Service b38f0b
    if (
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV1
Packit Service b38f0b
        ((session->version == SNMP_VERSION_1) &&
Packit Service b38f0b
         !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
Packit Service b38f0b
                                 NETSNMP_DS_LIB_DISABLE_V1)) ||
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit Service b38f0b
        ((session->version == SNMP_VERSION_2c) &&
Packit Service b38f0b
         !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
Packit Service b38f0b
                                 NETSNMP_DS_LIB_DISABLE_V2c)) ||
Packit Service b38f0b
#endif
Packit Service b38f0b
        0 ) { /* 0 to terminate '||' above */
Packit Service b38f0b
Packit Service b38f0b
        /*
Packit Service b38f0b
         * Check if session has community string defined for it.
Packit Service b38f0b
         * If not, need to extract community string from the pdu.
Packit Service b38f0b
         * Copy to session and set 'configured' to indicate this.
Packit Service b38f0b
         */
Packit Service b38f0b
        if (session->community_len == 0) {
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "session has no community string\n"));
Packit Service b38f0b
            if (reqinfo->asp == NULL || reqinfo->asp->pdu == NULL ||
Packit Service b38f0b
                reqinfo->asp->pdu->community_len == 0) {
Packit Service b38f0b
                return 0;
Packit Service b38f0b
            }
Packit Service b38f0b
Packit Service b38f0b
            *configured = strdup("-c");
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "pdu has community string\n"));
Packit Service b38f0b
            session->community_len = reqinfo->asp->pdu->community_len;
Packit Service b38f0b
            session->community = malloc(session->community_len + 1);
Packit Service b38f0b
            sprintf((char *)session->community, "%.*s",
Packit Service b38f0b
                    (int) session->community_len,
Packit Service b38f0b
                    (const char *)reqinfo->asp->pdu->community);
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
    return 1;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/*
Packit Service b38f0b
 * Free any specially configured parameters used on the session.
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
proxy_free_filled_in_session_args(netsnmp_session *session, void **configured)
Packit Service b38f0b
{
Packit Service b38f0b
Packit Service b38f0b
    /* Only do comparisions, etc., if something was configured */
Packit Service b38f0b
    if (*configured == NULL) {
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /* If used community string from pdu, release it from session now */
Packit Service b38f0b
    if (strcmp((const char *)(*configured), "-c") == 0) {
Packit Service b38f0b
        free(session->community);
Packit Service b38f0b
        session->community = NULL;
Packit Service b38f0b
        session->community_len = 0;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    free((u_char *)(*configured));
Packit Service b38f0b
    *configured = NULL;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
init_proxy(void)
Packit Service b38f0b
{
Packit Service b38f0b
    snmpd_register_config_handler("proxy", proxy_parse_config,
Packit Service b38f0b
                                  proxy_free_config,
Packit Service b38f0b
                                  "[snmpcmd args] host oid [remoteoid]");
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
shutdown_proxy(void)
Packit Service b38f0b
{
Packit Service b38f0b
    proxy_free_config();
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
int
Packit Service b38f0b
proxy_handler(netsnmp_mib_handler *handler,
Packit Service b38f0b
              netsnmp_handler_registration *reginfo,
Packit Service b38f0b
              netsnmp_agent_request_info *reqinfo,
Packit Service b38f0b
              netsnmp_request_info *requests)
Packit Service b38f0b
{
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_pdu    *pdu;
Packit Service b38f0b
    struct simple_proxy *sp;
Packit Service b38f0b
    oid            *ourname;
Packit Service b38f0b
    size_t          ourlength;
Packit Service b38f0b
    netsnmp_request_info *request = requests;
Packit Service b38f0b
    u_char         *configured = NULL;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("proxy", "proxy handler starting, mode = %d\n",
Packit Service b38f0b
                reqinfo->mode));
Packit Service b38f0b
Packit Service b38f0b
    switch (reqinfo->mode) {
Packit Service b38f0b
    case MODE_GET:
Packit Service b38f0b
    case MODE_GETNEXT:
Packit Service b38f0b
    case MODE_GETBULK:         /* WWWXXX */
Packit Service b38f0b
        pdu = snmp_pdu_create(reqinfo->mode);
Packit Service b38f0b
        break;
Packit Service b38f0b
Packit Service b38f0b
#ifndef NETSNMP_NO_WRITE_SUPPORT
Packit Service b38f0b
    case MODE_SET_ACTION:
Packit Service b38f0b
        pdu = snmp_pdu_create(SNMP_MSG_SET);
Packit Service b38f0b
        break;
Packit Service b38f0b
Packit Service b38f0b
    case MODE_SET_UNDO:
Packit Service b38f0b
        /*
Packit Service b38f0b
         *  If we set successfully (status == NOERROR),
Packit Service b38f0b
         *     we can't back out again, so need to report the fact.
Packit Service b38f0b
         *  If we failed to set successfully, then we're fine.
Packit Service b38f0b
         */
Packit Service b38f0b
        for (request = requests; request; request=request->next) {
Packit Service b38f0b
            if (request->status == SNMP_ERR_NOERROR) {
Packit Service b38f0b
                netsnmp_set_request_error(reqinfo, requests,
Packit Service b38f0b
                                          SNMP_ERR_UNDOFAILED);
Packit Service b38f0b
                return SNMP_ERR_UNDOFAILED;
Packit Service b38f0b
	    }
Packit Service b38f0b
	}
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
Packit Service b38f0b
    case MODE_SET_RESERVE1:
Packit Service b38f0b
    case MODE_SET_RESERVE2:
Packit Service b38f0b
    case MODE_SET_FREE:
Packit Service b38f0b
    case MODE_SET_COMMIT:
Packit Service b38f0b
        /*
Packit Service b38f0b
         *  Nothing to do in this pass
Packit Service b38f0b
         */
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
Packit Service b38f0b
Packit Service b38f0b
    default:
Packit Service b38f0b
        snmp_log(LOG_WARNING, "unsupported mode for proxy called (%d)\n",
Packit Service b38f0b
                               reqinfo->mode);
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    sp = (struct simple_proxy *) handler->myvoid;
Packit Service b38f0b
Packit Service b38f0b
    if (!pdu || !sp) {
Packit Service b38f0b
        netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR);
Packit Service b38f0b
        if (pdu)
Packit Service b38f0b
            snmp_free_pdu(pdu);
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    while (request) {
Packit Service b38f0b
        ourname = request->requestvb->name;
Packit Service b38f0b
        ourlength = request->requestvb->name_length;
Packit Service b38f0b
Packit Service b38f0b
        if (sp->base_len &&
Packit Service b38f0b
            reqinfo->mode == MODE_GETNEXT &&
Packit Service b38f0b
            (snmp_oid_compare(ourname, ourlength,
Packit Service 127f7a
                              sp->name, sp->name_len) < 0)) {
Packit Service b38f0b
            DEBUGMSGTL(( "proxy", "request is out of registered range\n"));
Packit Service b38f0b
            /*
Packit Service b38f0b
             * Create GETNEXT request with an OID so the
Packit Service b38f0b
             * master returns the first OID in the registered range.
Packit Service b38f0b
             */
Packit Service b38f0b
            memcpy(ourname, sp->base, sp->base_len * sizeof(oid));
Packit Service b38f0b
            ourlength = sp->base_len;
Packit Service b38f0b
            if (ourname[ourlength-1] <= 1) {
Packit Service b38f0b
                /*
Packit Service b38f0b
                 * The registered range ends with x.y.z.1
Packit Service b38f0b
                 * -> ask for the next of x.y.z
Packit Service b38f0b
                 */
Packit Service b38f0b
                ourlength--;
Packit Service b38f0b
            } else {
Packit Service b38f0b
                /*
Packit Service b38f0b
                 * The registered range ends with x.y.z.A
Packit Service b38f0b
                 * -> ask for the next of x.y.z.A-1.MAX_SUBID
Packit Service b38f0b
                 */
Packit Service b38f0b
                ourname[ourlength-1]--;
Packit Service b38f0b
                ourname[ourlength] = MAX_SUBID;
Packit Service b38f0b
                ourlength++;
Packit Service b38f0b
            }
Packit Service b38f0b
        } else if (sp->base_len > 0) {
Packit Service b38f0b
            if ((ourlength - sp->name_len + sp->base_len) > MAX_OID_LEN) {
Packit Service b38f0b
                /*
Packit Service b38f0b
                 * too large 
Packit Service b38f0b
                 */
Packit Service b38f0b
                if (pdu)
Packit Service b38f0b
                    snmp_free_pdu(pdu);
Packit Service b38f0b
                snmp_log(LOG_ERR,
Packit Service b38f0b
                         "proxy oid request length is too long\n");
Packit Service b38f0b
                return SNMP_ERR_NOERROR;
Packit Service b38f0b
            }
Packit Service b38f0b
            /*
Packit Service b38f0b
             * suffix appended? 
Packit Service b38f0b
             */
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "length=%d, base_len=%d, name_len=%d\n",
Packit Service b38f0b
                        (int)ourlength, (int)sp->base_len, (int)sp->name_len));
Packit Service b38f0b
            if (ourlength > sp->name_len)
Packit Service b38f0b
                memcpy(&(sp->base[sp->base_len]), &(ourname[sp->name_len]),
Packit Service b38f0b
                       sizeof(oid) * (ourlength - sp->name_len));
Packit Service b38f0b
            ourlength = ourlength - sp->name_len + sp->base_len;
Packit Service b38f0b
            ourname = sp->base;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        snmp_pdu_add_variable(pdu, ourname, ourlength,
Packit Service b38f0b
                              request->requestvb->type,
Packit Service b38f0b
                              request->requestvb->val.string,
Packit Service b38f0b
                              request->requestvb->val_len);
Packit Service b38f0b
        request->delegated = 1;
Packit Service b38f0b
        request = request->next;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * Customize session parameters based on request information
Packit Service b38f0b
     */
Packit Service b38f0b
    if (!proxy_fill_in_session(handler, reqinfo, (void **)&configured)) {
Packit Service b38f0b
        netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR);
Packit Service b38f0b
        if (pdu)
Packit Service b38f0b
            snmp_free_pdu(pdu);
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * send the request out 
Packit Service b38f0b
     */
Packit Service b38f0b
    DEBUGMSGTL(("proxy", "sending pdu\n"));
Packit Service b38f0b
    snmp_async_send(sp->sess, pdu, proxy_got_response,
Packit Service b38f0b
                    netsnmp_create_delegated_cache(handler, reginfo,
Packit Service b38f0b
                                                   reqinfo, requests,
Packit Service b38f0b
                                                   (void *) sp));
Packit Service b38f0b
Packit Service b38f0b
    /* Free any special parameters generated on the session */
Packit Service b38f0b
    proxy_free_filled_in_session_args(sp->sess, (void **)&configured);
Packit Service b38f0b
Packit Service b38f0b
    return SNMP_ERR_NOERROR;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
int
Packit Service b38f0b
proxy_got_response(int operation, netsnmp_session * sess, int reqid,
Packit Service b38f0b
                   netsnmp_pdu *pdu, void *cb_data)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data;
Packit Service b38f0b
    netsnmp_request_info  *requests, *request = NULL;
Packit Service b38f0b
    netsnmp_variable_list *vars,     *var     = NULL;
Packit Service b38f0b
Packit Service b38f0b
    struct simple_proxy *sp;
Packit Service b38f0b
    oid             myname[MAX_OID_LEN];
Packit Service b38f0b
    size_t          myname_len = MAX_OID_LEN;
Packit Service b38f0b
Packit Service b38f0b
    cache = netsnmp_handler_check_cache(cache);
Packit Service b38f0b
Packit Service b38f0b
    if (!cache) {
Packit Service b38f0b
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    requests = cache->requests;
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
    sp = (struct simple_proxy *) cache->localinfo;
Packit Service b38f0b
Packit Service b38f0b
    if (!sp) {
Packit Service b38f0b
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
Packit Service b38f0b
        return SNMP_ERR_NOERROR;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    switch (operation) {
Packit Service b38f0b
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
Packit Service b38f0b
        /*
Packit Service b38f0b
         * WWWXXX: don't leave requests delayed if operation is
Packit Service b38f0b
         * something like TIMEOUT 
Packit Service b38f0b
         */
Packit Service b38f0b
        DEBUGMSGTL(("proxy", "got timed out... requests = %8p\n", requests));
Packit Service b38f0b
Packit Service b38f0b
        netsnmp_handler_mark_requests_as_delegated(requests,
Packit Service b38f0b
                                                   REQUEST_IS_NOT_DELEGATED);
Packit Service b38f0b
        if(cache->reqinfo->mode != MODE_GETNEXT) {
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "  ignoring timeout\n"));
Packit Service b38f0b
            netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */
Packit Service b38f0b
                                      SNMP_ERR_GENERR);
Packit Service b38f0b
        }
Packit Service b38f0b
        netsnmp_free_delegated_cache(cache);
Packit Service b38f0b
        return 0;
Packit Service b38f0b
Packit Service b38f0b
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
Packit Service b38f0b
        vars = pdu->variables;
Packit Service b38f0b
Packit Service b38f0b
        if (pdu->errstat != SNMP_ERR_NOERROR) {
Packit Service b38f0b
            /*
Packit Service b38f0b
             *  If we receive an error from the proxy agent, pass it on up.
Packit Service b38f0b
             *  The higher-level processing seems to Do The Right Thing.
Packit Service b38f0b
             *
Packit Service b38f0b
             * 2005/06 rks: actually, it doesn't do the right thing for
Packit Service b38f0b
             * a get-next request that returns NOSUCHNAME. If we do nothing,
Packit Service b38f0b
             * it passes that error back to the comman initiator. What it should
Packit Service b38f0b
             * do is ignore the error and move on to the next tree. To
Packit Service b38f0b
             * accomplish that, all we need to do is clear the delegated flag.
Packit Service b38f0b
             * Not sure if any other error codes need the same treatment. Left
Packit Service b38f0b
             * as an exercise to the reader...
Packit Service b38f0b
             */
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "got error response (%ld)\n", pdu->errstat));
Packit Service b38f0b
            if((cache->reqinfo->mode == MODE_GETNEXT) &&
Packit Service b38f0b
               (SNMP_ERR_NOSUCHNAME == pdu->errstat)) {
Packit Service b38f0b
                DEBUGMSGTL(("proxy", "  ignoring error response\n"));
Packit Service b38f0b
                netsnmp_handler_mark_requests_as_delegated(requests,
Packit Service b38f0b
                                                           REQUEST_IS_NOT_DELEGATED);
Packit Service b38f0b
            }
Packit Service b38f0b
#ifndef NETSNMP_NO_WRITE_SUPPORT
Packit Service b38f0b
	    else if (cache->reqinfo->mode == MODE_SET_ACTION) {
Packit Service b38f0b
		/*
Packit Service b38f0b
		 * In order for netsnmp_wrap_up_request to consider the
Packit Service b38f0b
		 * SET request complete,
Packit Service b38f0b
		 * there must be no delegated requests pending.
Packit Service b38f0b
		 * https://sourceforge.net/tracker/
Packit Service b38f0b
		 *	?func=detail&atid=112694&aid=1554261&group_id=12694
Packit Service b38f0b
		 */
Packit Service b38f0b
		DEBUGMSGTL(("proxy",
Packit Service b38f0b
		    "got SET error %s, index %ld\n",
Packit Service b38f0b
		    snmp_errstring(pdu->errstat), pdu->errindex));
Packit Service b38f0b
		netsnmp_handler_mark_requests_as_delegated(
Packit Service b38f0b
		    requests, REQUEST_IS_NOT_DELEGATED);
Packit Service b38f0b
		netsnmp_request_set_error_idx(requests, pdu->errstat,
Packit Service b38f0b
                                                        pdu->errindex);
Packit Service b38f0b
	    }
Packit Service b38f0b
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
Packit Service b38f0b
            else {
Packit Service b38f0b
		netsnmp_handler_mark_requests_as_delegated( requests,
Packit Service b38f0b
                                             REQUEST_IS_NOT_DELEGATED);
Packit Service b38f0b
		netsnmp_request_set_error_idx(requests, pdu->errstat,
Packit Service b38f0b
                                                        pdu->errindex);
Packit Service b38f0b
            }
Packit Service b38f0b
Packit Service b38f0b
        /*
Packit Service b38f0b
         * update the original request varbinds with the results 
Packit Service b38f0b
         */
Packit Service b38f0b
	} else for (var = vars, request = requests;
Packit Service b38f0b
             request && var;
Packit Service b38f0b
             request = request->next, var = var->next_variable) {
Packit Service b38f0b
            /*
Packit Service b38f0b
             * XXX - should this be done here?
Packit Service b38f0b
             *       Or wait until we know it's OK?
Packit Service b38f0b
             */
Packit Service b38f0b
            snmp_set_var_typed_value(request->requestvb, var->type,
Packit Service b38f0b
                                     var->val.string, var->val_len);
Packit Service b38f0b
Packit Service b38f0b
            DEBUGMSGTL(("proxy", "got response... "));
Packit Service b38f0b
            DEBUGMSGOID(("proxy", var->name, var->name_length));
Packit Service b38f0b
            DEBUGMSG(("proxy", "\n"));
Packit Service b38f0b
            request->delegated = 0;
Packit Service b38f0b
Packit Service b38f0b
            /*
Packit Service b38f0b
             * Check the response oid is legitimate,
Packit Service b38f0b
             *   and discard the value if not.
Packit Service b38f0b
             *
Packit Service b38f0b
             * XXX - what's the difference between these cases?
Packit Service b38f0b
             */
Packit Service b38f0b
            if (sp->base_len &&
Packit Service b38f0b
                (var->name_length < sp->base_len ||
Packit Service b38f0b
                 snmp_oid_compare(var->name, sp->base_len, sp->base,
Packit Service b38f0b
                                  sp->base_len) != 0)) {
Packit Service b38f0b
                DEBUGMSGTL(( "proxy", "out of registered range... "));
Packit Service b38f0b
                DEBUGMSGOID(("proxy", var->name, sp->base_len));
Packit Service b38f0b
                DEBUGMSG((   "proxy", " (%d) != ", (int)sp->base_len));
Packit Service b38f0b
                DEBUGMSGOID(("proxy", sp->base, sp->base_len));
Packit Service b38f0b
                DEBUGMSG((   "proxy", "\n"));
Packit Service b38f0b
                snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0);
Packit Service b38f0b
Packit Service b38f0b
                continue;
Packit Service b38f0b
            } else if (!sp->base_len &&
Packit Service b38f0b
                       (var->name_length < sp->name_len ||
Packit Service b38f0b
                        snmp_oid_compare(var->name, sp->name_len, sp->name,
Packit Service b38f0b
                                         sp->name_len) != 0)) {
Packit Service b38f0b
                DEBUGMSGTL(( "proxy", "out of registered base range... "));
Packit Service b38f0b
                DEBUGMSGOID(("proxy", var->name, sp->name_len));
Packit Service b38f0b
                DEBUGMSG((   "proxy", " (%d) != ", (int)sp->name_len));
Packit Service b38f0b
                DEBUGMSGOID(("proxy", sp->name, sp->name_len));
Packit Service b38f0b
                DEBUGMSG((   "proxy", "\n"));
Packit Service b38f0b
                snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0);
Packit Service b38f0b
                continue;
Packit Service b38f0b
            } else {
Packit Service b38f0b
                /*
Packit Service b38f0b
                 * If the returned OID is legitimate, then update
Packit Service b38f0b
                 *   the original request varbind accordingly.
Packit Service b38f0b
                 */
Packit Service b38f0b
                if (sp->base_len) {
Packit Service b38f0b
                    /*
Packit Service b38f0b
                     * XXX: oid size maxed? 
Packit Service b38f0b
                     */
Packit Service b38f0b
                    memcpy(myname, sp->name, sizeof(oid) * sp->name_len);
Packit Service b38f0b
                    myname_len =
Packit Service b38f0b
                        sp->name_len + var->name_length - sp->base_len;
Packit Service b38f0b
                    if (myname_len > MAX_OID_LEN) {
Packit Service b38f0b
                        snmp_log(LOG_WARNING,
Packit Service b38f0b
                                 "proxy OID return length too long.\n");
Packit Service b38f0b
                        netsnmp_set_request_error(cache->reqinfo, requests,
Packit Service b38f0b
                                                  SNMP_ERR_GENERR);
Packit Service b38f0b
                        if (pdu)
Packit Service b38f0b
                            snmp_free_pdu(pdu);
Packit Service b38f0b
                        netsnmp_free_delegated_cache(cache);
Packit Service b38f0b
                        return 1;
Packit Service b38f0b
                    }
Packit Service b38f0b
Packit Service b38f0b
                    if (var->name_length > sp->base_len)
Packit Service b38f0b
                        memcpy(&myname[sp->name_len],
Packit Service b38f0b
                               &var->name[sp->base_len],
Packit Service b38f0b
                               sizeof(oid) * (var->name_length -
Packit Service b38f0b
                                              sp->base_len));
Packit Service b38f0b
                    snmp_set_var_objid(request->requestvb, myname,
Packit Service b38f0b
                                       myname_len);
Packit Service b38f0b
                } else {
Packit Service b38f0b
                    snmp_set_var_objid(request->requestvb, var->name,
Packit Service b38f0b
                                       var->name_length);
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        if (request || var) {
Packit Service b38f0b
            /*
Packit Service b38f0b
             * ack, this is bad.  The # of varbinds don't match and
Packit Service b38f0b
             * there is no way to fix the problem 
Packit Service b38f0b
             */
Packit Service b38f0b
            if (pdu)
Packit Service b38f0b
                snmp_free_pdu(pdu);
Packit Service b38f0b
            snmp_log(LOG_ERR,
Packit Service b38f0b
                     "response to proxy request illegal.  We're screwed.\n");
Packit Service b38f0b
            netsnmp_set_request_error(cache->reqinfo, requests,
Packit Service b38f0b
                                      SNMP_ERR_GENERR);
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        /* fix bulk_to_next operations */
Packit Service b38f0b
        if (cache->reqinfo->mode == MODE_GETBULK)
Packit Service b38f0b
            netsnmp_bulk_to_next_fix_requests(requests);
Packit Service b38f0b
        
Packit Service b38f0b
        /*
Packit Service b38f0b
         * free the response 
Packit Service b38f0b
         */
Packit Service b38f0b
        if (pdu && 0)
Packit Service b38f0b
            snmp_free_pdu(pdu);
Packit Service b38f0b
	break;
Packit Service b38f0b
Packit Service b38f0b
    default:
Packit Service b38f0b
        DEBUGMSGTL(("proxy", "no response received: op = %d\n",
Packit Service b38f0b
                    operation));
Packit Service b38f0b
	break;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_free_delegated_cache(cache);
Packit Service b38f0b
    return 1;
Packit Service b38f0b
}