Logo Search packages:      
Sourcecode: vdetelweb version File versions  Download package

web.c

/*   
 *   VDETELWEB: VDE telnet and WEB interface
 *
 *   web.c: http micro server for vde mgmt
 *   
 *   Copyright 2005 Virtual Square Team University of Bologna - Italy
 *   written by Renzo Davoli 2005
 *   management of sha1 Marco Dalla Via 2008
 *   modified by Renzo Davoli 2008
 *   
 *   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
 *   (at your option) 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.
 *
 *   You should have received a copy of the GNU General Public License along
 *   with this program; if not, write to the Free Software Foundation, Inc.,
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *   $Id: web.c 288 2008-06-17 13:22:02Z rd235 $
 *
 */
#include <config.h>
#include  <stdio.h>
#define __USE_GNU
#include  <signal.h>
#include <stdarg.h>
#include <syslog.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include  <errno.h>
#include  <sys/types.h>
#include  <sys/socket.h>
#include  <sys/poll.h>
#include  <sys/ioctl.h>
#include <linux/un.h>
#include  <netinet/in.h>
#include  <arpa/inet.h>
#include  <string.h>
#include <getopt.h>
#include "vdetelweb.h"
#include <lwipv6.h>

#define WEB_TCP_PORT 80
#define WEB_IDENTIFY 0x0
#define WEB_AUTHORIZED 0x1
#define WEB_UNAUTHORIZED 0x2
#define WEB_OP_GET 0x0
#define WEB_OP_POST 0x1
#define WEB_OP_POSTDATA 0x2

const char b64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//static char *base64passwd;
struct webstat {
      unsigned char status;
      unsigned char op;
      unsigned int bodylen;
      char linebuf[BUFSIZE];
      char path[BUFSIZE];
      int  bufindex;
};

static void lowercase(char *s)
{
      while (*s != 0) {
            *s = tolower(*s);
            s++;
      }
}

void encode64(const char *from, char *to, int tosize) {

      int convbuf;
      int n = strlen(from);

      while ((n > 0) && (tosize > 3)) {

            convbuf = *from;
            from++;
            n--;
            convbuf <<= 8;
            if (n > 0)
                  convbuf |= *from;
            from++;
            n--;
            convbuf <<= 8;
            if (n > 0)
                  convbuf |= *from;
            from++;
            n--;
            *(to++) = b64_chars[convbuf >> 18];
            *(to++) = b64_chars[(convbuf >> 12) & 0x3f];
            *(to++) = (n < -1) ? '=' : b64_chars[(convbuf >> 6) & 0x3f];
            *(to++) = (n < 0)  ? '=' : b64_chars[convbuf & 0x3f];
            tosize -= 4;
      }
      *to = 0;
}

void decode64(const char *src, char *dest, int dest_size) {

      int convbuf;
      int l = strlen(src);
      char c_src[l];
      char *c;

      int i, j;

      strcpy(c_src, src);

      /* Sostitute '=' (paddings) with 0 ['A'] */
      while ((c = strchr(c_src, '=')) != NULL)
            *c = 'A';

      /* Convert 4 byte in 6 bit (64) to 3 byte in 8 bit */
      for (i = 0, j = 0; i < l; i += 4, j += 3) {

            convbuf = (((int)(strchr(b64_chars, c_src[i]) - b64_chars) << 18) +
                        ((int)(strchr(b64_chars, c_src[i + 1]) - b64_chars) << 12) +
                        ((int)(strchr(b64_chars, c_src[i + 2]) - b64_chars) << 6) +
                        ((int)(strchr(b64_chars, c_src[i + 3]) - b64_chars)));
            dest[j]     = ((convbuf >> 16) & 255);
            dest[j + 1] = ((convbuf >> 8) & 255);
            dest[j + 2] = ((convbuf & 255));
      }

      dest[j] = '\0';
}

#if 0
static void createbase64passwd()
{
      char buf[BUFSIZE];
      char buf64[BUFSIZE*4/3];
      snprintf(buf,BUFSIZE,"admin:%s",passwd);
      encode64(buf,buf64,BUFSIZE*4/3);
      base64passwd=strdup(buf64);
}
#endif

static void lwip_printf(int fd, const char *format, ...)
{
      char outbuf[BUFSIZE];
      va_list arg;
      va_start (arg, format);
      vsnprintf(outbuf,BUFSIZE,format,arg);
      lwip_write(fd,outbuf,strlen(outbuf));
}

static void web_close(int fn,int fd)
{
      //printf("web_close %d %d\n",fn,fd);
      free(status[fn]);
      delpfd(fn);
      lwip_close(fd);
}

static int vde_getanswer(voidfun f,void *arg,int vdefd)
{
      char buf[BUFSIZE];
      char linebuf[BUFSIZE+1];
      int n=0,ib=0,il=0,indata=0,eoa=0;
      do {
            n=read(vdefd,buf,BUFSIZE);
            for(ib=0;ib<n;ib++)
            {
                  linebuf[il++]=buf[ib];
                  if (buf[ib] == '\n') {
                        linebuf[il-1]='\r';
                        linebuf[il]='\n';
                        linebuf[il+1]=0;
                        il++;
                        if (indata) {
                              if (linebuf[0]=='.' && linebuf[1]=='\r')
                                    indata=0;
                              else
                                    f(arg,linebuf,il,indata,0);
                        } else if (strncmp(linebuf,"0000",4)==0)
                              indata=1;
                        else {
                              if(linebuf[0]=='1' &&
                                          linebuf[1] >= '0' &&  linebuf[1] <= '9' &&
                                          linebuf[2] >= '0' &&  linebuf[2] <= '9' &&
                                          linebuf[3] >= '0' &&  linebuf[3] <= '9') {
                                    f(arg,linebuf+5,il-5,0,atoi(linebuf));
                                    eoa=atoi(linebuf);
                              }
                        }
                        il=0;
                  }
            }
      } while (!eoa);
      return(eoa);
}

struct vdesub {
      char *name;
      char *descr;
      char *syntax;
      struct vdesub *next;
};

struct vdemenu {
      char *name;
      char *descr;
      struct vdesub *sub;
      struct vdemenu *next;
};

static struct vdemenu *menuhead;

static struct vdemenu *vde_findmenu(struct vdemenu *head,char *name)
{
      if (head ==  NULL)
            return NULL;
      else 
            if (strcmp(head->name,name)==0) 
                  return head;
            else
                  return vde_findmenu(head->next,name);
}

static void vde_addsub(struct vdesub **headp,char *name,char *syntax,char *help)
{
      if (*headp == NULL) {
            *headp=malloc(sizeof(struct vdesub));
            if (*headp != NULL) {
                  (*headp)->name=name;
                  (*headp)->descr=help;
                  (*headp)->syntax=syntax;
                  (*headp)->next=NULL;
            }
      } else
            vde_addsub(&((*headp)->next),name,syntax,help);
}

static void vde_addcmd(struct vdemenu *head,char *menu,char *name,char *syntax,char *help)
{
      if (head != NULL) {
            if (strcmp(head->name,menu) == 0)
                  vde_addsub(&(head->sub),name,syntax,help);
            else
                  vde_addcmd(head->next,menu,name,syntax,help);
      }
}

static void vde_addmenu(struct vdemenu **headp,char *name,char *help)
{
      if (*headp == NULL) {
            *headp=malloc(sizeof(struct vdemenu));
            if (*headp != NULL) {
                  (*headp)->name=name;
                  (*headp)->descr=help;
                  (*headp)->sub=NULL;
                  (*headp)->next=NULL;
            }
      } else
            vde_addmenu(&((*headp)->next),name,help);
}

static void vde_helpline(struct vdemenu **headp,char *buf,int len,int indata,int rv)
{
      static int nl=0;
      static int syntaxpos,helppos;
      nl++;
      if (nl==2) {
            int i;
            for (i=0;i<len && buf[i]=='-';i++) ;
            for (;i<len && buf[i]==' ';i++) ;
            syntaxpos=i;
            for (;i<len && buf[i]=='-';i++) ;
            for (;i<len && buf[i]==' ';i++) ;
            helppos=i;
      }
      else if (nl > 2 && indata && (strncmp(buf,"debug",5) !=0 )) {
            char *name;
            char *syntax;
            char *help;
            int namelen;
            for (namelen=0;namelen<syntaxpos && buf[namelen]!=' ';namelen++) ;
            if (strncmp(buf+syntaxpos,"======",5) ==0) {
                  /* MENU */
                  name=strndup(buf,namelen);
                  help=strndup(buf+helppos,len-helppos-2);
                  vde_addmenu(headp,name,help);
            } else {
                  int slash;
                  for (slash=0;slash<namelen && buf[slash]!='/';slash++) ;
                  if (slash<namelen) {
                        int synlen;
                        buf[slash]=0;slash++;
                        namelen-=slash;
                        for (synlen=helppos-syntaxpos; synlen>0 && buf[syntaxpos+synlen-1]==' ';synlen--) ;
                        name=strndup(buf+slash,namelen);
                        if (synlen>0)
                              syntax=strndup(buf+syntaxpos,synlen);
                        else
                              syntax="";
                        help=strndup(buf+helppos,len-helppos-2);
                        vde_addcmd(*headp,buf,name,syntax,help);
                  }     
            }
      }
}

static struct vdemenu *vde_gethelp(int vdefd)
{
      struct vdemenu *head=NULL;
      write(vdefd,"help\n",5);
      vde_getanswer(vde_helpline,&head,vdefd);
      return head;
}

static void lwip_showline(int *fdp,char *buf,int len,int indata,int rv)
{
      if (indata)
            lwip_write(*fdp,buf,len);
}

static int lwip_showout(int fd, int vdefd)
{
      return vde_getanswer(lwip_showline,&fd,vdefd);
}

static int hex2num(int c)
{
      if (c>96) c-=32;
      c -='0';
      if (c>9)
            c-=7;
      return c;
}

static char *uriconv(char *in)
{
      char *s=in;
      char *t=in;
      while ((*t=*s) != 0) {
            if (*s=='+')
                  *t=' ';
            if (*s=='%') {
                  *t=(hex2num(*(s+1))<<4)+hex2num(*(s+2));
                  s+=2;
            }
            s++;t++;
      }
      return in;
}

static void postdata_parse(int fd,int vdefd,char *menu,char *postdata)
{
      char cmdbuf[BUFSIZE];
      int cmdlen,arglen,rv;
      char *postcmd,*cmd,*endcmd,*arg=NULL;
      /*printf("PD **%s**\n",postdata);*/
      if ((postcmd=strstr(postdata,"X="))!=NULL) {
            /* enter in a text field (catched through the hidden button) */
            cmd=NULL;
            while(postdata)
            {
                  char *token=strsep(&postdata,"&");
                  int l=strlen(token);
                  char *targ=index(token,'=');
                  if(strncmp("X=",token,2) != 0) {
                        if (targ+1 < token+l) {
                              if(cmd==NULL) {
                                    char *point;
                                    if ((point=strstr(token,".arg")) != NULL)
                                          *point=0;
                                    cmd=token;
                                    arg=targ+1;
                              } else 
                                    cmd="";
                        }
                  }
            }
            if(cmd!=NULL && *cmd != 0) {
                  strncpy(cmdbuf,menu,BUFSIZE);
                  strncat(cmdbuf,"/",BUFSIZE);
                  strncat(cmdbuf,cmd,BUFSIZE);
                  strncat(cmdbuf," ",BUFSIZE);
                  strncat(cmdbuf,uriconv(arg),BUFSIZE);
                  write(vdefd,cmdbuf,strlen(cmdbuf));
                  lwip_printf(fd,"<P> </P><B>%s %s</B><PRE>",prompt,cmdbuf);
                  rv=lwip_showout(fd,vdefd);
                  lwip_printf(fd,"</PRE><B>Result: %s</B>\r\n",strerror(rv-1000));
            }
      }
      else if ((postcmd=strstr(postdata,"COMMAND="))!=NULL) {
            /* accept button */
            postcmd+=8;
            for(cmdlen=0;postcmd[cmdlen] != '&' && postcmd[cmdlen] != 0; cmdlen++)
                  ;
            strncpy(cmdbuf,menu,BUFSIZE);
            strncat(cmdbuf,"/",BUFSIZE);
            cmd=cmdbuf+strlen(cmdbuf);
            strncat(cmdbuf,postcmd,(BUFSIZE<cmdlen)?BUFSIZE:cmdlen);
            endcmd=cmdbuf+strlen(cmdbuf);
            strncat(cmdbuf,".arg",BUFSIZE);
            if ((arg=strstr(postdata,cmd))!=NULL) {
                  arg+=strlen(cmd)+1;
                  for(arglen=0;arg[arglen] != '&' && arg[arglen] != 0; arglen++)
                        ;
                  arg[arglen]=0;
                  *endcmd=0;
                  if (*arg != 0) {
                        strncat(cmdbuf," ",BUFSIZE);
                        strncat(cmdbuf,uriconv(arg),BUFSIZE);
                  }
            } else
                  *endcmd=0;
            write(vdefd,cmdbuf,strlen(cmdbuf));
            lwip_printf(fd,"<P> </P><B>%s %s</B><PRE>",prompt,cmdbuf);
            rv=lwip_showout(fd,vdefd);
            lwip_printf(fd,"</PRE><B>Result: %s</B>\r\n",strerror(rv-1000));
      }
}

static char css[]=
"<style type=\"text/CSS\"\r\n"
"<!--\r\n"
".core {\r\n"
"font-family: Helvetica;\r\n"
"color: #0000FF;\r\n"
"background-color: #FFFFFF;\r\n"
"text-align: justify;\r\n"
"margin-left: 5pt;\r\n"
"margin-top: 5pt;\r\n"
"margin-right: 5pt;\r\n"
"margin-bottom: 5pt;\r\n"
"}\r\n"
".sidebar {\r\n"
"font-family: Helvetica;\r\n"
"font-size: 12px;\r\n"
"color: #ff0000;\r\n"
"}\r\n"
"-->\r\n"
"</style>\r\n";

static char okmsg[]= 
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n";

static char errmsg[]= 
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<HTML><HEAD>\r\n"
"<TITLE>404 Not Found</TITLE>\r\n"
"</HEAD><BODY>\r\n"
"<H1>Not Found</H1>\r\n"
"The requested URL was not found on this server.\r\n"
"<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
"</BODY></HTML>\r\n";

static void web_this_form(int fd,struct vdemenu *this)
{
      struct vdesub *sub;
      for (sub=this->sub;sub!=NULL;sub=sub->next) {
            if (*(sub->syntax) == 0) {
                  lwip_printf(fd,
                              "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
                              "<TD width=100></TD>\r\n"
                              "<TD width=100></TD>\r\n"
                              "<TD width=300>%s</TD></TR>\r\n",
                              "COMMAND",sub->name,sub->descr);
            } else {
                  lwip_printf(fd,
                              "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
                              "<TD width=100>%s</TD>\r\n"
                              "<TD width=100><INPUT type=text name=\"%s.arg\"></TD>\r\n"
                              "<TD width=300>%s</TD></TR>\r\n",
                              "COMMAND",sub->name,sub->syntax,sub->name,sub->descr);
            }
      }
}

static void web_menu_index(int fd)
{
      struct vdemenu *this;
      lwip_printf(fd,"<P><A HREF=\"index.html\">Home Page</A></P>\r\n");
      for (this=menuhead;this!=NULL;this=this->next)
            lwip_printf(fd,"<P><A HREF=\"%s.html\">%s</A></P>\r\n",this->name,this->name);
}

static void web_create_page(char *path,int fd,int vdefd,char *postdata)
{
      struct vdemenu *this=NULL;
      char *tail;
      if ((tail=strstr(path,".html")) != NULL)
            *tail=0;
      if (*path==0 || ((this=vde_findmenu(menuhead,path)) != NULL)) {
            lwip_write(fd,okmsg,sizeof(okmsg));
            lwip_printf(fd,
                        "<HTML><HEAD>\r\n"
                        "<TITLE>%s %s</TITLE>\r\n",
                        prompt, (*path==0)?"Home Page":path);
            lwip_write(fd,css,sizeof(css));
            lwip_printf(fd,
                        "</HEAD><BODY class=core>\r\n"
                        "<H1>%s %s</H1>\r\n"
                        "<TABLE BORDER=0><TD width=80 bgcolor=#aacbff valign=top class=sidebar>", 
                        prompt, (*path==0)?"Home Page":this->descr);
            web_menu_index(fd);
            if (*path==0) {/* HOME PAGE */
                  int rv;
                  write(vdefd,"showinfo\r\n",10);
                  lwip_printf(fd,
                              "</TD><TD><PRE>\r\n");
                  rv=lwip_showout(fd,vdefd);
                  lwip_printf(fd,"</PRE>\r\n");
                  if (rv != 1000)
                        lwip_printf(fd,"<B>%s</B>\r\n",strerror(rv-1000));
            } else {
                  lwip_printf(fd,
                              "</TD><TD><FORM action=\"%s.html\" method=post table-layout=fixed>\r\n<TABLE><THEAD><TR>\r\n"
                              "<TD><INPUT type=submit name=X style=\"visibility:hidden\" ></TD>\r\n"
                              "<TD><B>Syntax</B></TD><TD><B>Args</B>\r\n"
                              "</TD><TD><B>Description</B></TD></TR></THEAD>\r\n",path);
                  web_this_form(fd,this);
                  lwip_printf(fd,"</TABLE></FORM>\r\n");
                  if (postdata != NULL) {
                        postdata_parse(fd,vdefd,path,postdata);
                  }
            }
            lwip_printf(fd,
                        "</TD></TABLE>\r\n"
                        "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
                        "</BODY></HTML>\r\n");
      } else
            lwip_write(fd,errmsg,sizeof(errmsg));
}

static char authmsg[]= 
"HTTP/1.1 401 Authorization Required\r\n"
"WWW-Authenticate: Basic realm=\"";

//"Content-Length: 187\r\n"
//"Connection: close\r\n"
static char authmsg2[]= "\"\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<HTML><HEAD>\r\n"
"<TITLE>401 Authorization Required</TITLE>\r\n"
"</HEAD><BODY>\r\n"
"<H1>Authorization Required</H1>\r\n"
"Login and Password required\r\n"
"<hr>\r\nVDE 2.0 WEB MGMT INTERFACE\r\n"
"</BODY></HTML>\r\n";


int web_core(int fn,int fd,int vdefd)
{
      struct webstat *st=status[fn];
      //printf("CORE %s\n",st->linebuf);
      if (st->op==WEB_OP_POSTDATA) {
            //printf("POSTDATA %s\n",st->linebuf);
            web_create_page(&(st->path[1]),fd,vdefd,st->linebuf);
            return 1;
      } else if (strncmp(st->linebuf,"GET",3) == 0) {
            //printf("GET %s\n",st->linebuf);
            sscanf(st->linebuf+4,"%s",st->path);
            st->op=WEB_OP_GET;
            return 0;
      } else if (strncmp(st->linebuf,"POST",3) == 0) {
            //printf("POST %s\n",st->linebuf);
            sscanf(st->linebuf+5,"%s",st->path);
            st->op=WEB_OP_POST;
            return 0;
      } else if (strncmp(st->linebuf,"Content-Length: ",16) == 0) {
            st->bodylen=atoi(st->linebuf+16);
            //printf("BODYLEN %d\n",st->bodylen);
            return 0;
      } else if (strncmp(st->linebuf,"Authorization: Basic",20) == 0) {
            char passwd_buf[BUFSIZE];
            char *passwd_buf_shift;
            int len=strlen(st->linebuf);
            int k=20;
            while (st->linebuf[k] == ' ') k++;
            while (st->linebuf[len-1] == '\n' ||
                        st->linebuf[len-1] == '\r' ||
                        st->linebuf[len-1] == ' ') {
                  len--;
                  st->linebuf[len]=0;
            }
            /* SHA1 */
            decode64((st->linebuf + k), passwd_buf, strlen(st->linebuf + k));
            passwd_buf_shift = (char *)(strchr(passwd_buf, ':') + 1);
            if (sha1passwdok(passwd_buf_shift))
                  st->status=WEB_AUTHORIZED;
            return 0;
      } else if (st->linebuf[0]=='\n' || st->linebuf[0]=='\r') {
            switch (st->status) {
                  case WEB_IDENTIFY:
                        lwip_write(fd,authmsg,sizeof(authmsg));
                        lwip_write(fd,prompt,strlen(prompt));
                        lwip_write(fd,authmsg2,sizeof(authmsg2));
                        return 1;
                        break;
                  case WEB_AUTHORIZED:
                        lowercase(st->path);
                        if (strcmp(st->path,"/index.html") == 0) 
                              st->path[1]=0;
                        if (st->op == WEB_OP_GET) {
                              web_create_page(&(st->path[1]),fd,vdefd,NULL);
                              return 1;
                        } else {
                              st->op=WEB_OP_POSTDATA;
                              return 0;
                        }
                  default:
                        return 0;
            }
      } else
            return 0;
}

void webdata(int fn,int fd,int vdefd)
{
      char buf[BUFSIZE];
      int n,i;
      struct webstat *st=status[fn];
      n=lwip_read(fd,buf,BUFSIZE);
      if (n==0) {
            web_close(fn,fd);
      }
      else if (n<0)
            printlog(LOG_ERR,"web read err: %s",strerror(errno));
      else {
            for (i=0;i<n && st->bufindex<BUFSIZE;i++) {
                  st->linebuf[(st->bufindex)++]=buf[i];
                  if (buf[i]=='\n' || (st->op==WEB_OP_POSTDATA && st->bufindex==st->bodylen)) {
                        st->linebuf[(st->bufindex)]=0;
                        if (web_core(fn,fd,vdefd)) {
                              web_close(fn,fd);
                              break;
                        } else
                              st->bufindex=0;
                  }
            }
      }
}

void webaccept(int fn,int fd,int vdefd)
{
      struct sockaddr_in  cli_addr;
      int newsockfd;
      unsigned int clilen;
      struct webstat *st;
      int newfn;

      clilen = sizeof(cli_addr);
      newsockfd = lwip_accept(fd, (struct sockaddr *) &cli_addr, &clilen);

      if (newsockfd < 0) {
            printlog(LOG_ERR,"web accept err: %s",strerror(errno));
      }

      newfn=addpfd(newsockfd,webdata);
      status[newfn]=st=malloc(sizeof(struct webstat));
      st->status=WEB_IDENTIFY;
      st->op=0;
      st->bufindex=0;
}

void web_init(int vdefd)
{
      int sockfd;
      struct sockaddr_in  serv_addr;
      sockfd=lwip_socket(AF_INET, SOCK_STREAM, 0);

      if (!sockfd) {
            printlog(LOG_ERR,"web socket err: %s",strerror(errno));
      }

      bzero((char *) &serv_addr, sizeof(serv_addr));
      serv_addr.sin_family      = AF_INET;
      serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      serv_addr.sin_port        = htons(WEB_TCP_PORT);

      if (lwip_bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
            printlog(LOG_ERR,"web bind err: %s",strerror(errno));
      }

      lwip_listen(sockfd, 5);

      //createbase64passwd();
      menuhead=vde_gethelp(vdefd);
      addpfd(sockfd,webaccept);
}

Generated by  Doxygen 1.6.0   Back to index