├── 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 |
7 |
8 |
--------------------------------------------------------------------------------
/doc/dir/DirGet.html:
--------------------------------------------------------------------------------
1 |
2 |
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 |

109 |

110 |

111 |

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 |
--------------------------------------------------------------------------------