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