simple_httpd.c revision 38590
1/* simpleHTTPd (C) 1998 netSTOR Technologies, Inc. ("netSTOR") 2 FreeBSD port and additional work by Marc Nicholas <marc@netstor.com> 3 Based on work by:- 4 Thierry Leconte & Yury Shimanovsky 5 My Russian webserver writing friends :-) 6 7 This is an HTTP daemon that will serve up HTML, text files, JPEGs, 8 GIFs and do simple CGI work. 9 10 You may use this code for non-commercial distribution only. Commercial 11 distribution requires the express, written permission of netSTOR. No 12 warranty is implied or given -- use at your own risk! 13*/ 14 15/* 16 * $Id: simple_httpd.c,v 1.1 1998/08/19 16:24:06 abial Exp $ 17 */ 18 19#include <stdio.h> 20#include <unistd.h> 21#include <stdlib.h> 22#include <sys/stat.h> 23#include <sys/time.h> 24#include <sys/types.h> 25#include <time.h> 26#include <sys/socket.h> 27#include <netinet/in.h> 28#include <arpa/inet.h> 29#include <netdb.h> 30#include <fcntl.h> 31#include <string.h> 32#include <signal.h> 33#include <sys/wait.h> 34 35int http_sock, con_sock; 36int http_port = 80; 37struct sockaddr_in source; 38char homedir[100]; 39char *adate(); 40struct hostent *hst; 41 42void 43init_servconnection(void) 44{ 45 struct sockaddr_in server; 46 47 /* Create a socket */ 48 http_sock = socket(AF_INET, SOCK_STREAM, 0); 49 if (http_sock < 0) { 50 perror("socket"); 51 exit(1); 52 } 53 server.sin_family = AF_INET; 54 server.sin_port = htons(http_port); 55 server.sin_addr.s_addr = INADDR_ANY; 56 if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) { 57 perror("bind socket"); 58 exit(1); 59 } 60 printf("simpleHTTPd running on %d port\n",http_port); 61} 62 63attenteconnection(void) 64{ 65 int lg; 66 67 lg = sizeof(struct sockaddr_in); 68 69 con_sock = accept(http_sock, (struct sockaddr *) & source, &lg); 70 if (con_sock <= 0) { 71 perror("accept"); 72 exit(1); 73 } 74} 75 76outdate() 77{ 78 time_t tl; 79 char buff[50]; 80 81 tl = time(NULL); 82 strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl)); 83 write(con_sock, buff, strlen(buff)); 84} 85 86char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\ 87This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n", 88"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"}; 89 90char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\ 91Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n", 92"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"}; 93 94outerror(char **rep, int http1) /* ������ ������ ������� � html- ���� */ 95{ 96 97 if (http1) { 98 write(con_sock, rep[1], strlen(rep[1])); 99 outdate(); 100 write(con_sock, "\r\n", 2); 101 } 102 write(con_sock, rep[0], strlen(rep[0])); 103} 104 105char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n"; 106 107traite_req() 108{ 109 char buff[8192]; 110 int fd, lg, cmd, http1, i; 111 char *filename, *c; 112 struct stat statres; 113 char req[1024]; 114 char logfile[80]; 115 char msg[1024]; 116 char *p, 117 *par; 118 long addr; 119 FILE *log; 120 121 lg = read(con_sock, req, 1024); 122 123 if (p=strstr(req,"\n")) *p=0; 124 if (p=strstr(req,"\r")) *p=0; 125 126 if (geteuid()) 127 { 128 strcpy(logfile,getenv("HOME")); 129 strcat(logfile,"/"); 130 strcat(logfile,"jhttp.log"); 131 } 132 else strcpy(logfile,"/usr/adm/jhttpd.log"); 133 134 if ( access(logfile,W_OK)) 135 { 136 lg=creat (logfile,O_WRONLY); 137 chmod (logfile,00600); 138 close(lg); 139 } 140 141 strcpy(buff,inet_ntoa(source.sin_addr)); 142 143 addr=inet_addr(buff); 144 145 strcpy(msg,adate()); 146 strcat(msg," "); 147 hst=gethostbyaddr((char*) &addr, 4, AF_INET); 148 if (hst) strcat(msg,hst->h_name); 149 strcat(msg," ("); 150 strcat(msg,buff); 151 strcat(msg,") "); 152 strcat(msg,req); 153 154 log=fopen(logfile,"a"); 155 fprintf(log,"%s\n",msg); 156 fclose(log); 157 158 c = strtok(req, " "); 159 if (c == NULL) { 160 outerror(rep_err_nget, 0); 161 goto error; 162 } 163 cmd = 0; 164 if (strncmp(c, "GET", 3) == 0) 165 cmd = 1; 166 if (strncmp(c, "HEAD", 4) == 0) { 167 cmd = 2; 168 } 169 170 filename = strtok(NULL, " "); 171 172 http1 = 0; 173 c = strtok(NULL, " "); 174 if (c != NULL && strncmp(c, "HTTP", 4) == 0) 175 http1 = 1; 176 177 if (cmd == 0) { 178 outerror(rep_err_nget, http1); 179 goto error; 180 } 181 182 if (filename == NULL || 183 strlen(filename)==1) filename="/index.html"; 184 185 while (filename[0]== '/') filename++; 186 187 /**/ 188 if (!strncmp(filename,"cgi-bin/",8)) 189 { 190 par=0; 191 if (par=strstr(filename,"?")) 192 { 193 *par=0; 194 par++; 195 } 196 if (access(filename,X_OK)) goto conti; 197 stat (filename,&statres); 198 if (setuid(statres.st_uid)) return(0); 199 if (seteuid(statres.st_uid)) return(0); 200 if (!fork()) 201 { 202 close(1); 203 dup(con_sock); 204 printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n"); 205 execlp (filename,filename,par,0); 206 } 207 wait(&i); 208 return(0); 209 } 210 conti: 211 if (filename == NULL) { 212 outerror(rep_err_acc, http1); 213 goto error; 214 } 215 /* interdit les .. dans le path */ 216 c = filename; 217 while (*c != '\0') 218 if (c[0] == '.' && c[1] == '.') { 219 outerror(rep_err_acc, http1); 220 goto error; 221 } else 222 c++; 223 224 fd = open(filename, O_RDONLY); 225 if (fd < 0) { 226 outerror(rep_err_acc, http1); 227 goto error; 228 } 229 if (fstat(fd, &statres) < 0) { 230 outerror(rep_err_acc, http1); 231 goto error; 232 } 233 if (!S_ISREG(statres.st_mode)) 234 { 235 outerror(rep_err_acc, http1); 236 goto error; 237 } 238 if (http1) { 239 char buff[50]; 240 time_t tl; 241 242 write(con_sock, rep_head, strlen(rep_head)); 243 sprintf(buff, "Content-length: %d\r\n", statres.st_size); 244 write(con_sock, buff, strlen(buff)); 245 outdate(); 246 247 if (strstr(filename,".")) 248 { 249 strcpy(buff,"Content-type: "); 250 strcat(buff,strstr(filename,".")+1); 251 strcat(buff,"\r\n"); 252 write(con_sock,buff,strlen(buff)); 253 } 254 255 if (strstr(filename,".txt")) 256 { 257 strcpy(buff,"Content-type: text/plain\r\n"); 258 write(con_sock, buff, strlen(buff)); 259 } 260 261 if (strstr(filename,".html") || 262 strstr(filename,".htm")) 263 { 264 strcpy(buff,"Content-type: text/html\r\n"); 265 write(con_sock, buff, strlen(buff)); 266 } 267 268 if (strstr(filename,".gif")) 269 { 270 strcpy(buff,"Content-type: image/gif\r\n"); 271 write(con_sock, buff, strlen(buff)); 272 } 273 274 if (strstr(filename,".jpg")) 275 { 276 strcpy(buff,"Content-type: image/jpeg\r\n"); 277 write(con_sock, buff, strlen(buff)); 278 } 279 280 strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime)); 281 write(con_sock, buff, strlen(buff)); 282 } 283 if (cmd == 1) { 284 while (lg = read(fd, buff, 8192)) 285 write(con_sock, buff, lg); 286 } 287 288error: 289 close(fd); 290 close(con_sock); 291 292} 293 294 295main(int argc, char **argv) 296{ 297 int lg; 298 char hello[100]; 299 300 if (argc<2 && geteuid()) 301 { 302 printf("Usage: simple_htppd <port>\n"); 303 exit(1); 304 } 305 306 if (argc>=2) http_port = atoi(argv[1]); 307 308 strcpy (homedir,getenv("HOME")); 309 if (!geteuid()) strcpy (homedir,"/httphome"); 310 else strcat (homedir,"/httphome"); 311 312 strcpy(hello,homedir); 313 strcat(hello,"/0hello.html"); 314 315 if (chdir(homedir)) 316 { 317 perror("chdir"); 318 puts(homedir); 319 exit(1); 320 } 321 init_servconnection(); 322 323 if (fork()) exit(0); 324 325 setpgrp(0,65534); 326 signal(SIGQUIT, SIG_IGN); 327 signal(SIGHUP, SIG_IGN); 328 329 if (listen(http_sock,100) < 0) exit(1); 330 331 label: 332 attenteconnection(); 333 if (fork()) 334 { 335 close(con_sock); 336 goto label; 337 } 338 alarm(1800); 339 traite_req(); 340 exit(0); 341} 342 343 344 345char *adate() 346{ 347 static char out[50]; 348 long now; 349 struct tm *t; 350 time(&now); 351 t = localtime(&now); 352 sprintf(out, "%02d:%02d:%02d %02d/%02d/%02d", 353 t->tm_hour, t->tm_min, t->tm_sec, 354 t->tm_mday, t->tm_mon+1, t->tm_year ); 355 return out; 356} 357