Subversion Repositories wimsdev

Rev

Rev 17459 | 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. /* line input / output / translation routines
  19.  * and error routines
  20.  */
  21. #include <utime.h>
  22. #include <sys/socket.h>
  23. #include <sys/un.h>
  24.  
  25. #include "wims.h"
  26.  
  27. int is_class_module=0;
  28.  
  29. int trusted_module(void);
  30. void phtml_put_base(char *fname,int cache);
  31. void module_error(char msg[]);
  32. void user_error(char msg[]);
  33. void accessfile(char *content, char *type, char *s,...);
  34. int remove_tree(char *p);
  35. void output(char *s,...);
  36. char *_getvar(char *vname);
  37. int checkhost(char *hlist);
  38.  
  39. char *lastdata;
  40. char lastdatafile[MAX_FNAME+1];
  41. char *datacache[DATAFIELD_LIMIT];
  42. int  nextdatacache;
  43. struct stat ftst;
  44. char lastftest[MAX_FNAME+1];
  45. int lastftype;
  46. char outbuf[8192];
  47. char *outptr;
  48.  
  49. /* These modules can execute private programs.
  50.  * adm/ modules are always trusted, so need no definition here.
  51.  */
  52. char *trusted_modules="";
  53. /* bit 0: module is not trusted.
  54.   * bit 1: file in wimshome.
  55.   * bit 2: readdef or file in writable directory.
  56.   */
  57. int untrust=0;  /* non-zero if user detrusts the module. */
  58.  
  59. int error_status=0;
  60. char pidbuf[32];
  61.  
  62. void delete_pid(void);
  63.  
  64. /* Internal use only */
  65. void _debug(char *s,...)
  66. {
  67.   va_list vp;
  68.   char buf[MAX_LINELEN+1];
  69.  
  70.   va_start(vp,s);
  71.   vsnprintf(buf,sizeof(buf),s,vp);
  72.   va_end(vp);
  73.   setvar("debug",buf); module_error("debug");
  74.   exit(1);
  75. }
  76.  
  77.  
  78. /* HTTP response header for non-processed CGI interface */
  79. void nph_header(int code)
  80. {
  81.   char *cstr;
  82.   switch(code) {
  83.     case 200: cstr="OK"; break;
  84.     case 301: cstr="Moved Permanently"; break;
  85.     case 302: cstr="Moved Temporarily"; break;
  86.     case 420: cstr="WIMS Nested Error"; break;
  87.     case 450: cstr="WIMS User Error"; break;
  88.     case 500: cstr="WIMS Internal Error"; break;
  89.     case 550: cstr="WIMS Module Error"; break;
  90.     default: cstr="ERROR"; break;
  91.   }
  92.   if(httpd_type!=httpd_wims) printf("Status: %d %s\r\n",code,cstr);
  93.   else {
  94.     char *p, tbuf[256];
  95.     mystrncpy(tbuf,ctime(&nowtime),sizeof(tbuf));
  96.     for(p=tbuf+strlen(tbuf);p>=tbuf && (*(p-1)=='\n' || *(p-1)=='\r'); p--);
  97.     *p=0;
  98.     printf("HTTP/1.0 %d %s\r\n\
  99. Date: %s\r\n\
  100. Connection: close\r\n\
  101. ",code,cstr,tbuf);
  102.   }
  103. }
  104.  
  105. void flushoutput(void)
  106. {
  107.   int l2;
  108.   if(outptr<=outbuf) return;
  109.   l2=outptr-outbuf;
  110.   if(lastout_file!=-1) (void)write(lastout_file,outbuf,l2);
  111.   else fwrite(outbuf,l2,1,stdout);
  112.   outptr=outbuf;
  113. }
  114.  
  115. void internal_warn(char msg[])
  116. {
  117.   char buf[1024];
  118.   fprintf(stderr,"wims: %s\n%s\n",msg,strerror(errno));
  119.   snprintf(buf,sizeof(buf),"%s: %s\n",nowstr,msg);
  120.   accessfile(buf,"a","%s/internal_error.log",log_dir);
  121. }
  122.  
  123. /* Internal error: panic and forget about requester. */
  124. void internal_error(char msg[])
  125. {
  126.   if(error_status<2) {
  127.     nph_header(500);
  128.     printf("Cache-Control: no-cache, no-store, must-revalidate\r\n\
  129. Content-type: text/plain\r\n\r\n\r\n\
  130. WIMS panick! %s\n%s\n",msg,strerror(errno));
  131.       error_status=2; internal_warn(msg);
  132.   }
  133.   delete_pid(); exit(1);
  134. }
  135.  
  136. void tex_nospace(char *p)
  137. {
  138.   char *p1, *p2;
  139.   char buf[MAX_LINELEN+1];
  140.   for(p1=buf,p2=p;*p2 && p1-buf<MAX_LINELEN-4;p2++) {
  141.     if(!isspace(*p2)) {*p1++=*p2;continue;}
  142.     while(isspace(*p2)) p2++;
  143.     if(*(p1-1)=='\\' ||
  144.        (p1>buf && myisalnum(*(p1-1)) && myisalnum(*p2)))
  145.       *p1++=' ';
  146.     *p1++=*p2;
  147.   }
  148.   *p1++=0; memmove(p,buf,p1-buf);
  149. }
  150.  
  151. void nametoolong(char *p)
  152. {
  153.   char buf[MAX_FNAME+17];
  154.   snprintf(buf,sizeof(buf),"%s...",p);
  155.   force_setvar("wims_error_data",buf);
  156.   module_error("file_name_too_long");
  157. }
  158.  
  159. off_t ftest_size;
  160.  
  161. /* A simple front-end of stat(). */
  162. int ftest(char *fname)
  163. {
  164.   if(strcmp(fname,lastftest)==0) return lastftype;
  165. /* if(fname[0]=='/' || fname[0]=='.') fprintf(stderr,"ftest: %s\n",fname); */
  166.   mystrncpy(lastftest,fname,sizeof(lastftest));
  167.   if(stat(fname,&ftst)) return lastftype=-1;
  168.   ftest_size=ftst.st_size;
  169.   if(S_ISREG(ftst.st_mode)) {
  170.     if((ftst.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))!=0) return lastftype=is_exec;
  171.     else return lastftype=is_file;
  172.   }
  173.   if(S_ISDIR(ftst.st_mode)) return lastftype=is_dir;
  174.   if(S_ISFIFO(ftst.st_mode)) return lastftype=is_fifo;
  175.   if(S_ISSOCK(ftst.st_mode)) return lastftype=is_socket;
  176.   return lastftype=is_unknown;
  177. }
  178.  
  179. char fnbuf[MAX_FNAME+1];
  180.  
  181. /* make a filename and check length */
  182. char *mkfname(char buf[], char *s,...)
  183. {
  184.   va_list vp;
  185.   char *p;
  186.  
  187.   if(buf==NULL) p=fnbuf; else p=buf;
  188.   va_start(vp,s);
  189.   vsnprintf(p,MAX_FNAME,s,vp);
  190.   va_end(vp);
  191.   if(strlen(p)>=MAX_FNAME-1) nametoolong(p);
  192.   return p;
  193. }
  194.  
  195. void sysmask_trigger(char *s)
  196. {
  197.   char buf[MAX_FNAME+1];
  198.   struct stat st;
  199.   mkfname(buf,"%s/%s",sysmask_trigger_dir,s);
  200.   stat(buf,&st);
  201. }
  202.  
  203. /* read-in a file into buffer. Use open() and read().
  204.        * Return buffer address which will be malloc'ed if buf=NULL. */
  205. char *readfile(char *fname, char buf[], long int buflen)
  206. {
  207.   int fd, t, st;
  208.   long int l, lc;
  209.   char *bf;
  210.   t=0; if(buf) buf[0]=0;
  211.   st=ftest(fname); if(st!=is_file) {
  212.     if(st==is_exec) { /* refuse to open executable file */
  213.       setvar("executable",fname); module_error("executable");
  214.     }
  215.     return NULL;
  216.   }
  217.   l=ftst.st_size; if(l<0) return NULL;
  218.   if(l>=buflen) {
  219.     if(buflen<MAX_LINELEN) l=buflen-1;
  220.     else {
  221.       if(strncmp(fname,"modules/",strlen("modules/"))==0) {
  222.         setvar(error_data_string,fname); module_error("file_too_long");
  223.       }
  224.       else user_error("cmd_output_too_long");
  225.     }
  226.   }
  227.   fd=open(fname,O_RDONLY); if(fd==-1) return NULL;
  228.   if(buf==NULL) bf=xmalloc(l+8); else {bf=buf;if(l==0) {t=1; l=buflen-1;}}
  229.   lc=read(fd,bf,l); close(fd);
  230.   if(lc<0 || lc>l || (lc!=l && t==0)){
  231.     if(buf==NULL) free(bf); else buf[0]=0; return NULL;
  232.   }
  233.   bf[lc]=0; _tolinux(bf); return bf;
  234. }
  235.  
  236. /* Get a line in a stored working file.
  237.        * Buffer length is always MAX_LINELEN. */
  238. int wgetline(char buf[], size_t buflen, WORKING_FILE *f)
  239. {
  240.   int i,j; unsigned int n;
  241.   i=f->linepointer; buf[0]=0;
  242.   if(i>=f->linecnt || f->textbuf==NULL) return EOF;
  243.   n=f->lines[i].llen;
  244.   if(n>=buflen) n=buflen-1;
  245.   if(n>0) memmove(buf,f->lines[i].address,n);
  246.   buf[n]=0;
  247.   for(j=i+1;j<f->linecnt && f->lines[j].isstart==0;j++);
  248.   f->l=i; f->linepointer=j;
  249.   if(j>=f->linecnt && n==0) return EOF; else return n;
  250. }
  251.  
  252. int get_cached_file(char *name)
  253. {
  254.   int i,l,flag;
  255.   l=strlen(name); if(l>=127) return -1;
  256.   if(strncmp(module_prefix,module_dir,strlen(module_dir))!=0) flag=8; else flag=0;
  257.   for(i=0;i<mcachecnt;i++) {
  258.     if(flag==mcache[i].nocache && strcmp(name,mcache[i].name)==0) {
  259.       memmove(&m_file,mcache+i,sizeof(WORKING_FILE));
  260.       m_file.nocache|=4;
  261.       return i;
  262.     }
  263.   }
  264.   return -1;
  265. }
  266.  
  267. /* Open a work file. Returns 0 if OK. */
  268. int open_working_file(WORKING_FILE *f, char *fname)
  269. {
  270.   char *p, *q;
  271.   void *vp;
  272.   int i,j,k,laststart,lc[LINE_LIMIT];
  273.  
  274.   f->linecnt=f->linepointer=0;
  275.   f->for_idx=f->nocache=0;
  276.   f->l=-1; f->lines=NULL;
  277.   strncpy(f->filepath,fname,MAX_FNAME+1);
  278.   f->textbuf=readfile(fname,NULL,WORKFILE_LIMIT);
  279.   if(f->textbuf==NULL) return -1;
  280.   p=f->textbuf; if(*p) {
  281.     for(i=0,p--; i<LINE_LIMIT-1 && p!=NULL;p=strchr(p,'\n')) {
  282.       if(i>0) *p=0;
  283.       lc[i++]=(++p-f->textbuf);
  284.     }
  285.   }
  286.   else i=0;
  287.   if(i>=LINE_LIMIT-1) module_error("file_too_long");
  288.   lc[i]=lc[i-1]+strlen(f->textbuf+lc[i-1])+1;
  289.   f->textbuf[lc[i]]=0;
  290.   f->linecnt=i; laststart=0;
  291.   f->for_stack=xmalloc(MAX_FOR_LEVEL*sizeof(FOR_STACK)+(i+1)*sizeof(LINE_STRUCT));
  292.   vp=f->for_stack+MAX_FOR_LEVEL; f->lines=vp;
  293.   for(j=0;j<i;j++) {
  294.     f->lines[j].address=p=(f->textbuf)+lc[j];
  295.     f->lines[j].llen=lc[j+1]-lc[j]-1;
  296.     (f->lines[j]).execcode=(f->lines[j]).varcode=-1;
  297.     if(j==0) goto normal;
  298.     q=f->lines[laststart].address+f->lines[laststart].llen-1;
  299.     if(q>=f->textbuf && *q=='\\') {
  300.       f->lines[laststart].llen+=f->lines[j].llen; *q='\n';
  301.       f->lines[j].isstart=f->lines[j].llen=0;
  302.       memmove(q+1,p,lc[j+1]-lc[j]);
  303.     }
  304.     else {
  305.       normal: for(q=p;myislspace(*q);q++);
  306.       f->lines[j].isstart=1; laststart=j; k=0;
  307.       switch(*q) {
  308.                 /* isstart: bit 1 = start.
  309.                  * bit 2 = exec
  310.                  * bit 3 (4) = label
  311.                  * bit 4 (8) = hard comment (!!)
  312.                  * bit 5 (16) = soft comment (#) */
  313.         case exec_prefix_char: {
  314.           if(myisalpha(q[1])) f->lines[j].isstart=3;
  315.           else f->lines[j].isstart=9;
  316.           k=1; break;
  317.         }
  318.         case label_prefix_char: {f->lines[j].isstart=5; k=1; break;}
  319.         case comment_prefix_char: {f->lines[j].isstart=17; break;}
  320.         default: {f->lines[j].isstart=1; break;}
  321.       }
  322.       if(k && q>p) {f->lines[j].address=q;f->lines[j].llen-=q-p;}
  323.     }
  324.   }
  325.   f->lines[i].isstart=1; f->lines[i].llen=0;
  326.   f->lines[i].address=(f->textbuf)+lc[i];
  327.   mfilecnt++; return 0;
  328. }
  329.  
  330. /* close an earlier opened working file */
  331. void close_working_file(WORKING_FILE *f, int cache)
  332. {
  333.   f->linepointer=f->l=0;
  334.   if(cache && untrust==0 && mcachecnt<MAX_MCACHE && (f->nocache&7)==0) {
  335.     memmove(mcache+mcachecnt,f,sizeof(WORKING_FILE));
  336.     mcachecnt++;
  337.   }
  338.   else if((f->nocache&4)==0) {
  339.     if(f->for_stack!=NULL) free(f->for_stack);
  340.     if(f->textbuf!=NULL) free(f->textbuf);
  341.   }
  342.   f->for_stack=NULL; f->textbuf=NULL; f->linecnt=0;
  343. }
  344.  
  345. void free_mcache(void)
  346. {
  347.   int i;
  348.   untrust=0;
  349.   for(i=mcachecnt-1;i>=0;i--) close_working_file(mcache+i,0);
  350.   mcachecnt=0;
  351. }
  352.  
  353. void cleantmpdir(void);
  354. void user_error_log(char msg[]);
  355.  
  356. void nested_error(char msg[])
  357. {
  358.   fprintf(stderr,"\nNested error! %s\n",msg);
  359.   nph_header(420);
  360.   printf("\r\n\r\nWIMS error processing aborted on nested error.\r\n\r\n%s\r\n",msg);
  361.   delete_pid(); exit(1);
  362. }
  363.  
  364. /* Send an error message to requester and exit.
  365.  * This is for user errors, language-sensitive.
  366.  */
  367. void user_error(char msg[])
  368. {
  369.   char erfname[MAX_FNAME+1];
  370.  
  371.   if(error_status) nested_error(msg);
  372.   error_status=1;
  373.   mkfname(erfname,"%s.%s",user_error_msg_file,lang);
  374.   if(ftest(erfname)!=is_file) internal_error("user_error(): error message file not found.\n\
  375. Bad installation.");
  376.   force_setvar("wims_user_error",msg);
  377.   if(strcmp(msg,"threshold")!=0) user_error_log(msg);
  378.   memmove(module_prefix,".",2);
  379.   if(lastout_file!=-1 && outputing) {
  380.     flushoutput(); close(lastout_file); lastout_file=-1;
  381.   }
  382.   nph_header(450);
  383.   phtml_put_base(erfname,0);
  384.   if(strcmp(msg,"double_click")!=0) delete_pid();
  385.   else {
  386.     cleantmpdir(); flushlog();
  387.   }
  388.   flushoutput(); exit(0);
  389. }
  390.  
  391. void module_error_log(char msg[]);
  392.  
  393. /* Messages for module errors. English only.
  394.  * This is really rudimentary for the time being.
  395.  */
  396. void module_error(char msg[])
  397. {
  398.   int send=0;
  399.   char *p;
  400.   WORKING_FILE mf;
  401.  
  402.   if(error_status) nested_error(msg);
  403.   error_status=1; untrust=0;
  404.   module_error_log(msg);
  405.   nph_header(550);
  406.   printf("Server: %s %s (%s)\r\n", SHORTSWNAME,wims_version,LONGSWNAME);
  407.   p=getvar("wims_main_font");
  408.   if(p!=NULL && *p!=0) printf("Content-type: text/plain; charset=%s\r\n\r\n",p);
  409.   else printf("Content-type: text/plain\r\n\r\n");
  410.   p=getvar(ro_name[ro_module]); if(p==NULL) p="???";
  411.   printf("ERROR.\n\nwims has detected an error in the module '%s'.",p);
  412.   if(m_file.l>=0) printf("\n\nIn file '%s', line %d:", m_file.name,m_file.l+1);
  413.   printf(" %s.\n\n",msg);
  414.   if(open_working_file(&mf,mkfname(NULL,"%s.%s",module_error_msg_file,lang))!=0)
  415.     internal_error("module_error(): error message file not found.");
  416.   while(wgetline(tmplbuf,MAX_LINELEN,&mf)!=EOF) {
  417.     if(tmplbuf[0]!=tag_prefix_char) {
  418.       if(send) {substit(tmplbuf); puts(tmplbuf);}
  419.       continue;
  420.     }
  421.     strip_trailing_spaces(tmplbuf);
  422.     if(tmplbuf[1]==0 || strcmp(msg,tmplbuf+1)==0) send=1;
  423.     else send=0;
  424.   }
  425.   close_working_file(&mf,0);
  426.   outptr=outbuf; delete_pid(); exit(1);
  427. }
  428.  
  429. /* Output kernel routine */
  430. void _output_(char *s)
  431. {
  432.   int l,l2;
  433.   l=strlen(s); output_length+=l;
  434.   if(output_length>=OUTPUT_LENGTH_LIMIT) {
  435.     module_error("output_too_long"); return;
  436.   }
  437.   l2=sizeof(outbuf)-(outptr-outbuf);
  438.   put: if(l<=l2) {
  439.     memmove(outptr,s,l); outptr+=l; return;
  440.   }
  441.   memmove(outptr,s,l2); s+=l2; l-=l2;
  442.   if(lastout_file!=-1) (void)write(lastout_file,outbuf,sizeof(outbuf));
  443.   else fwrite(outbuf,sizeof(outbuf),1,stdout);
  444.   outptr=outbuf; l2=sizeof(outbuf); goto put;
  445. }
  446.  
  447. /* Output with no var. */
  448. void output0(char buf[])
  449. {
  450.   char *p1, *p2, *ps;
  451.   int dynsave;
  452.   if(backslash_insmath) {
  453.     ps=buf; dynsave=instex_usedynamic;
  454.     for(p1=strstr(buf,"\\("); p1; p1=strstr(p2,"\\(")) {
  455.       p2=find_matching(p1+2,')');
  456.       if(p2==NULL) break;
  457.       if(p1>buf && *(p1-1)=='\\') continue;
  458.       *p1=0; if(*(p2-1)=='\\') *(p2-1)=0; *p2++=0; _output_(ps); ps=p2;
  459.       instex_usedynamic=1; insmath(p1+2);
  460.     }
  461.     if(*ps) _output_(ps);
  462.     instex_usedynamic=dynsave;
  463.   }
  464.   else _output_(buf);
  465. }
  466.  
  467. /* Output routine */
  468. void output(char *s,...)
  469. {
  470.   va_list vp;
  471.   char buf[4*MAX_LINELEN+1];
  472.  
  473.   va_start(vp,s);
  474.   vsnprintf(buf,sizeof(buf),s,vp);
  475.   va_end(vp);
  476.   output0(buf);
  477. }
  478.  
  479. /* read in tmpf in tmp directory, and places in p.
  480.  * Maximal length: MAX_LINELEN.
  481.  */
  482. void read_tmp_file(char *p, const char *fname)
  483. {
  484.   char *name, *pp;
  485.   name=mkfname(NULL,"%s/%s",tmp_dir,fname);
  486.   if(!exec_is_module || !outputing || !direct_exec
  487.      || strcmp(fname,"exec.out")!=0) {
  488.     readfile(name,p,MAX_LINELEN);
  489.     pp=getvar("wims_exec_dollar_double");
  490.     if(pp && strcmp(pp,"yes")==0) {
  491.       for(pp=strchr(p,'$'); pp; pp=strchr(pp+2,'$'))
  492.         string_modify(p,pp,pp+1,"$$");
  493.     }
  494.   }
  495.   else {
  496.     char *s;
  497.     s=readfile(name,NULL,OUTPUT_LENGTH_LIMIT);
  498.     if(s==NULL) {*p=0; return;}
  499.     if(memcmp(s,"Error: ", strlen("Error: "))==0) mystrncpy(p,s,MAX_LINELEN);
  500.     output_length+=strlen(s);
  501.     if(output_length>=OUTPUT_LENGTH_LIMIT) module_error("output_too_long");
  502.     else _output_(s);
  503.     free(s); *p=0;
  504.     chmod(name,S_IRUSR|S_IWUSR);
  505.   }
  506. }
  507.  
  508. /* verify whether the module is trusted.
  509.  * Returns 1 if yes, 0 if no. -1 for error.
  510.  */
  511. int trusted_module(void)
  512. {
  513.   char *modname, *w, buf[MAX_LINELEN+1];
  514.   int i,n;
  515.   static int _trusted=-1;      /* avoid repeated computations */
  516.  
  517.   if(untrust&255) return 0;
  518.   if(_trusted>=0) return _trusted;
  519.   modname=getvar(ro_name[ro_module]);
  520.   if(modname==NULL || *modname==0) return 0;
  521.   if(memcmp(modname,"adm/",strlen("adm/"))==0 ||
  522.      memcmp(modname,"classes/",strlen("classes/"))==0 ||
  523.      strcmp(modname,home_module)==0 ||
  524.      memcmp(modname,"help/",strlen("help/"))==0) {
  525.     tr:
  526.     if(memcmp(modname,"classes/",strlen("classes/"))==0)
  527.       is_class_module=1;
  528.     setenv("trusted_module","yes",1);
  529.     return _trusted=1;
  530.   }
  531.   n=wordnum(trusted_modules);
  532.   for(i=0;i<n;i++) {
  533.     w=fnd_word(trusted_modules,i+1,buf);
  534.     if(strcmp(w,modname)==0) goto tr;
  535.   }
  536.   return _trusted=0;
  537. }
  538.  
  539. /* file should be in the module directory, but
  540.  * it may also be somewhere else.
  541.  * buf[] requires MAX_FNAME+1 length.
  542.  * Returns 0 if found.
  543.  */
  544. int find_module_file(char *fname, char buf[], int mode)
  545. {
  546.   char *p, dtest[32];
  547.  
  548.   fname=find_word_start(fname);
  549.   if(*fname==0) return -1;
  550. /* Name checking: no directory backtracing. */
  551.   if(strstr(fname,parent_dir_string)!=NULL) {
  552.     setvar(error_data_string,fname); module_error("illegal_fname");
  553.     return -1;
  554.   }
  555.   p=strchr(fname,'/'); if(p==NULL || p>fname+10) goto openit;
  556.   memmove(dtest,fname,p-fname); dtest[p-fname]=0;
  557.   if(strcmp(dtest,"datamodule")==0) {
  558.     mkfname(buf,"modules/data%s",p); goto lastopen;
  559.   }
  560.   if(strcmp(dtest,"wimshome")==0 && trusted_module()) {
  561.     mkfname(buf,"%s%s",getvar("wims_home"),p); goto lastopen;
  562.   }
  563.   if(strcmp(dtest,"writable")==0) {
  564.     if(strncmp(p+1,"TEMP_",5)==0 && strchr(p+1,'/')==NULL) {
  565.       mkfname(buf,"%s/%s",tmp_dir,p+1);
  566.     }
  567.     else {
  568.       mkfname(buf,"w/%s/%s",module_prefix,p+1);
  569.     }
  570.     untrust|=4;
  571.   }
  572.   else {
  573.     openit: mkfname(buf,"%s/%s",module_prefix,fname);
  574.   }
  575.   if(mode) return 0;
  576.   if(ftest(buf)!=is_file) {
  577.     if(lastftype==is_exec) {
  578. isexec:
  579.       setvar("executable",fname); module_error("executable");
  580.       return -1;
  581.     }
  582.     if(strncmp(fname,"adm/",4)==0 &&
  583.        (!trusted_module() || is_class_module)) return -1;
  584.       mkfname(buf,"scripts/%s",fname);
  585.     lastopen:
  586.     if(mode) return 0;
  587.     if(ftest(buf)!=is_file) {
  588.       if(lastftype==is_exec) goto isexec;
  589.       else return -1;
  590.     }
  591.   }
  592.   return 0;
  593. }
  594.  
  595. /* check whether a file is user-submitted
  596.  * This is deprecated because of the wimshome/ method.
  597.  */
  598. /* int user_file(char *name) {
  599.     if(name[0]=='/' || name[0]=='.' ||
  600.        strstr(name,"classes/")!=NULL ||
  601.        strstr(name,"forums/")!=NULL ||
  602.        strstr(name,"sessions/")!=NULL ||
  603.        strstr(name,"doc/")!=NULL) return 1; else return 0;
  604. }
  605.  */
  606.  
  607. /* returns 1 if violation */
  608. int datafile_check(char *name) {
  609.   if((untrust&255)==0) return 0;
  610.   if(strncmp(name,"data/",strlen("data/"))==0) return 0;
  611.   if(strncmp(name,"authors/",strlen("authors/"))==0) return 0;
  612.   if(strncmp(name,"datamodule/",strlen("datamodule/"))==0) return 0;
  613.   return 1;
  614. }
  615.  
  616. /* returns 0 if success */
  617. void readdatafile(char *name)
  618. {
  619.   char *pp;
  620.   if(strcmp(name,lastdatafile)==0) return;
  621.   lastdata[0]=0; readfile(name,lastdata,WORKFILE_LIMIT);
  622.   mystrncpy(lastdatafile,name,sizeof(lastdatafile));
  623.   datacache[0]=lastdata; nextdatacache=1;
  624.   if(lastdata[0]==tag_string[1]) {
  625.     datacache[1]=lastdata; nextdatacache++;
  626.   }
  627.   pp=strstr(lastdata,tag_string);
  628.   if(pp) datacache[nextdatacache]=pp;
  629.   else datacache[nextdatacache]=lastdata+strlen(lastdata);
  630. }
  631.  
  632. char *_nextdata(char *p)
  633. {
  634.   char *pp;
  635.   if(!*p) return p;
  636.   pp=strstr(p,tag_string);
  637.   if(pp) return pp;
  638.   else return p+strlen(p);
  639. }
  640.  
  641. /* datafile structure: number of records.
  642.  * tag=1 if direct access
  643.  */
  644. unsigned int datafile_recordnum(char *p)
  645. {
  646.   char nbuf[MAX_LINELEN+1], *pp;
  647.   int i, t, ret;
  648.  
  649.   t=untrust; ret=0;
  650.   if(direct_datafile) mystrncpy(nbuf,p,sizeof(nbuf));
  651.   else if(datafile_check(p)!=0 || find_module_file(p,nbuf,0)) goto ret;
  652.   readdatafile(nbuf);
  653.   for(i=nextdatacache, pp=datacache[i]; *pp;) {
  654.     pp=_nextdata(pp+1); i++;
  655.     if(i<DATAFIELD_LIMIT) {
  656.       datacache[i]=pp; nextdatacache=i;
  657.     }
  658.   }
  659.   ret=i-1;
  660.   ret:
  661.   untrust=t;
  662.   return ret;
  663. }
  664.  
  665. /* datafile structure: find record n, starting from 1 */
  666. char *datafile_fnd_record(char *p, int n, char bf[])
  667. {
  668.   char nbuf[MAX_LINELEN+1], *pp, *p2;
  669.   int i, t;
  670.  
  671.   bf[0]=0; t=untrust;
  672.   if(n<0) goto ret;
  673.   if(direct_datafile) mystrncpy(nbuf,p,sizeof(nbuf));
  674.   else if(datafile_check(p)!=0 || find_module_file(p,nbuf,0)) goto ret;
  675.   readdatafile(nbuf); if(*lastdata==0) goto ret;
  676.   if(n>nextdatacache) {
  677.     for(i=nextdatacache, pp=datacache[i]; i<n && *pp;) {
  678.       pp=_nextdata(pp+1); i++;
  679.       if(i<DATAFIELD_LIMIT) {
  680.         datacache[i]=pp; nextdatacache=i;
  681.       }
  682.     }
  683.   }
  684.   else pp=datacache[n];
  685.   if(!*pp) goto ret;
  686.   if(n>1 || (n==1 && *pp!=tag_string[1])) pp+=strlen(tag_string);
  687.   else if(n==1) pp+=strlen(tag_string)-1;
  688.   if(n<nextdatacache) p2=datacache[n+1];
  689.   else {
  690.     p2=strstr(pp,tag_string); if(p2==NULL) p2=pp+strlen(pp);
  691.     if(n<DATAFIELD_LIMIT-1 && n==nextdatacache) {
  692.           nextdatacache++; datacache[nextdatacache]=p2;
  693.     }
  694.   }
  695.   if(p2-pp>=MAX_LINELEN) p2=pp+MAX_LINELEN-1;
  696.   if(p2<pp) p2=pp;
  697.   memmove(bf,pp,p2-pp); bf[p2-pp]=0;
  698.   ret:
  699.   untrust=t; return bf;
  700. }
  701.  
  702. char hex2char(char c1, char c2)
  703. {
  704.   char tbuf[16];
  705.   if(c1<'0' || c1>'f' || c2<'0' || c2>'f') {
  706. invl:
  707.     snprintf(tbuf,sizeof(tbuf),"%%%c%c",c1,c2);
  708.     setvar(error_data_string,tbuf);
  709.     user_error("invalid_char_in_query_string");
  710.   }
  711.   c1=toupper(c1);c2=toupper(c2);
  712.   if(c1>'9' && c1<'A') goto invl;
  713.   if(c2>'9' && c2<'A') goto invl;
  714.   if(c1>'F' || c2>'F') goto invl;
  715.   if(c1>='A') c1=c1-'A'+'9'+1;
  716.   if(c2>='A') c2=c2-'A'+'9'+1;
  717.   return (c1-'0')*16+c2-'0';
  718. }
  719.  
  720. /* Converts back http escaped chars, slight. Does not check buffer length.
  721.  * Returns converted string length.
  722.  */
  723. int _http2env(char outs[], char ins[])
  724. {
  725.   int j,k,l;
  726.   l=strlen(ins);
  727.   for(j=k=0;j<l && !isspace(ins[j]);j++,k++) {
  728.     if(isspace(ins[j])) {  /* skip space characters in query string */
  729.       k--;continue;
  730.     }
  731.     if(ins[j]=='%') {
  732. /* skip Carriage-Return. */
  733.         if(ins[j+1]=='0' && (ins[j+2]=='d' || ins[j+2]=='D')) {
  734.           j+=2; k--; continue;
  735.         }
  736.         outs[k]=hex2char(ins[j+1],ins[j+2]);
  737.         j+=2; continue;
  738.     }
  739.     outs[k]=ins[j];
  740.   }
  741.   outs[k]=0;
  742.   return k;
  743. }
  744.  
  745. /* Converts back http escaped chars. Does not check buffer length.
  746.  * Returns converted string length.
  747.  */
  748. int http2env(char outs[], char ins[])
  749. {
  750.   int j,k,l;
  751.   l=strlen(ins);
  752.   for(j=k=0;j<l && !isspace(ins[j]);j++,k++) {
  753.     if(isspace(ins[j])) {  /* skip space characters in query string */
  754.       k--;continue;
  755.     }
  756.     if(ins[j]=='%') {
  757. /* skip Carriage-Return. */
  758.       if(ins[j+1]=='0' && (ins[j+2]=='d' || ins[j+2]=='D')) {
  759.         j+=2; k--; continue;
  760.       }
  761.       outs[k]=hex2char(ins[j+1],ins[j+2]);
  762.       j+=2; continue;
  763.     }
  764.     if(ins[j]=='+') {
  765.       outs[k]=' '; continue;
  766.     }
  767.     if(ins[j]=='?' || ins[j]=='&') {
  768.       outs[k]=0; continue;
  769.     }
  770.     outs[k]=ins[j];
  771.   }
  772.   outs[k]=0;
  773.   return k;
  774. }
  775.  
  776. /* translate a string to http querystring style.
  777.  * '&' is not translated.
  778.  * Buffer p must be at least MAX_LINELEN.
  779.  */
  780. void tohttpquery(char *p)
  781. {
  782.   char trlist[]="       ()[]{}+-*^|/\"\'!:;,<>\n";
  783.   char *pp;
  784.   for(pp=p;*pp;pp++) {
  785.     if(*pp==' ') {
  786.       *pp='+'; continue;
  787.     }
  788.     if(strchr(trlist,*pp)==NULL) continue;
  789.     if(*pp=='+' && pp>p && *(pp-1)=='&') continue;
  790.     if(pp>p && *(pp-1)=='\\') {
  791.       ovlstrcpy(pp-1,pp);pp--;continue;
  792.     }
  793.     if(*pp=='\n') {
  794.       string_modify(p,pp,pp+1,"%%0D%%0A");pp+=5;
  795.     }
  796.     else {
  797.         string_modify(p,pp,pp+1,"%%%02X",*pp);pp+=2;
  798.     }
  799.   }
  800. }
  801.  
  802. /* substitute backslash parameters. Internal use only.
  803. replace in expression all \var by value of m_var variable
  804. if m_var not defined do nothing
  805. principally used in primitive script and insmath.c*/
  806. void slashsubst(char *p)
  807. {
  808.   char *p1, *p2, *pt, *pp, namebuf[128];
  809.   int n;
  810.  
  811.   n=strlen(mathfont_prefix); memmove(namebuf,mathfont_prefix,n+1);
  812.   for(p1=strchr(p,'\\'); p1!=NULL; p1=strchr(p1,'\\')) {
  813.     p1++; for(p2=p1; myisalnum(*p2) || *p2=='_'; p2++);
  814.     if(p2<=p1 || p2>p1+100) continue;
  815.     memmove(namebuf+n,p1,p2-p1); namebuf[p2-p1+n]=0;
  816.     pt=_getvar(namebuf); if(pt==NULL) continue;
  817.     if(*p2=='[' && (pp=find_matching(p2+1,']'))!=NULL) {
  818.       string_modify(p,pp+1,pp+1,")");
  819.       string_modify(p,p1-1,p1,"$(%s",mathfont_prefix);
  820.     }
  821.     else string_modify(p,p1-1,p1,"$%s",mathfont_prefix);
  822.   }
  823. }
  824.  
  825. /* two alarm handlers. */
  826. void alarm1(int s)
  827. {
  828.   if(killpid>0 && kill(killpid,SIGKILL)) module_error("timeup");
  829.   killpid=0;
  830. }
  831.  
  832. void alarm2(int s)
  833. {
  834.   cleantmpdir();
  835.   alarm1(s); module_error("timeup");
  836. }
  837.  
  838. void finalalarm(void)
  839. {
  840.   time_t curr;
  841.   curr=time(0);
  842.   if(curr>=limtime) alarm2(SIGALRM);
  843.   errno=0;
  844.   if(signal(SIGALRM,alarm2)==SIG_ERR)
  845.     internal_error(strerror(errno));
  846.   alarm(limtime-curr+1);
  847. }
  848.  
  849. void initalarm(void)
  850. {
  851.   limtimex=nowtime+4*rlimit_cpu/3;
  852.   limtime=limtimex+2; finalalarm();
  853. }
  854.  
  855. void forkalarm(void)
  856. {
  857.   time_t curr;
  858.   curr=time(0);
  859.   if(curr>=limtimex) {alarm1(SIGALRM); return;}
  860.   if(signal(SIGALRM,alarm1)==SIG_ERR)
  861.     internal_error(strerror(errno));
  862.   alarm(limtimex-curr+1);
  863. }
  864.  
  865. /* create pid tag */
  866. void create_pid(void)
  867. {
  868.   char buf[MAX_FNAME+1], pbuf[256], obuf[MAX_FNAME+1];
  869.   struct stat dst;
  870.   struct utimbuf ub;
  871.  
  872.   if(robot_access || *session_prefix==0) return;
  873.   if(cmd_type==cmd_getframe) return;
  874.   mkfname(buf,"%s/.pid",s2_prefix);
  875. /* another process running? */
  876.   if(readfile(buf,pbuf,sizeof(pbuf))!=NULL) {
  877.     mkfname(obuf,"/proc/%s",pbuf);
  878.     if(stat(obuf,&dst)==0) user_error("double_click");
  879.   }
  880.   snprintf(pidbuf,sizeof(pidbuf),"%u",getpid());
  881.   accessfile(pidbuf,"w","%s",buf);
  882. /* Touch session time */
  883.   if(strstr(session_prefix,"sessions/")==NULL) return;
  884.   ub.actime=ub.modtime=nowtime;
  885.   utime(session_prefix,&ub);
  886.   if(strchr(session_prefix,'_')!=NULL) { /* touch parent too */
  887.     char sbuf[MAX_FNAME+1], *p;
  888.     mystrncpy(sbuf,session_prefix,sizeof(sbuf));
  889.     p=strchr(sbuf,'_'); if(p!=NULL) *p=0;
  890.     utime(sbuf,&ub);
  891.   }
  892. }
  893.  
  894. struct mxtab mxtab[MAX_MULTIEXEC];
  895. int mxno=0;
  896.  
  897. int execredirected(char *cmdf, char *inf, char *outf, char *errf, char *arg[])
  898. {
  899.   pid_t pid;
  900.   int status, t;
  901.  
  902.   if(robot_access) return 0;
  903.   if(time(0)>=limtimex) {
  904.     if(errf!=NULL)
  905.       accessfile("No time left to execute subprograms.\n","w","%s",errf);
  906.     return -100;
  907.   }
  908.   lastdatafile[0]=lastftest[0]=0;
  909.   fflush(NULL); /* flush all output streams before forking
  910.                  * otherwise they will be doubled
  911.                  */
  912.   pid=fork(); if(pid==-1) return -1;
  913.   if(!pid) {      /* child */
  914.     char buf[MAX_LINELEN+1]; int k;
  915.     (void)nice(10);      /* lower priority for children */
  916.     if(is_multiexec) {
  917.       dup2(mxtab[multiexec_index].pipe_stdin[0],0);
  918.       dup2(mxtab[multiexec_index].pipe_stdout[1],1);
  919.       dup2(mxtab[multiexec_index].pipe_stderr[1],2);
  920.     }
  921.     else {
  922.       if(inf!=NULL) (void)freopen(inf,"r",stdin);
  923.       if(outf!=NULL) (void)freopen(outf,"w",stdout);
  924.       if(errf!=NULL) (void)freopen(errf,"w",stderr);
  925.     }
  926. /* This is to patch LinuxPPC uid wrapping
  927.  * for scripts */
  928.     t=0; if(strchr(cmdf,'/')) {
  929.       int tf;
  930.       char tbuf[16];
  931.       tf=open(cmdf,O_RDONLY); (void)read(tf,tbuf,8); close(tf);
  932.       if(memcmp(tbuf+1,"ELF",3)!=0) t=1;
  933.     }
  934.     if(wrapexec==-1) {
  935.       setreuid(getuid(),getuid());setregid(getgid(),getgid());
  936.     }
  937.     if(wrapexec==1 || (t==1 && wrapexec==0)) {
  938.       setreuid(geteuid(),geteuid());setregid(getegid(),getegid());
  939.     }
  940.     errno=0;
  941.     if(strchr(cmdf,'/')) execve(cmdf,arg,environ);
  942.     else execvp(cmdf,arg);
  943.     snprintf(buf,sizeof(buf),"Failed to execute");
  944.     for(k=0;arg[k];k++) {
  945.       t=strlen(buf);
  946.       snprintf(buf+t,sizeof(buf)-t," %s",arg[k]);
  947.     }
  948.     t=strlen(buf);
  949.     snprintf(buf+t,sizeof(buf)-t,"\n    %s\n",strerror(errno));
  950.     accessfile(buf,"a","%s/exec.fail",tmp_dir);
  951.     exit(127);
  952.   }
  953.   else {      /* parent */
  954.     wrapexec=0; status=0;
  955.     if(exec_wait && !is_multiexec) {
  956.       killpid=pid; forkalarm();
  957.       waitpid(pid,&status,0); killpid=0; finalalarm();
  958.     }
  959.     return WEXITSTATUS(status);
  960.   }
  961. }
  962.  
  963. /* preparation for resident execution.
  964.  * Returns 1 if already up, otherwise 0.
  965.  */
  966. int multiexec(char *cmd, char **abuf)
  967. {
  968.   char *p;
  969.   int i;
  970.  
  971.   if(robot_access) return 0;
  972.   if(strstr(tmp_dir,"sessions/")==NULL) return 0;
  973.   if(strstr(tmp_debug,"yes")!=NULL && checkhost(manager_site)>=1)
  974.     setenv("multiexec_debug","yes",1);
  975.   p=getvar("wims_multiexec");
  976.   if(p==NULL || wordchr(p,cmd)==NULL) return 0; /* not allowed */
  977.   if(!multiexec_random[0]) {
  978.     snprintf(multiexec_random, sizeof(multiexec_random),
  979.            "%lX%lX%lX%lX%lX%lX%lX%lX",
  980.            random(),random(),random(),random(),
  981.            random(),random(),random(),random());
  982.     setenv("multiexec_random",multiexec_random,1);
  983.   }
  984.   for(i=0;i<mxno && strcmp(cmd,mxtab[i].cmd)!=0; i++);
  985.   multiexec_index=i;
  986.   if(i==mxno) {
  987.     if(mxno>=MAX_MULTIEXEC) return 0;
  988.     if(pipe(mxtab[i].pipe_stdin)<0) return 0;
  989.     if(pipe(mxtab[i].pipe_stdout)<0) return 0;
  990.     if(pipe(mxtab[i].pipe_stderr)<0) return 0;
  991.     mystrncpy(mxtab[i].cmd,cmd,sizeof(mxtab[i].cmd));
  992.     mxno++;      is_multiexec=1;
  993.     exportall(); setenv("wims_exec_parm",multiexec_random,1);
  994.     execredirected(abuf[0],NULL,NULL,NULL,abuf);
  995.   }
  996.   is_multiexec=0;
  997.   return 1;
  998. }
  999.  
  1000. /* my system(), but with variable parms
  1001.  * More secure than system(), and direct fork.
  1002.  */
  1003. int call_ssh(char *s,...)
  1004. {
  1005.   va_list vp;
  1006.   char buf[MAX_LINELEN+1];
  1007.   char *arg[1024];
  1008.   char *inf=NULL, *outf=NULL, *errf=NULL;
  1009.   char *cmdf, *p, *p2;
  1010.   int i, d;
  1011.  
  1012.   if(robot_access) return 0;
  1013.   va_start(vp,s);
  1014.   vsnprintf(buf,sizeof(buf),s,vp);
  1015.   va_end(vp);
  1016.   p=find_word_start(buf); if(*p==0) return 0;
  1017.   cmdf=p;
  1018.   for(i=0;*p!=0 && i<1000; p=find_word_start(p2)) {
  1019.     switch(*p) {
  1020.       case '\'': {
  1021.         p++; p2=strchr(p,'\''); if(p2==NULL) p2=p+strlen(p);
  1022.         d=0; break;
  1023.       }
  1024.       case '"': {
  1025.         p++; p2=strchr(p,'"'); if(p2==NULL) p2=p+strlen(p);
  1026.         d=0; break;
  1027.       }
  1028.       default: d=1; p2=find_word_end(p); break;
  1029.     }
  1030.     if(*p2) *p2++=0;
  1031.     if(!d) {arg[i++]=p; continue;}
  1032.     switch(*p) {
  1033.       case '<': inf=++p; break;
  1034.       case '>': {
  1035.         p++;
  1036.         if(*p=='&') {
  1037.           merge: p++; errf=outf=p; break;
  1038.         }
  1039.         else outf=p;
  1040.         break;
  1041.       }
  1042.       case '&': {
  1043.         p++;
  1044.         if(*p=='>') goto merge;
  1045.         else break;
  1046.       }
  1047.       case '2': {
  1048.         if(*(p+1)=='>') {errf=p+2; break;}
  1049.       }
  1050.       default: arg[i++]=p; break;
  1051.     }
  1052.   }
  1053.   arg[i]=NULL;
  1054.   return execredirected(cmdf,inf,outf,errf,arg);
  1055. }
  1056.  
  1057. /* Read/write to a file with variable parms to print filename */
  1058. void accessfile(char *content, char *type, char *s,...)
  1059. {
  1060.   va_list vp;
  1061.   char buf[MAX_FNAME+1];
  1062.   int fd;
  1063.  
  1064.   if(robot_access) return;
  1065.   va_start(vp,s);
  1066.   vsnprintf(buf,sizeof(buf),s,vp);
  1067.   va_end(vp);
  1068.   if(strlen(buf)>=MAX_FNAME-1) nametoolong(buf);
  1069.   switch(*type) {
  1070.     case 'r': readfile(buf,content,MAX_LINELEN); return;
  1071.     case 'e': readfile(buf,content,MAX_LINELEN/4); return; /* limited read */
  1072.     case 'w': fd=creat(buf,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); break;
  1073.     case 'a': fd=open(buf,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); break;
  1074.     default : return;
  1075.   }
  1076.   lastdatafile[0]=lastftest[0]=0;
  1077.   if(fd==-1) return;
  1078.   (void)write(fd,content,strlen(content)); close(fd);
  1079. }
  1080.  
  1081. /* system(), but with variable parms
  1082.  * Uses sh to execute command.
  1083.  */
  1084. int call_sh(char *s,...)
  1085. {
  1086.   va_list vp;
  1087.   char buf[MAX_LINELEN+1];
  1088.   char *abuf[8];
  1089.  
  1090.   if(robot_access) return 0;
  1091.   va_start(vp,s);
  1092.   vsnprintf(buf,sizeof(buf),s,vp);
  1093.   va_end(vp);
  1094.   abuf[0]="sh"; abuf[1]="-c"; abuf[2]=buf; abuf[3]=NULL;
  1095.   return execredirected(abuf[0],NULL,NULL,NULL,abuf);
  1096. }
  1097.  
  1098. void _getdef(char buf[], char *name, char value[])
  1099. {
  1100.   char *p1, *p2, *p3, *p4;
  1101.  
  1102.   if(*name==0) goto nothing;      /* this would create segfault. */
  1103.   for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) {
  1104.     p2=find_word_start(p1+strlen(name));
  1105.     if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue;
  1106.     p3=p1; while(p3>buf && *(p3-1)!='\n') p3--;
  1107.     p3=find_word_start(p3);
  1108.     if(p3<p1 && *p3!='!') continue;
  1109.     if(p3<p1) {
  1110.       p3++; p4=find_word_end(p3);
  1111.       if(find_word_start(p4)!=p1) continue;
  1112.       if(p4-p3!=3 || (strncmp(p3,"set",3)!=0 &&
  1113.            strncmp(p3,"let",3)!=0 &&
  1114.            strncmp(p3,"def",3)!=0)) {
  1115.         if(p4-p3!=6 || strncmp(p3,"define",6)!=0) continue;
  1116.       }
  1117.     }
  1118.     p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2);
  1119.     p2=find_word_start(p2);
  1120.     if(p2>p3) goto nothing;
  1121.     if(p3-p2>=MAX_LINELEN) user_error("cmd_output_too_long");
  1122.     memmove(value,p2,p3-p2); value[p3-p2]=0;
  1123.     strip_trailing_spaces(value); return;
  1124.   }
  1125. nothing:
  1126.   value[0]=0; return;
  1127. }
  1128.  
  1129. /* Get variable definition from a file.
  1130.  * Result stored in buffer value of length MAX_LINELEN.
  1131.  */
  1132. void getdef(char *fname, char *name, char value[])
  1133. {
  1134.   char buf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1], nbuf[MAX_NAMELEN+1];
  1135.   char *p1, *p2;
  1136.  
  1137.   value[0]=0; if(readfile(fname,buf,sizeof(buf)-16)==NULL) return;
  1138.   mystrncpy(value,name,MAX_LINELEN);
  1139.   for(p1=value; *p1; p1=p2) {
  1140.     while(*p1 && !myisalnum(*p1) && *p1!='_') p1++;
  1141.     if(*p1==0) break;
  1142.     for(p2=p1; myisalnum(*p2) || *p2=='_'; p2++);
  1143.     if(p2-p1>MAX_NAMELEN) continue;
  1144.     memmove(nbuf,p1,p2-p1); nbuf[p2-p1]=0;
  1145.     _getdef(buf,nbuf,tbuf);
  1146.     string_modify(value,p1,p2,"%s",tbuf);
  1147.     p2=p1+strlen(tbuf);
  1148.   }
  1149. }
  1150.  
  1151. int _setdef_changed;
  1152.  
  1153. void _setdef(char buf[], char *name, char *value)
  1154. {
  1155.   char *p1, *p2, *p3;
  1156.   int n;
  1157.  
  1158.   for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) {
  1159.     p2=find_word_start(p1+strlen(name));
  1160.     if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue;
  1161.     p3=p1; while(p3>buf && *(p3-1)==' ') p3--;
  1162.     if(p3>buf && *(p3-1)!='\n') continue;
  1163.     p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2);
  1164.     if(strlen(value)!=p3-p2 || strncmp(value,p2,p3-p2)!=0) {
  1165.       string_modify(buf,p2,p3,"%s",value);
  1166.       _setdef_changed++;
  1167.     }
  1168.     return;
  1169.   }
  1170.   n=strlen(buf);
  1171.   if(n>0 && buf[n-1]!='\n')
  1172.     snprintf(buf+n,MAX_LINELEN-n,"\n%s=%s\n",name,value);
  1173.   else
  1174.     snprintf(buf+n,MAX_LINELEN-n,"%s=%s\n",name,value);
  1175.   _setdef_changed++;
  1176. }
  1177.  
  1178. /* Set variable definition to a file. */
  1179. void setdef(char *fname, char *name)
  1180. {
  1181.   char buf[MAX_LINELEN+1];
  1182.   char *p1, *p2, *p3;
  1183.  
  1184.   _setdef_changed=0;
  1185.   if(strchr(name,'=')==NULL) return;
  1186.   for(p1=name;*p1;p1++) {
  1187.     if(isspace(*p1) && *p1!=' ' && *p1!='\n') *p1=' ';
  1188.     if(*p1==' ') {
  1189.       for(p2=p1+1; isspace(*p2) && *p2!='\n'; p2++);
  1190.       if(p2>p1+1) ovlstrcpy(p1+1,p2);
  1191.       p2=p1+1; if(*p2=='=' || *p2=='\n') ovlstrcpy(p1,p2);
  1192.     }
  1193.   }
  1194.   if(readfile(fname,buf,sizeof(buf))==NULL) buf[0]=0;
  1195.   for(p1=find_word_start(name); p1!=NULL; p1=p2) {
  1196.     p2=strchr(p1,'\n'); if(p2!=NULL) *p2++=0;
  1197.     p1=find_word_start(p1);
  1198.     p3=strchr(p1,'='); if(p3==NULL) continue;
  1199.     *p3++=0; p3=find_word_start(p3);
  1200.     _setdef(buf,p1,p3);
  1201.   }
  1202.   if(_setdef_changed) accessfile(buf,"w","%s",fname);
  1203. }
  1204.  
  1205. /* check whether connecting host is part of given list.
  1206.  * Returns 0 if no, 1 if yes.
  1207.  */
  1208. int checkhost(char *hlist)
  1209. {
  1210.   char buf[MAX_LINELEN+1];
  1211.   char lbuf[1024], hbuf1[256], hbuf2[256];
  1212.   char *p1, *p2, *pb, *pe, *pp;
  1213.  
  1214.   if(*remote_addr==0) return 0;
  1215.   snprintf(hbuf1,sizeof(hbuf1),"+%s+",remote_addr);
  1216.   if(*remote_host!=0) {
  1217.     snprintf(hbuf2,sizeof(hbuf2),"+%s+",remote_host);
  1218.     for(p1=hbuf2; *p1; p1++) *p1=tolower(*p1);
  1219.   }
  1220.   else hbuf2[0]=0;
  1221.   mystrncpy(buf,find_word_start(hlist),sizeof(buf)); strip_trailing_spaces(buf);
  1222.   for(p1=buf; *p1; p1++) {
  1223.     *p1=tolower(*p1);
  1224.     if(!myisalnum(*p1) && strchr(".-_",*p1)==NULL) *p1=' ';
  1225.   }
  1226.   if(strcmp(buf,"all")==0) return 1;      /* all is all */
  1227.   for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
  1228.     p2=find_word_end(p1); if(*p2) *p2++=0;
  1229.     if(p2-p1<3) continue;
  1230.     if(myisalnum(*p1)) pb="+"; else pb="";
  1231.     if(myisalnum(*(p2-1))) pe="+"; else pe="";
  1232.     snprintf(lbuf,sizeof(lbuf),"%s%s%s",pb,p1,pe);
  1233.     for(pp=p1; *pp && (myisdigit(*pp) || *pp=='.'); pp++);
  1234.     if(*pp) pp=hbuf2;      /* host name */
  1235.     else pp=hbuf1;         /* ip number */
  1236.     if(strstr(pp,lbuf)!=NULL) return 1;      /* found */
  1237.   }
  1238.   return 0;
  1239. }
  1240.  
  1241. /* return 1 if a word of bf2 is a substring of host
  1242.  * and if time constraints are verified
  1243.  * Like checkhost, but check first time then host.
  1244.  * The content of bf2[] is destroyed.
  1245.  * it is possible to put a joker in the times
  1246.  */
  1247. int checkhostt(char bf2[])
  1248. {
  1249.   char *p1, *p2, *p3;
  1250.   int i,maxremain=1;
  1251.   /* compare with starting time */
  1252.   for(p1=strchr(bf2,'>'); p1!=NULL; p1=strchr(p1+1,'>')) {
  1253.     if(p1>bf2 && !isspace(*(p1-1))) continue;
  1254.     p3=find_word_start(++p1); p2=find_word_end(p3);
  1255.     if(p2-p3!=14) continue;
  1256.     p3[8]='.'; p3[11]=':'; if(*p2) *p2++=0;
  1257.     for (i=0; i<14; i++) if(p3[i]=='*') p3[i]=nowstr[i];
  1258.     if(strncmp(nowstr,p3,14)<0) return 0;
  1259.     ovlstrcpy(p1-1,p2); p1-=2;
  1260.   }
  1261.   /* compare with ending time */
  1262.   for(p1=strchr(bf2,'<'); p1!=NULL; p1=strchr(p1+1,'<')) {
  1263.     if(p1>bf2 && !isspace(*(p1-1))) continue;
  1264.     p3=find_word_start(++p1); p2=find_word_end(p3);
  1265.     if(p2-p3!=14) continue;
  1266.     p3[8]='.'; p3[11]=':'; if(*p2) *p2++=0;
  1267.     for (i=0; i<14; i++) if(!isdigit(p3[i])) p3[i]=nowstr[i];
  1268.     if(strncmp(nowstr,p3,14)>0) return 0;
  1269. /* added to calculate max time in exam */
  1270.     if (isexam) {
  1271.        struct tm maxtime;
  1272.        char tmp[8];
  1273.        unsigned long time;
  1274.        snprintf(tmp,sizeof(tmp),"%c%c%c%c",p3[0],p3[1],p3[2],p3[3]);
  1275.        maxtime.tm_year=atoi(tmp)-1900;
  1276.        snprintf(tmp,sizeof(tmp),"%c%c",p3[4],p3[5]);
  1277.        maxtime.tm_mon=atoi(tmp)-1;
  1278.        snprintf(tmp,sizeof(tmp),"%c%c",p3[6],p3[7]);
  1279.        maxtime.tm_mday=atoi(tmp);
  1280.        snprintf(tmp,sizeof(tmp),"%c%c",p3[9],p3[10]);
  1281.        maxtime.tm_hour=atoi(tmp);
  1282.        snprintf(tmp,sizeof(tmp),"%c%c",p3[12],p3[13]);
  1283.        maxtime.tm_min=atoi(tmp);
  1284.        maxtime.tm_sec=0;
  1285.        maxtime.tm_isdst=-1;
  1286.        time=mktime(&maxtime);
  1287.        if (time<nowtime) maxremain=0; else maxremain=nowtime-time;
  1288.    }
  1289. /* end add */
  1290.     ovlstrcpy(p1-1,p2); p1-=2;
  1291.   }
  1292.   p1=find_word_start(bf2); if(*p1==0) return maxremain;
  1293.   if (checkhost(p1)) return maxremain; else return 0;
  1294. }
  1295.  
  1296. /* bad identification */
  1297. void bad_ident(void)
  1298. {
  1299.   if(cookiegot[0]!=0) {
  1300.   }
  1301.   user_error("bad_ident");
  1302. }
  1303.  
  1304. void instex_flush(void)
  1305. {
  1306.   char *p;
  1307.   setenv("texgif_style","",1);
  1308.   setenv("texgif_tmpdir",tmp_dir,1);
  1309.   setenv("texgif_src",instex_src,1);
  1310.   setenv("texgif_outfile",instex_fname,1);
  1311.   unsetenv("w_instex_color");
  1312.   getwimstexsize=0; fix_tex_size(); getwimstexsize=1;
  1313.   for(p=instex_fname;*p;p++) if(*p=='\n') *p=' ';
  1314.   wrapexec=0; call_ssh("%s/%s >%s/ins.Out 2>%s/ins.Err",
  1315.                  bin_dir,instex_processor,
  1316.                  tmp_dir,tmp_dir);
  1317.   call_ssh("mv %s %s >/dev/null 2>/dev/null", instex_fname,s2_prefix);
  1318.   instex_src[0]=instex_fname[0]=0; instex_cnt=0;
  1319. }
  1320.  
  1321. /* put last.phtml */
  1322. void putlastout(void)
  1323. {
  1324.   int t;
  1325.   if(instex_cnt>0) instex_flush();
  1326.   t=catfile(stdout,"%s/%s",s2_prefix,lastout);
  1327.   if(t==0) printf("Content-type: text/plain\r\n\r\n");
  1328. }
  1329.  
  1330. struct sockaddr_un sun;
  1331.  
  1332. /* returns >=0 if OK. */
  1333.  
  1334. int kerneld(char *p, int bufsize)
  1335. {
  1336.   int sock, s, t, t1, l, *ip;
  1337.   struct timeval tv;
  1338.   fd_set rset;
  1339.   sock=socket(PF_UNIX,SOCK_STREAM,0);
  1340.   s=connect(sock,(const struct sockaddr *)&sun,sizeof(sun));
  1341.   if(s) {bad: close(sock); return -1;}
  1342.   ip=(int *) p;
  1343.   l=strlen(p+sizeof(int)); *ip=l;
  1344.   s=write(sock,p,l+sizeof(int)); if(s!=l+sizeof(int)) goto bad;
  1345.   for(t=0, l=bufsize-1; t<l+sizeof(int);) {
  1346.     tv.tv_sec=2; tv.tv_usec=0;
  1347.     FD_ZERO(&rset); FD_SET(sock,&rset);
  1348.     if(select(sock+1,&rset,NULL,NULL,&tv)<=0) goto bad;
  1349.     t1=read(sock,p+t,l+sizeof(int)-t);
  1350.     if(t1+t<sizeof(int)) goto bad;
  1351.     if (t1 < 0) goto bad;
  1352.     l=*ip; if(l<=0) goto bad;
  1353.     if(l>=bufsize-sizeof(int)-4) user_error("cmd_output_too_long");
  1354.     t+=t1;
  1355.   }
  1356.   p[l+sizeof(int)]=0;
  1357.   close(sock);
  1358.   return l+sizeof(int);
  1359. }
  1360.  
  1361. void _daemoncmd(char *p)
  1362. {
  1363.   char buf[MAX_LINELEN+1+sizeof(int)];
  1364.   char *p1, *p2, *p3;
  1365.   mystrncpy(buf+sizeof(int),p,sizeof(buf)-sizeof(int));
  1366.   if(kerneld(buf,sizeof(buf))<0)
  1367.     internal_error("Daemon communication error.");
  1368.   p1=find_word_start(buf+sizeof(int));
  1369.   p2=find_word_end(p1); if(*p2) *p2++=0;
  1370.   if(strcmp(p1,"OK")==0) {
  1371.     mystrncpy(p,p2,MAX_LINELEN); return;
  1372.   }
  1373.   p1=find_word_start(p2); p2=find_word_end(p1); if(*p2) *p2++=0;
  1374.   p2=find_word_start(p2); p3=find_word_end(p2);
  1375.   if(*p3) {
  1376.     *p3++=0; p3=find_word_start(p3); strip_trailing_spaces(p3);
  1377.     setvar("wims_error_data",p3);
  1378.   }
  1379.   switch(*p1) {
  1380.     case '1': user_error(p2);
  1381.     case '2': module_error(p2);
  1382.     case '3':
  1383.     default: internal_error(p2);
  1384.   }
  1385.   *p=0;
  1386. }
  1387.