Subversion Repositories wimsdev

Rev

Rev 8343 | Rev 11125 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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