2 * VDETELWEB: VDE telnet and WEB interface
4 * web.c: http micro server for vde mgmt
6 * Copyright 2005 Virtual Square Team University of Bologna - Italy
7 * written by Renzo Davoli 2005
8 * management of sha1 Marco Dalla Via 2008
9 * modified by Renzo Davoli 2008
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <sys/ioctl.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
47 #include "vdetelweb.h"
50 #define WEB_TCP_PORT 80
51 #define WEB_IDENTIFY 0x0
52 #define WEB_AUTHORIZED 0x1
53 #define WEB_UNAUTHORIZED 0x2
54 #define WEB_OP_GET 0x0
55 #define WEB_OP_POST 0x1
56 #define WEB_OP_POSTDATA 0x2
58 const char b64_chars
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60 //static char *base64passwd;
65 char linebuf
[BUFSIZE
];
70 static void lowercase(char *s
)
78 void encode64(const char *from
, char *to
, int tosize
) {
83 while ((n
> 0) && (tosize
> 3)) {
98 *(to
++) = b64_chars
[convbuf
>> 18];
99 *(to
++) = b64_chars
[(convbuf
>> 12) & 0x3f];
100 *(to
++) = (n
< -1) ? '=' : b64_chars
[(convbuf
>> 6) & 0x3f];
101 *(to
++) = (n
< 0) ? '=' : b64_chars
[convbuf
& 0x3f];
107 void decode64(const char *src
, char *dest
, int dest_size
) {
118 /* Sostitute '=' (paddings) with 0 ['A'] */
119 while ((c
= strchr(c_src
, '=')) != NULL
)
122 /* Convert 4 byte in 6 bit (64) to 3 byte in 8 bit */
123 for (i
= 0, j
= 0; i
< l
; i
+= 4, j
+= 3) {
125 convbuf
= (((int)(strchr(b64_chars
, c_src
[i
]) - b64_chars
) << 18) +
126 ((int)(strchr(b64_chars
, c_src
[i
+ 1]) - b64_chars
) << 12) +
127 ((int)(strchr(b64_chars
, c_src
[i
+ 2]) - b64_chars
) << 6) +
128 ((int)(strchr(b64_chars
, c_src
[i
+ 3]) - b64_chars
)));
129 dest
[j
] = ((convbuf
>> 16) & 255);
130 dest
[j
+ 1] = ((convbuf
>> 8) & 255);
131 dest
[j
+ 2] = ((convbuf
& 255));
138 static void createbase64passwd()
141 char buf64
[BUFSIZE
*4/3];
142 snprintf(buf
,BUFSIZE
,"admin:%s",passwd
);
143 encode64(buf
,buf64
,BUFSIZE
*4/3);
144 base64passwd
=strdup(buf64
);
148 static void lwip_printf(int fd
, const char *format
, ...)
150 char outbuf
[BUFSIZE
];
152 va_start (arg
, format
);
153 vsnprintf(outbuf
,BUFSIZE
,format
,arg
);
154 lwip_write(fd
,outbuf
,strlen(outbuf
));
157 static void web_close(int fn
,int fd
)
159 //printf("web_close %d %d\n",fn,fd);
165 static int vde_getanswer(voidfun f
,void *arg
,int vdefd
)
168 char linebuf
[BUFSIZE
+1];
169 int n
=0,ib
=0,il
=0,indata
=0,eoa
=0;
171 n
=read(vdefd
,buf
,BUFSIZE
);
174 linebuf
[il
++]=buf
[ib
];
175 if (buf
[ib
] == '\n') {
181 if (linebuf
[0]=='.' && linebuf
[1]=='\r')
184 f(arg
,linebuf
,il
,indata
,0);
185 } else if (strncmp(linebuf
,"0000",4)==0)
188 if(linebuf
[0]=='1' &&
189 linebuf
[1] >= '0' && linebuf
[1] <= '9' &&
190 linebuf
[2] >= '0' && linebuf
[2] <= '9' &&
191 linebuf
[3] >= '0' && linebuf
[3] <= '9') {
192 f(arg
,linebuf
+5,il
-5,0,atoi(linebuf
));
214 struct vdemenu
*next
;
217 static struct vdemenu
*menuhead
;
219 static struct vdemenu
*vde_findmenu(struct vdemenu
*head
,char *name
)
224 if (strcmp(head
->name
,name
)==0)
227 return vde_findmenu(head
->next
,name
);
230 static void vde_addsub(struct vdesub
**headp
,char *name
,char *syntax
,char *help
)
232 if (*headp
== NULL
) {
233 *headp
=malloc(sizeof(struct vdesub
));
234 if (*headp
!= NULL
) {
236 (*headp
)->descr
=help
;
237 (*headp
)->syntax
=syntax
;
241 vde_addsub(&((*headp
)->next
),name
,syntax
,help
);
244 static void vde_addcmd(struct vdemenu
*head
,char *menu
,char *name
,char *syntax
,char *help
)
247 if (strcmp(head
->name
,menu
) == 0)
248 vde_addsub(&(head
->sub
),name
,syntax
,help
);
250 vde_addcmd(head
->next
,menu
,name
,syntax
,help
);
254 static void vde_addmenu(struct vdemenu
**headp
,char *name
,char *help
)
256 if (*headp
== NULL
) {
257 *headp
=malloc(sizeof(struct vdemenu
));
258 if (*headp
!= NULL
) {
260 (*headp
)->descr
=help
;
265 vde_addmenu(&((*headp
)->next
),name
,help
);
268 static void vde_helpline(struct vdemenu
**headp
,char *buf
,int len
,int indata
,int rv
)
271 static int syntaxpos
,helppos
;
275 for (i
=0;i
<len
&& buf
[i
]=='-';i
++) ;
276 for (;i
<len
&& buf
[i
]==' ';i
++) ;
278 for (;i
<len
&& buf
[i
]=='-';i
++) ;
279 for (;i
<len
&& buf
[i
]==' ';i
++) ;
282 else if (nl
> 2 && indata
&& (strncmp(buf
,"debug",5) !=0 )) {
287 for (namelen
=0;namelen
<syntaxpos
&& buf
[namelen
]!=' ';namelen
++) ;
288 if (strncmp(buf
+syntaxpos
,"======",5) ==0) {
290 name
=strndup(buf
,namelen
);
291 help
=strndup(buf
+helppos
,len
-helppos
-2);
292 vde_addmenu(headp
,name
,help
);
295 for (slash
=0;slash
<namelen
&& buf
[slash
]!='/';slash
++) ;
298 buf
[slash
]=0;slash
++;
300 for (synlen
=helppos
-syntaxpos
; synlen
>0 && buf
[syntaxpos
+synlen
-1]==' ';synlen
--) ;
301 name
=strndup(buf
+slash
,namelen
);
303 syntax
=strndup(buf
+syntaxpos
,synlen
);
306 help
=strndup(buf
+helppos
,len
-helppos
-2);
307 vde_addcmd(*headp
,buf
,name
,syntax
,help
);
313 static struct vdemenu
*vde_gethelp(int vdefd
)
315 struct vdemenu
*head
=NULL
;
316 write(vdefd
,"help\n",5);
317 vde_getanswer(vde_helpline
,&head
,vdefd
);
321 static void lwip_showline(int *fdp
,char *buf
,int len
,int indata
,int rv
)
324 lwip_write(*fdp
,buf
,len
);
327 static int lwip_showout(int fd
, int vdefd
)
329 return vde_getanswer(lwip_showline
,&fd
,vdefd
);
332 static int hex2num(int c
)
341 static char *uriconv(char *in
)
345 while ((*t
=*s
) != 0) {
349 *t
=(hex2num(*(s
+1))<<4)+hex2num(*(s
+2));
357 static void postdata_parse(int fd
,int vdefd
,char *menu
,char *postdata
)
359 char cmdbuf
[BUFSIZE
];
360 int cmdlen
,arglen
,rv
;
361 char *postcmd
,*cmd
,*endcmd
,*arg
=NULL
;
362 /*printf("PD **%s**\n",postdata);*/
363 if ((postcmd
=strstr(postdata
,"X="))!=NULL
) {
364 /* enter in a text field (catched through the hidden button) */
368 char *token
=strsep(&postdata
,"&");
370 char *targ
=index(token
,'=');
371 if(strncmp("X=",token
,2) != 0) {
372 if (targ
+1 < token
+l
) {
375 if ((point
=strstr(token
,".arg")) != NULL
)
384 if(cmd
!=NULL
&& *cmd
!= 0) {
385 strncpy(cmdbuf
,menu
,BUFSIZE
);
386 strncat(cmdbuf
,"/",BUFSIZE
);
387 strncat(cmdbuf
,cmd
,BUFSIZE
);
388 strncat(cmdbuf
," ",BUFSIZE
);
389 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
390 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
391 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
392 rv
=lwip_showout(fd
,vdefd
);
393 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
396 else if ((postcmd
=strstr(postdata
,"COMMAND="))!=NULL
) {
399 for(cmdlen
=0;postcmd
[cmdlen
] != '&' && postcmd
[cmdlen
] != 0; cmdlen
++)
401 strncpy(cmdbuf
,menu
,BUFSIZE
);
402 strncat(cmdbuf
,"/",BUFSIZE
);
403 cmd
=cmdbuf
+strlen(cmdbuf
);
404 strncat(cmdbuf
,postcmd
,(BUFSIZE
<cmdlen
)?BUFSIZE
:cmdlen
);
405 endcmd
=cmdbuf
+strlen(cmdbuf
);
406 strncat(cmdbuf
,".arg",BUFSIZE
);
407 if ((arg
=strstr(postdata
,cmd
))!=NULL
) {
409 for(arglen
=0;arg
[arglen
] != '&' && arg
[arglen
] != 0; arglen
++)
414 strncat(cmdbuf
," ",BUFSIZE
);
415 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
419 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
420 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
421 rv
=lwip_showout(fd
,vdefd
);
422 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
427 "<style type=\"text/CSS\"\r\n"
430 "font-family: Helvetica;\r\n"
431 "color: #0000FF;\r\n"
432 "background-color: #FFFFFF;\r\n"
433 "text-align: justify;\r\n"
434 "margin-left: 5pt;\r\n"
435 "margin-top: 5pt;\r\n"
436 "margin-right: 5pt;\r\n"
437 "margin-bottom: 5pt;\r\n"
440 "font-family: Helvetica;\r\n"
441 "font-size: 12px;\r\n"
442 "color: #ff0000;\r\n"
448 "HTTP/1.1 200 OK\r\n"
449 "Content-Type: text/html\r\n"
452 static char errmsg
[]=
453 "HTTP/1.1 404 Not Found\r\n"
454 "Content-Type: text/html\r\n"
457 "<TITLE>404 Not Found</TITLE>\r\n"
459 "<H1>Not Found</H1>\r\n"
460 "The requested URL was not found on this server.\r\n"
461 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
462 "</BODY></HTML>\r\n";
464 static void web_this_form(int fd
,struct vdemenu
*this)
467 for (sub
=this->sub
;sub
!=NULL
;sub
=sub
->next
) {
468 if (*(sub
->syntax
) == 0) {
470 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
471 "<TD width=100></TD>\r\n"
472 "<TD width=100></TD>\r\n"
473 "<TD width=300>%s</TD></TR>\r\n",
474 "COMMAND",sub
->name
,sub
->descr
);
477 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
478 "<TD width=100>%s</TD>\r\n"
479 "<TD width=100><INPUT type=text name=\"%s.arg\"></TD>\r\n"
480 "<TD width=300>%s</TD></TR>\r\n",
481 "COMMAND",sub
->name
,sub
->syntax
,sub
->name
,sub
->descr
);
486 static void web_menu_index(int fd
)
488 struct vdemenu
*this;
489 lwip_printf(fd
,"<P><A HREF=\"index.html\">Home Page</A></P>\r\n");
490 for (this=menuhead
;this!=NULL
;this=this->next
)
491 lwip_printf(fd
,"<P><A HREF=\"%s.html\">%s</A></P>\r\n",this->name
,this->name
);
494 static void web_create_page(char *path
,int fd
,int vdefd
,char *postdata
)
496 struct vdemenu
*this=NULL
;
498 if ((tail
=strstr(path
,".html")) != NULL
)
500 if (*path
==0 || ((this=vde_findmenu(menuhead
,path
)) != NULL
)) {
501 lwip_write(fd
,okmsg
,sizeof(okmsg
));
504 "<TITLE>%s %s</TITLE>\r\n",
505 prompt
, (*path
==0)?"Home Page":path
);
506 lwip_write(fd
,css
,sizeof(css
));
508 "</HEAD><BODY class=core>\r\n"
510 "<TABLE BORDER=0><TD width=80 bgcolor=#aacbff valign=top class=sidebar>",
511 prompt
, (*path
==0)?"Home Page":this->descr
);
513 if (*path
==0) {/* HOME PAGE */
515 write(vdefd
,"showinfo\r\n",10);
517 "</TD><TD><PRE>\r\n");
518 rv
=lwip_showout(fd
,vdefd
);
519 lwip_printf(fd
,"</PRE>\r\n");
521 lwip_printf(fd
,"<B>%s</B>\r\n",strerror(rv
-1000));
524 "</TD><TD><FORM action=\"%s.html\" method=post table-layout=fixed>\r\n<TABLE><THEAD><TR>\r\n"
525 "<TD><INPUT type=submit name=X style=\"visibility:hidden\" ></TD>\r\n"
526 "<TD><B>Syntax</B></TD><TD><B>Args</B>\r\n"
527 "</TD><TD><B>Description</B></TD></TR></THEAD>\r\n",path
);
528 web_this_form(fd
,this);
529 lwip_printf(fd
,"</TABLE></FORM>\r\n");
530 if (postdata
!= NULL
) {
531 postdata_parse(fd
,vdefd
,path
,postdata
);
536 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
537 "</BODY></HTML>\r\n");
539 lwip_write(fd
,errmsg
,sizeof(errmsg
));
542 static char authmsg
[]=
543 "HTTP/1.1 401 Authorization Required\r\n"
544 "WWW-Authenticate: Basic realm=\"";
546 //"Content-Length: 187\r\n"
547 //"Connection: close\r\n"
548 static char authmsg2
[]= "\"\r\n"
549 "Content-Type: text/html\r\n"
552 "<TITLE>401 Authorization Required</TITLE>\r\n"
554 "<H1>Authorization Required</H1>\r\n"
555 "Login and Password required\r\n"
556 "<hr>\r\nVDE 2.0 WEB MGMT INTERFACE\r\n"
557 "</BODY></HTML>\r\n";
560 int web_core(int fn
,int fd
,int vdefd
)
562 struct webstat
*st
=status
[fn
];
563 //printf("CORE %s\n",st->linebuf);
564 if (st
->op
==WEB_OP_POSTDATA
) {
565 //printf("POSTDATA %s\n",st->linebuf);
566 web_create_page(&(st
->path
[1]),fd
,vdefd
,st
->linebuf
);
568 } else if (strncmp(st
->linebuf
,"GET",3) == 0) {
569 //printf("GET %s\n",st->linebuf);
570 sscanf(st
->linebuf
+4,"%s",st
->path
);
573 } else if (strncmp(st
->linebuf
,"POST",3) == 0) {
574 //printf("POST %s\n",st->linebuf);
575 sscanf(st
->linebuf
+5,"%s",st
->path
);
578 } else if (strncmp(st
->linebuf
,"Content-Length: ",16) == 0) {
579 st
->bodylen
=atoi(st
->linebuf
+16);
580 //printf("BODYLEN %d\n",st->bodylen);
582 } else if (strncmp(st
->linebuf
,"Authorization: Basic",20) == 0) {
583 char passwd_buf
[BUFSIZE
];
584 char *passwd_buf_shift
;
585 int len
=strlen(st
->linebuf
);
587 while (st
->linebuf
[k
] == ' ') k
++;
588 while (st
->linebuf
[len
-1] == '\n' ||
589 st
->linebuf
[len
-1] == '\r' ||
590 st
->linebuf
[len
-1] == ' ') {
595 decode64((st
->linebuf
+ k
), passwd_buf
, strlen(st
->linebuf
+ k
));
596 passwd_buf_shift
= (char *)(strchr(passwd_buf
, ':') + 1);
597 if (sha1passwdok(passwd_buf_shift
))
598 st
->status
=WEB_AUTHORIZED
;
600 } else if (st
->linebuf
[0]=='\n' || st
->linebuf
[0]=='\r') {
601 switch (st
->status
) {
603 lwip_write(fd
,authmsg
,sizeof(authmsg
));
604 lwip_write(fd
,prompt
,strlen(prompt
));
605 lwip_write(fd
,authmsg2
,sizeof(authmsg2
));
610 if (strcmp(st
->path
,"/index.html") == 0)
612 if (st
->op
== WEB_OP_GET
) {
613 web_create_page(&(st
->path
[1]),fd
,vdefd
,NULL
);
616 st
->op
=WEB_OP_POSTDATA
;
626 void webdata(int fn
,int fd
,int vdefd
)
630 struct webstat
*st
=status
[fn
];
631 n
=lwip_read(fd
,buf
,BUFSIZE
);
636 printlog(LOG_ERR
,"web read err: %s",strerror(errno
));
638 for (i
=0;i
<n
&& st
->bufindex
<BUFSIZE
;i
++) {
639 st
->linebuf
[(st
->bufindex
)++]=buf
[i
];
640 if (buf
[i
]=='\n' || (st
->op
==WEB_OP_POSTDATA
&& st
->bufindex
==st
->bodylen
)) {
641 st
->linebuf
[(st
->bufindex
)]=0;
642 if (web_core(fn
,fd
,vdefd
)) {
652 void webaccept(int fn
,int fd
,int vdefd
)
654 struct sockaddr_in cli_addr
;
660 clilen
= sizeof(cli_addr
);
661 newsockfd
= lwip_accept(fd
, (struct sockaddr
*) &cli_addr
, &clilen
);
664 printlog(LOG_ERR
,"web accept err: %s",strerror(errno
));
667 newfn
=addpfd(newsockfd
,webdata
);
668 status
[newfn
]=st
=malloc(sizeof(struct webstat
));
669 st
->status
=WEB_IDENTIFY
;
674 void web_init(int vdefd
)
677 struct sockaddr_in serv_addr
;
678 sockfd
=lwip_socket(AF_INET
, SOCK_STREAM
, 0);
681 printlog(LOG_ERR
,"web socket err: %s",strerror(errno
));
684 bzero((char *) &serv_addr
, sizeof(serv_addr
));
685 serv_addr
.sin_family
= AF_INET
;
686 serv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
687 serv_addr
.sin_port
= htons(WEB_TCP_PORT
);
689 if (lwip_bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) < 0) {
690 printlog(LOG_ERR
,"web bind err: %s",strerror(errno
));
693 lwip_listen(sockfd
, 5);
695 //createbase64passwd();
696 menuhead
=vde_gethelp(vdefd
);
697 addpfd(sockfd
,webaccept
);