/*
NNTP authentication proxy by Lasse L. Johnsen
Based on FreeBSD bounce port by obrien@FreeBSD.org and others
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef _AIX
#include <sys/select.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#define QLEN 5
#define DEFAULT_PORT 119
char sbuf[16384], cbuf[16384];
void sigchld() {
signal(SIGCHLD, sigchld);
while(waitpid(0, (int *)0, WNOHANG|WUNTRACED)>=0);
}
void communicate(int sfd, int cfd) {
char *chead, *ctail, *shead, *stail;
int num, nfd, spos, cpos;
extern int errno;
fd_set rd, wr;
struct itimerval itime;
itime.it_interval.tv_sec=0;
itime.it_interval.tv_usec=0;
itime.it_value.tv_sec=21600;
itime.it_value.tv_usec=0;
setitimer(ITIMER_REAL,&itime,NULL);
/* arbitrary connection time limit: 6 hours (in case the client hangs) */
chead=ctail=cbuf;
cpos=0;
shead=stail=sbuf;
spos=0;
while (1) {
FD_ZERO(&rd);
FD_ZERO(&wr);
if (spos<sizeof(sbuf)-1)
FD_SET(sfd, &rd);
if (ctail>chead)
FD_SET(sfd, &wr);
if (cpos<sizeof(cbuf)-1)
FD_SET(cfd, &rd);
if (stail>shead)
FD_SET(cfd, &wr);
nfd=select(256, &rd, &wr, 0, 0);
if (nfd<=0) continue;
if (FD_ISSET(sfd, &rd)) {
num=read(sfd,stail,sizeof(sbuf)-spos);
if ((num==-1) && (errno != EWOULDBLOCK)) return;
if (num==0) {
#ifdef FNDELAY
fcntl(sfd,F_SETFL,fcntl(sfd,F_GETFL,0)&~FNDELAY);
fcntl(cfd,F_SETFL,fcntl(cfd,F_GETFL,0)&~FNDELAY);
#endif
if (ctail!=chead) write(sfd,chead,ctail-chead);
if (stail!=shead) write(cfd,shead,stail-shead);
write(cfd,chead,0);
return;
}
if (num>0) {
spos+=num;
stail+=num;
if (!--nfd) continue;
}
}
if (FD_ISSET(cfd, &rd)) {
num=read(cfd,ctail,sizeof(cbuf)-cpos);
if ((num==-1) && (errno != EWOULDBLOCK)) return;
if (num==0) {
#ifdef FNDELAY
fcntl(sfd,F_SETFL,fcntl(sfd,F_GETFL,0)&~FNDELAY);
fcntl(cfd,F_SETFL,fcntl(cfd,F_GETFL,0)&~FNDELAY);
#endif
if (ctail!=chead) write(sfd,chead,ctail-chead);
if (stail!=shead) write(cfd,shead,stail-shead);
write(sfd,chead,0);
return;
}
if (num>0) {
cpos+=num;
ctail+=num;
if (!--nfd) continue;
}
}
if (FD_ISSET(sfd, &wr)) {
num=write(sfd,chead,ctail-chead);
if ((num==-1) && (errno != EWOULDBLOCK)) return;
if (num>0) {
chead += num;
if (chead==ctail) {
chead=ctail=cbuf;
cpos=0;
}
if (!--nfd) continue;
}
}
if (FD_ISSET(cfd, &wr)) {
num=write(cfd,shead,stail-shead);
if ((num==-1) && (errno != EWOULDBLOCK)) return;
if (num>0) {
shead += num;
if (shead==stail) {
shead=stail=sbuf;
spos=0;
}
if (!--nfd) continue;
}
}
}
}
int main(int argc,char *argv[]) {
int srv_fd, rem_fd, len, cl_fd, on=1;
int myport=DEFAULT_PORT, remoteport;
struct sockaddr_in rem_addr, srv_addr, cl_addr;
char *myname;
struct hostent *hp, *hpLocal;
extern char *optarg;
extern int optind;
char *hostname = NULL;
char ch;
/* NNTP vars */
FILE *nntp_fi, *nntp_fo;
char *lineptr, *fuser, *fpass, **cap, *ca[3];
size_t ilen = 1;
int cnt = 0, usergiven = 0, passgiven = 0;
/* Ends */
myname=argv[0];
/* Process arguments */
while( (ch = getopt(argc, argv, "p:a:")) != -1 ) {
switch(ch) {
case 'a':
hostname = malloc( strlen(optarg) + 1);
if( !hostname ) {
fprintf( stderr, "Can't allocate memory!\n" );
exit(-1);
}
strcpy( hostname, optarg );
break;
case 'p':
if ((myport=atoi(optarg))==0) {
fprintf(stderr,"Bad port number.\n");
exit(-1);
}
break;
}
}
argc -= optind;
argv += optind;
if (argc!=4) {
fprintf(stderr,"Use: %s [-a localaddr] [-p localport] machine port username password\n",myname);
exit(-1);
}
if ((remoteport=atoi(argv[1]))<=0) {
fprintf(stderr, "Bad remote port number.\n");
exit(-1);
}
memset((char *) &rem_addr, 0, sizeof(rem_addr));
memset((char *) &srv_addr, 0, sizeof(srv_addr));
memset((char *) &cl_addr, 0, sizeof(cl_addr));
cl_addr.sin_family=AF_INET;
cl_addr.sin_port=htons(remoteport);
if ((hp=gethostbyname(argv[0]))==NULL) {
cl_addr.sin_addr.s_addr=inet_addr(argv[0]);
if (cl_addr.sin_addr.s_addr==-1) {
fprintf(stderr, "Unknown host.\n");
exit(-1);
}
} else
cl_addr.sin_addr=*(struct in_addr *)(hp->h_addr_list[0]);
if( hostname ) {
if ((hpLocal=gethostbyname(hostname))==NULL) {
srv_addr.sin_addr.s_addr=inet_addr(hostname);
if (srv_addr.sin_addr.s_addr==-1) {
fprintf(stderr, "Unknown host: %s\n", hostname);
exit(-1);
}
} else
srv_addr.sin_addr=*(struct in_addr *)(hp->h_addr_list[0]);
}
srv_addr.sin_family=AF_INET;
/* srv_addr.sin_addr.s_addr=htonl(INADDR_ANY); */
srv_addr.sin_port=htons(myport);
srv_fd=socket(PF_INET,SOCK_STREAM,0);
if (bind(srv_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr))==-1) {
perror("bind");
exit(-1);
}
listen(srv_fd,QLEN);
signal(SIGCHLD, sigchld);
printf("Ready to bounce connections from port %i to %s on port %i\n",
myport, argv[0], remoteport);
close(0); close(1); close(2);
chdir("/");
#ifdef TIOCNOTTY
if ((rem_fd=open("/dev/tty", O_RDWR)) >= 0) {
ioctl(rem_fd, TIOCNOTTY, (char *)0);
close(rem_fd);
}
#endif
if (fork()) exit(0);
while (1) {
len=sizeof(rem_addr);
rem_fd=accept(srv_fd,(struct sockaddr *)&rem_addr,&len);
if (rem_fd<0) {
if (errno==EINTR) continue;
exit(-1);
}
syslog( LOG_NOTICE, "connection from %s to local port %i. Bouncing to %s, %i",
inet_ntoa(rem_addr.sin_addr), myport, argv[0], remoteport );
switch(fork()) {
case -1:
/* we're in the background.. no-one to complain to */
break;
case 0: /* child process */
close(rem_fd);
break;
default: /* parent process */
close(srv_fd); /* close original socket */
if ((cl_fd=socket(PF_INET, SOCK_STREAM, 0))<0) {
close(rem_fd);
exit(-1);
}
if (connect(cl_fd, (struct sockaddr *)&cl_addr,
sizeof(cl_addr))<0) {
close(rem_fd);
exit(-1);
}
setsockopt(cl_fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
setsockopt(rem_fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
/* This is where the NNTP authentication goes on */
if(rem_fd > -1){
nntp_fi = fdopen(rem_fd, "r");
nntp_fo = fdopen(rem_fd, "w");
fuser = (char *)malloc(256);
fpass = (char *)malloc(256);
fprintf(nntp_fo,"200 NNTPProxy ready to authenticate\n");
fflush(nntp_fo);
while((lineptr = fgetln(nntp_fi, &ilen)) != NULL){
if(ilen > 2 ){
lineptr[ilen-2]='\0';
lineptr[ilen-1]='\0';
for (cap = ca; (*cap = strsep(&lineptr, " \t")) != NULL;)
if (**cap != '\0')
if (++cap >= &ca[3])
break;
if(strcasecmp("quit",ca[0]) == 0){
fprintf(nntp_fo,"205 Ciao\n");
fflush(nntp_fo);
fclose(nntp_fi);
fclose(nntp_fo);
}
if(strcasecmp("authinfo",ca[0]) == 0){
if(strcasecmp("user",ca[1]) == 0){
usergiven = 1;
snprintf(fuser,256,"%s",ca[2]);
fprintf(nntp_fo,"381 PASS required\n");
fflush(nntp_fo);
}
if(strcasecmp("pass",ca[1]) == 0){
if(usergiven == 1){
passgiven = 1;
snprintf(fpass,256,"%s",ca[2]);
}
else{
fprintf(nntp_fo,"480 Please give username first\n");
fflush(nntp_fo);
}
}
if((strcasecmp("pass",ca[1]) != 0) && (strcasecmp("user",ca[1]) != 0)){
fprintf(nntp_fo,"480 Unknown AUTHINFO parameter\n");
fflush(nntp_fo);
}
}
else{
fprintf(nntp_fo,"480 Please authenticate first\n");
fflush(nntp_fo);
}
if((usergiven == 1) && (passgiven == 1)){
if((strcmp(argv[2],fuser) == 0) && (strcmp(argv[3],fpass) == 0)){
fprintf(nntp_fo,"281 Let's go then\n");
fflush(nntp_fo);
break;
}
else{
fprintf(nntp_fo,"502 Username/Password incorrect\n");
fflush(nntp_fo);
fclose(nntp_fi);
fclose(nntp_fo);
}
}
cnt++;
if(cnt > 10){
fclose(nntp_fi);
fclose(nntp_fo);
}
}
}
}
/* Ends */
communicate(cl_fd, rem_fd);
close(rem_fd);
exit(0);
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1