Logo Search packages:      
Sourcecode: wims version File versions  Download package

lines.c

/*    Copyright (C) 1998 XIAO, Gang of Universite de Nice - Sophia Antipolis
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
      /* line input / output / translation routines
       * and error routines */

int trusted_module(void);
void phtml_put_base(char *fname);
void module_error(char msg[]);
void accessfile(char *content, char *type, char *s,...);
int remove_tree(char *p);

  /* Limit for any data working files. */
int WORKFILE_LIMIT=256000;

  /* These modules can execute private programs.
   * adm/ modules are always trusted, so need no definition here. */
char *trusted_modules="";
int untrust=0;  /* non-zero if user detrusts the module. */

int error_status=0;
char pidbuf[256];

void delete_pid(void);

void internal_warn(char msg[])
{
    fprintf(stderr,"wims: %s\n%s\n",msg,strerror(errno));
    accessfile(msg,"a","%s/internal_error.log",log_dir);
}

  /* Internal error: panic and forget about requester. */
void internal_error(char msg[])
{
    if(error_status<2) {
      printf("Cache-Control: no-cache\nPragma: no-cache\n\
Status: 500 WIMS internal error\n\
Content-type: text/plain\n\n\n\
WIMS panick! %s\n%s\n",msg,strerror(errno));
      error_status=2; internal_warn(msg);
    }
    delete_pid(); exit(1);
}

void tex_nospace(char *p)
{
    char *p1, *p2;
    char buf[MAX_LINELEN+1];
    for(p1=buf,p2=p;*p2 && p1-buf<MAX_LINELEN-4;p2++) {
      if(!isspace(*p2)) {*p1++=*p2;continue;}
      while(isspace(*p2)) p2++;
      if(*(p1-1)=='\\' || 
         (p1>buf && isalnum(*(p1-1)) && isalnum(*p2)))
        *p1++=' ';
      *p1++=*p2;
    }
    *p1=0;
    strcpy(p,buf);
}

      /* Get a line in a stored working file. 
       * Buffer length is always MAX_LINELEN. */
int wgetline(char buf[], size_t buflen, WORKING_FILE *f)
{
    int i,j; unsigned int n;
    i=f->linepointer; buf[0]=0;
    if(i>=f->linecnt || f->textbuf==NULL) return EOF;
    n=f->lines[i].llen;
    if(n>=buflen) n=buflen-1;
    if(n>0) memmove(buf,f->lines[i].address,n); buf[n]=0;
    for(j=i+1;j<f->linecnt && f->lines[j].isstart==0;j++);
    f->l=i; f->linepointer=j;
    if(j>=f->linecnt && n==0) return EOF; else return n;
}

      /* Open a work file. Returns 0 if OK. */
int open_working_file(WORKING_FILE *f, char *fname)
{
    FILE *F;
    char *p;
    long fl;
    int i,j;
    struct stat st;

    f->linecnt=f->linepointer=f->for_idx=0;
    f->l=-1;
    f->textbuf=NULL; f->lines=NULL;
    if(stat(fname,&st)) return -1;
    if(S_ISDIR(st.st_mode)) return -1; /* subdirectory */
      /* refuse to open executable file */
    if((st.st_mode&S_IXUSR)!=0) {
      setenv("executable",fname,1); module_error("executable");
    }
    f->name[0]=0;
    F=fopen(fname,"r"); if(F==NULL) return -1;
    fseek(F,0,SEEK_END); fl=ftell(F); fseek(F,0,SEEK_SET);
    if(fl<0) return -1;
    if(fl>WORKFILE_LIMIT) module_error("workfile_too_long");
    f->textbuf=xmalloc(fl+16);
    if(fread(f->textbuf,1,fl,F)!=fl) {
      free(f->textbuf); f->textbuf=NULL; 
      fclose(F); return 1;
    }
    f->textbuf[fl]=0; fclose(F);
    _tolinux(f->textbuf);
    p=f->textbuf; if(*p) for(i=0; p!=NULL;i++,p=strchr(++p,'\n'));
    else i=0;
    if(f->textbuf[0]=='\n') i++;
    f->linecnt=i;
    f->lines=xmalloc((i+1)*sizeof(LINE_STRUCT));
    for(j=0,p=f->textbuf; p!=NULL && j<i;j++,p=strchr(p,'\n')) {
      if(j>0 && *p) p++;
      (f->lines[j]).execcode=(f->lines[j]).varcode=-1;
      if(p>=f->textbuf+2 && *(p-2)=='\\') {
          f->lines[j].isstart=0;
          *(p-2)='\n';strcpy(p-1,p);
          p--;fl--;
      }
      else {
          char *pt=p;
          if(j>0) *(p-1)=0;
          f->lines[j].isstart=1;
          while(isspace(*pt) && *pt!='\n') pt++;
          if(*pt==exec_prefix_char) f->lines[j].isstart|=2;
          if(*pt==label_prefix_char) f->lines[j].isstart|=4;
      }
      (f->lines[j]).address=p;
    }
    (f->lines[i]).address=(f->textbuf)+fl;
    (f->lines[i]).isstart=1;
    f->linepointer=0;
    for(i=0;i<f->linecnt;i++) {
      if(f->lines[i].isstart) f->lines[i].llen=strlen(f->lines[i].address);
      else f->lines[i].llen=0;
    }
    snprintf(f->name,sizeof(f->name),"%s",fname);
    return 0;
}

      /* close an earlier opened working file */
void close_working_file(WORKING_FILE *f)
{
    if(f->lines!=NULL) free(f->lines);
    if(f->textbuf!=NULL) free(f->textbuf);
    f->lines=NULL; f->textbuf=NULL;
    f->linecnt=f->l=f->linepointer=0;
}

      /* print a string, substituting environment variables
       * with their values.
       * Not working exactly as sh yet. */       
void print_with_substitution(char *str)
{
    char nbuf[MAX_NAMELEN+1];
    char *p=str, *env; int i;
    while(*p) {
      if(*p!='$' || (p>str && *(p-1)=='\\')) {
          putchar(*p); p++; continue;
      }
      p++;
      for(i=0;i<MAX_NAMELEN && (isalnum(*p) || *p=='_'); i++,p++) 
        nbuf[i]=*p;
      nbuf[i]=0;
      env=getenv(nbuf); if(env!=NULL) printf("%s",env);       
    }
}

void puts_with_substitution(char *str)
{
    print_with_substitution(str); putchar('\n');
}

void cleantmpdir(void);

void user_error_log(char msg[]);

      /* Send an error message to requester and exit.
       * This is for user errors, language-sensitive. */
void user_error(char msg[])
{
    FILE *msg_file;
    char linebuf[MAX_LINELEN+1];

    if(error_status) {delete_pid(); exit(1);}
    error_status=1;
    snprintf(linebuf,sizeof(linebuf),"%s.%s",user_error_msg_file,lang);
    msg_file=fopen(linebuf,"r");
    if(msg_file==NULL) internal_error("user_error(): error message file not found.\n\
Probably suid bit not set.");
    fclose(msg_file);
    setvar("wims_user_error",msg);
    if(strcmp(msg,"threshold")!=0)
      user_error_log(msg); 
    strcpy(module_prefix,"."); 
    if(lastout_file!=NULL && outputing) {
      fclose(lastout_file); lastout_file=NULL;
    }
    phtml_put_base(linebuf); 
    if(strcmp(msg,"double_click")!=0) delete_pid(); 
    else cleantmpdir();
    exit(0);
}

void module_error_log(char msg[]);

      /* Messages for module errors. English only. */
      /* This is really rudimentary for the time being. */
void module_error(char msg[])
{
    int send=0;
    char *s;
    WORKING_FILE mf;
    char linebuf[MAX_LINELEN+1];

    if(error_status) {delete_pid(); exit(1);}
    error_status=1; untrust=0;
    module_error_log(msg);
    s=getvar(ro_name[ro_module]);
    if(s==NULL) s="???";
    if(!outputing || lastout_file!=NULL) {
      char *p;
      printf("Server: %s %s (%s)\n", SHORTSWNAME,wims_version,LONGSWNAME);
      printf("Status: 550 WIMS Module Error\n");
      p=getvar("wims_main_font");
      if(p!=NULL && *p!=0) printf("Content-type: text/plain; charset=%s\n\n",p);
      else printf("Content-type: text/plain\n\n");
    }
    else printf("<!--><!\"></A></SELECT></TABLE></SCRIPT></FORM></P></CENTER></FONT></TITLE></UL></OL></DL><PRE>\n");
    printf("ERROR.\n\nwims has detected an error in the module '%s'.",s);
    if(m_file.l>=0)
      printf("\n\nIn file '%s', line %d:",
           m_file.name,m_file.l+1);
    printf(" %s.\n\n",msg);
    snprintf(linebuf,sizeof(linebuf),"%s.%s",module_error_msg_file,lang);
    if(open_working_file(&mf,linebuf)!=0)
      internal_error("module_error(): error message file not found.");
    while(wgetline(linebuf,MAX_LINELEN,&mf)!=EOF) {
      if(linebuf[0]!=tag_prefix_char) {
          if(send) puts_with_substitution(linebuf);
          continue;
      }
      strip_trailing_spaces(linebuf);
      if(linebuf[1]==0 || strcmp(msg,linebuf+1)==0) send=1;
      else send=0;
    }
    close_working_file(&mf);
    delete_pid(); exit(1);
}

int output_already=0;

      /* Output routine */
void output(char *s,...)
{
    va_list vp;
    char buf[4*MAX_LINELEN+1];

    va_start(vp,s);
    vsnprintf(buf,sizeof(buf),s,vp);
    va_end(vp);
    output_length+=strlen(buf);
    if(output_length>=OUTPUT_LENGTH_LIMIT) {
      module_error("output_too_long");
      return;
    }
    if(backslash_insmath && output_already==0
       && strstr(buf,"\\(")!=NULL) {
      char *p1, *p2, *ps;
      int dynsave;
      output_already=1; ps=buf; dynsave=instex_usedynamic;
      for(p1=strstr(buf,"\\("); p1; p1=strstr(p2,"\\(")) {
          p2=find_matching(p1+2,')');
          if(p2==NULL) break;
          if(p1>buf && *(p1-1)=='\\') continue;
          *p1=0; if(*(p2-1)=='\\') *(p2-1)=0; *p2++=0; output(ps); ps=p2;
          instex_usedynamic=1; insmath(p1+2);
      }
      if(*ps) output(ps); output_already=0; instex_usedynamic=dynsave;
    }
    else {
      if(lastout_file!=NULL) fprintf(lastout_file,"%s",buf);
      else printf("%s",buf);
    }
}

      /* read in tmpf in session directory, and places in p.
       * Maximal length: MAX_LINELEN. */
void read_tmp_file(char *p, const char *fname)
{
    FILE *tmpf;
    char namebuf[MAX_LINELEN+1];
    snprintf(namebuf,sizeof(namebuf),"%s/%s",session_prefix,fname);
    tmpf=fopen(namebuf,"r"); if(tmpf!=NULL) {
      if(!exec_is_module || !outputing || !direct_exec
         || strcmp(fname,"exec.out")!=0) {
          int i;
          i=fread(p,1,MAX_LINELEN,tmpf);
          if(i<0 || (i>=MAX_LINELEN && !exec_is_module))
            user_error("cmd_output_too_long");
          *(p+i)=0;
      }
      else {
          long int l;
          char *s;
          fseek(tmpf,0,SEEK_END); l=ftell(tmpf);
          fseek(tmpf,0,SEEK_SET);
          if(l==0) {
            *p=0; return;
          }
          if(l<0 || l>=OUTPUT_LENGTH_LIMIT) module_error("output_too_long");
          s=xmalloc(l+1);
          fread(s,1,l,tmpf); *(s+l)=0;
          if(memcmp(s,"Error: ", strlen("Error: "))==0) {
            snprintf(p,MAX_LINELEN,"%s",s);
          }
          else {
            if(lastout_file!=NULL) fprintf(lastout_file,"%s",s);
            else puts(s);
            free(s); *p=0;
          }
      }
      fclose(tmpf);
      /* remove(namebuf); */
    }
    else *p=0;
}

      /* verify whether the module is trusted.
       * Returns 1 if yes, 0 if no. -1 for error. */
int trusted_module(void)
{
    char *modname, *w, buf[MAX_LINELEN+1];
    int i,n;
    static int _trusted=-1;   /* avoid repeated computations */
    
    if(untrust) return 0;
    if(_trusted>=0) return _trusted;
    modname=getvar(ro_name[ro_module]);
    if(modname==NULL || *modname==0) return 0;
    if(memcmp(modname,"adm/",strlen("adm/"))==0 || 
       strcmp(modname,home_module)==0 ||
       memcmp(modname,"help/",strlen("help/"))==0 ||
       memcmp(modname,"local/",strlen("local/"))==0) {
      tr:
      setenv("trusted_module","yes",1);
      return _trusted=1;
    }
    n=wordnum(trusted_modules); for(i=0;i<n;i++) {
      w=fnd_word(trusted_modules,i+1,buf);
      if(strcmp(w,modname)==0) goto tr;
    }
    return _trusted=0;
}

      /* check whether a file is user-submitted */
int user_file(char *name) {
    if(strstr(name,"classes/")!=NULL || 
       strstr(name,"forums/")!=NULL ||
       strstr(name,"sessions/")!=NULL ||
       strstr(name,"doc/")!=NULL) return 1; else return 0;
}

      /* returns 1 if violation */
int datafile_check(char *p) {
    if((untrust&6)==0 ||
       strncmp(m_file.name,"primitives/",strlen("primitives/"))==0)
      return 0;
    if(user_file(p) || user_file(m_file.name)) return 1; else return 0;
}

      /* datafile structure: number of records.
       * tag=1 if direct access */
unsigned int datafile_recordnum(char *p)
{
    char nbuf[MAX_LINELEN+1], *fbuf, *pp;
    long int l;
    int i;
    FILE *f;

    if(direct_datafile) snprintf(nbuf,sizeof(nbuf),"%s",p);
    else {
      if(strstr(p,parent_dir_string)!=NULL || datafile_check(p)!=0) {
          setenv(error_data_string,p,1);
          module_error("illegal_fname"); return 0;
      }
      snprintf(nbuf,sizeof(nbuf),"%s/%s",module_prefix,p);
    }
    f=fopen(nbuf,"r"); if(f==NULL) return 0;
    fseek(f,0,SEEK_END); l=ftell(f); fseek(f,0,SEEK_SET);
    if(l<=0) {
      fclose(f); return 0;
    }
    fbuf=xmalloc(l+1);
    fread(fbuf,1,l,f); *(fbuf+l)=0;
    fclose(f); _tolinux(fbuf);
    if(fbuf[0]!=tag_string[1]) i=0; else i=1;
    for(pp=strstr(fbuf,tag_string); pp!=NULL; i++) {
      pp=strstr(pp+1,tag_string); 
    }
    free(fbuf); return i;
}

      /* datafile structure: find record n, starting from 1 */
char *datafile_fnd_record(char *p, int n, char bf[])
{
    char nbuf[MAX_LINELEN+1], *fbuf, *pp, *p2;
    long int l;
    int i;
    FILE *f;

    if(n<0) {
  abort:    
      bf[0]=0; return bf;
    }
    else n--;
    if(direct_datafile) snprintf(nbuf,sizeof(nbuf),"%s",p);
    else {
      if(strstr(p,parent_dir_string)!=NULL || datafile_check(p)!=0) {
          setenv(error_data_string,p,1);
          module_error("illegal_fname"); goto abort;
      }
      snprintf(nbuf,sizeof(nbuf),"%s/%s",module_prefix,p);
    }
    f=fopen(nbuf,"r"); if(f==NULL) goto abort;
    fseek(f,0,SEEK_END); l=ftell(f); fseek(f,0,SEEK_SET);
    if(l<=0) {
      fclose(f); goto abort;
    }
    fbuf=xmalloc(l+1);
    fread(fbuf,1,l,f); *(fbuf+l)=0;
    fclose(f); _tolinux(fbuf);
    if(fbuf[0]!=tag_string[1]) i=0; else i=1;
    if(i<n+1)
      for(pp=strstr(fbuf,tag_string); i<n && pp<fbuf+l && pp!=NULL; i++) {
        pp=strstr(pp+1,tag_string); 
      }
    else {
      if(i>n+1) goto abort;
      pp=fbuf-1;
    }
    if(pp==NULL) { /* n too big */
      free(fbuf); goto abort;
    }
    if(n>=0) pp+=strlen(tag_string); else pp=fbuf;
      /* No comment line is allowed within records. */
    p2=strstr(pp,tag_string); 
    if(p2!=NULL) *p2=0;
    snprintf(bf,MAX_LINELEN,"%s",pp);
    free(fbuf);
    return bf;
}

char hex2char(char c1, char c2)
{
    char tbuf[16];
    if(c1<'0' || c1>'f' || c2<'0' || c2>'f') {
invl:
      snprintf(tbuf,sizeof(tbuf),"%%%c%c",c1,c2);
      setenv(error_data_string,tbuf,1);
      user_error("invalid_char_in_query_string");
    }
    c1=toupper(c1);c2=toupper(c2);
    if(c1>'9' && c1<'A') goto invl;
    if(c2>'9' && c2<'A') goto invl;
    if(c1>'F' || c2>'F') goto invl;
    if(c1>='A') c1=c1-'A'+'9'+1;
    if(c2>='A') c2=c2-'A'+'9'+1;
    return (c1-'0')*16+c2-'0';
}

      /* Converts back http escaped chars, slight. Does not check buffer length.
       * Returns converted string length. */
int _http2env(char outs[], char ins[])
{
    int j,k,l;
    l=strlen(ins);
    for(j=k=0;j<l && !isspace(ins[j]);j++,k++) {
      if(isspace(ins[j])) {  /* skip space characters in query string */
          k--;continue;
      }
      if(ins[j]=='%') {
            /* skip Carriage-Return. */
          if(ins[j+1]=='0' && (ins[j+2]=='d' || ins[j+2]=='D')) {
            j+=2; k--; continue;
          }
          outs[k]=hex2char(ins[j+1],ins[j+2]);
          j+=2; continue;
      }
      outs[k]=ins[j];
    }
    outs[k]=0;    
    return k;
}

      /* Converts back http escaped chars. Does not check buffer length.
       * Returns converted string length. */
int http2env(char outs[], char ins[])
{
    int j,k,l;
    l=strlen(ins);
    for(j=k=0;j<l && !isspace(ins[j]);j++,k++) {
      if(isspace(ins[j])) {  /* skip space characters in query string */
          k--;continue;
      }
      if(ins[j]=='%') {
            /* skip Carriage-Return. */
          if(ins[j+1]=='0' && (ins[j+2]=='d' || ins[j+2]=='D')) {
            j+=2; k--; continue;
          }
          outs[k]=hex2char(ins[j+1],ins[j+2]);
          j+=2; continue;
      }
      if(ins[j]=='+') {
          outs[k]=' '; continue;
      }
      if(ins[j]=='?' || ins[j]=='&') {
          outs[k]=0; continue;
      }
      outs[k]=ins[j];
    }
    outs[k]=0;    
    return k;
}

      /* translate a string to http querystring style.
       * '&' is not translated.
       * Buffer p must be at least MAX_LINELEN. */
void tohttpquery(char *p)
{
    char trlist[]="     ()[]{}+-*^|/\"\'!:;,<>\n";
    char *pp;
    for(pp=p;*pp;pp++) {
      if(*pp==' ') {
          *pp='+'; continue;
      }
      if(strchr(trlist,*pp)==NULL) continue;
      if(*pp=='+' && pp>p && *(pp-1)=='&') continue;
      if(pp>p && *(pp-1)=='\\') {
          strcpy(pp-1,pp);pp--;continue;
      }
      if(*pp=='\n') {
          string_modify(p,pp,pp+1,"%%0D%%0A");pp+=5;
      }
      else {
          string_modify(p,pp,pp+1,"%%%02X",*pp);pp+=2;
      }
    }
}

      /* two alarm handlers. */
void alarm1(int s)
{
    if(killpid>0) kill(killpid,SIGKILL);
    killpid=0;
}

void alarm2(int s)
{
    alarm1(s); module_error("timeup");
}

void finalalarm(void)
{
    time_t curr;
    curr=time(0);
    if(curr>=limtime) alarm2(SIGALRM);
    signal(SIGALRM,alarm2);
    alarm(limtime-curr+1);
}

void initalarm(void)
{
    limtimex=nowtime+4*rlimit_cpu/3;
    limtime=limtimex+2; finalalarm();
}

void forkalarm(void)
{
    time_t curr;
    curr=time(0);
    if(curr>=limtimex) {alarm1(SIGALRM); return;}
    signal(SIGALRM,alarm1);
    alarm(limtimex-curr+1);
}

      /* create pid tag */
void create_pid(void)
{
    char buf[256], pbuf[256], obuf[256];
    int i, k, oldp, lim;
    struct stat dst;
    FILE *f;
    
    if(robot_access || *session_prefix==0) return;
    if(cmd_type==cmd_getframe) return;
    snprintf(buf,sizeof(buf),"%s/.pid",session_prefix);
    f=fopen(buf,"r"); if(f!=NULL) { /* another process running? */
      oldp=fread(pbuf,1,sizeof(pbuf)-1,f); fclose(f);
        if(oldp>0 && oldp<sizeof(pbuf)) {
          pbuf[oldp]=0;
          lim=1;
          snprintf(obuf,sizeof(obuf),"/proc/%s",pbuf);
          for(i=0; (k=stat(obuf,&dst))==0 && i<lim; i++) sleep(1);
          if(k==0) user_error("double_click");
          else unlink(buf);
      }
    }
    snprintf(pidbuf,sizeof(pidbuf),"%u",getpid());
    f=fopen(buf,"w"); fputs(pidbuf,f); fclose(f);
}

int execredirected(char *cmdf, char *inf, char *outf, char *errf, char *arg[])
{
    pid_t pid;
    int status, t;

    if(robot_access) return 0;
    if(time(0)>=limtimex) {
      if(errf!=NULL)
        accessfile("No time left to execute subprograms.\n","w","%s",errf);
      return -100;
    }
    fflush(NULL); /* flush all output streams before forking
                   * otherwise they will be doubled */
    pid=fork(); if(pid==-1) return -1;
    if(!pid) {    /* child */
      char buf[4096]; int k;
      if(inf!=NULL) freopen(inf,"r",stdin);
      if(outf!=NULL) freopen(outf,"w",stdout);
      if(errf!=NULL) freopen(errf,"w",stderr);
            /* This is to patch LinuxPPC uid wrapping 
             * for scripts */
      t=0; if(strchr(cmdf,'/')) {
          FILE *tf;
          char buf[16];
          tf=fopen(cmdf,"r"); fread(buf,1,10,tf); fclose(tf);
          if(memcmp(buf+1,"ELF",3)!=0) t=1;
      }
      if(wrapexec==-1) {
          setreuid(getuid(),getuid());setregid(getgid(),getgid());
      }
      if(wrapexec==1 || (t==1 && wrapexec==0)) {
          setreuid(geteuid(),geteuid());setregid(getegid(),getegid());
      }
      errno=0;
      if(strchr(cmdf,'/')) execve(cmdf,arg,environ);
      else execvp(cmdf,arg);
      snprintf(buf,sizeof(buf),"Failed to execute");
      for(k=0;arg[k];k++) {
          t=strlen(buf);
          snprintf(buf+t,sizeof(buf)-t," %s",arg[k]);
      }
      t=strlen(buf);
      snprintf(buf+t,sizeof(buf)-t,"\n    %s\n",strerror(errno));
      accessfile(buf,"a","%s/exec.fail",tmp_dir);
      exit(127);
    }
    else {  /* parent */
      wrapexec=0; status=0; 
      if(exec_wait) {
          killpid=pid; forkalarm();
          waitpid(pid,&status,0); killpid=0; finalalarm();
      }
      return WEXITSTATUS(status);
    }
}

struct {
    char cmd[MAX_EXEC_NAME+1];
    unsigned int fd1, fd2;
} mxtab[MAX_MULTIEXEC];
int mxno=0;
#define fifomode (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)

      /* preparation for resident execution.
       * Returns 1 if already up, otherwise 0. */
int multiexec(char *cmd)
{
    char *p, buf[256];
    int i, fd, status, mnew;
    
    if(robot_access) return 0;
    if(strstr(tmp_dir,"sessions/")==NULL) return 0;
    setenv("fifo_fd","",1);
    p=getvar("wims_multiexec");
    if(p==NULL || wordchr(p,cmd)==NULL) return 0; /* not allowed */
    for(i=0;i<mxno && strcmp(cmd,mxtab[i].cmd)!=0; i++);
    if(i>=mxno) {
      if(mxno>=MAX_MULTIEXEC) return 0;
      status=0;
      snprintf(mxtab[i].cmd,sizeof(mxtab[i].cmd),"%s",cmd);
      snprintf(buf,sizeof(buf),"%s/fifo.in.%d",tmp_dir,i+1);
      unlink(buf); status|=mkfifo(buf,fifomode);
      status|=chmod(buf,fifomode);
      fd=open(buf,O_RDWR|O_NONBLOCK); mxtab[i].fd1=fd;
      snprintf(buf,sizeof(buf),"%s/fifo.out.%d",tmp_dir,i+1);
      unlink(buf); status|=mkfifo(buf,fifomode);
      status|=chmod(buf,fifomode);
      fd=open(buf,O_RDWR|O_NONBLOCK); mxtab[i].fd2=fd;
      if(status) return 0;
      mxno++; mnew=0;
    }
    else mnew=1;
    snprintf(buf,sizeof(buf),"%d %u %u",i+1,mxtab[i].fd1,mxtab[i].fd2);
    setenv("fifo_fd",buf,1); return mnew;
}

      /* my system(), but with variable parms
       * More secure than system(), and direct fork. */
int call_ssh(char *s,...)
{
    va_list vp;
    char buf[MAX_LINELEN+1];
    char *arg[1024];
    char *inf=NULL, *outf=NULL, *errf=NULL;
    char *cmdf, *p, *p2;
    int i, d;

    if(robot_access) return 0;
    va_start(vp,s);
    vsnprintf(buf,sizeof(buf),s,vp);
    va_end(vp);
    p=find_word_start(buf); if(*p==0) return 0;
    cmdf=p;
    for(i=0;*p!=0 && i<1000; p=find_word_start(p2)) {
      switch(*p) {
          case '\'': {
            p++; p2=strchr(p,'\''); if(p2==NULL) p2=p+strlen(p);
            d=0; break;
          }
          case '"': {
            p++; p2=strchr(p,'"'); if(p2==NULL) p2=p+strlen(p);
            d=0; break;
          }
          default: d=1; p2=find_word_end(p); break;
      }
      if(*p2) *p2++=0;
      if(!d) {arg[i++]=p; continue;}
      switch(*p) {
          case '<': inf=++p; break;
          case '>': {
            p++; if(*p=='&') {
                merge: p++; errf=outf=p; break;
            }
            else outf=p;
            break;
          }
          case '&': {
            p++; if(*p=='>') goto merge;
            else break;
          }
          case '2': {
            if(*(p+1)=='>') {errf=p+2; break;}
          }
          default: arg[i++]=p; break;
      }
    }
    arg[i]=NULL;
    return execredirected(cmdf,inf,outf,errf,arg);
}

      /* Read/write to a file with variable parms to print filename */
void accessfile(char *content, char *type, char *s,...)
{
    va_list vp;
    char buf[MAX_LINELEN+1];
    FILE *f;
    int l;

    if(robot_access) return;
    va_start(vp,s);
    vsnprintf(buf,sizeof(buf),s,vp);
    va_end(vp);
    f=fopen(buf,type); if(f==NULL) {
      if(*type=='r') content[0]=0; return;
    }
    switch(*type) {
      case 'a':
      case 'w': {
          l=strlen(content); fwrite(content,1,l,f); break;
      }
      case 'r': {
          l=fread(content,1,MAX_LINELEN-1,f);
          if(l>0 && l<MAX_LINELEN) content[l]=0;
          else content[0]=0;
          _tolinux(content);
          break;
      }
      default: {
          content[0]=0; break;
      }
    }
    fclose(f);
}

      /* system(), but with variable parms
       * Uses sh to execute command. */
int call_sh(char *s,...)
{
    va_list vp;
    char buf[MAX_LINELEN+1];
    char *abuf[8];

    if(robot_access) return 0;
    va_start(vp,s);
    vsnprintf(buf,sizeof(buf),s,vp);
    va_end(vp);
    abuf[0]="sh"; abuf[1]="-c"; abuf[2]=buf; abuf[3]=NULL;
    return execredirected(abuf[0],NULL,NULL,NULL,abuf);
}

void _getdef(char buf[], char *name, char value[])
{
    char *p1, *p2, *p3, *p4;
    
    for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) {
      p2=find_word_start(p1+strlen(name));
      if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue;
      p3=p1; while(p3>buf && *(p3-1)!='\n') p3--;
      p3=find_word_start(p3);
      if(p3<p1 && *p3!='!') continue;
      if(p3<p1) {
          p3++; p4=find_word_end(p3);
          if(find_word_start(p4)!=p1) continue;
          if(p4-p3!=3 || (strncmp(p3,"set",3)!=0 &&
             strncmp(p3,"let",3)!=0 &&
             strncmp(p3,"def",3)!=0)) {
            if(p4-p3!=6 || strncmp(p3,"define",6)!=0) continue;
          }
      }
      p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2);
      p2=find_word_start(p2);
      if(p2>p3) {value[0]=0; return;}
      snprintf(value,MAX_LINELEN,"%s",p2);
      if(p3!=NULL && p3-p2<MAX_LINELEN) value[p3-p2]=0;
      strip_trailing_spaces(value);
      return;
    }
}

      /* Get variable definition from a file.
       * Result stored in buffer value of length MAX_LINELEN. */
void getdef(char *fname, char *name, char value[])
{
    FILE *f;
    char *buf, tbuf[MAX_LINELEN+1], nbuf[MAX_NAMELEN+1];
    int l;
    char *p1, *p2;
    
    value[0]=0;
    f=fopen(fname,"r"); if(f==NULL) return;
    fseek(f,0,SEEK_END); l=ftell(f); fseek(f,0,SEEK_SET);
    buf=xmalloc(l+256); l=fread(buf,1,l,f);
    fclose(f);
    if(l<=0) return; else buf[l]=0;
    _tolinux(buf);
    snprintf(value,MAX_LINELEN,"%s",name);
    for(p1=value; *p1; p1=p2) {
      while(*p1 && !isalnum(*p1) && *p1!='_') p1++;
      if(*p1==0) break;
      for(p2=p1; isalnum(*p2) || *p2=='_'; p2++);
      if(p2-p1>MAX_NAMELEN) continue;
      memmove(nbuf,p1,p2-p1); nbuf[p2-p1]=0;
      tbuf[0]=0; _getdef(buf,nbuf,tbuf);
      string_modify(value,p1,p2,"%s",tbuf);
      p2=p1+strlen(tbuf);
    }
    free(buf);
}

int _setdef_changed;

void _setdef(char buf[], char *name, char *value)
{
    char *p1, *p2, *p3;
    int n;
    
    for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) {
      p2=find_word_start(p1+strlen(name));
      if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue;
      p3=p1; while(p3>buf && *(p3-1)==' ') p3--;
      if(p3>buf && *(p3-1)!='\n') continue;
      p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2);
      if(strlen(value)!=p3-p2 || strncmp(value,p2,p3-p2)!=0) {
          string_modify(buf,p2,p3,"%s",value);
          _setdef_changed++;
      }
      return;
    }
    n=strlen(buf);
    if(n>0 && buf[n-1]!='\n') 
      snprintf(buf+n,MAX_LINELEN-n,"\n%s=%s\n",name,value);
    else
      snprintf(buf+n,MAX_LINELEN-n,"%s=%s\n",name,value);
    _setdef_changed++;
}

      /* Set variable definition to a file. */
void setdef(char *fname, char *name)
{
    FILE *f;
    char buf[MAX_LINELEN+1];
    int l;
    char *p1, *p2, *p3;

    _setdef_changed=0;
    if(strchr(name,'=')==NULL) return;
    for(p1=name;*p1;p1++) {
      if(isspace(*p1) && *p1!=' ' && *p1!='\n') *p1=' ';
      if(*p1==' ') {
          for(p2=p1+1; isspace(*p2) && *p2!='\n'; p2++);
          if(p2>p1+1) strcpy(p1+1,p2);
          p2=p1+1; if(*p2=='=' || *p2=='\n') strcpy(p1,p2);
      }
    }
    f=fopen(fname,"r"); if(f!=NULL) {
      l=fread(buf,1,MAX_LINELEN,f);
      fclose(f);
      if(l<0 || l>MAX_LINELEN) l=0; buf[l]=0;
      _tolinux(buf);
    }
    else buf[0]=0;
    for(p1=find_word_start(name); p1!=NULL; p1=p2) {
      p2=strchr(p1,'\n'); if(p2!=NULL) *p2++=0;
      p1=find_word_start(p1);
      p3=strchr(p1,'='); if(p3==NULL) continue;
      *p3++=0; p3=find_word_start(p3);
      _setdef(buf,p1,p3);
    }
    if(_setdef_changed) {
      f=fopen(fname,"w"); if(f!=NULL) {
          fprintf(f,"%s",buf); fclose(f);
      }
    }
}

      /* check whether connecting host is part of given list.
       * Returns 0 if no, 1 if yes. */
int checkhost(char *hlist)
{
    char buf[MAX_LINELEN+1];
    char lbuf[1024], hbuf1[256], hbuf2[256];
    char *p1, *p2, *pb, *pe, *pp;
    
    if(*remote_addr==0) return 0;
    snprintf(hbuf1,sizeof(hbuf1),"+%s+",remote_addr);
    if(*remote_host!=0) {
      snprintf(hbuf2,sizeof(hbuf2),"+%s+",remote_host);
      for(p1=hbuf2; *p1; p1++) *p1=tolower(*p1);
    }
    else hbuf2[0]=0;
    snprintf(buf,sizeof(buf),"%s",hlist);
    for(p1=buf; *p1; p1++) {
      *p1=tolower(*p1);
      if(!isalnum(*p1) && strchr(".-_",*p1)==NULL) *p1=' ';
    }
    for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
      p2=find_word_end(p1); if(*p2) *p2++=0;
      if(p2-p1<3) continue;
      if(isalnum(*p1)) pb="+"; else pb="";
      if(isalnum(*(p2-1))) pe="+"; else pe="";
      snprintf(lbuf,sizeof(lbuf),"%s%s%s",pb,p1,pe);
      for(pp=p1; *pp && (isdigit(*pp) || *pp=='.'); pp++); 
      if(*pp) pp=hbuf2; /* host name */
      else pp=hbuf1;          /* ip number */
      if(strstr(pp,lbuf)!=NULL) return 1; /* found */
    }
    return 0;
}

      /* bad identification */
void bad_ident(void)
{
    if(cookiegot[0]!=0) {
    }
    user_error("bad_ident");
}

void instex_flush(void)
{
    char *p;
    setenv("texgif_style","",1);
    setenv("texgif_tmpdir",tmp_dir,1);
    setenv("texgif_src",instex_src,1);
    setenv("texgif_outfile",instex_fname,1);
    unsetenv("w_instex_color");
    getwimstexsize=0; fix_tex_size(); getwimstexsize=1;
    for(p=instex_fname;*p;p++) if(*p=='\n') *p=' ';
    wrapexec=0; call_ssh("%s/%s >%s/ins.Out 2>%s/ins.Err",
                   bin_dir,instex_processor,
                   session_prefix,session_prefix);
    call_ssh("mv %s %s", instex_fname,session_prefix);
    instex_src[0]=instex_fname[0]=0; instex_cnt=0;
}

      /* put last.phtml */
void putlastout(void)
{
    if(instex_cnt>0) instex_flush();
    catfile(stdout,"%s/%s",session_prefix,lastout);
}


Generated by  Doxygen 1.6.0   Back to index