You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/x11vnc/inet.c

388 lines
7.4 KiB

/* -- inet.c -- */
#include "x11vnc.h"
#include "unixpw.h"
#include "sslhelper.h"
/*
* Simple utility to map host name to dotted IP address. Ignores aliases.
* Up to caller to free returned string.
*/
char *host2ip(char *host);
char *raw2host(char *raw, int len);
char *raw2ip(char *raw);
char *ip2host(char *ip);
int dotted_ip(char *host);
int get_remote_port(int sock);
int get_local_port(int sock);
char *get_remote_host(int sock);
char *get_local_host(int sock);
char *ident_username(rfbClientPtr client);
int find_free_port(int start, int end);
int have_ssh_env(void);
static int get_port(int sock, int remote);
static char *get_host(int sock, int remote);
char *host2ip(char *host) {
struct hostent *hp;
struct sockaddr_in addr;
char *str;
if (! host_lookup) {
return NULL;
}
hp = gethostbyname(host);
if (!hp) {
return NULL;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
str = strdup(inet_ntoa(addr.sin_addr));
return str;
}
char *raw2host(char *raw, int len) {
char *str;
#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
struct hostent *hp;
if (! host_lookup) {
return strdup("unknown");
}
hp = gethostbyaddr(raw, len, AF_INET);
if (!hp) {
return strdup(inet_ntoa(*((struct in_addr *)raw)));
}
str = strdup(hp->h_name);
#else
str = strdup("unknown");
#endif
return str;
}
char *raw2ip(char *raw) {
return strdup(inet_ntoa(*((struct in_addr *)raw)));
}
char *ip2host(char *ip) {
char *str;
#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
struct hostent *hp;
in_addr_t iaddr;
if (! host_lookup) {
return strdup("unknown");
}
iaddr = inet_addr(ip);
if (iaddr == htonl(INADDR_NONE)) {
return strdup("unknown");
}
hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET);
if (!hp) {
return strdup("unknown");
}
str = strdup(hp->h_name);
#else
str = strdup("unknown");
#endif
return str;
}
int dotted_ip(char *host) {
char *p = host;
while (*p != '\0') {
if (*p == '.' || isdigit((unsigned char) (*p))) {
p++;
continue;
}
return 0;
}
return 1;
}
static int get_port(int sock, int remote) {
struct sockaddr_in saddr;
unsigned int saddr_len;
int saddr_port;
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
if (remote) {
if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_port = ntohs(saddr.sin_port);
}
} else {
if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_port = ntohs(saddr.sin_port);
}
}
return saddr_port;
}
int get_remote_port(int sock) {
return get_port(sock, 1);
}
int get_local_port(int sock) {
return get_port(sock, 0);
}
static char *get_host(int sock, int remote) {
struct sockaddr_in saddr;
unsigned int saddr_len;
int saddr_port;
char *saddr_ip_str = NULL;
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
#if LIBVNCSERVER_HAVE_NETINET_IN_H
if (remote) {
if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_ip_str = inet_ntoa(saddr.sin_addr);
}
} else {
if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_ip_str = inet_ntoa(saddr.sin_addr);
}
}
#endif
if (! saddr_ip_str) {
saddr_ip_str = "unknown";
}
return strdup(saddr_ip_str);
}
char *get_remote_host(int sock) {
return get_host(sock, 1);
}
char *get_local_host(int sock) {
return get_host(sock, 0);
}
char *ident_username(rfbClientPtr client) {
ClientData *cd = (ClientData *) client->clientData;
char *str, *newhost, *user = NULL, *newuser = NULL;
int len;
if (cd) {
user = cd->username;
}
if (!user || *user == '\0') {
char msg[128];
int n, sock, ok = 0;
int block = 0;
/*
* need to check to see if the operation will block for
* a long time: a firewall may just ignore our packets.
*/
#if LIBVNCSERVER_HAVE_FORK
{ pid_t pid, pidw;
int rc;
if ((pid = fork()) > 0) {
usleep(100 * 1000); /* 0.1 sec */
pidw = waitpid(pid, &rc, WNOHANG);
if (pidw <= 0) {
usleep(1000 * 1000); /* 1.0 sec */
pidw = waitpid(pid, &rc, WNOHANG);
if (pidw <= 0) {
block = 1;
kill(pid, SIGTERM);
}
}
} else if (pid == -1) {
;
} else {
/* child */
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
if ((sock = rfbConnectToTcpAddr(client->host, 113)) < 0) {
exit(1);
} else {
close(sock);
exit(0);
}
}
}
#endif
if (block) {
;
} else if ((sock = rfbConnectToTcpAddr(client->host, 113)) < 0) {
rfbLog("could not connect to ident: %s:%d\n",
client->host, 113);
} else {
int ret;
fd_set rfds;
struct timeval tv;
int rport = get_remote_port(client->sock);
int lport = get_local_port(client->sock);
sprintf(msg, "%d, %d\r\n", rport, lport);
n = write(sock, msg, strlen(msg));
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
ret = select(sock+1, &rfds, NULL, NULL, &tv);
if (ret > 0) {
int i;
char *q, *p;
for (i=0; i<128; i++) {
msg[i] = '\0';
}
usleep(250*1000);
n = read(sock, msg, 127);
close(sock);
if (n <= 0) goto badreply;
/* 32782 , 6000 : USERID : UNIX :runge */
q = strstr(msg, "USERID");
if (!q) goto badreply;
q = strstr(q, ":");
if (!q) goto badreply;
q++;
q = strstr(q, ":");
if (!q) goto badreply;
q++;
q = lblanks(q);
p = q;
while (*p) {
if (*p == '\r' || *p == '\n') {
*p = '\0';
}
p++;
}
ok = 1;
if (strlen(q) > 24) {
*(q+24) = '\0';
}
newuser = strdup(q);
badreply:
n = 0; /* avoid syntax error */
} else {
close(sock);
}
}
if (! ok || !newuser) {
newuser = strdup("unknown-user");
}
if (cd) {
if (cd->username) {
free(cd->username);
}
cd->username = newuser;
}
user = newuser;
}
if (!strcmp(user, "unknown-user") && cd && cd->unixname[0] != '\0') {
user = cd->unixname;
}
if (unixpw && openssl_last_ip && strstr("UNIX:", user) != user) {
newhost = ip2host(openssl_last_ip);
} else {
newhost = ip2host(client->host);
}
len = strlen(user) + 1 + strlen(newhost) + 1;
str = (char *) malloc(len);
sprintf(str, "%s@%s", user, newhost);
free(newhost);
return str;
}
int find_free_port(int start, int end) {
int port;
if (start <= 0) {
start = 1024;
}
if (end <= 0) {
end = 65530;
}
for (port = start; port <= end; port++) {
int sock = rfbListenOnTCPPort(port, htonl(INADDR_ANY));
if (sock >= 0) {
close(sock);
return port;
}
}
return 0;
}
int have_ssh_env(void) {
char *str, *p = getenv("SSH_CONNECTION");
char *rhost, *rport, *lhost, *lport;
if (! p) {
char *q = getenv("SSH_CLIENT");
if (! q) {
return 0;
}
if (strstr(q, "127.0.0.1") != NULL) {
return 0;
}
return 1;
}
if (strstr(p, "127.0.0.1") != NULL) {
return 0;
}
str = strdup(p);
p = strtok(str, " ");
rhost = p;
p = strtok(NULL, " ");
if (! p) goto fail;
rport = p;
p = strtok(NULL, " ");
if (! p) goto fail;
lhost = p;
p = strtok(NULL, " ");
if (! p) goto fail;
lport = p;
if (0) fprintf(stderr, "%d/%d - '%s' '%s'\n", atoi(rport), atoi(lport), rhost, lhost);
if (atoi(rport) <= 16 || atoi(rport) > 65535) {
goto fail;
}
if (atoi(lport) <= 16 || atoi(lport) > 65535) {
goto fail;
}
if (!strcmp(rhost, lhost)) {
goto fail;
}
free(str);
return 1;
fail:
free(str);
return 0;
}