Subversion Repositories wimsdev

Rev

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