├── Makefile ├── README ├── README.md ├── cert.pem ├── cgi-bin ├── Makefile ├── getAuth.c └── postAuth.c ├── config.ini ├── daemon_init.c ├── doc ├── back.c ├── config.ini ├── dir.png ├── dir │ ├── DirAuth.html │ ├── DirGet.html │ ├── back │ │ ├── cert.csr │ │ ├── cert.pem │ │ ├── key.pem │ │ ├── privkey.pem │ │ └── shadow │ ├── back_main.c │ ├── file.png │ └── main.c ├── fifo.png ├── file.png ├── getAuth.html ├── home.html ├── img.gif ├── img_switch_01.png ├── img_switch_02.png ├── img_switch_03.png ├── img_switch_04.png ├── img_switch_bg.png ├── link.png ├── postAuth.html └── socket.png ├── info.txt ├── log.c ├── main.c ├── parse.h ├── parse_config.c ├── parse_option.c ├── pid.file ├── secure_access.c ├── webd ├── webserver.sh ├── wrap.c └── wrap.h /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | #CFLAGS = -O2 -Wall -I . 3 | CFLAGS = -g -I . 4 | 5 | #If you support https,then LIB=-DHTTPS -lpthread -lssl -lcrypto 6 | #else LIB=-lpthread 7 | LIB = -DHTTPS -lpthread -lssl -lcrypto 8 | #LIB = -lpthread 9 | 10 | all: webd 11 | 12 | webd: main.c wrap.o parse_config.o daemon_init.o parse_option.o log.o secure_access.o cgi 13 | $(CC) $(CFLAGS) -o $@ main.c wrap.o parse_config.o daemon_init.o parse_option.o log.o secure_access.o $(LIB) 14 | 15 | wrap.o: wrap.c 16 | $(CC) $(CFLAGS) -c wrap.c 17 | 18 | parse_config.o: parse_config.c parse.h 19 | $(CC) $(CFLAGS) -c parse_config.c 20 | 21 | daemon_init.o: daemon_init.c parse.h 22 | $(CC) $(CFLAGS) -c daemon_init.c 23 | 24 | parse_option.o: parse_option.c parse.h 25 | $(CC) $(CFLAGS) -c parse_option.c $(LIB) 26 | 27 | log.o: log.c parse.h 28 | $(CC) $(CFLAGS) -c log.c 29 | 30 | secure_access.o: secure_access.c parse.h 31 | $(CC) $(CFLAGS) -c secure_access.c 32 | 33 | cgi: 34 | (cd cgi-bin; make) 35 | 36 | clean: 37 | rm -f *.o main access.log *~ 38 | (cd cgi-bin; make clean) 39 | 40 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Webd uses the GET/POST method to serve static content 2 | (text, HTML, GIF, and JPG ....files) out of ./ and to serve dynamic 3 | content by running CGI programs out of ./cgi-bin. 4 | 5 | webd provides following functions: 6 | 1.provide GET/POST method to view static content and run cgi script 7 | 2.provide HTTP and HTTPS connection 8 | 3.provide dircetory view function 9 | 4.provide some access control based by ip address 10 | 5.provide easy logging function 11 | 12 | To run Webd: 13 | Run "webd" on the server machine, 14 | e.g., "webd" 15 | Maybe you should type "./webd" if current directory is not in your $PATH 16 | 17 | There are several argument option: 18 | -d --daemon -> webd run in the background 19 | -p --port -> assigned http port 20 | -s --sslport -> assigned https port 21 | -l --log -> assigned log path 22 | -e --extent -> provide https function 23 | -h --help -> help 24 | -v --version -> some other informations 25 | 26 | 27 | So,you can also do this: 28 | webd -d -p 8888 -s 4444 -e 29 | 30 | If your port is less then 1024,you must have the root permission,or use the sudo command. 31 | 32 | 33 | Point your browser at webd: for example,http port is 8888,and https port is 4444 34 | you can view following page: 35 | http: 36 | 127.0.0.1:8000 home page 37 | 38 | 127.0.0.1:8000/dir view dir 39 | -> you can point the file name to view file contents 40 | or point the directory name to view the directory content 41 | 42 | 127.0.0.1:8888/getAuth.html 43 | -> a GET method page,login with email and password, 44 | you will see you email and password content 45 | 46 | 127.0.0.1:8888/postAuth.html 47 | -> a POST method page,login with email and password, 48 | you will see you email and password content 49 | 50 | https: the same function as to http,just uri has a litter changes 51 | https://127.0.0.1:4444 52 | https://127.0.0.1:4444/dir 53 | https://127.0.0.1:4444/getAuth.html 54 | https://127.0.0.1:4444/postAuth.html 55 | 56 | Files: 57 | cert.pem -> the https CA,use openssl to create, 58 | so you must accept the CA to continue 59 | cgi-bin -> cgi script directory 60 | getAuth.c -> the get method cgi script 61 | postAuth.c -> the post method cgi script 62 | Makefile -> cgi/bin/*.c Makefile 63 | config.ini -> configuration file 64 | daemon_init.c -> daemon process 65 | doc -> the web page root directory 66 | log.c -> provide logging 67 | main.c -> the main source file 68 | Makefile -> *.c Makefile 69 | parse_config.c -> read the config.ini 70 | parse.h -> the main head file 71 | parse_option.c -> parse the argv 72 | README -> it's me 73 | secure_access.c -> provide easy access control 74 | webserver.sh -> a shell script,to provide start/stop/restart/status the webd 75 | e.g. webserver.sh start/stop/restart/status 76 | wrap.c -> must functions wrap file 77 | wrap.h -> the wrap.c's head file 78 | 79 | Bugs: 80 | If openssl lib library isn't accessible in your computer,you should change the 81 | Makefile.For datail,you could see Makefile. 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Linux-C-Web-Server 2 | ================== 3 | 4 | Linux下的小型Web服务器,支持GET/POST/SSL等功能. 5 | ------ 6 | 这个主要是在CSAPP基础上做的,添加了POST,SSL,目录显示等功能。 7 | ### 8 | 实现功能: 9 | ### 10 | 1. 支持GET/POST方法 11 | 2. 支持SSL安全连接即HTTPS 12 | 3. 支持CGI 13 | 4. 基于IP地址和掩码的认证 14 | 5. 目录显示 15 | 6. 日志功能 16 | 7. 错误提示页面 17 | 18 | 博客地址:http://blog.csdn.net/yueguanghaidao/article/details/8450938/ 19 | ### 20 | -------------------------------------------------------------------------------- /cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQDgtpALf512661nz40CA9IMgXItnbfcGBkheK3ivKIvbdQ9gzs+ 3 | hnghBkhIKMGxDvXzkBb5rIZoouIXQH6rbz6JyFBxhHi5diS8x6t1OomYNp5Sco0d 4 | 6s9yfSAmkLNRNvlqg5aLXlif9ptQg6pHM1/vVqinTuy/KuPaus9v53p7VwIDAQAB 5 | AoGARJKRbGDaDXMn7Hjin83IqHZMAG2TsL9N0+/+qCVGHNEYJllIl/Dy8aj4H8UI 6 | Ll7RYS0ERdaHAaFK+yt8PBZrb4/hmPcXxZbA+ibCiU0SxyrOS9e4eQahCJL28Gp7 7 | z6Wk1JH0MLckQm22oeZ/pqzkhgV4FREDM/PEsl5axrWAvjECQQDzjFYMpSpK15e7 8 | fJFiPeZUTfheINNzISnNeBivlLx6EY57wSiGa1imJ5lJZlFko9/tU48kcdzqkLIJ 9 | fHgk8BZZAkEA7DO0isZT1Nnz9eNxOF0MqKDVgNprBKqRs3boXjrhrT6Re4DRBvGm 10 | KtfLy+q5hbriNmW3L+QoHhZuU9bTjl9JLwJAY1KdGSUWfVU1DQH9LGqAD2uI2aJb 11 | eX1R1fifYKOwxbt5NyEMDN2kVoaZreRrVza5sMi9/Kfu5z5BTTsUqEO9aQJBAOPx 12 | 6hPa3eAWDjeHrSXltmet/x0ArDKuoTl+UTVOwae9MAzt/csjvWavJr+94BhMiC5S 13 | 7vxKxOR0ZTiHo1ZMYoUCQCzAX1AZsT0yRWb9RVY5r3lw47syeEBryPrRVvRvbSy7 14 | FoqUCC9Gi9TB1OHLyVn3vcd7+CoKxX6QqauhtU/PG0Y= 15 | -----END RSA PRIVATE KEY----- 16 | -----BEGIN CERTIFICATE----- 17 | MIIC0TCCAjoCCQCd7jWupY/ZPDANBgkqhkiG9w0BAQUFADCBrDELMAkGA1UEBhMC 18 | eWwxEDAOBgNVBAgMB2ppYW5nc3UxEDAOBgNVBAcMB25hbmppbmcxJTAjBgNVBAoM 19 | HGNvbXB1dGVyIGNvbW11bmljYXRpb24gb2YgbmcxHjAcBgNVBAsMFWNvbXB1dGVy 20 | IGNtbXVuaWNhdGlvbjEQMA4GA1UEAwwHeWloYWlibzEgMB4GCSqGSIb3DQEJARYR 21 | eWloYWlib2JiQDE2My5jb20wHhcNMTIxMjA1MDg0NjMzWhcNMTMxMjA1MDg0NjMz 22 | WjCBrDELMAkGA1UEBhMCeWwxEDAOBgNVBAgMB2ppYW5nc3UxEDAOBgNVBAcMB25h 23 | bmppbmcxJTAjBgNVBAoMHGNvbXB1dGVyIGNvbW11bmljYXRpb24gb2YgbmcxHjAc 24 | BgNVBAsMFWNvbXB1dGVyIGNtbXVuaWNhdGlvbjEQMA4GA1UEAwwHeWloYWlibzEg 25 | MB4GCSqGSIb3DQEJARYReWloYWlib2JiQDE2My5jb20wgZ8wDQYJKoZIhvcNAQEB 26 | BQADgY0AMIGJAoGBAOC2kAt/nXbrrWfPjQID0gyBci2dt9wYGSF4reK8oi9t1D2D 27 | Oz6GeCEGSEgowbEO9fOQFvmshmii4hdAfqtvPonIUHGEeLl2JLzHq3U6iZg2nlJy 28 | jR3qz3J9ICaQs1E2+WqDloteWJ/2m1CDqkczX+9WqKdO7L8q49q6z2/nentXAgMB 29 | AAEwDQYJKoZIhvcNAQEFBQADgYEAQnlRL1pLK6nPyvpVvBoqlXVrmutxHLVUWfyT 30 | d7FvFk3RgV7IgYh3bEsB8Wc/dzzwc5wW+HMCbkTjtcf1wkRhbIxeiXl3OrmlZkZ8 31 | aquROQ9Ac1K9D61DsAM2k69cQBRKkCdxf8pHYHo/vtdrfA/6JVr89yX8WZKzI+rt 32 | tTIQ+zM= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /cgi-bin/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -Wall -I .. 3 | 4 | all: getAuth postAuth 5 | 6 | getAuth: getAuth.c 7 | $(CC) $(CFLAGS) -o getAuth getAuth.c 8 | 9 | postAuth: postAuth.c 10 | $(CC) $(CFLAGS) -o postAuth postAuth.c 11 | 12 | clean: 13 | rm -f getAuth postAuth *~ 14 | -------------------------------------------------------------------------------- /cgi-bin/getAuth.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | #include "parse.h" 3 | 4 | int main(void) { 5 | char *buf, *p; 6 | char name[MAXLINE], passwd[MAXLINE],content[MAXLINE]; 7 | 8 | /* Extract the two arguments */ 9 | if ((buf = getenv("QUERY_STRING")) != NULL) { 10 | p = strchr(buf, '&'); 11 | *p = '\0'; 12 | strcpy(name, buf); 13 | strcpy(passwd, p+1); 14 | } 15 | 16 | 17 | /* Make the response body */ 18 | sprintf(content, "Welcome to auth.com:%s and %s\r\n

",name,passwd); 19 | sprintf(content, "%s\r\n", content); 20 | 21 | sprintf(content, "%sThanks for visiting!\r\n", content); 22 | 23 | /* Generate the HTTP response */ 24 | printf("Content-length: %d\r\n", strlen(content)); 25 | printf("Content-type: text/html\r\n\r\n"); 26 | printf("%s", content); 27 | fflush(stdout); 28 | exit(0); 29 | } 30 | -------------------------------------------------------------------------------- /cgi-bin/postAuth.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | #include "parse.h" 3 | 4 | int main(void) { 5 | char *buf,*p; 6 | int length=0; 7 | char content[MAXLINE],data[MAXLINE]; 8 | 9 | 10 | if ((buf = getenv("CONTENT-LENGTH")) != NULL) 11 | { 12 | length=atol(buf); 13 | } 14 | 15 | p=fgets(data,length+1,stdin); 16 | if(p==NULL) 17 | sprintf(content, "Something is wrong\r\n"); 18 | else 19 | sprintf(content, "Info:%s\r\n",data); 20 | 21 | printf("Content-length: %d\r\n", strlen(content)); 22 | printf("Content-type: text/html\r\n\r\n"); 23 | printf("%s", content); 24 | fflush(stdout); 25 | exit(0); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | #config.ini 2 | 3 | #the web is daemon or not 4 | daemon = yes 5 | 6 | #port set 7 | http=8000 8 | https=4444 9 | 10 | #default certifile 11 | ca= cert.pem 12 | 13 | #show dir or not 14 | dir= yes 15 | 16 | #dossl or not 17 | dossl=yes 18 | 19 | #the web root position 20 | root =doc 21 | 22 | #log position 23 | log = access.log 24 | 25 | #access ip mask 26 | mask =0.0.0.0/0.0.0.0 27 | 28 | #cgi-bin dir location 29 | cgi =cgi-bin 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /daemon_init.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | 3 | void init_daemon(void) 4 | { 5 | int i; 6 | pid_t pid; 7 | struct sigaction sa; 8 | umask(0); 9 | if(pid=fork()) 10 | exit(0); 11 | else if(pid<0) 12 | exit(1); 13 | setsid(); 14 | 15 | sa.sa_handler=SIG_IGN; 16 | sigemptyset(&sa.sa_mask); 17 | sa.sa_flags=0; 18 | sigaction(SIGHUP,&sa,NULL); 19 | 20 | 21 | if(pid=fork()) 22 | exit(0); 23 | else if(pid<0) 24 | exit(1); 25 | 26 | for(i=0;i0) 80 | { 81 | close(connfd); 82 | continue; 83 | } 84 | else if(pid==0) 85 | { 86 | ishttps=1; 87 | doit(connfd); 88 | } 89 | } 90 | } 91 | 92 | /* $end https */ 93 | 94 | while (1) 95 | { 96 | clientlen = sizeof(clientaddr); 97 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 98 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 99 | { 100 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 101 | continue; 102 | } 103 | 104 | if((pid=Fork())>0) 105 | { 106 | close(connfd); 107 | continue; 108 | } 109 | else if(pid==0) 110 | { 111 | doit(connfd); 112 | } 113 | 114 | } 115 | } 116 | /* $end main */ 117 | 118 | /* $begin ssl init */ 119 | void ssl_init(void) 120 | { 121 | static char crypto[]="RC4-MD5"; 122 | certfile= DEFAULT_CERTFILE; 123 | 124 | SSL_load_error_strings(); 125 | SSLeay_add_ssl_algorithms(); 126 | ssl_ctx = SSL_CTX_new( SSLv23_server_method() ); 127 | 128 | if ( certfile[0] != '\0' ) 129 | if ( SSL_CTX_use_certificate_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_use_PrivateKey_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_check_private_key( ssl_ctx ) == 0 ) 130 | { 131 | ERR_print_errors_fp( stderr ); 132 | exit( 1 ); 133 | } 134 | if ( crypto != (char*) 0 ) 135 | { 136 | 137 | if ( SSL_CTX_set_cipher_list( ssl_ctx, crypto ) == 0 ) 138 | { 139 | ERR_print_errors_fp( stderr ); 140 | exit( 1 ); 141 | } 142 | } 143 | 144 | } 145 | /* $end ssl init */ 146 | 147 | 148 | /* 149 | * doit - handle one HTTP request/response transaction 150 | */ 151 | /* $begin doit */ 152 | void doit(int fd) 153 | { 154 | int is_static,contentLength=0,isGet=1; 155 | struct stat sbuf; 156 | char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; 157 | char filename[MAXLINE], cgiargs[MAXLINE],httpspostdata[MAXLINE]; 158 | rio_t rio; 159 | 160 | memset(buf,0,MAXLINE); 161 | if(ishttps) 162 | { 163 | ssl=SSL_new(ssl_ctx); 164 | SSL_set_fd(ssl,fd); 165 | if(SSL_accept(ssl)==0) 166 | { 167 | ERR_print_errors_fp(stderr); 168 | exit(1); 169 | } 170 | SSL_read(ssl,buf,sizeof(buf)); 171 | printf(".............\n"); 172 | printf("%s",buf); 173 | printf(".............\n"); 174 | } 175 | else 176 | { 177 | /* Read request line and headers */ 178 | Rio_readinitb(&rio, fd); 179 | Rio_readlineb(&rio, buf, MAXLINE); 180 | } 181 | 182 | sscanf(buf, "%s %s %s", method, uri, version); 183 | 184 | /* 185 | if (strcasecmp(method, "GET")!=0&&strcasecmp(method,"POST")!=0) 186 | { 187 | clienterror(fd, method, "501", "Not Implemented", 188 | "Tiny does not implement this method"); 189 | return; 190 | } 191 | */ 192 | 193 | 194 | /* Parse URI from GET request */ 195 | is_static = parse_uri(uri, filename, cgiargs); 196 | 197 | 198 | if (lstat(filename, &sbuf) < 0) 199 | { 200 | clienterror(fd, filename, "404", "Not found", 201 | "Tiny couldn't find this file"); 202 | return; 203 | } 204 | 205 | if(S_ISDIR(sbuf.st_mode)&&isShowdir) 206 | serve_dir(fd,filename); 207 | 208 | 209 | if (strcasecmp(method, "POST")==0) 210 | isGet=0; 211 | 212 | 213 | if (is_static) 214 | { /* Serve static content */ 215 | if(!ishttps) 216 | get_requesthdrs(&rio); /* because https already read the headers -> SSL_read() */ 217 | 218 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) 219 | { 220 | clienterror(fd, filename, "403", "Forbidden", 221 | "Tiny couldn't read the file"); 222 | return; 223 | } 224 | serve_static(fd, filename, sbuf.st_size); 225 | } 226 | else 227 | { /* Serve dynamic content */ 228 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) 229 | { 230 | clienterror(fd, filename, "403", "Forbidden", 231 | "Tiny couldn't run the CGI program"); 232 | return; 233 | } 234 | 235 | if(isGet) 236 | { 237 | if(!ishttps) 238 | get_requesthdrs(&rio); /* because https already read headers by SSL_read() */ 239 | 240 | get_dynamic(fd, filename, cgiargs); 241 | } 242 | else 243 | { 244 | printf("ishttps:%d\n",ishttps); 245 | if(ishttps) 246 | https_getlength(buf,&contentLength); 247 | else 248 | post_requesthdrs(&rio,&contentLength); 249 | 250 | post_dynamic(fd, filename,contentLength,&rio); 251 | } 252 | } 253 | } 254 | /* $end doit */ 255 | 256 | /* $begin https_getlength */ 257 | void https_getlength(char* buf,int* length) 258 | { 259 | char *p,line[MAXLINE]; 260 | char *tmpbuf=buf; 261 | int i=1; 262 | printf("NNNNN"); 263 | printf("^^^%s^^^",buf); 264 | printf("NNNNN"); 265 | fflush(stdout); 266 | 267 | while(*tmpbuf!='\0') 268 | { 269 | p=line; 270 | while(*tmpbuf!='\n'||*tmpbuf!='\0') 271 | *p++=*tmpbuf++; 272 | *p='\0'; 273 | printf("**%s**",line); 274 | fflush(stdout); 275 | if(strncasecmp(line,"Content-Length:",15)==0) 276 | { 277 | p=&line[15]; 278 | p+=strspn(p," \t"); 279 | *length=atoi(p); 280 | } 281 | 282 | ++tmpbuf; 283 | } 284 | printf("#####%d##########\n",*length); 285 | return; 286 | } 287 | 288 | /* $end https_getlength */ 289 | 290 | /* 291 | * read_requesthdrs - read and parse HTTP request headers 292 | */ 293 | /* $begin get_requesthdrs */ 294 | void get_requesthdrs(rio_t *rp) 295 | { 296 | char buf[MAXLINE]; 297 | 298 | Rio_readlineb(rp, buf, MAXLINE); 299 | writetime(); /* write access time in log file */ 300 | printf("%s", buf); 301 | while(strcmp(buf, "\r\n")) 302 | { 303 | Rio_readlineb(rp, buf, MAXLINE); 304 | writelog(buf); 305 | printf("%s", buf); 306 | } 307 | return; 308 | } 309 | /* $end get_requesthdrs */ 310 | 311 | /* $begin post_requesthdrs */ 312 | void post_requesthdrs(rio_t *rp,int *length) 313 | { 314 | char buf[MAXLINE]; 315 | char *p; 316 | 317 | Rio_readlineb(rp, buf, MAXLINE); 318 | writetime(); /* write access time in log file */ 319 | while(strcmp(buf, "\r\n")) 320 | { 321 | Rio_readlineb(rp, buf, MAXLINE); 322 | if(strncasecmp(buf,"Content-Length:",15)==0) 323 | { 324 | p=&buf[15]; 325 | p+=strspn(p," \t"); 326 | *length=atol(p); 327 | } 328 | writelog(buf); 329 | printf("%s", buf); 330 | } 331 | return; 332 | } 333 | /* $end post_requesthdrs */ 334 | 335 | 336 | /* $begin post_dynamic */ 337 | void serve_dir(int fd,char *filename) 338 | { 339 | DIR *dp; 340 | struct dirent *dirp; 341 | struct stat sbuf; 342 | struct passwd *filepasswd; 343 | int num=1; 344 | char files[MAXLINE],buf[MAXLINE],name[MAXLINE],img[MAXLINE],modifyTime[MAXLINE],dir[MAXLINE]; 345 | char *p; 346 | 347 | /* 348 | * Start get the dir 349 | * for example: /home/yihaibo/kerner/web/doc/dir -> dir[]="dir/"; 350 | */ 351 | p=strrchr(filename,'/'); 352 | ++p; 353 | strcpy(dir,p); 354 | strcat(dir,"/"); 355 | /* End get the dir */ 356 | 357 | if((dp=opendir(filename))==NULL) 358 | syslog(LOG_ERR,"cannot open dir:%s",filename); 359 | 360 | sprintf(files, "Dir Browser"); 361 | sprintf(files,"%s",files); 362 | sprintf(files, "%s\r\n", files); 363 | 364 | while((dirp=readdir(dp))!=NULL) 365 | { 366 | if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0) 367 | continue; 368 | sprintf(name,"%s/%s",filename,dirp->d_name); 369 | lstat(name,&sbuf); 370 | filepasswd=getpwuid(sbuf.st_uid); 371 | 372 | if(S_ISDIR(sbuf.st_mode)) 373 | { 374 | sprintf(img,""); 375 | } 376 | else if(S_ISFIFO(sbuf.st_mode)) 377 | { 378 | sprintf(img,""); 379 | } 380 | else if(S_ISLNK(sbuf.st_mode)) 381 | { 382 | sprintf(img,""); 383 | } 384 | else if(S_ISSOCK(sbuf.st_mode)) 385 | { 386 | sprintf(img,""); 387 | } 388 | else 389 | sprintf(img,""); 390 | 391 | 392 | sprintf(files,"%s

%-2d %s ""%-15s%-10s%10d %24s

\r\n",files,num++,img,dir,dirp->d_name,dirp->d_name,filepasswd->pw_name,(int)sbuf.st_size,timeModify(sbuf.st_mtime,modifyTime)); 393 | } 394 | closedir(dp); 395 | sprintf(files,"%s",files); 396 | 397 | /* Send response headers to client */ 398 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 399 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 400 | sprintf(buf, "%sContent-length: %d\r\n", buf, strlen(files)); 401 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, "text/html"); 402 | 403 | if(ishttps) 404 | { 405 | SSL_write(ssl,buf,strlen(buf)); 406 | SSL_write(ssl,files,strlen(files)); 407 | } 408 | else 409 | { 410 | Rio_writen(fd, buf, strlen(buf)); 411 | Rio_writen(fd, files, strlen(files)); 412 | } 413 | exit(0); 414 | 415 | } 416 | /* $end serve_dir */ 417 | 418 | 419 | /* $begin post_dynamic */ 420 | void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp) 421 | { 422 | char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE]; 423 | int p[2]; 424 | 425 | sprintf(length,"%d",contentLength); 426 | 427 | if(pipe(p)==-1) 428 | syslog(LOG_ERR,"cannot create pipe"); 429 | 430 | /* The post data is sended by client,we need to redirct the data to cgi stdin. 431 | * so, child read contentLength bytes data from fp,and write to p[1]; 432 | * parent should redirct p[0] to stdin. As a result, the cgi script can 433 | * read the post data from the stdin. 434 | */ 435 | if(!ishttps) /* https already read all data ,include post data by SSL_read() */ 436 | { 437 | if (Fork() == 0) 438 | { /* child */ 439 | close(p[0]); 440 | Rio_readnb(rp,data,contentLength); 441 | Rio_writen(p[1],data,contentLength); 442 | exit(0) ; 443 | } 444 | } 445 | else 446 | { 447 | } 448 | 449 | 450 | /* Send response headers to client */ 451 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 452 | Rio_writen(fd, buf, strlen(buf)); 453 | sprintf(buf, "Server: Tiny Web Server\r\n"); 454 | Rio_writen(fd, buf, strlen(buf)); 455 | 456 | Dup2(p[0],STDIN_FILENO); /* Redirct p[0] to stdin */ 457 | close(p[0]); 458 | 459 | close(p[1]); 460 | setenv("CONTENT-LENGTH",length , 1); 461 | Dup2(fd,STDOUT_FILENO); /* Redirct stdout to client */ 462 | Execve(filename, emptylist, environ); 463 | } 464 | /* $end post_dynamic */ 465 | 466 | 467 | 468 | 469 | 470 | /* 471 | * parse_uri - parse URI into filename and CGI args 472 | * return 0 if dynamic content, 1 if static 473 | */ 474 | /* $begin parse_uri */ 475 | int parse_uri(char *uri, char *filename, char *cgiargs) 476 | { 477 | char *ptr; 478 | char tmpcwd[MAXLINE]; 479 | strcpy(tmpcwd,cwd); 480 | strcat(tmpcwd,"/"); 481 | 482 | if (!strstr(uri, "cgi-bin")) 483 | { /* Static content */ 484 | strcpy(cgiargs, ""); 485 | strcpy(filename, strcat(tmpcwd,getconfig("root"))); 486 | strcat(filename, uri); 487 | if (uri[strlen(uri)-1] == '/') 488 | strcat(filename, "home.html"); 489 | return 1; 490 | } 491 | else 492 | { /* Dynamic content */ 493 | ptr = index(uri, '?'); 494 | if (ptr) 495 | { 496 | strcpy(cgiargs, ptr+1); 497 | *ptr = '\0'; 498 | } 499 | else 500 | strcpy(cgiargs, ""); 501 | strcpy(filename, cwd); 502 | strcat(filename, uri); 503 | return 0; 504 | } 505 | } 506 | /* $end parse_uri */ 507 | 508 | /* 509 | * serve_static - copy a file back to the client 510 | */ 511 | /* $begin serve_static */ 512 | void serve_static(int fd, char *filename, int filesize) 513 | { 514 | int srcfd; 515 | char *srcp, filetype[MAXLINE], buf[MAXBUF]; 516 | 517 | /* Send response headers to client */ 518 | get_filetype(filename, filetype); 519 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 520 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 521 | sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); 522 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); 523 | 524 | /* Send response body to client */ 525 | srcfd = Open(filename, O_RDONLY, 0); 526 | srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 527 | Close(srcfd); 528 | 529 | if(ishttps) 530 | { 531 | SSL_write(ssl, buf, strlen(buf)); 532 | SSL_write(ssl, srcp, filesize); 533 | } 534 | else 535 | { 536 | Rio_writen(fd, buf, strlen(buf)); 537 | Rio_writen(fd, srcp, filesize); 538 | } 539 | Munmap(srcp, filesize); 540 | } 541 | 542 | /* 543 | * get_filetype - derive file type from file name 544 | */ 545 | void get_filetype(char *filename, char *filetype) 546 | { 547 | if (strstr(filename, ".html")) 548 | strcpy(filetype, "text/html"); 549 | else if (strstr(filename, ".gif")) 550 | strcpy(filetype, "image/gif"); 551 | else if (strstr(filename, ".jpg")) 552 | strcpy(filetype, "image/jpeg"); 553 | else if (strstr(filename, ".png")) 554 | strcpy(filetype, "image/png"); 555 | else 556 | strcpy(filetype, "text/plain"); 557 | } 558 | /* $end serve_static */ 559 | 560 | /* 561 | * serve_dynamic - run a CGI program on behalf of the client 562 | */ 563 | /* $begin get_dynamic */ 564 | void get_dynamic(int fd, char *filename, char *cgiargs) 565 | { 566 | char buf[MAXLINE], *emptylist[] = { NULL },httpsbuf[MAXLINE]; 567 | int p[2]; 568 | 569 | /* Return first part of HTTP response */ 570 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 571 | sprintf(buf, "%sServer: Tiny Web Server\r\n",buf); 572 | 573 | if(ishttps) 574 | SSL_write(ssl,buf,strlen(buf)); 575 | 576 | else 577 | Rio_writen(fd, buf, strlen(buf)); 578 | 579 | if(ishttps) 580 | { 581 | if(pipe(p)==-1) 582 | syslog(LOG_ERR,"cannot create pipe"); 583 | 584 | if (Fork() == 0) 585 | { /* child */ 586 | close(p[0]); 587 | setenv("QUERY_STRING", cgiargs, 1); 588 | Dup2(p[1], STDOUT_FILENO); /* Redirect stdout to p[1] */ 589 | Execve(filename, emptylist, environ); /* Run CGI program */ 590 | } 591 | close(p[1]); 592 | Read(p[0],httpsbuf,MAXLINE); /* parent read from p[0] */ 593 | SSL_write(ssl,httpsbuf,strlen(httpsbuf)); 594 | Wait(NULL); /* Parent waits for and reaps child */ 595 | } 596 | else 597 | { 598 | if (Fork() == 0) 599 | { /* child */ 600 | /* Real server would set all CGI vars here */ 601 | setenv("QUERY_STRING", cgiargs, 1); 602 | Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ 603 | Execve(filename, emptylist, environ); /* Run CGI program */ 604 | } 605 | Wait(NULL); /* Parent waits for and reaps child */ 606 | } 607 | } 608 | /* $end get_dynamic */ 609 | 610 | /* 611 | * clienterror - returns an error message to the client 612 | */ 613 | /* $begin clienterror */ 614 | void clienterror(int fd, char *cause, char *errnum, 615 | char *shortmsg, char *longmsg) 616 | { 617 | char buf[MAXLINE], body[MAXBUF]; 618 | 619 | /* Build the HTTP response body */ 620 | sprintf(body, "Tiny Error"); 621 | sprintf(body, "%s\r\n", body); 622 | sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); 623 | sprintf(body, "%s

%s: %s\r\n", body, longmsg, cause); 624 | sprintf(body, "%s


The Tiny Web server\r\n", body); 625 | 626 | /* Print the HTTP response */ 627 | sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); 628 | sprintf(buf, "%sContent-type: text/html\r\n",buf); 629 | sprintf(buf, "%sContent-length: %d\r\n\r\n",buf,(int)strlen(body)); 630 | 631 | printf("...................\n"); 632 | printf("%s\n",buf); 633 | printf("%s\n",body); 634 | printf("...................\n"); 635 | 636 | if(ishttps) 637 | { 638 | SSL_write(ssl,buf,strlen(buf)); 639 | SSL_write(ssl,body,strlen(body)); 640 | } 641 | else 642 | { 643 | Rio_writen(fd, buf, strlen(buf)); 644 | Rio_writen(fd, body, strlen(body)); 645 | } 646 | } 647 | /* $end clienterror */ 648 | -------------------------------------------------------------------------------- /doc/config.ini: -------------------------------------------------------------------------------- 1 | #config.ini 2 | 3 | #the web is daemon or not 4 | daemon = no 5 | 6 | port=8000 7 | 8 | #show dir or not 9 | dir= yes 10 | 11 | #the web root position 12 | root =doc 13 | 14 | #log position 15 | log = access.log 16 | 17 | #access ip mask 18 | mask =0.0.0.0/0.0.0.0 19 | 20 | #cgi-bin 21 | cgi =cgi-bin 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /doc/dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/dir.png -------------------------------------------------------------------------------- /doc/dir/DirAuth.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

NAME:

4 |

PASSWD:

5 | 6 |
7 | 8 | -------------------------------------------------------------------------------- /doc/dir/DirGet.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | NAME: 4 | PASSWD: 5 | 6 |
7 | 8 | -------------------------------------------------------------------------------- /doc/dir/back/cert.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICFzCCAYACAQAwgawxCzAJBgNVBAYTAnlsMRAwDgYDVQQIDAdqaWFuZ3N1MRAw 3 | DgYDVQQHDAduYW5qaW5nMSUwIwYDVQQKDBxjb21wdXRlciBjb21tdW5pY2F0aW9u 4 | IG9mIG5nMR4wHAYDVQQLDBVjb21wdXRlciBjbW11bmljYXRpb24xEDAOBgNVBAMM 5 | B3lpaGFpYm8xIDAeBgkqhkiG9w0BCQEWEXlpaGFpYm9iYkAxNjMuY29tMIGfMA0G 6 | CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtpALf512661nz40CA9IMgXItnbfcGBkh 7 | eK3ivKIvbdQ9gzs+hnghBkhIKMGxDvXzkBb5rIZoouIXQH6rbz6JyFBxhHi5diS8 8 | x6t1OomYNp5Sco0d6s9yfSAmkLNRNvlqg5aLXlif9ptQg6pHM1/vVqinTuy/KuPa 9 | us9v53p7VwIDAQABoCowEQYJKoZIhvcNAQkCMQQMAnlsMBUGCSqGSIb3DQEJBzEI 10 | DAZsd3l5aGIwDQYJKoZIhvcNAQEFBQADgYEAJvzDGC8bt4itZQH/fvvl2Oq4i0l4 11 | o1sSaGRaNVAW4HX/DYVOEQz8hLZKrQHemCo2qOMh7BLlEW+YVnkydWYJfGa+3zW1 12 | RYjJ2gCRAiRT0eA3KRcP8vpj+JlBtnzuencxkkgJrjefb3B+q5XNwPzmhXZNPRWz 13 | bEPvb2LsbvwKjbI= 14 | -----END CERTIFICATE REQUEST----- 15 | -------------------------------------------------------------------------------- /doc/dir/back/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC0TCCAjoCCQCd7jWupY/ZPDANBgkqhkiG9w0BAQUFADCBrDELMAkGA1UEBhMC 3 | eWwxEDAOBgNVBAgMB2ppYW5nc3UxEDAOBgNVBAcMB25hbmppbmcxJTAjBgNVBAoM 4 | HGNvbXB1dGVyIGNvbW11bmljYXRpb24gb2YgbmcxHjAcBgNVBAsMFWNvbXB1dGVy 5 | IGNtbXVuaWNhdGlvbjEQMA4GA1UEAwwHeWloYWlibzEgMB4GCSqGSIb3DQEJARYR 6 | eWloYWlib2JiQDE2My5jb20wHhcNMTIxMjA1MDg0NjMzWhcNMTMxMjA1MDg0NjMz 7 | WjCBrDELMAkGA1UEBhMCeWwxEDAOBgNVBAgMB2ppYW5nc3UxEDAOBgNVBAcMB25h 8 | bmppbmcxJTAjBgNVBAoMHGNvbXB1dGVyIGNvbW11bmljYXRpb24gb2YgbmcxHjAc 9 | BgNVBAsMFWNvbXB1dGVyIGNtbXVuaWNhdGlvbjEQMA4GA1UEAwwHeWloYWlibzEg 10 | MB4GCSqGSIb3DQEJARYReWloYWlib2JiQDE2My5jb20wgZ8wDQYJKoZIhvcNAQEB 11 | BQADgY0AMIGJAoGBAOC2kAt/nXbrrWfPjQID0gyBci2dt9wYGSF4reK8oi9t1D2D 12 | Oz6GeCEGSEgowbEO9fOQFvmshmii4hdAfqtvPonIUHGEeLl2JLzHq3U6iZg2nlJy 13 | jR3qz3J9ICaQs1E2+WqDloteWJ/2m1CDqkczX+9WqKdO7L8q49q6z2/nentXAgMB 14 | AAEwDQYJKoZIhvcNAQEFBQADgYEAQnlRL1pLK6nPyvpVvBoqlXVrmutxHLVUWfyT 15 | d7FvFk3RgV7IgYh3bEsB8Wc/dzzwc5wW+HMCbkTjtcf1wkRhbIxeiXl3OrmlZkZ8 16 | aquROQ9Ac1K9D61DsAM2k69cQBRKkCdxf8pHYHo/vtdrfA/6JVr89yX8WZKzI+rt 17 | tTIQ+zM= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /doc/dir/back/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQDgtpALf512661nz40CA9IMgXItnbfcGBkheK3ivKIvbdQ9gzs+ 3 | hnghBkhIKMGxDvXzkBb5rIZoouIXQH6rbz6JyFBxhHi5diS8x6t1OomYNp5Sco0d 4 | 6s9yfSAmkLNRNvlqg5aLXlif9ptQg6pHM1/vVqinTuy/KuPaus9v53p7VwIDAQAB 5 | AoGARJKRbGDaDXMn7Hjin83IqHZMAG2TsL9N0+/+qCVGHNEYJllIl/Dy8aj4H8UI 6 | Ll7RYS0ERdaHAaFK+yt8PBZrb4/hmPcXxZbA+ibCiU0SxyrOS9e4eQahCJL28Gp7 7 | z6Wk1JH0MLckQm22oeZ/pqzkhgV4FREDM/PEsl5axrWAvjECQQDzjFYMpSpK15e7 8 | fJFiPeZUTfheINNzISnNeBivlLx6EY57wSiGa1imJ5lJZlFko9/tU48kcdzqkLIJ 9 | fHgk8BZZAkEA7DO0isZT1Nnz9eNxOF0MqKDVgNprBKqRs3boXjrhrT6Re4DRBvGm 10 | KtfLy+q5hbriNmW3L+QoHhZuU9bTjl9JLwJAY1KdGSUWfVU1DQH9LGqAD2uI2aJb 11 | eX1R1fifYKOwxbt5NyEMDN2kVoaZreRrVza5sMi9/Kfu5z5BTTsUqEO9aQJBAOPx 12 | 6hPa3eAWDjeHrSXltmet/x0ArDKuoTl+UTVOwae9MAzt/csjvWavJr+94BhMiC5S 13 | 7vxKxOR0ZTiHo1ZMYoUCQCzAX1AZsT0yRWb9RVY5r3lw47syeEBryPrRVvRvbSy7 14 | FoqUCC9Gi9TB1OHLyVn3vcd7+CoKxX6QqauhtU/PG0Y= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /doc/dir/back/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIZ8xnhLX3vI0CAggA 3 | MBQGCCqGSIb3DQMHBAg1HqxeYsT1tQSCAoCj89ekut39T/EXn2kyJjToaVlCY09F 4 | VMeTdfdc1dfP8E0549r1tXtTlDILIU5Qi/Zex5jtfjGyA9363lMliXX2g27yTGMT 5 | cTB0zlE6zjhTruCt7fRIQSKX0Jbq21uSysxkVo0MGdZGyyf3zJMc2iMNdL5XjcQe 6 | nMtvem2tjlZhnCgxFcQLdjkafVdlxQpnNVMnAFXGSUBM9jHwc+PUyzca+3UL5D2k 7 | IW7DYB0iS3cq2B0yw+lyYLcQsn0VlSfDwbbxTdThVqhNGPIp06TNZrcNhF+i5iGz 8 | FjHuujHP9ZqQTcpouv9Q3PalK3dx8Nk2zaiASjb3W0rQrwXNuGmTs4SJjTtaT0Jq 9 | 5rlsXDwqbuso5ZLjnjLHP2Rgx3d1vFLsR3JxhPvgrG2VacyeG8LOrmTZzD8ie+Ea 10 | Aj6NEvQqXCi6uXJqK3ZIJnGEqyxrM+qsGZAjU6sDUc/aZakbe468Wq5OGllwGx9O 11 | oOjBwpblnvOv7uJCbvKuh/0jGt10YFcujGee5EUn0IcsPpl/V9YZQD0Kqi1Qd43H 12 | /71O6GczR3d+mB+ji9H1vpUua6PqIgGYatQLG6WY9p4mQBgcEZet5XAo1fmCVGy8 13 | GQoHJu6CPtwA4nuerdQiQEsefDOOUDkMmtNO1zZ/XzlgwwhjPn1LVbk02gFc0h+7 14 | m4d86nf5xRveXQEABmRfaNat542GWWH3lhAjoFtwpVyIQGD/t000FXAi7D6HKJDc 15 | YZovdttMRlsWDrkzSwTN+TwDjJ1XGShKT6s3Uesyk8cMKVUftAsrTmfENjA1MT/L 16 | HfiPzmv1OdRD/+aUxLoKriuXDla/tOFPpaSu41UG41Zt4ybO2D57cDIX 17 | -----END ENCRYPTED PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /doc/dir/back/shadow: -------------------------------------------------------------------------------- 1 | root:$6$htIReI5a$7.csLnjjzr4.r/o8NVCK/k/giBPwnZJIgX2EdqsD1.1ZnQm1yrDIXa1Hsu1oasFjJROTUCxLUIZ.GjMJu90VM/:15531:0:99999:7::: 2 | daemon:*:15453:0:99999:7::: 3 | bin:*:15453:0:99999:7::: 4 | sys:*:15453:0:99999:7::: 5 | sync:*:15453:0:99999:7::: 6 | games:*:15453:0:99999:7::: 7 | man:*:15453:0:99999:7::: 8 | lp:*:15453:0:99999:7::: 9 | mail:*:15453:0:99999:7::: 10 | news:*:15453:0:99999:7::: 11 | uucp:*:15453:0:99999:7::: 12 | proxy:*:15453:0:99999:7::: 13 | www-data:*:15453:0:99999:7::: 14 | backup:*:15453:0:99999:7::: 15 | list:*:15453:0:99999:7::: 16 | irc:*:15453:0:99999:7::: 17 | gnats:*:15453:0:99999:7::: 18 | nobody:*:15453:0:99999:7::: 19 | libuuid:!:15453:0:99999:7::: 20 | syslog:*:15453:0:99999:7::: 21 | messagebus:*:15453:0:99999:7::: 22 | colord:*:15453:0:99999:7::: 23 | lightdm:*:15453:0:99999:7::: 24 | whoopsie:*:15453:0:99999:7::: 25 | avahi-autoipd:*:15453:0:99999:7::: 26 | avahi:*:15453:0:99999:7::: 27 | usbmux:*:15453:0:99999:7::: 28 | kernoops:*:15453:0:99999:7::: 29 | pulse:*:15453:0:99999:7::: 30 | rtkit:*:15453:0:99999:7::: 31 | speech-dispatcher:!:15453:0:99999:7::: 32 | hplip:*:15453:0:99999:7::: 33 | saned:*:15453:0:99999:7::: 34 | yihaibo:$6$LzYgxFO7$dTlAPrfOfOqaFzlNJ94k9a6/vIoHeOL1lCZKvAsem7/VwkQIzICimNi0jxFvOtzYDqerZ2oo2RvgFv1DRLH5l.:15507:0:99999:7::: 35 | guest-YJIgim:*:15507:0:99999:7::: 36 | landscape:*:15508:0:99999:7::: 37 | sshd:*:15554:0:99999:7::: 38 | lwy:$6$XdyWZNHi$LnO2yLNyHJIWRz6v6vneNapn0RIayozjdO5tNNPoUJM6oorvUQdiYievCuJXBFXG74lcVnQfVw3BAaWXwL/nJ/:15558:0:99999:7::: 39 | user:$6$WJebXF9S$eTg8epKOK5Wtrh36nu./63q1LHUIXj2n9ctNzl6ei.g24TQiup9BWxPEH6TgrH6b2XJHRpcMRIRZFkqF3xlkF.:15664:0:99999:7::: 40 | -------------------------------------------------------------------------------- /doc/dir/back_main.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | #include "parse.h" 3 | 4 | #define PID_FILE "pid.file" 5 | 6 | static void doit(int fd); 7 | static void writePid(int option); 8 | static void get_requesthdrs(rio_t *rp); 9 | static void post_requesthdrs(rio_t *rp,int *length); 10 | static int parse_uri(char *uri, char *filename, char *cgiargs); 11 | static void serve_static(int fd, char *filename, int filesize); 12 | static void serve_dir(int fd,char *filename); 13 | static void get_filetype(const char *filename, char *filetype); 14 | static void get_dynamic(int fd, char *filename, char *cgiargs); 15 | static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp); 16 | static void clienterror(int fd, char *cause, char *errnum, 17 | char *shortmsg, char *longmsg); 18 | 19 | static void sigChldHandler(int signo); 20 | /* $begin ssl */ 21 | #ifdef SSL 22 | static void ssl_init(void); 23 | static void https_getlength(char* buf,int* length); 24 | #endif 25 | 26 | /* $end ssl */ 27 | 28 | 29 | static int isShowdir=1; 30 | char* cwd; 31 | 32 | #ifdef SSL 33 | static SSL_CTX* ssl_ctx; 34 | static SSL* ssl; 35 | static char* certfile; 36 | static int ishttps=0; 37 | static char httpspostdata[MAXLINE]; 38 | #endif 39 | 40 | 41 | 42 | int main(int argc, char **argv) 43 | { 44 | int listenfd,connfd, port,clientlen; 45 | pid_t pid; 46 | struct sockaddr_in clientaddr; 47 | char isdaemon=0,*portp=NULL,*logp=NULL,tmpcwd[MAXLINE]; 48 | 49 | #ifdef SSL 50 | int sslport; 51 | char dossl=0,*sslportp=NULL; 52 | #endif 53 | 54 | openlog(argv[0],LOG_NDELAY|LOG_PID,LOG_DAEMON); 55 | cwd=(char*)get_current_dir_name(); 56 | strcpy(tmpcwd,cwd); 57 | strcat(tmpcwd,"/"); 58 | /* parse argv */ 59 | parse_option(argc,argv,&isdaemon,&portp,&logp,&sslportp,&dossl); 60 | portp==NULL ?(port=atoi(Getconfig("http"))) : (port=atoi(portp)); 61 | 62 | 63 | sslportp==NULL ?(sslport=atoi(Getconfig("https"))) : (sslport=atoi(sslportp)); 64 | 65 | Signal(SIGCHLD,sigChldHandler); 66 | 67 | 68 | /* init log */ 69 | if(logp==NULL) 70 | logp=Getconfig("log"); 71 | initlog(strcat(tmpcwd,logp)); 72 | 73 | /* whethe show dir */ 74 | if(strcmp(Getconfig("dir"),"no")==0) 75 | isShowdir=0; 76 | 77 | if(dossl==1||strcmp(Getconfig("dossl"),"yes")==0) 78 | dossl=1; 79 | 80 | clientlen = sizeof(clientaddr); 81 | 82 | 83 | if(isdaemon==1||strcmp(Getconfig("daemon"),"yes")==0) 84 | Daemon(1,1); 85 | 86 | writePid(1); 87 | 88 | /* $https start */ 89 | if(dossl) 90 | { 91 | if((pid=Fork())==0) 92 | { 93 | listenfd= Open_listenfd(sslport); 94 | ssl_init(); 95 | 96 | while(1) 97 | { 98 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 99 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 100 | { 101 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 102 | continue; 103 | } 104 | 105 | if((pid=Fork())>0) 106 | { 107 | Close(connfd); 108 | continue; 109 | } 110 | else if(pid==0) 111 | { 112 | ishttps=1; 113 | doit(connfd); 114 | exit(1); 115 | } 116 | } 117 | } 118 | } 119 | 120 | /* $end https */ 121 | 122 | 123 | listenfd = Open_listenfd(port); 124 | while (1) 125 | { 126 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 127 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 128 | { 129 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 130 | continue; 131 | } 132 | 133 | if((pid=Fork())>0) 134 | { 135 | Close(connfd); 136 | continue; 137 | } 138 | else if(pid==0) 139 | { 140 | doit(connfd); 141 | exit(1); 142 | } 143 | } 144 | } 145 | /* $end main */ 146 | 147 | 148 | /*$sigChldHandler to protect zimble process */ 149 | static void sigChldHandler(int signo) 150 | { 151 | Waitpid(-1,NULL,WNOHANG); 152 | return; 153 | } 154 | /*$end sigChldHandler */ 155 | 156 | 157 | /* $begin ssl init */ 158 | static void ssl_init(void) 159 | { 160 | static char crypto[]="RC4-MD5"; 161 | certfile=Getconfig("ca"); 162 | 163 | SSL_load_error_strings(); 164 | SSLeay_add_ssl_algorithms(); 165 | ssl_ctx = SSL_CTX_new( SSLv23_server_method() ); 166 | 167 | if ( certfile[0] != '\0' ) 168 | if ( SSL_CTX_use_certificate_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_use_PrivateKey_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_check_private_key( ssl_ctx ) == 0 ) 169 | { 170 | ERR_print_errors_fp( stderr ); 171 | exit( 1 ); 172 | } 173 | if ( crypto != (char*) 0 ) 174 | { 175 | 176 | if ( SSL_CTX_set_cipher_list( ssl_ctx, crypto ) == 0 ) 177 | { 178 | ERR_print_errors_fp( stderr ); 179 | exit( 1 ); 180 | } 181 | } 182 | 183 | } 184 | /* $end ssl init */ 185 | 186 | 187 | /* 188 | * doit - handle one HTTP request/response transaction 189 | */ 190 | /* $begin doit */ 191 | static void doit(int fd) 192 | { 193 | int is_static,contentLength=0,isGet=1; 194 | struct stat sbuf; 195 | char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; 196 | char filename[MAXLINE], cgiargs[MAXLINE],httpspostdata[MAXLINE]; 197 | rio_t rio; 198 | 199 | memset(buf,0,MAXLINE); 200 | if(ishttps) 201 | { 202 | ssl=SSL_new(ssl_ctx); 203 | SSL_set_fd(ssl,fd); 204 | if(SSL_accept(ssl)==0) 205 | { 206 | ERR_print_errors_fp(stderr); 207 | exit(1); 208 | } 209 | SSL_read(ssl,buf,sizeof(buf)); 210 | } 211 | else 212 | { 213 | /* Read request line and headers */ 214 | Rio_readinitb(&rio, fd); 215 | Rio_readlineb(&rio, buf, MAXLINE); 216 | } 217 | 218 | sscanf(buf, "%s %s %s", method, uri, version); 219 | 220 | if (strcasecmp(method, "GET")!=0&&strcasecmp(method,"POST")!=0) 221 | { 222 | clienterror(fd, method, "501", "Not Implemented", 223 | "Tiny does not implement this method"); 224 | return; 225 | } 226 | 227 | 228 | /* Parse URI from GET request */ 229 | is_static = parse_uri(uri, filename, cgiargs); 230 | 231 | 232 | if (lstat(filename, &sbuf) < 0) 233 | { 234 | clienterror(fd, filename, "404", "Not found", 235 | "Tiny couldn't find this file"); 236 | return; 237 | } 238 | 239 | if(S_ISDIR(sbuf.st_mode)&&isShowdir) 240 | serve_dir(fd,filename); 241 | 242 | 243 | if (strcasecmp(method, "POST")==0) 244 | isGet=0; 245 | 246 | 247 | if (is_static) 248 | { /* Serve static content */ 249 | if(!ishttps) 250 | get_requesthdrs(&rio); /* because https already read the headers -> SSL_read() */ 251 | 252 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) 253 | { 254 | clienterror(fd, filename, "403", "Forbidden", 255 | "Tiny couldn't read the file"); 256 | return; 257 | } 258 | serve_static(fd, filename, sbuf.st_size); 259 | } 260 | else 261 | { /* Serve dynamic content */ 262 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) 263 | { 264 | clienterror(fd, filename, "403", "Forbidden", 265 | "Tiny couldn't run the CGI program"); 266 | return; 267 | } 268 | 269 | if(isGet) 270 | { 271 | if(!ishttps) 272 | get_requesthdrs(&rio); /* because https already read headers by SSL_read() */ 273 | 274 | get_dynamic(fd, filename, cgiargs); 275 | } 276 | else 277 | { 278 | if(ishttps) 279 | https_getlength(buf,&contentLength); 280 | else 281 | post_requesthdrs(&rio,&contentLength); 282 | 283 | post_dynamic(fd, filename,contentLength,&rio); 284 | } 285 | } 286 | } 287 | /* $end doit */ 288 | 289 | /* $begin https_getlength */ 290 | static void https_getlength(char* buf,int* length) 291 | { 292 | char *p,line[MAXLINE]; 293 | char *tmpbuf=buf; 294 | int lengthfind=0; 295 | 296 | while(*tmpbuf!='\0') 297 | { 298 | p=line; 299 | while(*tmpbuf!='\n' && *tmpbuf!='\0') 300 | *p++=*tmpbuf++; 301 | *p='\0'; 302 | if(!lengthfind) 303 | { 304 | if(strncasecmp(line,"Content-Length:",15)==0) 305 | { 306 | p=&line[15]; 307 | p+=strspn(p," \t"); 308 | *length=atoi(p); 309 | lengthfind=1; 310 | } 311 | } 312 | 313 | if(strncasecmp(line,"\r",1)==0) 314 | { 315 | strcpy(httpspostdata,++tmpbuf); 316 | break; 317 | } 318 | ++tmpbuf; 319 | } 320 | return; 321 | } 322 | 323 | /* $end https_getlength */ 324 | 325 | /* 326 | * read_requesthdrs - read and parse HTTP request headers 327 | */ 328 | /* $begin get_requesthdrs */ 329 | static void get_requesthdrs(rio_t *rp) 330 | { 331 | char buf[MAXLINE]; 332 | 333 | Rio_readlineb(rp, buf, MAXLINE); 334 | writetime(); /* write access time in log file */ 335 | //printf("%s", buf); 336 | while(strcmp(buf, "\r\n")) 337 | { 338 | Rio_readlineb(rp, buf, MAXLINE); 339 | writelog(buf); 340 | //printf("%s", buf); 341 | } 342 | return; 343 | } 344 | /* $end get_requesthdrs */ 345 | 346 | /* $begin post_requesthdrs */ 347 | static void post_requesthdrs(rio_t *rp,int *length) 348 | { 349 | char buf[MAXLINE]; 350 | char *p; 351 | 352 | Rio_readlineb(rp, buf, MAXLINE); 353 | writetime(); /* write access time in log file */ 354 | while(strcmp(buf, "\r\n")) 355 | { 356 | Rio_readlineb(rp, buf, MAXLINE); 357 | if(strncasecmp(buf,"Content-Length:",15)==0) 358 | { 359 | p=&buf[15]; 360 | p+=strspn(p," \t"); 361 | *length=atol(p); 362 | } 363 | writelog(buf); 364 | //printf("%s", buf); 365 | } 366 | return; 367 | } 368 | /* $end post_requesthdrs */ 369 | 370 | 371 | /* $begin post_dynamic */ 372 | static void serve_dir(int fd,char *filename) 373 | { 374 | DIR *dp; 375 | struct dirent *dirp; 376 | struct stat sbuf; 377 | struct passwd *filepasswd; 378 | int num=1; 379 | char files[MAXLINE],buf[MAXLINE],name[MAXLINE],img[MAXLINE],modifyTime[MAXLINE],dir[MAXLINE]; 380 | char *p; 381 | 382 | /* 383 | * Start get the dir 384 | * for example: /home/yihaibo/kerner/web/doc/dir -> dir[]="dir/"; 385 | */ 386 | p=strrchr(filename,'/'); 387 | ++p; 388 | strcpy(dir,p); 389 | strcat(dir,"/"); 390 | /* End get the dir */ 391 | 392 | if((dp=opendir(filename))==NULL) 393 | syslog(LOG_ERR,"cannot open dir:%s",filename); 394 | 395 | sprintf(files, "Dir Browser"); 396 | sprintf(files,"%s",files); 397 | sprintf(files, "%s\r\n", files); 398 | 399 | while((dirp=readdir(dp))!=NULL) 400 | { 401 | if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0) 402 | continue; 403 | sprintf(name,"%s/%s",filename,dirp->d_name); 404 | Stat(name,&sbuf); 405 | filepasswd=getpwuid(sbuf.st_uid); 406 | 407 | if(S_ISDIR(sbuf.st_mode)) 408 | { 409 | sprintf(img,""); 410 | } 411 | else if(S_ISFIFO(sbuf.st_mode)) 412 | { 413 | sprintf(img,""); 414 | } 415 | else if(S_ISLNK(sbuf.st_mode)) 416 | { 417 | sprintf(img,""); 418 | } 419 | else if(S_ISSOCK(sbuf.st_mode)) 420 | { 421 | sprintf(img,""); 422 | } 423 | else 424 | sprintf(img,""); 425 | 426 | 427 | sprintf(files,"%s

%-2d %s ""%-15s%-10s%10d %24s

\r\n",files,num++,img,dir,dirp->d_name,dirp->d_name,filepasswd->pw_name,(int)sbuf.st_size,timeModify(sbuf.st_mtime,modifyTime)); 428 | } 429 | closedir(dp); 430 | sprintf(files,"%s",files); 431 | 432 | /* Send response headers to client */ 433 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 434 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 435 | sprintf(buf, "%sContent-length: %d\r\n", buf, strlen(files)); 436 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, "text/html"); 437 | 438 | if(ishttps) 439 | { 440 | SSL_write(ssl,buf,strlen(buf)); 441 | SSL_write(ssl,files,strlen(files)); 442 | } 443 | else 444 | { 445 | Rio_writen(fd, buf, strlen(buf)); 446 | Rio_writen(fd, files, strlen(files)); 447 | } 448 | exit(0); 449 | 450 | } 451 | /* $end serve_dir */ 452 | 453 | 454 | /* $begin post_dynamic */ 455 | static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp) 456 | { 457 | char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE]; 458 | int p[2],httpsp[2]; 459 | 460 | sprintf(length,"%d",contentLength); 461 | memset(data,0,MAXLINE); 462 | 463 | Pipe(p); 464 | 465 | /* The post data is sended by client,we need to redirct the data to cgi stdin. 466 | * so, child read contentLength bytes data from fp,and write to p[1]; 467 | * parent should redirct p[0] to stdin. As a result, the cgi script can 468 | * read the post data from the stdin. 469 | */ 470 | 471 | /* https already read all data ,include post data by SSL_read() */ 472 | 473 | if (Fork() == 0) 474 | { /* child */ 475 | Close(p[0]); 476 | if(ishttps) 477 | { 478 | Write(p[1],httpspostdata,contentLength); 479 | } 480 | else 481 | { 482 | Rio_readnb(rp,data,contentLength); 483 | Rio_writen(p[1],data,contentLength); 484 | } 485 | exit(0) ; 486 | } 487 | 488 | /* Send response headers to client */ 489 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 490 | sprintf(buf, "%sServer: Tiny Web Server\r\n",buf); 491 | 492 | if(ishttps) 493 | SSL_write(ssl,buf,strlen(buf)); 494 | else 495 | Rio_writen(fd, buf, strlen(buf)); 496 | 497 | //Wait(NULL); 498 | Dup2(p[0],STDIN_FILENO); /* Redirct p[0] to stdin */ 499 | Close(p[0]); 500 | 501 | Close(p[1]); 502 | setenv("CONTENT-LENGTH",length , 1); 503 | 504 | if(ishttps) /* if ishttps,we couldnot redirct stdout to client,we must use SSL_write */ 505 | { 506 | Pipe(httpsp); 507 | 508 | if(Fork()==0) 509 | { 510 | Dup2(httpsp[1],STDOUT_FILENO); /* Redirct stdout to https[1] */ 511 | Execve(filename, emptylist, environ); 512 | } 513 | //Wait(NULL); 514 | read(httpsp[0],data,MAXLINE); 515 | SSL_write(ssl,data,strlen(data)); 516 | } 517 | else 518 | { 519 | Dup2(fd,STDOUT_FILENO); /* Redirct stdout to client */ 520 | Execve(filename, emptylist, environ); 521 | } 522 | } 523 | /* $end post_dynamic */ 524 | 525 | 526 | 527 | 528 | 529 | /* 530 | * parse_uri - parse URI into filename and CGI args 531 | * return 0 if dynamic content, 1 if static 532 | */ 533 | /* $begin parse_uri */ 534 | static int parse_uri(char *uri, char *filename, char *cgiargs) 535 | { 536 | char *ptr; 537 | char tmpcwd[MAXLINE]; 538 | strcpy(tmpcwd,cwd); 539 | strcat(tmpcwd,"/"); 540 | 541 | if (!strstr(uri, "cgi-bin")) 542 | { /* Static content */ 543 | strcpy(cgiargs, ""); 544 | strcpy(filename, strcat(tmpcwd,Getconfig("root"))); 545 | strcat(filename, uri); 546 | if (uri[strlen(uri)-1] == '/') 547 | strcat(filename, "home.html"); 548 | return 1; 549 | } 550 | else 551 | { /* Dynamic content */ 552 | ptr = index(uri, '?'); 553 | if (ptr) 554 | { 555 | strcpy(cgiargs, ptr+1); 556 | *ptr = '\0'; 557 | } 558 | else 559 | strcpy(cgiargs, ""); 560 | strcpy(filename, cwd); 561 | strcat(filename, uri); 562 | return 0; 563 | } 564 | } 565 | /* $end parse_uri */ 566 | 567 | /* 568 | * serve_static - copy a file back to the client 569 | */ 570 | /* $begin serve_static */ 571 | static void serve_static(int fd, char *filename, int filesize) 572 | { 573 | int srcfd; 574 | char *srcp, filetype[MAXLINE], buf[MAXBUF]; 575 | 576 | /* Send response headers to client */ 577 | get_filetype(filename, filetype); 578 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 579 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 580 | sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); 581 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); 582 | 583 | /* Send response body to client */ 584 | srcfd = Open(filename, O_RDONLY, 0); 585 | srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 586 | Close(srcfd); 587 | 588 | if(ishttps) 589 | { 590 | SSL_write(ssl, buf, strlen(buf)); 591 | SSL_write(ssl, srcp, filesize); 592 | } 593 | else 594 | { 595 | Rio_writen(fd, buf, strlen(buf)); 596 | Rio_writen(fd, srcp, filesize); 597 | } 598 | Munmap(srcp, filesize); 599 | } 600 | 601 | /* 602 | * get_filetype - derive file type from file name 603 | */ 604 | static void get_filetype(const char *filename, char *filetype) 605 | { 606 | if (strstr(filename, ".html")) 607 | strcpy(filetype, "text/html"); 608 | else if (strstr(filename, ".gif")) 609 | strcpy(filetype, "image/gif"); 610 | else if (strstr(filename, ".jpg")) 611 | strcpy(filetype, "image/jpeg"); 612 | else if (strstr(filename, ".png")) 613 | strcpy(filetype, "image/png"); 614 | else 615 | strcpy(filetype, "text/plain"); 616 | } 617 | /* $end serve_static */ 618 | 619 | /* 620 | * serve_dynamic - run a CGI program on behalf of the client 621 | */ 622 | /* $begin get_dynamic */ 623 | void get_dynamic(int fd, char *filename, char *cgiargs) 624 | { 625 | char buf[MAXLINE], *emptylist[] = { NULL },httpsbuf[MAXLINE]; 626 | int p[2]; 627 | 628 | /* Return first part of HTTP response */ 629 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 630 | sprintf(buf, "%sServer: Tiny Web Server\r\n",buf); 631 | 632 | if(ishttps) 633 | SSL_write(ssl,buf,strlen(buf)); 634 | 635 | else 636 | Rio_writen(fd, buf, strlen(buf)); 637 | 638 | if(ishttps) 639 | { 640 | Pipe(p); 641 | if (Fork() == 0) 642 | { /* child */ 643 | Close(p[0]); 644 | setenv("QUERY_STRING", cgiargs, 1); 645 | Dup2(p[1], STDOUT_FILENO); /* Redirect stdout to p[1] */ 646 | Execve(filename, emptylist, environ); /* Run CGI program */ 647 | } 648 | Close(p[1]); 649 | Read(p[0],httpsbuf,MAXLINE); /* parent read from p[0] */ 650 | SSL_write(ssl,httpsbuf,strlen(httpsbuf)); 651 | } 652 | else 653 | { 654 | if (Fork() == 0) 655 | { /* child */ 656 | /* Real server would set all CGI vars here */ 657 | setenv("QUERY_STRING", cgiargs, 1); 658 | Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ 659 | Execve(filename, emptylist, environ); /* Run CGI program */ 660 | } 661 | } 662 | //Wait(NULL); /* Parent waits for and reaps child */ 663 | } 664 | /* $end get_dynamic */ 665 | 666 | /* 667 | * clienterror - returns an error message to the client 668 | */ 669 | /* $begin clienterror */ 670 | static void clienterror(int fd, char *cause, char *errnum, 671 | char *shortmsg, char *longmsg) 672 | { 673 | char buf[MAXLINE], body[MAXBUF]; 674 | 675 | /* Build the HTTP response body */ 676 | sprintf(body, "Tiny Error"); 677 | sprintf(body, "%s\r\n", body); 678 | sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); 679 | sprintf(body, "%s

%s: %s\r\n", body, longmsg, cause); 680 | sprintf(body, "%s


The Tiny Web server\r\n", body); 681 | 682 | /* Print the HTTP response */ 683 | sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); 684 | sprintf(buf, "%sContent-type: text/html\r\n",buf); 685 | sprintf(buf, "%sContent-length: %d\r\n\r\n",buf,(int)strlen(body)); 686 | 687 | if(ishttps) 688 | { 689 | SSL_write(ssl,buf,strlen(buf)); 690 | SSL_write(ssl,body,strlen(body)); 691 | } 692 | else 693 | { 694 | Rio_writen(fd, buf, strlen(buf)); 695 | Rio_writen(fd, body, strlen(body)); 696 | } 697 | } 698 | /* $end clienterror */ 699 | 700 | 701 | 702 | /* $begin writePid */ 703 | /* if the process is running, the interger in the pid file is the pid, else is -1 */ 704 | static void writePid(int option) 705 | { 706 | int pid; 707 | FILE *fp=Fopen(PID_FILE,"w+"); 708 | if(option) 709 | pid=(int)getpid(); 710 | else 711 | pid=-1; 712 | fprintf(fp,"%d",pid); 713 | Fclose(fp); 714 | } 715 | /* $end writePid */ 716 | -------------------------------------------------------------------------------- /doc/dir/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/dir/file.png -------------------------------------------------------------------------------- /doc/dir/main.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | #include "parse.h" 3 | #include "daemon_init.h" 4 | 5 | void doit(int fd); 6 | void get_requesthdrs(rio_t *rp); 7 | void post_requesthdrs(rio_t *rp,int *length); 8 | int parse_uri(char *uri, char *filename, char *cgiargs); 9 | void serve_static(int fd, char *filename, int filesize); 10 | void serve_dir(int fd,char *filename); 11 | void get_filetype(char *filename, char *filetype); 12 | void get_dynamic(int fd, char *filename, char *cgiargs); 13 | void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp); 14 | void clienterror(int fd, char *cause, char *errnum, 15 | char *shortmsg, char *longmsg); 16 | 17 | static int isShowdir=1; 18 | char *cwd; 19 | 20 | int main(int argc, char **argv) 21 | { 22 | int listenfd, connfd, port, clientlen; 23 | pid_t pid; 24 | struct sockaddr_in clientaddr; 25 | char daemon=0,*portp=NULL,*logp=NULL,tmpcwd[MAXLINE]; 26 | 27 | cwd=(char*)get_current_dir_name(); 28 | strcpy(tmpcwd,cwd); 29 | strcat(tmpcwd,"/"); 30 | /* parse argv */ 31 | parse_option(argc,argv,&daemon,&portp,&logp); 32 | portp==NULL ?(port=atoi(getconfig("port"))) : (port=atoi(portp)); 33 | 34 | /* init log */ 35 | if(logp==NULL) 36 | logp=getconfig("log"); 37 | initlog(strcat(tmpcwd,logp)); 38 | 39 | /* where show dir */ 40 | if(strcmp(getconfig("dir"),"no")==0) 41 | isShowdir=0; 42 | 43 | if(daemon==1||strcmp(getconfig("daemon"),"yes")==0) 44 | init_daemon(); 45 | 46 | listenfd = Open_listenfd(port); 47 | 48 | while (1) 49 | { 50 | clientlen = sizeof(clientaddr); 51 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 52 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 53 | { 54 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 55 | continue; 56 | } 57 | 58 | if((pid=Fork())>0) 59 | { 60 | close(connfd); 61 | continue; 62 | } 63 | else if(pid==0) 64 | { 65 | doit(connfd); 66 | } 67 | 68 | } 69 | } 70 | /* $end main */ 71 | 72 | 73 | /* 74 | * doit - handle one HTTP request/response transaction 75 | */ 76 | /* $begin doit */ 77 | void doit(int fd) 78 | { 79 | int is_static,contentLength=0,isGet=1; 80 | struct stat sbuf; 81 | char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; 82 | char filename[MAXLINE], cgiargs[MAXLINE]; 83 | rio_t rio; 84 | 85 | /* Read request line and headers */ 86 | Rio_readinitb(&rio, fd); 87 | Rio_readlineb(&rio, buf, MAXLINE); 88 | sscanf(buf, "%s %s %s", method, uri, version); 89 | 90 | if (strcasecmp(method, "GET")!=0&&strcasecmp(method,"POST")!=0) 91 | { 92 | clienterror(fd, method, "501", "Not Implemented", 93 | "Tiny does not implement this method"); 94 | return; 95 | } 96 | 97 | 98 | /* Parse URI from GET request */ 99 | is_static = parse_uri(uri, filename, cgiargs); 100 | 101 | 102 | if (lstat(filename, &sbuf) < 0) 103 | { 104 | clienterror(fd, filename, "404", "Not found", 105 | "Tiny couldn't find this file"); 106 | return; 107 | } 108 | 109 | if(S_ISDIR(sbuf.st_mode)&&isShowdir) 110 | serve_dir(fd,filename); 111 | 112 | 113 | if (strcasecmp(method, "POST")==0) 114 | isGet=0; 115 | 116 | 117 | if (is_static) 118 | { /* Serve static content */ 119 | get_requesthdrs(&rio); 120 | 121 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) 122 | { 123 | clienterror(fd, filename, "403", "Forbidden", 124 | "Tiny couldn't read the file"); 125 | return; 126 | } 127 | serve_static(fd, filename, sbuf.st_size); 128 | } 129 | else 130 | { /* Serve dynamic content */ 131 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) 132 | { 133 | clienterror(fd, filename, "403", "Forbidden", 134 | "Tiny couldn't run the CGI program"); 135 | return; 136 | } 137 | 138 | if(isGet) 139 | { 140 | get_requesthdrs(&rio); 141 | get_dynamic(fd, filename, cgiargs); 142 | } 143 | else 144 | { 145 | post_requesthdrs(&rio,&contentLength); 146 | post_dynamic(fd, filename,contentLength,&rio); 147 | } 148 | } 149 | } 150 | /* $end doit */ 151 | 152 | /* 153 | * read_requesthdrs - read and parse HTTP request headers 154 | */ 155 | /* $begin get_requesthdrs */ 156 | void get_requesthdrs(rio_t *rp) 157 | { 158 | char buf[MAXLINE]; 159 | 160 | Rio_readlineb(rp, buf, MAXLINE); 161 | writetime(); // write access time in log file 162 | printf("%s", buf); 163 | while(strcmp(buf, "\r\n")) 164 | { 165 | Rio_readlineb(rp, buf, MAXLINE); 166 | writelog(buf); 167 | printf("%s", buf); 168 | } 169 | return; 170 | } 171 | /* $end get_requesthdrs */ 172 | 173 | /* $begin post_requesthdrs */ 174 | void post_requesthdrs(rio_t *rp,int *length) 175 | { 176 | char buf[MAXLINE]; 177 | char *p; 178 | 179 | Rio_readlineb(rp, buf, MAXLINE); 180 | writetime(); // write access time in log file 181 | printf("%s", buf); 182 | while(strcmp(buf, "\r\n")) 183 | { 184 | Rio_readlineb(rp, buf, MAXLINE); 185 | if(strncasecmp(buf,"Content-Length:",15)==0) 186 | { 187 | p=&buf[15]; 188 | p+=strspn(p," \t"); 189 | *length=atol(p); 190 | } 191 | writelog(buf); 192 | printf("%s", buf); 193 | } 194 | return; 195 | } 196 | /* $end post_requesthdrs */ 197 | 198 | 199 | /* $begin post_dynamic */ 200 | void serve_dir(int fd,char *filename) 201 | { 202 | DIR *dp; 203 | struct dirent *dirp; 204 | struct stat sbuf; 205 | int num=1; 206 | char files[MAXLINE],buf[MAXLINE],name[MAXLINE],img[MAXLINE]; 207 | 208 | if((dp=opendir(filename))==NULL) 209 | syslog(LOG_ERR,"cannot open dir:%s",filename); 210 | 211 | sprintf(files, "Dir Browser"); 212 | sprintf(files, "%s\r\n", files); 213 | 214 | while((dirp=readdir(dp))!=NULL) 215 | { 216 | if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0) 217 | continue; 218 | sprintf(name,"%s/%s",filename,dirp->d_name); 219 | lstat(name,&sbuf); 220 | 221 | if(S_ISDIR(sbuf.st_mode)) 222 | { 223 | sprintf(img,""); 224 | } 225 | else if(S_ISFIFO(sbuf.st_mode)) 226 | { 227 | sprintf(img,""); 228 | } 229 | else if(S_ISLNK(sbuf.st_mode)) 230 | { 231 | sprintf(img,""); 232 | } 233 | else if(S_ISSOCK(sbuf.st_mode)) 234 | { 235 | sprintf(img,""); 236 | } 237 | else 238 | sprintf(img,""); 239 | 240 | 241 | sprintf(files,"%s

%-3d %s %-20s%20d

\r\n",files,num++,img,dirp->d_name,(int)sbuf.st_size); 242 | //sprintf(files,"%s

%-3d %-20s%20d

\r\n",files,num++,dirp->d_name,(int)sbuf.st_size); 243 | } 244 | closedir(dp); 245 | sprintf(files,"%s",files); 246 | printf("%s\n",files); 247 | 248 | /* Send response headers to client */ 249 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 250 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 251 | sprintf(buf, "%sContent-length: %d\r\n", buf, strlen(files)); 252 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, "text/html"); 253 | Rio_writen(fd, buf, strlen(buf)); 254 | 255 | /* Send data to client */ 256 | Rio_writen(fd, files, strlen(files)); 257 | exit(0); 258 | 259 | } 260 | /* $end serve_dir */ 261 | 262 | 263 | /* $begin post_dynamic */ 264 | void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp) 265 | { 266 | char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE]; 267 | int p[2]; 268 | 269 | sprintf(length,"%d",contentLength); 270 | 271 | if(pipe(p)==-1) 272 | syslog(LOG_ERR,"cannot create pipe"); 273 | 274 | /* The post data is sended by client,we need to redirct the data to cgi stdin. 275 | * so, child read contentLength bytes data from fp,and write to p[1]; 276 | * parent should redirct p[0] to stdin. As a result, the cgi script can 277 | * read the post data from the stdin. 278 | */ 279 | if (Fork() == 0) 280 | { /* child */ 281 | close(p[0]); 282 | Rio_readnb(rp,data,contentLength); 283 | Rio_writen(p[1],data,contentLength); 284 | exit(0); 285 | } 286 | 287 | 288 | /* Send response headers to client */ 289 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 290 | Rio_writen(fd, buf, strlen(buf)); 291 | sprintf(buf, "Server: Tiny Web Server\r\n"); 292 | Rio_writen(fd, buf, strlen(buf)); 293 | 294 | Dup2(p[0],STDIN_FILENO); /* Redirct p[0] to stdin */ 295 | close(p[0]); 296 | 297 | close(p[1]); 298 | setenv("CONTENT-LENGTH",length , 1); 299 | Dup2(fd,STDOUT_FILENO); /* Redirct stdout to client */ 300 | Execve(filename, emptylist, environ); 301 | } 302 | /* $end post_dynamic */ 303 | 304 | 305 | 306 | 307 | 308 | /* 309 | * parse_uri - parse URI into filename and CGI args 310 | * return 0 if dynamic content, 1 if static 311 | */ 312 | /* $begin parse_uri */ 313 | int parse_uri(char *uri, char *filename, char *cgiargs) 314 | { 315 | char *ptr; 316 | char tmpcwd[MAXLINE]; 317 | strcpy(tmpcwd,cwd); 318 | strcat(tmpcwd,"/"); 319 | 320 | if (!strstr(uri, "cgi-bin")) 321 | { /* Static content */ 322 | strcpy(cgiargs, ""); 323 | strcpy(filename, strcat(tmpcwd,getconfig("root"))); 324 | strcat(filename, uri); 325 | if (uri[strlen(uri)-1] == '/') 326 | strcat(filename, "home.html"); 327 | return 1; 328 | } 329 | else 330 | { /* Dynamic content */ 331 | ptr = index(uri, '?'); 332 | if (ptr) 333 | { 334 | strcpy(cgiargs, ptr+1); 335 | *ptr = '\0'; 336 | } 337 | else 338 | strcpy(cgiargs, ""); 339 | strcpy(filename, cwd); 340 | strcat(filename, uri); 341 | return 0; 342 | } 343 | } 344 | /* $end parse_uri */ 345 | 346 | /* 347 | * serve_static - copy a file back to the client 348 | */ 349 | /* $begin serve_static */ 350 | void serve_static(int fd, char *filename, int filesize) 351 | { 352 | int srcfd; 353 | char *srcp, filetype[MAXLINE], buf[MAXBUF]; 354 | 355 | /* Send response headers to client */ 356 | get_filetype(filename, filetype); 357 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 358 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 359 | sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); 360 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); 361 | Rio_writen(fd, buf, strlen(buf)); 362 | 363 | /* Send response body to client */ 364 | srcfd = Open(filename, O_RDONLY, 0); 365 | srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 366 | Close(srcfd); 367 | Rio_writen(fd, srcp, filesize); 368 | Munmap(srcp, filesize); 369 | } 370 | 371 | /* 372 | * get_filetype - derive file type from file name 373 | */ 374 | void get_filetype(char *filename, char *filetype) 375 | { 376 | if (strstr(filename, ".html")) 377 | strcpy(filetype, "text/html"); 378 | else if (strstr(filename, ".gif")) 379 | strcpy(filetype, "image/gif"); 380 | else if (strstr(filename, ".jpg")) 381 | strcpy(filetype, "image/jpeg"); 382 | else if (strstr(filename, ".png")) 383 | strcpy(filetype, "image/png"); 384 | else 385 | strcpy(filetype, "text/plain"); 386 | } 387 | /* $end serve_static */ 388 | 389 | /* 390 | * serve_dynamic - run a CGI program on behalf of the client 391 | */ 392 | /* $begin get_dynamic */ 393 | void get_dynamic(int fd, char *filename, char *cgiargs) 394 | { 395 | char buf[MAXLINE], *emptylist[] = { NULL }; 396 | 397 | /* Return first part of HTTP response */ 398 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 399 | Rio_writen(fd, buf, strlen(buf)); 400 | sprintf(buf, "Server: Tiny Web Server\r\n"); 401 | Rio_writen(fd, buf, strlen(buf)); 402 | 403 | if (Fork() == 0) 404 | { /* child */ 405 | /* Real server would set all CGI vars here */ 406 | setenv("QUERY_STRING", cgiargs, 1); 407 | Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ 408 | Execve(filename, emptylist, environ); /* Run CGI program */ 409 | } 410 | Wait(NULL); /* Parent waits for and reaps child */ 411 | } 412 | /* $end get_dynamic */ 413 | 414 | /* 415 | * clienterror - returns an error message to the client 416 | */ 417 | /* $begin clienterror */ 418 | void clienterror(int fd, char *cause, char *errnum, 419 | char *shortmsg, char *longmsg) 420 | { 421 | char buf[MAXLINE], body[MAXBUF]; 422 | 423 | /* Build the HTTP response body */ 424 | sprintf(body, "Tiny Error"); 425 | sprintf(body, "%s\r\n", body); 426 | sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); 427 | sprintf(body, "%s

%s: %s\r\n", body, longmsg, cause); 428 | sprintf(body, "%s


The Tiny Web server\r\n", body); 429 | 430 | /* Print the HTTP response */ 431 | sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); 432 | Rio_writen(fd, buf, strlen(buf)); 433 | sprintf(buf, "Content-type: text/html\r\n"); 434 | Rio_writen(fd, buf, strlen(buf)); 435 | sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); 436 | Rio_writen(fd, buf, strlen(buf)); 437 | Rio_writen(fd, body, strlen(body)); 438 | } 439 | /* $end clienterror */ 440 | -------------------------------------------------------------------------------- /doc/fifo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/fifo.png -------------------------------------------------------------------------------- /doc/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/file.png -------------------------------------------------------------------------------- /doc/getAuth.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/getAuth.html -------------------------------------------------------------------------------- /doc/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My web index 6 | 99 | 104 | 105 | 106 | 107 |
108 | 6年专业建站资历,品质值得信赖. 109 | 智徽医疗管理系统 110 | All were merely just started 111 | 博弈OA销售管理系统 112 |
113 |
114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /doc/img.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img.gif -------------------------------------------------------------------------------- /doc/img_switch_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img_switch_01.png -------------------------------------------------------------------------------- /doc/img_switch_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img_switch_02.png -------------------------------------------------------------------------------- /doc/img_switch_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img_switch_03.png -------------------------------------------------------------------------------- /doc/img_switch_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img_switch_04.png -------------------------------------------------------------------------------- /doc/img_switch_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/img_switch_bg.png -------------------------------------------------------------------------------- /doc/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/link.png -------------------------------------------------------------------------------- /doc/postAuth.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/postAuth.html -------------------------------------------------------------------------------- /doc/socket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/doc/socket.png -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include "wrap.h" 3 | 4 | FILE* logfp=NULL; 5 | 6 | void initlog(const char* logp) 7 | { 8 | logfp=Fopen(logp,"a+"); 9 | } 10 | 11 | static int getmonth(struct tm* local) // return month index ,eg. Oct->10 12 | { 13 | char buf[8]; 14 | int i; 15 | static char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"}; 16 | 17 | strftime(buf,127,"%b",local); 18 | for(i=0;i<12;++i) 19 | { 20 | if(!strcmp(buf,months[i])) 21 | return i+1; 22 | } 23 | return 0; 24 | } 25 | 26 | void writetime() 27 | { 28 | time_t timeval; 29 | char other[24]; 30 | char year[8]; 31 | char together[64]; 32 | int month; 33 | 34 | (void)time(&timeval); 35 | struct tm *local=localtime(&timeval); 36 | 37 | /* get year */ 38 | strftime(year,7,"%Y",local); 39 | /*get month */ 40 | month=getmonth(local); 41 | /*get other */ 42 | strftime(other,23,"%d %H:%M:%S",local); 43 | /*together all */ 44 | sprintf(together,"%s/%d/%s\r\n",year,month,other); 45 | fwrite(together,strlen(together),1,logfp); 46 | } 47 | 48 | char* timeModify(time_t timeval,char *time) 49 | { 50 | char other[24]; 51 | char year[8]; 52 | int month; 53 | 54 | struct tm *local=localtime(&timeval); 55 | 56 | /* get year */ 57 | strftime(year,7,"%Y",local); 58 | /*get month */ 59 | month=getmonth(local); 60 | /*get other */ 61 | strftime(other,23,"%d %H:%M:%S",local); 62 | /*together all */ 63 | sprintf(time,"%s/%d/%s\r\n",year,month,other); 64 | return time; 65 | } 66 | 67 | void writelog(const char* buf) 68 | { 69 | fwrite(buf,strlen(buf),1,logfp); 70 | fflush(logfp); 71 | } 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | #include "parse.h" 3 | 4 | #define PID_FILE "pid.file" 5 | 6 | static void doit(int fd); 7 | static void writePid(int option); 8 | static void get_requesthdrs(rio_t *rp); 9 | static void post_requesthdrs(rio_t *rp,int *length); 10 | static int parse_uri(char *uri, char *filename, char *cgiargs); 11 | static void serve_static(int fd, char *filename, int filesize); 12 | static void serve_dir(int fd,char *filename); 13 | static void get_filetype(const char *filename, char *filetype); 14 | static void get_dynamic(int fd, char *filename, char *cgiargs); 15 | static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp); 16 | static void clienterror(int fd, char *cause, char *errnum, 17 | char *shortmsg, char *longmsg); 18 | 19 | static void sigChldHandler(int signo); 20 | /* $begin ssl */ 21 | #ifdef HTTPS 22 | static void ssl_init(void); 23 | static void https_getlength(char* buf,int* length); 24 | #endif 25 | 26 | /* $end ssl */ 27 | 28 | 29 | static int isShowdir=1; 30 | char* cwd; 31 | 32 | #ifdef HTTPS 33 | static SSL_CTX* ssl_ctx; 34 | static SSL* ssl; 35 | static char* certfile; 36 | static int ishttps=0; 37 | static char httpspostdata[MAXLINE]; 38 | #endif 39 | 40 | 41 | 42 | int main(int argc, char **argv) 43 | { 44 | int listenfd,connfd, port,clientlen; 45 | pid_t pid; 46 | struct sockaddr_in clientaddr; 47 | char isdaemon=0,*portp=NULL,*logp=NULL,tmpcwd[MAXLINE]; 48 | 49 | #ifdef HTTPS 50 | int sslport; 51 | char dossl=0,*sslportp=NULL; 52 | #endif 53 | 54 | openlog(argv[0],LOG_NDELAY|LOG_PID,LOG_DAEMON); 55 | cwd=(char*)get_current_dir_name(); 56 | strcpy(tmpcwd,cwd); 57 | strcat(tmpcwd,"/"); 58 | /* parse argv */ 59 | 60 | #ifdef HTTPS 61 | parse_option(argc,argv,&isdaemon,&portp,&logp,&sslportp,&dossl); 62 | sslportp==NULL ?(sslport=atoi(Getconfig("https"))) : (sslport=atoi(sslportp)); 63 | 64 | if(dossl==1||strcmp(Getconfig("dossl"),"yes")==0) 65 | dossl=1; 66 | #else 67 | parse_option(argc,argv,&isdaemon,&portp,&logp); 68 | #endif 69 | 70 | portp==NULL ?(port=atoi(Getconfig("http"))) : (port=atoi(portp)); 71 | 72 | 73 | Signal(SIGCHLD,sigChldHandler); 74 | 75 | 76 | /* init log */ 77 | if(logp==NULL) 78 | logp=Getconfig("log"); 79 | initlog(strcat(tmpcwd,logp)); 80 | 81 | /* whethe show dir */ 82 | if(strcmp(Getconfig("dir"),"no")==0) 83 | isShowdir=0; 84 | 85 | 86 | clientlen = sizeof(clientaddr); 87 | 88 | 89 | if(isdaemon==1||strcmp(Getconfig("daemon"),"yes")==0) 90 | Daemon(1,1); 91 | 92 | writePid(1); 93 | 94 | /* $https start */ 95 | #ifdef HTTPS 96 | if(dossl) 97 | { 98 | if((pid=Fork())==0) 99 | { 100 | listenfd= Open_listenfd(sslport); 101 | ssl_init(); 102 | 103 | while(1) 104 | { 105 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 106 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 107 | { 108 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 109 | continue; 110 | } 111 | 112 | if((pid=Fork())>0) 113 | { 114 | Close(connfd); 115 | continue; 116 | } 117 | else if(pid==0) 118 | { 119 | ishttps=1; 120 | doit(connfd); 121 | exit(1); 122 | } 123 | } 124 | } 125 | } 126 | #endif 127 | 128 | /* $end https */ 129 | 130 | 131 | listenfd = Open_listenfd(port); 132 | while (1) 133 | { 134 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 135 | if(access_ornot(inet_ntoa(clientaddr.sin_addr))==0) 136 | { 137 | clienterror(connfd,"maybe this web server not open to you!" , "403", "Forbidden", "Tiny couldn't read the file"); 138 | continue; 139 | } 140 | 141 | if((pid=Fork())>0) 142 | { 143 | Close(connfd); 144 | continue; 145 | } 146 | else if(pid==0) 147 | { 148 | doit(connfd); 149 | exit(1); 150 | } 151 | } 152 | } 153 | /* $end main */ 154 | 155 | 156 | /*$sigChldHandler to protect zimble process */ 157 | static void sigChldHandler(int signo) 158 | { 159 | Waitpid(-1,NULL,WNOHANG); 160 | return; 161 | } 162 | /*$end sigChldHandler */ 163 | 164 | 165 | /* $begin ssl init */ 166 | #ifdef HTTPS 167 | static void ssl_init(void) 168 | { 169 | static char crypto[]="RC4-MD5"; 170 | certfile=Getconfig("ca"); 171 | 172 | SSL_load_error_strings(); 173 | SSLeay_add_ssl_algorithms(); 174 | ssl_ctx = SSL_CTX_new( SSLv23_server_method() ); 175 | 176 | if ( certfile[0] != '\0' ) 177 | if ( SSL_CTX_use_certificate_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_use_PrivateKey_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_check_private_key( ssl_ctx ) == 0 ) 178 | { 179 | ERR_print_errors_fp( stderr ); 180 | exit( 1 ); 181 | } 182 | if ( crypto != (char*) 0 ) 183 | { 184 | 185 | if ( SSL_CTX_set_cipher_list( ssl_ctx, crypto ) == 0 ) 186 | { 187 | ERR_print_errors_fp( stderr ); 188 | exit( 1 ); 189 | } 190 | } 191 | 192 | } 193 | #endif 194 | /* $end ssl init */ 195 | 196 | 197 | /* 198 | * doit - handle one HTTP request/response transaction 199 | */ 200 | /* $begin doit */ 201 | static void doit(int fd) 202 | { 203 | int is_static,contentLength=0,isGet=1; 204 | struct stat sbuf; 205 | char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; 206 | char filename[MAXLINE], cgiargs[MAXLINE],httpspostdata[MAXLINE]; 207 | rio_t rio; 208 | 209 | memset(buf,0,MAXLINE); 210 | 211 | #ifdef HTTPS 212 | if(ishttps) 213 | { 214 | ssl=SSL_new(ssl_ctx); 215 | SSL_set_fd(ssl,fd); 216 | if(SSL_accept(ssl)==0) 217 | { 218 | ERR_print_errors_fp(stderr); 219 | exit(1); 220 | } 221 | SSL_read(ssl,buf,sizeof(buf)); 222 | } 223 | else 224 | #endif 225 | { 226 | /* Read request line and headers */ 227 | Rio_readinitb(&rio, fd); 228 | Rio_readlineb(&rio, buf, MAXLINE); 229 | } 230 | 231 | sscanf(buf, "%s %s %s", method, uri, version); 232 | 233 | if (strcasecmp(method, "GET")!=0&&strcasecmp(method,"POST")!=0) 234 | { 235 | clienterror(fd, method, "501", "Not Implemented", 236 | "Tiny does not implement this method"); 237 | return; 238 | } 239 | 240 | 241 | /* Parse URI from GET request */ 242 | is_static = parse_uri(uri, filename, cgiargs); 243 | 244 | 245 | if (lstat(filename, &sbuf) < 0) 246 | { 247 | clienterror(fd, filename, "404", "Not found", 248 | "Tiny couldn't find this file"); 249 | return; 250 | } 251 | 252 | if(S_ISDIR(sbuf.st_mode)&&isShowdir) 253 | serve_dir(fd,filename); 254 | 255 | 256 | if (strcasecmp(method, "POST")==0) 257 | isGet=0; 258 | 259 | 260 | if (is_static) 261 | { /* Serve static content */ 262 | 263 | #ifdef HTTPS 264 | if(!ishttps) 265 | #endif 266 | get_requesthdrs(&rio); /* because https already read the headers -> SSL_read() */ 267 | 268 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) 269 | { 270 | clienterror(fd, filename, "403", "Forbidden", 271 | "Tiny couldn't read the file"); 272 | return; 273 | } 274 | serve_static(fd, filename, sbuf.st_size); 275 | } 276 | else 277 | { /* Serve dynamic content */ 278 | if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) 279 | { 280 | clienterror(fd, filename, "403", "Forbidden", 281 | "Tiny couldn't run the CGI program"); 282 | return; 283 | } 284 | 285 | if(isGet) 286 | { 287 | #ifdef HTTPS 288 | if(!ishttps) 289 | #endif 290 | get_requesthdrs(&rio); /* because https already read headers by SSL_read() */ 291 | 292 | get_dynamic(fd, filename, cgiargs); 293 | } 294 | else 295 | { 296 | #ifdef HTTPS 297 | if(ishttps) 298 | https_getlength(buf,&contentLength); 299 | else 300 | #endif 301 | post_requesthdrs(&rio,&contentLength); 302 | 303 | post_dynamic(fd, filename,contentLength,&rio); 304 | } 305 | } 306 | } 307 | /* $end doit */ 308 | 309 | /* $begin https_getlength */ 310 | #ifdef HTTPS 311 | static void https_getlength(char* buf,int* length) 312 | { 313 | char *p,line[MAXLINE]; 314 | char *tmpbuf=buf; 315 | int lengthfind=0; 316 | 317 | while(*tmpbuf!='\0') 318 | { 319 | p=line; 320 | while(*tmpbuf!='\n' && *tmpbuf!='\0') 321 | *p++=*tmpbuf++; 322 | *p='\0'; 323 | if(!lengthfind) 324 | { 325 | if(strncasecmp(line,"Content-Length:",15)==0) 326 | { 327 | p=&line[15]; 328 | p+=strspn(p," \t"); 329 | *length=atoi(p); 330 | lengthfind=1; 331 | } 332 | } 333 | 334 | if(strncasecmp(line,"\r",1)==0) 335 | { 336 | strcpy(httpspostdata,++tmpbuf); 337 | break; 338 | } 339 | ++tmpbuf; 340 | } 341 | return; 342 | } 343 | #endif 344 | /* $end https_getlength */ 345 | 346 | /* 347 | * read_requesthdrs - read and parse HTTP request headers 348 | */ 349 | /* $begin get_requesthdrs */ 350 | static void get_requesthdrs(rio_t *rp) 351 | { 352 | char buf[MAXLINE]; 353 | 354 | Rio_readlineb(rp, buf, MAXLINE); 355 | writetime(); /* write access time in log file */ 356 | //printf("%s", buf); 357 | while(strcmp(buf, "\r\n")) 358 | { 359 | Rio_readlineb(rp, buf, MAXLINE); 360 | writelog(buf); 361 | //printf("%s", buf); 362 | } 363 | return; 364 | } 365 | /* $end get_requesthdrs */ 366 | 367 | /* $begin post_requesthdrs */ 368 | static void post_requesthdrs(rio_t *rp,int *length) 369 | { 370 | char buf[MAXLINE]; 371 | char *p; 372 | 373 | Rio_readlineb(rp, buf, MAXLINE); 374 | writetime(); /* write access time in log file */ 375 | while(strcmp(buf, "\r\n")) 376 | { 377 | Rio_readlineb(rp, buf, MAXLINE); 378 | if(strncasecmp(buf,"Content-Length:",15)==0) 379 | { 380 | p=&buf[15]; 381 | p+=strspn(p," \t"); 382 | *length=atol(p); 383 | } 384 | writelog(buf); 385 | //printf("%s", buf); 386 | } 387 | return; 388 | } 389 | /* $end post_requesthdrs */ 390 | 391 | 392 | /* $begin post_dynamic */ 393 | static void serve_dir(int fd,char *filename) 394 | { 395 | DIR *dp; 396 | struct dirent *dirp; 397 | struct stat sbuf; 398 | struct passwd *filepasswd; 399 | int num=1; 400 | char files[MAXLINE],buf[MAXLINE],name[MAXLINE],img[MAXLINE],modifyTime[MAXLINE],dir[MAXLINE]; 401 | char *p; 402 | 403 | /* 404 | * Start get the dir 405 | * for example: /home/yihaibo/kerner/web/doc/dir -> dir[]="dir/"; 406 | */ 407 | p=strrchr(filename,'/'); 408 | ++p; 409 | strcpy(dir,p); 410 | strcat(dir,"/"); 411 | /* End get the dir */ 412 | 413 | if((dp=opendir(filename))==NULL) 414 | syslog(LOG_ERR,"cannot open dir:%s",filename); 415 | 416 | sprintf(files, "Dir Browser"); 417 | sprintf(files,"%s",files); 418 | sprintf(files, "%s\r\n", files); 419 | 420 | while((dirp=readdir(dp))!=NULL) 421 | { 422 | if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0) 423 | continue; 424 | sprintf(name,"%s/%s",filename,dirp->d_name); 425 | Stat(name,&sbuf); 426 | filepasswd=getpwuid(sbuf.st_uid); 427 | 428 | if(S_ISDIR(sbuf.st_mode)) 429 | { 430 | sprintf(img,""); 431 | } 432 | else if(S_ISFIFO(sbuf.st_mode)) 433 | { 434 | sprintf(img,""); 435 | } 436 | else if(S_ISLNK(sbuf.st_mode)) 437 | { 438 | sprintf(img,""); 439 | } 440 | else if(S_ISSOCK(sbuf.st_mode)) 441 | { 442 | sprintf(img,""); 443 | } 444 | else 445 | sprintf(img,""); 446 | 447 | 448 | sprintf(files,"%s

%-2d %s ""%-15s%-10s%10d %24s

\r\n",files,num++,img,dir,dirp->d_name,dirp->d_name,filepasswd->pw_name,(int)sbuf.st_size,timeModify(sbuf.st_mtime,modifyTime)); 449 | } 450 | closedir(dp); 451 | sprintf(files,"%s",files); 452 | 453 | /* Send response headers to client */ 454 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 455 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 456 | sprintf(buf, "%sContent-length: %d\r\n", buf, strlen(files)); 457 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, "text/html"); 458 | 459 | #ifdef HTTPS 460 | if(ishttps) 461 | { 462 | SSL_write(ssl,buf,strlen(buf)); 463 | SSL_write(ssl,files,strlen(files)); 464 | } 465 | else 466 | #endif 467 | { 468 | Rio_writen(fd, buf, strlen(buf)); 469 | Rio_writen(fd, files, strlen(files)); 470 | } 471 | exit(0); 472 | 473 | } 474 | /* $end serve_dir */ 475 | 476 | 477 | /* $begin post_dynamic */ 478 | static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp) 479 | { 480 | char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE]; 481 | int p[2]; 482 | 483 | #ifdef HTTPS 484 | int httpsp[2]; 485 | #endif 486 | 487 | sprintf(length,"%d",contentLength); 488 | memset(data,0,MAXLINE); 489 | 490 | Pipe(p); 491 | 492 | /* The post data is sended by client,we need to redirct the data to cgi stdin. 493 | * so, child read contentLength bytes data from fp,and write to p[1]; 494 | * parent should redirct p[0] to stdin. As a result, the cgi script can 495 | * read the post data from the stdin. 496 | */ 497 | 498 | /* https already read all data ,include post data by SSL_read() */ 499 | 500 | if (Fork() == 0) 501 | { /* child */ 502 | Close(p[0]); 503 | #ifdef HTTPS 504 | if(ishttps) 505 | { 506 | Write(p[1],httpspostdata,contentLength); 507 | } 508 | else 509 | #endif 510 | { 511 | Rio_readnb(rp,data,contentLength); 512 | Rio_writen(p[1],data,contentLength); 513 | } 514 | exit(0) ; 515 | } 516 | 517 | /* Send response headers to client */ 518 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 519 | sprintf(buf, "%sServer: Tiny Web Server\r\n",buf); 520 | 521 | #ifdef HTTPS 522 | if(ishttps) 523 | SSL_write(ssl,buf,strlen(buf)); 524 | else 525 | #endif 526 | Rio_writen(fd, buf, strlen(buf)); 527 | 528 | //Wait(NULL); 529 | Dup2(p[0],STDIN_FILENO); /* Redirct p[0] to stdin */ 530 | Close(p[0]); 531 | 532 | Close(p[1]); 533 | setenv("CONTENT-LENGTH",length , 1); 534 | 535 | #ifdef HTTPS 536 | if(ishttps) /* if ishttps,we couldnot redirct stdout to client,we must use SSL_write */ 537 | { 538 | Pipe(httpsp); 539 | 540 | if(Fork()==0) 541 | { 542 | Dup2(httpsp[1],STDOUT_FILENO); /* Redirct stdout to https[1] */ 543 | Execve(filename, emptylist, environ); 544 | } 545 | //Wait(NULL); 546 | Read(httpsp[0],data,MAXLINE); 547 | SSL_write(ssl,data,strlen(data)); 548 | } 549 | else 550 | #endif 551 | { 552 | Dup2(fd,STDOUT_FILENO); /* Redirct stdout to client */ 553 | Execve(filename, emptylist, environ); 554 | } 555 | } 556 | /* $end post_dynamic */ 557 | 558 | 559 | 560 | 561 | 562 | /* 563 | * parse_uri - parse URI into filename and CGI args 564 | * return 0 if dynamic content, 1 if static 565 | */ 566 | /* $begin parse_uri */ 567 | static int parse_uri(char *uri, char *filename, char *cgiargs) 568 | { 569 | char *ptr; 570 | char tmpcwd[MAXLINE]; 571 | strcpy(tmpcwd,cwd); 572 | strcat(tmpcwd,"/"); 573 | 574 | if (!strstr(uri, "cgi-bin")) 575 | { /* Static content */ 576 | strcpy(cgiargs, ""); 577 | strcpy(filename, strcat(tmpcwd,Getconfig("root"))); 578 | strcat(filename, uri); 579 | if (uri[strlen(uri)-1] == '/') 580 | strcat(filename, "home.html"); 581 | return 1; 582 | } 583 | else 584 | { /* Dynamic content */ 585 | ptr = index(uri, '?'); 586 | if (ptr) 587 | { 588 | strcpy(cgiargs, ptr+1); 589 | *ptr = '\0'; 590 | } 591 | else 592 | strcpy(cgiargs, ""); 593 | strcpy(filename, cwd); 594 | strcat(filename, uri); 595 | return 0; 596 | } 597 | } 598 | /* $end parse_uri */ 599 | 600 | /* 601 | * serve_static - copy a file back to the client 602 | */ 603 | /* $begin serve_static */ 604 | static void serve_static(int fd, char *filename, int filesize) 605 | { 606 | int srcfd; 607 | char *srcp, filetype[MAXLINE], buf[MAXBUF]; 608 | 609 | /* Send response headers to client */ 610 | get_filetype(filename, filetype); 611 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 612 | sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); 613 | sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); 614 | sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); 615 | 616 | /* Send response body to client */ 617 | srcfd = Open(filename, O_RDONLY, 0); 618 | srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 619 | Close(srcfd); 620 | 621 | #ifdef HTTPS 622 | if(ishttps) 623 | { 624 | SSL_write(ssl, buf, strlen(buf)); 625 | SSL_write(ssl, srcp, filesize); 626 | } 627 | else 628 | #endif 629 | { 630 | Rio_writen(fd, buf, strlen(buf)); 631 | Rio_writen(fd, srcp, filesize); 632 | } 633 | Munmap(srcp, filesize); 634 | } 635 | 636 | /* 637 | * get_filetype - derive file type from file name 638 | */ 639 | static void get_filetype(const char *filename, char *filetype) 640 | { 641 | if (strstr(filename, ".html")) 642 | strcpy(filetype, "text/html"); 643 | else if (strstr(filename, ".gif")) 644 | strcpy(filetype, "image/gif"); 645 | else if (strstr(filename, ".jpg")) 646 | strcpy(filetype, "image/jpeg"); 647 | else if (strstr(filename, ".png")) 648 | strcpy(filetype, "image/png"); 649 | else 650 | strcpy(filetype, "text/plain"); 651 | } 652 | /* $end serve_static */ 653 | 654 | /* 655 | * serve_dynamic - run a CGI program on behalf of the client 656 | */ 657 | /* $begin get_dynamic */ 658 | void get_dynamic(int fd, char *filename, char *cgiargs) 659 | { 660 | char buf[MAXLINE], *emptylist[] = { NULL },httpsbuf[MAXLINE]; 661 | int p[2]; 662 | 663 | /* Return first part of HTTP response */ 664 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 665 | sprintf(buf, "%sServer: Tiny Web Server\r\n",buf); 666 | 667 | #ifdef HTTPS 668 | if(ishttps) 669 | SSL_write(ssl,buf,strlen(buf)); 670 | else 671 | #endif 672 | Rio_writen(fd, buf, strlen(buf)); 673 | 674 | #ifdef HTTPS 675 | if(ishttps) 676 | { 677 | Pipe(p); 678 | if (Fork() == 0) 679 | { /* child */ 680 | Close(p[0]); 681 | setenv("QUERY_STRING", cgiargs, 1); 682 | Dup2(p[1], STDOUT_FILENO); /* Redirect stdout to p[1] */ 683 | Execve(filename, emptylist, environ); /* Run CGI program */ 684 | } 685 | Close(p[1]); 686 | Read(p[0],httpsbuf,MAXLINE); /* parent read from p[0] */ 687 | SSL_write(ssl,httpsbuf,strlen(httpsbuf)); 688 | } 689 | else 690 | #endif 691 | { 692 | if (Fork() == 0) 693 | { /* child */ 694 | /* Real server would set all CGI vars here */ 695 | setenv("QUERY_STRING", cgiargs, 1); 696 | Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ 697 | Execve(filename, emptylist, environ); /* Run CGI program */ 698 | } 699 | } 700 | //Wait(NULL); /* Parent waits for and reaps child */ 701 | } 702 | /* $end get_dynamic */ 703 | 704 | /* 705 | * clienterror - returns an error message to the client 706 | */ 707 | /* $begin clienterror */ 708 | static void clienterror(int fd, char *cause, char *errnum, 709 | char *shortmsg, char *longmsg) 710 | { 711 | char buf[MAXLINE], body[MAXBUF]; 712 | 713 | /* Build the HTTP response body */ 714 | sprintf(body, "Tiny Error"); 715 | sprintf(body, "%s\r\n", body); 716 | sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); 717 | sprintf(body, "%s

%s: %s\r\n", body, longmsg, cause); 718 | sprintf(body, "%s


The Tiny Web server\r\n", body); 719 | 720 | /* Print the HTTP response */ 721 | sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); 722 | sprintf(buf, "%sContent-type: text/html\r\n",buf); 723 | sprintf(buf, "%sContent-length: %d\r\n\r\n",buf,(int)strlen(body)); 724 | 725 | #ifdef HTTPS 726 | if(ishttps) 727 | { 728 | SSL_write(ssl,buf,strlen(buf)); 729 | SSL_write(ssl,body,strlen(body)); 730 | } 731 | else 732 | #endif 733 | { 734 | Rio_writen(fd, buf, strlen(buf)); 735 | Rio_writen(fd, body, strlen(body)); 736 | } 737 | } 738 | /* $end clienterror */ 739 | 740 | 741 | 742 | /* $begin writePid */ 743 | /* if the process is running, the interger in the pid file is the pid, else is -1 */ 744 | static void writePid(int option) 745 | { 746 | int pid; 747 | FILE *fp=Fopen(PID_FILE,"w+"); 748 | if(option) 749 | pid=(int)getpid(); 750 | else 751 | pid=-1; 752 | fprintf(fp,"%d",pid); 753 | Fclose(fp); 754 | } 755 | /* $end writePid */ 756 | -------------------------------------------------------------------------------- /parse.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARSE_CONFIG_H 2 | #define _PARSE_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef HTTPS 19 | #include 20 | #include 21 | #endif 22 | 23 | #define _GNU_SOURCE //enable the getopt_long 24 | #include 25 | 26 | /* daemon_init.c */ 27 | void init_daemon(void); 28 | 29 | /* parse_config.c */ 30 | char* Getconfig(char*); 31 | extern FILE *configfp; 32 | 33 | /*parse_option.c */ 34 | #ifdef HTTPS 35 | void parse_option(int argc,char **argv,char* d,char** portp,char** logp,char** sslp,char* dossl); 36 | #else 37 | void parse_option(int argc,char **argv,char* d,char** portp,char** logp); 38 | #endif 39 | 40 | /* log.c */ 41 | #define MAXLINELEN 8192 42 | extern FILE *logfp; 43 | void initlog(const char* logp); 44 | void writetime(); 45 | void writelog(const char* buf); 46 | char* timeModify(time_t timeval,char *time); 47 | 48 | /* secure_access.c */ 49 | int access_ornot(const char *destip); // 0 -> not 1 -> ok 50 | 51 | /* main.c */ 52 | 53 | 54 | #endif 55 | 56 | -------------------------------------------------------------------------------- /parse_config.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include "wrap.h" 3 | extern char *cwd; 4 | 5 | FILE *configfp=NULL; 6 | static FILE *getfp(char *path) 7 | { 8 | configfp=Fopen(path,"r"); 9 | return configfp; 10 | } 11 | 12 | 13 | static char* getconfig(char* name) 14 | { 15 | /* 16 | pointer meaning: 17 | 18 | ...port...=...8000... 19 | | | | | | 20 | *fs | | | *be f->forward b-> back 21 | *fe | *bs s->start e-> end 22 | *equal 23 | */ 24 | static char info[64]; 25 | int find=0; 26 | char tmp[256],fore[64],back[64],tmpcwd[MAXLINE]; 27 | char *fs,*fe,*equal,*bs,*be,*start; 28 | 29 | strcpy(tmpcwd,cwd); 30 | strcat(tmpcwd,"/"); 31 | FILE *fp=getfp(strcat(tmpcwd,"config.ini")); 32 | while(fgets(tmp,255,fp)!=NULL) 33 | { 34 | start=tmp; 35 | equal=strchr(tmp,'='); 36 | 37 | while(isblank(*start)) 38 | ++start; 39 | fs=start; 40 | 41 | if(*fs=='#') 42 | continue; 43 | while(isalpha(*start)) 44 | ++start; 45 | fe=start-1; 46 | 47 | strncpy(fore,fs,fe-fs+1); 48 | fore[fe-fs+1]='\0'; 49 | if(strcmp(fore,name)!=0) 50 | continue; 51 | find=1; 52 | 53 | start=equal+1; 54 | while(isblank(*start)) 55 | ++start; 56 | bs=start; 57 | 58 | while(!isblank(*start)&&*start!='\n') 59 | ++start; 60 | be=start-1; 61 | 62 | strncpy(back,bs,be-bs+1); 63 | back[be-bs+1]='\0'; 64 | strcpy(info,back); 65 | break; 66 | } 67 | if(find) 68 | return info; 69 | else 70 | return NULL; 71 | } 72 | 73 | char* Getconfig(char* name) 74 | { 75 | char *p=getconfig(name); 76 | if(p==NULL) 77 | { 78 | syslog(LOG_ERR,"there is no %s in the configure",name); 79 | exit(0); 80 | } 81 | else 82 | return p; 83 | } 84 | 85 | /* parse_config test 86 | 87 | int main() 88 | { 89 | char *s=getconfig("port"); 90 | printf("%s\n",s); 91 | 92 | s=getconfig("root"); 93 | printf("%s\n",s); 94 | } 95 | 96 | */ 97 | 98 | 99 | -------------------------------------------------------------------------------- /parse_option.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | 3 | /* parse the command option 4 | -d(--daemon) daemon process 5 | -p(--port) assign http port 6 | -s(--port) assign https port 7 | -l(--log) log path 8 | */ 9 | 10 | static void usage(void) 11 | { 12 | fprintf(stderr,"usage:./main [-d --daemon] [-p --port] [-s --sslport] [-l --log] [-v --version] [-h --help]\n\n"); 13 | exit(1); 14 | } 15 | 16 | static void version(void) 17 | { 18 | fprintf(stderr,"版本:1.0\n功能:web服务器的实现\n" 19 | "提供GET,POST功能\n" 20 | "实现SSL安全连接\n" 21 | "提供目录访问和简单的访问控制\n\n" 22 | "作者:...\n\n" 23 | "SSL实现:基于OPENSSL库\n\n" 24 | ); 25 | exit(1); 26 | } 27 | 28 | /* $start parse_option */ 29 | #ifdef HTTPS 30 | void parse_option(int argc,char **argv,char* d,char** portp,char **logp,char** sslp,char* dossl) 31 | #else 32 | void parse_option(int argc,char **argv,char* d,char** portp,char **logp) 33 | #endif 34 | { 35 | int opt; 36 | static char port[16]; 37 | #ifdef HTTPS 38 | static char sslport[16]; 39 | #endif 40 | static char log[64]; 41 | 42 | struct option longopts[]={ 43 | {"daemon",0,NULL,'d'}, /* 0->hasn't arg 1-> has arg */ 44 | {"port",1,NULL,'p'}, 45 | #ifdef HTTPS 46 | {"sslport",1,NULL,'s'}, 47 | {"extent",0,NULL,'e'}, /* extent function -> https */ 48 | #endif 49 | {"log",1,NULL,'l'}, 50 | {"help",0,NULL,'h'}, 51 | {"version",0,NULL,'v'}, 52 | {0,0,0,0}}; /* the last must be a zero array */ 53 | 54 | #ifdef HTTPS 55 | while((opt=getopt_long(argc,argv,":dp:s:l:ehv",longopts,NULL))!=-1) 56 | #else 57 | while((opt=getopt_long(argc,argv,":dp:l:hv",longopts,NULL))!=-1) 58 | #endif 59 | { 60 | switch(opt) 61 | { 62 | case 'd': 63 | *d=1; 64 | break; 65 | case 'p': 66 | strncpy(port,optarg,15); 67 | *portp=port; 68 | break; 69 | #ifdef HTTPS 70 | case 's': 71 | strncpy(sslport,optarg,15); 72 | *sslp=sslport; 73 | break; 74 | case 'e': 75 | *dossl=1; 76 | break; 77 | #endif 78 | case 'l': 79 | strncpy(log,optarg,63); 80 | *logp=log; 81 | break; 82 | case ':': 83 | fprintf(stderr,"-%c:option needs a value.\n",optopt); 84 | exit(1); 85 | break; 86 | case 'h': 87 | usage(); 88 | break; 89 | case 'v': 90 | version(); 91 | break; 92 | case '?': 93 | fprintf(stderr,"unknown option:%c\n",optopt); 94 | usage(); 95 | break; 96 | } 97 | } 98 | } 99 | /* $end parse_option */ 100 | 101 | 102 | 103 | /* parse_option test 104 | int main(int argc,char **argv) 105 | { 106 | 107 | char d=0,*p=NULL; 108 | 109 | parse_option(argc,argv,&d,&p); 110 | if(d==1) 111 | printf("daemon\n"); 112 | if(p!=NULL) 113 | printf("%s\n",p); 114 | 115 | } 116 | */ 117 | -------------------------------------------------------------------------------- /pid.file: -------------------------------------------------------------------------------- 1 | 2169 -------------------------------------------------------------------------------- /secure_access.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | 3 | /* 4 | * Function: can accesser access this web or not 5 | * e.g. the seg ip address: 192.168.1.0/255.255.255.0 6 | * accesser ip: 192.168.1.2 & 255.255.255.0 ?= 192.168.1.0 7 | */ 8 | 9 | 10 | /* 11 | * Function: a ip address effective or not 12 | * return value : -1 error 13 | */ 14 | 15 | 16 | /* 17 | * Function: convert ip to long long 18 | */ 19 | static long long ipadd_to_longlong(const char *ip) 20 | { 21 | const char *p=ip; 22 | int ge,shi,bai,qian; 23 | qian=atoi(p); 24 | 25 | p=strchr(p,'.')+1; 26 | bai=atoi(p); 27 | 28 | p=strchr(p,'.')+1; 29 | shi=atoi(p); 30 | 31 | p=strchr(p,'.')+1; 32 | ge=atoi(p); 33 | 34 | return (qian<<24)+(bai<<16)+(shi<<8)+ge; 35 | } 36 | 37 | 38 | int access_ornot(const char *destip) // 0 -> not 1 -> ok 39 | { 40 | //192.168.1/255.255.255.0 41 | 42 | char ipinfo[16],maskinfo[16]; 43 | char *p,*ip=ipinfo,*mask=maskinfo; 44 | char count=0; 45 | char *maskget=Getconfig("mask"); 46 | const char *destipconst,*ipinfoconst,*maskinfoconst; 47 | if(maskget=="") 48 | { 49 | printf("ok:%s\n",maskget); 50 | return 1; 51 | } 52 | p=maskget; 53 | 54 | /* get ipinfo[] start */ 55 | 56 | while(*p!='/') 57 | { 58 | if(*p=='.') 59 | ++count; 60 | *ip++=*p++; 61 | } 62 | 63 | while(count<3) 64 | { 65 | *ip++='.'; 66 | *ip++='0'; 67 | ++count; 68 | } 69 | *ip='\0'; 70 | 71 | /* get ipinfo[] end */ 72 | 73 | /* get maskinfo[] start */ 74 | 75 | ++p; 76 | while(*p!='\0') 77 | { 78 | if(*p=='.') 79 | ++count; 80 | *mask++=*p++; 81 | } 82 | 83 | while(count<3) 84 | { 85 | *mask++='.'; 86 | *mask++='0'; 87 | ++count; 88 | } 89 | *mask='\0'; 90 | 91 | /* get maskinfo[] end */ 92 | destipconst=destip; 93 | ipinfoconst=ipinfo; 94 | maskinfoconst=maskinfo; 95 | 96 | return ipadd_to_longlong(ipinfoconst)==(ipadd_to_longlong(maskinfoconst)&ipadd_to_longlong(destipconst)); 97 | } 98 | 99 | /* access_ornot test 100 | 101 | int main() 102 | { 103 | printf("%d\n",access_ornot("127.0.0.1")); 104 | } 105 | 106 | */ 107 | -------------------------------------------------------------------------------- /webd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycrab/Linux-C-Web-Server/942e196ef54528bde2e44566dbf50e14b82f66be/webd -------------------------------------------------------------------------------- /webserver.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | PName='webd' 4 | Grep='grep' 5 | Echo='echo' 6 | Skill='skill' 7 | 8 | Running=0 9 | 10 | run() 11 | { 12 | Command=`ps aux | grep -v grep | grep -c $PName ` 13 | 14 | if [ $Command -eq 0 ];then 15 | Running=0 16 | else 17 | Running=1 18 | fi 19 | } 20 | 21 | start() 22 | { 23 | run 24 | 25 | if [ $Running -eq 0 ];then 26 | ./$PName 27 | $Echo "$PName is running" 28 | else 29 | $Echo "$PName is running" 30 | fi 31 | } 32 | 33 | stop() 34 | { 35 | run 36 | 37 | if [ $Running -eq 1 ];then 38 | $Skill -KILL $PName 39 | $Echo "$PName is stopped" 40 | else 41 | $Echo "$PName is stopped" 42 | fi 43 | } 44 | 45 | 46 | status() 47 | { 48 | run 49 | 50 | if [ $Running -eq 0 ];then 51 | $Echo "$PName is stopped" 52 | else 53 | $Echo "$PName is running" 54 | fi 55 | 56 | } 57 | 58 | case "$1" in 59 | start) 60 | start 61 | ;; 62 | stop) 63 | stop 64 | ;; 65 | restart|reload) 66 | stop && start 67 | ;; 68 | status) 69 | status 70 | ;; 71 | *) 72 | echo "Usage: $0 {start|stop|restart|reload|status}" 73 | exit 1 74 | esac 75 | -------------------------------------------------------------------------------- /wrap.c: -------------------------------------------------------------------------------- 1 | #include "wrap.h" 2 | 3 | /************************** 4 | * Error-handling functions 5 | **************************/ 6 | /* $begin errorfuns */ 7 | /* $begin unixerror */ 8 | void unix_error(char *msg) /* unix-style error */ 9 | { 10 | fprintf(stderr, "%s: %s\n", msg, strerror(errno)); 11 | exit(0); 12 | } 13 | /* $end unixerror */ 14 | 15 | 16 | void dns_error(char *msg) /* dns-style error */ 17 | { 18 | fprintf(stderr, "%s: DNS error %d\n", msg, h_errno); 19 | exit(0); 20 | } 21 | 22 | /* $end errorfuns */ 23 | 24 | /********************************************* 25 | * Wrappers for Unix process control functions 26 | ********************************************/ 27 | 28 | /* $begin forkwrapper */ 29 | pid_t Fork(void) 30 | { 31 | pid_t pid; 32 | 33 | if ((pid = fork()) < 0) 34 | { 35 | syslog(LOG_CRIT,"Fork error"); 36 | unix_error("Fork error"); 37 | } 38 | return pid; 39 | } 40 | /* $end forkwrapper */ 41 | 42 | void Execve(const char *filename, char *const argv[], char *const envp[]) 43 | { 44 | if (execve(filename, argv, envp) < 0) 45 | { 46 | syslog(LOG_CRIT,"Execve error"); 47 | unix_error("Execve error"); 48 | } 49 | } 50 | 51 | /* $begin wait */ 52 | pid_t Wait(int *status) 53 | { 54 | pid_t pid; 55 | 56 | if ((pid = wait(status)) < 0) 57 | { 58 | syslog(LOG_CRIT,"Wait error"); 59 | unix_error("Wait error"); 60 | } 61 | return pid; 62 | } 63 | /* $end wait */ 64 | 65 | pid_t Waitpid(pid_t pid, int *iptr, int options) 66 | { 67 | pid_t retpid; 68 | 69 | if ((retpid = waitpid(pid, iptr, options)) < 0) 70 | { 71 | syslog(LOG_CRIT,"Waitpid error"); 72 | unix_error("Waitpid error"); 73 | } 74 | return(retpid); 75 | } 76 | 77 | /* $begin kill */ 78 | void Kill(pid_t pid, int signum) 79 | { 80 | int rc; 81 | 82 | if ((rc = kill(pid, signum)) < 0) 83 | { 84 | syslog(LOG_CRIT,"Kill error"); 85 | unix_error("Kill error"); 86 | } 87 | } 88 | /* $end kill */ 89 | 90 | unsigned int Sleep(unsigned int secs) 91 | { 92 | unsigned int rc; 93 | 94 | if ((rc = sleep(secs)) < 0) 95 | { 96 | syslog(LOG_CRIT,"Sleep error"); 97 | unix_error("Sleep error"); 98 | } 99 | return rc; 100 | } 101 | 102 | 103 | 104 | /************************************ 105 | * Wrappers for Unix signal functions 106 | ***********************************/ 107 | 108 | /* $begin sigaction */ 109 | handler_t *Signal(int signum, handler_t *handler) 110 | { 111 | struct sigaction action, old_action; 112 | 113 | action.sa_handler = handler; 114 | sigemptyset(&action.sa_mask); /* block sigs of type being handled */ 115 | action.sa_flags = SA_RESTART; /* restart syscalls if possible */ 116 | 117 | if (sigaction(signum, &action, &old_action) < 0) 118 | { 119 | syslog(LOG_CRIT,"Signal error"); 120 | unix_error("Signal error"); 121 | } 122 | return (old_action.sa_handler); 123 | } 124 | /* $end sigaction */ 125 | 126 | void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) 127 | { 128 | if (sigprocmask(how, set, oldset) < 0) 129 | { 130 | syslog(LOG_CRIT,"Sigprocmask error"); 131 | unix_error("Sigprocmask error"); 132 | } 133 | return; 134 | } 135 | 136 | void Sigemptyset(sigset_t *set) 137 | { 138 | if (sigemptyset(set) < 0) 139 | { 140 | syslog(LOG_CRIT,"Sigemptyset error"); 141 | unix_error("Sigemptyset error"); 142 | } 143 | return; 144 | } 145 | 146 | void Sigfillset(sigset_t *set) 147 | { 148 | if (sigfillset(set) < 0) 149 | { 150 | syslog(LOG_CRIT,"Sigfillset error"); 151 | unix_error("Sigfillset error"); 152 | } 153 | return; 154 | } 155 | 156 | void Sigaddset(sigset_t *set, int signum) 157 | { 158 | if (sigaddset(set, signum) < 0) 159 | { 160 | syslog(LOG_CRIT,"Sigaddset error"); 161 | unix_error("Sigaddset error"); 162 | } 163 | return; 164 | } 165 | 166 | void Sigdelset(sigset_t *set, int signum) 167 | { 168 | if (sigdelset(set, signum) < 0) 169 | { 170 | syslog(LOG_CRIT,"Sigdelset error"); 171 | unix_error("Sigdelset error"); 172 | } 173 | return; 174 | } 175 | 176 | int Sigismember(const sigset_t *set, int signum) 177 | { 178 | int rc; 179 | if ((rc = sigismember(set, signum)) < 0) 180 | { 181 | syslog(LOG_CRIT,"Sigmember error"); 182 | unix_error("Sigismember error"); 183 | } 184 | return rc; 185 | } 186 | 187 | 188 | /******************************** 189 | * Wrappers for Unix I/O routines 190 | ********************************/ 191 | 192 | int Open(const char *pathname, int flags, mode_t mode) 193 | { 194 | int rc; 195 | 196 | if ((rc = open(pathname, flags, mode)) < 0) 197 | { 198 | syslog(LOG_CRIT,"Open %s error",pathname); 199 | unix_error("Open error"); 200 | } 201 | return rc; 202 | } 203 | 204 | ssize_t Read(int fd, void *buf, size_t count) 205 | { 206 | ssize_t rc; 207 | 208 | if ((rc = read(fd, buf, count)) < 0) 209 | { 210 | syslog(LOG_CRIT,"Read error"); 211 | unix_error("Read error"); 212 | } 213 | return rc; 214 | } 215 | 216 | ssize_t Write(int fd, const void *buf, size_t count) 217 | { 218 | ssize_t rc; 219 | 220 | if ((rc = write(fd, buf, count)) < 0) 221 | { 222 | syslog(LOG_CRIT,"Write error"); 223 | unix_error("Write error"); 224 | } 225 | return rc; 226 | } 227 | 228 | void Close(int fd) 229 | { 230 | int rc; 231 | 232 | if ((rc = close(fd)) < 0) 233 | { 234 | syslog(LOG_CRIT,"Close error"); 235 | unix_error("Close error"); 236 | } 237 | } 238 | 239 | 240 | int Dup2(int fd1, int fd2) 241 | { 242 | int rc; 243 | 244 | if ((rc = dup2(fd1, fd2)) < 0) 245 | { 246 | syslog(LOG_CRIT,"Dup2 error"); 247 | unix_error("Dup2 error"); 248 | } 249 | return rc; 250 | } 251 | 252 | void Stat(const char *filename, struct stat *buf) 253 | { 254 | if (stat(filename, buf) < 0) 255 | { 256 | syslog(LOG_CRIT,"Stat error"); 257 | unix_error("Stat error"); 258 | } 259 | } 260 | 261 | 262 | /*************************************** 263 | * Wrappers for memory mapping functions 264 | ***************************************/ 265 | void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 266 | { 267 | void *ptr; 268 | 269 | if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1)) 270 | { 271 | syslog(LOG_CRIT,"Mmap error"); 272 | unix_error("mmap error"); 273 | } 274 | return(ptr); 275 | } 276 | 277 | void Munmap(void *start, size_t length) 278 | { 279 | if (munmap(start, length) < 0) 280 | { 281 | syslog(LOG_CRIT,"Munmap error"); 282 | unix_error("munmap error"); 283 | } 284 | } 285 | 286 | 287 | /****************************************** 288 | * Wrappers for the Standard I/O functions. 289 | ******************************************/ 290 | void Fclose(FILE *fp) 291 | { 292 | if (fclose(fp) != 0) 293 | { 294 | syslog(LOG_CRIT,"Fclose error"); 295 | unix_error("Fclose error"); 296 | } 297 | } 298 | 299 | 300 | FILE *Fopen(const char *filename, const char *mode) 301 | { 302 | FILE *fp; 303 | 304 | if ((fp = fopen(filename, mode)) == NULL) 305 | { 306 | syslog(LOG_CRIT,"Fopen %s error",filename); 307 | unix_error("Fopen error"); 308 | } 309 | 310 | return fp; 311 | } 312 | 313 | void Fputs(const char *ptr, FILE *stream) 314 | { 315 | if (fputs(ptr, stream) == EOF) 316 | { 317 | syslog(LOG_CRIT,"Fputs error"); 318 | unix_error("Fputs error"); 319 | } 320 | } 321 | 322 | size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 323 | { 324 | size_t n; 325 | 326 | if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream)) 327 | { 328 | syslog(LOG_CRIT,"Fread error"); 329 | unix_error("Fread error"); 330 | } 331 | return n; 332 | } 333 | 334 | void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 335 | { 336 | if (fwrite(ptr, size, nmemb, stream) < nmemb) 337 | { 338 | syslog(LOG_CRIT,"Fwrite error"); 339 | unix_error("Fwrite error"); 340 | } 341 | } 342 | 343 | 344 | /**************************** 345 | * Sockets interface wrappers 346 | ****************************/ 347 | 348 | int Socket(int domain, int type, int protocol) 349 | { 350 | int rc; 351 | 352 | if ((rc = socket(domain, type, protocol)) < 0) 353 | { 354 | syslog(LOG_CRIT,"Socket error"); 355 | unix_error("Socket error"); 356 | } 357 | return rc; 358 | } 359 | 360 | void Setsockopt(int s, int level, int optname, const void *optval, int optlen) 361 | { 362 | int rc; 363 | 364 | if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0) 365 | { 366 | syslog(LOG_CRIT,"Setsockopt error"); 367 | unix_error("Setsockopt error"); 368 | } 369 | } 370 | 371 | void Bind(int sockfd, struct sockaddr *my_addr, int addrlen) 372 | { 373 | int rc; 374 | 375 | if ((rc = bind(sockfd, my_addr, addrlen)) < 0) 376 | { 377 | syslog(LOG_CRIT,"Bind error"); 378 | unix_error("Bind error"); 379 | } 380 | } 381 | 382 | void Listen(int s, int backlog) 383 | { 384 | int rc; 385 | 386 | if ((rc = listen(s, backlog)) < 0) 387 | { 388 | syslog(LOG_CRIT,"Listen error"); 389 | unix_error("Listen error"); 390 | } 391 | } 392 | 393 | int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) 394 | { 395 | int rc; 396 | 397 | if ((rc = accept(s, addr, addrlen)) < 0) 398 | { 399 | syslog(LOG_CRIT,"Accept error"); 400 | unix_error("Accept error"); 401 | } 402 | return rc; 403 | } 404 | 405 | void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen) 406 | { 407 | int rc; 408 | 409 | if ((rc = connect(sockfd, serv_addr, addrlen)) < 0) 410 | { 411 | syslog(LOG_CRIT,"Connect error"); 412 | unix_error("Connect error"); 413 | } 414 | } 415 | 416 | /************************ 417 | * DNS interface wrappers 418 | ***********************/ 419 | 420 | /* $begin gethostbyname */ 421 | struct hostent *Gethostbyname(const char *name) 422 | { 423 | struct hostent *p; 424 | 425 | if ((p = gethostbyname(name)) == NULL) 426 | { 427 | syslog(LOG_CRIT,"Gethostbyname error"); 428 | dns_error("Gethostbyname error"); 429 | } 430 | return p; 431 | } 432 | /* $end gethostbyname */ 433 | 434 | struct hostent *Gethostbyaddr(const char *addr, int len, int type) 435 | { 436 | struct hostent *p; 437 | 438 | if ((p = gethostbyaddr(addr, len, type)) == NULL) 439 | { 440 | syslog(LOG_CRIT,"Gethostbyaddr error"); 441 | dns_error("Gethostbyaddr error"); 442 | } 443 | return p; 444 | } 445 | 446 | 447 | /********************************************************************* 448 | * The Rio package - robust I/O functions 449 | **********************************************************************/ 450 | /* 451 | * rio_readn - robustly read n bytes (unbuffered) 452 | */ 453 | /* $begin rio_readn */ 454 | ssize_t rio_readn(int fd, void *usrbuf, size_t n) 455 | { 456 | size_t nleft = n; 457 | ssize_t nread; 458 | char *bufp = usrbuf; 459 | 460 | while (nleft > 0) { 461 | if ((nread = read(fd, bufp, nleft)) < 0) { 462 | if (errno == EINTR) /* interrupted by sig handler return */ 463 | nread = 0; /* and call read() again */ 464 | else 465 | return -1; /* errno set by read() */ 466 | } 467 | else if (nread == 0) 468 | break; /* EOF */ 469 | nleft -= nread; 470 | bufp += nread; 471 | } 472 | return (n - nleft); /* return >= 0 */ 473 | } 474 | /* $end rio_readn */ 475 | 476 | /* 477 | * rio_writen - robustly write n bytes (unbuffered) 478 | */ 479 | /* $begin rio_writen */ 480 | ssize_t rio_writen(int fd, void *usrbuf, size_t n) 481 | { 482 | size_t nleft = n; 483 | ssize_t nwritten; 484 | char *bufp = usrbuf; 485 | 486 | while (nleft > 0) { 487 | if ((nwritten = write(fd, bufp, nleft)) <= 0) { 488 | if (errno == EINTR) /* interrupted by sig handler return */ 489 | nwritten = 0; /* and call write() again */ 490 | else 491 | return -1; /* errorno set by write() */ 492 | } 493 | nleft -= nwritten; 494 | bufp += nwritten; 495 | } 496 | return n; 497 | } 498 | /* $end rio_writen */ 499 | 500 | 501 | /* 502 | * rio_read - This is a wrapper for the Unix read() function that 503 | * transfers min(n, rio_cnt) bytes from an internal buffer to a user 504 | * buffer, where n is the number of bytes requested by the user and 505 | * rio_cnt is the number of unread bytes in the internal buffer. On 506 | * entry, rio_read() refills the internal buffer via a call to 507 | * read() if the internal buffer is empty. 508 | */ 509 | /* $begin rio_read */ 510 | static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n) 511 | { 512 | int cnt; 513 | 514 | while (rp->rio_cnt <= 0) { /* refill if buf is empty */ 515 | rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, 516 | sizeof(rp->rio_buf)); 517 | if (rp->rio_cnt < 0) { 518 | if (errno != EINTR) /* interrupted by sig handler return */ 519 | return -1; 520 | } 521 | else if (rp->rio_cnt == 0) /* EOF */ 522 | return 0; 523 | else 524 | rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */ 525 | } 526 | 527 | /* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */ 528 | cnt = n; 529 | if (rp->rio_cnt < n) 530 | cnt = rp->rio_cnt; 531 | memcpy(usrbuf, rp->rio_bufptr, cnt); 532 | rp->rio_bufptr += cnt; 533 | rp->rio_cnt -= cnt; 534 | return cnt; 535 | } 536 | /* $end rio_read */ 537 | 538 | /* 539 | * rio_readinitb - Associate a descriptor with a read buffer and reset buffer 540 | */ 541 | /* $begin rio_readinitb */ 542 | void rio_readinitb(rio_t *rp, int fd) 543 | { 544 | rp->rio_fd = fd; 545 | rp->rio_cnt = 0; 546 | rp->rio_bufptr = rp->rio_buf; 547 | } 548 | /* $end rio_readinitb */ 549 | 550 | /* 551 | * rio_readnb - Robustly read n bytes (buffered) 552 | */ 553 | /* $begin rio_readnb */ 554 | ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) 555 | { 556 | size_t nleft = n; 557 | ssize_t nread; 558 | char *bufp = usrbuf; 559 | 560 | while (nleft > 0) { 561 | if ((nread = rio_read(rp, bufp, nleft)) < 0) { 562 | if (errno == EINTR) /* interrupted by sig handler return */ 563 | nread = 0; /* call read() again */ 564 | else 565 | return -1; /* errno set by read() */ 566 | } 567 | else if (nread == 0) 568 | break; /* EOF */ 569 | nleft -= nread; 570 | bufp += nread; 571 | } 572 | return (n - nleft); /* return >= 0 */ 573 | } 574 | /* $end rio_readnb */ 575 | 576 | /* 577 | * rio_readlineb - robustly read a text line (buffered) 578 | */ 579 | /* $begin rio_readlineb */ 580 | ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) 581 | { 582 | int n, rc; 583 | char c, *bufp = usrbuf; 584 | 585 | for (n = 1; n < maxlen; n++) { 586 | if ((rc = rio_read(rp, &c, 1)) == 1) { 587 | *bufp++ = c; 588 | if (c == '\n') 589 | break; 590 | } else if (rc == 0) { 591 | if (n == 1) 592 | return 0; /* EOF, no data read */ 593 | else 594 | break; /* EOF, some data was read */ 595 | } else 596 | return -1; /* error */ 597 | } 598 | *bufp = 0; 599 | return n; 600 | } 601 | /* $end rio_readlineb */ 602 | 603 | /********************************** 604 | * Wrappers for robust I/O routines 605 | **********************************/ 606 | ssize_t Rio_readn(int fd, void *ptr, size_t nbytes) 607 | { 608 | ssize_t n; 609 | 610 | if ((n = rio_readn(fd, ptr, nbytes)) < 0) 611 | { 612 | syslog(LOG_CRIT,"Rio_readn error"); 613 | unix_error("Rio_readn error"); 614 | } 615 | return n; 616 | } 617 | 618 | void Rio_writen(int fd, void *usrbuf, size_t n) 619 | { 620 | if (rio_writen(fd, usrbuf, n) != n) 621 | { 622 | syslog(LOG_CRIT,"Rio_writen error"); 623 | unix_error("Rio_writen error"); 624 | } 625 | } 626 | 627 | void Rio_readinitb(rio_t *rp, int fd) 628 | { 629 | rio_readinitb(rp, fd); 630 | } 631 | 632 | ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n) 633 | { 634 | ssize_t rc; 635 | 636 | if ((rc = rio_readnb(rp, usrbuf, n)) < 0) 637 | { 638 | syslog(LOG_CRIT,"Rio_readnb error"); 639 | unix_error("Rio_readnb error"); 640 | } 641 | return rc; 642 | } 643 | 644 | ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) 645 | { 646 | ssize_t rc; 647 | 648 | if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0) 649 | { 650 | syslog(LOG_CRIT,"Rio_readlineb error"); 651 | unix_error("Rio_readlineb error"); 652 | } 653 | return rc; 654 | } 655 | 656 | /******************************** 657 | * Client/server helper functions 658 | ********************************/ 659 | /* 660 | * open_clientfd - open connection to server at 661 | * and return a socket descriptor ready for reading and writing. 662 | * Returns -1 and sets errno on Unix error. 663 | * Returns -2 and sets h_errno on DNS (gethostbyname) error. 664 | */ 665 | /* $begin open_clientfd */ 666 | int open_clientfd(char *hostname, int port) 667 | { 668 | int clientfd; 669 | struct hostent *hp; 670 | struct sockaddr_in serveraddr; 671 | 672 | if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 673 | return -1; /* check errno for cause of error */ 674 | 675 | /* Fill in the server's IP address and port */ 676 | if ((hp = gethostbyname(hostname)) == NULL) 677 | return -2; /* check h_errno for cause of error */ 678 | bzero((char *) &serveraddr, sizeof(serveraddr)); 679 | serveraddr.sin_family = AF_INET; 680 | bcopy((char *)hp->h_addr_list[0], 681 | (char *)&serveraddr.sin_addr.s_addr, hp->h_length); 682 | serveraddr.sin_port = htons(port); 683 | 684 | /* Establish a connection with the server */ 685 | if (connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)) < 0) 686 | return -1; 687 | return clientfd; 688 | } 689 | /* $end open_clientfd */ 690 | 691 | /* 692 | * open_listenfd - open and return a listening socket on port 693 | * Returns -1 and sets errno on Unix error. 694 | */ 695 | /* $begin open_listenfd */ 696 | int open_listenfd(int port) 697 | { 698 | int listenfd, optval=1; 699 | struct sockaddr_in serveraddr; 700 | 701 | /* Create a socket descriptor */ 702 | if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 703 | return -1; 704 | 705 | /* Eliminates "Address already in use" error from bind. */ 706 | if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, 707 | (const void *)&optval , sizeof(int)) < 0) 708 | return -1; 709 | 710 | /* Listenfd will be an endpoint for all requests to port 711 | on any IP address for this host */ 712 | bzero((char *) &serveraddr, sizeof(serveraddr)); 713 | serveraddr.sin_family = AF_INET; 714 | serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 715 | serveraddr.sin_port = htons((unsigned short)port); 716 | if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0) 717 | return -1; 718 | 719 | /* Make it a listening socket ready to accept connection requests */ 720 | if (listen(listenfd, LISTENQ) < 0) 721 | return -1; 722 | return listenfd; 723 | } 724 | /* $end open_listenfd */ 725 | 726 | /****************************************** 727 | * Wrappers for the client/server helper routines 728 | ******************************************/ 729 | int Open_clientfd(char *hostname, int port) 730 | { 731 | int rc; 732 | 733 | if ((rc = open_clientfd(hostname, port)) < 0) { 734 | if (rc == -1) 735 | { 736 | syslog(LOG_CRIT,"Open_clientfd Unix error"); 737 | unix_error("Open_clientfd Unix error"); 738 | } 739 | else 740 | { 741 | syslog(LOG_CRIT,"Open_clientfd NDS error"); 742 | dns_error("Open_clientfd DNS error"); 743 | } 744 | } 745 | return rc; 746 | } 747 | 748 | int Open_listenfd(int port) 749 | { 750 | int rc; 751 | 752 | if ((rc = open_listenfd(port)) < 0) 753 | { 754 | syslog(LOG_CRIT,"Open_listentfd error"); 755 | unix_error("Open_listenfd error"); 756 | } 757 | return rc; 758 | } 759 | 760 | 761 | /****************************************** 762 | * Wrappers for others 763 | ******************************************/ 764 | 765 | int Daemon(int nochdir, int noclose) 766 | { 767 | if(daemon(nochdir,noclose)<0) 768 | { 769 | syslog(LOG_CRIT,"daemon error"); 770 | unix_error("Daemon error"); 771 | } 772 | } 773 | 774 | struct passwd *Getpwnam(const char *name) 775 | { 776 | struct passwd* pwd; 777 | pwd = getpwnam(name); 778 | if ( pwd == (struct passwd*) 0 ) 779 | { 780 | syslog(LOG_CRIT,"unknown user: '%s'",name); 781 | unix_error("unknown user"); 782 | } 783 | return pwd; 784 | 785 | } 786 | int Fchown(int fd, uid_t owner, gid_t group) 787 | { 788 | if(fchown(fd,owner,group)<0) 789 | { 790 | syslog(LOG_WARNING,"fchown logfile error"); 791 | unix_error("fchown logfile error"); 792 | } 793 | return 1; 794 | } 795 | 796 | int Setgroups(size_t size, const gid_t *list) 797 | { 798 | if(setgroups(size,list)<0) 799 | { 800 | syslog(LOG_CRIT,"setgroups error"); 801 | unix_error("setgroups error"); 802 | } 803 | return 1; 804 | } 805 | 806 | int Setgid(gid_t gid) 807 | { 808 | if(setgid(gid)<0) 809 | { 810 | syslog(LOG_CRIT,"setgid error"); 811 | unix_error("setgid error"); 812 | } 813 | return 1; 814 | } 815 | 816 | int Initgroups(const char *user, gid_t group) 817 | { 818 | if(initgroups(user,group)<0) 819 | { 820 | syslog(LOG_CRIT,"initgroups error"); 821 | perror("initgroups error"); 822 | } 823 | return 1; 824 | } 825 | 826 | int Setuid(uid_t uid) 827 | { 828 | if(setuid(uid)<0) 829 | { 830 | syslog(LOG_CRIT,"setuid error"); 831 | unix_error("setuid error"); 832 | } 833 | return 1; 834 | } 835 | 836 | int Pipe(int pipefd[2]) 837 | { 838 | if(pipe(pipefd)==-1) 839 | { 840 | syslog(LOG_ERR,"Pipe error"); 841 | unix_error("Pipe error"); 842 | } 843 | return 1; 844 | } 845 | 846 | 847 | -------------------------------------------------------------------------------- /wrap.h: -------------------------------------------------------------------------------- 1 | #ifndef __WRAP_H__ 2 | #define __WRAP_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | /* Default file permissions are DEF_MODE & ~DEF_UMASK */ 31 | /* $begin createmasks */ 32 | #define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH 33 | #define DEF_UMASK S_IWGRP|S_IWOTH 34 | /* $end createmasks */ 35 | 36 | /* Simplifies calls to bind(), connect(), and accept() */ 37 | /* $begin sockaddrdef */ 38 | typedef struct sockaddr SA; 39 | /* $end sockaddrdef */ 40 | 41 | /* Persistent state for the robust I/O (Rio) package */ 42 | /* $begin rio_t */ 43 | #define RIO_BUFSIZE 8192 44 | typedef struct { 45 | int rio_fd; /* descriptor for this internal buf */ 46 | int rio_cnt; /* unread bytes in internal buf */ 47 | char *rio_bufptr; /* next unread byte in internal buf */ 48 | char rio_buf[RIO_BUFSIZE]; /* internal buffer */ 49 | } rio_t; 50 | /* $end rio_t */ 51 | 52 | /* External variables */ 53 | extern int h_errno; /* defined by BIND for DNS errors */ 54 | extern char **environ; /* defined by libc */ 55 | 56 | /* Misc constants */ 57 | #define MAXLINE 8192 /* max text line length */ 58 | #define MAXBUF 8192 /* max I/O buffer size */ 59 | #define LISTENQ 1024 /* second argument to listen() */ 60 | 61 | /* Our own error-handling functions */ 62 | void unix_error(char *msg); 63 | void dns_error(char *msg); 64 | 65 | /* Process control wrappers */ 66 | pid_t Fork(void); 67 | void Execve(const char *filename, char *const argv[], char *const envp[]); 68 | pid_t Wait(int *status); 69 | pid_t Waitpid(pid_t pid, int *iptr, int options); 70 | void Kill(pid_t pid, int signum); 71 | unsigned int Sleep(unsigned int secs); 72 | 73 | /* Signal wrappers */ 74 | typedef void handler_t(int); 75 | handler_t *Signal(int signum, handler_t *handler); 76 | void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 77 | void Sigemptyset(sigset_t *set); 78 | void Sigfillset(sigset_t *set); 79 | void Sigaddset(sigset_t *set, int signum); 80 | void Sigdelset(sigset_t *set, int signum); 81 | int Sigismember(const sigset_t *set, int signum); 82 | 83 | /* Unix I/O wrappers */ 84 | int Open(const char *pathname, int flags, mode_t mode); 85 | ssize_t Read(int fd, void *buf, size_t count); 86 | ssize_t Write(int fd, const void *buf, size_t count); 87 | void Close(int fd); 88 | int Dup2(int fd1, int fd2); 89 | void Stat(const char *filename, struct stat *buf); 90 | 91 | /* Memory mapping wrappers */ 92 | void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); 93 | void Munmap(void *start, size_t length); 94 | 95 | /* Standard I/O wrappers */ 96 | void Fclose(FILE *fp); 97 | FILE *Fdopen(int fd, const char *type); 98 | char *Fgets(char *ptr, int n, FILE *stream); 99 | FILE *Fopen(const char *filename, const char *mode); 100 | void Fputs(const char *ptr, FILE *stream); 101 | size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 102 | void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 103 | 104 | 105 | /* Sockets interface wrappers */ 106 | int Socket(int domain, int type, int protocol); 107 | void Setsockopt(int s, int level, int optname, const void *optval, int optlen); 108 | void Bind(int sockfd, struct sockaddr *my_addr, int addrlen); 109 | void Listen(int s, int backlog); 110 | int Accept(int s, struct sockaddr *addr, socklen_t *addrlen); 111 | void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 112 | 113 | /* DNS wrappers */ 114 | struct hostent *Gethostbyname(const char *name); 115 | struct hostent *Gethostbyaddr(const char *addr, int len, int type); 116 | 117 | /* Rio (Robust I/O) package */ 118 | ssize_t rio_readn(int fd, void *usrbuf, size_t n); 119 | ssize_t rio_writen(int fd, void *usrbuf, size_t n); 120 | void rio_readinitb(rio_t *rp, int fd); 121 | ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n); 122 | ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen); 123 | 124 | /* Wrappers for Rio package */ 125 | ssize_t Rio_readn(int fd, void *usrbuf, size_t n); 126 | void Rio_writen(int fd, void *usrbuf, size_t n); 127 | void Rio_readinitb(rio_t *rp, int fd); 128 | ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n); 129 | ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen); 130 | 131 | /* Client/server helper functions */ 132 | int open_clientfd(char *hostname, int portno); 133 | int open_listenfd(int portno); 134 | 135 | /* Wrappers for client/server helper functions */ 136 | int Open_clientfd(char *hostname, int port); 137 | int Open_listenfd(int port); 138 | 139 | /* Wrappers for others */ 140 | int Daemon(int nochdir, int noclose); 141 | struct passwd *Getpwnam(const char *name); 142 | int Fchown(int fd, uid_t owner, gid_t group); 143 | int Setgroups(size_t size, const gid_t *list); 144 | int Setgid(gid_t gid); 145 | int Initgroups(const char *user, gid_t group); 146 | int Setuid(uid_t uid); 147 | int Pipe(int pipefd[2]); 148 | 149 | #endif 150 | --------------------------------------------------------------------------------