1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6
7 /*
8 ** $Id: sqwebmail.c,v 1.147 2009/11/08 18:14:47 mrsam Exp $
9 */
10 #include "sqwebmail.h"
11 #include "sqconfig.h"
12 #include "auth.h"
13 #include "folder.h"
14 #include "pref.h"
15 #include "maildir.h"
16 #include "cgi/cgi.h"
17 #include "pref.h"
18 #include "mailinglist.h"
19 #include "newmsg.h"
20 #include "pcp.h"
21 #include "acl.h"
22 #include "addressbook.h"
23 #include "autoresponse.h"
24 #include "http11/http11.h"
25 #include "random128/random128.h"
26 #include "maildir/maildirmisc.h"
27 #include "maildir/maildirinfo.h"
28 #include "maildir/maildiraclt.h"
29 #include "liblock/config.h"
30 #include "liblock/liblock.h"
31 #include "rfc822/rfc822hdr.h"
32 #include "courierauth.h"
33 #include <stdio.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #include <string.h>
40 #include <signal.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #if HAVE_FCNTL_H
46 #include <fcntl.h>
47 #endif
48 #if HAVE_LOCALE_H
49 #if HAVE_SETLOCALE
50 #include <locale.h>
51 #if USE_LIBCHARSET
52 #if HAVE_LOCALCHARSET_H
53 #include <localcharset.h>
54 #elif HAVE_LIBCHARSET_H
55 #include <libcharset.h>
56 #endif /* HAVE_LOCALCHARSET_H */
57 #elif HAVE_LANGINFO_CODESET
58 #include <langinfo.h>
59 #endif /* USE_LIBCHARSET */
60 #endif /* HAVE_SETLOCALE */
61 #endif /* HAVE_LOCALE_H */
62 #include <ctype.h>
63 #if HAVE_SYS_WAIT_H
64 #include <sys/wait.h>
65 #endif
66 #if HAVE_SYS_SELECT_H
67 #include <sys/select.h>
68 #endif
69 #if HAVE_SYS_UIO_H
70 #include <sys/uio.h>
71 #endif
72 #define MD5_INTERNAL
73 #include "md5/md5.h"
74
75 #include <courierauthdebug.h>
76 #include "maildir/maildircache.h"
77 #include "maildir/maildiraclt.h"
78 #include "maildir/maildirnewshared.h"
79 #include "mailfilter.h"
80 #include "numlib/numlib.h"
81 #include "gpglib/gpglib.h"
82 #include "gpg.h"
83 #if HAVE_CRYPT_H
84 #include <crypt.h>
85 #endif
86 #if NEED_CRYPT_PROTOTYPE
87 extern char *crypt(const char *, const char *);
88 #endif
89 #include "htmllibdir.h"
90
91 #include "logindomainlist.h"
92
93 #include "strftime.h"
94
95 extern void spell_show();
96 extern void spell_check_continue();
97 extern void print_safe(const char *);
98 extern void ldaplist();
99 extern int ldapsearch();
100 extern void doldapsearch();
101
102 extern void sent_gpgerrtxt();
103 extern void sent_gpgerrresume();
104 extern const char *redirect_hash(const char *);
105
106 const char *sqwebmail_mailboxid=0;
107 const char *sqwebmail_folder=0;
108
109 #define ALL_RIGHTS \
110 ACL_ADMINISTER \
111 ACL_CREATE \
112 ACL_EXPUNGE \
113 ACL_INSERT \
114 ACL_LOOKUP \
115 ACL_READ \
116 ACL_SEEN \
117 ACL_DELETEMSGS \
118 ACL_WRITE \
119 ACL_DELETEFOLDER
120 char sqwebmail_folder_rights[sizeof(ALL_RIGHTS)];
121
122 const char *sqwebmail_sessiontoken=0;
123
124 const char *sqwebmail_content_language=0;
125 const char *sqwebmail_content_locale;
126 const char *sqwebmail_system_charset=0;
127 static char *sys_locale_charset=0;
128
129 const char *sqwebmail_content_ispelldict;
130 const char *sqwebmail_content_charset;
131
132 dev_t sqwebmail_homedir_dev;
133 ino_t sqwebmail_homedir_ino;
134
135 static int noimages=0;
136
137 time_t login_time;
138
139 extern int nochangepass();
140
141 /* Need to cache the following environment variables */
142 static const char * const authvars[] = { "AUTHADDR", "AUTHFULLNAME",
143 "OPTIONS", "AUTHENTICATED", 0 };
144
145 #ifdef GZIP
146 static int gzip_save_fd;
147
148 #endif
149
150 static const char *sqwebmail_formname;
151
152 extern void attachments_head(const char *, const char *, const char *);
153 extern void attachments_opts(const char *);
154 extern void doattach(const char *, const char *);
155
156 static void timezonelist();
157
158 struct template_stack {
159 struct template_stack *next;
160 FILE *fp;
161 } ;
162
163 static struct template_stack *template_stack=NULL;
164
165 char *trim_spaces(const char *s);
166
get_timeoutsoft()167 size_t get_timeoutsoft()
168 {
169 time_t n=TIMEOUTSOFT;
170 const char *p;
171
172 p=getenv("SQWEBMAIL_TIMEOUTSOFT");
173
174 if (p && *p)
175 n=atoi(p);
176
177 return n;
178 }
179
get_timeouthard()180 size_t get_timeouthard()
181 {
182 time_t n=TIMEOUTHARD;
183 const char *p;
184
185 p=getenv("SQWEBMAIL_TIMEOUTHARD");
186
187 if (p && *p)
188 n=atoi(p);
189
190 return n;
191 }
192
fake_exit(int n)193 void fake_exit(int n)
194 {
195 maildir_cache_cancel();
196 exit(n);
197 }
198
199
200 /* Stub to catch aborts from authlib */
201
authexit(int n)202 void authexit(int n)
203 {
204 fake_exit(n);
205 }
206
207 /* enomem() used to be just an out-of-memory handler. Now, I use it as a
208 ** generic failure type of a deal.
209 */
210
rfc2045_error(const char * p)211 void rfc2045_error(const char *p)
212 {
213 error(p);
214 }
215
print_attrencodedlen(const char * p,size_t len,int oknl,FILE * fp)216 void print_attrencodedlen(const char *p, size_t len, int oknl, FILE *fp)
217 {
218 for (; len; p++, --len)
219 {
220 switch (*p) {
221 case '<':
222 fprintf(fp, "<");
223 continue;
224 case '>':
225 fprintf(fp, ">");
226 continue;
227 case '&':
228 fprintf(fp, "&");
229 continue;
230 case '"':
231 fprintf(fp, """);
232 continue;
233 case '\n':
234 if (oknl)
235 {
236 if (oknl == 2)
237 {
238 fprintf(fp, "<br />");
239 continue;
240 }
241 putc('\n', fp);
242 continue;
243 }
244 default:
245 if (!ISCTRL(*p))
246 {
247 putc(*p, fp);
248 continue;
249 }
250 }
251 fprintf(fp, "&#%d;", (int)(unsigned char)*p);
252 }
253 }
254
output_attrencoded_fp(const char * p,FILE * fp)255 void output_attrencoded_fp(const char *p, FILE *fp)
256 {
257 print_attrencodedlen(p, strlen(p), 0, fp);
258 }
259
output_attrencoded(const char * p)260 void output_attrencoded(const char *p)
261 {
262 output_attrencoded_fp(p, stdout);
263 }
264
output_attrencoded_oknl_fp(const char * p,FILE * fp)265 void output_attrencoded_oknl_fp(const char *p, FILE *fp)
266 {
267 print_attrencodedlen(p, strlen(p), 1, fp);
268 }
269
output_attrencoded_oknl(const char * p)270 void output_attrencoded_oknl(const char *p)
271 {
272 output_attrencoded_oknl_fp(p, stdout);
273 }
274
output_attrencoded_nltobr(const char * p)275 void output_attrencoded_nltobr(const char *p)
276 {
277 print_attrencodedlen(p, strlen(p), 2, stdout);
278 }
279
output_urlencoded(const char * p)280 void output_urlencoded(const char *p)
281 {
282 char *q=cgiurlencode(p);
283
284 printf("%s", q);
285 free(q);
286 }
287
output_loginscriptptr()288 void output_loginscriptptr()
289 {
290 #if USE_HTTPS_LOGIN
291 const char *p=cgihttpsscriptptr();
292 #elif USE_RELATIVE_URL
293 const char *p=cgirelscriptptr();
294 #else
295 const char *p=cgihttpscriptptr();
296 #endif
297
298 printf("%s", p);
299 }
300
nonloginscriptptr()301 const char *nonloginscriptptr()
302 {
303 #if USE_HTTPS
304 return (cgihttpsscriptptr());
305 #elif USE_RELATIVE_URL
306 return (cgirelscriptptr());
307 #else
308 return (cgihttpscriptptr());
309 #endif
310 }
311
312
output_scriptptr()313 void output_scriptptr()
314 {
315 const char *p=nonloginscriptptr();
316
317 printf("%s", p);
318 if (sqwebmail_mailboxid)
319 {
320 char *q=cgiurlencode(sqwebmail_mailboxid);
321 char buf[NUMBUFSIZE];
322
323 printf("/login/%s/%s/%s", q,
324 sqwebmail_sessiontoken ? sqwebmail_sessiontoken:" ",
325 libmail_str_time_t(login_time, buf));
326 free(q);
327 }
328 }
329
output_loginscriptptr_get()330 void output_loginscriptptr_get()
331 {
332 output_loginscriptptr();
333 if (sqwebmail_mailboxid)
334 {
335 char *q=cgiurlencode(sqwebmail_mailboxid);
336 char buf[NUMBUFSIZE];
337
338 printf("/login/%s/%s/%s", q,
339 sqwebmail_sessiontoken ? sqwebmail_sessiontoken:" ",
340 libmail_str_time_t(login_time, buf));
341 free(q);
342 }
343 }
344
scriptptrget()345 char *scriptptrget()
346 {
347 char *q=0;
348 size_t l=0;
349 int i;
350 char buf[NUMBUFSIZE];
351
352 #define ADD(s) {const char *zz=(s); if (i) strcat(q, zz); l += strlen(zz);}
353 #define ADDE(ue) { char *yy=cgiurlencode(ue); ADD(yy); free(yy); }
354
355 for (i=0; i<2; i++)
356 {
357 if (i && (q=malloc(l+1)) == 0) enomem();
358 if (i) *q=0;
359 ADD( nonloginscriptptr() );
360 if (!sqwebmail_mailboxid)
361 {
362 ADD("?");
363 continue;
364 }
365
366 ADD("/login/");
367 ADDE(sqwebmail_mailboxid);
368 ADD("/");
369 ADD(sqwebmail_sessiontoken ? sqwebmail_sessiontoken:" ");
370 ADD("/");
371 ADD(libmail_str_time_t(login_time, buf));
372
373 ADD( "?" );
374 if (sqwebmail_folder)
375 {
376 ADD("folder=");
377 ADDE(sqwebmail_folder);
378 }
379 }
380 #undef ADD
381 #undef ADDE
382 return (q);
383 }
384
output_scriptptrget()385 void output_scriptptrget()
386 {
387 char *p=scriptptrget();
388
389 printf("%s", p);
390 free(p);
391 return;
392 }
393
output_scriptptrpostinfo()394 void output_scriptptrpostinfo()
395 {
396 if (sqwebmail_folder)
397 {
398 printf("<input type=\"hidden\" name=\"folder\" value=\"");
399 output_attrencoded(sqwebmail_folder);
400 printf("\" />");
401 }
402
403 if (*cgi("folderdir")) /* In folders.html */
404 {
405 printf("<input type=\"hidden\" name=\"folderdir\" value=\"");
406 output_attrencoded(cgi("folderdir"));
407 printf("\" />");
408 }
409 }
410
error(const char * errmsg)411 void error(const char *errmsg)
412 {
413 cginocache();
414 printf("Content-Type: text/html; charset=us-ascii\n\n"
415 "<html><head><title>%s</title></head><body><h1>%s</h1></body></html>\n",
416 errmsg, errmsg);
417 cleanup();
418 fake_exit(1);
419 }
420
error2(const char * file,int line)421 void error2(const char *file, int line)
422 {
423 cginocache();
424 printf("Content-Type: text/html; charset=us-ascii\n\n"
425 "<html><head><title>Internal error</title></head><body>"
426 "<h1>Internal error (module %s, line %d) - contact system administrator</h1>"
427 "</body></html>\n",
428 file, line);
429 cleanup();
430 fake_exit(1);
431 }
432
error3(const char * file,int line,const char * msg1,const char * msg2,int err)433 void error3(const char *file, int line, const char *msg1, const char *msg2, int err)
434 {
435 cginocache();
436 if (err == -1) err = errno;
437 printf("Content-Type: text/html; charset=us-ascii\n\n"
438 "<html><head><title>Internal error</title></head><body>"
439 "<h1>Internal error (module %s, line %d) - contact system administrator</h1>"
440 "<pre>%s\n%s\n%s</pre>"
441 "</body></html>\n",
442 file, line, msg1?msg1:"", msg2?msg2:"", err?strerror(err):"");
443 cleanup();
444 fake_exit(1);
445 }
446
447
get_templatedir()448 char *get_templatedir()
449 {
450 char *templatedir=getenv("SQWEBMAIL_TEMPLATEDIR");
451
452 if (!templatedir || !*templatedir) templatedir=HTMLLIBDIR;
453
454 return templatedir;
455 }
456
457
get_imageurl()458 char *get_imageurl()
459 {
460 char *imageurl=getenv("SQWEBMAIL_IMAGEURL");
461
462 if (!imageurl || !*imageurl) imageurl=IMGPATH;
463
464 return imageurl;
465 }
466
467
open_langform(const char * lang,const char * formname,int print_header)468 FILE *open_langform(const char *lang, const char *formname,
469 int print_header)
470 {
471 char *formpath;
472 FILE *f;
473 char *templatedir=get_templatedir();
474
475 /* templatedir/lang/formname */
476
477 if (!(formpath=malloc(strlen(templatedir)+3+
478 strlen(lang)+strlen(formname))))
479 error("Out of memory.");
480
481 strcat(strcat(strcat(strcat(strcpy(formpath, templatedir), "/"),
482 lang), "/"), formname);
483
484 f=fopen(formpath, "r");
485
486 free(formpath);
487
488 if (f && print_header)
489 printf("Content-Language: %s\n", lang);
490 if (f)
491 fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
492 return (f);
493 }
494
ishttps()495 int ishttps()
496 {
497 const char *p=getenv("HTTPS");
498
499 return (p && strcasecmp(p, "on") == 0);
500 }
501
502 struct var_put_buf {
503 char argbuf[3072];
504 char *argp;
505 size_t argn;
506 } ;
507
var_put_buf_func(int c,void * p)508 static void var_put_buf_func(int c, void *p)
509 {
510 struct var_put_buf *pp=(struct var_put_buf *)p;
511
512 if (pp->argn)
513 {
514 *pp->argp++=c;
515 --pp->argn;
516 }
517 }
518
pass_image_through(int c,void * p)519 static void pass_image_through(int c, void *p)
520 {
521 putchar(c);
522 }
523
output_image(FILE * f,void (* output_func)(int,void *),void * void_arg)524 static void output_image( FILE *f,
525 void (*output_func)(int, void *), void *void_arg)
526 {
527 int c;
528
529 /*
530 Conditional image. It's formatted as follows:
531
532 @@filename,width=x height=y@text@
533 ^
534 |
535 ----- we're at this point now.
536
537 If images are enabled, we replace that with an IMG tag we build from
538 filename,width=x, height=y.
539 If images are disabled, we replace all of this with text.
540
541 */
542
543 #define MKIMG(c) (*output_func)((c), void_arg)
544
545 if (noimages)
546 {
547 while ((c=getc(f)) >= 0
548 && c != '@')
549 ;
550 while ((c=getc(f)) >= 0
551 && c != '@')
552 MKIMG(c);
553 }
554 else
555 {
556 char *p;
557
558 MKIMG('<');
559 MKIMG('i');
560 MKIMG('m');
561 MKIMG('g');
562 MKIMG(' ');
563 MKIMG('s');
564 MKIMG('r');
565 MKIMG('c');
566 MKIMG('=');
567 MKIMG('"');
568 for (p=get_imageurl(); *p; p++)
569 MKIMG(*p);
570
571 MKIMG('/');
572 while ((c=getc(f)) >= 0
573 && c != '@' && c != ',')
574 MKIMG(c);
575 MKIMG('"');
576 MKIMG(' ');
577 if (c == ',')
578 c=getc(f);
579 while (c >= 0 && c != '@')
580 {
581 MKIMG(c);
582 c=getc(f);
583 }
584 while ((c=getc(f)) >= 0 && c != '@')
585 ;
586 MKIMG(' ');
587 MKIMG('/');
588 MKIMG('>');
589 }
590 }
591
592 /* ---- time zone list ---- */
593
timezonefile(int (* callback_func)(const char *,const char *,void *),void * callback_arg)594 static int timezonefile( int (*callback_func)(const char *, const char *,
595 void *), void *callback_arg)
596 {
597 FILE *f=NULL;
598 char buffer[BUFSIZ];
599
600 if (sqwebmail_content_language)
601 f=open_langform(sqwebmail_content_language, "TIMEZONELIST", 0);
602
603 if (!f) f=open_langform(HTTP11_DEFAULTLANG, "TIMEZONELIST", 0);
604
605 if (!f)
606 return (0);
607
608 while (fgets(buffer, sizeof(buffer), f) != NULL)
609 {
610 char *p=strchr(buffer, '\n');
611 char *tz;
612 int rc;
613
614 if (p) *p=0;
615
616 p=strchr(buffer, '#');
617 if (p) *p=0;
618
619 for (p=buffer; *p; p++)
620 if (!isspace((int)(unsigned char)*p))
621 break;
622
623 if (!*p)
624 continue;
625
626 tz=p;
627 while (*p)
628 {
629 if (isspace((int)(unsigned char)*p))
630 break;
631 ++p;
632 }
633 if (*p) *p++=0;
634 while (*p && isspace((int)(unsigned char)*p))
635 ++p;
636
637 if (strcmp(p, "*") == 0)
638 p="";
639 if (strcmp(tz, "*") == 0)
640 tz="";
641
642 rc= (*callback_func)(tz, p, callback_arg);
643
644 if (rc)
645 {
646 fclose(f);
647 return (rc);
648 }
649 }
650 fclose(f);
651 return (0);
652 }
653
654 static int callback_timezonelist(const char *, const char *, void *);
655
timezonelist()656 static void timezonelist()
657 {
658 printf("<select name=\"timezonelist\" class=\"timezonelist\">");
659 timezonefile(callback_timezonelist, NULL);
660 printf("</select>\n");
661 }
662
callback_timezonelist(const char * tz,const char * n,void * dummy)663 static int callback_timezonelist(const char *tz, const char *n, void *dummy)
664 {
665 printf("<option value=\"%s\">", tz);
666 output_attrencoded(n);
667 printf("</option>\n");
668 return (0);
669 }
670
set_timezone(const char * p)671 static int set_timezone(const char *p)
672 {
673 static char *s_buffer=0;
674 char *buffer;
675
676 if (!p || !*p || strcmp(p, "*") == 0)
677 return (0);
678
679 buffer=malloc(strlen(p)+10);
680 if (!buffer)
681 return (0);
682 strcat(strcpy(buffer, "TZ="), p);
683
684 putenv(buffer);
685
686 if (s_buffer)
687 free(buffer);
688 s_buffer=buffer;
689
690 return (0);
691 }
692
693 static int callback_get_timezone(const char *, const char *, void *);
694
695 /* Return TZ selected from login dropdown */
696
get_timezone()697 static char *get_timezone()
698 {
699 char *langptr=0;
700
701 timezonefile(callback_get_timezone, &langptr);
702
703 if (!langptr)
704 {
705 langptr=strdup("");
706 if (!langptr)
707 enomem();
708 }
709
710 if (*langptr == 0)
711 {
712 free(langptr);
713 langptr=strdup("*");
714 if (!langptr)
715 enomem();
716 }
717
718 return(langptr);
719 }
720
callback_get_timezone(const char * tz,const char * n,void * dummy)721 static int callback_get_timezone(const char *tz, const char *n, void *dummy)
722 {
723 if (strcmp(tz, cgi("timezonelist")) == 0)
724 {
725 char **p=(char **)dummy;
726
727 if (*p)
728 free(*p);
729
730 *p=strdup(tz);
731 }
732 return (0);
733 }
734
735 /* ------------------------ */
736
do_open_form(const char * formname,int flag)737 static FILE *do_open_form(const char *formname, int flag)
738 {
739 struct template_stack *ts;
740 FILE *f=NULL;
741
742 if ((ts=(struct template_stack *)malloc(sizeof(struct template_stack)))
743 == NULL)
744 return (NULL);
745
746 if (sqwebmail_content_language)
747 f=open_langform(sqwebmail_content_language, formname, flag);
748 if (!f) f=open_langform(HTTP11_DEFAULTLANG, formname, flag);
749
750 if (!f)
751 {
752 free(ts);
753 return (NULL);
754 }
755
756 ts->next=template_stack;
757 template_stack=ts;
758 ts->fp=f;
759 return (f);
760 }
761
do_close_form()762 static void do_close_form()
763 {
764 struct template_stack *ts=template_stack;
765
766 if (!ts)
767 enomem();
768
769 fclose(ts->fp);
770 template_stack=ts->next;
771 free(ts);
772 }
773
774 static void do_output_form_loop(FILE *);
775
fix_xml_header(FILE * f)776 static void fix_xml_header(FILE *f)
777 {
778 char linebuf[80];
779
780 /*
781 ** Some templates now have an <?xml > header. Adjust the
782 ** encoding to match the selected default. Yes, it's a dirty hack,
783 ** and I'm proud of it, since it allows me to continue editing the
784 ** HTML templates in Amaya.
785 */
786
787 if (fgets(linebuf, sizeof(linebuf), f) == NULL)
788 return;
789
790 if (strncasecmp(linebuf, "<?xml version=", 14) == 0)
791 sprintf(linebuf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
792 sqwebmail_content_charset);
793
794 printf("%s", linebuf);
795 }
796
output_form(const char * formname)797 void output_form(const char *formname)
798 {
799 FILE *f;
800
801 #ifdef GZIP
802 int dogzip;
803 int pipefd[2];
804 pid_t pid= -1;
805 #endif
806
807 noimages= auth_getoptionenvint("wbnoimages");
808
809 f=do_open_form(formname, 1);
810
811 sqwebmail_formname=formname;
812
813 if (!f) error("Can't open form template.");
814
815 /*
816 ** Except for the dummy frame window (and the tiny empty frame),
817 ** and the window containing the print preview of the message,
818 ** expire everything.
819 */
820
821 if (strcmp(formname, "index.html") && strcmp(formname, "empty.html") &&
822 strcmp(formname, "print.html"))
823 cginocache();
824
825 #ifdef GZIP
826
827 dogzip=0;
828 if (strcmp(formname, "readmsg.html") == 0 ||
829 strcmp(formname, "folder.html") == 0 ||
830 strcmp(formname, "folders.html") == 0 ||
831 strcmp(formname, "gpg.html") == 0)
832 {
833 const char *p=getenv("HTTP_ACCEPT_ENCODING");
834
835 if (p)
836 {
837 char *q=strdup(p), *r;
838
839 if (!q) enomem();
840 for (r=q; *r; r++)
841 *r= tolower((int)(unsigned char)*r);
842 for (r=q; (r=strtok(r, ", ")) != 0; r=0)
843 if (strcmp(r, "gzip") == 0)
844 {
845 dogzip=1;
846 if (pipe(pipefd))
847 enomem();
848 }
849 free(q);
850 }
851 }
852 #endif
853
854 /* Do not send a Vary header for attachment downloads */
855
856 if (*cgi("download") == 0)
857 printf("Vary: Accept-Language\n");
858
859 #ifdef GZIP
860 if (dogzip)
861 printf("Content-Encoding: gzip\n");
862 #endif
863
864 printf("Content-Type: text/html");
865
866 if (sqwebmail_content_charset)
867 printf("; charset=%s", sqwebmail_content_charset);
868
869 printf("\n\n");
870
871 #ifdef GZIP
872 if (dogzip)
873 {
874 fflush(stdout);
875 while ((pid=fork()) == -1)
876 sleep(5);
877 if (pid == 0)
878 {
879 dup2(pipefd[0], 0);
880 close(pipefd[0]);
881 close(pipefd[1]);
882 execl(GZIP, "gzip", "-c", (char *)0);
883 fprintf(stderr,
884 "ERR: Cannot execute " GZIP ": %s\n",
885 strerror(errno));
886 exit(1);
887 }
888
889 gzip_save_fd=dup(1);
890 dup2(pipefd[1], 1);
891 close(pipefd[1]);
892 close(pipefd[0]);
893 }
894 #endif
895 fix_xml_header(f);
896 do_output_form_loop(f);
897 do_close_form();
898
899 #ifdef GZIP
900 if (pid > 0)
901 {
902 int waitstat;
903 pid_t p2;
904
905 /* Restore original stdout */
906
907 fflush(stdout);
908 dup2(gzip_save_fd, 1);
909 close(gzip_save_fd);
910 gzip_save_fd= -1;
911 while ((p2=wait(&waitstat)) >= 0 && p2 != pid)
912 ;
913 }
914 #endif
915 }
916
917 static FILE *openinclude(const char *);
918
919
insert_include(const char * inc_name)920 void insert_include(const char *inc_name)
921 {
922 FILE *ff=openinclude(inc_name);
923 do_output_form_loop(ff);
924 do_close_form();
925 }
926
do_output_form_loop(FILE * f)927 static void do_output_form_loop(FILE *f)
928 {
929 int c, c2, c3;
930
931 while ((c=getc(f)) >= 0)
932 {
933 char kw[64];
934
935 if (c != '[')
936 {
937 putchar(c);
938 continue;
939 }
940 c=getc(f);
941 if (c != '#')
942 {
943 putchar('[');
944 ungetc(c,f);
945 continue;
946 }
947 c=getc(f);
948 if (c == '?')
949 {
950 c=getc(f);
951 if (c < '0' || c > '9')
952 {
953 putchar('[');
954 putchar('#');
955 putchar('?');
956 putchar(c);
957 continue;
958 }
959 if (
960 ( c == '0' && nochangepass()) ||
961 (c == '1' && strncmp(cgi("folderdir"),
962 SHARED ".",
963 sizeof(SHARED)) == 0) ||
964 (c == '2' && strncmp(cgi("folderdir"),
965 SHARED ".",
966 sizeof(SHARED))) ||
967 (c == '4' && maildir_filter_hasmaildirfilter(".")) ||
968 (c == '5' && libmail_gpg_has_gpg(GPGDIR)) ||
969 (c == '6' && !ishttps()) ||
970 (c == '7' && !sqpcp_has_calendar()) ||
971 (c == '8' && !sqpcp_has_groupware())
972 )
973 {
974 while ((c=getc(f)) != EOF)
975 {
976 if (c != '[') continue;
977 if ( getc(f) != '#') continue;
978 if ( getc(f) != '?') continue;
979 if ( getc(f) != '#') continue;
980 if ( getc(f) == ']') break;
981 }
982 }
983 continue;
984 }
985
986 if (c == '$')
987 {
988 struct var_put_buf buf;
989
990 buf.argp=buf.argbuf;
991 buf.argn=sizeof(buf.argbuf)-1;
992
993 while ((c=getc(f)) >= 0 && c != '\n')
994 {
995 if (c == '#')
996 {
997 c=getc(f);
998 if (c == ']') break;
999 ungetc(c, f);
1000 c='#';
1001 }
1002
1003 if (c == '@')
1004 {
1005 c=getc(f);
1006 if (c == '@')
1007 {
1008 output_image(f,
1009 var_put_buf_func,
1010 &buf);
1011 continue;
1012 }
1013 ungetc(c, f);
1014 c='@';
1015 }
1016 var_put_buf_func(c, &buf);
1017 }
1018 *buf.argp=0;
1019 addarg(buf.argbuf);
1020 continue;
1021 }
1022
1023 if (c == '@')
1024 {
1025 output_image(f, pass_image_through, NULL);
1026 c=getc(f);
1027 if (c == '#')
1028 {
1029 c=getc(f);
1030 if (c == ']')
1031 continue;
1032 }
1033 if (c != EOF)
1034 ungetc(c, f);
1035 continue;
1036 }
1037
1038 if (!isalnum(c) && c != ':')
1039 {
1040 putchar('[');
1041 putchar('#');
1042 ungetc(c, f);
1043 continue;
1044 }
1045 c2=0;
1046 while (c != EOF && (isalnum(c) || c == ':' || c == '_'))
1047 {
1048 if (c2 < sizeof(kw)-1)
1049 kw[c2++]=c;
1050 c=getc(f);
1051 }
1052 kw[c2]=0;
1053 c2=c;
1054
1055 if (c2 != '#')
1056 {
1057 putchar('[');
1058 putchar('#');
1059 printf("%s", kw);
1060 ungetc(c2, f);
1061 continue;
1062 }
1063
1064 if ((c3=getc(f)) != ']')
1065 {
1066 putchar('[');
1067 putchar('#');
1068 printf("%s", kw);
1069 putchar(c2);
1070 ungetc(c3, f);
1071 continue;
1072 }
1073
1074 if (strcmp(kw, "a") == 0)
1075 {
1076 addressbook();
1077 }
1078 else if (strcmp(kw, "d") == 0)
1079 {
1080 const char *f=cgi("folderdir");
1081 char *origc, *c;
1082 const char *sep="";
1083
1084 origc=c=folder_fromutf7(f);
1085
1086 if (*c && strcmp(c, INBOX))
1087 {
1088 printf(" - ");
1089
1090 if (strcmp(c, NEWSHAREDSP) == 0 ||
1091 strncmp(c, NEWSHAREDSP ".",
1092 sizeof(NEWSHAREDSP)) == 0)
1093 {
1094 printf("%s", getarg("PUBLICFOLDERS"));
1095 sep=".";
1096 }
1097
1098 c=strchr(c, '.');
1099 if (c)
1100 {
1101 printf(sep);
1102 print_safe(c+1);
1103 }
1104 }
1105 free(origc);
1106 }
1107 else if (strcmp(kw, "D") == 0)
1108 {
1109 const char *p=cgi("folder");
1110 const char *q=strrchr(p, '.');
1111
1112 if (q)
1113 {
1114 char *r=malloc(q-p+1);
1115
1116 if (!r) enomem();
1117 memcpy(r, p, q-p);
1118 r[q-p]=0;
1119 output_urlencoded(r);
1120 free(r);
1121 }
1122 }
1123 else if (strcmp(kw, "G") == 0)
1124 {
1125 output_attrencoded(login_returnaddr());
1126 }
1127 else if (strcmp(kw, "r") == 0)
1128 {
1129 output_attrencoded(cgi("redirect"));
1130 }
1131 else if (strcmp(kw, "s") == 0)
1132 {
1133 output_scriptptrget();
1134 }
1135 else if (strcmp(kw, "S") == 0)
1136 {
1137 output_loginscriptptr();
1138 }
1139 else if (strcmp(kw, "R") == 0)
1140 {
1141 output_loginscriptptr_get();
1142 }
1143 else if (strcmp(kw, "p") == 0)
1144 {
1145 output_scriptptr();
1146 }
1147 else if (strcmp(kw, "P") == 0)
1148 {
1149 output_scriptptrpostinfo();
1150 }
1151 else if (strcmp(kw, "f") == 0)
1152 {
1153 folder_contents_title();
1154 }
1155 else if (strcmp(kw, "F") == 0)
1156 {
1157 folder_contents(sqwebmail_folder, atol(cgi("pos")));
1158 }
1159 else if (strcmp(kw, "n") == 0)
1160 {
1161 folder_initnextprev(sqwebmail_folder, atol(cgi("pos")));
1162 }
1163 else if (strcmp(kw, "N") == 0)
1164 {
1165 folder_nextprev();
1166 }
1167 else if (strcmp(kw, "m") == 0)
1168 {
1169 folder_msgmove();
1170 }
1171 else if (strcmp(kw, "M") == 0)
1172 {
1173 folder_showmsg(sqwebmail_folder, atol(cgi("pos")));
1174 }
1175 else if (strcmp(kw, "T") == 0)
1176 {
1177 folder_showtransfer();
1178 }
1179 else if (strcmp(kw, "L") == 0)
1180 {
1181 folder_list();
1182 }
1183 else if (strcmp(kw, "l") == 0)
1184 {
1185 folder_list2();
1186 }
1187 else if (strcmp(kw, "E") == 0)
1188 {
1189 folder_rename_list();
1190 }
1191 else if (strcmp(kw, "W") == 0)
1192 {
1193 newmsg_init(sqwebmail_folder, cgi("pos"));
1194 }
1195 else if (strcmp(kw, "z") == 0)
1196 {
1197 pref_isdisplayfullmsg();
1198 }
1199 else if (strcmp(kw, "y") == 0)
1200 {
1201 pref_isoldest1st();
1202 }
1203 else if (strcmp(kw, "H") == 0)
1204 {
1205 pref_displayhtml();
1206 }
1207 else if (strcmp(kw, "FLOWEDTEXT") == 0)
1208 {
1209 pref_displayflowedtext();
1210 }
1211 else if (strcmp(kw, "NOARCHIVE") == 0)
1212 {
1213 pref_displaynoarchive();
1214 }
1215 else if (strcmp(kw, "NOAUTORENAMESENT") == 0)
1216 {
1217 pref_displaynoautorenamesent();
1218 }
1219 else if (strcmp(kw, "x") == 0)
1220 {
1221 pref_setprefs();
1222 }
1223 else if (strcmp(kw, "w") == 0)
1224 {
1225 pref_sortorder();
1226 }
1227 else if (strcmp(kw, "t") == 0)
1228 {
1229 pref_signature();
1230 }
1231 else if (strcmp(kw, "u") == 0)
1232 {
1233 pref_pagesize();
1234 }
1235 else if (strcmp(kw, "v") == 0)
1236 {
1237 pref_displayautopurge();
1238 }
1239 else if (strcmp(kw, "A") == 0)
1240 {
1241 attachments_head(sqwebmail_folder, cgi("pos"),
1242 cgi("draft"));
1243 }
1244 else if (strcmp(kw, "ATTACHOPTS") == 0)
1245 {
1246 attachments_opts(cgi("draft"));
1247 }
1248 else if (strcmp(kw, "GPGERR") == 0)
1249 {
1250 sent_gpgerrtxt();
1251 }
1252 else if (strcmp(kw, "GPGERRRESUME") == 0)
1253 {
1254 sent_gpgerrresume();
1255 }
1256 #ifdef ISPELL
1257 else if (strcmp(kw, "K") == 0)
1258 {
1259 spell_show();
1260 }
1261 #endif
1262 #ifdef BANNERPROG
1263 else if (strcmp(kw, "B") == 0)
1264 {
1265 char banargbuf[31];
1266 int i=0;
1267 int wait_stat;
1268 pid_t p, p2;
1269
1270 if ((c=getc(f)) != '{')
1271 ungetc(c, f);
1272 else while ((c=getc(f)), isalnum(c))
1273 if (i < sizeof(banargbuf)-1)
1274 banargbuf[i++]=c;
1275 banargbuf[i]=0;
1276 fflush(stdout);
1277
1278 if ( (p=fork()) == 0 )
1279 {
1280 execl(BANNERPROG, BANNERPROG,
1281 sqwebmail_formname,
1282 banargbuf, (char *)0);
1283 _exit(0);
1284 }
1285 if (p > 0)
1286 {
1287 while ((p2=wait(&wait_stat)) > 0 &&
1288 p2 != p)
1289 ;
1290 }
1291 }
1292 #endif
1293 else if (strcmp(kw, "h") == 0)
1294 {
1295 FILE *fp=fopen(LOGINDOMAINLIST, "r");
1296
1297 if (fp) {
1298 /* parse LOGINDOMAINLIST and print proper output */
1299 print_logindomainlist(fp);
1300 fclose(fp);
1301 }
1302 }
1303 else if (strcmp(kw, "o") == 0)
1304 {
1305 ldaplist();
1306 }
1307 else if (strcmp(kw, "O") == 0)
1308 {
1309 doldapsearch();
1310 }
1311 else if (strcmp(kw, "IMAGEURL") == 0)
1312 {
1313 printf("%s", get_imageurl());
1314 }
1315 else if (strcmp(kw, "LOADMAILFILTER") == 0)
1316 {
1317 mailfilter_init();
1318 }
1319 else if (strcmp(kw, "MAILFILTERLIST") == 0)
1320 {
1321 mailfilter_list();
1322 }
1323 else if (strcmp(kw, "MAILFILTERLISTFOLDERS") == 0)
1324 {
1325 mailfilter_listfolders();
1326 }
1327 else if (strcmp(kw, "QUOTA") == 0)
1328 {
1329 folder_showquota();
1330 }
1331 else if (strcmp(kw, "NICKLIST") == 0)
1332 {
1333 ab_listselect();
1334 }
1335 else if (strcmp(kw, "LISTPUB") == 0)
1336 {
1337 gpglistpub();
1338 }
1339 else if (strcmp(kw, "LISTSEC") == 0)
1340 {
1341 gpglistsec();
1342 }
1343 else if (strcmp(kw, "KEYIMPORT") == 0)
1344 {
1345 folder_keyimport(sqwebmail_folder, atol(cgi("pos")));
1346 }
1347 else if (strcmp(kw, "GPGCREATE") == 0)
1348 {
1349 gpgcreate();
1350 }
1351 else if (strcmp(kw, "DOGPG") == 0)
1352 {
1353 gpgdo();
1354 }
1355 else if (strcmp(kw, "ATTACHPUB") == 0)
1356 {
1357 gpgselectpubkey();
1358 }
1359 else if (strcmp(kw, "ATTACHSEC") == 0)
1360 {
1361 gpgselectprivkey();
1362 }
1363 else if (strcmp(kw, "MAILINGLISTS") == 0)
1364 {
1365 char *p=getmailinglists();
1366
1367 /* <sigh> amaya inserts a bunch of spaces that mess
1368 ** things up in Netscape.
1369 */
1370
1371 output_attrencoded(p ? p:"");
1372 if (p)
1373 free(p);
1374 }
1375 else if (strcmp(kw, "AUTORESPONSE") == 0)
1376 {
1377 autoresponse();
1378 }
1379 else if (strcmp(kw, "AUTORESPONSE_LIST") == 0)
1380 {
1381 autoresponselist();
1382 }
1383 else if (strcmp(kw, "AUTORESPONSE_PICK") == 0)
1384 {
1385 autoresponsepick();
1386 }
1387 else if (strcmp(kw, "AUTORESPONSE_DELETE") == 0)
1388 {
1389 autoresponsedelete();
1390 }
1391 else if (strcmp(kw, "SQWEBMAILCSS") == 0)
1392 {
1393 printf("%s/sqwebmail.css", get_imageurl());
1394 }
1395 else if (strcmp(kw, "timezonelist") == 0)
1396 {
1397 timezonelist();
1398 }
1399 else if (strcmp(kw, "PREFWEEK") == 0)
1400 {
1401 pref_displayweekstart();
1402 }
1403 else if (strcmp(kw, "NEWEVENT") == 0)
1404 {
1405 sqpcp_newevent();
1406 }
1407 else if (strcmp(kw, "RECURRING") == 0)
1408 {
1409 printf("%s", getarg("RECURRING"));
1410 }
1411 else if (strcmp(kw, "EVENTSTART") == 0)
1412 {
1413 sqpcp_eventstart();
1414 }
1415 else if (strcmp(kw, "EVENTEND") == 0)
1416 {
1417 sqpcp_eventend();
1418 }
1419 else if (strcmp(kw, "EVENTFROM") == 0)
1420 {
1421 sqpcp_eventfrom();
1422 }
1423 else if (strcmp(kw, "EVENTTIMES") == 0)
1424 {
1425 sqpcp_eventtimes();
1426 }
1427 else if (strcmp(kw, "EVENTPARTICIPANTS") == 0)
1428 {
1429 sqpcp_eventparticipants();
1430 }
1431 else if (strcmp(kw, "EVENTTEXT") == 0)
1432 {
1433 sqpcp_eventtext();
1434 }
1435 else if (strcmp(kw, "EVENTATTACH") == 0)
1436 {
1437 sqpcp_eventattach();
1438 }
1439 else if (strcmp(kw, "EVENTSUMMARY") == 0)
1440 {
1441 sqpcp_summary();
1442 }
1443 else if (strcmp(kw, "CALENDARTODAY") == 0)
1444 {
1445 sqpcp_todays_date();
1446 }
1447 else if (strcmp(kw, "CALENDARWEEKLYLINK") == 0)
1448 {
1449 sqpcp_weeklylink();
1450 }
1451 else if (strcmp(kw, "CALENDARMONTHLYLINK") == 0)
1452 {
1453 sqpcp_monthlylink();
1454 }
1455 else if (strcmp(kw, "CALENDARTODAYV") == 0)
1456 {
1457 sqpcp_todays_date_verbose();
1458 }
1459 else if (strcmp(kw, "CALENDARDAYVIEW") == 0)
1460 {
1461 sqpcp_daily_view();
1462 }
1463 else if (strcmp(kw, "CALENDARPREVDAY") == 0)
1464 {
1465 sqpcp_prevday();
1466 }
1467 else if (strcmp(kw, "CALENDARNEXTDAY") == 0)
1468 {
1469 sqpcp_nextday();
1470 }
1471 else if (strcmp(kw, "CALENDARWEEK") == 0)
1472 {
1473 sqpcp_show_cal_week();
1474 }
1475 else if (strcmp(kw, "CALENDARNEXTWEEK") == 0)
1476 {
1477 sqpcp_show_cal_nextweek();
1478 }
1479 else if (strcmp(kw, "CALENDARPREVWEEK") == 0)
1480 {
1481 sqpcp_show_cal_prevweek();
1482 }
1483 else if (strcmp(kw, "CALENDARWEEKVIEW") == 0)
1484 {
1485 sqpcp_displayweek();
1486 }
1487 else if (strcmp(kw, "CALENDARMONTH") == 0)
1488 {
1489 sqpcp_show_cal_month();
1490 }
1491 else if (strcmp(kw, "CALENDARNEXTMONTH") == 0)
1492 {
1493 sqpcp_show_cal_nextmonth();
1494 }
1495 else if (strcmp(kw, "CALENDARPREVMONTH") == 0)
1496 {
1497 sqpcp_show_cal_prevmonth();
1498 }
1499 else if (strcmp(kw, "CALENDARMONTHVIEW") == 0)
1500 {
1501 sqpcp_displaymonth();
1502 }
1503 else if (strcmp(kw, "EVENTDISPLAYINIT") == 0)
1504 {
1505 sqpcp_displayeventinit();
1506 }
1507 else if (strcmp(kw, "EVENTDELETEINIT") == 0)
1508 {
1509 sqpcp_deleteeventinit();
1510 }
1511 else if (strcmp(kw, "EVENTDISPLAY") == 0)
1512 {
1513 sqpcp_displayevent();
1514 }
1515 else if (strcmp(kw, "EVENTBACKLINK") == 0)
1516 {
1517 sqpcp_eventbacklink();
1518 }
1519 else if (strcmp(kw, "EVENTEDITLINK") == 0)
1520 {
1521 sqpcp_eventeditlink();
1522 }
1523 else if (strcmp(kw, "EVENTCANCELUNCANCELLINK") == 0)
1524 {
1525 sqpcp_eventcanceluncancellink();
1526 }
1527 else if (strcmp(kw, "EVENTCANCELUNCANCELLINK") == 0)
1528 {
1529 sqpcp_eventcanceluncancellink();
1530 }
1531 else if (strcmp(kw, "EVENTCANCELUNCANCELIMAGE") == 0)
1532 {
1533 sqpcp_eventcanceluncancelimage();
1534 }
1535 else if (strcmp(kw, "EVENTCANCELUNCANCELTEXT") == 0)
1536 {
1537 sqpcp_eventcanceluncanceltext();
1538 }
1539 else if (strcmp(kw, "EVENTDELETELINK") == 0)
1540 {
1541 sqpcp_eventdeletelink();
1542 }
1543 else if (strcmp(kw, "EVENTACL") == 0)
1544 {
1545 sqpcp_eventacl();
1546 }
1547 else if (strcmp(kw, "ABOOKNAMELIST") == 0)
1548 {
1549 ab_addrselect();
1550 }
1551 else if (strcmp(kw, "LISTRIGHTS") == 0)
1552 listrights();
1553 else if (strcmp(kw, "GETACL") == 0)
1554 getacl();
1555 else if (strncmp(kw, "radio:", 6) == 0)
1556 {
1557 const char *name=strtok(kw+6, ":");
1558 const char *value=strtok(0, ":");
1559
1560 if (name && value)
1561 {
1562 printf("<input type=\"radio\" name=\"%s\""
1563 " value=\"%s\"",
1564 name, value);
1565 if ( strcmp(cgi(name), value) == 0)
1566 printf(" checked=\"checked\"");
1567 printf(" />");
1568 }
1569 }
1570 else if (strncmp(kw, "checkbox:", 9) == 0)
1571 {
1572 const char *name=strtok(kw+9, ":");
1573 const char *cgivar=strtok(0, ":");
1574
1575 if (name && cgivar)
1576 {
1577 printf("<input type=\"checkbox\" name=\"%s\""
1578 "%s />",
1579 name,
1580 *cgi(cgivar) ? " checked=\"checked\"":"");
1581 }
1582 }
1583 else if (strncmp(kw, "input:", 6) == 0)
1584 {
1585 output_attrencoded(cgi(kw+6));
1586 }
1587 else if (strncmp(kw, "select:", 7) == 0)
1588 {
1589 const char *name=strtok(kw+7, ":");
1590 const char *class=strtok(0, ":");
1591 const char *size=strtok(0, ":");
1592
1593 printf("<select name=\"%s\"", name ? name:"");
1594 if (class) printf(" class=\"%s\"", class);
1595 if (size) printf(" size=\"%s\"", size);
1596 printf(">");
1597 }
1598 else if (strncmp(kw, "option:", 7) == 0)
1599 {
1600 const char *name=strtok(kw+7, ":");
1601 const char *cgivar=strtok(0, ":");
1602 const char *cgival=strtok(0, ":");
1603
1604 printf("<option value=\"%s\"", name ? name:"");
1605 if (cgivar && cgival &&
1606 strcmp(cgi(cgivar), cgival) == 0)
1607 printf(" selected='selected'");
1608 printf(">");
1609 }
1610 else if (strcmp(kw, "endoption") == 0)
1611 printf("</option>");
1612 else if (strcmp(kw, "endselect") == 0)
1613 printf("</select>");
1614 else if (strncmp(kw, "env:", 4) == 0) {
1615 const char *val = getenv(kw+4);
1616 if (val) output_attrencoded(val);
1617 }
1618 else if (strncmp(kw, "include:", 8) == 0)
1619 {
1620 insert_include(kw+8);
1621 }
1622 else if (strcmp(kw, "endinclude") == 0)
1623 {
1624 break;
1625 }
1626 }
1627 }
1628
1629 /* Include another template file */
1630
openinclude(const char * p)1631 static FILE *openinclude(const char *p)
1632 {
1633 char buffer[BUFSIZ];
1634 FILE *f;
1635
1636 buffer[0]=0;
1637 strncat(buffer, p, 100);
1638 strcat(buffer, ".inc.html");
1639
1640 f=do_open_form(buffer, 0);
1641
1642 if (!f)
1643 error("Can't open form template.");
1644
1645 while (fgets(buffer, sizeof(buffer), f))
1646 {
1647 const char *p=strchr(buffer, '[');
1648
1649 if (!p)
1650 continue;
1651
1652 if (strncmp(p, "[#begininclude#]", 16) == 0)
1653 {
1654 break;
1655 }
1656 }
1657 return (f);
1658 }
1659
1660
1661 /* Top level HTTP redirect without referencing a particular mailbox */
1662
http_redirect_top(const char * app)1663 static void http_redirect_top(const char *app)
1664 {
1665 const char *p=nonloginscriptptr();
1666 char *buf=malloc(strlen(p)+strlen(app)+2);
1667
1668 if (!buf) enomem();
1669 strcat(strcpy(buf, p), app);
1670 cgiredirect(buf);
1671 free(buf);
1672 }
1673
1674 /* HTTP redirects within a given mailbox, various formats */
1675
http_redirect_argu(const char * fmt,unsigned long un)1676 void http_redirect_argu(const char *fmt, unsigned long un)
1677 {
1678 char buf[MAXLONGSIZE];
1679
1680 sprintf(buf, "%lu", un);
1681 http_redirect_argss(fmt, buf, "");
1682 }
1683
http_redirect_argss(const char * fmt,const char * arg1,const char * arg2)1684 void http_redirect_argss(const char *fmt, const char *arg1, const char *arg2)
1685 {
1686 http_redirect_argsss(fmt, arg1, arg2, "");
1687 }
1688
http_redirect_argsss(const char * fmt,const char * arg1,const char * arg2,const char * arg3)1689 void http_redirect_argsss(const char *fmt, const char *arg1, const char *arg2,
1690 const char *arg3)
1691 {
1692 char *base=scriptptrget();
1693 char *arg1s=cgiurlencode(arg1);
1694 char *arg2s=cgiurlencode(arg2);
1695 char *arg3s=cgiurlencode(arg3);
1696 char *q;
1697
1698 /* We generate a Location: redirected_url header. The actual
1699 ** header is generated in cgiredirect, we just build it here */
1700
1701 q=malloc(strlen(base)+strlen(fmt)+strlen(arg1s)+strlen(arg2s)+
1702 strlen(arg3s)+1);
1703 if (!q) enomem();
1704 strcpy(q, base);
1705 sprintf(q+strlen(q), fmt, arg1s, arg2s, arg3s);
1706 cgiredirect(q);
1707 free(q);
1708 free(arg1s);
1709 free(arg2s);
1710 free(arg3s);
1711 free(base);
1712 }
1713
output_user_form(const char * formname)1714 void output_user_form(const char *formname)
1715 {
1716 char *p;
1717
1718 if (!*formname || strchr(formname, '.') || strchr(formname, '/'))
1719 error("Invalid request.");
1720
1721 if ((strcmp(formname, "filter") == 0
1722 || strcmp(formname, "autoresponse") == 0)
1723 && maildir_filter_hasmaildirfilter("."))
1724 /* Script kiddies... */
1725 formname="nofilter";
1726
1727 if (strcmp(formname, "filter") == 0 && *cgi("do.submitfilter"))
1728 mailfilter_submit();
1729
1730 if (strcmp(formname, "gpg") == 0 && libmail_gpg_has_gpg(GPGDIR))
1731 error("Invalid request.");
1732
1733 if (strcmp(formname, "gpgcreate") == 0 && libmail_gpg_has_gpg(GPGDIR))
1734 error("Invalid request.");
1735
1736 if (*cgi("ldapsearch")) /* Special voodoo for LDAP address book stuff */
1737 {
1738 if (ldapsearch() == 0)
1739 {
1740 output_form("ldapsearch.html");
1741 return;
1742 }
1743 }
1744
1745 /*
1746 ** In order to hide the session ID in the URL of the message what
1747 ** we do is that the initial URL, that contains setcookie=1, results
1748 ** in us setting a temporary cookie that contains the session ID,
1749 ** then we return a redirect to a url which has /printmsg/ in the
1750 ** PATH_INFO, instead of the session ID. The code in main()
1751 ** traps /printmsg/ PATH_INFO, fetches the path info from the
1752 ** cookie, and punts after resetting setcookie to 0.
1753 */
1754
1755 if (strcmp(formname, "print") == 0 && *cgi("setcookie") == '1')
1756 {
1757 const char *qs=getenv("QUERY_STRING");
1758 const char *pi=getenv("PATH_INFO");
1759 const char *nl;
1760 char *buf;
1761
1762 if (!pi) pi="";
1763 if (!pi) pi="";
1764
1765 nl=nonloginscriptptr();
1766
1767 buf=malloc(strlen(nl) + sizeof("/printmsg/print?")+strlen(qs));
1768 if (!buf) enomem();
1769 strcat(strcat(strcpy(buf, nl), "/printmsg/print?"), qs);
1770 cginocache();
1771 cgi_setcookie("sqwebmail-pi", pi);
1772 printf("Refresh: 0; URL=%s\n", buf);
1773 free(buf);
1774 output_form("printredirect.html");
1775 return;
1776 }
1777
1778 if (strcmp(cgi("fromscreen"), "mailfilter") == 0)
1779 maildir_filter_endmaildirfilter("."); /* Remove the temp file */
1780
1781 if (strcmp(formname, "logout") == 0)
1782 {
1783 unlink(IPFILE);
1784 http_redirect_top("");
1785 return;
1786 }
1787
1788 if (strcmp(formname, "fetch") == 0)
1789 {
1790 folder_download( sqwebmail_folder, atol(cgi("pos")),
1791 cgi("mimeid") );
1792 return;
1793 }
1794
1795 if (strcmp(formname, "delmsg") == 0)
1796 {
1797 folder_delmsg( atol(cgi("pos")));
1798 return;
1799 }
1800
1801 if (strcmp(formname, "donewmsg") == 0)
1802 {
1803 newmsg_do(sqwebmail_folder);
1804 return;
1805 }
1806
1807 if (strcmp(formname, "doattach") == 0)
1808 {
1809 doattach(sqwebmail_folder, cgi("draft"));
1810 return;
1811 }
1812
1813 if (strcmp(formname, "folderdel") == 0)
1814 {
1815 folder_delmsgs(sqwebmail_folder, atol(cgi("pos")));
1816 return;
1817 }
1818 if (strcmp(formname, "spellchk") == 0)
1819 {
1820 #ifdef ISPELL
1821 spell_check_continue();
1822 #else
1823 printf("Status: 404");
1824 #endif
1825 return;
1826 }
1827
1828 if (sqpcp_loggedin())
1829 {
1830 if (*cgi("do.neweventpreview"))
1831 {
1832 sqpcp_preview();
1833 return;
1834 }
1835
1836 if (*cgi("do.neweventsave"))
1837 {
1838 sqpcp_save();
1839 return;
1840 }
1841
1842 if (*cgi("do.neweventpostpone"))
1843 {
1844 sqpcp_postpone();
1845 return;
1846 }
1847
1848 if (*cgi("do.neweventdeleteattach"))
1849 {
1850 sqpcp_deleteattach();
1851 return;
1852 }
1853
1854 if (*cgi("do.neweventupload"))
1855 {
1856 sqpcp_uploadattach();
1857 return;
1858 }
1859
1860 if (*cgi("do.neweventuppubkey"))
1861 {
1862 sqpcp_attachpubkey();
1863 return;
1864 }
1865
1866 if (*cgi("do.neweventupprivkey"))
1867 {
1868 sqpcp_attachprivkey();
1869 return;
1870 }
1871 if (*cgi("do.eventdelete"))
1872 {
1873 sqpcp_dodelete();
1874 return;
1875 }
1876 }
1877
1878 if (strcmp(formname, "event-edit") == 0)
1879 {
1880 formname="folders";
1881 if (sqpcp_loggedin())
1882 {
1883 formname="eventshow"; /* default */
1884 if (sqpcp_eventedit() == 0)
1885 formname="newevent";
1886 }
1887 }
1888
1889
1890 if (strcmp(formname, "open-draft") == 0)
1891 {
1892 formname="newmsg";
1893 if (sqpcp_has_calendar())
1894 /* DRAFTS may contain event files */
1895 {
1896 const char *n=cgi("draft");
1897 char *filename;
1898 FILE *fp;
1899
1900 CHECKFILENAME(n);
1901
1902 filename=maildir_find(INBOX "." DRAFTS, n);
1903
1904 if (filename)
1905 {
1906 if ((fp=fopen(filename, "r")) != NULL)
1907 {
1908 struct rfc822hdr h;
1909
1910 rfc822hdr_init(&h, 8192);
1911
1912 while (rfc822hdr_read(&h, fp, NULL, 0)
1913 == 0)
1914 {
1915 if (strcasecmp(h.header,
1916 "X-Event") == 0)
1917 {
1918 formname="newevent";
1919 cgi_put("draftmessage",
1920 cgi("draft"));
1921 break;
1922 }
1923 }
1924 rfc822hdr_free(&h);
1925 fclose(fp);
1926 }
1927 free(filename);
1928 }
1929 }
1930 }
1931
1932 if (strcmp(formname, "newevent") == 0 ||
1933 strcmp(formname, "eventdaily") == 0 ||
1934 strcmp(formname, "eventweekly") == 0 ||
1935 strcmp(formname, "eventmonthly") == 0 ||
1936 strcmp(formname, "eventshow") == 0 ||
1937 strcmp(formname, "eventacl") == 0)
1938 {
1939 if (!sqpcp_has_calendar() ||
1940 !sqpcp_loggedin())
1941 formname="folders"; /* Naughty boy */
1942 }
1943
1944 p=malloc(strlen(formname)+6);
1945 if (!p) enomem();
1946
1947 strcat(strcpy(p, formname),".html");
1948 output_form(p);
1949 free(p);
1950 }
1951
1952
1953 extern void folder_cleanup();
1954 extern void maildir_cleanup();
1955 extern void mailfilter_cleanup();
1956
1957 #ifdef ISPELL
1958 extern void ispell_cleanup();
1959 #endif
1960
cleanup()1961 void cleanup()
1962 {
1963 sqwebmail_formname = NULL;
1964 sqwebmail_mailboxid=0;
1965 sqwebmail_folder=0;
1966 sqwebmail_sessiontoken=0;
1967 sqwebmail_content_language=0;
1968 sqwebmail_content_locale=0;
1969 sqwebmail_system_charset=0;
1970 if (sys_locale_charset)
1971 free(sys_locale_charset);
1972 sys_locale_charset=0;
1973 sqwebmail_content_ispelldict=0;
1974 folder_cleanup();
1975 maildir_cleanup();
1976 mailfilter_cleanup();
1977 #ifdef ISPELL
1978 ispell_cleanup();
1979 #endif
1980
1981 #ifdef GZIP
1982 if (gzip_save_fd >= 0) /* Restore original stdout */
1983 {
1984 dup2(gzip_save_fd, 1);
1985 close(gzip_save_fd);
1986 gzip_save_fd= -1;
1987 }
1988 #endif
1989
1990 libmail_gpg_cleanup();
1991 freeargs();
1992 sqpcp_close();
1993 }
1994
1995
1996
catch_sig(int n)1997 static RETSIGTYPE catch_sig(int n)
1998 {
1999 n=n;
2000 cleanup();
2001 maildir_cache_cancel();
2002 exit(0);
2003 }
2004
setlang()2005 static void setlang()
2006 {
2007 static char *lang_buf=0;
2008 char *p;
2009
2010 if (sqwebmail_content_locale && *sqwebmail_content_locale
2011 && (p=malloc(sizeof("LANG=")+strlen(sqwebmail_content_locale)))!=0)
2012 {
2013 strcat(strcpy(p, "LANG="), sqwebmail_content_locale);
2014 putenv(p);
2015 if (lang_buf)
2016 free(lang_buf);
2017 lang_buf=p;
2018 }
2019 }
2020
init_default_locale()2021 static void init_default_locale()
2022 {
2023 char *templatedir=get_templatedir();
2024 char *cl=http11_best_content_language(templatedir,
2025 getenv("HTTP_ACCEPT_LANGUAGE"));
2026
2027 sqwebmail_content_language=
2028 http11_content_language(templatedir, cl);
2029 sqwebmail_content_locale=
2030 http11_content_locale(templatedir, cl);
2031 sqwebmail_content_ispelldict=
2032 http11_content_ispelldict(templatedir, cl);
2033 sqwebmail_content_charset=
2034 http11_content_charset(templatedir, cl);
2035
2036 free(cl);
2037 #if HAVE_LOCALE_H
2038 #if HAVE_SETLOCALE
2039 setlocale(LC_ALL, sqwebmail_content_locale);
2040 #if USE_LIBCHARSET
2041 setlocale(LC_CTYPE, sqwebmail_content_locale);
2042 sqwebmail_system_charset = locale_charset();
2043 #elif HAVE_LANGINFO_CODESET
2044 setlocale(LC_CTYPE, sqwebmail_content_locale);
2045 sqwebmail_system_charset = sys_locale_charset=strdup(nl_langinfo(CODESET));
2046 #else
2047 sqwebmail_system_charset = NULL;
2048 #endif /* USE_LIBCHARSET */
2049 setlocale(LC_CTYPE, "C");
2050 setlang();
2051 #endif
2052 #endif
2053 }
2054
rename_sent_folder(int really)2055 void rename_sent_folder(int really)
2056 {
2057 char buf[128];
2058 char yyyymm[128];
2059 const char *yyyymmp;
2060
2061 time_t t;
2062 struct tm *tm;
2063 char *pp;
2064
2065 if (really)
2066 (void)maildir_create(INBOX "." SENT); /* No matter what */
2067
2068 time(&t);
2069 tm=localtime(&t);
2070 if (!tm)
2071 return;
2072
2073 if (tm->tm_mon == 0)
2074 {
2075 tm->tm_mon=11;
2076 --tm->tm_year;
2077 }
2078 else
2079 --tm->tm_mon;
2080
2081 if (strftime (yyyymm, sizeof(yyyymm), "%Y%m", tm) == 0)
2082 return;
2083
2084 if ((yyyymmp=read_sqconfig(".", SENTSTAMP, NULL)) != NULL &&
2085 strcmp(yyyymm, yyyymmp) == 0)
2086 return;
2087
2088 if (strftime (buf, sizeof(buf), "." SENT ".%Y.%m-%b", tm) == 0)
2089 return;
2090
2091 pp=folder_toutf7(buf);
2092
2093 if (really)
2094 rename("." SENT, pp);
2095 free(pp);
2096 if (really)
2097 (void)maildir_create(INBOX "." SENT);
2098
2099 write_sqconfig(".", SENTSTAMP, yyyymm);
2100 }
2101
2102 static int valid_redirect();
2103
redirect(const char * url)2104 static void redirect(const char *url)
2105 {
2106 if (valid_redirect())
2107 {
2108 printf("Refresh: 0; URL=%s\n", url);
2109 output_form("redirect.html");
2110 return;
2111 }
2112
2113 printf("Content-Type: text/plain\n\n"
2114 "The URL you clicked on is no longer valid.\n");
2115 return;
2116 }
2117
valid_redirect()2118 static int valid_redirect()
2119 {
2120 const char *timestamp=cgi("timestamp"), *p;
2121 unsigned long timestamp_n;
2122 time_t timestamp_t;
2123 time_t now;
2124
2125 if (sscanf(timestamp, "%lu", ×tamp_n) != 1)
2126 return 0;
2127
2128 timestamp_t=(time_t)timestamp_n;
2129 time(&now);
2130
2131 if (now < timestamp_t || now > timestamp_t + get_timeouthard())
2132 return 0;
2133
2134 p=redirect_hash(timestamp);
2135
2136 if (*p == 0 || strcmp(cgi("md5"), p))
2137 return 0;
2138 return 1;
2139 }
2140
2141 static void main2();
2142
usage()2143 static void usage()
2144 {
2145 fprintf(stderr, "sqwebmaild does not accept command arguments.\n"
2146 "Use sqwebmaild.rc script to start sqwebmaild as a daemon.\n");
2147 exit(1);
2148 }
2149
call_main2(void * dummy)2150 static void call_main2(void *dummy)
2151 {
2152 main2();
2153 cleanup();
2154 }
2155
main(int argc,char ** argv)2156 int main(int argc, char **argv)
2157 {
2158 const char *prefork;
2159 int n;
2160
2161 courier_authdebug_login_init();
2162
2163 if (argc > 1)
2164 usage();
2165
2166 prefork=getenv("SQWEBMAIL_PREFORK");
2167
2168 n=prefork ? atoi(prefork):5;
2169
2170 cgi_daemon(n, SOCKFILENAME, NULL, call_main2, NULL);
2171
2172 return (0);
2173 }
2174
setuidgid(uid_t u,gid_t g,const char * dir,void * dummy)2175 static int setuidgid(uid_t u, gid_t g, const char *dir, void *dummy)
2176 {
2177 if (setgid(g) || setuid(u))
2178 {
2179 fprintf(stderr,
2180 "CRIT: Cache - can't setuid/setgid to %u/%u\n",
2181 (unsigned)u, (unsigned)g);
2182 return (-1);
2183 }
2184
2185 if (chdir(dir))
2186 {
2187 fprintf(stderr,
2188 "CRIT: Cache - can't chdir to %s: %s\n", dir, strerror(errno));
2189 return (-1);
2190 }
2191 return (0);
2192 }
2193
main2()2194 static void main2()
2195 {
2196 const char *u;
2197 const char *ip_addr;
2198 char *pi;
2199 char *pi_malloced;
2200 int reset_cookie=0;
2201 time_t timeouthard=get_timeouthard();
2202
2203
2204 #ifdef GZIP
2205 gzip_save_fd= -1;
2206 #endif
2207 u=ip_addr=pi=NULL;
2208
2209 ip_addr=getenv("REMOTE_ADDR");
2210
2211 #if 0
2212 {
2213 FILE *f;
2214
2215 f=fopen("/tmp/pid", "w");
2216 fprintf(f, "%d\n", (int)getpid());
2217 fclose(f);
2218 sleep(10);
2219 }
2220 #endif
2221
2222 /*
2223 * Note: if we get a signal during FastCGI processing, this means
2224 * means we need to terminate so that the webserver can respawn us.
2225 * Exception is SIGPIPE which we just ignore (this is what we get
2226 * if we try to write data to a client which goes away before
2227 * we finished sending them the reply)
2228 */
2229
2230 signal(SIGHUP, catch_sig);
2231 signal(SIGINT, catch_sig);
2232 signal(SIGPIPE, catch_sig);
2233 signal(SIGTERM, catch_sig);
2234
2235 if (!ip_addr) ip_addr="127.0.0.1";
2236
2237 umask(0077);
2238
2239 {
2240 timeouthard=get_timeouthard();
2241 }
2242
2243 if (maildir_cache_init(timeouthard, CACHEDIR, CACHEOWNER, authvars))
2244 {
2245 printf("Content-Type: text/plain\n\nmaildir_cache_init() failed\n");
2246 fake_exit(0);
2247 }
2248
2249 pi=getenv("PATH_INFO");
2250
2251 pi_malloced=0;
2252 sqpcp_init();
2253
2254 if (pi && strncmp(pi, "/printmsg/", 10) == 0)
2255 {
2256 /* See comment in output_user_form */
2257
2258 pi_malloced=pi=cgi_cookie("sqwebmail-pi");
2259 if (*pi_malloced == 0)
2260 {
2261 free(pi_malloced);
2262 setgid(getgid());
2263 setuid(getuid());
2264 output_form("printnocookie.html");
2265 return;
2266 }
2267 reset_cookie=1;
2268 cgi_setcookie("sqwebmail-pi", "DELETED");
2269 }
2270
2271 if (pi && strncmp(pi, "/login/", 7) == 0)
2272 {
2273 const char *p;
2274 time_t last_time, current_time;
2275 char *q;
2276 time_t timeoutsoft=get_timeoutsoft();
2277
2278 /* Logging into the mailbox */
2279
2280 pi=strdup(pi);
2281 if (pi_malloced) free(pi_malloced);
2282
2283 if (!pi) enomem();
2284
2285 (void)strtok(pi, "/"); /* Skip login */
2286 u=strtok(NULL, "/"); /* mailboxid */
2287 sqwebmail_sessiontoken=strtok(NULL, "/"); /* sessiontoken */
2288 q=strtok(NULL, "/"); /* login time */
2289 login_time=0;
2290 while (q && *q >= '0' && *q <= '9')
2291 login_time=login_time * 10 + (*q++ - '0');
2292
2293 if (maildir_cache_search(u, login_time, setuidgid, NULL)
2294 && prelogin(u))
2295 {
2296 free(pi);
2297 error("Unable to access your mailbox, sqwebmail permissions may be wrong.");
2298 }
2299
2300 time(¤t_time);
2301
2302 /* Ok, boys and girls, time to validate the connection as
2303 ** follows */
2304
2305 if ( !sqwebmail_sessiontoken
2306
2307 /* 1. Read IPFILE. Check that it's timestamp is current enough,
2308 ** and the session hasn't timed out.
2309 */
2310
2311 || !(p=read_sqconfig(".", IPFILE, &last_time))
2312
2313 /* || last_time > current_time */
2314
2315 || last_time + timeouthard < current_time
2316
2317 /* 2. IPFILE will contain seven words - IP address, session
2318 ** token, language, locale, ispell dictionary,
2319 ** timezone, charset. Validate both.
2320 */
2321 || !(q=strdup(p))
2322 || !(p=strtok(q, " "))
2323 || (strcmp(p, ip_addr) && strcmp(p, "none"))
2324 || !(p=strtok(NULL, " "))
2325 || strcmp(p, sqwebmail_sessiontoken)
2326 || !(p=strtok(NULL, " "))
2327 || !(sqwebmail_content_language=strdup(p))
2328 || !(p=strtok(NULL, " "))
2329 || !(sqwebmail_content_locale=strdup(p))
2330 || !(p=strtok(NULL, " "))
2331 || !(sqwebmail_content_ispelldict=strdup(p))
2332 || !(p=strtok(NULL, " "))
2333 || set_timezone(p)
2334 || !(p=strtok(NULL, " "))
2335 || !(sqwebmail_content_charset=strdup(p))
2336
2337 /* 3. Check the timestamp on the TIMESTAMP file. See if the
2338 ** session has reached its soft timeout.
2339 */
2340
2341 || !read_sqconfig(".", TIMESTAMP, &last_time)
2342
2343 /* || last_time > current_time */
2344
2345 || last_time + timeoutsoft < current_time)
2346 {
2347 setgid(getgid());
2348 setuid(getuid()); /* Drop root prevs */
2349 if (chdir("/") < 0)
2350 {
2351 output_form("expired.html");
2352 return;
2353 }
2354 cgi_setup();
2355 init_default_locale();
2356 free(pi);
2357
2358 u=getenv("SQWEBMAIL_SHAREDMUNGENAMES");
2359
2360 maildir_info_munge_complex(u && *u);
2361
2362 if (strcmp(cgi("form"), "logout") == 0)
2363 /* Already logged out, and the link
2364 ** had target=_parent tag.
2365 */
2366 {
2367 http_redirect_top("");
2368 return;
2369 }
2370 output_form("expired.html");
2371 return;
2372 }
2373 free(q);
2374 cgiformdatatempdir("tmp");
2375 cgi_setup(); /* Read CGI environment */
2376 if (reset_cookie)
2377 cgi_put("setcookie", "0");
2378
2379 /* Update soft timeout stamp */
2380
2381 write_sqconfig(".", TIMESTAMP, "");
2382
2383 /* We must always have the folder CGI arg */
2384
2385 if (!*(sqwebmail_folder=cgi("folder")))
2386 {
2387 init_default_locale();
2388 output_form("expired.html");
2389 free(pi);
2390 return;
2391 }
2392
2393 sqwebmail_mailboxid=u;
2394
2395 {
2396 struct stat stat_buf;
2397
2398 if (stat(".", &stat_buf) < 0)
2399 {
2400 output_form("expired.html");
2401 free(pi);
2402 return;
2403 }
2404
2405 sqwebmail_homedir_dev=stat_buf.st_dev;
2406 sqwebmail_homedir_ino=stat_buf.st_ino;
2407 }
2408
2409 #if HAVE_LOCALE_H
2410 #if HAVE_SETLOCALE
2411 setlocale(LC_ALL, sqwebmail_content_locale);
2412 #if USE_LIBCHARSET
2413 setlocale(LC_CTYPE, sqwebmail_content_locale);
2414 sqwebmail_system_charset = locale_charset();
2415 #elif HAVE_LANGINFO_CODESET
2416 setlocale(LC_CTYPE, sqwebmail_content_locale);
2417 sqwebmail_system_charset = sys_locale_charset
2418 = strdup(nl_langinfo(CODESET));
2419 #else
2420 sqwebmail_system_charset = NULL;
2421 #endif /* USE_LIBCHARSET */
2422 setlocale(LC_CTYPE, "C");
2423 setlang();
2424 #endif
2425 #endif
2426 CHECKFILENAME(sqwebmail_folder);
2427
2428 strcpy(sqwebmail_folder_rights, ALL_RIGHTS);
2429 acl_computeRightsOnFolder(sqwebmail_folder,
2430 sqwebmail_folder_rights);
2431
2432 pref_init();
2433 (void)sqpcp_loggedin();
2434 if (auth_getoptionenvint("disableshared"))
2435 {
2436 maildir_acl_disabled=1;
2437 maildir_newshared_disabled=1;
2438 }
2439
2440 if (strcmp(cgi("form"), "empty"))
2441 {
2442 if (*cgi("refresh"))
2443 {
2444 printf("Refresh: %ld; URL=",
2445 (long)get_timeoutsoft()/2);
2446 output_scriptptrget();
2447 printf("&empty=1&refresh=1\n");
2448 }
2449 }
2450
2451 output_user_form(cgi("form"));
2452 free(pi);
2453 }
2454 else
2455 /* Must be one of those special forms */
2456 {
2457 char *rm;
2458 long n;
2459
2460 if (pi_malloced) free(pi_malloced);
2461
2462 if ((rm=getenv("REQUEST_METHOD")) == 0 ||
2463 (strcmp(rm, "POST") == 0 &&
2464 ((rm=getenv("CONTENT_TYPE")) != 0 &&
2465 strncasecmp(rm,"multipart/form-data;", 20)
2466 == 0)))
2467 emsg("multipart/formdata posts not allowed","");
2468
2469 /* Some additional safety checks */
2470
2471 rm=getenv("CONTENT_LENGTH");
2472 n= rm ? atol(rm):0;
2473 if (n < 0 || n > 256) enomem();
2474
2475 cgi_setup();
2476 init_default_locale();
2477
2478 if (*(u=trim_spaces(cgi("username"))))
2479 /* Request to log in */
2480 {
2481 const char *p=cgi("password");
2482 const char *mailboxid;
2483 const char *u2=cgi("logindomain");
2484 char *ubuf=malloc(strlen(u)+strlen(u2)+2);
2485
2486 if (ubuf == NULL) enomem();
2487 strcpy(ubuf, u);
2488 if (*u2)
2489 strcat(strcat(ubuf, "@"), u2);
2490
2491 maildir_cache_start();
2492
2493 if (*p && (mailboxid=do_login(ubuf, p, ip_addr))
2494 != 0)
2495 {
2496 char *q;
2497 const char *saveip=ip_addr;
2498 char *tz;
2499
2500 sqwebmail_mailboxid=mailboxid;
2501 sqwebmail_folder="INBOX";
2502 sqwebmail_sessiontoken=random128();
2503
2504 tz=get_timezone();
2505 if (*cgi("sameip") == 0)
2506 saveip="none";
2507
2508 q=malloc(strlen(saveip)
2509 +strlen(sqwebmail_sessiontoken)
2510 +strlen(sqwebmail_content_language)
2511 +strlen(sqwebmail_content_ispelldict)
2512 +strlen(sqwebmail_content_charset)
2513 +strlen(tz)
2514 +strlen(sqwebmail_content_locale)+7);
2515 if (!q) enomem();
2516 sprintf(q, "%s %s %s %s %s %s %s", saveip,
2517 sqwebmail_sessiontoken,
2518 sqwebmail_content_language,
2519 sqwebmail_content_locale,
2520 sqwebmail_content_ispelldict,
2521 tz,
2522 sqwebmail_content_charset);
2523 write_sqconfig(".", IPFILE, q);
2524 free(q);
2525 free(tz);
2526 time(&login_time);
2527 {
2528 char buf[1024];
2529
2530 buf[sizeof(buf)-1]=0;
2531 if (getcwd(buf, sizeof(buf)-1) == 0)
2532 {
2533 fprintf(stderr,
2534 "CRIT: getcwd() failed: %s\n",strerror(errno));
2535 fake_exit(1);
2536 } /* oops */
2537
2538 maildir_cache_save(mailboxid,
2539 login_time,
2540 buf,
2541 geteuid(), getegid()
2542 );
2543
2544 }
2545 write_sqconfig(".", TIMESTAMP, "");
2546 #if HAVE_LOCALE_H
2547 #if HAVE_SETLOCALE
2548 setlocale(LC_ALL, sqwebmail_content_locale);
2549 #if USE_LIBCHARSET
2550 setlocale(LC_CTYPE, sqwebmail_content_locale);
2551 sqwebmail_system_charset = locale_charset();
2552 #elif HAVE_LANGINFO_CODESET
2553 setlocale(LC_CTYPE, sqwebmail_content_locale);
2554
2555 sqwebmail_system_charset = sys_locale_charset
2556 = strdup(nl_langinfo(CODESET));
2557 #else
2558 sqwebmail_system_charset = NULL;
2559 #endif /* USE_LIBCHARSET */
2560 setlocale(LC_CTYPE, "C");
2561 setlang();
2562 #endif
2563 #endif
2564 pref_init();
2565 (void)maildir_create(INBOX "." DRAFTS);
2566
2567 if (!pref_noautorenamesent)
2568 (void)rename_sent_folder(1);
2569 (void)maildir_create(INBOX "." SENT);
2570 (void)maildir_create(INBOX "." TRASH);
2571 maildir_autopurge();
2572 unlink(SHAREDPATHCACHE);
2573
2574 sqpcp_login(ubuf, p);
2575 maildir_acl_reset(".");
2576
2577 http_redirect_argss(*cgi("inpublic") ?
2578 "&form=folders":
2579 "&form=refreshfr", "", "");
2580 free(ubuf);
2581 return;
2582 }
2583 maildir_cache_cancel();
2584
2585 free(ubuf);
2586 setgid(getgid());
2587 setuid(getuid());
2588 output_form("invalid.html"); /* Invalid login */
2589 return;
2590 }
2591
2592 setgid(getgid());
2593 setuid(getuid());
2594 if ( *(u=cgi("redirect")))
2595 /* Redirection request to hide the referral tag */
2596 {
2597 redirect(u);
2598 }
2599 else if ( *cgi("noframes") == '1')
2600 output_form("login.html"); /* Main frame */
2601 else
2602 if ( *cgi("empty") == '1')
2603 {
2604 output_form("empty.html"); /* Minor frameset */
2605 }
2606
2607 /*
2608 ** Apparently we can't show just SCRIPT NAME as our frameset due to some
2609 ** weird bug in Communicator which, under certain conditions, will get
2610 ** confused figuring out which page views have expired. POSTs with URLs
2611 ** referring to SCRIPT_NAME will be replied with an expiration header, and
2612 ** Communicator will assume that index.html also has expired, forcing a
2613 ** frameset reload the next time the Communicator window is resized,
2614 ** essentially logging the user off.
2615 */
2616
2617 else if (*cgi("index") == '1')
2618 output_form("index.html"); /* Frameset Window */
2619 else
2620 {
2621 http_redirect_top("?index=1");
2622 }
2623
2624 return;
2625 }
2626 return;
2627 }
2628
2629 #ifdef malloc
2630
2631 #undef malloc
2632 #undef realloc
2633 #undef free
2634 #undef strdup
2635 #undef calloc
2636
2637 static void *allocp[1000];
2638
2639 extern void *malloc(size_t), *realloc(void *, size_t), free(void *),
2640 *calloc(size_t, size_t);
2641 extern char *strdup(const char *);
2642
my_strdup(const char * c)2643 char *my_strdup(const char *c)
2644 {
2645 size_t i;
2646
2647 for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2648 if (!allocp[i])
2649 return (allocp[i]=strdup(c));
2650 abort();
2651 return (0);
2652 }
2653
my_malloc(size_t n)2654 void *my_malloc(size_t n)
2655 {
2656 size_t i;
2657
2658 for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2659 if (!allocp[i])
2660 return (allocp[i]=malloc(n));
2661 abort();
2662 return (0);
2663 }
2664
my_calloc(size_t a,size_t b)2665 void *my_calloc(size_t a, size_t b)
2666 {
2667 size_t i;
2668
2669 for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2670 if (!allocp[i])
2671 return (allocp[i]=calloc(a,b));
2672 abort();
2673 return (0);
2674 }
2675
my_realloc(void * p,size_t s)2676 void *my_realloc(void *p, size_t s)
2677 {
2678 size_t i;
2679
2680 for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2681 if (p && allocp[i] == p)
2682 {
2683 void *q=realloc(p, s);
2684
2685 if (q) allocp[i]=q;
2686 return (q);
2687 }
2688 abort();
2689 }
2690
my_free(void * p)2691 void my_free(void *p)
2692 {
2693 size_t i;
2694
2695 for (i=0; i<sizeof(allocp)/sizeof(allocp[0]); i++)
2696 if (p && allocp[i] == p)
2697 {
2698 free(p);
2699 allocp[i]=0;
2700 return;
2701 }
2702 abort();
2703 }
2704 #endif
2705
2706 /* Trim leading and trailing white spaces from string */
2707
trim_spaces(const char * s)2708 char *trim_spaces(const char *s)
2709 {
2710 char *p, *q;
2711
2712 p=strdup(s);
2713 if (!p)
2714 enomem();
2715
2716 if (*p)
2717 {
2718 for (q=p+strlen(p)-1; q >= p && isspace(*q); q--)
2719 *q=0;
2720
2721 for (q=p; *q && isspace(*q); q++)
2722 ;
2723 if (p != q)
2724 p=q;
2725 }
2726
2727 return (p);
2728 }
2729
2730