Subversion Repositories wimsdev

Rev

Rev 7673 | Rev 8178 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /* Web mathematical exerciser */
  19.  
  20. #define WEBMATH 1
  21. #include "Lib/libwims.h"
  22. #include "wims.h"
  23. #include <sys/socket.h>
  24. #include <sys/un.h>
  25.  
  26. struct {
  27.     char *name;
  28.     char *font;
  29. } charname[]={
  30.     {"en","iso-8859-1"},
  31.       {"fr","iso-8859-1"},
  32.       {"es","iso-8859-1"},
  33.       {"cn","gb2312"},
  34.       {"de","iso-8859-1"},
  35.       {"it","iso-8859-1"},
  36.       {"nl","iso-8859-1"},
  37.       {"si","iso-8859-2"},
  38.       {"ar","iso-8859-6"},
  39.       {"tw","big5"},
  40.       {"pt","iso-8859-1"},
  41.       {"ca","iso-8859-1"},
  42.       {"pt","iso-8859-1"},
  43.       {"ru","iso-8859-5"},
  44.       {"ty","iso-8859-13"}
  45. };
  46.  
  47. #define charname_no (sizeof(charname)/sizeof(charname[0]))
  48.  
  49. /* left to right   or   right to left   writing */
  50. struct {
  51.     char *name;
  52.     char *dirn;
  53. } dirnname[]={
  54.     {"en","ltr"},
  55.       {"fr","ltr"},
  56.       {"es","ltr"},
  57.       {"cn","ltr"},
  58.       {"de","ltr"},
  59.       {"it","ltr"},
  60.       {"nl","ltr"},
  61.       {"si","ltr"},
  62.       {"ar","rtl"},
  63.       {"tw","ltr"},
  64.       {"pt","ltr"},
  65.       {"ca","ltr"},
  66.       {"pt","ltr"},
  67.       {"ru","ltr"},
  68.       {"ty","ltr"}
  69.  
  70. };
  71.  
  72. #define dirnname_no (sizeof(dirnname)/sizeof(dirnname[0]))
  73.  
  74.  
  75. #define evalue strevalue
  76. char *robot_session="../tmp/robot";
  77. int robot_access=0,human_access=0;
  78. int user_error_nolog=0;
  79. char *good_agent[]={
  80.       "Mozilla","Netscape","Opera","WIMS",
  81.       "MSIE","Konqueror","Java"
  82. };
  83. #define good_agent_no (sizeof(good_agent)/sizeof(good_agent[0]))
  84.  
  85. char *bad_agent[]={ /* These are really bad agents: prohibited. */
  86.       "HTTrack","MemoWeb","Teleport","Offline","Wget","eCatch",
  87.       "Powermarks","EmailSiphon", "WebCopier"
  88. };
  89. #define bad_agent_no (sizeof(bad_agent)/sizeof(bad_agent[0]))
  90.  
  91. /* used for debugging */
  92. int debug=0;
  93.  
  94. char class_dir[MAX_FNAME+1]; /* directory name of this class */
  95.  
  96. struct {
  97.     char *name;
  98.     char *value;
  99. } user_variable[MAX_VAR_NUM];
  100. int user_var_no;
  101.  
  102. struct VAR_DEF {
  103.     char *name;
  104.     short int beg,end;
  105.     char allow, log_num, defined_in_parm, unused_padding;
  106. } var_def[MAX_VAR_NUM];
  107. int defined_var_total;
  108.  
  109. /* Destinated to module error messages */
  110. WORKING_FILE m_file,svar_file,mcache[MAX_MCACHE];
  111. int mcachecnt;
  112.  
  113. /* Limit for any data working files. */
  114. int WORKFILE_LIMIT=2048*1024;
  115.  
  116. /* whether the user has defined language */
  117. int user_lang=0;
  118.  
  119. /* for instex grouping */
  120. int instex_cnt=0, getwimstexsize=1;
  121. char instex_src[MAX_LINELEN+1], instex_fname[MAX_LINELEN+1];
  122. char *instex_processor="tex..gif";
  123.  
  124. /* Cookie management */
  125. char cookiegot[256], cookieset[256], cookieheader[64]="WIMSUSER=";
  126.  
  127. /* multipart boundary */
  128. char mpboundary[1024];
  129. int  deplen=0; /* length of deposit */
  130.  
  131. int confset=0; /* set to 1 if setvar for config */
  132.  
  133. /* Operating mode: default, popup, raw, etc. */
  134. enum {mode_default, mode_popup, mode_raw} NAME_MODES;
  135. int mode=mode_default;
  136.  
  137. /* Switch; notice subroutines wherether we are outputing. */
  138. int outputing;
  139.  
  140. char *home_module="home"; /* name of home module */
  141. extern char **environ;      /* table of environment variables */
  142. int module_defined=0;
  143.  
  144.         /* directory prefix buffers */
  145. char session_prefix[MAX_FNAME+1], s2_prefix[MAX_FNAME+1], module_prefix[MAX_FNAME+1];
  146.  
  147. char *stdinbuf;
  148. int sesrandomtab[MAX_SESRANDOM]; /* session random values */
  149. char multiexec_random[64];
  150. int executed_gotos; /* number of goto's executed. to check with GOTO_LIMIT. */
  151. int insert_no; /* number of instex, insplot, insPLOT. */
  152. int output_length; /* length of the output. */
  153. int isexam=0; /* non-zero if request is exam */
  154. int simuxam=0; /* exam is simulation */
  155. int is_multiexec=0; /* for execredirected */
  156. int multiexec_index;
  157. int direct_datafile=0;
  158. int exec_is_module=0;
  159.   /* root directory of modules */
  160. char *module_dir="modules";
  161. int new_session=0; /* =1 if new session created */
  162. int good_httpd=0; /* Whether the http server is intelligent */
  163. /* int internal_sql=0; */ /* for internal sql use */
  164. int direct_exec=0; /* calc routine is exected by exec if 1 */
  165. int print_precision=8; /* precision when printing real numbers */
  166. int session_serial; /* request serial for session control */
  167. int form_access=0; /* identifies form access, for robot identification */
  168. int lastout_file=-1; /* file to hold last output */
  169. char *instex_style=""; /* "": text "$": math "$$": displaymath */
  170. int instex_usedynamic=0; /* always dynamic if 1 */
  171. int wrapexec=0; /* if set to 1, change uid (nobody) to euid (wims).
  172.                  * if set to -1, change euid to uid when exec(). */
  173. int parm_restore=0; /* Restoring saved parameters? */
  174. int exec_wait=1; /* whether to wait for fork return */
  175. int execnt=0; /* count executions */
  176. int readnest; /* nested read count */
  177. int mfilecnt=0; /* count working files */
  178. int forceresume=0; /* force user to resume old request */
  179. int manageable=0; /* whether the connection may be site manager
  180.                    * 0: no; 1: maybe; 2: sure */
  181. int ismhelp=0;  /* 1 if session is in mhelp. */
  182. int getvar_len; /* length of the last-got variable. */
  183. int noout=0; /* if set to 1 then output is skipped */
  184. char tmp_dir[MAX_FNAME+1]; /* temporary directory */
  185. char *bin_dir="bin"; /* directory containing executable scripts and programs. */
  186. char cwdbuf[MAX_FNAME+1]; /* store current working directory */
  187. char var_hacking=0; /* Trying to hack a variable? */
  188. char *tmp_debug="no";
  189. char ins_alt[MAX_LINELEN+1]; /* dynamic insertion alternative text */
  190. char *devel_modules="close"; /* whether to open devel modules */
  191. int isclassmodule=0; /* 1 if the module is class module */
  192. int isdevelmodule=0; /* development module? */
  193. int setcookie=0; /* 1 if need to set cookie */
  194. int killpid=0; /* pid of process to kill by alarm */
  195. char *mathalign_sup1, *mathalign_sup2; /* see mathalign_base */
  196. int substnest=0; /* nesting level of substit() */
  197. int exodepOK=1;
  198. long int startmtime; /* start time in milliseconds */
  199. long int startmtime2; /* start time in microseconds */
  200. int backslash_insmath=0; /* \(...) substitution? */
  201. char examlogf[MAX_FNAME+1]; /* examlog file name */
  202. char examlogd[MAX_FNAME+1]; /* examlog file name */
  203. char exam_sheetexo[32]; /* sheet data of an exam */
  204. char loadavg[64];
  205. /* user file variable access control. */
  206. char *var_readable, *var_writable, *var_nr, *var_nw, *var_pfx;
  207. int hostcquota;
  208. int var_noexport; /* do not export variable */
  209.  
  210. char tmplbuf[MAX_LINELEN+1]; /* for temporary uses not thru subroutines. */
  211.  
  212. struct tm *now, Now; /* time of request */
  213. time_t nowtime, limtime, limtimex;
  214. char nowstr[32];
  215.  
  216. /* Resource limits. Capital names are reserved by system. */
  217. int rlimit_cpu=20;  /* cpu time in seconds */
  218. int rlimit_fsize=8388608;/* file size */
  219. int rlimit_as=614457600;/* virtual memory size */
  220. int rlimit_data=204857600;/* data segment size; maxima requires a lot (must be lower than rlimit_as)*/
  221. int rlimit_stack=2097152;/* stack size */
  222. int rlimit_core=0; /* core dump size */
  223. int rlimit_rss=16777216; /* resident size */
  224. int rlimit_nproc=1024; /* number of processes */
  225. int rlimit_nofile=512; /* number of open files */
  226. int rlimit_memlock=2097152;/* locked-in-memory address space */
  227.  
  228. char *var_str; /* malloc'ed buffer to hold translated query_string */
  229.  
  230. /* buffer to hold module's variable definition file, malloc'ed. */
  231. char *var_def_buf;
  232.  
  233.  /* job_identifier is even a reserved variable name */
  234. char job_identifier[32];
  235.  
  236.   /* site manager definition IPv4 IPv6*/
  237. char *manager_site="127.0.0.1 ::1";
  238. int   manager_https=0;
  239.  
  240.  /* sheet and exercise information */
  241. int wims_sheet=0,wims_exo=0;
  242.  
  243.  /* Form method: get or post */
  244. char *default_form_method="post";
  245.  
  246.  /* Je suis maintenant oblige de passer a l'anglais
  247.   * pour la langue de defaut. */
  248. char lang[16]="en";
  249. char available_lang[MAX_LANGUAGES][4]={"en","fr"};
  250. int available_lang_no=2;
  251. char pre_language[4]="";
  252. char *protocol="http"; /* http or https */
  253.  
  254.  /* check for coordinate input. This will mean that
  255.   * the request is manual, but not robot. */
  256. int coord_input=0;
  257.  
  258.  /* These are readonly environment variable names */
  259.  /* special parm used for special cmds (getins, etc). */
  260. char *ro_name[]={
  261.       "cmd" ,
  262.       "empty",
  263.       "lang" ,
  264.       "module" ,
  265.       "session" ,
  266.       "special_parm",
  267.       "special_parm2",
  268.       "special_parm3",
  269.       "special_parm4",
  270.       "useropts" ,
  271.       "wims_session",
  272.       "wims_subsession",
  273.       "wims_window",
  274.       "worksheet"
  275. };
  276. enum {
  277.     ro_cmd, ro_empty, ro_lang, ro_module, ro_session, ro_special_parm,
  278.       ro_special_parm2, ro_special_parm3, ro_special_parm4, ro_useropts, ro_wsession, ro_subsession, ro_win, ro_worksheet
  279. } RO_NAMES;
  280. #define RO_NAME_NO (sizeof(ro_name)/sizeof(ro_name[0]))
  281.  
  282. int cmd_type;
  283. char *commands[]={
  284.     "intro" , "new" , "renew" , "reply" , "config" , "hint" , "help" ,
  285.       "resume", "next", "getins", "getframe", "getfile", "close", "ref"
  286. };
  287. enum {
  288.     cmd_intro, cmd_new, cmd_renew, cmd_reply, cmd_config, cmd_hint, cmd_help,
  289.       cmd_resume, cmd_next, cmd_getins, cmd_getframe, cmd_getfile, cmd_close,
  290.       cmd_ref
  291. }COMMANDS;
  292. #define CMD_NO (sizeof(commands)/sizeof(commands[0]))
  293.  
  294.  /* stat=0: saved variables */
  295.  /* all names starting with wims_priv_ are also internal. */
  296. struct {
  297.     char *name; int stat;
  298. } internal_name[]={
  299.       {"accessright", 1}, /* right to access commercial resources */
  300.       {"caller", 1}, /* caller session */
  301.       {"check", 1}, /* for exam check use */
  302.       {"class", 1},
  303.       {"class_examlog", 1},
  304.       {"class_exolog", 1},
  305.       {"class_limit", 1},
  306.       {"class_quota", 1},
  307.       {"class_regpass", 1},
  308.       {"class_user_limit", 1},
  309.       {"classdir", 1},
  310.       {"classname", 1},
  311.       {"devel_modules", 1},
  312.       {"developer", 1},
  313.       {"doc_quota", 1},
  314.       {"doc_regpass", 1},
  315.       {"email", 1},
  316.       {"exo", 0}, /* exercise number */
  317.       {"exoption", 1}, /* exercise option */
  318.       {"firstname", 1},
  319.       {"forum_limit", 1},
  320.       {"home", 1},
  321.       {"institutionname", 1},
  322.       {"isexam", 0}, /* whether the sheet is an exam sheet */
  323.       {"ismanager", 0},
  324.       {"lastname", 1},
  325.       {"mode", 0}, /* operating mode */
  326.       {"module_start_time", 0},
  327.       {"now", 1}, /* date and time, yyyymmdd.hh:mm:ss */
  328.       {"nowseconds", 1}, /* date and time, seconds since EPOCH */
  329.       {"nr", 1}, /* non-readable variables in user file, words */
  330.       {"nw", 1}, /* non-writable variables in user file, words */
  331.       {"otherclass", 1}, /* Remember other logins */
  332.       {"participate", 1}, /* superclass definition */
  333.       {"prefix", 1}, /* user file prefix */
  334.       {"protocol", 0}, /* http protocol */
  335.       {"rafale", 0}, /* rapidfire request information */
  336.       {"readable", 1}, /* readable variables in user file, words */
  337.       {"realuser", 1}, /* real user for supervisor in gateway */
  338.       {"req_time", 0}, /* time of the request */
  339.       {"sclassdir", 1},
  340.       {"scorereg", 0}, /* score registration flag */
  341.       {"sequence", 0}, /*sequence number */
  342.       {"sescookie", 1}, /* session cookie */
  343.       {"sesdir", 1},
  344.       {"session_serial", 0}, /* request serial in the session */
  345.       {"session_start_time", 0},
  346.       {"sheet", 0}, /* sheet number */
  347.       {"sup_secure", 1}, /* secure level of supervisor */
  348.       {"superclass", 1}, /* superclass code */
  349.       {"superclass_quota", 1},
  350.       {"supertype", 1}, /* superclass type */
  351.       {"supervise", 1}, /* superclass definition */
  352.       {"supervisor", 1}, /* real name of the supervisor */
  353.       {"supervisormail",1}, /* email of supervisor */
  354.       {"trustfile", 1}, /* trusted files in special adm modules */
  355.       {"useropts", 1}, /* user options */
  356.       {"writable", 1}, /* writable variables in user file, words */
  357. };
  358. #define INTERNAL_NAME_NO (sizeof(internal_name)/sizeof(internal_name[0]))
  359.  
  360. char *httpd_vars[]={
  361.       "HTTP_ACCEPT",
  362.       "HTTP_ACCEPT_CHARSET",
  363.       "HTTP_ACCEPT_LANGUAGE",
  364.       "HTTP_COOKIE",
  365.       "HTTP_HOST",
  366.       "HTTP_USER_AGENT",
  367.       "HTTPS",
  368.       "QUERY_STRING",
  369.       "REMOTE_HOST",
  370.       "REMOTE_ADDR",
  371.       "REMOTE_PORT",
  372.       "REQUEST_METHOD",
  373.       "SCRIPT_NAME",
  374.       "SERVER_NAME",
  375.       "SERVER_SOFTWARE",
  376.       "SERVER_PROTOCOL"
  377. };
  378. #define HTTPD_VAR_NO (sizeof(httpd_vars)/sizeof(httpd_vars[0]))
  379.  
  380. /* security: these variables will not be visible to
  381.  * child processes */
  382. char *unsetvars[]={
  383.  "DOCUMENT_ROOT","SERVER_SIGNATURE","SERVER_SOFTWARE",
  384.       "UNIQUE_ID","HTTP_KEEP_ALIVE","SSL_SESSION_ID"
  385. };
  386. #define unsetvarcnt (sizeof(unsetvars)/sizeof(unsetvars[0]))
  387.  
  388. enum {httpd_apache, httpd_wims};
  389. int httpd_type=httpd_apache;
  390.  
  391. char *remote_addr=""; /* storing for performance */
  392. char *remote_host="";
  393.  
  394. char ref_name[2048], ref_base[2048];
  395.  
  396. void put_special_page(char *pname);
  397. void useropts(void);
  398.  
  399. #include "lines.c"
  400. #include "var.c"
  401. #include "config.c"
  402. #include "cleaning.c"
  403. #include "files.c"
  404. #include "pedia.c"
  405. #include "evalue.c"
  406. #include "test.c"
  407. #include "compare.c"
  408. #include "html.c"
  409. #include "mathml.c"
  410. #include "texmath.c"
  411. #include "rawmath.c"
  412. #include "insmath.c"
  413. #include "matrix.c"
  414. #include "score.c"
  415. #include "calc.c"
  416. #include "exec.c"
  417. #include "auth.c"
  418. #include "variables.c"
  419. #include "exam.c"
  420. #include "log.c"
  421.  
  422. /* Make certain httpd variables readable by modules */
  423. void take_httpd_vars(void)
  424. {
  425.     int i;
  426.     char *p, buf[MAX_NAMELEN+1];
  427.     var_noexport=1;
  428.     for(i=0;i<HTTPD_VAR_NO;i++) {
  429.      snprintf(buf,sizeof(buf),"httpd_%s",httpd_vars[i]);
  430.      if((p=getenv(httpd_vars[i]))!=NULL) setvar(buf,p);
  431.     }
  432.     var_noexport=0;
  433.  
  434.     for(i=0;i<unsetvarcnt;i++) unsetenv(unsetvars[i]);
  435.      /* IPv4 IPv6*/
  436.     p=getenv("REMOTE_ADDR");if(p!=NULL && (strcmp(p,"127.0.0.1")==0 || strcmp(p,"::1")==0)) human_access=1;
  437.     p=getenv("HTTP_REFERER"); if(p!=NULL && *p!=0) setvar("wims_referer",p);
  438. }
  439.  
  440. void cookie2session(void)
  441. {
  442.     char cksession[64], psession[32], *ckey, *p;
  443.     char nbuf[MAX_FNAME+1];
  444.  
  445.     if(mode==mode_popup) return;
  446.     if(cookiegot[0]==0) {
  447.      ckset: cookiegot[0]=0; setcookie=1; return;
  448.     }
  449.     p=getvar("special_parm");
  450.     if(p!=NULL && strcmp(p,"ignorecookie")==0) return;
  451.     mystrncpy(cksession,cookiegot,sizeof(cksession));
  452.     ckey=strchr(cksession,'-');
  453.     if(ckey==NULL) goto ckset; else *ckey++=0;
  454.     p=getvar("wims_session"); if(p==NULL) p="";
  455.     if(strstr(p,"new")!=NULL) goto ckset;
  456.     mystrncpy(psession,p,sizeof(psession));
  457.     p=strchr(psession,'_'); if(p!=NULL) *p=0;
  458.     if(psession[0]!=0) {
  459.       if(strcmp(psession,cksession)==0) return;
  460.       if(session_exists(psession)) goto ckset;
  461.       if(session_exists(cksession)) goto change;
  462.     }
  463.     else {
  464.       if(!session_exists(cksession)) return;
  465.       change:
  466.       p=getenv("HTTPS");
  467.       if(p!=NULL && strcasecmp(p,"on")==0) goto ckset;
  468.       mkfname(nbuf,"%s/%s/var",session_dir,cksession);
  469.       getdef(nbuf,"w_wims_ismanager",tmplbuf);
  470.       if(tmplbuf[0]!=0 && tmplbuf[0]!='0') goto ckset;
  471.       getdef(nbuf,"w_wims_protocol",tmplbuf);
  472.       if(strcasecmp(tmplbuf,"https")==0) goto ckset;
  473.       mkfname(nbuf,"%s/%s/var.stat",session_dir,cksession);
  474.       getdef(nbuf,"wims_user",tmplbuf);
  475.       if(tmplbuf[0]!=0) goto ckset;
  476.       force_setvar(ro_name[ro_session],cksession);
  477.       setsesdir(cksession);
  478.       force_setvar("wims_subsession","");
  479.       session_serial=0;
  480.     }
  481. }
  482.  
  483. void determine_font(char *l)
  484. {
  485.     int i;
  486.  
  487.     if(l==NULL || *l==0) return;
  488.     for(i=0;i<charname_no && memcmp(charname[i].name,l,2);i++);
  489.     if(i<charname_no) setvar("wims_main_font",charname[i].font);
  490. }
  491.  
  492. void determine_dirn(char *l)
  493. {
  494.     int i;
  495.  
  496.     if(l==NULL || *l==0) return;
  497.     for(i=0;i<dirnname_no && memcmp(dirnname[i].name,l,2);i++);
  498.     if(i<dirnname_no) setvar("wims_main_dirn",dirnname[i].dirn);
  499. }
  500.  
  501. void predetermine_language(void)
  502. {
  503.     char *p;
  504.     int i,n;
  505.  
  506.     if(pre_language[0]!=0) p=pre_language;
  507.     else p=getenv("HTTP_ACCEPT_LANGUAGE");
  508.     if(p!=NULL && strlen(p)>=2) {
  509.       for(i=0;i<available_lang_no && memcmp(p,available_lang[i],2)!=0;i++);
  510.       if(i<available_lang_no) goto lend;
  511.     }
  512.     p=getenv("HTTP_USER_AGENT");
  513.     if(p!=NULL && strlen(p)>=5) {
  514.       char *q;
  515.       if((q=strchr(p,'['))!=NULL && islower(*(q+1)) && islower(*(q+2)) && *(q+3)==']') {
  516.           char bb[4];
  517.           bb[0]=*(q+1);bb[1]=*(q+2);bb[2]=0;
  518.           for(i=0;i<available_lang_no && memcmp(bb,available_lang[i],2)!=0;i++);
  519.           if(i<available_lang_no) {
  520.             memmove(lang,bb,2); lang[2]=0;
  521.             goto lend2;
  522.           }
  523.       }
  524.     }
  525.     p=getenv("HTTP_HOST"); if(p==NULL) goto lend2;
  526.     n=strlen(p); if(n<=3 || *(p+n-3)!='.') goto lend2;
  527.     p=p+n-2;
  528.     for(i=0;i<available_lang_no && memcmp(p,available_lang[i],2)!=0;i++);
  529.     if(i<available_lang_no) {
  530.       lend: memmove(lang,p,2); lang[2]=0;
  531.       lend2: determine_font(lang);determine_dirn(lang);
  532.     }
  533. }
  534.  
  535. /* print a special page */
  536. void put_special_page(char *pname)
  537. {
  538.     determine_font(lang);
  539.     determine_dirn(lang);
  540.     phtml_put_base(mkfname(NULL,"%s.phtml.%s",pname,lang),0);
  541.     write_logs();free(var_str);
  542. }
  543.  
  544. /* check whether the connection is a site manager. */
  545. void manager_check(void)
  546. {
  547.     char *p, *pp, buf[16];
  548.     struct stat confstat;
  549.     int i;
  550.  
  551.     manageable=0;
  552.     if(robot_access || *manager_site==0 || checkhost(manager_site)<1)
  553.       goto mend;
  554.     if(manager_https) {
  555.       p=getenv("HTTPS");
  556.       if(p==NULL || strcmp(p,"on")!=0) goto mend;
  557.     }
  558.  /* IPv4 IPv6*/
  559.     if(strcmp(remote_addr,"127.0.0.1")==0 || strcmp(remote_addr,"::1")==0) {
  560.       int port, port2;
  561.       char tester[128];
  562.       p=getenv("REMOTE_PORT"); if(p==NULL) goto mend;
  563.       port=atoi(p); if(port<1024 || port>65535) goto mend;
  564.       p=getenv("SERVER_PORT"); if(p==NULL) goto mend;
  565.       port2=atoi(p); if(port2>=10000 || port2<=0) goto mend;
  566. /* this is very non-portable */
  567.       manageable=1;
  568.       accessfile(tmplbuf,"r","/proc/net/tcp");
  569.       snprintf(tester,sizeof(tester)," 0100007F:%04X 0100007F:%04X ",
  570.              port,port2);
  571.       p=strstr(tmplbuf,tester);
  572.       if(p!=NULL) {
  573.           pp=strchr(p,'\n'); if(pp!=NULL) *pp=0;
  574.           if(strlen(p)>=75) {
  575.             p=find_word_start(p+70); *find_word_end(p)=0;
  576.             if(atoi(p)==geteuid()) manageable=2;
  577.           }
  578.       }
  579.     }
  580.     else manageable=1;
  581.     i=stat(config_file,&confstat);
  582.     if(i==0 && manageable>0 && (confstat.st_mode&(S_IRWXO|S_IRWXG))!=0) manageable=-1;
  583.     if(manageable>0 && !trusted_module()) manageable=0;
  584.     if(manageable==1) {
  585.       accessfile(tmplbuf,"r","%s/.manager",session_prefix);
  586.       if(strstr(tmplbuf,"yes")!=NULL) manageable=2;
  587.     }
  588.     if(manageable==1) {
  589.       p=getvar(ro_name[ro_module]);
  590.       if(p!=NULL && strncmp(p,"adm/manage",strlen("adm/manage"))==0) {
  591.           struct stat pstat;
  592.           if(stat("../log/.wimspass",&pstat)==0) {
  593.             if((S_IFMT&pstat.st_mode)!=S_IFREG ||
  594.                ((S_IRWXO|S_IRWXG)&pstat.st_mode)!=0)
  595.               manageable=-2;
  596.           }
  597.       }
  598.     }
  599.     mend:
  600.     mystrncpy(buf,int2str(manageable),sizeof(buf));
  601.     force_setvar("wims_ismanager",buf);
  602.     if(manageable>=2) {
  603.       struct rlimit rlim;
  604.       rlimit_cpu*=10;
  605.       rlim.rlim_cur=rlim.rlim_max=rlimit_cpu;
  606.       setrlimit(RLIMIT_CPU,&rlim);
  607.       mystrncpy(buf,int2str(rlimit_cpu),sizeof(buf));
  608.       setvar("wims_cpu_limit",buf);
  609.       initalarm();
  610.     }
  611. }
  612.  
  613. /* check for robot access */
  614. void robot_check(void)
  615. {
  616.     char *ua, *p, *ses, *c, *mod;
  617.     int i;
  618.  
  619.     if(human_access) return;
  620.     mod=getvar(ro_name[ro_module]);
  621.     if(mod!=NULL && strcmp(mod,"adm/raw")==0) return;
  622.     ses=getvar(ro_name[ro_session]);
  623. /* user has valid session; OK */
  624.     if(ses!=NULL && strncmp(ses,robot_session,strlen(robot_session))!=0
  625.        && strchr(ses,'/')==NULL
  626.        && ftest(mkfname(NULL,"%s/%s",s2_dir,ses))==is_dir)
  627.       return;
  628.     ua=getenv("HTTP_USER_AGENT"); if(ua==NULL) ua="";
  629.     ua=find_word_start(ua);
  630.     if(strncasecmp(ua,"Mozilla",strlen("Mozilla"))==0 &&
  631.        (p=strstr(ua,"compatible"))!=NULL)
  632.       ua=find_word_start(find_word_end(p));
  633.     if(*ua) {
  634.       for(i=0;i<good_agent_no
  635.           && strncasecmp(ua,good_agent[i],strlen(good_agent[i]));i++);
  636.       if(i<good_agent_no) return;
  637.       for(i=0;i<bad_agent_no
  638.           && strstr(ua,bad_agent[i])==NULL;i++);
  639.       if(i<bad_agent_no) user_error("trapped");
  640.     }
  641.     force_setvar(ro_name[ro_session],robot_session);
  642.     setsesdir(robot_session);
  643.     c=getvar(ro_name[ro_cmd]);
  644.     robot_access=1;
  645.     if(c!=NULL && strcmp(c,"new") && strcmp(c,"intro")) {
  646.       force_setvar(ro_name[ro_cmd],"robot_error");
  647.       nph_header(450); put_special_page("robot");
  648.       flushoutput(); flushlog(); exit(0);
  649.     }
  650. }
  651.  
  652. /* type=0: ordinary; type=1: multipart/form-data */
  653. void parse_query_string(int len, int type)
  654. {
  655.     int i,j,l,v,cmd_defined;
  656.     int parenth=-1, ll, lb, dlen;
  657.     char *start, *p, *p1, *pt, *b1="";
  658.  
  659.     cmd_defined=0;
  660.     setvar("wims_subsession","");
  661.     ll=lb=0;
  662.     if(type) {
  663.       ll=strlen(mpboundary);
  664.       start=strstr(var_str,mpboundary);
  665.       if(start==NULL) start=var_str+strlen(var_str);
  666.       if(strstr(var_str,"\r\n\r\n")!=NULL) b1="\r\n\r\n";
  667.       else b1="\n\n";
  668.       lb=strlen(b1);
  669.     }
  670.     else start=var_str;
  671.     for(v=0, p1=start;p1<var_str+len;p1+=l) {
  672.       if(type) {
  673.           char *p2, *p3, *p4, *p5;
  674.           p2=p1+ll; p3=memstr(p2,mpboundary,var_str+len-p2); l=p3-p1;
  675.           p=memstr(p2,b1,var_str+len-p2); if(p>=p3) continue;
  676.           p+=lb; if(p3<var_str+len) {
  677.             while(*p3!='\n' && p3>p2) p3--; *p3=0;
  678.             p3--; if(*p3=='\r') *p3=0;
  679.           }
  680.           dlen=p3-p;
  681.           p2=memstr(p2,"name=",p3-p2); if(p2>=p3) continue;
  682.           p2+=strlen("name="); if(*p2=='"') p2++;
  683.           for(p3=p2; myisalnum(*p3) || strchr("._",*p3)!=NULL; p3++);
  684.           if(p3==p2) continue;
  685.           if(p3-p2==strlen("wims_deposit") &&
  686.              strncmp(p2,"wims_deposit",p3-p2)==0) {
  687.             p4=memstr(p1,"filename=",p-p1); if(p4<p) {
  688.                 p4+=strlen("filename="); if(*p4=='"') {
  689.                   p4++; p5=strchr(p4,'"');
  690.                   if(p5==NULL || p5-p4>=MAX_FNAME) goto emptyquote;
  691.                 }
  692.                 else {
  693.                   emptyquote:
  694.                   for(p5=p4; p5<p && !isspace(*p5) &&
  695.                       strchr(";\"~#*?=,'",*p5)==NULL; p5++);
  696.                 }
  697.                 if(p5>p4) {
  698.                   *p5=0;
  699.                   for(p5--;
  700.                       p5>=p4 && !isspace(*p5) && strchr("/\\:",*p5)==NULL;
  701.                       p5--);
  702.                   if(p5>=p4) p4=p5+1; if(*p4==0) goto noname;
  703.                   if(strstr(p4,"..")!=NULL || *p4=='.')
  704.                     p4="noname.file";
  705.                   setvar("wims_deposit",p4);
  706.                 }
  707.                 else {
  708.                   noname: setvar("wims_deposit","noname.file");
  709.                 }
  710.             }
  711.             deplen=dlen;
  712.           }
  713.           *p3=0; l-=p2-p1; p1=p2;
  714.       }
  715.       else {
  716.           p1=find_word_start(p1);
  717.           l=strlen(p1)+1; p=strchr(p1,'=');
  718.           if(p==NULL) p=p1+strlen(p1);
  719.           if(*p==0 && l>1) {
  720.             user_variable[v].name="no_name";
  721.             user_variable[v].value=p1;
  722.             coord_input=1;
  723.             goto nnext;
  724.           }
  725.           *p++=0;
  726.       }
  727. /* empty name or empty value: ignore */
  728.         if(*p1==0 || *p==0) continue;
  729. /* We do not treat names containing '.' */
  730.       for(pt=strchr(p1,'.'); pt; pt=strchr(++pt,'.')) *pt='_';
  731. /* Restrictions on variable names */
  732.       for(pt=p1; myisalnum(*pt) || *pt=='_'; pt++);
  733.       if(*pt) continue;
  734.       if(strcmp(p1,"wims_deposit")!=0) _tolinux(p);
  735. /* This is a restriction:
  736.  * Every parameter must have matching parentheses. */
  737.       if(parenth==-1 && strncmp(p1,"freepar_",strlen("freepar_"))!=0
  738.          && strcmp(p1,"wims_deposit")!=0
  739.          && check_parentheses(p,1)) parenth=v;
  740.       if(strcmp(p1,"special_parm")==0 && strcmp(p,"wims")==0)
  741.         human_access=1;
  742.       j=search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),p1);
  743.       if(j>=0) {
  744.           if(j==ro_session) {
  745.             p=find_word_start(p); *find_word_end(p)=0;
  746.             if(strlen(p)>MAX_SESSIONLEN) continue;
  747.             if(strcmp(p,robot_session)==0) p="";
  748.             if(strcasecmp(p,"popup")==0) {
  749.                 mode=mode_popup;
  750.                 force_setvar("wims_mode","popup");
  751.                 force_setvar("session","");
  752.                 continue;
  753.             }
  754.           }
  755.           if(j==ro_module) module_defined=1;
  756.           if(j==ro_cmd) {
  757.             p=find_word_start(p); *find_word_end(p)=0;
  758.             if(strlen(p)>16) continue;
  759.             cmd_defined=1;
  760.           }
  761.           if(j==ro_lang) {
  762.             if(strlen(p)!=2) continue;
  763.             for(i=0;i<available_lang_no && strcmp(available_lang[i],p)!=0;i++);
  764.             if(i<available_lang_no) {user_lang=1; ovlstrcpy(lang,p);}
  765.             else continue;
  766.           }
  767. /* strip leading and trailing '/'s in module name */
  768.           if(j==ro_module) {
  769.             p=find_word_start(p); *find_word_end(p)=0;
  770.             while(*p=='/') p++;
  771.             while(*p!=0 && *(p+strlen(p)-1)=='/') *(p+strlen(p)-1)=0;
  772.             if(strlen(p)>MAX_MODULELEN) continue;
  773.           }
  774.           setvar(p1,p);
  775.           if(j==ro_session && mode!=mode_popup) {
  776.             char *pp, *pr;
  777.             char buf[1024];
  778.             mystrncpy(buf,p,sizeof(buf));
  779.             if((pp=strchr(buf,'.'))!=NULL) {
  780.                 *pp++=0; session_serial=atoi(pp);
  781.                 if(pp<0) pp=0;
  782.             }
  783.             else session_serial=0;
  784.             pp=strchr(buf,'_');
  785.             if(pp!=NULL && (pr=strstr(pp,"_mhelp"))!=NULL) {
  786.                 *pr=0; ismhelp=1; lastout_file=-1;
  787.                 setvar("wims_inssub","mh");
  788.             }
  789.             force_setvar("wims_session",buf);
  790.             if(pp!=NULL) force_setvar("wims_subsession",pp);
  791.           }
  792.           continue;
  793.       }
  794.       user_variable[v].name=p1;
  795.       user_variable[v].value=p;
  796. nnext:v++; if(v>=MAX_VAR_NUM) user_error("too_many_variables");
  797.     }
  798.     user_var_no=v;
  799.     if(parenth>=0) {
  800.       char buf[16];
  801.       mystrncpy(buf,int2str(user_var_no),sizeof(buf));
  802.       setvar("user_var_no",buf);
  803.       for(i=0;i<user_var_no;i++) {
  804.           snprintf(buf,sizeof(buf),"name%d",i);
  805.           setvar(buf,user_variable[i].name);
  806.           snprintf(buf,sizeof(buf),"value%d",i);
  807.           setvar(buf,user_variable[i].value);
  808.       }
  809.       mystrncpy(buf,int2str(parenth),sizeof(buf));
  810.       setvar("bad_parentheses",buf);
  811.       user_error("unmatched_parentheses");
  812.     }
  813.     p=getenv("SCRIPT_NAME");
  814.     if(p!=NULL && (p=strstr(p,"/getfile/"))!=NULL) {
  815.       p+=strlen("/getfile/");
  816.       force_setvar(ro_name[ro_cmd],commands[cmd_getfile]);
  817.       force_setvar("special_parm",p);
  818.       cmd_defined=1;
  819.     }
  820.     if(module_defined && !cmd_defined) setvar(ro_name[ro_cmd],commands[cmd_intro]);
  821.     robot_check(); cookie2session();
  822. }
  823.  
  824. /* parse special commands */
  825. void special_cmds(void)
  826. {
  827.     char *c, *p;
  828.     int i;
  829.     long int l=-1;
  830.  
  831.     c=getvar(ro_name[ro_cmd]);
  832.     if(c==NULL || *c==0) {  /* no module name nor command */
  833.       setvar(ro_name[ro_module],home_module);
  834.       setvar(ro_name[ro_cmd],commands[cmd_new]);
  835.       return;
  836.     }
  837.     for(i=0;i<CMD_NO && strcmp(commands[i],c)!=0; i++);
  838.     switch(i) {
  839.       case cmd_intro: {
  840.           set_module_prefix();
  841.           default_form_method="get";
  842.           if(ftest(mkfname(NULL,"%s/%s",module_prefix,intro_file))<0) {
  843.             force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  844.             return;
  845.           }
  846.           p=getvar("wims_session");
  847.           if(p!=NULL && *p!=0) {
  848.             if(set_session_prefix()==0) check_session();
  849.             else {
  850.                 trap_check(p);
  851.                 if(strchr(p,'_')!=NULL && strchr(p,'/')==NULL) {
  852.                   get_static_session_var();
  853.                 }
  854.             }
  855.           }
  856. /* determine http protocol name. How to detect? */
  857.           p=getenv("HTTPS"); if(p!=NULL && strcmp(p,"on")==0) {
  858.             protocol="https"; set_protocol();
  859.           }
  860.           force_setvar("wims_protocol",protocol);
  861.           determine_font(lang);
  862.           determine_dirn(lang);
  863.           main_phtml_put(intro_file); debug_output();
  864.           introend: write_logs();free(var_str);
  865.           delete_pid(); exit(0);
  866.       }
  867.       case cmd_ref: {
  868.           set_module_prefix();
  869.           default_form_method="get";
  870.           p=getvar("wims_session");
  871.           if(p!=NULL && *p!=0) {
  872.             if(set_session_prefix()==0) check_session();
  873.             else trap_check(p);
  874.           }
  875.           determine_font(lang);
  876.           determine_dirn(lang);
  877.           main_phtml_put(ref_file); goto introend;
  878.       }
  879.       case cmd_getins: {
  880.           c=getvar(ro_name[ro_special_parm]);
  881.           if(c==NULL || *c==0) {
  882.             user_error_nolog=1; user_error("no_insnum");
  883.           }
  884.           if(*c=='/' || strstr(c,"..")!=NULL) goto badins;
  885.           set_session_prefix();
  886.           if(strstr(session_prefix,"robot")!=NULL) exit(0);
  887.           l=filelength("%s/%s",s2_prefix,c);
  888.           if(l<0) {
  889.             badins: user_error_nolog=1; user_error("bad_insnum");
  890.           }
  891.           {
  892.             char *fmt;
  893.             fmt=strchr(c,'.');
  894.             if(fmt==NULL) {
  895.                 user_error_nolog=1; user_error("bad_insnum");
  896.             }
  897.             else fmt++;
  898.  
  899.             nph_header(200);
  900. /* insert format problem; bricolage */
  901.             printf("Content-type: image/%s\r\n\
  902. Content-length: %ld\r\n\r\n",fmt,l);
  903.             catfile(stdout,"%s/%s",s2_prefix,c); exit(0);
  904.           }
  905.       }
  906.       case cmd_getfile: {
  907.           char fname[MAX_FNAME+1];
  908.           c=getvar(ro_name[ro_special_parm]);
  909.           if(c==NULL || *c==0) {
  910.             user_error_nolog=1; user_error("no_insnum");
  911.           }
  912.           if(*c=='/' || strstr(c,"..")!=NULL) goto badfile;
  913.  
  914.           set_session_prefix();
  915.           if(strstr(session_prefix,"robot")!=NULL) exit(0);
  916.           mkfname(fname,"%s/getfile/%s",session_prefix,c);
  917.           l=filelength("%s",fname);
  918.           if(l<0 && strchr(session_prefix,'_')!=NULL) {
  919.             char *pt;
  920.             mystrncpy(fname,session_prefix,sizeof(fname));
  921.             pt=strrchr(fname,'_'); if(pt) *pt=0;
  922.             snprintf(fname+(pt-fname),sizeof(fname)-(pt-fname),
  923.                   "/getfile/%s",c);
  924.             l=filelength("%s",fname);
  925.           }
  926.           if(l<0) {
  927.             badfile: user_error_nolog=1; user_error("bad_insnum");
  928.           }
  929.           if(l>512*1024) {
  930.             struct rlimit rlim;
  931.             rlimit_cpu*=l/(10*1024);
  932.             rlim.rlim_cur=rlim.rlim_max=rlimit_cpu;
  933.             initalarm();
  934.           }
  935.           {
  936.             char *p1;
  937.             char mime[MAX_LINELEN+1];
  938.             for(p1=c+strlen(c);p1>c && isalpha(*(p1-1)); p1--);
  939.             ovlstrcpy(mime,"application/octet-stream");
  940.             if(p1>c && *(p1-1)=='.') {
  941.                 setvar("translator_unknown",mime);
  942.                 setvar("dictionary","bases/sys/mime");
  943.                 snprintf(mime,sizeof(mime),"translator %s",p1);
  944.                 calc_exec(mime);
  945.             }
  946.             nph_header(200);
  947.             printf("Content-type: %s\r\n\
  948. Content-length: %ld\r\n\r\n",mime,l);
  949.             catfile(stdout,"%s",fname); exit(0);
  950.           }
  951.       }
  952.       case cmd_close: {
  953.           char *p, b2[32]; int w;
  954.           char nbuf[MAX_FNAME+1], vbuf[MAX_LINELEN+1];
  955.           p=getvar(ro_name[ro_session]);
  956.           if(p==NULL || strlen(p)<10 ||
  957.              strchr(p,'/')!=NULL) return;
  958.           mystrncpy(b2,p,sizeof(b2));
  959.           p=strchr(b2,'.'); if(p!=NULL) *p=0;
  960.           mkfname(nbuf,"%s/%s/var.stat",session_dir,b2);
  961.           getdef(nbuf,"wims_caller",vbuf);
  962.           if(vbuf[0]!=0) force_setvar(ro_name[ro_session],vbuf);
  963.           w=wrapexec; wrapexec=1;
  964.           call_sh("rm -Rf %s/%s* %s/%s* >/dev/null 2>&1",session_dir,b2,s2_dir,b2);
  965.           wrapexec=w; cookiegot[0]=0;
  966.           force_setvar(ro_name[ro_cmd],"new");
  967.       }
  968.       default: return;
  969.     }
  970. }
  971.  
  972. /* This is run only when manually invoking the program.
  973.  * Verifies the orderedness of various list tables. */
  974. int verify_tables(void)
  975. {
  976.     if(verify_order(calc_routine,CALC_FN_NO,sizeof(calc_routine[0]))) return -1;
  977.     if(verify_order(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]))) return -1;
  978.     if(verify_order(main_config,MAIN_CONFIG_NO,sizeof(main_config[0]))) return -1;
  979.     if(verify_order(mathname,mathname_no,sizeof(mathname[0]))) return -1;
  980.     if(verify_order(hmname,hmname_no,sizeof(hmname[0]))) return -1;
  981.     if(verify_order(ro_name,RO_NAME_NO,sizeof(ro_name[0]))) return -1;
  982.     if(verify_order(distr_cmd,distr_cmd_no,sizeof(distr_cmd[0]))) return -1;
  983.     if(verify_order(internal_name,INTERNAL_NAME_NO,
  984.                 sizeof(internal_name[0]))) return -1;
  985.     if(verify_order(tmathfn,tmathfn_no,sizeof(tmathfn[0]))) return -1;
  986.     if(verify_order(tmathvar,tmathvar_no,sizeof(tmathvar[0]))) return -1;
  987.     if(verify_order(modindex,MODINDEX_NO,sizeof(modindex[0]))) return -1;
  988.     if(verify_order(exportvars,exportvarcnt,sizeof(exportvars[0]))) return -1;
  989.     if(evaltab_verify()) return -1;
  990.     if(textab_verify()) return -1;
  991.     return 0;
  992. }
  993.  
  994. void config_defaults(void)
  995. {
  996.     int i;
  997.     for(i=0;i<MAIN_CONFIG_NO;i++) {
  998.       if((1&main_config[i].is_integer)==1) {
  999.           int *pi = (int*)main_config[i].address;
  1000.           printf("DF_%s=%d\n",main_config[i].name, *pi);
  1001.         }
  1002.       else {
  1003.             char **ps = (char**)main_config[i].address;
  1004.           printf("DF_%s=%s\n",main_config[i].name,*ps);
  1005.         }
  1006.     }
  1007. }
  1008.  
  1009. /* get and set useroptions */
  1010. void useropts(void)
  1011. {
  1012.     char *p;
  1013.     setvar("lang",lang);
  1014.     p=getvar("useropts");
  1015.     if(p==NULL || *p==0) p=getvar("wims_useropts");
  1016.     if(p!=NULL && *p!=0) {
  1017.       if(myisdigit(p[0])) {
  1018.         usertexsize=p[0]-'0';
  1019.         /* fourth digit is for special fonts*/
  1020.         if(p[1]!=0) { mathalign_base=p[1]-'0'; }
  1021.       }
  1022.       if(myisdigit(p[3]) && p[3]!=0){ spec_font=p[3]-'0';}
  1023.     }
  1024.     if(mathalign_base==1) {
  1025.         mathalign_sup1="<sup>"; mathalign_sup2="</sup>";
  1026.     } else mathalign_sup1=mathalign_sup2="";
  1027. }
  1028.  
  1029. /* popup module help */
  1030. void mhelp(void)
  1031. {
  1032.     char *p, buf[MAX_LINELEN+1];
  1033.     main_phtml_put(""); buf[0]=0;
  1034.     if(cmd_type!=cmd_help) {
  1035.       phtml_put_base("closemhelp.phtml",0);
  1036.     }
  1037.     else {
  1038.       phtml_put_base("mhelpheader.phtml",0);
  1039.       p=getvar("special_parm");
  1040.       if(p!=NULL && strcmp(p,"about")==0)
  1041.         phtml_put("about.phtml",0);
  1042.       else phtml_put("help.phtml",0); phtml_put_base("mhelptail.phtml",0);
  1043.       exec_tail(buf);
  1044.     }
  1045. }
  1046.  
  1047. #define READSTDIN_WINDOW 4096
  1048.  
  1049. void readstdin(int len)
  1050. {
  1051.     int ll, l1, lt, lr;
  1052.     int cpulim;
  1053.  
  1054.     cpulim=rlimit_cpu; rlimit_cpu=3;
  1055.     lr=len; l1=0;
  1056.     while(lr>0) {
  1057.       nowtime=time(0); initalarm();
  1058.       ll=lr; if(ll>READSTDIN_WINDOW) ll=READSTDIN_WINDOW;
  1059.       lt=fread(stdinbuf+l1,1,ll,stdin);
  1060.       if(lt!=ll) user_error("parm_too_long");
  1061.       lr-=ll; l1+=ll;
  1062.     }
  1063.     if(l1!=len) user_error("parm_too_long");
  1064.     stdinbuf[len]=0; rlimit_cpu=cpulim;
  1065. }
  1066.  
  1067. /* input: p=QUERY_STRING. output: parameter length. */
  1068. /* Netscape puts form content into /tmp. */
  1069. int formdata(char *p)
  1070. {
  1071.     char *pp;
  1072.     int inlen;
  1073.     char *ctype;
  1074.     inlen=0; ctype=getenv("CONTENT_TYPE");
  1075.     if(ctype==NULL || strstr(ctype,"multipart/form-data")==NULL
  1076.        || (p=strstr(ctype,"boundary="))==NULL) {
  1077.       bad: stdinbuf=""; return 0;
  1078.     }
  1079.     pp=getenv("CONTENT_LENGTH");
  1080.     if(pp==NULL) goto bad;
  1081.     inlen=atoi(pp); if(inlen<=10) goto bad;
  1082.     if(inlen>=MAX_DEPOSITLEN) user_error("parm_too_long");
  1083.     stdinbuf=xmalloc(inlen+1); readstdin(inlen);
  1084.     p+=strlen("boundary=");
  1085.     for(pp=p;myisalnum(*pp) || *pp=='-'; pp++);
  1086.     if(pp-p<sizeof(mpboundary)-2) {
  1087.       memmove(mpboundary,p,pp-p); mpboundary[pp-p]=0;
  1088.     }
  1089. /* empty data */
  1090.     if(strstr(stdinbuf,mpboundary)==NULL || strstr(stdinbuf,"name=")==NULL) {
  1091.       free(stdinbuf); goto bad;
  1092.     }
  1093.     form_access=1; post_log();
  1094.     return inlen;
  1095. }
  1096.  
  1097. /* get the content of POST */
  1098. void getpost(void)
  1099. {
  1100.     int ll;
  1101.     char *pp;
  1102.     pp=getenv("CONTENT_LENGTH");
  1103.     if(pp==NULL || (ll=atoi(pp))<=0) {
  1104.       stdinbuf=xmalloc(16); stdinbuf[0]=0;
  1105.     }
  1106.     else {
  1107.       if(ll>QUERY_STRING_LIMIT) user_error("parm_too_long");
  1108.       stdinbuf=xmalloc(ll+16); readstdin(ll);
  1109.       if(ll>0) {
  1110.           setenv("QUERY_STRING",stdinbuf,1);
  1111.           form_access=1; post_log();
  1112.       }
  1113.     }
  1114. }
  1115.  
  1116. void buffer_init(void)
  1117. {
  1118.     struct timeval tv;
  1119.  
  1120.     mcachecnt=readnest=0;
  1121.     mpboundary[0]=cookiegot[0]=cookieset[0]=cwdbuf[0]=0;
  1122.     rscore_class[0]=rscore_user[0]=multiexec_random[0]=0;
  1123.     lastftest[0]=0;
  1124.     lastdatafile[0]=0; lastdata=xmalloc(WORKFILE_LIMIT);
  1125.     outptr=outbuf;
  1126.     instex_src[0]=instex_fname[0]=module_prefix[0]=0;
  1127.     examlogf[0]=examlogd[0]=exam_sheetexo[0]=0;
  1128.     stdinbuf=NULL;
  1129.     mkfname(tmp_dir,"../tmp/forall");
  1130.     mkfname(session_dir,"../%s",SESSION_BASE);
  1131.     mkfname(s2_dir,"../%s",S2_BASE);
  1132.     if(gettimeofday(&tv,NULL)) startmtime=startmtime2=0;
  1133.     else {
  1134.       startmtime=((tv.tv_sec%10000)*1000+tv.tv_usec/1000);
  1135.       startmtime2=(tv.tv_sec%1000)*1000000+tv.tv_usec;
  1136.     }
  1137. }
  1138.  
  1139. int main(int argc, char *argv[], char *envp[])
  1140. {
  1141.     char *p, homebuf[MAX_FNAME+1], lbuf[32];
  1142.     int inlen=0;
  1143. /*    int mfd;
  1144. */
  1145.     error1=user_error; error2=module_error; error3=internal_error;
  1146.     class_dir[0]=0;
  1147.     substitute=substit; buffer_init(); var_init();
  1148. /* WIMS internal locale is always C. */
  1149.     setenv("LANG","C",1); umask(022);
  1150.     setenv("LANGUAGE","us",1);
  1151.     setenv("LC_ALL","C",1);
  1152.     if(argc>1) {
  1153.       if(strcasecmp(argv[1],"table")==0) {
  1154.           if(verify_tables()) internal_error("Table disorder.");
  1155.           else printf("Table orders OK.\n");
  1156.           return 0;
  1157.       }
  1158.       if(strcasecmp(argv[1],"version")==0) {
  1159.           printf("%s",wims_version); return 0;
  1160.       }
  1161.       if(strcasecmp(argv[1],"defaults")==0) {
  1162.           config_defaults(); return 0;
  1163.       }
  1164.     }
  1165.     p=getenv("SERVER_SOFTWARE"); if(p!=NULL && strcasecmp(p,"WIMS")==0)
  1166.       httpd_type=httpd_wims;
  1167.     p=getenv("REMOTE_ADDR"); if(p!=NULL) remote_addr=p;
  1168.     p=getenv("REMOTE_HOST"); if(p!=NULL) remote_host=p;
  1169.     nowtime=time(0); now=localtime(&nowtime);
  1170.     memmove(&Now, now, sizeof(Now)); now=&Now;
  1171.     snprintf(nowstr,sizeof(nowstr),"%04d%02d%02d.%02d:%02d:%02d",
  1172.            (now->tm_year)+1900,(now->tm_mon)+1,now->tm_mday,
  1173.            now->tm_hour,now->tm_min,now->tm_sec);
  1174.     p=getenv("QUERY_STRING");
  1175.     if(p==NULL || *p==0) getpost();
  1176.     else if(strncmp(p,"form-data",9)==0) inlen=formdata(p);
  1177.  
  1178.     force_setvar("wims_now",nowstr);
  1179.     snprintf(lbuf,sizeof(lbuf),"%lu",nowtime);
  1180.     force_setvar("wims_nowseconds",lbuf);
  1181.     nowtime=time(0);
  1182.     initalarm();
  1183.  
  1184.     executed_gotos=insert_no=output_length=0; ins_alt[0]=0;
  1185.     setvar("empty","");       /* lock this variable */
  1186.     setvar("wims_version",wims_version);
  1187.     setvar("wims_version_date",wims_version_date);
  1188.     setvar("wims_main_font","utf-8");
  1189.     take_httpd_vars();
  1190.  
  1191.     main_configure();
  1192.     checklogd();
  1193. /*    mfd=shm_open(SHM_NAME,O_RDONLY,-1);
  1194.     if(mfd==-1) internal_error("Unable to find shared memory.");
  1195.     shmptr=mmap(0,SHM_SIZE,PROT_READ,MAP_SHARED,mfd,0);
  1196.     if(shmptr==MAP_FAILED) internal_error("Shared memory failure.");
  1197. */
  1198.     getppid(); /* this is the first sysmask trigger, must be after checklogd() */
  1199.     predetermine_language();
  1200.     /* modify a few rlimits for 64-bit processors */
  1201.     if (sizeof(long) == 8) {
  1202.       rlimit_as*=2;    /* virtual memory size */
  1203.       rlimit_data*=2;  /* data segment size; maxima requires a lot */
  1204.       rlimit_stack*=2; /* stack size */
  1205.     }
  1206.     set_rlimits();
  1207.     init_random();
  1208.     module_configure();
  1209.     set_job_ident();
  1210.     m_file.name[0]=0;m_file.linecnt=m_file.linepointer=0;
  1211.     p=getenv("QUERY_STRING");
  1212.     if(p==NULL || strlen(p)==0) {
  1213.       setvar("lang",lang);
  1214.       snprintf(homebuf,sizeof(homebuf),"module=%s",home_module);
  1215.       p=homebuf;
  1216.     }
  1217.     if(strlen(p)>=QUERY_STRING_LIMIT) user_error("parm_too_long");
  1218.     if(mpboundary[0]==0) {
  1219.       var_str=xmalloc(strlen(p)+2);
  1220.       parse_query_string(http2env(var_str,p),0);
  1221.     }
  1222.     else {
  1223.       var_str=stdinbuf;
  1224.       parse_query_string(inlen,1);
  1225.     }
  1226.     if(ismhelp) {
  1227.       p=getvar(ro_name[ro_cmd]);
  1228.       if(p==NULL || (strcmp(p,"help")!=0 && strcmp(p,"getins")!=0)) {
  1229.           mhelp(); goto outgo;
  1230.       }
  1231.     }
  1232.     check_exam();
  1233.     useropts();
  1234.     special_cmds();
  1235.     parse_ro_names();
  1236.     manager_check();
  1237.     access_check(0);
  1238.     set_variables();
  1239.     determine_font(getvar("module_language"));
  1240.     determine_dirn(getvar("module_language"));
  1241.     if(!robot_access && session_prefix[0]!=0 && cmd_type!=cmd_help && !ismhelp)
  1242.       lastout_file=creat(mkfname(NULL,"%s/%s",s2_prefix,lastout),
  1243.                    S_IRUSR|S_IWUSR);
  1244.     p=getvar("module_category");
  1245.     if(p==NULL || strstr(p,"tool")==NULL) default_form_method="get";
  1246.     if(noout) {
  1247.       write_logs(); save_session_vars();
  1248.       goto outgo;
  1249.     }
  1250.     if(ismhelp) {
  1251.       mhelp();
  1252.     }
  1253.     else {
  1254.       main_phtml_put(html_file);
  1255.       if(lastout_file!=-1) {
  1256.           flushoutput(); close(lastout_file); putlastout();
  1257.       }
  1258.       write_logs(); save_session_vars();
  1259.     }
  1260.     outgo:
  1261.     debug_output();
  1262.     if(var_str!=stdinbuf) free(var_str);
  1263.     delete_pid();
  1264.     if(mode!=mode_popup && trusted_module()) {
  1265.       p=getvar("wims_mode");
  1266.       if(p!=NULL && strcmp(p,"popup")==0) mode=mode_popup;
  1267.     }
  1268.     if(mode==mode_popup && insert_no==0) {
  1269.       p=getvar("wims_mode");
  1270.       if(p!=NULL && strcmp(p,"popup")==0) {
  1271.           remove_tree(session_prefix);
  1272.  
  1273.           remove_tree(s2_prefix);
  1274.       }
  1275.     }
  1276.     return 0;
  1277. }
  1278.