/* SAS 1.1 - Simple Authentication Server (c) 2002 netEstate GmbH (www.netestate.de) This simple HTTP-server will bind to the port specified with PORT (default is 19432) and wait for HTTP-connections. Every new connection will be reported to syslog. If a request contains the string 'password=' (as in a GET-request containing a form-variable 'password'), sas will extract all following alphanumerical characters to a maximum length of MAX_PASSWORD_SIZE (default is 16) and call the command './login browser_ip password'. The output is sent as html-page to the browser. If a request contains the string 'logout', sas will call './logout browser_ip'. The output is sent as html-page to the browser. For all other Requests, sas will send the file index.html from the current directory to the browser. COPYING ------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. To receive a copy of the GNU General Public License, got to www.fsf.org or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // defines the TCP-port the server is listening on #define PORT 19432 // passwords longer than this will be truncated #define MAX_PASSWORD_SIZE 16 // this is a buffer size #define MAX_DGRAM_SIZE 65534 // this is our HTTP-Header char* http_header="\ HTTP/1.0 200 OK\r\n\ Content-Type: text/html\r\n\ Server: Simple Authentication Server 1.0 - Connection has beed logged\r\n\ \r\n"; // concatenate two strings and send the resulting message to the system log void log(char* msg1,char* msg2) { openlog("sas",LOG_PERROR,LOG_AUTHPRIV); syslog(LOG_INFO,"%s%s",msg1,msg2); closelog(); } // write the data in buf with length len to handle dst void senddata(int dst,char* buf,unsigned long len) { int len1,pos; pos=0; while (1) { len1=write(dst,buf+pos,len-pos); if (!len1) break; if (len1==-1) { if (errno==EINTR) continue; break; }; pos=pos+len1; if (pos>=len) break; }; return; }; // copy all data from handle src to handle dst void copy(int src,int dst) { int len; char buf[MAX_DGRAM_SIZE]; while (1) { len=read(src,buf,MAX_DGRAM_SIZE); if (!len) break; if (len==-1) { if (errno==EINTR) continue; break; }; senddata(dst,buf,len); }; return; } // copy all data from stream src to handle dst void copy1(FILE* src,int dst) { int len; char buf[MAX_DGRAM_SIZE]; while ((len=fread(buf,sizeof(char),(size_t) MAX_DGRAM_SIZE,src))) { if (len==-1) break; senddata(dst,buf,len); }; return; } // signal handler for SIGCHLD void sigchld(int sig) { int status; struct sigaction haction; while (waitpid(-1,&status,WNOHANG)>0); haction.sa_handler=&sigchld; haction.sa_flags=SA_RESETHAND|SA_RESTART; sigfillset(&haction.sa_mask); sigaction(sig,&haction,0); return; } int main() { int on=1; int sock,sock1; struct sockaddr_in my_addr; struct sockaddr_in other_addr; int socklen=sizeof(other_addr); char* other_ip; unsigned long len,bufpos; char buf[MAX_DGRAM_SIZE+1]; // +1 for string-terminating 0-byte char* needle; char ch; unsigned long pwlen; char password[MAX_PASSWORD_SIZE+1]; // +1 for string-terminating 0-byte // this contains ./login ipaddr password or ./logout ipaddr char cmdbuf[32+MAX_PASSWORD_SIZE+1]; // +1 for string-terminating 0-byte FILE* cmd; int handle; struct sigaction haction; // set signal handler for SIGCHLD haction.sa_handler=&sigchld; haction.sa_flags=SA_RESETHAND|SA_RESTART; sigfillset(&haction.sa_mask); sigaction(SIGCHLD,&haction,0); // get a socket sock=socket(AF_INET,SOCK_STREAM,6); if (sock==-1) exit(1); // set SO_REUSEADDR on it if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*) &on,sizeof(on))) exit(1); // bind to our port on all interfaces memset((void*)& my_addr,0,sizeof(my_addr)); my_addr.sin_port=htons(PORT); my_addr.sin_family=AF_INET; my_addr.sin_addr.s_addr=htonl(INADDR_ANY); if (bind(sock,(struct sockaddr*)&my_addr,sizeof(my_addr))==-1) { fprintf(stderr,"Error: Cannot bind to port %i\n",PORT); exit(1); }; // we want to listen to the socket if (listen(sock,1)==-1) exit(1); log("ready to accept connections",""); // this is the main loop accepting new connections while (1) { // accept a new connection memset((void*)& other_addr,0,sizeof(other_addr)); sock1=accept(sock,(struct sockaddr*) &other_addr,(socklen_t*)&socklen); if (sock1==-1) exit(1); // get ip-address of peer and log connection other_ip=inet_ntoa(other_addr.sin_addr); log("connection from ",other_ip); // now fork and handle request as child if (fork()) { // this is the parent close(sock1); continue; }; // receive complete request bufpos=0; while (1) { len=read(sock1,buf+bufpos,MAX_DGRAM_SIZE-bufpos); if (!len) break; if (len==-1) { if (errno==EINTR) continue; break; }; bufpos+=len; buf[bufpos]=0; if (bufpos>=MAX_DGRAM_SIZE) break; if (strstr(buf,"\r\n\r\n") || strstr(buf,"\n\n")) break; }; len=bufpos; /* now distinguish the three cases 1) request contains the string 'password=' -> user has supplied pw 2) request contains the string 'logout' -> user wants to log out default) user wants to log on -> display index.html */ needle=strstr(buf,"password="); if (needle) { // case 1: attempt to login. now extract alphanumerical password needle=needle+9; pwlen=0; password[pwlen]=0; ch=needle[0]; while ((ch>=48 && ch<=57) || (ch>=65 && ch<=90) || (ch>=97 && ch<=122)) { password[pwlen++]=ch; password[pwlen]=0; if (pwlen>=MAX_PASSWORD_SIZE) break; needle++; ch=needle[0]; }; // send http header senddata(sock1,http_header,strlen(http_header)); // prepare login command strcpy(cmdbuf,"./login "); strcat(cmdbuf,other_ip); strcat(cmdbuf," "); strcat(cmdbuf,password); // call login command and send output to peer cmd=popen(cmdbuf,"r"); if (cmd) { copy1(cmd,sock1); pclose(cmd); }; } else if (strstr(buf,"logout")) { // case 2: logout // send http header senddata(sock1,http_header,strlen(http_header)); // prepare logout command strcpy(cmdbuf,"./logout "); strcat(cmdbuf,other_ip); // call logout command and send output to peer cmd=popen(cmdbuf,"r"); if (cmd) { copy1(cmd,sock1); pclose(cmd); }; } else { // case 3: send default page // send http-header senddata(sock1,http_header,strlen(http_header)); // send default page index.html handle=open("index.html",O_RDONLY); if (handle!=-1) { copy(handle,sock1); close(handle); }; }; // now close connection and exit (child) close(sock1); exit(0); }; }