1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <dirent.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <signal.h> 8 #include <fcntl.h> 9 #include <stdio.h> 10 #include <time.h> 11 #include <pwd.h> 12 #include <grp.h> 13 #include "config.h" 14 #include "md5.h" 15 #if defined(DEBUG) && !defined(WWWFTP_NO_BT) 16 #define ENABLE_BACKTRACE 17 #endif 18 #include "bt.h" 19 20 extern char **environ; 21 22 #ifndef WWWFTP_TOS_DECLINE 23 #define WWWFTP_TOS_DECLINE url 24 #endif 25 26 #ifndef WWWFTP_WEBMASTER 27 #define WWWFTP_WEBMASTER "webmaster@somewhere" 28 #endif 29 30 #define WWWFTP_NO_FOOTER 127 31 32 #if DEBUG>=2 33 extern char **environ; 34 #endif 35 36 #ifdef WWWFTP_STATIC_DL 37 void *_dlopen(const char *pathname, int mode) { return(NULL); } 38 void *_dlsym(void *handle, const char *name) { return(NULL); } 39 int _dlclose(void *handle) { return(-1); } 40 #endif 41 42 43 char *wwwftp_strsep(char **stringp, const char *delim) { 44 char *ret = *stringp; 45 46 bt_reg; 47 48 if (ret == NULL) bt_reg_return(NULL); /* grrr */ 49 if ((*stringp = strpbrk(*stringp, delim)) != NULL) { 50 *((*stringp)++) = '\0'; 51 } 52 bt_reg_return(ret); 53 } 54 55 56 void WWWFtp_HackAttempt(const char *arg, ...) { 57 /* This should do something, I bet... */ 58 return; 59 } 60 61 int Header(const char *title) { 62 static int HeaderSent=0; 63 64 bt_reg; 65 66 if (HeaderSent) bt_reg_return(1); 67 HeaderSent=1; 68 69 printf("Content-type: text/html\n\n"); 70 printf("<HTML><HEAD><TITLE>"); 71 #ifdef WWWFTP_PAGE_TITLE 72 printf(WWWFTP_PAGE_TITLE); 73 #endif 74 if (title) { 75 printf(" :: %s", title); 76 } 77 printf("</TITLE></HEAD><BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\">\n"); 78 #ifdef WWWFTP_PAGE_HEADER 79 printf(WWWFTP_PAGE_HEADER); 80 #endif 81 printf("<HR WIDTH=\"85%%\">\n"); 82 bt_reg_return(0); 83 } 84 85 86 /* Return value indicates whether or not an error was actually printed */ 87 /* 0 = msg held/not printed, 1 = msg printed, -1 = msg ignored */ 88 #ifdef DEBUG 89 #define ErrorMsg(x) ErrorMsg_real(x, __FILE__, __func__, __LINE__) 90 int ErrorMsg_real(const char *msg, const char *file, const char *func, const int line) { 91 #else 92 int ErrorMsg(const char *msg) { 93 #endif 94 static char HoldBuf[1024]={0}; 95 static int holdit=0; 96 97 bt_reg; 98 99 if (msg==(void *) 1) { 100 holdit=1; 101 bt_reg_return(0); 102 } 103 if (msg==(void *) 2) { 104 holdit=0; 105 msg=NULL; 106 if (strlen(HoldBuf)==0) bt_reg_return(0); 107 } 108 if (!holdit) Header("*** ERROR ***"); 109 if (!holdit && strlen(HoldBuf)!=0) { 110 printf("%s", HoldBuf); 111 HoldBuf[0]='\0'; 112 bt_reg_return(1); 113 } 114 #ifdef DEBUG 115 if (file && func) { 116 if ((strlen(HoldBuf)+strlen(file)+strlen(func)+42)>=sizeof(HoldBuf)) bt_reg_return(-1); 117 sprintf(HoldBuf, "%s%s:%04i:%s(...): ", HoldBuf, file, line, func); 118 } else if (file) { 119 if ((strlen(HoldBuf)+strlen(file)+38)>=sizeof(HoldBuf)) bt_reg_return(-1); 120 sprintf(HoldBuf, "%s%s:%04i: ", HoldBuf, file, line); 121 } 122 #endif 123 sprintf(HoldBuf, "%s*** AN ERROR HAS OCURRED", HoldBuf); 124 if (msg) { 125 if ((strlen(HoldBuf)+strlen(msg)+6)>=sizeof(HoldBuf)) bt_reg_return(-1); 126 sprintf(HoldBuf, "%s: \"%s\"", HoldBuf, msg); 127 } 128 sprintf(HoldBuf, "%s ***<br>\n", HoldBuf); 129 if (!holdit) { 130 printf("%s", HoldBuf); 131 HoldBuf[0]='\0'; 132 fflush(stdout); 133 bt_reg_return(1); 134 } 135 bt_reg_return(0); 136 } 137 138 int Footer(void) { 139 #if DEBUG>=2 140 int i; 141 #endif 142 bt_reg; 143 144 Header("Blank page"); 145 146 #if DEBUG>=2 147 printf("<HR WIDTH=\"85%%\">\n"); 148 for (i=0;environ[i];i++) { 149 printf("%s<br>\n", environ[i]); 150 } 151 printf("<PRE>%s</PRE>", backtrace_show(1)); 152 #endif 153 154 printf("<HR WIDTH=\"85%%\">\n"); 155 printf("Webmaster: <a href=\"mailto:%s\">%s</a><br>\n", WWWFTP_WEBMASTER, WWWFTP_WEBMASTER); 156 #ifdef WWWFTP_HOMEPAGE 157 printf("<A HREF=\"%s\">Home</A>", WWWFTP_HOMEPAGE); 158 #endif 159 printf("</BODY></HTML>\n"); 160 bt_reg_return(0); 161 } 162 163 void sighandler(int sig) { 164 bt_reg; 165 166 if (sig==11) { 167 Header("URGENT ERROR"); 168 printf("Backtrace:<br><PRE>%s</PRE>", backtrace_show(0)); 169 Footer(); 170 fflush(stdout); 171 exit(0); 172 } 173 } 174 175 176 #ifndef MD5bet 177 #define MD5bet "qwertyuiopabcdef" 178 #endif 179 #ifndef MD5UPDATE 180 #define MD5UPDATE(x) if ((buf=(x))!=NULL) MD5Update(&md5c, buf, strlen(buf)); 181 #endif 182 char *CalcMagicCookie(char *extra) { 183 struct MD5Context md5c; 184 char *buf, md5text[33], *md5str; 185 md5byte md5sum[16]; 186 int i; 187 188 bt_reg; 189 190 MD5Init(&md5c); 191 MD5UPDATE(getenv("REMOTE_ADDR")); 192 MD5UPDATE(getenv("REMOTE_HOST")); 193 MD5UPDATE(getenv("SERVER_PORT")); 194 MD5UPDATE(getenv("SERVER_NAME")); 195 MD5UPDATE(getenv("HTTP_USER_AGENT")); 196 MD5UPDATE(getenv("HTTP_ACCEPT")); 197 MD5UPDATE(getenv("HTTP_ACCEPT_CHARSET")); 198 MD5UPDATE(extra); 199 MD5Final(md5sum, &md5c); 200 for (i=0;i<16;i++) { 201 md5text[i*2]=MD5bet[(md5sum[i]&0xf0)>>4]; 202 md5text[(i*2)+1]=MD5bet[(md5sum[i]&0xf)]; 203 } 204 md5text[32]='\0'; 205 md5str=strdup(md5text); 206 bt_reg_return(md5str); 207 } 208 209 char *WWWFtp_FixStr(const char *str) { 210 char *ret, valstr[3]; 211 int i, x, sl, val; 212 213 sl=strlen(str)+1; 214 if ((ret=malloc(sl))==NULL) return(NULL); 215 for (x=i=0;i<sl;i++,x++) { 216 if (str[i]=='+') { ret[x]=' '; continue; } 217 if (str[i]=='%') { 218 strncpy(valstr, str+i+1, 2); 219 valstr[2]='\0'; 220 val=strtol(valstr, NULL, 16); 221 ret[x]=val; 222 i+=2; 223 continue; 224 } 225 ret[x]=str[i]; 226 } 227 return(ret); 228 } 229 230 #ifdef WWWFTP_ASK_USERINFO 231 int WWWFtp_ParseClient(const char *cid, const char *filename, char *name, char *email) { 232 FILE *fp; 233 char lbuf[1024]; 234 int found=0; 235 236 fp=fopen(filename, "r"); 237 if (fp) { 238 while (!feof(fp)) { 239 fgets(lbuf, sizeof(lbuf), fp); 240 if (strncmp(lbuf+3,cid,strlen(cid))==0) { found=1; break; } 241 } 242 fclose(fp); 243 } 244 245 if (found) { 246 return(1); 247 } 248 return(0); 249 } 250 251 void WWWFtp_SaveClient(const char *cid, const char *qstr, const char *filename) { 252 FILE *fp; 253 char *qbuf, *qbuf_s, *item; 254 255 /* If we don't have a list, abort. */ 256 if (strchr(qstr, '&')==NULL) return; 257 258 /* Check to see if there's already an entry for this client. */ 259 if (WWWFtp_ParseClient(cid,filename,NULL,NULL)!=0) return; 260 261 /* Parse and add the client to the file. */ 262 fp=fopen(filename, "a+"); 263 if (!fp) return; 264 265 qbuf_s=qbuf=strdup(qstr); 266 267 fprintf(fp, "id=%s ", cid); 268 269 while ((item=wwwftp_strsep(&qbuf, "&"))!=NULL) { 270 if (strstr(item, cid)==item) continue; 271 fprintf(fp, "\"%s\" ", WWWFtp_FixStr(item)); 272 } 273 fprintf(fp, "\n"); 274 fclose(fp); 275 276 return; 277 } 278 #else 279 void WWWFtp_SaveClient(const char *cid, const char *qstr, const char *filename) { return; } 280 int WWWFtp_ParseClient(const char *cid, const char *filename, char *name, char *email) { return(0); } 281 #endif 282 283 284 int VerifyClient(const char *cid, const char *file) { 285 FILE *fp=NULL; 286 char *url=WWWFTP_DEFAULTURL; 287 char *purl, *purl_c, buf[1024]; 288 int printed=0; 289 290 bt_reg; 291 292 Header("Verify Client"); 293 if ((purl=getenv("REQUEST_URI"))!=NULL) { 294 if ((purl_c=strchr(purl, '?'))!=NULL) *purl_c='\0'; 295 url=purl; 296 } 297 printf("<b>"); 298 if (file) { 299 fp=fopen(file, "r"); 300 if (fp) { 301 while (1) { 302 fgets(buf, sizeof(buf), fp); 303 if (feof(fp)) break; 304 printf("%s<br>", buf); 305 printed=1; 306 } 307 fclose(fp); 308 } 309 } 310 if (!printed) { 311 printf("Please read the following TERMS OF SERVICE:<br>"); 312 /* What should we do when no disclaimer is specified? LIE! */ 313 printf("(empty)"); 314 } 315 printf("</b><br>"); 316 #ifdef WWWFTP_ASK_USERINFO 317 printf("<FORM ACTION=\"%s\" METHOD=get>", url); 318 if (WWWFtp_ParseClient(cid, WWWFTP_ASK_USERINFO, NULL, NULL)==0) { 319 printf("<strong>You may also <i>optionally</i> tell us information about yourself.</strong><br>"); 320 printf("We will not obtain personally identifying information about you when you visit this site unless you choose to provide such information to us. If you choose to send email to the site webmaster or submit contact information, that information will be used soley for contacting you and not stored.<br>"); 321 printf("<TABLE>"); 322 printf("<TR><TD>Your name:</TD><TD><INPUT TYPE=text NAME=name></TD></TR>"); 323 printf("<TR><TD>Your email address:</TD><TD><INPUT TYPE=text NAME=email></TD></TR>"); 324 printf("</TABLE>\n"); 325 } 326 printf("Do you accept the TERMS OF SERVICE?<br>"); 327 printf("<INPUT TYPE=submit NAME=\"%s\" VALUE=\"Yes\">\n", cid); 328 printf("<INPUT TYPE=submit NAME=decline VALUE=\"No\">\n"); 329 printf("</FORM>"); 330 #else 331 printf("Do you accept the TERMS OF SERVICE?<br>"); 332 printf("<a href=\"%s?%s\">YES</a> <a href=\"%s\">NO</a>", url, cid, WWWFTP_TOS_DECLINE); 333 #endif 334 bt_reg_return(0); 335 } 336 337 char *GetMimeType(const char *filename) { 338 #if defined(WWWFTP_MIMEFILE) && !defined(WWWFTP_NO_TYPE) 339 static char buf[1024]; 340 char *lbuf, *ibuf, *type; 341 char *ext; 342 FILE *fd; 343 int i; 344 345 bt_reg; 346 347 if ((ext=strrchr(filename, '.'))==NULL) bt_reg_return(WWWFTP_MIME_DEFAULT); 348 if (!(fd=fopen(WWWFTP_MIMEFILE, "r"))) bt_reg_return(WWWFTP_MIME_DEFAULT); 349 ext++; 350 while (!feof(fd)) { 351 fgets(buf, sizeof(buf)-1, fd); 352 for (i=strlen(buf)-1;i>=0;i--) { 353 if (buf[i]<32) { buf[i]=0; break; } 354 } 355 if (buf[0]=='#') continue; 356 lbuf=buf; 357 type=wwwftp_strsep(&lbuf, "\t "); 358 while ((ibuf=wwwftp_strsep(&lbuf," \t"))!=NULL) { 359 if (strcasecmp(ibuf, ext)==0) bt_reg_return(type); 360 } 361 } 362 fclose(fd); 363 #endif 364 bt_reg_return(WWWFTP_MIME_DEFAULT); 365 } 366 367 int WWWFtp_Sendfile(const char *file) { 368 struct stat stbuf; 369 #ifndef WWWFTP_NO_TIMEINFO 370 struct tm *lastmodbuf; 371 #endif 372 struct tm *currtimebuf; 373 time_t currtime; 374 char buf[1024]; 375 int fd, x; 376 int ftp_wronly=0; 377 char *pwd, *pwd_s; 378 379 bt_reg; 380 381 pwd=getcwd(NULL, 256); 382 if (strlen(pwd)<strlen(WWWFTP_ROOT)) { 383 pwd_s="[invalid path]"; 384 free(pwd); 385 pwd=NULL; 386 } else { 387 pwd_s=pwd+strlen(WWWFTP_ROOT); 388 if (strcmp(pwd_s,"")==0) { 389 pwd_s="/"; 390 free(pwd); 391 pwd=NULL; 392 } 393 } 394 395 #ifdef WWWFTP_USER 396 if (stbuf.st_uid==WWWFTP_USER && (stbuf.st_mode&S_IWUSR)==S_IWUSR) ftp_wronly=1; 397 #endif 398 if (access(".", W_OK)==0) ftp_wronly=1; 399 if (strstr(pwd_s, "/incoming")) ftp_wronly=1; 400 401 if (ftp_wronly) bt_reg_return(ErrorMsg("Could not open file")); 402 403 currtime=time(NULL); 404 if (stat(file, &stbuf)<0) bt_reg_return(ErrorMsg("Could not open file")); 405 if ((fd=open(file, O_RDONLY))<0) bt_reg_return(ErrorMsg("Could not open file")); 406 407 currtimebuf=localtime(&currtime); 408 strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", currtimebuf); 409 printf("Date: %s\n", buf); 410 411 #ifndef WWWFTP_NO_TIMEINFO 412 lastmodbuf=localtime(&stbuf.st_mtime); 413 strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", lastmodbuf); 414 printf("Last-Modified: %s\n", buf); 415 #endif 416 417 printf("Content-Length: %i\n", (int) stbuf.st_size); 418 printf("Content-Type: %s\n\n", GetMimeType(file)); 419 while ((x=read(fd, buf, sizeof(buf)))>0) { 420 fwrite(buf, x, 1, stdout); 421 } 422 close(fd); 423 bt_reg_return(WWWFTP_NO_FOOTER); 424 } 425 426 int strcmp_wwwftp(char **a, char **b) { 427 bt_reg; 428 429 bt_reg_return(strcmp(*a, *b)); 430 } 431 432 433 int WWWFtp_ProcessDir(const char *dir, const char *magic) { 434 DIR *dh; 435 #ifdef WWWFTP_SORTDIR 436 char **file_list; 437 int file_list_ents=0,files_len=WWWFTP_MAX_ENTRIES,i; 438 #endif 439 struct dirent *file; 440 struct stat stbuf; 441 #ifndef WWWFTP_NO_TIMEINFO 442 struct tm *tmbuf; 443 #endif 444 #ifndef WWWFTP_NO_USERINFO 445 struct passwd *pwbuf; 446 struct group *grbuf; 447 char *group_s, *username_s; 448 #endif 449 char *fname, *fadd, timestr[64], *username, *group; 450 char *pwd, *pwd_s; 451 int ftp_wronly=0, writable=0; 452 453 bt_reg; 454 455 if (chdir(dir)<0) bt_reg_return(ErrorMsg("Invalid path name.")); 456 457 Header("Directory Viewer"); 458 459 pwd=getcwd(NULL, 256); 460 if (strlen(pwd)<strlen(WWWFTP_ROOT)) { 461 pwd_s="[invalid path]"; 462 free(pwd); 463 pwd=NULL; 464 } else { 465 pwd_s=pwd+strlen(WWWFTP_ROOT); 466 if (strcmp(pwd_s,"")==0) { 467 pwd_s="/"; 468 free(pwd); 469 pwd=NULL; 470 } 471 } 472 473 #ifdef WWWFTP_NO_USERINFO 474 group=username="ftp"; 475 #endif 476 #ifdef WWWFTP_NO_TIMEINFO 477 strcpy(timestr,"Jan 01 1970 00:00"); 478 #endif 479 480 #ifdef WWWFTP_USER 481 stat(dir, &stbuf); 482 if (stbuf.st_uid==WWWFTP_USER && (stbuf.st_mode&S_IWUSR)==S_IWUSR) ftp_wronly=1; 483 #endif 484 if (access(dir, W_OK)==0) ftp_wronly=1; 485 if (strstr(pwd_s, "/incoming")) ftp_wronly=1; 486 487 dh=opendir(dir); 488 if (!dh) bt_reg_return(ErrorMsg("Could not open directory.")); 489 printf("Directory of %s<br>\n", pwd_s); 490 printf("<PRE>"); 491 #ifdef WWWFTP_SORTDIR 492 file_list=malloc(files_len*sizeof(char*)); 493 while ((file=readdir(dh))!=NULL) { 494 if (file_list_ents>=files_len) { 495 files_len*=2; 496 if ((file_list=realloc(file_list, files_len*sizeof(char *)))==NULL) bt_reg_return(ErrorMsg("Unable to open directory")); 497 } 498 file_list[file_list_ents++]=strdup(file->d_name); 499 } 500 qsort(file_list, file_list_ents, sizeof(char *), (void *) strcmp_wwwftp); 501 for (i=0;i<file_list_ents;i++) { 502 fname=file_list[i]; 503 #else 504 while ((file=readdir(dh))!=NULL) { 505 fname=file->d_name; 506 #endif 507 if (strcmp(".", fname)==0 || strcmp("wwwftp.cgi", fname)==0 || strcmp("DISCLAIMER.TXT", fname)==0 || strcmp("WWWFTP_PARMS.TXT", fname)==0) continue; 508 if (stat(fname, &stbuf)<0) continue; 509 if (strcmp("..", fname)!=0 && ftp_wronly) continue; 510 if ((stbuf.st_mode&S_IFDIR)==S_IFDIR) { fadd="/"; } else { fadd=""; } 511 #ifndef WWWFTP_SHOWBAD 512 if (access(fname, R_OK)!=0 || (*fadd=='/' && access(fname, X_OK)!=0)) continue; 513 #endif 514 #ifndef WWWFTP_NO_TIMEINFO 515 tmbuf=localtime(&stbuf.st_mtime); 516 if (tmbuf) { 517 strftime(timestr, sizeof(timestr)-1, "%b %d %Y %H:%M", tmbuf); 518 } else { 519 strcpy(timestr,"[unknown]"); 520 } 521 #endif 522 #ifndef WWWFTP_NO_USERINFO 523 pwbuf=getpwuid(stbuf.st_uid); 524 grbuf=getgrgid(stbuf.st_gid); 525 if (pwbuf && pwbuf->pw_name) { 526 username=pwbuf->pw_name; 527 username_s=NULL; 528 } else { 529 username_s=username=malloc(1024); 530 sprintf(username, "%i", (int) stbuf.st_uid); 531 } 532 if (grbuf && grbuf->gr_name) { 533 group=grbuf->gr_name; 534 group_s=NULL; 535 } else { 536 group_s=group=malloc(1024); 537 sprintf(group, "%i", (int) stbuf.st_gid); 538 } 539 #endif 540 541 542 #ifndef WWWFTP_NO_WRITE 543 writable=0; 544 #ifdef WWWFTP_USER 545 if (stbuf.st_uid==WWWFTP_USER && (stbuf.st_mode&S_IWUSR)==S_IWUSR) writable=2; 546 #endif 547 if (access(fname, W_OK)==0) writable=2; 548 #endif 549 550 printf(" %c%s%s%s %-10s %-12s %11i %s <a href=\"%s%s?%s\">%s</a>%s\n", 551 "-d"[(*fadd)/'/'], 552 #ifdef WWWFTP_NO_USERINFO 553 "r--\0r-x\0rw-\0rwx"+((((*fadd)/'/')+writable)*4), 554 "r--\0r-x"+((*fadd/'/')*4), 555 "r--\0r-x"+((*fadd/'/')*4), 556 #else 557 "---\0--x\0-w-\0-wx\0r--\0r-x\0rw-\0rwx"+(((stbuf.st_mode>>6)&0x7)*4), 558 "---\0--x\0-w-\0-wx\0r--\0r-x\0rw-\0rwx"+(((stbuf.st_mode>>3)&0x7)*4), 559 "---\0--x\0-w-\0-wx\0r--\0r-x\0rw-\0rwx"+((stbuf.st_mode&0x7)*4), 560 #endif 561 username, 562 group, 563 (int) stbuf.st_size, 564 timestr, 565 fname, fadd, magic, fname, fadd); 566 #ifndef WWWFTP_NO_USERINFO 567 if (group_s) free(group_s); 568 if (username_s) free(username_s); 569 #endif 570 } 571 printf("</PRE>\n"); 572 closedir(dh); 573 574 #ifndef WWWFTP_NO_WRITE 575 if (ftp_wronly) { 576 printf("<FORM ACTION=\"?%s\" METHOD=\"POST\" ENCTYPE=\"multipart/form-data\">\n", magic); 577 printf("<INPUT TYPE=\"FILE\" NAME=upload>"); 578 printf("</FORM>"); 579 } 580 #endif 581 bt_reg_return(0); 582 } 583 584 char *WWWFtp_Dequote(const char *str) { 585 char *ret, *deq; 586 int sl; 587 588 if ((ret=strdup(str))==NULL) return(NULL); 589 sl=strlen(ret)+1; 590 while ((deq=strchr(ret, '\"'))!=NULL) { 591 memmove(deq, deq+1, sl-(deq-ret)-1); 592 } 593 return(ret); 594 } 595 596 597 int WWWFtp_ProcessUL(const char *dir, int length, const char *cid) { 598 char linebuf[1024]; 599 char *bound, *cn_type, *file, *ele_name; 600 int inband=0, canwrite=0; 601 int x; 602 603 bt_reg; 604 605 if (access(dir, W_OK)==0) canwrite=1; 606 607 if (!canwrite) bt_reg_return(ErrorMsg("Invalid path name.")); 608 609 if (chdir(dir)<0) bt_reg_return(ErrorMsg("Invalid path name.")); 610 if ((cn_type=getenv("CONTENT_TYPE"))==NULL) bt_reg_return(ErrorMsg("Invalid HTTP headers.")); 611 612 bound=strstr(cn_type, "boundary="); 613 if (!bound) bt_reg_return(ErrorMsg("Invalid HTTP headers.")); 614 bound+=9; 615 if (strchr(bound, ' ')) *strchr(bound, ' ')='\0'; 616 617 // Header(NULL); 618 // printf("len=%i, bound=\"%s\"<br>\n", length, bound); 619 while (1) { 620 fgets(linebuf, sizeof(linebuf), stdin); 621 if (feof(stdin)) break; 622 for (x=strlen(linebuf)-1;x>=0;x--) { if (linebuf[x]>=' ') break; linebuf[x]=0; } 623 if (strncmp(linebuf+2, bound, strlen(bound))==0) { inband=!inband; continue; } 624 if (!inband) continue; 625 if (strncasecmp(linebuf, "content-disposition: form-data;", 31)==0) { 626 if (!(file=strstr(linebuf, "filename="))) continue; 627 if (!(ele_name=strstr(linebuf, "name="))) continue; 628 ele_name+=5; file+=9; 629 if (strpbrk(file, "; ")) *strpbrk(file, "; ")='\0'; 630 if (strpbrk(ele_name, "; ")) *strpbrk(ele_name, "; ")='\0'; 631 if (strpbrk(file, "/")!=NULL) { 632 WWWFtp_HackAttempt("Attempt to upload", file, NULL); 633 bt_reg_return(ErrorMsg("Invalid file specificaiton. Saving data for review.")); 634 } 635 ele_name=WWWFtp_Dequote(ele_name); 636 if (strcmp(ele_name, "upload")!=0) { free(ele_name); continue; } 637 free(ele_name); 638 Header("Upload File"); 639 640 file=WWWFtp_Dequote(file); 641 printf("UPLOAD: file=%s<br>\n", file); 642 /* XXX: Open, it's safe.. I swear ! */ 643 644 /* We no longer know the file name past the next line, do we need it? */ 645 free(file); 646 647 /* XXX: We need to make it read the data here. */ 648 649 650 // close(...) 651 } 652 } 653 654 655 bt_reg_return(0); 656 } 657 658 int WWWFtp_SetParms(const char *fname) { 659 /* XXX: We should process the PARMS file. We need to figure out what is going to go in there. */ 660 return(0); 661 } 662 663 664 int WWWFtp(void) { 665 struct stat stbuf; 666 char *path_cp, *ele, *pwd, *path=NULL, *path_tmp=NULL, *disc_file=NULL, *file=NULL, *parms_file=NULL; 667 char *uri=NULL; 668 char *ClientID, *ClientCheck; 669 char *cn_length_str; 670 char *url; 671 int rv=0; 672 int cn_length; 673 674 bt_reg; 675 676 url=WWWFTP_DEFAULTURL; 677 678 ErrorMsg((char *) 1); /* This makes it hold all the error messages */ 679 680 /* In this block (everything before the `error' label) we need to do three things for an error: 681 * Call ErrorMsg() To print (eventually) the error 682 * path=NULL To prevent the code from attempting to traverse the path 683 * goto error To abort further processing on the path 684 */ 685 686 if ((uri=getenv("REQUEST_URI"))!=NULL) { 687 path=strdup(uri); 688 path_tmp=strchr(path, '?'); 689 if (path_tmp) *path_tmp='\0'; 690 } else { 691 path=getenv("PATH_INFO"); 692 } 693 if (path!=NULL) { 694 if (strstr(path, "..")!=NULL) { ErrorMsg("Invalid path name"); path=NULL; goto error; } 695 while (*path && *path=='/') path++; 696 if (chdir(WWWFTP_ROOT)!=0) { ErrorMsg("Invalid path name"); path=NULL; goto error; } 697 if (strcmp(path, "")!=0) { 698 if (stat(path, &stbuf)<0) { ErrorMsg("File does not exist"); path=NULL; goto error; } 699 if ((stbuf.st_mode&S_IFREG)==S_IFREG) { 700 file=strrchr(path,'/'); 701 if (file) { 702 *file='\0'; 703 file++; 704 } else { 705 file=path; 706 path=NULL; 707 } 708 } 709 if (path) { 710 if (chdir(path)!=0) { ErrorMsg("Invalid path name"); path=NULL; goto error; } 711 } 712 } 713 } else { 714 if (chdir(WWWFTP_ROOT)!=0) { ErrorMsg("Invalid path name"); path=NULL; goto error; } 715 } 716 pwd=getcwd(NULL, 1024); 717 if (strncmp(pwd, WWWFTP_ROOT, strlen(WWWFTP_ROOT))!=0) { ErrorMsg("Invalid path name"); path=NULL; goto error; } 718 free(pwd); pwd=NULL; 719 720 error: 721 if (path) { 722 chdir(WWWFTP_ROOT); 723 path_cp=strdup(path); 724 while ((ele=wwwftp_strsep(&path_cp,"/"))!=NULL) { 725 if (access("WWWFTP_PARMS.TXT", R_OK)==0) { 726 if (parms_file) free(parms_file); 727 pwd=getcwd(NULL, 1024); 728 parms_file=malloc(strlen(pwd)+strlen("WWWFTP_PARMS.TXT")+5); 729 sprintf(disc_file, "%s/WWWFTP_PARMS.TXT", pwd); 730 free(pwd); pwd=NULL; 731 } 732 if (access("DISCLAIMER.TXT", R_OK)==0) { 733 if (disc_file) free(disc_file); 734 pwd=getcwd(NULL, 1024); 735 disc_file=malloc(strlen(pwd)+strlen("DISCLAIMER.TXT")+5); 736 sprintf(disc_file, "%s/DISCLAIMER.TXT", pwd); 737 free(pwd); pwd=NULL; 738 } 739 if (chdir(ele)<0) break; 740 } 741 } else { 742 chdir(WWWFTP_ROOT); 743 if (access("WWWFTP_PARMS.TXT", R_OK)==0) { 744 if (parms_file) free(parms_file); 745 pwd=getcwd(NULL, 1024); 746 parms_file=malloc(strlen(pwd)+strlen("WWWFTP_PARMS.TXT")+5); 747 sprintf(disc_file, "%s/WWWFTP_PARMS.TXT", pwd); 748 free(pwd); pwd=NULL; 749 } 750 if (access("DISCLAIMER.TXT", R_OK)==0) { 751 if (disc_file) free(disc_file); 752 pwd=getcwd(NULL, 1024); 753 disc_file=malloc(strlen(pwd)+strlen("DISCLAIMER.TXT")+5); 754 sprintf(disc_file, "%s/DISCLAIMER.TXT", pwd); 755 free(pwd); pwd=NULL; 756 } 757 } 758 759 /* If we have a config file, process it. */ 760 if (parms_file) WWWFtp_SetParms(parms_file); 761 762 /* One thing I want to do here is find a DISCLAIMER.TXT in the directory structure leading up to here 763 * and add it's path to the "ClientID", this file should also be a parameter for VerifyClient() so it 764 * can have something to read. This will mean moving the following block down until after the client 765 * path has been followed, which could lead to a compromise of information that the files don't exist 766 * so we may have to remove all the ErrorMsg()'s ... or make a flag so that ErrorMsg() holds them for 767 * a while, until the flag is turned off, which is probably best since it will preserve our debugging 768 * info. 769 * -- Roy Keene [0180420031349] 770 * This should now be how it's working 771 * -- Roy Keene [0220420031212] 772 */ 773 ClientID=CalcMagicCookie(disc_file); 774 if ((ClientCheck=getenv("QUERY_STRING"))!=NULL) { 775 #ifdef WWWFTP_ASK_USERINFO 776 if (strstr(ClientCheck, "decline=")!=NULL) { 777 Header("Client denied."); 778 printf("Failed to agree to the terms of service.<br>"); 779 #ifdef WWWFTP_TOS_DECLINE 780 printf("Please click <A HREF=\"%s\">here</A> to continue.<br>", WWWFTP_TOS_DECLINE); 781 #endif 782 bt_reg_return(0); 783 } 784 #endif 785 if (strcmp(ClientCheck, "")==0) bt_reg_return(VerifyClient(ClientID, disc_file)); 786 if (strstr(ClientCheck, ClientID)==NULL) bt_reg_return(VerifyClient(ClientID, disc_file)); 787 #ifdef WWWFTP_ASK_USERINFO 788 WWWFtp_SaveClient(ClientID, ClientCheck, WWWFTP_ASK_USERINFO); 789 #endif 790 } else { 791 bt_reg_return(VerifyClient(ClientID, disc_file)); 792 } 793 794 795 /* If we got any error messages while we were holding them, print them, and abort further processing. */ 796 if ((rv=ErrorMsg((char *) 2))!=0) { 797 bt_reg_return(rv); 798 } 799 800 if (file) { 801 if (strchr(file, '/')!=NULL) bt_reg_return(ErrorMsg("Invalid file name")); 802 bt_reg_return(WWWFtp_Sendfile(file)); 803 } else { 804 if ((cn_length_str=getenv("CONTENT_LENGTH"))!=NULL) { 805 cn_length=atoi(cn_length_str); 806 if (cn_length<=0) bt_reg_return(ErrorMsg("Invalid upload.")); 807 bt_reg_return(WWWFtp_ProcessUL(".", cn_length, ClientID)); 808 } else { 809 bt_reg_return(WWWFtp_ProcessDir(".", ClientID)); 810 } 811 } 812 813 bt_reg_return(0); 814 } 815 816 int main(void) { 817 bt_reg; 818 #ifdef WWWFTP_USER 819 if (setuid(WWWFTP_USER)<0) { 820 if (getuid()!=WWWFTP_USER) { 821 ErrorMsg("Could not setup FTP."); 822 Footer(); 823 bt_reg_return(0); 824 } 825 } 826 #endif 827 signal(SIGSEGV, sighandler); 828 829 if (WWWFtp()!=WWWFTP_NO_FOOTER) Footer(); 830 bt_reg_return(0); 831 } |