Subversion Repositories wimsdev

Rev

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