示例#1
0
static int
netsnmp_tcp6_accept(netsnmp_transport *t)
{
    struct sockaddr_in6 *farend = NULL;
    int             newsock = -1;
    socklen_t       farendlen = sizeof(struct sockaddr_in6);
    char           *str = NULL;

    farend = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));

    if (farend == NULL) {
        /*
         * Indicate that the acceptance of this socket failed.  
         */
        DEBUGMSGTL(("netsnmp_tcp6", "accept: malloc failed\n"));
        return -1;
    }

    if (t != NULL && t->sock >= 0) {
        newsock = (int) accept(t->sock, (struct sockaddr *) farend, &farendlen);

        if (newsock < 0) {
            DEBUGMSGTL(("netsnmp_tcp6","accept failed rc %d errno %d \"%s\"\n",
			newsock, errno, strerror(errno)));
            free(farend);
            return newsock;
        }

        if (t->data != NULL) {
            free(t->data);
        }

        t->data = farend;
        t->data_length = farendlen;
        str = netsnmp_tcp6_fmtaddr(NULL, farend, farendlen);
        DEBUGMSGTL(("netsnmp_tcp6", "accept succeeded (from %s)\n", str));
        free(str);

        /*
         * Try to make the new socket blocking.  
         */

        if (netsnmp_set_non_blocking_mode(newsock, FALSE) < 0)
            DEBUGMSGTL(("netsnmp_tcp6",
                        "accept: couldn't f_getfl of fd %d\n", newsock));

        /*
         * Allow user to override the send and receive buffers. Default is
         * to use os default.  Don't worry too much about errors --
         * just plough on regardless.  
         */
        netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
        netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);

        return newsock;
    } else {
        free(farend);
        return -1;
    }
}
示例#2
0
static int
netsnmp_unix_accept(netsnmp_transport *t)
{
    struct sockaddr *farend = NULL;
    int             newsock = -1;
    socklen_t       farendlen = sizeof(struct sockaddr_un);

    farend = (struct sockaddr *) malloc(farendlen);

    if (farend == NULL) {
        /*
         * Indicate that the acceptance of this socket failed.
         */
        DEBUGMSGTL(("netsnmp_unix", "accept: malloc failed\n"));
        return -1;
    }
    memset(farend, 0, farendlen);

    if (t != NULL && t->sock >= 0) {
        newsock = accept(t->sock, farend, &farendlen);

        if (newsock < 0) {
            DEBUGMSGTL(("netsnmp_unix","accept failed rc %d errno %d \"%s\"\n",
                        newsock, errno, strerror(errno)));
            free(farend);
            return newsock;
        }

        if (t->data != NULL) {
            free(t->data);
        }

        DEBUGMSGTL(("netsnmp_unix", "accept succeeded (farend %p len %d)\n",
                    farend, farendlen));
        t->data = farend;
        t->data_length = sizeof(struct sockaddr_un);
       netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
       netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);
        return newsock;
    } else {
        free(farend);
        return -1;
    }
}
示例#3
0
netsnmp_transport *
netsnmp_unix_transport(struct sockaddr_un *addr, int local)
{
    netsnmp_transport *t = NULL;
    sockaddr_un_pair *sup = NULL;
    int             rc = 0;
    char           *string = NULL;

    if (addr == NULL || addr->sun_family != AF_UNIX) {
        return NULL;
    }

    t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
    if (t == NULL) {
        return NULL;
    }

    string = netsnmp_unix_fmtaddr(NULL, (void *)addr,
                                  sizeof(struct sockaddr_un));
    DEBUGMSGTL(("netsnmp_unix", "open %s %s\n", local ? "local" : "remote",
                string));
    free(string);

    memset(t, 0, sizeof(netsnmp_transport));

    t->domain = netsnmp_UnixDomain;
    t->domain_length =
        sizeof(netsnmp_UnixDomain) / sizeof(netsnmp_UnixDomain[0]);

    t->data = malloc(sizeof(sockaddr_un_pair));
    if (t->data == NULL) {
        netsnmp_transport_free(t);
        return NULL;
    }
    memset(t->data, 0, sizeof(sockaddr_un_pair));
    t->data_length = sizeof(sockaddr_un_pair);
    sup = (sockaddr_un_pair *) t->data;

    t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
    if (t->sock < 0) {
        netsnmp_transport_free(t);
        return NULL;
    }

    t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;

    if (local) {
      t->local = (u_char *)malloc(strlen(addr->sun_path));
        if (t->local == NULL) {
            netsnmp_transport_free(t);
            return NULL;
        }
        memcpy(t->local, addr->sun_path, strlen(addr->sun_path));
        t->local_length = strlen(addr->sun_path);

        /*
         * This session is inteneded as a server, so we must bind to the given
         * path (unlinking it first, to avoid errors).
         */

        t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;

        unlink(addr->sun_path);
        rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
        if (rc != 0) {
            DEBUGMSGTL(("netsnmp_unix_transport",
                        "couldn't bind \"%s\", errno %d (%s)\n",
                        addr->sun_path, errno, strerror(errno)));
            netsnmp_unix_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

        /*
         * Save the address in the transport-specific data pointer for later
         * use by netsnmp_unix_close.
         */

        sup->server.sun_family = AF_UNIX;
        strcpy(sup->server.sun_path, addr->sun_path);
        sup->local = 1;

        /*
         * Now sit here and listen for connections to arrive.
         */

        rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
        if (rc != 0) {
            DEBUGMSGTL(("netsnmp_unix_transport",
                        "couldn't listen to \"%s\", errno %d (%s)\n",
                        addr->sun_path, errno, strerror(errno)));
            netsnmp_unix_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

    } else {
      t->remote = (u_char *)malloc(strlen(addr->sun_path));
        if (t->remote == NULL) {
            netsnmp_transport_free(t);
            return NULL;
        }
        memcpy(t->remote, addr->sun_path, strlen(addr->sun_path));
        t->remote_length = strlen(addr->sun_path);

        rc = connect(t->sock, (struct sockaddr *) addr,
                     sizeof(struct sockaddr_un));
        if (rc != 0) {
            DEBUGMSGTL(("netsnmp_unix_transport",
                        "couldn't connect to \"%s\", errno %d (%s)\n",
                        addr->sun_path, errno, strerror(errno)));
            netsnmp_unix_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

        /*
         * Save the remote address in the transport-specific data pointer for
         * later use by netsnmp_unix_send.
         */

        sup->server.sun_family = AF_UNIX;
        strcpy(sup->server.sun_path, addr->sun_path);
        sup->local = 0;
       netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0);
       netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0);
    }

    /*
     * Message size is not limited by this transport (hence msgMaxSize
     * is equal to the maximum legal size of an SNMP message).
     */

    t->msgMaxSize = 0x7fffffff;
    t->f_recv     = netsnmp_unix_recv;
    t->f_send     = netsnmp_unix_send;
    t->f_close    = netsnmp_unix_close;
    t->f_accept   = netsnmp_unix_accept;
    t->f_fmtaddr  = netsnmp_unix_fmtaddr;

    return t;
}
示例#4
0
netsnmp_transport *
netsnmp_ssh_transport(const struct sockaddr_in *addr, int local)
{
    netsnmp_transport *t = NULL;
    netsnmp_ssh_addr_pair *addr_pair = NULL;
    int rc = 0;
    int i, auth_pw = 0;
    const char *fingerprint;
    char *userauthlist;
    struct sockaddr_un *unaddr;
    const char *sockpath =
        netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
                              NETSNMP_DS_LIB_SSHTOSNMP_SOCKET);
    char tmpsockpath[MAXPATHLEN];

#ifdef NETSNMP_NO_LISTEN_SUPPORT
    if (local)
        return NULL;
#endif /* NETSNMP_NO_LISTEN_SUPPORT */

    if (addr == NULL || addr->sin_family != AF_INET) {
        return NULL;
    }

    t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
    if (t == NULL) {
        return NULL;
    }

    t->domain = netsnmp_snmpSSHDomain;
    t->domain_length = netsnmp_snmpSSHDomain_len;
    t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED;

    addr_pair = SNMP_MALLOC_TYPEDEF(netsnmp_ssh_addr_pair);
    if (addr_pair == NULL) {
        netsnmp_transport_free(t);
        return NULL;
    }
    t->data = addr_pair;
    t->data_length = sizeof(netsnmp_ssh_addr_pair);

    if (local) {
#ifndef NETSNMP_NO_LISTEN_SUPPORT
#ifdef SNMPSSHDOMAIN_USE_EXTERNAL_PIPE

        /* XXX: set t->local and t->local_length */


        t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;

        unaddr = &addr_pair->unix_socket_end;

        /* open a unix domain socket */
        /* XXX: get data from the transport def for it's location */
        unaddr->sun_family = AF_UNIX;
        if (NULL == sockpath) {
            sprintf(tmpsockpath, "%s/%s", get_persistent_directory(),
                    DEFAULT_SOCK_NAME);
            sockpath = tmpsockpath;
        }

        snprintf(unaddr->sun_path, sizeof(unaddr->sun_path), "%s", sockpath);
        snprintf(addr_pair->socket_path, sizeof(addr_pair->socket_path), "%s",
                 sockpath);

        t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
        if (t->sock < 0) {
            netsnmp_transport_free(t);
            return NULL;
        }

        /* set the SO_PASSCRED option so we can receive the remote uid */
        {
            int one = 1;
            setsockopt(t->sock, SOL_SOCKET, SO_PASSCRED, (void *) &one,
                       sizeof(one));
        }

        unlink(unaddr->sun_path);
        rc = bind(t->sock, unaddr, SUN_LEN(unaddr));
        if (rc != 0) {
            DEBUGMSGTL(("netsnmp_ssh_transport",
                        "couldn't bind \"%s\", errno %d (%s)\n",
                        unaddr->sun_path, errno, strerror(errno)));
            netsnmp_ssh_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }


        /* set the socket permissions */
        {
            /*
             * Apply any settings to the ownership/permissions of the
             * Sshdomain socket
             */
            int sshdomain_sock_perm =
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_SSHDOMAIN_SOCK_PERM);
            int sshdomain_sock_user =
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_SSHDOMAIN_SOCK_USER);
            int sshdomain_sock_group =
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_SSHDOMAIN_SOCK_GROUP);

            DEBUGMSGTL(("ssh", "here: %s, %d, %d, %d\n",
                        unaddr->sun_path,
                        sshdomain_sock_perm, sshdomain_sock_user,
                        sshdomain_sock_group));
            if (sshdomain_sock_perm != 0) {
                DEBUGMSGTL(("ssh", "Setting socket perms to %d\n",
                            sshdomain_sock_perm));
                chmod(unaddr->sun_path, sshdomain_sock_perm);
            }

            if (sshdomain_sock_user || sshdomain_sock_group) {
                /*
                 * If either of user or group haven't been set,
                 *  then leave them unchanged.
                 */
                if (sshdomain_sock_user == 0 )
                    sshdomain_sock_user = -1;
                if (sshdomain_sock_group == 0 )
                    sshdomain_sock_group = -1;
                DEBUGMSGTL(("ssh", "Setting socket user/group to %d/%d\n",
                            sshdomain_sock_user, sshdomain_sock_group));
                chown(unaddr->sun_path,
                      sshdomain_sock_user, sshdomain_sock_group);
            }
        }

        rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
        if (rc != 0) {
            DEBUGMSGTL(("netsnmp_ssh_transport",
                        "couldn't listen to \"%s\", errno %d (%s)\n",
                        unaddr->sun_path, errno, strerror(errno)));
            netsnmp_ssh_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }
        

#else /* we're called directly by sshd and use stdin/out */
        /* for ssh on the server side we've been launched so bind to
           stdin/out */

        /* nothing to do */

        /* XXX: verify we're inside ssh */
        t->sock = STDIN_FILENO;
#endif /* ! SNMPSSHDOMAIN_USE_EXTERNAL_PIPE */
#else /* NETSNMP_NO_LISTEN_SUPPORT */
        netsnmp_transport_free(t);
        return NULL;
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
    } else {
        char *username;
        char *keyfilepub;
        char *keyfilepriv;
        
        /* use the requested user name */
        /* XXX: default to the current user name on the system like ssh does */
        username = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
                                         NETSNMP_DS_LIB_SSH_USERNAME);
        if (!username || 0 == *username) {
            snmp_log(LOG_ERR, "You must specify a ssh username to use.  See the snmp.conf manual page\n");
            netsnmp_transport_free(t);
            return NULL;
        }

        /* use the requested public key file */
        keyfilepub = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
                                           NETSNMP_DS_LIB_SSH_PUBKEY);
        if (!keyfilepub || 0 == *keyfilepub) {
            /* XXX: default to ~/.ssh/id_rsa.pub */
            snmp_log(LOG_ERR, "You must specify a ssh public key file to use.  See the snmp.conf manual page\n");
            netsnmp_transport_free(t);
            return NULL;
        }

        /* use the requested private key file */
        keyfilepriv = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
                                            NETSNMP_DS_LIB_SSH_PRIVKEY);
        if (!keyfilepriv || 0 == *keyfilepriv) {
            /* XXX: default to keyfilepub without the .pub suffix */
            snmp_log(LOG_ERR, "You must specify a ssh private key file to use.  See the snmp.conf manual page\n");
            netsnmp_transport_free(t);
            return NULL;
        }

        /* xxx: need an ipv6 friendly one too (sigh) */

        /* XXX: not ideal when structs don't actually match size wise */
        memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));

        t->sock = socket(PF_INET, SOCK_STREAM, 0);
        if (t->sock < 0) {
            netsnmp_transport_free(t);
            return NULL;
        }

        t->remote_length = sizeof(*addr);
        t->remote = netsnmp_memdup(addr, sizeof(*addr));
        if (!t->remote) {
            netsnmp_ssh_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

        /*
         * This is a client-type session, so attempt to connect to the far
         * end.  We don't go non-blocking here because it's not obvious what
         * you'd then do if you tried to do snmp_sends before the connection
         * had completed.  So this can block.
         */

        rc = connect(t->sock, addr, sizeof(struct sockaddr));

        if (rc < 0) {
            netsnmp_ssh_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

        /*
         * Allow user to override the send and receive buffers. Default is
         * to use os default.  Don't worry too much about errors --
         * just plough on regardless.  
         */
        netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0);
        netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0);

        /* open the SSH session and channel */
        addr_pair->session = libssh2_session_init();
        if (libssh2_session_startup(addr_pair->session, t->sock)) {
          shutdown:
            snmp_log(LOG_ERR, "Failed to establish an SSH session\n");
            netsnmp_ssh_close(t);
            netsnmp_transport_free(t);
            return NULL;
        }

        /* At this point we havn't authenticated, The first thing to
           do is check the hostkey's fingerprint against our known
           hosts Your app may have it hard coded, may go to a file,
           may present it to the user, that's your call
         */
        fingerprint =
            libssh2_hostkey_hash(addr_pair->session, LIBSSH2_HOSTKEY_HASH_MD5);
        DEBUGMSGTL(("ssh", "Fingerprint: "));
        for(i = 0; i < 16; i++) {
            DEBUGMSG(("ssh", "%02x",
                      (unsigned char)fingerprint[i]));
        }
        DEBUGMSG(("ssh", "\n"));

        /* check what authentication methods are available */
        userauthlist =
            libssh2_userauth_list(addr_pair->session,
                                  username, strlen(username));
        DEBUGMSG(("ssh", "Authentication methods: %s\n", userauthlist));

        /* XXX: allow other types */
        /* XXX: 4 seems magic to me... */
        if (strstr(userauthlist, "publickey") != NULL) {
            auth_pw |= 4;
        }

        /* XXX: hard coded paths and users */
        if (auth_pw & 4) {
            /* public key */
            if (libssh2_userauth_publickey_fromfile(addr_pair->session,
                                                    username,
                                                    keyfilepub, keyfilepriv,
                                                    NULL)) {
                snmp_log(LOG_ERR,"Authentication by public key failed!\n");
                goto shutdown;
            } else {
                DEBUGMSG(("ssh",
                          "\tAuthentication by public key succeeded.\n"));
            }
        } else {
            snmp_log(LOG_ERR,"Authentication by public key failed!\n");
            goto shutdown;
        }

        /* we've now authenticated both sides; contining onward ... */

        /* Request a channel */
        if (!(addr_pair->channel =
              libssh2_channel_open_session(addr_pair->session))) {
            snmp_log(LOG_ERR, "Unable to open a session\n");
            goto shutdown;
        }

        /* Request a terminal with 'vanilla' terminal emulation
         * See /etc/termcap for more options
         */
        /* XXX: needed?  doubt it */
/*         if (libssh2_channel_request_pty(addr_pair->channel, "vanilla")) { */
/*             snmp_log(LOG_ERR, "Failed requesting pty\n"); */
/*             goto shutdown; */
/*         } */
        if (libssh2_channel_subsystem(addr_pair->channel, "snmp")) {
            snmp_log(LOG_ERR, "Failed to request the ssh 'snmp' subsystem\n");
            goto shutdown;
        }
    }

    DEBUGMSG(("ssh","Opened connection.\n"));
    /*
     * Message size is not limited by this transport (hence msgMaxSize
     * is equal to the maximum legal size of an SNMP message).  
     */

    t->msgMaxSize = SNMP_MAX_PACKET_LEN;
    t->f_recv     = netsnmp_ssh_recv;
    t->f_send     = netsnmp_ssh_send;
    t->f_close    = netsnmp_ssh_close;
    t->f_accept   = netsnmp_ssh_accept;
    t->f_fmtaddr  = netsnmp_ssh_fmtaddr;

    return t;
}
示例#5
0
static int
netsnmp_ssh_accept(netsnmp_transport *t)
{
#ifdef SNMPSSHDOMAIN_USE_EXTERNAL_PIPE

    /* much of this is duplicated from snmpUnixDomain.c */

    netsnmp_ssh_addr_pair *addr_pair;    
    int                    newsock   = -1;
    struct sockaddr       *farend    = NULL;
    socklen_t              farendlen = sizeof(struct sockaddr_un);


    if (t != NULL && t->sock >= 0) {
        addr_pair = SNMP_MALLOC_TYPEDEF(netsnmp_ssh_addr_pair);

        if (addr_pair == NULL) {
            /*
             * Indicate that the acceptance of this socket failed.
             */
            DEBUGMSGTL(("ssh", "accept: malloc failed\n"));
            return -1;
        }

        farend = (struct sockaddr *) &addr_pair->unix_socket_end;

        newsock = accept(t->sock, farend, &farendlen);

        if (newsock < 0) {
            DEBUGMSGTL(("ssh","accept failed rc %d errno %d \"%s\"\n",
                        newsock, errno, strerror(errno)));
            free(addr_pair);
            return newsock;
        }

        /* set the SO_PASSCRED option so we can receive the remote uid */
        {
            int one = 1;
            setsockopt(newsock, SOL_SOCKET, SO_PASSCRED, (void *) &one,
                       sizeof(one));
        }

        if (t->data != NULL) {
            free(t->data);
        }

        DEBUGMSGTL(("ssh", "accept succeeded (farend %p len %d)\n",
                    farend, farendlen));
        t->data = addr_pair;
        t->data_length = sizeof(netsnmp_ssh_addr_pair);
        netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
        netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);
        return newsock;
    } else {
        return -1;
    }

#else /* we're called directly by sshd and use stdin/out */
    /* we don't need to do anything; server side uses stdin/out */
    /* XXX: check that we're an ssh connection */
    
    return STDIN_FILENO; /* return stdin */
#endif /* ! SNMPSSHDOMAIN_USE_EXTERNAL_PIPE */

}