sqwebmail.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:28k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. /*
  6. ** $Id: sqwebmail.c,v 1.43 2000/07/01 23:09:28 mrsam Exp $
  7. */
  8. #include "sqwebmail.h"
  9. #include "sqconfig.h"
  10. #include "auth.h"
  11. #include "folder.h"
  12. #include "pref.h"
  13. #include "maildir.h"
  14. #include "cgi/cgi.h"
  15. #include "pref.h"
  16. #include "newmsg.h"
  17. #include "addressbook.h"
  18. #include "http11/http11.h"
  19. #include "random128/random128.h"
  20. #include "maildir/maildirmisc.h"
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #if HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #include <string.h>
  28. #include <signal.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #if HAVE_FCNTL_H
  32. #include <fcntl.h>
  33. #endif
  34. #if HAVE_LOCALE_H
  35. #if HAVE_SETLOCALE
  36. #include <locale.h>
  37. #endif
  38. #endif
  39. #include <ctype.h>
  40. #if HAVE_SYS_WAIT_H
  41. #include <sys/wait.h>
  42. #endif
  43. #define MD5_INTERNAL
  44. #include "md5/md5.h"
  45. #include "logincache.h"
  46. #include "numlib/numlib.h"
  47. #if HAVE_CRYPT_H
  48. #include <crypt.h>
  49. #endif
  50. #if     NEED_CRYPT_PROTOTYPE
  51. extern char *crypt(const char *, const char *);
  52. #endif
  53. #include "htmllibdir.h"
  54. #ifdef WEBPASS_CHANGE_VCHKPW
  55. #include "vpopmail.h"
  56. #include "vauth.h"
  57. #endif
  58. extern void spell_show();
  59. extern void spell_check_continue();
  60. extern void print_safe(const char *);
  61. extern void ldaplist();
  62. extern int ldapsearch();
  63. extern void doldapsearch();
  64. const char *sqwebmail_mailboxid=0;
  65. const char *sqwebmail_folder=0;
  66. const char *sqwebmail_sessiontoken=0;
  67. const char *sqwebmail_content_language=0;
  68. const char *sqwebmail_content_locale;
  69. const char *sqwebmail_content_ispelldict;
  70. const char *sqwebmail_content_charset;
  71. static int noimages=0;
  72. time_t login_time;
  73. #ifdef GZIP
  74. static int gzip_save_fd;
  75. #endif
  76. static const char *sqwebmail_formname;
  77. extern void attachments_head(const char *, const char *, const char *);
  78. extern void doattach(const char *, const char *);
  79. char form_args[2048];
  80. #if HAVE_LIBFCGI
  81. #include <signal.h>
  82. #include <setjmp.h>
  83. static jmp_buf stackenv;
  84. void fake_exit(int n)
  85. {
  86. cancel_login_cache();
  87. FCGI_SetExitStatus(n);
  88. longjmp(stackenv,1);
  89. }
  90. #ifdef BANNERPROG
  91. #error "Bannerprog not supported with FCGI"
  92. #endif
  93. #else
  94. void fake_exit(int n)
  95. {
  96. cancel_login_cache();
  97. exit(n);
  98. }
  99. #endif
  100. /* Stub to catch aborts from authlib */
  101. void authexit(int n)
  102. {
  103. fake_exit(n);
  104. }
  105. /* enomem() used to be just an out-of-memory handler.  Now, I use it as a
  106. ** generic failure type of a deal.
  107. */
  108. void rfc2045_error(const char *p)
  109. {
  110. error(p);
  111. }
  112. void print_attrencodedlen(const char *p, size_t len, int oknl, FILE *fp)
  113. {
  114. for (; len; p++, --len)
  115. {
  116. switch (*p) {
  117. case '<':
  118. fprintf(fp, "&lt;");
  119. continue;
  120. case '>':
  121. fprintf(fp, "&gt;");
  122. continue;
  123. case '&':
  124. fprintf(fp, "&amp;");
  125. continue;
  126. case '"':
  127. fprintf(fp, "&quot;");
  128. continue;
  129. case 'n':
  130. if (oknl)
  131. {
  132. if (oknl == 2)
  133. {
  134. fprintf(fp, "<BR>");
  135. continue;
  136. }
  137. putc('n', fp);
  138. continue;
  139. }
  140. default:
  141. if (!ISCTRL(*p))
  142. {
  143. putc(*p, fp);
  144. continue;
  145. }
  146. }
  147. fprintf(fp, "&#%d;", (int)(unsigned char)*p);
  148. }
  149. }
  150. void output_attrencoded_fp(const char *p, FILE *fp)
  151. {
  152. print_attrencodedlen(p, strlen(p), 0, fp);
  153. }
  154. void output_attrencoded(const char *p)
  155. {
  156. output_attrencoded_fp(p, stdout);
  157. }
  158. void output_attrencoded_oknl_fp(const char *p, FILE *fp)
  159. {
  160. print_attrencodedlen(p, strlen(p), 1, fp);
  161. }
  162. void output_attrencoded_oknl(const char *p)
  163. {
  164. output_attrencoded_oknl_fp(p, stdout);
  165. }
  166. void output_attrencoded_nltobr(const char *p)
  167. {
  168. print_attrencodedlen(p, strlen(p), 2, stdout);
  169. }
  170. void output_urlencoded(const char *p)
  171. {
  172. char *q=cgiurlencode(p);
  173. printf("%s", q);
  174. free(q);
  175. }
  176. void output_loginscriptptr()
  177. {
  178. #if USE_HTTPS_LOGIN
  179. const char *p=cgihttpsscriptptr();
  180. #else
  181. const char *p=cgihttpscriptptr();
  182. #endif
  183. printf("%s", p);
  184. }
  185. const char *nonloginscriptptr()
  186. {
  187. #if USE_HTTPS
  188. return (cgihttpsscriptptr());
  189. #else
  190. return (cgihttpscriptptr());
  191. #endif
  192. }
  193. void output_scriptptr()
  194. {
  195. const char *p=nonloginscriptptr();
  196. printf("%s", p);
  197. if (sqwebmail_mailboxid)
  198. {
  199. char *q=cgiurlencode(sqwebmail_mailboxid);
  200. char buf[NUMBUFSIZE];
  201. printf("/login/%s/%s/%s", q,
  202. sqwebmail_sessiontoken ?  sqwebmail_sessiontoken:" ",
  203. str_time_t(login_time, buf));
  204. free(q);
  205. }
  206. }
  207. void output_loginscriptptr_get()
  208. {
  209. output_loginscriptptr();
  210. if (sqwebmail_mailboxid)
  211. {
  212. char *q=cgiurlencode(sqwebmail_mailboxid);
  213. char buf[NUMBUFSIZE];
  214. printf("/login/%s/%s/%s", q,
  215. sqwebmail_sessiontoken ?  sqwebmail_sessiontoken:" ",
  216. str_time_t(login_time, buf));
  217. free(q);
  218. }
  219. }
  220. char *scriptptrget()
  221. {
  222. char *q=0;
  223. size_t l=0;
  224. int i;
  225. char buf[NUMBUFSIZE];
  226. #define ADD(s) {const char *zz=(s); if (i) strcat(q, zz); l += strlen(zz);}
  227. #define ADDE(ue) { char *yy=cgiurlencode(ue); ADD(yy); free(yy); }
  228. for (i=0; i<2; i++)
  229. {
  230. if (i && (q=malloc(l+1)) == 0) enomem();
  231. if (i) *q=0;
  232. ADD( nonloginscriptptr() );
  233. if (!sqwebmail_mailboxid)
  234. {
  235. ADD("?");
  236. continue;
  237. }
  238. ADD("/login/");
  239. ADD(sqwebmail_mailboxid);
  240. ADD("/");
  241. ADD(sqwebmail_sessiontoken ? sqwebmail_sessiontoken:" ");
  242. ADD("/");
  243. ADD(str_time_t(login_time, buf));
  244. ADD( "?" );
  245. if (sqwebmail_folder)
  246. {
  247. ADD("folder=");
  248. ADDE(sqwebmail_folder);
  249. }
  250. }
  251. #undef ADD
  252. #undef ADDE
  253. return (q);
  254. }
  255. void output_scriptptrget()
  256. {
  257. char *p=scriptptrget();
  258. printf("%s", p);
  259. free(p);
  260. return;
  261. }
  262. void output_scriptptrpostinfo()
  263. {
  264. #if 0
  265. if (sqwebmail_mailboxid)
  266. {
  267. printf("<INPUT TYPE=HIDDEN NAME="mailbox" VALUE="");
  268. output_attrencoded(sqwebmail_mailboxid);
  269. printf("">");
  270. }
  271. if (sqwebmail_sessiontoken)
  272. printf("<INPUT TYPE=HIDDEN NAME="session" VALUE="%s">",
  273. sqwebmail_sessiontoken);
  274. #endif
  275. if (sqwebmail_folder)
  276. {
  277. printf("<INPUT TYPE=HIDDEN NAME="folder" VALUE="");
  278. output_attrencoded(sqwebmail_folder);
  279. printf("">");
  280. }
  281. if (*cgi("folderdir")) /* In folders.html */
  282. {
  283. printf("<INPUT TYPE=HIDDEN NAME="folderdir" VALUE="");
  284. output_attrencoded(cgi("folderdir"));
  285. printf("">");
  286. }
  287. }
  288. void error(const char *errmsg)
  289. {
  290. cginocache();
  291. printf("Content-Type: text/html; charset="us-ascii"nn<H1>%s</H1>n",
  292. errmsg);
  293. cleanup();
  294. fake_exit(1);
  295. }
  296. void error2(const char *file, int line)
  297. {
  298. cginocache();
  299. printf("Content-Type: text/html; charset="us-ascii"nn<H1>Internal error (module %s, line %d) - contact system administrator</H1>n",
  300. file, line);
  301. cleanup();
  302. fake_exit(1);
  303. }
  304. static FILE *open_langform(const char *lang, const char *formname)
  305. {
  306. char *formpath;
  307. FILE *f;
  308. char *templatedir=getenv("SQWEBMAIL_TEMPLATEDIR");
  309. if (!templatedir || !*templatedir) templatedir=HTMLLIBDIR;
  310. /* templatedir/lang/formname */
  311. if (!(formpath=malloc(strlen(templatedir)+3+
  312. strlen(lang)+strlen(formname))))
  313. error("Out of memory.");
  314. strcat(strcat(strcat(strcat(strcpy(formpath, templatedir), "/"),
  315. lang), "/"), formname);
  316. f=fopen(formpath, "r");
  317. free(formpath);
  318. if (f)
  319. printf("Content-Language: %sn", lang);
  320. return (f);
  321. }
  322. void output_form(const char *formname)
  323. {
  324. int c, c2, c3;
  325. char *argp;
  326. size_t argn;
  327. FILE *f=0;
  328. #ifdef GZIP
  329. int dogzip;
  330. int pipefd[2];
  331. pid_t pid= -1;
  332. #endif
  333. noimages= access(NOIMAGES, 0) == 0;
  334. if (sqwebmail_content_language)
  335. f=open_langform(sqwebmail_content_language, formname);
  336. if (!f) f=open_langform(HTTP11_DEFAULTLANG, formname);
  337. sqwebmail_formname=formname;
  338. if (!f) error("Can't open form template.");
  339. /*
  340. ** Except for the dummy frame window (and the tiny empty frame),
  341. ** and the window containing the print preview of the message,
  342. ** expire everything.
  343. */
  344. if (strcmp(formname, "index.html") && strcmp(formname, "empty.html") &&
  345. strcmp(formname, "print.html"))
  346. cginocache();
  347. #ifdef GZIP
  348. dogzip=0;
  349. if (strcmp(formname, "readmsg.html") == 0)
  350. {
  351. const char *p=getenv("HTTP_ACCEPT_ENCODING");
  352. if (p)
  353. {
  354. char *q=strdup(p), *r;
  355. if (!q) enomem();
  356. for (r=q; *r; r++)
  357. *r= tolower((int)(unsigned char)*r);
  358. for (r=q; (r=strtok(r, ", ")) != 0; r=0)
  359. if (strcmp(r, "gzip") == 0)
  360. {
  361. dogzip=1;
  362. if (pipe(pipefd))
  363. enomem();
  364. }
  365. free(q);
  366. }
  367. }
  368. #endif
  369. printf("Vary: Accept-Languagen");
  370. #ifdef GZIP
  371. if (dogzip)
  372. printf("Content-Encoding: gzipn");
  373. #endif
  374. printf("Content-Type: text/htmlnn");
  375. form_args[0]='';
  376. #ifdef GZIP
  377. if (dogzip)
  378. {
  379. fflush(stdout);
  380. while ((pid=fork()) == -1)
  381. sleep(5);
  382. if (pid == 0)
  383. {
  384. close(0);
  385. dup(pipefd[0]);
  386. close(pipefd[0]);
  387. close(pipefd[1]);
  388. execl(GZIP, "gzip", "-c", (char *)0);
  389. exit(1);
  390. }
  391. gzip_save_fd=dup(1);
  392. close(1);
  393. dup(pipefd[1]);
  394. close(pipefd[1]);
  395. close(pipefd[0]);
  396. }
  397. #endif
  398. while ((c=getc(f)) >= 0)
  399. {
  400. if (c != '[')
  401. {
  402. putchar(c);
  403. continue;
  404. }
  405. c=getc(f);
  406. if (c != '#')
  407. {
  408. putchar('[');
  409. ungetc(c,f);
  410. continue;
  411. }
  412. c=getc(f);
  413. if (c == '?')
  414. {
  415. c=getc(f);
  416. if (c < '0' || c > '9')
  417. {
  418. putchar('[');
  419. putchar('#');
  420. putchar('?');
  421. putchar(c);
  422. continue;
  423. }
  424. if (
  425. #if ENABLE_WEBPASS
  426. #else
  427. c == '0' ||
  428. #endif
  429. (c == '1' && *cgi("folderdir") == ':') ||
  430. (c == '2' && *cgi("folderdir") != ':')
  431. )
  432. {
  433. while ((c=getc(f)) != EOF)
  434. {
  435. if (c != '[') continue;
  436. if ( getc(f) != '#') continue;
  437. if ( getc(f) != '?') continue;
  438. if ( getc(f) != '#') continue;
  439. if ( getc(f) == ']') break;
  440. }
  441. }
  442. continue;
  443. }
  444. if (c == '@')
  445. {
  446. argp=form_args;
  447. argn=sizeof(form_args)-1;
  448. while ((c=getc(f)) >= 0 && c != 'n' && argn)
  449. {
  450. if (c == '#')
  451. {
  452. c=getc(f);
  453. if (c == ']') break;
  454. ungetc(c, f);
  455. c='#';
  456. }
  457. if (c == '@')
  458. {
  459. c=getc(f);
  460. if (c == '@')
  461. {
  462. /*
  463.    Conditional image.  It's formatted as follows:
  464.    @@filename,width=x height=y@text@
  465.    If images are enabled, we replace that with an IMG tag we build from
  466.    filename,width=x, height=y.
  467.    If images are disabled, we replace all of this with text.
  468. */
  469. #define MKIMG(c) (argn ? *argp++=(c):0)
  470. if (noimages)
  471. {
  472. while ((c=getc(f)) >= 0
  473. && c != '@')
  474. if (c == '@')
  475. c=getc(f);
  476. while ((c=getc(f)) >= 0
  477. && c != '@')
  478. MKIMG(c);
  479. }
  480. else
  481. {
  482. char *p;
  483. MKIMG('<');
  484. MKIMG('I');
  485. MKIMG('M');
  486. MKIMG('G');
  487. MKIMG(' ');
  488. MKIMG('S');
  489. MKIMG('R');
  490. MKIMG('C');
  491. MKIMG('=');
  492. MKIMG('"');
  493. for (p=IMGPATH; *p; p++)
  494. MKIMG(*p);
  495. while ((c=getc(f)) >= 0
  496. && c != '@'
  497. && c != ',')
  498. MKIMG(c);
  499. MKIMG('"');
  500. MKIMG(' ');
  501. if (c == ',')
  502. c=getc(f);
  503. while (c >= 0 &&
  504. c != '@')
  505. {
  506. MKIMG(c);
  507. c=getc(f);
  508. }
  509. while ((c=getc(f)) >= 0
  510. && c != '@')
  511. ;
  512. MKIMG('>');
  513. }
  514. continue;
  515. }
  516. ungetc(c, f);
  517. c='@';
  518. }
  519. *argp++=c;
  520. --argn;
  521. }
  522. *argp=0;
  523. continue;
  524. }
  525. if (!isalnum(c))
  526. {
  527. putchar('[');
  528. putchar('#');
  529. ungetc(c, f);
  530. continue;
  531. }
  532. if ((c2=getc(f)) != '#')
  533. {
  534. putchar('[');
  535. putchar('#');
  536. putchar(c);
  537. ungetc(c2, f);
  538. continue;
  539. }
  540. if ((c3=getc(f)) != ']')
  541. {
  542. putchar('[');
  543. putchar('#');
  544. putchar(c);
  545. putchar(c2);
  546. ungetc(c3, f);
  547. continue;
  548. }
  549. switch (c) {
  550. case 'a':
  551. addressbook();
  552. break;
  553. case 'd':
  554. if (*cgi("folderdir"))
  555. {
  556. const char *c=cgi("folderdir");
  557. if (*c == ':')
  558. ++c; /* Sharable hierarchy */
  559. printf(" - ");
  560. print_safe(c);
  561. }
  562. break;
  563. case 'D':
  564. {
  565. const char *p=cgi("folder");
  566. const char *q=strrchr(p, '.');
  567. if (q)
  568. {
  569. char *r=malloc(q-p+1);
  570. if (!r) enomem();
  571. memcpy(r, p, q-p);
  572. r[q-p]=0;
  573. output_urlencoded(r);
  574. free(r);
  575. }
  576. }
  577. break;
  578. case 'G':
  579. output_attrencoded(login_returnaddr());
  580. break;
  581. case 'r':
  582. output_attrencoded(cgi("redirect"));
  583. break;
  584. case 's':
  585. output_scriptptrget();
  586. break;
  587. case 'S':
  588. output_loginscriptptr();
  589. break;
  590. case 'R':
  591. output_loginscriptptr_get();
  592. break;
  593. case 'p':
  594. output_scriptptr();
  595. break;
  596. case 'P':
  597. output_scriptptrpostinfo();
  598. break;
  599. case 'f':
  600. folder_contents_title();
  601. break;
  602. case 'F':
  603. folder_contents(sqwebmail_folder, atol(cgi("pos")));
  604. break;
  605. case 'n':
  606. folder_initnextprev(sqwebmail_folder, atol(cgi("pos")));
  607. break;
  608. case 'N':
  609. folder_nextprev();
  610. break;
  611. case 'm':
  612. folder_msgmove();
  613. break;
  614. case 'M':
  615. folder_showmsg(sqwebmail_folder, atol(cgi("pos")));
  616. break;
  617. case 'T':
  618. folder_showtransfer();
  619. break;
  620. case 'L':
  621. folder_list();
  622. break;
  623. case 'l':
  624. folder_list2();
  625. break;
  626. case 'E':
  627. folder_rename_list();
  628. break;
  629. case 'W':
  630. newmsg_init(sqwebmail_folder, cgi("pos"));
  631. break;
  632. case 'z':
  633. pref_isdisplayfullmsg();
  634. break;
  635. case 'y':
  636. pref_isoldest1st();
  637. break;
  638. case 'H':
  639. pref_displayhtml();
  640. break;
  641. case 'x':
  642. pref_setprefs();
  643. break;
  644. case 'w':
  645. pref_sortorder();
  646. break;
  647. case 't':
  648. pref_signature();
  649. break;
  650. case 'u':
  651. pref_pagesize();
  652. break;
  653. case 'v':
  654. pref_displayautopurge();
  655. break;
  656. case 'A':
  657. attachments_head(sqwebmail_folder, cgi("pos"),
  658. cgi("draft"));
  659. break;
  660. #ifdef ISPELL
  661. case 'K':
  662. spell_show();
  663. break;
  664. #endif
  665. #ifdef BANNERPROG
  666. case 'B':
  667. {
  668. char banargbuf[31];
  669. int i=0;
  670. int wait_stat;
  671. pid_t p, p2;
  672. if ((c=getc(f)) != '{')
  673. ungetc(c, f);
  674. else while ((c=getc(f)), isalnum(c))
  675. if (i < sizeof(banargbuf)-1)
  676. banargbuf[i++]=c;
  677. banargbuf[i]=0;
  678. fflush(stdout);
  679. if ( (p=fork()) == 0 )
  680. {
  681. execl(BANNERPROG, BANNERPROG,
  682. sqwebmail_formname,
  683. banargbuf, (char *)0);
  684. _exit(0);
  685. }
  686. if (p > 0)
  687. while ((p2=wait(&wait_stat)) > 0 &&
  688. p2 != p)
  689. ;
  690. }
  691. break;
  692. #endif
  693. case 'h':
  694. {
  695. FILE *fp=fopen(LOGINDOMAINLIST, "r");
  696. char buf[256];
  697. if (!fp) break;
  698. printf("<select name=logindomain><option value="">&nbsp;");
  699. while (fgets(buf, sizeof(buf), fp))
  700. {
  701. char *p=strchr(buf, 'n');
  702. if (*p) *p=0;
  703. printf("<option value="%s">@%s",
  704. buf, buf);
  705. }
  706. fclose(fp);
  707. printf("</select>");
  708. }
  709. break;
  710. case 'o':
  711. ldaplist();
  712. break;
  713. case 'O':
  714. doldapsearch();
  715. break;
  716. }
  717. }
  718. fclose(f);
  719. #ifdef GZIP
  720. if (pid > 0)
  721. {
  722. int waitstat;
  723. pid_t p2;
  724. /* Restore original stdout */
  725. fflush(stdout);
  726. close(1);
  727. dup(gzip_save_fd);
  728. close(gzip_save_fd);
  729. gzip_save_fd= -1;
  730. while ((p2=wait(&waitstat)) >= 0 && p2 != pid)
  731. ;
  732. }
  733. #endif
  734. }
  735. /* Top level HTTP redirect without referencing a particular mailbox */
  736. static void http_redirect_top(const char *app)
  737. {
  738. const char *p=nonloginscriptptr();
  739. char *buf=malloc(strlen(p)+strlen(app)+2);
  740. if (!buf) enomem();
  741. strcat(strcpy(buf, p), app);
  742. cgiredirect(buf);
  743. free(buf);
  744. }
  745. /* HTTP redirects within a given mailbox, various formats */
  746. void http_redirect_argu(const char *fmt, unsigned long un)
  747. {
  748. char buf[MAXLONGSIZE];
  749. sprintf(buf, "%lu", un);
  750. http_redirect_argss(fmt, buf, "");
  751. }
  752. void http_redirect_argss(const char *fmt, const char *arg1, const char *arg2)
  753. {
  754. http_redirect_argsss(fmt, arg1, arg2, "");
  755. }
  756. void http_redirect_argsss(const char *fmt, const char *arg1, const char *arg2,
  757. const char *arg3)
  758. {
  759. char *base=scriptptrget();
  760. char *arg1s=cgiurlencode(arg1);
  761. char *arg2s=cgiurlencode(arg2);
  762. char *arg3s=cgiurlencode(arg3);
  763. char *q;
  764. /* We generate a Location: redirected_url header.  The actual
  765. ** header is generated in cgiredirect, we just build it here */
  766. q=malloc(strlen(base)+strlen(fmt)+strlen(arg1s)+strlen(arg2s)+
  767. strlen(arg3s)+1);
  768. if (!q) enomem();
  769. strcpy(q, base);
  770. sprintf(q+strlen(q), fmt, arg1s, arg2s, arg3s);
  771. cgiredirect(q);
  772. free(q);
  773. free(arg1s);
  774. free(arg2s);
  775. free(arg3s);
  776. free(base);
  777. }
  778. void output_user_form(const char *formname)
  779. {
  780. char *p;
  781. if (!*formname || strchr(formname, '.') || strchr(formname, '/'))
  782. error("Invalid request.");
  783. if (*cgi("ldapsearch")) /* Special voodoo for LDAP address book stuff */
  784. {
  785. if (ldapsearch() == 0)
  786. {
  787. output_form("ldapsearch.html");
  788. return;
  789. }
  790. }
  791. /*
  792. ** In order to hide the session ID in the URL of the message what
  793. ** we do is that the initial URL, that contains setcookie=1, results
  794. ** in us setting a temporary cookie that contains the session ID,
  795. ** then we return a redirect to a url which has /printmsg/ in the
  796. ** PATH_INFO, instead of the session ID.  The code in main()
  797. ** traps /printmsg/ PATH_INFO, fetches the path info from the
  798. ** cookie, and punts after resetting setcookie to 0.
  799. */
  800. if (strcmp(formname, "print") == 0 && *cgi("setcookie") == '1')
  801. {
  802. const char *qs=getenv("QUERY_STRING");
  803. const char *pi=getenv("PATH_INFO");
  804. const char *nl;
  805. char *buf;
  806. if (!pi) pi="";
  807. if (!pi) pi="";
  808. nl=nonloginscriptptr();
  809. buf=malloc(strlen(nl) + sizeof("/printmsg/print?")+strlen(qs));
  810. if (!buf) enomem();
  811. strcat(strcat(strcpy(buf, nl), "/printmsg/print?"), qs);
  812. cginocache();
  813. cgi_setcookie("sqwebmail-pi", pi);
  814. printf("Refresh: 0; URL="%s"n", buf);
  815. free(buf);
  816. output_form("printredirect.html");
  817. return;
  818. }
  819. if (strcmp(formname, "logout") == 0)
  820. {
  821. unlink(IPFILE);
  822. http_redirect_top("");
  823. return;
  824. }
  825. if (strcmp(formname, "fetch") == 0)
  826. {
  827. folder_download( sqwebmail_folder, atol(cgi("pos")),
  828. cgi("mimeid") );
  829. return;
  830. }
  831. if (strcmp(formname, "delmsg") == 0)
  832. {
  833. folder_delmsg( atol(cgi("pos")));
  834. return;
  835. }
  836. if (strcmp(formname, "donewmsg") == 0)
  837. {
  838. newmsg_do(sqwebmail_folder);
  839. return;
  840. }
  841. if (strcmp(formname, "doattach") == 0)
  842. {
  843. doattach(sqwebmail_folder, cgi("draft"));
  844. return;
  845. }
  846. if (strcmp(formname, "folderdel") == 0)
  847. {
  848. folder_delmsgs(sqwebmail_folder, atol(cgi("pos")));
  849. return;
  850. }
  851. if (strcmp(formname, "spellchk") == 0)
  852. {
  853. #ifdef ISPELL
  854. spell_check_continue();
  855. #else
  856. printf("Status: 404");
  857. #endif
  858. return;
  859. }
  860. p=malloc(strlen(formname)+6);
  861. if (!p) enomem();
  862. strcat(strcpy(p, formname),".html");
  863. output_form(p);
  864. free(p);
  865. }
  866. #if ENABLE_WEBPASS
  867. /* System-compatible crypt function */
  868. static const char *auth_crypt(const char *password, const char *salt)
  869. {
  870. #if     HAVE_CRYPT
  871. if (strncmp(salt, "$1$", 3))
  872. return (crypt(password, salt));
  873. #endif
  874. return (md5_crypt(password, salt));
  875. }
  876. /*
  877. ** Support for sqwebmail-only password.  Versions prior to 0.12 stored
  878. ** it in clear test.  0.12 and later use crypt(), but still are able to
  879. ** handle cleartex
  880. */
  881. int check_sqwebpass(const char *pass)
  882. {
  883. const char *p=read_sqconfig(".", PASSFILE, 0);
  884. if (p && *p == 't')
  885. /* Starts with t - crypt */
  886. {
  887. ++p;
  888. if (strcmp(p, auth_crypt(pass, p)) == 0) return (0);
  889. return (-1);
  890. }
  891. if (p && strcmp(p, pass) == 0) return (0);
  892. return (-1);
  893. }
  894. int has_sqwebpass()
  895. {
  896. return (read_sqconfig(".", PASSFILE, 0) ? 1:0);
  897. }
  898. static const char salt[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
  899. void set_sqwebpass(const char *pw)
  900. {
  901. char buf[100];
  902. char buf2[100];
  903. const char *r=random128();
  904. unsigned i;
  905. #ifdef WEBPASS_CHANGE_VCHKPW
  906. const char *p;
  907. #endif
  908. /* r is 16 bytes.  We need 12 bits to initialize the salt */
  909. buf2[4]=0;
  910. i=0;
  911. while (*r)
  912. {
  913. i <<= 1;
  914. i |= (*r & 1);
  915. ++r;
  916. }
  917. buf[0]= salt[ i & 63];
  918. i /= 64;
  919. buf[1]= salt[ i & 63 ];
  920. buf[2]= 0;
  921. strcpy(buf, auth_crypt(pw, buf));
  922. buf2[0]='t';
  923. strcpy(buf2+1, buf);
  924. #ifdef WEBPASS_CHANGE_VCHKPW
  925. if(( p=login_returnaddr() ))
  926. {
  927. char *user;
  928. char *domain;
  929. char *p2;
  930. char *pw2;
  931. p2=strdup(p);
  932. pw2=strdup(pw);
  933. user=strtok(p2, "@");
  934. domain=strtok(0, "@");
  935. if(vpasswd(user,domain,pw2,0) == 0)
  936. write_sqconfig(".", PASSFILE, buf2);
  937. free(p2);
  938. free(pw2);
  939. return;
  940. }
  941. #endif
  942. write_sqconfig(".", PASSFILE, buf2);
  943. }
  944. #endif
  945. extern void folder_cleanup();
  946. extern void maildir_cleanup();
  947. #ifdef ISPELL
  948. extern void ispell_cleanup();
  949. #endif
  950. void cleanup()
  951. {
  952. int i;
  953. for(i=0; i<sizeof(form_args); ++i)
  954. form_args[i] = '';
  955. sqwebmail_formname = NULL;
  956. sqwebmail_mailboxid=0;
  957. sqwebmail_folder=0;
  958. sqwebmail_sessiontoken=0;
  959. sqwebmail_content_language=0;
  960. sqwebmail_content_locale=0;
  961. sqwebmail_content_ispelldict=0;
  962. folder_cleanup();
  963. maildir_cleanup();
  964. #ifdef ISPELL
  965. ispell_cleanup();
  966. #endif
  967. #ifdef GZIP
  968. if (gzip_save_fd >= 0) /* Restore original stdout */
  969. {
  970. close(1);
  971. dup(gzip_save_fd);
  972. close(gzip_save_fd);
  973. gzip_save_fd= -1;
  974. }
  975. #endif
  976. }
  977. static RETSIGTYPE catch_sig(int n)
  978. {
  979. n=n;
  980. cleanup();
  981. fake_exit(0);
  982. #if RETSIGTYPE != void
  983. return (0);
  984. #endif
  985. }
  986. static void init_default_locale()
  987. {
  988. char *cl=http11_best_content_language(HTMLLIBDIR,
  989. getenv("HTTP_ACCEPT_LANGUAGE"));
  990. sqwebmail_content_language=
  991. http11_content_language(HTMLLIBDIR, cl);
  992. sqwebmail_content_locale=
  993. http11_content_locale(HTMLLIBDIR, cl);
  994. sqwebmail_content_ispelldict=
  995. http11_content_ispelldict(HTMLLIBDIR, cl);
  996. sqwebmail_content_charset=
  997. http11_content_charset(HTMLLIBDIR, cl);
  998. free(cl);
  999. #if HAVE_LOCALE_H
  1000. #if HAVE_SETLOCALE
  1001. setlocale(LC_ALL, sqwebmail_content_locale);
  1002. #endif
  1003. #endif
  1004. }
  1005. static int main2();
  1006. int main()
  1007. {
  1008. int rc;
  1009. #if HAVE_LIBFCGI
  1010. while ( FCGI_Accept() >= 0)
  1011. {
  1012. if (setjmp(stackenv) == 0)
  1013. {
  1014. rc=main2();
  1015. cleanup(); /* make sure we hit it */
  1016. FCGI_SetExitStatus(rc);
  1017. continue;
  1018. }
  1019. cleanup(); /* make sure we hit it */
  1020. signal(SIGHUP, catch_sig);
  1021. signal(SIGINT, catch_sig);
  1022. signal(SIGPIPE, catch_sig);
  1023. signal(SIGTERM, catch_sig);
  1024. }
  1025. return (0);
  1026. #else
  1027. rc=main2();
  1028. exit(rc);
  1029. return (rc);
  1030. #endif
  1031. }
  1032. static int main2()
  1033. {
  1034. const char *u;
  1035. const char *ip_addr;
  1036. char *pi;
  1037. char *pi_malloced;
  1038. int reset_cookie=0;
  1039. #ifdef GZIP
  1040. gzip_save_fd= -1;
  1041. #endif
  1042. u=ip_addr=pi=NULL;
  1043. ip_addr=getenv("REMOTE_ADDR");
  1044. signal(SIGHUP, catch_sig);
  1045. signal(SIGINT, catch_sig);
  1046. signal(SIGPIPE, catch_sig);
  1047. signal(SIGTERM, catch_sig);
  1048. if (!ip_addr) ip_addr="127.0.0.1";
  1049. umask(0077);
  1050. init_login_cache(TIMEOUTHARD);
  1051. pi=getenv("PATH_INFO");
  1052. pi_malloced=0;
  1053. if (pi && strncmp(pi, "/printmsg/", 10) == 0)
  1054. {
  1055. /* See comment in output_user_form */
  1056. pi_malloced=pi=cgi_cookie("sqwebmail-pi");
  1057. if (*pi_malloced == 0)
  1058. {
  1059. free(pi_malloced);
  1060. output_form("printnocookie.html");
  1061. return (0);
  1062. }
  1063. reset_cookie=1;
  1064. cgi_setcookie("sqwebmail-pi", "DELETED");
  1065. }
  1066. if (pi && strncmp(pi, "/login/", 7) == 0)
  1067. {
  1068. const char *p;
  1069. time_t last_time, current_time;
  1070. char *q;
  1071. /* Logging into the mailbox */
  1072. pi=strdup(pi);
  1073. if (pi_malloced) free(pi_malloced);
  1074. if (!pi) enomem();
  1075. (void)strtok(pi, "/"); /* Skip login */
  1076. u=strtok(NULL, "/"); /* mailboxid */
  1077. sqwebmail_sessiontoken=strtok(NULL, "/"); /* sessiontoken */
  1078. q=strtok(NULL, "/"); /* login time */
  1079. login_time=0;
  1080. while (q && *q >= '0' && *q <= '9')
  1081. login_time=login_time * 10 + (*q++ - '0');
  1082. if (check_login_cache(u, login_time) && prelogin(u))
  1083. {
  1084. free(pi);
  1085. error("Unable to access your mailbox, sqwebmail permissions may be wrong.");
  1086. }
  1087. time(&current_time);
  1088. /* Ok, boys and girls, time to validate the connection as
  1089. ** follows */
  1090. if ( !sqwebmail_sessiontoken
  1091. /* 1. Read IPFILE.  Check that it's timestamp is current enough,
  1092. ** and the session hasn't timed out.
  1093. */
  1094. || !(p=read_sqconfig(".", IPFILE, &last_time))
  1095. /* || last_time > current_time */
  1096. || last_time + TIMEOUTHARD < current_time
  1097. /* 2. IPFILE will contain four words - IP address, session
  1098. ** token, language, locale, ispell dictionary.  Validate both.
  1099. */
  1100. || !(q=strdup(p))
  1101. || !(p=strtok(q, " "))
  1102. || (strcmp(p, ip_addr) && strcmp(p, "none"))
  1103. || !(p=strtok(NULL, " "))
  1104. || strcmp(p, sqwebmail_sessiontoken)
  1105. || !(p=strtok(NULL, " "))
  1106. || !(sqwebmail_content_language=strdup(p))
  1107. || !(p=strtok(NULL, " "))
  1108. || !(sqwebmail_content_locale=strdup(p))
  1109. || !(p=strtok(NULL, " "))
  1110. || !(sqwebmail_content_ispelldict=strdup(p))
  1111. || !(p=strtok(NULL, " "))
  1112. || !(sqwebmail_content_charset=strdup(p))
  1113. /* 3. Check the timestamp on the TIMESTAMP file.  See if the
  1114. ** session has reached its soft timeout.
  1115. */
  1116. || !read_sqconfig(".", TIMESTAMP, &last_time)
  1117. /* || last_time > current_time */
  1118. || last_time + TIMEOUTSOFT < current_time)
  1119. {
  1120. setgid(getgid());
  1121. setuid(getuid()); /* Drop root prevs */
  1122. chdir("/");
  1123. cgi_setup();
  1124. init_default_locale();
  1125. free(pi);
  1126. if (strcmp(cgi("form"), "logout") == 0)
  1127. /* Already logged out, and the link
  1128. ** had target=_parent tag.
  1129. */
  1130. {
  1131. http_redirect_top("");
  1132. return (0);
  1133. }
  1134. output_form("expired.html");
  1135. return (0);
  1136. }
  1137. free(q);
  1138. cgiformdatatempdir("tmp");
  1139. cgi_setup(); /* Read CGI environment */
  1140. if (reset_cookie)
  1141. cgi_put("setcookie", "0");
  1142. /* Update soft timeout stamp */
  1143. write_sqconfig(".", TIMESTAMP, "");
  1144. /* We must always have the folder CGI arg */
  1145. if (!*(sqwebmail_folder=cgi("folder")))
  1146. {
  1147. init_default_locale();
  1148. output_form("expired.html");
  1149. free(pi);
  1150. return (0);
  1151. }
  1152. sqwebmail_mailboxid=u;
  1153. #if HAVE_LOCALE_H
  1154. #if HAVE_SETLOCALE
  1155. setlocale(LC_ALL, sqwebmail_content_locale);
  1156. #endif
  1157. #endif
  1158. pref_init();
  1159. output_user_form(cgi("form"));
  1160. free(pi);
  1161. }
  1162. else
  1163. /* Must be one of those special forms */
  1164. {
  1165. char *rm;
  1166. long n;
  1167. if (pi_malloced) free(pi_malloced);
  1168. if ((rm=getenv("REQUEST_METHOD")) == 0 ||
  1169. (strcmp(rm, "POST") == 0 &&
  1170. ((rm=getenv("CONTENT_TYPE")) != 0 &&
  1171. strncasecmp(rm,"multipart/form-data;", 20)
  1172. == 0)))
  1173. enomem(); /* multipart/formdata posts not allowed
  1174. */
  1175. /* Some additional safety checks */
  1176. rm=getenv("CONTENT_LENGTH");
  1177. n= rm ? atol(rm):0;
  1178. if (n < 0 || n > 256) enomem();
  1179. cgi_setup();
  1180. init_default_locale();
  1181. if (*(u=cgi("username")))
  1182. /* Request to log in */
  1183. {
  1184. const char *p=cgi("password");
  1185. const char *mailboxid;
  1186. const char *u2=cgi("logindomain");
  1187. char *ubuf=malloc(strlen(u)+strlen(u2)+2);
  1188. strcpy(ubuf, u);
  1189. if (*u2)
  1190. strcat(strcat(ubuf, "@"), u2);
  1191. prepare_login_cache();
  1192. if (*p && (mailboxid=login(ubuf, p)) != 0)
  1193. {
  1194. char *q;
  1195. const char *saveip=ip_addr;
  1196. #if ENABLE_WEBPASS
  1197. if (!has_sqwebpass())
  1198. set_sqwebpass(p);
  1199. #endif
  1200. sqwebmail_mailboxid=mailboxid;
  1201. sqwebmail_folder="INBOX";
  1202. sqwebmail_sessiontoken=random128();
  1203. if (*cgi("sameip") == 0)
  1204. saveip="none";
  1205. q=malloc(strlen(saveip)
  1206. +strlen(sqwebmail_sessiontoken)
  1207. +strlen(sqwebmail_content_language)
  1208. +strlen(sqwebmail_content_ispelldict)
  1209. +strlen(sqwebmail_content_charset)
  1210. +strlen(sqwebmail_content_locale)+6);
  1211. if (!q) enomem();
  1212. sprintf(q, "%s %s %s %s %s %s", saveip,
  1213. sqwebmail_sessiontoken,
  1214. sqwebmail_content_language,
  1215. sqwebmail_content_locale,
  1216. sqwebmail_content_ispelldict,
  1217. sqwebmail_content_charset);
  1218. write_sqconfig(".", IPFILE, q);
  1219. free(q);
  1220. time(&login_time);
  1221. save_login_cache(mailboxid, login_time);
  1222. write_sqconfig(".", TIMESTAMP, "");
  1223. (void)maildir_create(DRAFTS);
  1224. (void)maildir_create(SENT);
  1225. (void)maildir_create(TRASH);
  1226. pref_init();
  1227. maildir_autopurge();
  1228. http_redirect_argss("&form=folders", "", "");
  1229. /* output_form("folders.html"); */
  1230. free(ubuf);
  1231. return(0);
  1232. }
  1233. cancel_login_cache();
  1234. free(ubuf);
  1235. output_form("invalid.html"); /* Invalid login */
  1236. return (0);
  1237. }
  1238. setgid(getgid());
  1239. setuid(getuid());
  1240. if ( *(u=cgi("redirect")))
  1241. /* Redirection request to hide the referral tag */
  1242. {
  1243. printf("Refresh: 0; URL="%s"n", u);
  1244. output_form("redirect.html");
  1245. }
  1246. else if ( *cgi("noframes") == '1')
  1247. output_form("login.html"); /* Main frame */
  1248. else
  1249. if ( *cgi("empty") == '1')
  1250. output_form("empty.html"); /* Minor frameset */
  1251. /*
  1252. ** Apparently we can't show just SCRIPT NAME as our frameset due to some
  1253. ** weird bug in Communicator which, under certain conditions, will get
  1254. ** confused figuring out which page views have expired.  POSTs with URLs
  1255. ** referring to SCRIPT_NAME will be replied with an expiration header, and
  1256. ** Communicator will assume that index.html also has expired, forcing a
  1257. ** frameset reload the next time the Communicator window is resized,
  1258. ** essentially logging the user off.
  1259. */
  1260. else if (*cgi("index") == '1')
  1261. output_form("index.html"); /* Frameset Window */
  1262. else
  1263. {
  1264. http_redirect_top("?index=1");
  1265. }
  1266. return (0);
  1267. }
  1268. return (0);
  1269. }
  1270. #ifdef malloc
  1271. #undef malloc
  1272. #undef realloc
  1273. #undef free
  1274. #undef strdup
  1275. #undef calloc
  1276. static void *allocp[1000];
  1277. extern void *malloc(size_t), *realloc(void *, size_t), free(void *),
  1278. *calloc(size_t, size_t);
  1279. extern char *strdup(const char *);
  1280. char *my_strdup(const char *c)
  1281. {
  1282. size_t i;
  1283. for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
  1284. if (!allocp[i])
  1285. return (allocp[i]=strdup(c));
  1286. abort();
  1287. return (0);
  1288. }
  1289. void *my_malloc(size_t n)
  1290. {
  1291. size_t i;
  1292. for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
  1293. if (!allocp[i])
  1294. return (allocp[i]=malloc(n));
  1295. abort();
  1296. return (0);
  1297. }
  1298. void *my_calloc(size_t a, size_t b)
  1299. {
  1300. size_t i;
  1301. for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
  1302. if (!allocp[i])
  1303. return (allocp[i]=calloc(a,b));
  1304. abort();
  1305. return (0);
  1306. }
  1307. void *my_realloc(void *p, size_t s)
  1308. {
  1309. size_t i;
  1310. for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
  1311. if (p && allocp[i] == p)
  1312. {
  1313. void *q=realloc(p, s);
  1314. if (q) allocp[i]=q;
  1315. return (q);
  1316. }
  1317. abort();
  1318. }
  1319. void my_free(void *p)
  1320. {
  1321. size_t i;
  1322. for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
  1323. if (p && allocp[i] == p)
  1324. {
  1325. free(p);
  1326. allocp[i]=0;
  1327. return;
  1328. }
  1329. abort();
  1330. }
  1331. #endif