simple_httpd.c revision 43939
1/*- 2 * SimpleHTTPd v1.0 - a very small, barebones HTTP server 3 * 4 * Copyright (c) 1998-1999 Marc Nicholas <marc@netstor.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: simple_httpd.c,v 1.2.2.1 1999/02/05 12:21:41 abial Exp $ 29 */ 30 31#include <stdio.h> 32#include <unistd.h> 33#include <stdlib.h> 34#include <sys/stat.h> 35#include <sys/time.h> 36#include <sys/types.h> 37#include <time.h> 38#include <sys/socket.h> 39#include <netinet/in.h> 40#include <arpa/inet.h> 41#include <netdb.h> 42#include <fcntl.h> 43#include <string.h> 44#include <signal.h> 45#include <sys/wait.h> 46 47int http_sock, con_sock; 48int http_port = 80; 49struct sockaddr_in source; 50char homedir[100]; 51char *adate(); 52struct hostent *hst; 53 54void 55init_servconnection(void) 56{ 57 struct sockaddr_in server; 58 59 /* Create a socket */ 60 http_sock = socket(AF_INET, SOCK_STREAM, 0); 61 if (http_sock < 0) { 62 perror("socket"); 63 exit(1); 64 } 65 server.sin_family = AF_INET; 66 server.sin_port = htons(http_port); 67 server.sin_addr.s_addr = INADDR_ANY; 68 if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) { 69 perror("bind socket"); 70 exit(1); 71 } 72 printf("simpleHTTPd running on %d port\n",http_port); 73} 74 75attenteconnection(void) 76{ 77 int lg; 78 79 lg = sizeof(struct sockaddr_in); 80 81 con_sock = accept(http_sock, (struct sockaddr *) & source, &lg); 82 if (con_sock <= 0) { 83 perror("accept"); 84 exit(1); 85 } 86} 87 88outdate() 89{ 90 time_t tl; 91 char buff[50]; 92 93 tl = time(NULL); 94 strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl)); 95 write(con_sock, buff, strlen(buff)); 96} 97 98char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\ 99This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n", 100"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"}; 101 102char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\ 103Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n", 104"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"}; 105 106outerror(char **rep, int http1) /* ������ ������ ������� � html- ���� */ 107{ 108 109 if (http1) { 110 write(con_sock, rep[1], strlen(rep[1])); 111 outdate(); 112 write(con_sock, "\r\n", 2); 113 } 114 write(con_sock, rep[0], strlen(rep[0])); 115} 116 117char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n"; 118 119traite_req() 120{ 121 char buff[8192]; 122 int fd, lg, cmd, http1, i; 123 char *filename, *c; 124 struct stat statres; 125 char req[1024]; 126 char logfile[80]; 127 char msg[1024]; 128 char *p, 129 *par; 130 long addr; 131 FILE *log; 132 133 lg = read(con_sock, req, 1024); 134 135 if (p=strstr(req,"\n")) *p=0; 136 if (p=strstr(req,"\r")) *p=0; 137 138 if (geteuid()) 139 { 140 strcpy(logfile,getenv("HOME")); 141 strcat(logfile,"/"); 142 strcat(logfile,"jhttp.log"); 143 } 144 else strcpy(logfile,"/var/log/jhttpd.log"); 145 146 if ( access(logfile,W_OK)) 147 { 148 lg=creat (logfile,O_WRONLY); 149 chmod (logfile,00600); 150 close(lg); 151 } 152 153 strcpy(buff,inet_ntoa(source.sin_addr)); 154 155 addr=inet_addr(buff); 156 157 strcpy(msg,adate()); 158 strcat(msg," "); 159 hst=gethostbyaddr((char*) &addr, 4, AF_INET); 160 if (hst) strcat(msg,hst->h_name); 161 strcat(msg," ("); 162 strcat(msg,buff); 163 strcat(msg,") "); 164 strcat(msg,req); 165 166 log=fopen(logfile,"a"); 167 fprintf(log,"%s\n",msg); 168 fclose(log); 169 170 c = strtok(req, " "); 171 if (c == NULL) { 172 outerror(rep_err_nget, 0); 173 goto error; 174 } 175 cmd = 0; 176 if (strncmp(c, "GET", 3) == 0) 177 cmd = 1; 178 if (strncmp(c, "HEAD", 4) == 0) { 179 cmd = 2; 180 } 181 182 filename = strtok(NULL, " "); 183 184 http1 = 0; 185 c = strtok(NULL, " "); 186 if (c != NULL && strncmp(c, "HTTP", 4) == 0) 187 http1 = 1; 188 189 if (cmd == 0) { 190 outerror(rep_err_nget, http1); 191 goto error; 192 } 193 194 if (filename == NULL || 195 strlen(filename)==1) filename="/index.html"; 196 197 while (filename[0]== '/') filename++; 198 199 /**/ 200 if (!strncmp(filename,"cgi-bin/",8)) 201 { 202 par=0; 203 if (par=strstr(filename,"?")) 204 { 205 *par=0; 206 par++; 207 } 208 if (access(filename,X_OK)) goto conti; 209 stat (filename,&statres); 210 if (setuid(statres.st_uid)) return(0); 211 if (seteuid(statres.st_uid)) return(0); 212 if (!fork()) 213 { 214 close(1); 215 dup(con_sock); 216 printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n"); 217 execlp (filename,filename,par,0); 218 } 219 wait(&i); 220 return(0); 221 } 222 conti: 223 if (filename == NULL) { 224 outerror(rep_err_acc, http1); 225 goto error; 226 } 227 /* interdit les .. dans le path */ 228 c = filename; 229 while (*c != '\0') 230 if (c[0] == '.' && c[1] == '.') { 231 outerror(rep_err_acc, http1); 232 goto error; 233 } else 234 c++; 235 236 fd = open(filename, O_RDONLY); 237 if (fd < 0) { 238 outerror(rep_err_acc, http1); 239 goto error; 240 } 241 if (fstat(fd, &statres) < 0) { 242 outerror(rep_err_acc, http1); 243 goto error; 244 } 245 if (!S_ISREG(statres.st_mode)) 246 { 247 outerror(rep_err_acc, http1); 248 goto error; 249 } 250 if (http1) { 251 char buff[50]; 252 time_t tl; 253 254 write(con_sock, rep_head, strlen(rep_head)); 255 sprintf(buff, "Content-length: %d\r\n", statres.st_size); 256 write(con_sock, buff, strlen(buff)); 257 outdate(); 258 259 if (strstr(filename,".")) 260 { 261 strcpy(buff,"Content-type: "); 262 strcat(buff,strstr(filename,".")+1); 263 strcat(buff,"\r\n"); 264 write(con_sock,buff,strlen(buff)); 265 } 266 267 if (strstr(filename,".txt")) 268 { 269 strcpy(buff,"Content-type: text/plain\r\n"); 270 write(con_sock, buff, strlen(buff)); 271 } 272 273 if (strstr(filename,".html") || 274 strstr(filename,".htm")) 275 { 276 strcpy(buff,"Content-type: text/html\r\n"); 277 write(con_sock, buff, strlen(buff)); 278 } 279 280 if (strstr(filename,".gif")) 281 { 282 strcpy(buff,"Content-type: image/gif\r\n"); 283 write(con_sock, buff, strlen(buff)); 284 } 285 286 if (strstr(filename,".jpg")) 287 { 288 strcpy(buff,"Content-type: image/jpeg\r\n"); 289 write(con_sock, buff, strlen(buff)); 290 } 291 292 strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime)); 293 write(con_sock, buff, strlen(buff)); 294 } 295 if (cmd == 1) { 296 while (lg = read(fd, buff, 8192)) 297 write(con_sock, buff, lg); 298 } 299 300error: 301 close(fd); 302 close(con_sock); 303 304} 305 306 307main(int argc, char **argv) 308{ 309 int lg; 310 char hello[100]; 311 312 if (argc<2 && geteuid()) 313 { 314 printf("Usage: simple_htppd <port>\n"); 315 exit(1); 316 } 317 318 if (argc>=2) http_port = atoi(argv[1]); 319 320 strcpy (homedir,getenv("HOME")); 321 if (!geteuid()) strcpy (homedir,"/httphome"); 322 else strcat (homedir,"/httphome"); 323 324 strcpy(hello,homedir); 325 strcat(hello,"/0hello.html"); 326 327 if (chdir(homedir)) 328 { 329 perror("chdir"); 330 puts(homedir); 331 exit(1); 332 } 333 init_servconnection(); 334 335 if (fork()) exit(0); 336 337 setpgrp(0,65534); 338 signal(SIGQUIT, SIG_IGN); 339 signal(SIGHUP, SIG_IGN); 340 341 if (listen(http_sock,100) < 0) exit(1); 342 343 label: 344 attenteconnection(); 345 if (fork()) 346 { 347 close(con_sock); 348 goto label; 349 } 350 alarm(1800); 351 traite_req(); 352 exit(0); 353} 354 355 356 357char *adate() 358{ 359 static char out[50]; 360 long now; 361 struct tm *t; 362 time(&now); 363 t = localtime(&now); 364 sprintf(out, "%02d:%02d:%02d %02d/%02d/%02d", 365 t->tm_hour, t->tm_min, t->tm_sec, 366 t->tm_mday, t->tm_mon+1, t->tm_year ); 367 return out; 368} 369