|
Packit |
fcad23 |
/* Copyright 2009 SPARTA, Inc. All rights reserved
|
|
Packit |
fcad23 |
* Use is subject to license terms specified in the COPYING file
|
|
Packit |
fcad23 |
* distributed with the Net-SNMP package.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* This is merely a wrapper around stdin/out for sshd to call. It
|
|
Packit |
fcad23 |
* simply passes traffic to the running snmpd through a unix domain
|
|
Packit |
fcad23 |
* socket after first passing any needed SSH Domain information.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include <net-snmp/net-snmp-config.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#ifdef HAVE_SYS_PARAM_H
|
|
Packit |
fcad23 |
#include <sys/param.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#ifdef HAVE_SYS_SOCKET_H
|
|
Packit |
fcad23 |
#include <sys/socket.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_SYS_UN_H
|
|
Packit |
fcad23 |
#include <sys/un.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include <sys/select.h>
|
|
Packit |
fcad23 |
#include <unistd.h>
|
|
Packit |
fcad23 |
#include <stdlib.h>
|
|
Packit |
fcad23 |
#include <errno.h>
|
|
Packit |
fcad23 |
#include <stdio.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#ifndef MAXPATHLEN
|
|
Packit |
fcad23 |
#warning no system max path length detected
|
|
Packit |
fcad23 |
#define MAXPATHLEN 2048
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#define DEFAULT_SOCK_PATH "/var/net-snmp/sshdomainsocket"
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#define NETSNMP_SSHTOSNMP_VERSION_NUMBER 1
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Extra debugging output for, um, debugging.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#undef DEBUGGING
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#define DEBUG(x) deb(x)
|
|
Packit |
fcad23 |
#ifdef DEBUGGING
|
|
Packit |
fcad23 |
FILE *debf = NULL;
|
|
Packit |
fcad23 |
static void
|
|
Packit |
fcad23 |
deb(const char *string) {
|
|
Packit |
fcad23 |
if (NULL == debf) {
|
|
Packit |
fcad23 |
debf = fopen("/tmp/sshtosnmp.log", "a");
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if (NULL != debf) {
|
|
Packit |
fcad23 |
fprintf(debf, "%s\n", string);
|
|
Packit |
fcad23 |
fflush(debf);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
#else /* !DEBUGGING */
|
|
Packit |
fcad23 |
NETSNMP_STATIC_INLINE void
|
|
Packit |
fcad23 |
deb(const char *string) { }
|
|
Packit |
fcad23 |
#endif /* DEBUGGING code */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
int
|
|
Packit |
fcad23 |
main(int argc, char **argv) {
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
int sock;
|
|
Packit |
fcad23 |
struct sockaddr_un addr;
|
|
Packit |
fcad23 |
u_char buf[4096];
|
|
Packit |
fcad23 |
size_t buf_len = sizeof(buf);
|
|
Packit |
fcad23 |
int rc = 0, pktsize = 0;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
fd_set read_set;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUG("----------\nstarting up");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Open a connection to the UNIX domain socket or fail */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
addr.sun_family = AF_UNIX;
|
|
Packit |
fcad23 |
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s",
|
|
Packit |
fcad23 |
argc > 1 ? argv[1] : DEFAULT_SOCK_PATH);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
Packit |
fcad23 |
DEBUG("created socket");
|
|
Packit |
fcad23 |
if (sock <= 0) {
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* set the SO_PASSCRED option so we can pass uid */
|
|
Packit |
fcad23 |
/* XXX: according to the unix(1) manual this shouldn't be needed
|
|
Packit |
fcad23 |
on the sending side? */
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
int one = 1;
|
|
Packit |
fcad23 |
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, (void *) &one,
|
|
Packit |
fcad23 |
sizeof(one));
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (connect(sock, (struct sockaddr *) &addr,
|
|
Packit |
fcad23 |
sizeof(struct sockaddr_un)) != 0) {
|
|
Packit |
fcad23 |
DEBUG("FAIL CONNECT");
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUG("opened socket");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* we are running as the user that ssh authenticated us as, and this
|
|
Packit |
fcad23 |
* is the name/uid that the agent needs for processing as a SNMPv3
|
|
Packit |
fcad23 |
* security name. So this is the only thing needed to pass to the
|
|
Packit |
fcad23 |
* agent.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* version 1 of our internal ssh to snmp wrapper is just a single
|
|
Packit |
fcad23 |
byte version number and indicates we're also passing unix
|
|
Packit |
fcad23 |
socket credentials containing our user id */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* In case of future changes, we'll pass a version number first */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
buf[0] = NETSNMP_SSHTOSNMP_VERSION_NUMBER;
|
|
Packit |
fcad23 |
buf_len = 1;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* send the prelim message and the credentials together using sendmsg() */
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
struct msghdr m;
|
|
Packit |
fcad23 |
struct {
|
|
Packit |
fcad23 |
struct cmsghdr cm;
|
|
Packit |
fcad23 |
struct ucred ouruser;
|
|
Packit |
fcad23 |
} cmsg;
|
|
Packit |
fcad23 |
struct iovec iov = { buf, buf_len };
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Make sure that even padding fields get initialized.*/
|
|
Packit |
fcad23 |
memset(&cmsg, 0, sizeof(cmsg));
|
|
Packit |
fcad23 |
memset(&m, 0, sizeof(m));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* set up the basic message */
|
|
Packit |
fcad23 |
cmsg.cm.cmsg_len = sizeof(struct cmsghdr) + sizeof(struct ucred);
|
|
Packit |
fcad23 |
cmsg.cm.cmsg_level = SOL_SOCKET;
|
|
Packit |
fcad23 |
cmsg.cm.cmsg_type = SCM_CREDENTIALS;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
cmsg.ouruser.uid = getuid();
|
|
Packit |
fcad23 |
cmsg.ouruser.gid = getgid();
|
|
Packit |
fcad23 |
cmsg.ouruser.pid = getpid();
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
m.msg_iov = &iov;
|
|
Packit |
fcad23 |
m.msg_iovlen = 1;
|
|
Packit |
fcad23 |
m.msg_control = &cmsg;
|
|
Packit |
fcad23 |
m.msg_controllen = sizeof(cmsg);
|
|
Packit |
fcad23 |
m.msg_flags = 0;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUG("sending to sock");
|
|
Packit |
fcad23 |
rc = sendmsg(sock, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
|
|
Packit |
fcad23 |
if (rc < 0) {
|
|
Packit |
fcad23 |
fprintf(stderr, "failed to send startup message\n");
|
|
Packit |
fcad23 |
DEBUG("failed to send startup message\n");
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUG("sent name");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* now we just send and receive from both the socket and stdin/stdout */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
while(1) {
|
|
Packit |
fcad23 |
/* read from stdin and the socket */
|
|
Packit |
fcad23 |
FD_ZERO(&read_set);
|
|
Packit |
fcad23 |
FD_SET(sock, &read_set);
|
|
Packit |
fcad23 |
FD_SET(STDIN_FILENO, &read_set);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* blocking without a timeout be fine fine */
|
|
Packit |
fcad23 |
select(sock+1, &read_set, NULL, NULL, NULL);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (FD_ISSET(STDIN_FILENO, &read_set)) {
|
|
Packit |
fcad23 |
/* read from stdin to get stuff from sshd to send to the agent */
|
|
Packit |
fcad23 |
DEBUG("data from stdin");
|
|
Packit |
fcad23 |
rc = read(STDIN_FILENO, buf, sizeof(buf));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (rc <= 0) {
|
|
Packit |
fcad23 |
/* end-of-file */
|
|
Packit |
fcad23 |
#ifndef HAVE_CLOSESOCKET
|
|
Packit |
fcad23 |
rc = close(sock);
|
|
Packit |
fcad23 |
#else
|
|
Packit |
fcad23 |
rc = closesocket(sock);
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
exit(0);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
DEBUG("read from stdin");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* send it up the pipe */
|
|
Packit |
fcad23 |
pktsize = rc;
|
|
Packit |
fcad23 |
rc = -1;
|
|
Packit |
fcad23 |
while (rc < 0) {
|
|
Packit |
fcad23 |
DEBUG("sending to socket");
|
|
Packit |
fcad23 |
rc = sendto(sock, buf, pktsize, 0, NULL, 0);
|
|
Packit |
fcad23 |
DEBUG("back from sendto");
|
|
Packit |
fcad23 |
if (rc < 0)
|
|
Packit |
fcad23 |
DEBUG("sentto failed");
|
|
Packit |
fcad23 |
if (rc < 0 && errno != EINTR) {
|
|
Packit |
fcad23 |
break;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if (rc > 0)
|
|
Packit |
fcad23 |
DEBUG("sent to socket");
|
|
Packit |
fcad23 |
else
|
|
Packit |
fcad23 |
DEBUG("failed to send to socket!!");
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (FD_ISSET(sock, &read_set)) {
|
|
Packit |
fcad23 |
/* read from the socket and send to to stdout which goes to sshd */
|
|
Packit |
fcad23 |
DEBUG("data on unix socket");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
rc = -1;
|
|
Packit |
fcad23 |
while (rc < 0) {
|
|
Packit |
fcad23 |
rc = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
|
|
Packit |
fcad23 |
if (rc < 0 && errno != EINTR) {
|
|
Packit |
fcad23 |
close(sock);
|
|
Packit |
fcad23 |
exit(0);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
DEBUG("read from socket");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
pktsize = rc;
|
|
Packit |
fcad23 |
rc = write(STDOUT_FILENO, buf, pktsize);
|
|
Packit |
fcad23 |
/* XXX: check that counts match */
|
|
Packit |
fcad23 |
if (rc > 0) {
|
|
Packit |
fcad23 |
DEBUG("wrote to stdout");
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
DEBUG("failed to write to stdout");
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|